/* kernel.h * Author: Josh Holtrop * Date: 08/16/04 * Modified: 11/02/05 * This is the main kernel initialization and boot-strapping file */ #include "kernel.h" #include "multiboot.h" #include "module.h" #include "lang/lang.h" #include "functions.h" #include "mm/mm.h" #include "mm/vmm.h" #include "lang/conv.h" #include "devices.h" #include "display/display.h" #include "display/kout.h" #include "sys/io.h" #include "sys/pic.h" #include "char/keyboard.h" #include "block/ramdisk.h" #include "fs/vfs.h" #include "fs/ext2/ext2.h" #include "sys/pci.h" #include "proc/proc.h" #include "syscall.h" mb_info_t mb_info_block; mb_mmap_t mb_mmap[MAX_MMAP]; u32_t mmap_entries; mb_module_t mb_modules[MAX_MODULES]; mb_apm_t mb_apm_table; mb_module_t *real_mode_module; // pointer to real mode module (if present) real_mode_param_t rm_params; char mb_cmdline[256]; int criticalCounter; // semaphore for if interrupts are disabled u32_t timer; // number of IRQ 0's extern u32_t mm_freepages; extern u32_t proc_new_esp; extern u32_t cur_task; /* This function runs in segmented memory - 0xC000_0000 is mapped to 0x0 but 0x0 itself is an invalid linear address. Therefore, the multiboot information addresses must be manually adjusted by VIRT_OFFSET to become valid linear addresses. */ mb_module_t *k_mbsave(mb_info_t *mbinfo, unsigned int mb_magic) { real_mode_module = NULL; if (mb_magic != MULTIBOOT_BOOTLOADER_MAGIC) { char *msg = "Bad multiboot magic identifier!"; char *dest = (char *) CONSOLE_MEMORY; while (*msg) { *dest++ = *msg++; *dest++ = 0x04; //red error message } for (;;) ; } mb_info_block = *mbinfo; if (mb_info_block.flags & MB_BOOTLOADER_COMMAND_LINE) { mb_info_block.cmdline += VIRT_OFFSET; memcpy(mb_cmdline, (void *)mb_info_block.cmdline, 256); mb_cmdline[255] = 0; } if (mb_info_block.flags & MB_BOOTLOADER_MODS) { mb_info_block.mods_addr += VIRT_OFFSET; int i; for (i = 0; i < mb_info_block.mods_count && i < MAX_MODULES; i++) { mb_modules[i] = ((mb_module_t *)mb_info_block.mods_addr)[i]; mb_modules[i].mod_start += VIRT_OFFSET; mb_modules[i].mod_end += VIRT_OFFSET; hos_module_header_t *mod = (hos_module_header_t *)mb_modules[i].mod_start; if (mod->mod_magic == 0x4D534F48 && mod->mod_type == MOD_REAL_MODE) real_mode_module = &mb_modules[i]; } } if (mb_info_block.flags & MB_BOOTLOADER_MMAP) { mb_info_block.mmap_addr += (VIRT_OFFSET - 4); //-4 to get to size field, not base_addr_low field mb_mmap_t *mmap = (mb_mmap_t *)mb_info_block.mmap_addr; int i, sz = 0; for (i = 0; sz < mb_info_block.mmap_length && i < MAX_MMAP; i++) { sz += mmap->size + 4; mb_mmap[i] = *mmap; mmap = (mb_mmap_t *)(((u32_t) mmap) + mmap->size + 4); mmap_entries++; } } if (mb_info_block.flags & MB_BOOTLOADER_APM) { mb_info_block.apm_table += VIRT_OFFSET; mb_apm_table = *(mb_apm_t *)mb_info_block.apm_table; } return real_mode_module; } /* Main kernel initialization routine */ void k_init() { criticalCounter++; pic_remap(0x20, 0x28); pic_mask1(0); //unmask IRQ's 0-7 pic_mask2(0); //unmask IRQ's 8-15 timer_init(HOS_TIMER_FREQ); mm_init(); vmm_init(); devices_init(); if (real_mode_module) { if (rm_params.vid_addr) // there is video memory to map in { u32_t vid_mem = rm_params.width * rm_params.height; switch (rm_params.bpp) { case 15: case 16: vid_mem <<= 1; break; case 24: vid_mem *= 3; break; case 32: vid_mem <<= 2; break; } // map in video memory so we can access the video card's LFB vmm_mapn(LFB_MEMORY, (u32_t)rm_params.vid_addr, (vid_mem >> 12) + 1); } } display_init(); // initialize display subsystem kprintf("HOS v0.16 initializing...\n"); kprintf("Kernel load line: '%s'\n", mb_cmdline); kprintf("Kernel load size: %d (0x%x) bytes (%d kb)\n", kernel_size(), kernel_size(), kernel_size() >> 10); kprintf("Kernel memory size: %d (0x%x) bytes (%d kb)\n", kernel_size_used(), kernel_size_used(), kernel_size_used() >> 10); k_check(pci_init(), "pci_init() failed!"); k_check(vfs_init(), "vfs_init() failed!"); k_check(proc_init(), "proc_init() failed!"); int i; for (i = 0; i < mb_info_block.mods_count; i++) { kprintf("Loaded kernel module %d: 0x%x - 0x%x (%d bytes, type %d)\n", i, mb_modules[i].mod_start, mb_modules[i].mod_end, mb_modules[i].mod_end - mb_modules[i].mod_start, ((hos_module_header_t*)mb_modules[i].mod_start)->mod_type); if (((mb_modules[i].mod_end - mb_modules[i].mod_start) > 2048) && ((ext2_super_block_t *)(mb_modules[i].mod_start + 1024))->s_magic == EXT2_MAGIC) { // we found an initrd minor_t initrd_minor = ramdisk_register((void *)mb_modules[i].mod_start, mb_modules[i].mod_end - mb_modules[i].mod_start); kprintf("initrd (%dkb) loaded\n", (mb_modules[i].mod_end - mb_modules[i].mod_start) >> 10); k_check(vfs_mount(DEV(MAJOR_RAMDISK, initrd_minor), "ext2", "/"), "Kernel panic: Could not mount initrd to /!"); } } void *root = vfs_open_dir("///"); char name[VFS_MAX_PATH_LENGTH]; if (root) { vfs_dir_entry_t dentry; vfs_stat_t fstat; while (!vfs_read_dir(root, &dentry)) { strcpy(name, "/"); strcat(name, dentry.name); vfs_stat(name, &fstat); kprintf("%d\t", fstat.inode); putc(fstat.type == VFS_FT_DIR ? 'd' : fstat.type == VFS_FT_CHAR ? 'c' : fstat.type == VFS_FT_BLOCK ? 'b' : fstat.type == VFS_FT_SYMLINK ? 'l' : '-'); putc(fstat.permissions & VFS_PERMS_UR ? 'r' : '-'); putc(fstat.permissions & VFS_PERMS_UW ? 'w' : '-'); putc(fstat.permissions & VFS_PERMS_UX ? 'x' : '-'); putc(fstat.permissions & VFS_PERMS_GR ? 'r' : '-'); putc(fstat.permissions & VFS_PERMS_GW ? 'w' : '-'); putc(fstat.permissions & VFS_PERMS_GX ? 'x' : '-'); putc(fstat.permissions & VFS_PERMS_OR ? 'r' : '-'); putc(fstat.permissions & VFS_PERMS_OW ? 'w' : '-'); putc(fstat.permissions & VFS_PERMS_OX ? 'x' : '-'); kprintf(" %d\t%d\t%d\t%d\t%s", fstat.links, fstat.uid, fstat.gid, fstat.size, dentry.name); if (fstat.type == VFS_FT_CHAR || fstat.type == VFS_FT_BLOCK) kprintf("\t(%d, %d)", fstat.dev >> 8, fstat.dev & 0xFF); if (fstat.type == VFS_FT_SYMLINK) { char *link = kmalloc(4096); vfs_link_deref(name, link); kprintf(" -> %s", link); kfree(link); } putc('\n'); } vfs_close_dir(root); } else kprintf("Error: Could not open directory\n"); /* Create the initial task */ vfs_stat_t stat; if (!vfs_stat(HOS_INIT_TASK, &stat)) { if (stat.permissions & (VFS_PERMS_UX | VFS_PERMS_GX | VFS_PERMS_UX)) { u8_t *buf = kmalloc(stat.size); void *file = vfs_open_file(HOS_INIT_TASK, VFS_MODE_READ); vfs_read_file_block(file, buf, stat.size); vfs_close_file(file); create_task(buf, stat.size, 0, 0); } } criticalCounter--; } void isr(u32_t num, int_stack_t *int_stack) { criticalCounter++; switch (num) { case 0x0: /* divide by zero */ kprintf("divide by zero, current process: %u\n", cur_task); break; case 0x20: // timer timer++; (*(u16_t *)CONSOLE_MEMORY)++; proc_sched(int_stack); pic_eoi(); break; case 0x21: // keyboard isr_keyboard(); pic_eoi(); break; case 0x30: syscall(cur_task, int_stack); break; case 0x0D: /* general protection (error code) */ kprintf("General protection fault process %u, error #%u\n", cur_task, int_stack->error); break; case 0x0E: /* Page fault (error code) */ kprintf("Page fault process %u, error #%u\n", cur_task, int_stack->error); break; case 0x01: /* debug exception */ case 0x02: /* non-maskable interrupt */ case 0x03: /* breakpoint */ case 0x04: /* overflow */ case 0x05: /* bound exception */ case 0x06: /* invalid opcode */ case 0x07: /* FPU not available */ case 0x08: /* Double fault (error code) */ case 0x09: /* coprocessor segment overrun */ case 0x0A: /* invalid TSS (error code) */ case 0x0B: /* segment not present (error code) */ case 0x0C: /* stack exception (error code) */ case 0x10: /* floating point error */ case 0x11: /* alignment check */ case 0x12: /* machine check */ default: kprintf("Unhandled interrupt #%d, CR2 = 0x%x, int_stack at 0x%x!\n", num, read_cr2(), int_stack); halt(); } criticalCounter--; } void k_enter_critical() // functions for implementing "atomic actions" { disable_ints(); criticalCounter++; } void k_leave_critical() { criticalCounter--; if (!criticalCounter) enable_ints(); } void k_check(int val, char *msg) { if (val) { kprintf("\e[31;1m%s\n", msg); halt(); } }