From 72bb80a9ae3bf1c705e7a31f54409d84a4fb1e3b Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 16 Oct 2018 11:06:35 +0200 Subject: [PATCH] These changes were lying around uncommitted in the old repo. I'm just gonna commit them without too much thinking and then take it from there. --- Kernel/Syscall.cpp | 2 +- Kernel/Task.cpp | 136 +++++++++++++++++++++---------------------- Kernel/Task.h | 14 +++-- Kernel/Userspace.cpp | 5 ++ Kernel/Userspace.h | 1 + Kernel/i8253.cpp | 9 +-- Kernel/init.cpp | 3 +- Kernel/types.h | 5 ++ 8 files changed, 94 insertions(+), 81 deletions(-) diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 0540dd8247..163b11af74 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -102,7 +102,7 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) kprintf( "%c", arg1 & 0xFF ); break; case Syscall::Sleep: - kprintf("syscall: sleep(%d)\n", arg1); + //kprintf("syscall: sleep(%d)\n", arg1); current->sys$sleep(arg1); break; case Syscall::PosixOpen: diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 672883930d..b38b37335f 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -8,45 +8,48 @@ #include "FileSystem.h" Task* current; -static Task* kt; -Task* Task::s_kernelTask; +Task* s_kernelTask; static pid_t next_pid; static DoublyLinkedList* s_tasks; -PRIVATE void context_switch(Task*); +static bool contextSwitch(Task*); -static void redo_kt_td() +static void redoKernelTaskTSS() { - Descriptor td; + if (!s_kernelTask->selector()) + s_kernelTask->setSelector(allocateGDTEntry()); - td.setBase(&kt->tss()); - td.setLimit(0xffff); - td.dpl = 0; - td.segment_present = 1; - td.granularity = 1; - td.zero = 0; - td.operation_size = 1; - td.descriptor_type = 0; - td.type = 9; + auto& tssDescriptor = getGDTEntry(s_kernelTask->selector()); - if (!kt->selector()) - kt->setSelector(allocateGDTEntry()); + tssDescriptor.setBase(&s_kernelTask->tss()); + tssDescriptor.setLimit(0xffff); + tssDescriptor.dpl = 0; + tssDescriptor.segment_present = 1; + tssDescriptor.granularity = 1; + tssDescriptor.zero = 0; + tssDescriptor.operation_size = 1; + tssDescriptor.descriptor_type = 0; + tssDescriptor.type = 9; - writeGDTEntry(kt->selector(), td); flushGDT(); } +void Task::prepForIRETToNewTask() +{ + redoKernelTaskTSS(); + s_kernelTask->tss().backlink = current->selector(); + loadTaskRegister(s_kernelTask->selector()); +} + void Task::initialize() { current = nullptr; next_pid = 0; - Task::s_kernelTask = nullptr; s_tasks = new DoublyLinkedList; - - kt = new Task(0, "dummy", IPC::Handle::Any, Task::Ring0); - - redo_kt_td(); + s_kernelTask = new Task(0, "idle", IPC::Handle::Any, Task::Ring0); + redoKernelTaskTSS(); + loadTaskRegister(s_kernelTask->selector()); } #ifdef TASK_SANITY_CHECKS @@ -146,17 +149,13 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring) // HACK: Ring2 SS in the TSS is the current PID. m_tss.ss2 = m_pid; - // Get a nice GDT entry @ next context switch. - m_selector = 0; + m_farPtr.offset = 0x12345678; // Don't add task 0 (kernel dummy task) to task list. // FIXME: This doesn't belong in the constructor. if (m_pid == 0) return; - if (m_pid == 1) - s_kernelTask = this; - // Add it to head of task list (meaning it's next to run too, ATM.) s_tasks->prepend(this); @@ -178,21 +177,28 @@ void yield() HANG; } - current->setTicksLeft(1); + //kprintf("%s<%u> yield()\n", current->name().characters(), current->pid()); - // HACK: To avoid ridiculous clock skew, decrement the system uptime - // counter. It's incremented by int 0x50... - --system.uptime; - asm("int $0x50"); + if (!scheduleNewTask()) + return; + + Descriptor& descriptor = getGDTEntry(current->selector()); + descriptor.type = 9; + flushGDT(); + + //kprintf("yield() jumping to new task: %x (%s)\n", current->farPtr().selector, current->name().characters()); + asm( + "ljmp *(%%eax)\n" + ::"a"(¤t->farPtr()) + ); } -void sched() +bool scheduleNewTask() { if (!current) { // XXX: The first ever context_switch() goes to the idle task. // This to setup a reliable place we can return to. - context_switch(Task::kernelTask()); - return; + return contextSwitch(Task::kernelTask()); } // Check and unblock tasks whose wait conditions have been met. @@ -226,20 +232,20 @@ void sched() if (task->state() == Task::Runnable || task->state() == Task::Running) { //kprintf("switch to %s\n", task->name().characters()); - context_switch(task); - return; + return contextSwitch(task); } if (task == prevHead) { // Back at task_head, nothing wants to run. - context_switch(Task::kernelTask()); - return; + return contextSwitch(Task::kernelTask()); } } } static void drawSchedulerBanner(Task& task) { + // FIXME: We need a kernel lock to do stuff like this :( + //return; auto c = vga_get_cursor(); auto a = vga_get_attr(); vga_set_cursor(0, 50); @@ -257,10 +263,14 @@ static void drawSchedulerBanner(Task& task) vga_set_cursor(c); } -static void context_switch(Task* t) +static bool contextSwitch(Task* t) { + //kprintf("c_s to %s (same:%u)\n", t->name().characters(), current == t); t->setTicksLeft(5); + if (current == t) + return false; + // If the last task hasn't blocked (still marked as running), // mark it as runnable for the next round. if (current->state() == Task::Running) @@ -269,37 +279,27 @@ static void context_switch(Task* t) current = t; t->setState(Task::Running); - // You might be looking at the slowest i386 context switcher ever made. - // (But I don't think so.) - - Descriptor td; - - td.limit_hi = 0; - td.limit_lo = 0xFFFF; - td.base_lo = (DWORD)(&t->tss()) & 0xFFFF; - td.base_hi = ((DWORD)(&t->tss()) >> 16) & 0xFF; - td.base_hi2 = ((DWORD)(&t->tss()) >> 24) & 0xFF; - td.dpl = 0; - td.segment_present = 1; - td.granularity = 1; - td.zero = 0; - td.operation_size = 1; - td.descriptor_type = 0; - td.type = 11; - - if (!t->selector()) { + if (!t->selector()) t->setSelector(allocateGDTEntry()); - writeGDTEntry(t->selector(), td); - flushGDT(); - } else { - writeGDTEntry(t->selector(), td); - } + auto& tssDescriptor = getGDTEntry(t->selector()); + + tssDescriptor.limit_hi = 0; + tssDescriptor.limit_lo = 0xFFFF; + tssDescriptor.base_lo = (DWORD)(&t->tss()) & 0xFFFF; + tssDescriptor.base_hi = ((DWORD)(&t->tss()) >> 16) & 0xFF; + tssDescriptor.base_hi2 = ((DWORD)(&t->tss()) >> 24) & 0xFF; + tssDescriptor.dpl = 0; + tssDescriptor.segment_present = 1; + tssDescriptor.granularity = 1; + tssDescriptor.zero = 0; + tssDescriptor.operation_size = 1; + tssDescriptor.descriptor_type = 0; + tssDescriptor.type = 11; // Busy TSS + + flushGDT(); drawSchedulerBanner(*t); - - redo_kt_td(); - kt->tss().backlink = t->selector(); - loadTaskRegister(kt->selector()); + return true; } Task* Task::fromPID(pid_t pid) diff --git a/Kernel/Task.h b/Kernel/Task.h index fcaa9848fe..7078a94c25 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -46,11 +46,13 @@ public: const String& name() const { return m_name; } pid_t pid() const { return m_pid; } DWORD ticks() const { return m_ticks; } - WORD selector() const { return m_selector; } + WORD selector() const { return m_farPtr.selector; } TSS32& tss() { return m_tss; } State state() const { return m_state; } IPC::Handle handle() const { return m_handle; } + const FarPtr& farPtr() const { return m_farPtr; } + FileHandle* fileHandleIfExists(int fd); FileHandle* createFileHandle(); @@ -62,10 +64,12 @@ public: void setWakeupTime(DWORD t) { m_wakeupTime = t; } DWORD wakeupTime() const { return m_wakeupTime; } + static void prepForIRETToNewTask(); + bool tick() { ++m_ticks; return --m_ticksLeft; } void setTicksLeft(DWORD t) { m_ticksLeft = t; } - void setSelector(WORD s) { m_selector = s; } + void setSelector(WORD s) { m_farPtr.selector = s; } void setState(State s) { m_state = s; } uid_t sys$getuid(); @@ -104,7 +108,7 @@ private: DWORD m_ticksLeft { 0 }; IPC::Handle m_handle { 0 }; DWORD m_stackTop { 0 }; - WORD m_selector { 0 }; + FarPtr m_farPtr; State m_state { Invalid }; DWORD m_wakeupTime { 0 }; TSS32 m_tss; @@ -112,13 +116,11 @@ private: Vector m_fileHandles; RingLevel m_ring { Ring0 }; int m_error { 0 }; - - static Task* s_kernelTask; }; extern void task_init(); extern void yield(); -extern void sched(); +extern bool scheduleNewTask(); extern void block(Task::State); extern void sleep(DWORD ticks); diff --git a/Kernel/Userspace.cpp b/Kernel/Userspace.cpp index 539d94748d..eee7fdde9f 100644 --- a/Kernel/Userspace.cpp +++ b/Kernel/Userspace.cpp @@ -39,4 +39,9 @@ void sleep(DWORD ticks) DO_SYSCALL_A1(Syscall::Sleep, ticks); } +void yield() +{ + DO_SYSCALL_A0(Syscall::Yield); +} + } diff --git a/Kernel/Userspace.h b/Kernel/Userspace.h index 3f83556b6c..1a8f0a1857 100644 --- a/Kernel/Userspace.h +++ b/Kernel/Userspace.h @@ -11,5 +11,6 @@ int seek(int fd, int offset); int kill(pid_t pid, int sig); uid_t getuid(); void sleep(DWORD ticks); +void yield(); } diff --git a/Kernel/i8253.cpp b/Kernel/i8253.cpp index 3b114c0f73..42eea444b5 100644 --- a/Kernel/i8253.cpp +++ b/Kernel/i8253.cpp @@ -94,6 +94,7 @@ void clock_handle() if (current->tick()) return; + //return; auto& regs = *reinterpret_cast(state_dump); current->tss().gs = regs.gs; @@ -131,12 +132,12 @@ void clock_handle() // Add 12 for CS, EIP, EFLAGS (interrupt mechanic) current->tss().esp = regs.esp + 12; - // Prepare a new task to run. - sched(); + // Prepare a new task to run; + if (!scheduleNewTask()) + return; + Task::prepForIRETToNewTask(); // Set the NT (nested task) flag. - // sched() has LTRed a dummy task with a backlink to the next task. - // This is probably super slow/stupid, but I'm just learning... asm( "pushf\n" "orl $0x00004000, (%esp)\n" diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 7351e0c5af..746467e08a 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -111,12 +111,11 @@ void init() extern void panel_main(); - new Task(0, "KernelTask", IPC::Handle::Any, Task::Ring0); new Task(panel_main, "panel", IPC::Handle::PanelTask, Task::Ring0); //new Task(led_disco, "led-disco", IPC::Handle::Any, Task::Ring0); - sched(); + scheduleNewTask(); enableInterrupts(); banner(); diff --git a/Kernel/types.h b/Kernel/types.h index 168960ccae..b69b2af662 100644 --- a/Kernel/types.h +++ b/Kernel/types.h @@ -63,3 +63,8 @@ typedef DWORD gid_t; typedef int pid_t; typedef DWORD time_t; typedef DWORD size_t; + +struct FarPtr { + DWORD offset { 0 }; + WORD selector { 0 }; +} PACKED;