start.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * start.c
  3. *
  4. * Copyright (C) 2016 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. static char cmdline[MAX_CMDLINE_LENGTH] = "";
  40. static uintptr_t lowest_physical = 0;
  41. static multiboot_tag_mmap_t *mmap = NULL;
  42. static multiboot_tag_sections_t *kernel_sections = NULL;
  43. static size_t tasks_completed = 0, num_tasks = 12;
  44. static const char *manager_path = "";
  45. bool_t video_initialized = FALSE;
  46. const elf32_symbol_t *kernel_symtab = NULL;
  47. dword_t kernel_symcount = 0;
  48. const char *kernel_strtab = NULL;
  49. void *get_kernel_symbol(const char *name)
  50. {
  51. int i;
  52. for (i = 0; i < kernel_symcount; i++)
  53. {
  54. if (strcmp(name, &kernel_strtab[kernel_symtab[i].st_name]) == 0)
  55. {
  56. return (void*)kernel_symtab[i].st_value;
  57. }
  58. }
  59. return NULL;
  60. }
  61. const char *lookup_kernel_symbol_name(uintptr_t address)
  62. {
  63. int i;
  64. for (i = 0; i < kernel_symcount; i++)
  65. {
  66. if (address >= kernel_symtab[i].st_value && address < (kernel_symtab[i].st_value + kernel_symtab[i].st_size))
  67. {
  68. return &kernel_strtab[kernel_symtab[i].st_name];
  69. }
  70. }
  71. return NULL;
  72. }
  73. static dword_t __attribute__((__noreturn__)) system_idle_thread(void *param)
  74. {
  75. UNUSED_PARAMETER(param);
  76. while (TRUE)
  77. {
  78. syscall_yield_quantum();
  79. cpu_halt();
  80. }
  81. }
  82. static void pre_initialization(void)
  83. {
  84. cpu_init();
  85. segments_init();
  86. interrupt_init();
  87. syscalls_init();
  88. irq_init();
  89. exceptions_init();
  90. object_init();
  91. cpu_enable_interrupts();
  92. }
  93. static void scan_multiboot_info(multiboot_tag_t *mboot)
  94. {
  95. multiboot_tag_t *tag;
  96. for (tag = mboot; tag->type != MULTIBOOT_INFO_END; tag = (multiboot_tag_t*)(((uintptr_t)tag + tag->size + 7) & ~7))
  97. {
  98. switch (tag->type)
  99. {
  100. case MULTIBOOT_INFO_CMDLINE:
  101. strncpy(cmdline, ((multiboot_tag_cmdline_t*)tag)->string, sizeof(cmdline));
  102. break;
  103. case MULTIBOOT_INFO_MODULES:
  104. {
  105. multiboot_tag_module_t *module = (multiboot_tag_module_t*)tag;
  106. if (module->mod_end > lowest_physical) lowest_physical = module->mod_end;
  107. num_tasks++;
  108. }
  109. break;
  110. case MULTIBOOT_INFO_MEMORY_MAP:
  111. mmap = (multiboot_tag_mmap_t*)tag;
  112. break;
  113. case MULTIBOOT_INFO_SECTIONS:
  114. {
  115. kernel_sections = (multiboot_tag_sections_t*)tag;
  116. elf32_section_t *sections = (elf32_section_t*)(kernel_sections + 1);
  117. int i;
  118. for (i = 0; i < kernel_sections->num; i++)
  119. {
  120. uintptr_t section_end = sections[i].sh_addr + sections[i].sh_size;
  121. if (section_end < 0x80000000 && section_end > lowest_physical) lowest_physical = section_end;
  122. }
  123. }
  124. break;
  125. }
  126. }
  127. }
  128. static bool_t load_kernel_symbols()
  129. {
  130. int i;
  131. const elf32_section_t *sections = (elf32_section_t*)(kernel_sections + 1);
  132. for (i = 0; i < kernel_sections->num; i++)
  133. {
  134. if (sections[i].sh_type == ELF_SECTION_TYPE_SYMTAB && !kernel_symtab)
  135. {
  136. if (map_memory((void*)sections[i].sh_addr, (void**)&kernel_symtab, sections[i].sh_size, MEMORY_BLOCK_ACCESSIBLE) != ERR_SUCCESS)
  137. {
  138. continue;
  139. }
  140. kernel_symcount = sections[i].sh_size / sizeof(elf32_symbol_t);
  141. }
  142. else if (sections[i].sh_type == ELF_SECTION_TYPE_STRTAB && i != kernel_sections->shndx && !kernel_strtab)
  143. {
  144. if (map_memory((void*)sections[i].sh_addr, (void**)&kernel_strtab, sections[i].sh_size, MEMORY_BLOCK_ACCESSIBLE) != ERR_SUCCESS)
  145. {
  146. continue;
  147. }
  148. }
  149. }
  150. if (!kernel_symtab || !kernel_strtab)
  151. {
  152. if (kernel_symtab) unmap_memory((void*)kernel_symtab);
  153. if (kernel_strtab) unmap_memory((void*)kernel_strtab);
  154. kernel_symcount = 0;
  155. return FALSE;
  156. }
  157. return TRUE;
  158. }
  159. static void setup_memory_management(void)
  160. {
  161. if (!mmap) KERNEL_CRASH("The bootloader failed to supply a memory map");
  162. memory_init(mmap, PAGE_ALIGN_UP(lowest_physical));
  163. heap_init();
  164. map_memory_internal((void*)TEXT_VIDEO_MEMORY,
  165. (void*)TEXT_VIDEO_MEMORY,
  166. TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t),
  167. PAGE_PRESENT | PAGE_WRITABLE);
  168. }
  169. static void parse_command_line(void)
  170. {
  171. static char cmdline_copy[MAX_CMDLINE_LENGTH];
  172. strcpy(cmdline_copy, cmdline);
  173. char *token;
  174. for (token = strtok(cmdline_copy, " "); token != NULL; token = strtok(NULL, " "))
  175. {
  176. char *separator = strchr(token, ':');
  177. if (separator == NULL) continue;
  178. char *value = separator + 1;
  179. *separator = '\0';
  180. if (strcmp(token, "manager") == 0)
  181. {
  182. manager_path = value;
  183. }
  184. else if (strcmp(token, "debug") == 0)
  185. {
  186. char *ptr = strchr(value, ',');
  187. if (ptr)
  188. {
  189. *ptr = '\0';
  190. log_level_t min_level = *(ptr + 1) - '0';
  191. if (min_level >= LOG_DEBUG || min_level <= LOG_CRITICAL) debug_min_level = min_level;
  192. }
  193. debug_channel = value;
  194. }
  195. }
  196. }
  197. static handle_t start_system_manager(void)
  198. {
  199. char *root_disk = strdup(manager_path);
  200. char *slash = strchr(root_disk, '/');
  201. if (slash == NULL) KERNEL_CRASH("Invalid or missing system manager path");
  202. *slash = 0;
  203. log_write(LOG_NORMAL, "Mounting root disk: %s\n", root_disk);
  204. dword_t ret = syscall_mount(root_disk, root_disk, NULL, MOUNT_FLAG_READONLY);
  205. if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot mount root disk");
  206. free(root_disk);
  207. handle_t manager_process;
  208. handle_t main_thread;
  209. process_params_t parameters;
  210. parameters.command_line = cmdline;
  211. parameters.standard_input = INVALID_HANDLE;
  212. parameters.standard_output = INVALID_HANDLE;
  213. parameters.standard_error = INVALID_HANDLE;
  214. log_write(LOG_NORMAL, "Starting the system manager: %s\n", manager_path);
  215. ret = syscall_create_process(manager_path, 0, &parameters, &manager_process, &main_thread);
  216. if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot start system manager");
  217. syscall_close_object(main_thread);
  218. return manager_process;
  219. }
  220. static void draw_progress_bar(void)
  221. {
  222. static const char text[] = "The Monolithium kernel is loading, please wait...";
  223. word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
  224. memset(video_mem, 0x00, TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t));
  225. int i;
  226. size_t length = sizeof(text) - 1;
  227. size_t text_start = 10 * TEXT_WIDTH + (TEXT_WIDTH - length) / 2;
  228. for (i = 0; i < length; i++) video_mem[text_start + i] = text[i] | 0x0700;
  229. video_mem[11 * TEXT_WIDTH + 14] = 0x07DA;
  230. for (i = 15; i < TEXT_WIDTH - 15; i++) video_mem[11 * TEXT_WIDTH + i] = 0x07C4;
  231. video_mem[12 * TEXT_WIDTH - 15] = 0x07BF;
  232. video_mem[12 * TEXT_WIDTH + 14] = video_mem[13 * TEXT_WIDTH - 15] = 0x07B3;
  233. video_mem[13 * TEXT_WIDTH + 14] = 0x07C0;
  234. for (i = 15; i < TEXT_WIDTH - 15; i++) video_mem[13 * TEXT_WIDTH + i] = 0x07C4;
  235. video_mem[14 * TEXT_WIDTH - 15] = 0x07D9;
  236. }
  237. static void advance_progress(void)
  238. {
  239. word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
  240. size_t old_status = tasks_completed * 50 / num_tasks;
  241. size_t new_status = (tasks_completed + 1) * 50 / num_tasks;
  242. int i;
  243. for (i = old_status; i < new_status; i++) video_mem[12 * TEXT_WIDTH + i + 15] = 0x7020;
  244. tasks_completed++;
  245. }
  246. void kernel_main(uintptr_t mboot_tags, size_t mboot_size)
  247. {
  248. log_write(LOG_NORMAL, "Monolithium 0.1\n");
  249. pre_initialization();
  250. log_write(LOG_NORMAL, "Pre-initialization complete\n");
  251. draw_progress_bar();
  252. extern int _end;
  253. lowest_physical = PAGE_ALIGN_UP((uintptr_t)&_end) - 0x7FF00000;
  254. if ((mboot_tags + mboot_size) > lowest_physical) lowest_physical = mboot_tags + mboot_size;
  255. multiboot_tag_t *mboot = (multiboot_tag_t*)(PAGE_ALIGN_UP((uintptr_t)&_end) + PAGE_OFFSET(mboot_tags));
  256. map_memory_internal((void*)mboot_tags, mboot, mboot_size, PAGE_PRESENT | PAGE_WRITABLE);
  257. DO_TASK(scan_multiboot_info, mboot);
  258. DO_TASK(parse_command_line);
  259. DO_TASK(setup_memory_management);
  260. if (kernel_sections) load_kernel_symbols();
  261. DO_TASK(device_init);
  262. DO_TASK(timer_init);
  263. DO_TASK(clock_init);
  264. DO_TASK(process_init);
  265. DO_TASK(thread_init);
  266. thread_t *idle;
  267. ASSERT(create_system_thread(system_idle_thread, 0, THREAD_PRIORITY_IDLE, 0, NULL, &idle) == ERR_SUCCESS);
  268. DO_TASK(user_init);
  269. DO_TASK(pci_init);
  270. DO_TASK(video_init);
  271. unmap_memory_internal((void*)TEXT_VIDEO_MEMORY, TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t));
  272. video_initialized = TRUE;
  273. multiboot_tag_t *tag;
  274. for (tag = mboot; tag->type != MULTIBOOT_INFO_END; tag = (multiboot_tag_t*)(((uintptr_t)tag + tag->size + 7) & ~7))
  275. {
  276. if (tag->type == MULTIBOOT_INFO_MODULES)
  277. {
  278. multiboot_tag_module_t *module = (multiboot_tag_module_t*)tag;
  279. module_t *mod = (module_t*)malloc(sizeof(module_t));
  280. mod->physical_address = module->mod_start;
  281. mod->size = module->mod_end - module->mod_start;
  282. dword_t ret = module_load_from_physical(mod, module->string);
  283. if (ret == ERR_SUCCESS)
  284. {
  285. log_write(LOG_NORMAL, "Loaded module %s at 0x%08X\n", mod->name, mod->base_address);
  286. }
  287. else
  288. {
  289. if (mod->name) log_write(LOG_ERROR, "Cannot load module %s: %s\n", mod->name, get_error_string(ret));
  290. else log_write(LOG_ERROR, "Cannot load module from physical address 0x%08X: %s\n", module->mod_start, get_error_string(ret));
  291. free(mod);
  292. }
  293. advance_progress();
  294. // TODO: Reclaim pages
  295. }
  296. }
  297. handle_t manager_process = DO_TASK(start_system_manager);
  298. syscall_wait_for_one(manager_process, NULL, NO_TIMEOUT);
  299. KERNEL_CRASH("The system manager has stopped working");
  300. ASSERT(FALSE);
  301. }