#include "paging.h" #include "window.h" #include "drive.h" #include "panic.h" #include "cmos.h" #include "pmap.h" #include "task.h" #include "util.h" #include "elf.h" #include "idt.h" #include "kbd.h" #include "log.h" enum { IDT_PRESENT = 0x80, IDT_INT = 0x0e, }; struct idt_entry { uint16_t addr_low; uint16_t cs; uint8_t zero; uint8_t flags; uint16_t addr_high; } __attribute__ ((packed)); struct idt_entry idt[256]; struct { uint16_t limit; uint32_t start; } __attribute__ ((packed)) idtr = { .limit = 256 * sizeof(struct idt_entry) - 1, .start = (uint32_t)idt }; //file handles as (drive_number << 8) + file_id_t uint32_t sc_open_file(uint32_t drive_number, char *path) { return (drive_number << 8) + drives[drive_number].get_file(drives + drive_number, path); } void sc_close_file(uint32_t handle) { if (!handle) return; drives[handle >> 8].free_file(drives + (handle >> 8), handle & 0xff); } uint32_t sc_file_get_size(uint32_t handle) { if (!handle) return 0; return drives[handle >> 8].get_file_length(drives + (handle >> 8), handle & 0xff); } void sc_file_set_size(uint32_t handle, uint32_t new_size) { if (!handle) return; drives[handle >> 8].set_file_length(drives + (handle >> 8), handle & 0xff, new_size); } uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { if (!handle) return 0; uint32_t len = sc_file_get_size(handle); if (file_offset + count > len) count = len - file_offset; fmcpy(buffer, drives + (handle >> 8), handle & 0xff, file_offset, count); return count; } uint32_t sc_file_write(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { if (!handle) return 0; const struct drive *const d = drives + (handle >> 8); const fs_id_t fid = handle & 0xff; if (!d->is_writable(d, fid)) return 0; const uint32_t l = d->get_file_length(d, fid); if (file_offset + count > l) count = l - file_offset; mfcpy(d, fid, file_offset, buffer, count); return count; } uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass, uint32_t io_task) { switch_to_kernel_cr3(); uint32_t process_id = try_elf_run(drives + drive_number, vma_to_pma(active_task->page_directory, path), pass, io_task); switch_to_task_cr3(); return process_id; } void *sc_allocate_ram(uint32_t pages) { return pd_user_allocate_anywhere_writable(active_task->page_directory, pages); } enum mi_arg { MI_KERNEL_MAX, MI_KERNEL_LEFT, MI_USER_MAX, MI_USER_LEFT, MI_TASK_LEFT }; __attribute__ ((pure)) uint32_t sc_memory_info(enum mi_arg arg) { switch (arg) { case MI_KERNEL_MAX: return max_kernel_pages; case MI_KERNEL_LEFT: return kernel_pages_left; case MI_USER_MAX: return max_user_pages; case MI_USER_LEFT: return user_pages_left; case MI_TASK_LEFT: PANIC("TODO: memory info task left"); default: return -1; } } void sc_wait_for_task(uint32_t handle) { add_wait((struct wait){.mode = PROCESS_END, .task = tasks + handle - 1}); } uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct directory_content_info *buffer, uint32_t max_entries) { //not static to ensure sysv abi return drives[drive_number].enumerate_dir(drives + drive_number, path, buffer, max_entries); } uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) { return drives[drive_number].n_dir_entries(drives + drive_number, path); } void sc_get_next_window_action(struct window *w, struct window_action *action) { *action = next_window_action(w); } void sc_wait_window_action() { add_wait((struct wait){.mode = WINDOW_ACTION}); } void sc_wait_ipc_sent(uint32_t task_handle) { add_wait((struct wait){.mode = IPC_SENT, .task = tasks + task_handle - 1}); } void sc_system_log(const char *sz) { logf(LOG_USER, "[%s] %s", active_task->name, sz); } void sc_wait_any_ipc_sent() { add_wait((struct wait){.mode = IPC_SENT_ANY}); } void sc_wait_ipc_read(uint32_t handle) { add_wait((struct wait){.mode = IPC_READ, .task = tasks + handle - 1}); } //returns a uint32_t to ensure upper twenty-four bits of // eax are set to zero - otherwise userland stuff break __attribute__ ((pure)) uint32_t sc_is_task_running(uint32_t handle) { return tasks[handle - 1].page_directory ? 1 : 0; } static const uint16_t days_into_four_years_per_month[] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 366+31, 366+59, 366+90, 366+120, 366+151, 366+181, 366+212, 366+243, 366+273, 366+304, 366+334, 731, 731+31, 731+59, 731+90, 731+120, 731+151, 731+181, 731+212, 731+243, 731+273, 731+304, 731+334, 1096, 1096+31, 1096+59, 1096+90, 1096+120, 1096+151, 1096+181, 1096+212, 1096+243, 1096+273, 1096+304, 1096+334 }; //gregorian, assumes year is in 2001 to 2099 uint32_t sc_get_timestamp() { const struct rtc_time time = get_rtc_time(); const uint32_t secs_into_month = time.seconds + time.minutes * 60 + time.hours * 3600 + (time.day_of_month - 1) * 86400; const uint32_t days_to_month_into_four_years = days_into_four_years_per_month[time.month + (time.year % 4) * 12 - 1]; return secs_into_month + days_to_month_into_four_years * 86400 + (time.year / 4) * (365 * 4 + 1) * 86400; } void const *syscall_table[] = { &sc_open_file, &sc_close_file, &sc_file_read, &sc_file_get_size, &sc_start_task, &ipc_send, &ipc_read, &sc_allocate_ram, &sc_memory_info, &sc_wait_for_task, &sc_enumerate_dir, &sc_system_log, &sc_count_of_dir, &new_window, &del_window, &resize_window, &reassign_pixel_buffer, &push_window_paint, &sc_get_next_window_action, &sc_wait_window_action, &sc_wait_ipc_sent, &sc_wait_any_ipc_sent, &find_unread_ipc, &sc_wait_ipc_read, &sc_is_task_running, &sc_get_timestamp, &sc_file_write, &sc_file_set_size }; //these aren't really void ()'s, but gcc complains if we take an address of a void, so we give it a type typedef void isr_t(); extern isr_t syscall_isr; extern isr_t quit_isr; extern isr_t yield_isr; extern isr_t kbd_isr; extern isr_t udf_isr; extern isr_t dfa_isr; extern isr_t tsf_isr; extern isr_t npf_isr; extern isr_t ssf_isr; extern isr_t gpf_isr; extern isr_t pff_isr; enum { F_ID = 0x00200000, F_VIP = 0x00100000, F_VIF = 0x00080000, F_AC = 0x00040000, F_VM = 0x00020000, F_RF = 0x00010000, F_NT = 0x00004000, F_OF = 0x00000800, F_DF = 0x00000400, F_IF = 0x00000200, F_TF = 0x00000100, F_SF = 0x00000080, F_ZF = 0x00000040, F_AF = 0x00000010, F_PF = 0x00000004, F_CF = 0x00000001, F_IOPL_MASK = 0x00003000 }; __attribute__ ((noreturn)) void exception_halt(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx, uint32_t esi, uint32_t edi, const char *id, uint32_t code, uint32_t eip, uint32_t cs, uint32_t eflags, uint32_t esp, uint32_t ss) { if (code) logf(LOG_ERROR, "Exception #%s (0x%h) in %s", id, code, active_task->name); else logf(LOG_ERROR, "Exception #%s in %s:", id, active_task->name); logf(LOG_ERROR, " cs: 0x%hb ss: 0x%hb", cs, ss); logf(LOG_ERROR, " eip: 0x%h esp: 0x%h", eip, esp); logf(LOG_ERROR, " eax: 0x%h ebx: 0x%h", eax, ebx); logf(LOG_ERROR, " ecx: 0x%h edx: 0x%h", ecx, edx); logf(LOG_ERROR, " esi: 0x%h edi: 0x%h", esi, edi); logf(LOG_ERROR, " eflags:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", eflags & F_ID ? " ID" : "", eflags & F_VIP ? " VIP" : "", eflags & F_VIF ? " VIF" : "", eflags & F_AC ? " AC" : "", eflags & F_VM ? " VM" : "", eflags & F_RF ? " RF" : "", eflags & F_NT ? " NT" : "", eflags & F_OF ? " OF" : "", eflags & F_DF ? " DF" : "", eflags & F_IF ? " IF" : "", eflags & F_TF ? " TF" : "", eflags & F_SF ? " SF" : "", eflags & F_ZF ? " ZF" : "", eflags & F_AF ? " AF" : "", eflags & F_PF ? " PF" : "", eflags & F_CF ? " CF" : "", eflags & ~F_IOPL_MASK ? "" : " none"); logf(LOG_ERROR, " iopl: %d", (eflags >> 12) & 3); logf(LOG_INFO, "Killing %s.", active_task->name); quit_isr(); __builtin_unreachable(); } #define MAX_STACK_EXPAND_PAGES 256 //returns true if stack was expanded bool pf_check_stack(uint32_t cr2) { if (cr2 >= active_task->stack_bottom - 0x1000 * MAX_STACK_EXPAND_PAGES) { switch_to_kernel_cr3(); pd_user_allocate(active_task->page_directory, active_task->stack_bottom -= 4096, 1, true); switch_to_task_cr3(); return true; } else { logf(LOG_ERROR, "Illegal access of 0x%h", cr2); return false; } } static void register_int(uint8_t n, isr_t *isr, uint8_t dpl) { idt[n].addr_low = (uint32_t)isr & 0xffff; idt[n].addr_high = (uint32_t)isr >> 16; idt[n].cs = 0x10; idt[n].flags = IDT_PRESENT | (dpl << 5) | IDT_INT; } enum { PIC_MCMD = 0x0020, PIC_MDATA = 0x0021, PIC_SCMD = 0x00a0, PIC_SDATA = 0x00a1 }; enum { PIC_RESET = 0x11 }; void init_idt() { for (uint16_t i = 0; i < 256; ++i) { idt[i].flags = 0; idt[i].zero = 0; } register_int(0x30, &syscall_isr, 3); register_int(0x38, &quit_isr, 3); register_int(0x39, &yield_isr, 3); register_int(0x21, &kbd_isr, 0); register_int(0x08, &udf_isr, 0); register_int(0x08, &dfa_isr, 0); register_int(0x0a, &tsf_isr, 0); register_int(0x0b, &npf_isr, 0); register_int(0x0c, &ssf_isr, 0); register_int(0x0d, &gpf_isr, 0); register_int(0x0e, &pff_isr, 0); outb(PIC_MCMD, PIC_RESET); outb(PIC_SCMD, PIC_RESET); outb(PIC_MDATA, 0x20); outb(PIC_SDATA, 0x28); outb(PIC_MDATA, 0x04); outb(PIC_SDATA, 0x02); outb(PIC_MDATA, 0x01); outb(PIC_SDATA, 0x01); outb(PIC_MDATA, 0xfd); outb(PIC_SDATA, 0xff); asm volatile ( "lidt %0" : : "m" (idtr) : "al"); }