1 #define UNPAGED 1 /* for proper kmain() prototype */ 2 3 #include "kernel/kernel.h" 4 #include <assert.h> 5 #include <stdlib.h> 6 #include <minix/minlib.h> 7 #include <minix/const.h> 8 #include <minix/type.h> 9 #include <minix/board.h> 10 #include <minix/com.h> 11 #include <sys/types.h> 12 #include <sys/param.h> 13 #include <sys/reboot.h> 14 #include "string.h" 15 #include "arch_proto.h" 16 #include "direct_utils.h" 17 #include "bsp_serial.h" 18 #include "glo.h" 19 #include <machine/multiboot.h> 20 21 #if USE_SYSDEBUG 22 #define MULTIBOOT_VERBOSE 1 23 #endif 24 25 /* to-be-built kinfo struct, diagnostics buffer */ 26 kinfo_t kinfo; 27 struct kmessages kmessages; 28 29 /* pg_utils.c uses this; in this phase, there is a 1:1 mapping. */ 30 phys_bytes vir2phys(void *addr) { return (phys_bytes) addr; } 31 32 static void setup_mbi(multiboot_info_t *mbi, char *bootargs); 33 34 /* String length used for mb_itoa */ 35 #define ITOA_BUFFER_SIZE 20 36 37 /* Kernel may use memory */ 38 int kernel_may_alloc = 1; 39 40 /* kernel bss */ 41 extern u32_t _edata; 42 extern u32_t _end; 43 44 /* kernel unpaged bss */ 45 extern char _kern_unpaged_edata; 46 extern char _kern_unpaged_end; 47 48 /** 49 * 50 * The following function combines a few things together 51 * that can well be done using standard libc like strlen/strstr 52 * and such but these are not available in pre_init stage. 53 * 54 * The function expects content to be in the form of space separated 55 * key value pairs. 56 * param content the contents to search in 57 * param key the key to find (this *should* include the key/value delimiter) 58 * param value a pointer to an initialized char * of at least value_max_len length 59 * param value_max_len the maximum length of the value to store in value including 60 * the end char 61 * 62 **/ 63 int find_value(char * content,char * key,char *value,int value_max_len){ 64 65 char *iter,*keyp; 66 int key_len,content_len,match_len,value_len; 67 68 /* return if the input is invalid */ 69 if (key == NULL || content == NULL || value == NULL) { 70 return 1; 71 } 72 73 /* find the key and content length */ 74 key_len = content_len =0; 75 for(iter = key ; *iter != '\0'; iter++, key_len++); 76 for(iter = content ; *iter != '\0'; iter++, content_len++); 77 78 /* return if key or content length invalid */ 79 if (key_len == 0 || content_len == 0) { 80 return 1; 81 } 82 83 /* now find the key in the contents */ 84 match_len =0; 85 for (iter = content ,keyp=key; match_len < key_len && *iter != '\0' ; iter++) { 86 if (*iter == *keyp) { 87 match_len++; 88 keyp++; 89 continue; 90 } 91 /* The current key does not match the value , reset */ 92 match_len =0; 93 keyp=key; 94 } 95 96 if (match_len == key_len) { 97 printf("key found at %d %s\n", match_len, &content[match_len]); 98 value_len = 0; 99 /* copy the content to the value char iter already points to the first 100 char value */ 101 while(*iter != '\0' && *iter != ' ' && value_len + 1< value_max_len) { 102 *value++ = *iter++; 103 value_len++; 104 } 105 *value='\0'; 106 return 0; 107 } 108 return 1; /* not found */ 109 } 110 111 static int mb_set_param(char *bigbuf,char *name,char *value, kinfo_t *cbi) 112 { 113 /* bigbuf contains a list of key=value pairs separated by \0 char. 114 * The list itself is ended by a second \0 terminator*/ 115 char *p = bigbuf; 116 char *bufend = bigbuf + MULTIBOOT_PARAM_BUF_SIZE; 117 char *q; 118 int namelen = strlen(name); 119 int valuelen = strlen(value); 120 121 /* Some variables we recognize */ 122 if(!strcmp(name, SERVARNAME)) { cbi->do_serial_debug = 1; } 123 if(!strcmp(name, SERBAUDVARNAME)) { cbi->serial_debug_baud = atoi(value); } 124 125 /* Delete the item if already exists */ 126 while (*p) { 127 if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') { 128 q = p; 129 /* let q point to the end of the entry */ 130 while (*q) q++; 131 /* now copy the remained of the buffer */ 132 for (q++; q < bufend; q++, p++) 133 *p = *q; 134 break; 135 } 136 137 /* find the end of the buffer */ 138 while (*p++); 139 p++; 140 } 141 142 143 /* find the first empty spot */ 144 for (p = bigbuf; p < bufend && (*p || *(p + 1)); p++); 145 146 /* unless we are the first entry step over the delimiter */ 147 if (p > bigbuf) p++; 148 149 /* Make sure there's enough space for the new parameter */ 150 if (p + namelen + valuelen + 3 > bufend) { 151 return -1; 152 } 153 154 strcpy(p, name); 155 p[namelen] = '='; 156 strcpy(p + namelen + 1, value); 157 p[namelen + valuelen + 1] = 0; 158 p[namelen + valuelen + 2] = 0; /* end with a second delimiter */ 159 return 0; 160 } 161 162 int overlaps(multiboot_module_t *mod, int n, int cmp_mod) 163 { 164 multiboot_module_t *cmp = &mod[cmp_mod]; 165 int m; 166 167 #define INRANGE(mod, v) ((v) >= mod->mod_start && (v) <= thismod->mod_end) 168 #define OVERLAP(mod1, mod2) (INRANGE(mod1, mod2->mod_start) || \ 169 INRANGE(mod1, mod2->mod_end)) 170 for(m = 0; m < n; m++) { 171 multiboot_module_t *thismod = &mod[m]; 172 if(m == cmp_mod) continue; 173 if(OVERLAP(thismod, cmp)) { 174 return 1; 175 } 176 } 177 return 0; 178 } 179 180 /* XXX: hard-coded stuff for modules */ 181 #define MB_MODS_NR NR_BOOT_MODULES 182 #define MB_MODS_BASE 0x82000000 183 #define MB_MODS_ALIGN 0x00800000 /* 8 MB */ 184 #define MB_MMAP_START 0x80000000 185 #define MB_MMAP_SIZE 0x10000000 /* 256 MB */ 186 187 multiboot_module_t mb_modlist[MB_MODS_NR]; 188 multiboot_memory_map_t mb_memmap; 189 190 void setup_mbi(multiboot_info_t *mbi, char *bootargs) 191 { 192 memset(mbi, 0, sizeof(*mbi)); 193 mbi->flags = MULTIBOOT_INFO_MODS | MULTIBOOT_INFO_MEM_MAP | 194 MULTIBOOT_INFO_CMDLINE; 195 mbi->mi_mods_count = MB_MODS_NR; 196 mbi->mods_addr = (u32_t)&mb_modlist; 197 198 int i; 199 for (i = 0; i < MB_MODS_NR; ++i) { 200 mb_modlist[i].mod_start = MB_MODS_BASE + i * MB_MODS_ALIGN; 201 mb_modlist[i].mod_end = mb_modlist[i].mod_start + MB_MODS_ALIGN 202 - ARM_PAGE_SIZE; 203 mb_modlist[i].cmdline = 0; 204 } 205 206 /* morph the bootargs into multiboot */ 207 mbi->cmdline = (u32_t) bootargs; 208 209 mbi->mmap_addr =(u32_t)&mb_memmap; 210 mbi->mmap_length = sizeof(mb_memmap); 211 212 mb_memmap.size = sizeof(multiboot_memory_map_t); 213 mb_memmap.mm_base_addr = MB_MMAP_START; 214 mb_memmap.mm_length = MB_MMAP_SIZE; 215 mb_memmap.type = MULTIBOOT_MEMORY_AVAILABLE; 216 } 217 218 void get_parameters(kinfo_t *cbi, char *bootargs) 219 { 220 multiboot_memory_map_t *mmap; 221 multiboot_info_t *mbi = &cbi->mbi; 222 int var_i,value_i, m, k; 223 char *p; 224 extern char _kern_phys_base, _kern_vir_base, _kern_size, 225 _kern_unpaged_start, _kern_unpaged_end; 226 phys_bytes kernbase = (phys_bytes) &_kern_phys_base, 227 kernsize = (phys_bytes) &_kern_size; 228 #define BUF 1024 229 static char cmdline[BUF]; 230 231 /* get our own copy of the multiboot info struct and module list */ 232 setup_mbi(mbi, bootargs); 233 234 /* Set various bits of info for the higher-level kernel. */ 235 cbi->mem_high_phys = 0; 236 cbi->user_sp = (vir_bytes) &_kern_vir_base; 237 cbi->vir_kern_start = (vir_bytes) &_kern_vir_base; 238 cbi->bootstrap_start = (vir_bytes) &_kern_unpaged_start; 239 cbi->bootstrap_len = (vir_bytes) &_kern_unpaged_end - 240 cbi->bootstrap_start; 241 cbi->kmess = &kmess; 242 243 /* set some configurable defaults */ 244 cbi->do_serial_debug = 1; 245 cbi->serial_debug_baud = 115200; 246 247 /* parse boot command line */ 248 if (mbi->flags&MULTIBOOT_INFO_CMDLINE) { 249 static char var[BUF]; 250 static char value[BUF]; 251 252 /* Override values with cmdline argument */ 253 memcpy(cmdline, (void *) mbi->cmdline, BUF); 254 p = cmdline; 255 while (*p) { 256 var_i = 0; 257 value_i = 0; 258 while (*p == ' ') p++; /* skip spaces */ 259 if (!*p) break; /* is this the end? */ 260 while (*p && *p != '=' && *p != ' ' && var_i < BUF - 1) 261 var[var_i++] = *p++ ; 262 var[var_i] = 0; 263 if (*p++ != '=') continue; /* skip if not name=value */ 264 while (*p && *p != ' ' && value_i < BUF - 1) { 265 value[value_i++] = *p++ ; 266 } 267 value[value_i] = 0; 268 269 mb_set_param(cbi->param_buf, var, value, cbi); 270 } 271 } 272 273 /* let higher levels know what we are booting on */ 274 mb_set_param(cbi->param_buf, ARCHVARNAME, (char *)get_board_arch_name(machine.board_id), cbi); 275 mb_set_param(cbi->param_buf, BOARDVARNAME,(char *)get_board_name(machine.board_id) , cbi); 276 277 278 /* round user stack down to leave a gap to catch kernel 279 * stack overflow; and to distinguish kernel and user addresses 280 * at a glance (0xf.. vs 0xe..) 281 */ 282 cbi->user_sp &= 0xF0000000; 283 cbi->user_end = cbi->user_sp; 284 285 /* kernel bytes without bootstrap code/data that is currently 286 * still needed but will be freed after bootstrapping. 287 */ 288 kinfo.kernel_allocated_bytes = (phys_bytes) &_kern_size; 289 kinfo.kernel_allocated_bytes -= cbi->bootstrap_len; 290 291 assert(!(cbi->bootstrap_start % ARM_PAGE_SIZE)); 292 cbi->bootstrap_len = rounddown(cbi->bootstrap_len, ARM_PAGE_SIZE); 293 assert(mbi->flags & MULTIBOOT_INFO_MODS); 294 assert(mbi->mi_mods_count < MULTIBOOT_MAX_MODS); 295 assert(mbi->mi_mods_count > 0); 296 memcpy(&cbi->module_list, (void *) mbi->mods_addr, 297 mbi->mi_mods_count * sizeof(multiboot_module_t)); 298 299 memset(cbi->memmap, 0, sizeof(cbi->memmap)); 300 /* mem_map has a variable layout */ 301 if(mbi->flags & MULTIBOOT_INFO_MEM_MAP) { 302 cbi->mmap_size = 0; 303 for (mmap = (multiboot_memory_map_t *) mbi->mmap_addr; 304 (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length; 305 mmap = (multiboot_memory_map_t *) 306 ((unsigned long) mmap + mmap->size + sizeof(mmap->size))) { 307 if(mmap->type != MULTIBOOT_MEMORY_AVAILABLE) continue; 308 add_memmap(cbi, mmap->mm_base_addr, mmap->mm_length); 309 } 310 } else { 311 assert(mbi->flags & MULTIBOOT_INFO_MEMORY); 312 add_memmap(cbi, 0, mbi->mem_lower_unused*1024); 313 add_memmap(cbi, 0x100000, mbi->mem_upper_unused*1024); 314 } 315 316 /* Sanity check: the kernel nor any of the modules may overlap 317 * with each other. Pretend the kernel is an extra module for a 318 * second. 319 */ 320 k = mbi->mi_mods_count; 321 assert(k < MULTIBOOT_MAX_MODS); 322 cbi->module_list[k].mod_start = kernbase; 323 cbi->module_list[k].mod_end = kernbase + kernsize; 324 cbi->mods_with_kernel = mbi->mi_mods_count+1; 325 cbi->kern_mod = k; 326 327 for(m = 0; m < cbi->mods_with_kernel; m++) { 328 #if 0 329 printf("checking overlap of module %08lx-%08lx\n", 330 cbi->module_list[m].mod_start, cbi->module_list[m].mod_end); 331 #endif 332 if(overlaps(cbi->module_list, cbi->mods_with_kernel, m)) 333 panic("overlapping boot modules/kernel"); 334 /* We cut out the bits of memory that we know are 335 * occupied by the kernel and boot modules. 336 */ 337 cut_memmap(cbi, 338 cbi->module_list[m].mod_start, 339 cbi->module_list[m].mod_end); 340 } 341 } 342 343 /* 344 * During low level init many things are not supposed to work 345 * serial being one of them. We therefore can't rely on the 346 * serial to debug. POORMANS_FAILURE_NOTIFICATION can be used 347 * before we setup our own vector table and will result in calling 348 * the bootloader's debugging methods that will hopefully show some 349 * information like the currnet PC at on the serial. 350 */ 351 #define POORMANS_FAILURE_NOTIFICATION asm volatile("svc #00\n") 352 353 /* use the passed cmdline argument to determine the machine id */ 354 void set_machine_id(char *cmdline) 355 { 356 357 char boardname[20]; 358 memset(boardname,'\0',20); 359 if (find_value(cmdline,"board_name=",boardname,20)){ 360 /* we expect the bootloader to pass a board_name as argument 361 * this however did not happen and given we still are in early 362 * boot we can't use the serial. We therefore generate an interrupt 363 * and hope the bootloader will do something nice with it */ 364 POORMANS_FAILURE_NOTIFICATION; 365 } 366 machine.board_id = get_board_id_by_short_name(boardname); 367 368 if (machine.board_id ==0){ 369 /* same thing as above there is no safe escape */ 370 POORMANS_FAILURE_NOTIFICATION; 371 } 372 } 373 374 kinfo_t *pre_init(int argc, char **argv) 375 { 376 char *bootargs; 377 /* This is the main "c" entry point into the kernel. It gets called 378 from head.S */ 379 380 /* Clear BSS */ 381 memset(&_edata, 0, (u32_t)&_end - (u32_t)&_edata); 382 memset(&_kern_unpaged_edata, 0, (u32_t)&_kern_unpaged_end - (u32_t)&_kern_unpaged_edata); 383 384 /* we get called in a c like fashion where the first arg 385 * is the program name (load address) and the rest are 386 * arguments. by convention the second argument is the 387 * command line */ 388 if (argc != 2) { 389 POORMANS_FAILURE_NOTIFICATION; 390 } 391 392 bootargs = argv[1]; 393 set_machine_id(bootargs); 394 bsp_ser_init(); 395 /* Get our own copy boot params pointed to by ebx. 396 * Here we find out whether we should do serial output. 397 */ 398 get_parameters(&kinfo, bootargs); 399 400 /* Make and load a pagetable that will map the kernel 401 * to where it should be; but first a 1:1 mapping so 402 * this code stays where it should be. 403 */ 404 dcache_clean(); /* clean the caches */ 405 pg_clear(); 406 pg_identity(&kinfo); 407 kinfo.freepde_start = pg_mapkernel(); 408 pg_load(); 409 vm_enable_paging(); 410 411 /* Done, return boot info so it can be passed to kmain(). */ 412 return &kinfo; 413 } 414 415 /* pre_init gets executed at the memory location where the kernel was loaded by the boot loader. 416 * at that stage we only have a minimum set of functionality present (all symbols gets renamed to 417 * ensure this). The following methods are used in that context. Once we jump to kmain they are no 418 * longer used and the "real" implementations are visible 419 */ 420 void send_diag_sig(void) { } 421 void minix_shutdown(minix_timer_t *t) { arch_shutdown(0); } 422 void busy_delay_ms(int x) { } 423 int raise(int n) { panic("raise(%d)\n", n); } 424 int kern_phys_map_ptr( phys_bytes base_address, vir_bytes io_size, int vm_flags, 425 struct kern_phys_map * priv, vir_bytes ptr) {}; 426 struct machine machine; /* pre init stage machine */ 427