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