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 19BOOT_BSS 20char cmdline_val[MAX_CMDLINE_VAL_LEN]; 21 22/* workaround because string literals are not supported by C parser */ 23const char cmdline_str_max_num_nodes[] = {'m', 'a', 'x', '_', 'n', 'u', 'm', '_', 'n', 'o', 'd', 'e', 's', 0}; 24const char cmdline_str_num_sh_frames[] = {'n', 'u', 'm', '_', 's', 'h', '_', 'f', 'r', 'a', 'm', 'e', 's', 0}; 25const char cmdline_str_disable_iommu[] = {'d', 'i', 's', 'a', 'b', 'l', 'e', '_', 'i', 'o', 'm', 'm', 'u', 0}; 26 27static int is_space(char c) 28{ 29 return c <= ' '; 30} 31 32static 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 62static 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 82static 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 106void 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#ifdef 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