start.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. * start.c
  3. *
  4. * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <boot/multiboot.h>
  20. #include <common.h>
  21. #include <log.h>
  22. #include <cpu.h>
  23. #include <memory.h>
  24. #include <heap.h>
  25. #include <segments.h>
  26. #include <interrupt.h>
  27. #include <timer.h>
  28. #include <clock.h>
  29. #include <process.h>
  30. #include <thread.h>
  31. #include <exception.h>
  32. #include <video.h>
  33. #include <device.h>
  34. #include <power.h>
  35. #include <module.h>
  36. #include <exec/elf.h>
  37. #define DO_TASK(x, ...) x(__VA_ARGS__); advance_progress()
  38. #define MAX_CMDLINE_LENGTH 256
  39. extern void (*_end)();
  40. static char cmdline[MAX_CMDLINE_LENGTH] = "";
  41. static multiboot_tag_sections_t *kernel_sections = NULL;
  42. static size_t tasks_completed = 0, num_tasks = 12;
  43. static const char *manager_path = "";
  44. bool_t video_initialized = FALSE;
  45. const elf32_symbol_t *kernel_symtab = NULL;
  46. dword_t kernel_symcount = 0;
  47. const char *kernel_strtab = NULL;
  48. void *get_kernel_symbol(const char *name)
  49. {
  50. int i;
  51. for (i = 0; i < kernel_symcount; i++)
  52. {
  53. if (strcmp(name, &kernel_strtab[kernel_symtab[i].st_name]) == 0)
  54. {
  55. return (void*)kernel_symtab[i].st_value;
  56. }
  57. }
  58. return NULL;
  59. }
  60. const char *lookup_kernel_symbol_name(uintptr_t address)
  61. {
  62. int i;
  63. for (i = 0; i < kernel_symcount; i++)
  64. {
  65. if (address >= kernel_symtab[i].st_value && address < (kernel_symtab[i].st_value + kernel_symtab[i].st_size))
  66. {
  67. return &kernel_strtab[kernel_symtab[i].st_name];
  68. }
  69. }
  70. return NULL;
  71. }
  72. static dword_t __attribute__((__noreturn__)) system_idle_thread(void *param)
  73. {
  74. UNUSED_PARAMETER(param);
  75. while (TRUE)
  76. {
  77. syscall_yield_quantum();
  78. cpu_halt();
  79. }
  80. }
  81. static void pre_initialization(void)
  82. {
  83. cpu_init();
  84. segments_init();
  85. interrupt_init();
  86. syscalls_init();
  87. irq_init();
  88. exceptions_init();
  89. object_init();
  90. cpu_enable_interrupts();
  91. }
  92. static void scan_multiboot_info(multiboot_tag_t *mboot)
  93. {
  94. multiboot_tag_t *tag;
  95. for (tag = mboot; tag->type != MULTIBOOT_INFO_END; tag = (multiboot_tag_t*)(((uintptr_t)tag + tag->size + 7) & ~7))
  96. {
  97. switch (tag->type)
  98. {
  99. case MULTIBOOT_INFO_CMDLINE:
  100. strncpy(cmdline, ((multiboot_tag_cmdline_t*)tag)->string, sizeof(cmdline));
  101. break;
  102. case MULTIBOOT_INFO_MODULES:
  103. num_tasks++;
  104. break;
  105. case MULTIBOOT_INFO_SECTIONS:
  106. kernel_sections = (multiboot_tag_sections_t*)tag;
  107. break;
  108. }
  109. }
  110. }
  111. static bool_t load_kernel_symbols()
  112. {
  113. int i;
  114. const elf32_section_t *sections = (elf32_section_t*)(kernel_sections + 1);
  115. for (i = 0; i < kernel_sections->num; i++)
  116. {
  117. if (sections[i].sh_type == ELF_SECTION_TYPE_SYMTAB && !kernel_symtab)
  118. {
  119. area_t area = {
  120. .pages = memory_find_page_by_address(sections[i].sh_addr),
  121. .count = PAGE_NUMBER(PAGE_ALIGN_UP(sections[i].sh_size))
  122. };
  123. ASSERT(area.pages);
  124. if (memory_view_area(memory_upper_space, (void**)&kernel_symtab, &area, MEMORY_FLAG_ACCESSIBLE) != ERR_SUCCESS) continue;
  125. kernel_symcount = sections[i].sh_size / sizeof(elf32_symbol_t);
  126. }
  127. else if (sections[i].sh_type == ELF_SECTION_TYPE_STRTAB && i != kernel_sections->shndx && !kernel_strtab)
  128. {
  129. area_t area = {
  130. .pages = memory_find_page_by_address(sections[i].sh_addr),
  131. .count = PAGE_NUMBER(PAGE_ALIGN_UP(sections[i].sh_size))
  132. };
  133. ASSERT(area.pages);
  134. if (memory_view_area(memory_upper_space, (void**)&kernel_strtab, &area, MEMORY_FLAG_ACCESSIBLE) != ERR_SUCCESS) continue;
  135. }
  136. }
  137. if (!kernel_symtab || !kernel_strtab)
  138. {
  139. if (kernel_symtab) memory_free(memory_upper_space, (void*)kernel_symtab);
  140. if (kernel_strtab) memory_free(memory_upper_space, (void*)kernel_strtab);
  141. kernel_symcount = 0;
  142. return FALSE;
  143. }
  144. return TRUE;
  145. }
  146. static void setup_memory_management(uintptr_t mboot_tags, size_t mboot_size)
  147. {
  148. memory_init(mboot_tags, mboot_size);
  149. heap_init();
  150. memory_claim_physical_region(0xA0000, 0x20000, PAGE_STATUS_RESERVED);
  151. page_t *page = memory_find_page_by_address(TEXT_VIDEO_MEMORY);
  152. ASSERT(page);
  153. area_t area = { .pages = page, .count = 8 };
  154. sysret_t ret = memory_map_area(memory_default_table, &area, (void*)TEXT_VIDEO_MEMORY, MEMORY_FLAG_ACCESSIBLE | MEMORY_FLAG_WRITABLE);
  155. ASSERT(ret == ERR_SUCCESS);
  156. }
  157. static void parse_command_line(void)
  158. {
  159. static char cmdline_copy[MAX_CMDLINE_LENGTH];
  160. strcpy(cmdline_copy, cmdline);
  161. char *token;
  162. for (token = strtok(cmdline_copy, " "); token != NULL; token = strtok(NULL, " "))
  163. {
  164. char *separator = strchr(token, ':');
  165. if (separator == NULL) continue;
  166. char *value = separator + 1;
  167. *separator = '\0';
  168. if (strcmp(token, "manager") == 0)
  169. {
  170. manager_path = value;
  171. }
  172. else if (strcmp(token, "debug") == 0)
  173. {
  174. char *ptr = strchr(value, ',');
  175. if (ptr)
  176. {
  177. *ptr = '\0';
  178. log_level_t min_level = *(ptr + 1) - '0';
  179. if (min_level >= LOG_DEBUG || min_level <= LOG_CRITICAL) debug_min_level = min_level;
  180. }
  181. debug_channel = value;
  182. }
  183. }
  184. }
  185. static handle_t start_system_manager(void)
  186. {
  187. char *root_disk = strdup(manager_path);
  188. char *slash = strchr(root_disk, '/');
  189. if (slash == NULL) KERNEL_CRASH("Invalid or missing system manager path");
  190. *slash = 0;
  191. log_write(LOG_NORMAL, "Mounting root disk: %s\n", root_disk);
  192. dword_t ret = syscall_mount(root_disk, root_disk, NULL, MOUNT_FLAG_READONLY);
  193. if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot mount root disk");
  194. free(root_disk);
  195. handle_t manager_process;
  196. handle_t main_thread;
  197. process_params_t parameters;
  198. parameters.command_line = cmdline;
  199. parameters.standard_input = INVALID_HANDLE;
  200. parameters.standard_output = INVALID_HANDLE;
  201. parameters.standard_error = INVALID_HANDLE;
  202. log_write(LOG_NORMAL, "Starting the system manager: %s\n", manager_path);
  203. ret = syscall_create_process(manager_path, 0, &parameters, &manager_process, &main_thread);
  204. if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot start system manager");
  205. syscall_close_object(main_thread);
  206. return manager_process;
  207. }
  208. static void draw_progress_bar(void)
  209. {
  210. static const char text[] = "The Monolithium kernel is loading, please wait...";
  211. word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
  212. memset(video_mem, 0x00, TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t));
  213. int i;
  214. size_t length = sizeof(text) - 1;
  215. size_t text_start = 10 * TEXT_WIDTH + (TEXT_WIDTH - length) / 2;
  216. for (i = 0; i < length; i++) video_mem[text_start + i] = text[i] | 0x0700;
  217. video_mem[11 * TEXT_WIDTH + 14] = 0x07DA;
  218. for (i = 15; i < TEXT_WIDTH - 15; i++) video_mem[11 * TEXT_WIDTH + i] = 0x07C4;
  219. video_mem[12 * TEXT_WIDTH - 15] = 0x07BF;
  220. video_mem[12 * TEXT_WIDTH + 14] = video_mem[13 * TEXT_WIDTH - 15] = 0x07B3;
  221. video_mem[13 * TEXT_WIDTH + 14] = 0x07C0;
  222. for (i = 15; i < TEXT_WIDTH - 15; i++) video_mem[13 * TEXT_WIDTH + i] = 0x07C4;
  223. video_mem[14 * TEXT_WIDTH - 15] = 0x07D9;
  224. }
  225. static void advance_progress(void)
  226. {
  227. word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
  228. size_t old_status = tasks_completed * 50 / num_tasks;
  229. size_t new_status = (tasks_completed + 1) * 50 / num_tasks;
  230. int i;
  231. for (i = old_status; i < new_status; i++) video_mem[12 * TEXT_WIDTH + i + 15] = 0x7020;
  232. tasks_completed++;
  233. }
  234. void kernel_main(uintptr_t mboot_tags, size_t mboot_size)
  235. {
  236. log_write(LOG_NORMAL, "Monolithium 0.1\n");
  237. pre_initialization();
  238. log_write(LOG_NORMAL, "Pre-initialization complete\n");
  239. draw_progress_bar();
  240. DO_TASK(setup_memory_management, mboot_tags, mboot_size);
  241. area_t area = {
  242. .pages = memory_find_page_by_address(mboot_tags),
  243. .count = PAGE_NUMBER(PAGE_ALIGN_UP(mboot_size))
  244. };
  245. multiboot_tag_t *mboot = NULL;
  246. memory_view_area(memory_upper_space, (void**)&mboot, &area, MEMORY_FLAG_ACCESSIBLE | MEMORY_FLAG_STICKY);
  247. mboot = (multiboot_tag_t*)((uintptr_t)mboot + PAGE_OFFSET(mboot_tags));
  248. DO_TASK(scan_multiboot_info, mboot);
  249. DO_TASK(parse_command_line);
  250. if (kernel_sections) load_kernel_symbols();
  251. DO_TASK(device_init);
  252. DO_TASK(timer_init);
  253. DO_TASK(clock_init);
  254. DO_TASK(process_init);
  255. DO_TASK(thread_init);
  256. thread_t *idle;
  257. ASSERT(create_system_thread(system_idle_thread, 0, THREAD_PRIORITY_IDLE, 0, NULL, &idle) == ERR_SUCCESS);
  258. DO_TASK(user_init);
  259. DO_TASK(pci_init);
  260. DO_TASK(video_init);
  261. memory_unmap_clear_area(memory_default_table,
  262. (void*)TEXT_VIDEO_MEMORY,
  263. PAGE_NUMBER(PAGE_ALIGN_UP(TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t))));
  264. video_initialized = TRUE;
  265. multiboot_tag_t *tag;
  266. for (tag = mboot; tag->type != MULTIBOOT_INFO_END; tag = (multiboot_tag_t*)(((uintptr_t)tag + tag->size + 7) & ~7))
  267. {
  268. if (tag->type == MULTIBOOT_INFO_MODULES)
  269. {
  270. multiboot_tag_module_t *module = (multiboot_tag_module_t*)tag;
  271. module_t *mod = (module_t*)malloc(sizeof(module_t));
  272. mod->physical_address = module->mod_start;
  273. mod->size = module->mod_end - module->mod_start;
  274. dword_t ret = module_load_from_physical(mod, module->string);
  275. if (ret == ERR_SUCCESS)
  276. {
  277. log_write(LOG_NORMAL, "Loaded module %s at 0x%08X\n", mod->name, mod->base_address);
  278. }
  279. else
  280. {
  281. if (mod->name) log_write(LOG_ERROR, "Cannot load module %s: %s\n", mod->name, get_error_string(ret));
  282. else log_write(LOG_ERROR, "Cannot load module from physical address 0x%08X: %s\n", module->mod_start, get_error_string(ret));
  283. free(mod);
  284. }
  285. advance_progress();
  286. // TODO: Reclaim pages
  287. }
  288. }
  289. handle_t manager_process = DO_TASK(start_system_manager);
  290. syscall_wait_for_one(manager_process, NULL, NO_TIMEOUT);
  291. KERNEL_CRASH("The system manager has stopped working");
  292. ASSERT(FALSE);
  293. }