123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- /*
- * start.c
- *
- * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <boot/multiboot.h>
- #include <common.h>
- #include <log.h>
- #include <cpu.h>
- #include <memory.h>
- #include <heap.h>
- #include <segments.h>
- #include <interrupt.h>
- #include <timer.h>
- #include <clock.h>
- #include <process.h>
- #include <thread.h>
- #include <exception.h>
- #include <video.h>
- #include <device.h>
- #include <power.h>
- #include <module.h>
- #include <exec/elf.h>
- #define DO_TASK(x, ...) x(__VA_ARGS__); advance_progress()
- #define MAX_CMDLINE_LENGTH 256
- extern void (*_end)();
- static char cmdline[MAX_CMDLINE_LENGTH] = "";
- static multiboot_tag_sections_t *kernel_sections = NULL;
- static size_t tasks_completed = 0, num_tasks = 12;
- static const char *manager_path = "";
- bool_t video_initialized = FALSE;
- const elf32_symbol_t *kernel_symtab = NULL;
- dword_t kernel_symcount = 0;
- const char *kernel_strtab = NULL;
- void *get_kernel_symbol(const char *name)
- {
- int i;
- for (i = 0; i < kernel_symcount; i++)
- {
- if (strcmp(name, &kernel_strtab[kernel_symtab[i].st_name]) == 0)
- {
- return (void*)kernel_symtab[i].st_value;
- }
- }
- return NULL;
- }
- const char *lookup_kernel_symbol_name(uintptr_t address)
- {
- int i;
- for (i = 0; i < kernel_symcount; i++)
- {
- if (address >= kernel_symtab[i].st_value && address < (kernel_symtab[i].st_value + kernel_symtab[i].st_size))
- {
- return &kernel_strtab[kernel_symtab[i].st_name];
- }
- }
- return NULL;
- }
- static dword_t __attribute__((__noreturn__)) system_idle_thread(void *param)
- {
- UNUSED_PARAMETER(param);
- while (TRUE)
- {
- syscall_yield_quantum();
- cpu_halt();
- }
- }
- static void pre_initialization(void)
- {
- cpu_init();
- segments_init();
- interrupt_init();
- syscalls_init();
- irq_init();
- exceptions_init();
- object_init();
- cpu_enable_interrupts();
- }
- static void scan_multiboot_info(multiboot_tag_t *mboot)
- {
- multiboot_tag_t *tag;
- for (tag = mboot; tag->type != MULTIBOOT_INFO_END; tag = (multiboot_tag_t*)(((uintptr_t)tag + tag->size + 7) & ~7))
- {
- switch (tag->type)
- {
- case MULTIBOOT_INFO_CMDLINE:
- strncpy(cmdline, ((multiboot_tag_cmdline_t*)tag)->string, sizeof(cmdline));
- break;
- case MULTIBOOT_INFO_MODULES:
- num_tasks++;
- break;
- case MULTIBOOT_INFO_SECTIONS:
- kernel_sections = (multiboot_tag_sections_t*)tag;
- break;
- }
- }
- }
- static bool_t load_kernel_symbols()
- {
- int i;
- const elf32_section_t *sections = (elf32_section_t*)(kernel_sections + 1);
- for (i = 0; i < kernel_sections->num; i++)
- {
- if (sections[i].sh_type == ELF_SECTION_TYPE_SYMTAB && !kernel_symtab)
- {
- area_t area = {
- .pages = memory_find_page_by_address(sections[i].sh_addr),
- .count = PAGE_NUMBER(PAGE_ALIGN_UP(sections[i].sh_size))
- };
- ASSERT(area.pages);
- if (memory_view_area(memory_upper_space, (void**)&kernel_symtab, &area, MEMORY_FLAG_ACCESSIBLE) != ERR_SUCCESS) continue;
- kernel_symcount = sections[i].sh_size / sizeof(elf32_symbol_t);
- }
- else if (sections[i].sh_type == ELF_SECTION_TYPE_STRTAB && i != kernel_sections->shndx && !kernel_strtab)
- {
- area_t area = {
- .pages = memory_find_page_by_address(sections[i].sh_addr),
- .count = PAGE_NUMBER(PAGE_ALIGN_UP(sections[i].sh_size))
- };
- ASSERT(area.pages);
- if (memory_view_area(memory_upper_space, (void**)&kernel_strtab, &area, MEMORY_FLAG_ACCESSIBLE) != ERR_SUCCESS) continue;
- }
- }
- if (!kernel_symtab || !kernel_strtab)
- {
- if (kernel_symtab) memory_free(memory_upper_space, (void*)kernel_symtab);
- if (kernel_strtab) memory_free(memory_upper_space, (void*)kernel_strtab);
- kernel_symcount = 0;
- return FALSE;
- }
- return TRUE;
- }
- static void setup_memory_management(uintptr_t mboot_tags, size_t mboot_size)
- {
- memory_init(mboot_tags, mboot_size);
- heap_init();
- memory_claim_physical_region(0xA0000, 0x20000, PAGE_STATUS_RESERVED);
- page_t *page = memory_find_page_by_address(TEXT_VIDEO_MEMORY);
- ASSERT(page);
- area_t area = { .pages = page, .count = 8 };
- sysret_t ret = memory_map_area(memory_default_table, &area, (void*)TEXT_VIDEO_MEMORY, MEMORY_FLAG_ACCESSIBLE | MEMORY_FLAG_WRITABLE);
- ASSERT(ret == ERR_SUCCESS);
- }
- static void parse_command_line(void)
- {
- static char cmdline_copy[MAX_CMDLINE_LENGTH];
- strcpy(cmdline_copy, cmdline);
- char *token;
- for (token = strtok(cmdline_copy, " "); token != NULL; token = strtok(NULL, " "))
- {
- char *separator = strchr(token, ':');
- if (separator == NULL) continue;
- char *value = separator + 1;
- *separator = '\0';
- if (strcmp(token, "manager") == 0)
- {
- manager_path = value;
- }
- else if (strcmp(token, "debug") == 0)
- {
- char *ptr = strchr(value, ',');
- if (ptr)
- {
- *ptr = '\0';
- log_level_t min_level = *(ptr + 1) - '0';
- if (min_level >= LOG_DEBUG || min_level <= LOG_CRITICAL) debug_min_level = min_level;
- }
- debug_channel = value;
- }
- }
- }
- static handle_t start_system_manager(void)
- {
- char *root_disk = strdup(manager_path);
- char *slash = strchr(root_disk, '/');
- if (slash == NULL) KERNEL_CRASH("Invalid or missing system manager path");
- *slash = 0;
- log_write(LOG_NORMAL, "Mounting root disk: %s\n", root_disk);
- dword_t ret = syscall_mount(root_disk, root_disk, NULL, MOUNT_FLAG_READONLY);
- if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot mount root disk");
- free(root_disk);
- handle_t manager_process;
- handle_t main_thread;
- process_params_t parameters;
- parameters.command_line = cmdline;
- parameters.standard_input = INVALID_HANDLE;
- parameters.standard_output = INVALID_HANDLE;
- parameters.standard_error = INVALID_HANDLE;
- log_write(LOG_NORMAL, "Starting the system manager: %s\n", manager_path);
- ret = syscall_create_process(manager_path, 0, ¶meters, &manager_process, &main_thread);
- if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot start system manager");
- syscall_close_object(main_thread);
- return manager_process;
- }
- static void draw_progress_bar(void)
- {
- static const char text[] = "The Monolithium kernel is loading, please wait...";
- word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
- memset(video_mem, 0x00, TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t));
- int i;
- size_t length = sizeof(text) - 1;
- size_t text_start = 10 * TEXT_WIDTH + (TEXT_WIDTH - length) / 2;
- for (i = 0; i < length; i++) video_mem[text_start + i] = text[i] | 0x0700;
- video_mem[11 * TEXT_WIDTH + 14] = 0x07DA;
- for (i = 15; i < TEXT_WIDTH - 15; i++) video_mem[11 * TEXT_WIDTH + i] = 0x07C4;
- video_mem[12 * TEXT_WIDTH - 15] = 0x07BF;
- video_mem[12 * TEXT_WIDTH + 14] = video_mem[13 * TEXT_WIDTH - 15] = 0x07B3;
- video_mem[13 * TEXT_WIDTH + 14] = 0x07C0;
- for (i = 15; i < TEXT_WIDTH - 15; i++) video_mem[13 * TEXT_WIDTH + i] = 0x07C4;
- video_mem[14 * TEXT_WIDTH - 15] = 0x07D9;
- }
- static void advance_progress(void)
- {
- word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
- size_t old_status = tasks_completed * 50 / num_tasks;
- size_t new_status = (tasks_completed + 1) * 50 / num_tasks;
- int i;
- for (i = old_status; i < new_status; i++) video_mem[12 * TEXT_WIDTH + i + 15] = 0x7020;
- tasks_completed++;
- }
- void kernel_main(uintptr_t mboot_tags, size_t mboot_size)
- {
- log_write(LOG_NORMAL, "Monolithium 0.1\n");
- pre_initialization();
- log_write(LOG_NORMAL, "Pre-initialization complete\n");
- draw_progress_bar();
- DO_TASK(setup_memory_management, mboot_tags, mboot_size);
- area_t area = {
- .pages = memory_find_page_by_address(mboot_tags),
- .count = PAGE_NUMBER(PAGE_ALIGN_UP(mboot_size))
- };
- multiboot_tag_t *mboot = NULL;
- memory_view_area(memory_upper_space, (void**)&mboot, &area, MEMORY_FLAG_ACCESSIBLE | MEMORY_FLAG_STICKY);
- mboot = (multiboot_tag_t*)((uintptr_t)mboot + PAGE_OFFSET(mboot_tags));
- DO_TASK(scan_multiboot_info, mboot);
- DO_TASK(parse_command_line);
- if (kernel_sections) load_kernel_symbols();
- DO_TASK(device_init);
- DO_TASK(timer_init);
- DO_TASK(clock_init);
- DO_TASK(process_init);
- DO_TASK(thread_init);
- thread_t *idle;
- ASSERT(create_system_thread(system_idle_thread, 0, THREAD_PRIORITY_IDLE, 0, NULL, &idle) == ERR_SUCCESS);
- DO_TASK(user_init);
- DO_TASK(pci_init);
- DO_TASK(video_init);
- memory_unmap_clear_area(memory_default_table,
- (void*)TEXT_VIDEO_MEMORY,
- PAGE_NUMBER(PAGE_ALIGN_UP(TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t))));
- video_initialized = TRUE;
- multiboot_tag_t *tag;
- for (tag = mboot; tag->type != MULTIBOOT_INFO_END; tag = (multiboot_tag_t*)(((uintptr_t)tag + tag->size + 7) & ~7))
- {
- if (tag->type == MULTIBOOT_INFO_MODULES)
- {
- multiboot_tag_module_t *module = (multiboot_tag_module_t*)tag;
- module_t *mod = (module_t*)malloc(sizeof(module_t));
- mod->physical_address = module->mod_start;
- mod->size = module->mod_end - module->mod_start;
- dword_t ret = module_load_from_physical(mod, module->string);
- if (ret == ERR_SUCCESS)
- {
- log_write(LOG_NORMAL, "Loaded module %s at 0x%08X\n", mod->name, mod->base_address);
- }
- else
- {
- if (mod->name) log_write(LOG_ERROR, "Cannot load module %s: %s\n", mod->name, get_error_string(ret));
- else log_write(LOG_ERROR, "Cannot load module from physical address 0x%08X: %s\n", module->mod_start, get_error_string(ret));
- free(mod);
- }
- advance_progress();
- // TODO: Reclaim pages
- }
- }
- handle_t manager_process = DO_TASK(start_system_manager);
- syscall_wait_for_one(manager_process, NULL, NO_TIMEOUT);
- KERNEL_CRASH("The system manager has stopped working");
- ASSERT(FALSE);
- }
|