1 /*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7 #include <config.h>
8 #include <util.h>
9 #include <machine/io.h>
10 #include <arch/kernel/cmdline.h>
11 #include <arch/kernel/boot_sys.h>
12 #include <linker.h>
13 #include <plat/machine/io.h>
14
15 /* 'cmdline_val' is declared globally because of a C-subset restriction.
16 * It is only used in cmdline_parse(), which therefore is non-reentrant.
17 */
18 #define MAX_CMDLINE_VAL_LEN 1000
19 BOOT_BSS
20 char cmdline_val[MAX_CMDLINE_VAL_LEN];
21
22 /* workaround because string literals are not supported by C parser */
23 const char cmdline_str_max_num_nodes[] = {'m', 'a', 'x', '_', 'n', 'u', 'm', '_', 'n', 'o', 'd', 'e', 's', 0};
24 const char cmdline_str_num_sh_frames[] = {'n', 'u', 'm', '_', 's', 'h', '_', 'f', 'r', 'a', 'm', 'e', 's', 0};
25 const char cmdline_str_disable_iommu[] = {'d', 'i', 's', 'a', 'b', 'l', 'e', '_', 'i', 'o', 'm', 'm', 'u', 0};
26
is_space(char c)27 static int is_space(char c)
28 {
29 return c <= ' ';
30 }
31
parse_opt(const char * cmdline,const char * opt,char * value,int bufsize)32 static int UNUSED parse_opt(const char *cmdline, const char *opt, char *value, int bufsize)
33 {
34 int len = -1;
35 const char *optptr = NULL;
36
37 while (true) {
38 for (; is_space(*cmdline) && (*cmdline != 0); cmdline++);
39 if (*cmdline == 0) {
40 break;
41 }
42
43 for (optptr = opt; *optptr && *cmdline && (*cmdline != '=') && !is_space(*cmdline)
44 && (*optptr == *cmdline); optptr++, cmdline++);
45
46 if (*optptr == '\0' && *cmdline == '=') {
47 cmdline++;
48
49 for (len = 0; !is_space(*cmdline) && (len < bufsize - 1); cmdline++, len++) {
50 value[len] = *cmdline;
51 }
52 if (bufsize) {
53 value[len] = '\0';
54 }
55 }
56 for (; !is_space(*cmdline); cmdline++);
57 }
58
59 return len;
60 }
61
parse_bool(const char * cmdline,const char * opt)62 static int parse_bool(const char *cmdline, const char *opt)
63 {
64 const char *optptr = NULL;
65
66 while (1) {
67 for (; is_space(*cmdline) && (*cmdline != 0); cmdline++);
68 if (*cmdline == 0) {
69 return 0;
70 }
71
72 for (optptr = opt; *optptr && *cmdline && !is_space(*cmdline) && (*optptr == *cmdline); optptr++, cmdline++);
73
74 if (*optptr == '\0' && is_space(*cmdline)) {
75 return 1;
76 } else {
77 for (; !is_space(*cmdline); cmdline++);
78 }
79 }
80 }
81
parse_uint16_array(char * str,uint16_t * array,int array_size)82 static void UNUSED parse_uint16_array(char *str, uint16_t *array, int array_size)
83 {
84 char *last;
85 int i = 0;
86 int v;
87
88 while (str && i < array_size) {
89 for (last = str; *str && *str != ','; str++);
90 if (*str == 0) {
91 str = 0;
92 } else {
93 *str = 0;
94 str++;
95 }
96 v = str_to_long(last);
97 if (v == -1) {
98 array[i] = 0;
99 } else {
100 array[i] = v;
101 }
102 i++;
103 }
104 }
105
cmdline_parse(const char * cmdline,cmdline_opt_t * cmdline_opt)106 void cmdline_parse(const char *cmdline, cmdline_opt_t *cmdline_opt)
107 {
108 #if defined(CONFIG_PRINTING) || defined(CONFIG_DEBUG_BUILD)
109 /* use BIOS data area to read serial configuration. The BDA is not
110 * fully standardized and parts are absolete. See http://wiki.osdev.org/Memory_Map_(x86)#BIOS_Data_Area_.28BDA.29
111 * for an explanation */
112 const unsigned short *bda_port = (unsigned short *)0x400;
113 const unsigned short *bda_equi = (unsigned short *)0x410;
114 int const bda_ports_count = (*bda_equi >> 9) & 0x7;
115 #endif
116
117 #ifdef CONFIG_PRINTING
118 /* initialise to default or use BDA if available */
119 cmdline_opt->console_port = bda_ports_count && *bda_port ? *bda_port : 0x3f8;
120
121 if (parse_opt(cmdline, "console_port", cmdline_val, MAX_CMDLINE_VAL_LEN) != -1) {
122 parse_uint16_array(cmdline_val, &cmdline_opt->console_port, 1);
123 }
124
125 /* initialise console ports to enable debug output */
126 if (cmdline_opt->console_port) {
127 serial_init(cmdline_opt->console_port);
128 x86KSconsolePort = cmdline_opt->console_port;
129 }
130
131 /* only start printing here after having parsed/set/initialised the console_port */
132 printf("\nBoot config: parsing cmdline '%s'\n", cmdline);
133
134 if (cmdline_opt->console_port) {
135 printf("Boot config: console_port = 0x%x\n", cmdline_opt->console_port);
136 }
137 #endif
138
139 #if defined(CONFIG_PRINTING) || defined(CONFIG_DEBUG_BUILD)
140 /* initialise to default or use BDA if available */
141 cmdline_opt->debug_port = bda_ports_count && *bda_port ? *bda_port : 0x3f8;
142 if (parse_opt(cmdline, "debug_port", cmdline_val, MAX_CMDLINE_VAL_LEN) != -1) {
143 parse_uint16_array(cmdline_val, &cmdline_opt->debug_port, 1);
144 }
145
146 /* initialise debug ports */
147 if (cmdline_opt->debug_port) {
148 serial_init(cmdline_opt->debug_port);
149 x86KSdebugPort = cmdline_opt->debug_port;
150 printf("Boot config: debug_port = 0x%x\n", cmdline_opt->debug_port);
151 }
152 #endif
153
154 cmdline_opt->disable_iommu = parse_bool(cmdline, cmdline_str_disable_iommu);
155 printf("Boot config: disable_iommu = %s\n", cmdline_opt->disable_iommu ? "true" : "false");
156 }
157