#include "kernel/kernel.h" #include #include /* * == IMPORTANT == * Routines in this file can not use any variable in kernel BSS, * since before image is extracted, no BSS is allocated. * So pay attention to any external call (including library call). * * */ #include #include #include #include #include #include "../../../boot/image.h" #include "string.h" #include "arch_proto.h" #include "libexec.h" #include #define MULTIBOOT_VERBOSE 1 /* FIXME: Share this define with kernel linker script */ #define MULTIBOOT_KERNEL_ADDR 0x00200000UL /* Granularity used in image file and copying */ #define GRAN 512 #define SECT_CEIL(x) ((((x) - 1) / GRAN + 1) * GRAN) /* String length used for mb_itoa */ #define ITOA_BUFFER_SIZE 20 /* Info on boot modules */ phys_bytes mulitboot_modules_addr; #define mb_load_phymem(buf, phy, len) \ phys_copy((phy), (u32_t)(buf), (len)) #define mb_save_phymem(buf, phy, len) \ phys_copy((u32_t)(buf), (phy), (len)) FORWARD _PROTOTYPE(void mb_print, (char *str)); PRIVATE void mb_itoa(u32_t val, char * out) { char ret[ITOA_BUFFER_SIZE]; int i = ITOA_BUFFER_SIZE - 2; /* Although there's a library version of itoa(int n), * we can't use it since that implementation relies on BSS segment */ ret[ITOA_BUFFER_SIZE - 2] = '0'; if (val) { for (; i >= 0; i--) { char c; if (val == 0) break; c = val % 10; val = val / 10; c += '0'; ret[i] = c; } } else i--; ret[ITOA_BUFFER_SIZE - 1] = 0; strcpy(out, ret + i + 1); } PRIVATE void mb_itox(u32_t val, char *out) { char ret[9]; int i = 7; /* Convert a number to hex string */ ret[7] = '0'; if (val) { for (; i >= 0; i--) { char c; if (val == 0) break; c = val & 0xF; val = val >> 4; if (c > 9) c += 'A' - 10; else c += '0'; ret[i] = c; } } else i--; ret[8] = 0; strcpy(out, ret + i + 1); } PRIVATE void mb_put_char(char c, int line, int col) { /* Write a char to vga display buffer. */ if (line= MULTIBOOT_CONSOLE_COLS) { print_line++; print_col = 0; } while (print_line >= MULTIBOOT_CONSOLE_LINES) mb_scroll_up(1); } } PRIVATE void mb_print_hex(u32_t value) { int i; char c; char out[9] = "00000000"; /* Print a hex value */ for (i = 7; i >= 0; i--) { c = value % 0x10; value /= 0x10; if (c < 10) c += '0'; else c += 'A'-10; out[i] = c; } mb_print(out); } PRIVATE int mb_set_param(char *name, char *value) { char *p = multiboot_param_buf; char *q; int namelen = strlen(name); int valuelen = strlen(value); /* Delete the item if already exists */ while (*p) { if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') { q = p; while (*q) q++; for (q++; q < multiboot_param_buf + MULTIBOOT_PARAM_BUF_SIZE; q++, p++) *p = *q; break; } while (*p++) ; p++; } for (p = multiboot_param_buf; p < multiboot_param_buf + MULTIBOOT_PARAM_BUF_SIZE && (*p || *(p + 1)); p++) ; if (p > multiboot_param_buf) p++; /* Make sure there's enough space for the new parameter */ if (p + namelen + valuelen + 3 > multiboot_param_buf + MULTIBOOT_PARAM_BUF_SIZE) return -1; strcpy(p, name); p[namelen] = '='; strcpy(p + namelen + 1, value); p[namelen + valuelen + 1] = 0; p[namelen + valuelen + 2] = 0; return 0; } PRIVATE void get_parameters(multiboot_info_t *mbi) { char mem_value[40], temp[ITOA_BUFFER_SIZE]; int i, processor; int dev; int ctrlr; int disk, prim, sub; int var_i,value_i; char *p; const static int dev_cNd0[] = { 0x0300, 0x0800, 0x0A00, 0x0C00, 0x1000 }; static char mb_cmd_buff[GRAN] = "add some value to avoid me in BSS"; static char var[GRAN] = "add some value to avoid me in BSS"; static char value[GRAN] = "add some value to avoid me in BSS"; for (i = 0; i < MULTIBOOT_PARAM_BUF_SIZE; i++) multiboot_param_buf[i] = 0; if (mbi->flags & MULTIBOOT_INFO_BOOTDEV) { disk = ((mbi->boot_device&0xff000000) >> 24)-0x80; prim = (mbi->boot_device & 0xff0000) >> 16; if (prim == 0xff) prim = 0; sub = (mbi->boot_device & 0xff00) >> 8; if (sub == 0xff) sub = 0; ctrlr = 0; dev = dev_cNd0[ctrlr]; /* Determine the value of rootdev */ dev += 0x80 + (disk * NR_PARTITIONS + prim) * NR_PARTITIONS + sub; mb_itoa(dev, temp); mb_set_param("rootdev", temp); mb_set_param("ramimagedev", temp); } mb_set_param("ramsize", "0"); mb_set_param("hz", "60"); processor = getprocessor(); if (processor == 1586) processor = 686; mb_itoa(processor, temp); mb_set_param("processor", temp); mb_set_param("bus", "at"); mb_set_param("video", "ega"); mb_set_param("chrome", "color"); if (mbi->flags & MULTIBOOT_INFO_MEMORY) { strcpy(mem_value, "800:"); mb_itox( mbi->mem_lower * 1024 > MULTIBOOT_LOWER_MEM_MAX ? MULTIBOOT_LOWER_MEM_MAX : mbi->mem_lower * 1024, temp); strcat(mem_value, temp); strcat(mem_value, ",100000:"); mb_itox(mbi->mem_upper * 1024, temp); strcat(mem_value, temp); mb_set_param("memory", mem_value); } if (mbi->flags&MULTIBOOT_INFO_CMDLINE) { /* Override values with cmdline argument */ p = mb_cmd_buff; mb_load_phymem(mb_cmd_buff, mbi->cmdline, GRAN); while (*p) { var_i = 0; value_i = 0; while (*p == ' ') p++; if (!*p) break; while (*p && *p != '=' && var_i < GRAN - 1) var[var_i++] = *p++ ; var[var_i] = 0; p++; /* skip '=' */ while (*p && *p != ' ' && value_i < GRAN - 1) value[value_i++] = *p++ ; value[value_i] = 0; mb_set_param(var, value); } } } PRIVATE int mb_clear_memrange(phys_bytes start, phys_bytes end) { int empty = 0; int i; /* FIXME: use faster function */ for (i = start; i < end; i++) phys_copy((phys_bytes)&empty, i, 1); return 0; } PRIVATE void mb_extract_image(multiboot_info_t mbi) { multiboot_module_t *mb_module_info; multiboot_module_t *module; u32_t mods_count = mbi.mods_count; int r, i; vir_bytes text_vaddr, text_filebytes, text_membytes; vir_bytes data_vaddr, data_filebytes, data_membytes; phys_bytes text_paddr, data_paddr; vir_bytes stack_bytes; vir_bytes pc; off_t text_offset, data_offset; /* Save memory map for kernel tasks */ r = read_header_elf((const char *)MULTIBOOT_KERNEL_ADDR, &text_vaddr, &text_paddr, &text_filebytes, &text_membytes, &data_vaddr, &data_paddr, &data_filebytes, &data_membytes, &pc, &text_offset, &data_offset); for (i = 0; i < NR_TASKS; ++i) { image[i].memmap.text_vaddr = trunc_page(text_vaddr); image[i].memmap.text_paddr = trunc_page(text_paddr); image[i].memmap.text_bytes = text_membytes; image[i].memmap.data_vaddr = trunc_page(data_vaddr); image[i].memmap.data_paddr = trunc_page(data_paddr); image[i].memmap.data_bytes = data_membytes; image[i].memmap.stack_bytes = 0; image[i].memmap.entry = pc; } #ifdef MULTIBOOT_VERBOSE mb_print("\nKernel: "); mb_print_hex(trunc_page(text_paddr)); mb_print("-"); mb_print_hex(trunc_page(data_paddr) + data_membytes); mb_print(" Entry: "); mb_print_hex(pc); #endif mb_module_info = ((multiboot_module_t *)mbi.mods_addr); module = &mb_module_info[0]; /* Load boot image services into memory and save memory map */ for (i = 0; module < &mb_module_info[mods_count]; ++module, ++i) { r = read_header_elf((const char *)module->mod_start, &text_vaddr, &text_paddr, &text_filebytes, &text_membytes, &data_vaddr, &data_paddr, &data_filebytes, &data_membytes, &pc, &text_offset, &data_offset); if (r) { mb_print("fatal: ELF parse failure\n"); /* Spin here */ while (1) ; } stack_bytes = round_page(image[NR_TASKS+i].stack_kbytes * 1024); /* Load text segment */ phys_copy(module->mod_start+text_offset, text_paddr, text_filebytes); mb_clear_memrange(text_paddr+text_filebytes, trunc_page(text_paddr) + text_membytes); /* Load data and stack segments */ phys_copy(module->mod_start+data_offset, data_paddr, data_filebytes); mb_clear_memrange(data_paddr+data_filebytes, trunc_page(data_paddr) + data_membytes + stack_bytes); /* Save memmap for non-kernel tasks, so subscript past kernel tasks. */ image[NR_TASKS+i].memmap.text_vaddr = trunc_page(text_vaddr); image[NR_TASKS+i].memmap.text_paddr = trunc_page(text_paddr); image[NR_TASKS+i].memmap.text_bytes = text_membytes; image[NR_TASKS+i].memmap.data_vaddr = trunc_page(data_vaddr); image[NR_TASKS+i].memmap.data_paddr = trunc_page(data_paddr); image[NR_TASKS+i].memmap.data_bytes = data_membytes; image[NR_TASKS+i].memmap.stack_bytes = stack_bytes; image[NR_TASKS+i].memmap.entry = pc; #ifdef MULTIBOOT_VERBOSE mb_print("\n"); mb_print_hex(i); mb_print(": "); mb_print_hex(trunc_page(text_paddr)); mb_print("-"); mb_print_hex(trunc_page(data_paddr) + data_membytes + stack_bytes); mb_print(" Entry: "); mb_print_hex(pc); mb_print(" Stack: "); mb_print_hex(stack_bytes); mb_print(" "); mb_print((char *)module->cmdline); #endif } return; } PUBLIC phys_bytes pre_init(u32_t ebx) { multiboot_info_t mbi; /* Do pre-initialization for multiboot, returning physical address of * of multiboot module info */ mb_cls(); mb_print("\nMINIX booting... "); mb_load_phymem(&mbi, ebx, sizeof(mbi)); get_parameters(&mbi); mb_print("\nLoading image... "); mb_extract_image(mbi); return mbi.mods_addr; }