From 79ffdb720564bea95d753f6ebe7815fa0ada3501 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 22 Oct 2018 11:15:16 +0200 Subject: [PATCH] A lot of hacking: - More work on funneling console output through Console. - init() now breaks off into a separate task ASAP. - ..this leaves the "colonel" task as a simple hlt idle loop. - Mask all IRQs on startup (except IRQ2 for slave passthru) - Fix underallocation bug in Task::allocateRegion(). - Remember how many times each Task has been scheduled. The panel and scheduling banner are disabled until I get things working nicely in the (brave) new Console world. --- Kernel/Console.cpp | 25 ++++++- Kernel/IPC.h | 1 + Kernel/MemoryManager.cpp | 2 +- Kernel/PIC.cpp | 12 ++-- Kernel/Task.cpp | 28 ++++++-- Kernel/Task.h | 4 ++ Kernel/VGA.cpp | 37 +++------- Kernel/VGA.h | 3 +- Kernel/i8253.cpp | 9 +++ Kernel/init.cpp | 93 +++++++++++++------------ Kernel/kassert.h | 2 +- Kernel/panel.cpp | 1 + VirtualFileSystem/VirtualFileSystem.cpp | 3 + 13 files changed, 130 insertions(+), 90 deletions(-) diff --git a/Kernel/Console.cpp b/Kernel/Console.cpp index 22fc41754ba..9ea51a8b249 100644 --- a/Kernel/Console.cpp +++ b/Kernel/Console.cpp @@ -27,7 +27,30 @@ ssize_t Console::read(byte* buffer, size_t bufferSize) void Console::putChar(char ch) { - vga_putch(nullptr, ch); + switch (ch) { + case '\n': + m_cursorColumn = 0; + if (m_cursorRow == (m_rows - 2)) { + vga_scroll_up(); + } else { + ++m_cursorRow; + } + vga_set_cursor(m_cursorRow, m_cursorColumn); + return; + } + + vga_putch_at(m_cursorRow, m_cursorColumn, ch); + + ++m_cursorColumn; + if (m_cursorColumn >= m_columns) { + if (m_cursorRow == (m_rows - 2)) { + vga_scroll_up(); + } else { + ++m_cursorRow; + } + m_cursorColumn = 0; + } + vga_set_cursor(m_cursorRow, m_cursorColumn); } ssize_t Console::write(const byte* data, size_t size) diff --git a/Kernel/IPC.h b/Kernel/IPC.h index a15a406effa..be595b7741f 100644 --- a/Kernel/IPC.h +++ b/Kernel/IPC.h @@ -33,6 +33,7 @@ public: FileSystemTask = 4003, MotdTask = 4004, UserTask = 4005, + InitTask = 4006, }; Handle(KernelTask task) : m_data((DWORD)task) { } diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index 6bc79673185..1d85aca254c 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -173,7 +173,7 @@ bool MemoryManager::mapRegionsForTask(Task& task) pte.setWritable(true); pte.setUserAllowed(!task.isRing0()); - kprintf("MM: >> Mapped L%x => P%x <<\n", laddr, zone.m_pages[i].get()); + //kprintf("MM: >> Mapped L%x => P%x <<\n", laddr, zone.m_pages[i].get()); } } return true; diff --git a/Kernel/PIC.cpp b/Kernel/PIC.cpp index e22cc4d9cec..2da6b5eb907 100644 --- a/Kernel/PIC.cpp +++ b/Kernel/PIC.cpp @@ -77,14 +77,12 @@ void initialize() IO::out8(PIC0_CMD, 0x01); IO::out8(PIC1_CMD, 0x01 ); - // Mask -- enable all interrupts on both PICs. - // Not really what I want here, but I'm unsure how to - // selectively enable secondary PIC IRQs... - IO::out8(PIC0_CMD, 0x00); - IO::out8(PIC1_CMD, 0x00); + // Mask -- start out with all IRQs disabled. + IO::out8(PIC0_CMD, 0xff); + IO::out8(PIC1_CMD, 0xff); - // HACK: Disable busmouse IRQ for now. - disable(5); + // ...except IRQ2, since that's needed for the master to let through slave interrupts. + enable(2); kprintf("PIC(i8259): cascading mode, vectors 0x%b-0x%b\n", IRQ_VECTOR_BASE, IRQ_VECTOR_BASE + 0x08); diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 71644bb930e..581345a6692 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -49,7 +49,7 @@ void Task::initialize() current = nullptr; next_pid = 0; s_tasks = new InlineLinkedList; - s_kernelTask = new Task(0, "idle", IPC::Handle::Any, Task::Ring0); + s_kernelTask = new Task(0, "colonel", IPC::Handle::Any, Task::Ring0); redoKernelTaskTSS(); loadTaskRegister(s_kernelTask->selector()); } @@ -96,7 +96,7 @@ Task::Region* Task::allocateRegion(size_t size, String&& name) { // FIXME: This needs sanity checks. What if this overlaps existing regions? - auto zone = MemoryManager::the().createZone(PAGE_SIZE); + auto zone = MemoryManager::the().createZone(size); ASSERT(zone); m_regions.append(make(m_nextRegion, size, move(zone), move(name))); m_nextRegion = m_nextRegion.offset(size).offset(16384); @@ -152,6 +152,8 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring) m_tss.ss = stackSegment; m_tss.cs = codeSegment; + ASSERT((codeSegment & 3) == (stackSegment & 3)); + m_tss.cr3 = MemoryManager::the().pageDirectoryBase().get(); if (isRing0()) { @@ -160,14 +162,13 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring) m_tss.eip = codeRegion->linearAddress.get(); } - kprintf("basically ready\n"); - // NOTE: Each task gets 16KB of stack. static const DWORD defaultStackSize = 16384; if (isRing0()) { // FIXME: This memory is leaked. // But uh, there's also no kernel task termination, so I guess it's not technically leaked... + dword stackBottom = (dword)kmalloc(defaultStackSize); m_stackTop = (stackBottom + defaultStackSize) & 0xffffff8; m_tss.esp = m_stackTop; @@ -290,6 +291,13 @@ bool scheduleNewTask() return contextSwitch(Task::kernelTask()); } +#if 0 + kprintf("Scheduler choices:\n"); + for (auto* task = s_tasks->head(); task; task = task->next()) { + kprintf("%p %u %s\n", task, task->pid(), task->name().characters()); + } +#endif + // Check and unblock tasks whose wait conditions have been met. for (auto* task = s_tasks->head(); task; task = task->next()) { if (task->state() == Task::BlockedReceive && (task->ipc.msg.isValid() || task->ipc.notifies)) { @@ -320,12 +328,13 @@ bool scheduleNewTask() auto* task = s_tasks->head(); if (task->state() == Task::Runnable || task->state() == Task::Running) { - //kprintf("switch to %s\n", task->name().characters()); + //kprintf("switch to %s (%p vs %p)\n", task->name().characters(), task, current); return contextSwitch(task); } if (task == prevHead) { // Back at task_head, nothing wants to run. + kprintf("Switch to kernel task\n"); return contextSwitch(Task::kernelTask()); } } @@ -333,6 +342,7 @@ bool scheduleNewTask() static void drawSchedulerBanner(Task& task) { + return; // FIXME: We need a kernel lock to do stuff like this :( //return; auto c = vga_get_cursor(); @@ -360,6 +370,11 @@ static bool contextSwitch(Task* t) if (current == t) return false; + // Some sanity checking to force a crash earlier. + auto csRPL = t->tss().cs & 3; + auto ssRPL = t->tss().ss & 3; + ASSERT(csRPL == ssRPL); + if (current) { // If the last task hasn't blocked (still marked as running), // mark it as runnable for the next round. @@ -396,6 +411,8 @@ static bool contextSwitch(Task* t) flushGDT(); drawSchedulerBanner(*t); + + t->didSchedule(); return true; } @@ -481,7 +498,6 @@ FileHandle* Task::openFile(String&& path) handle->setFD(m_fileHandles.size()); kprintf("vfs::open() worked! handle=%p, fd=%d\n", handle.ptr(), handle->fd()); m_fileHandles.append(move(handle)); // FIXME: allow non-move Vector::append - kprintf("Task::openFile(): FileHandle{%p} fd=%d\n", handle.ptr(), handle->fd()); return m_fileHandles.last().ptr(); } diff --git a/Kernel/Task.h b/Kernel/Task.h index c3d55e36214..964e193d77b 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -99,6 +99,9 @@ public: void dumpRegions(); + void didSchedule() { ++m_timesScheduled; } + dword timesScheduled() const { return m_timesScheduled; } + private: friend class MemoryManager; @@ -126,6 +129,7 @@ private: RingLevel m_ring { Ring0 }; int m_error { 0 }; void* m_kernelStack { nullptr }; + dword m_timesScheduled { 0 }; struct Region { Region(LinearAddress, size_t, RetainPtr&&, String&&); diff --git a/Kernel/VGA.cpp b/Kernel/VGA.cpp index 9dffa336c98..4b412122b9f 100644 --- a/Kernel/VGA.cpp +++ b/Kernel/VGA.cpp @@ -19,36 +19,17 @@ static void console_putch(char*, char ch) Console::the().write((byte*)&ch, 1); } -void vga_putch(char*, char ch) +void vga_scroll_up() { - WORD soft_cursor = vga_get_cursor(); - WORD row; + memcpy(vga_mem, vga_mem + 160, 160 * 23); + memset(vga_mem + (160 * 23), 0, 160); +} - switch (ch) { - case '\n': - row = soft_cursor / 80; - if (row == 23) { - memcpy(vga_mem, vga_mem + 160, 160 * 23); - memset(vga_mem + (160 * 23), 0, 160); - soft_cursor = row * 80; - } else { - soft_cursor = (row + 1) * 80; - } - vga_set_cursor(soft_cursor); - return; - default: - vga_mem[soft_cursor * 2] = ch; - vga_mem[soft_cursor * 2 + 1] = current_attr; - ++soft_cursor; - } - row = soft_cursor / 80; - if ((row >= 24 && current->handle() != IPC::Handle::PanelTask)) { - memcpy(vga_mem, vga_mem + 160, 160 * 23); - memset(vga_mem + (160 * 23), 0, 160); - soft_cursor = 23 * 80; - } - - vga_set_cursor(soft_cursor); +void vga_putch_at(byte row, byte column, byte ch) +{ + word cur = (row * 160) + (column * 2); + vga_mem[cur] = ch; + vga_mem[cur + 1] = current_attr; } template diff --git a/Kernel/VGA.h b/Kernel/VGA.h index c7816d05b09..08cf97149f5 100644 --- a/Kernel/VGA.h +++ b/Kernel/VGA.h @@ -8,7 +8,8 @@ void vga_set_attr(BYTE); void vga_set_cursor(WORD); void vga_set_cursor(BYTE row, BYTE column); WORD vga_get_cursor(); -void vga_putch(char*, char); +void vga_putch_at(byte row, byte column, byte ch); +void vga_scroll_up(); int kprintf(const char *fmt, ...); int ksprintf(char* buf, const char *fmt, ...); diff --git a/Kernel/i8253.cpp b/Kernel/i8253.cpp index 0f603b44107..0b77366d9ec 100644 --- a/Kernel/i8253.cpp +++ b/Kernel/i8253.cpp @@ -117,6 +117,15 @@ void clock_handle() // If this IRQ occurred while in a user task, wouldn't that also push the stack ptr? current->tss().esp = regs.esp + 12; + // FIXME: Is this really safe? What if the interrupted process didn't have SS==DS? + current->tss().ss = regs.ds; + + if ((current->tss().cs & 3) != 0) { + // What do I do now? + kprintf("clk'ed across to ring0\n"); + HANG; + } + // Prepare a new task to run; if (!scheduleNewTask()) return; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 297376c554e..39736ad7d7f 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -26,9 +26,9 @@ #include #include "Console.h" -//#define TEST_VFS -//#define TEST_ELF_LOADER -//#define TEST_CRASHY_USER_PROCESSES +#define TEST_VFS +#define TEST_ELF_LOADER +#define TEST_CRASHY_USER_PROCESSES #if 0 /* Keyboard LED disco task ;^) */ @@ -94,16 +94,6 @@ static void user_main() } } -static void user_kprintf_main() NORETURN; -static void user_kprintf_main() -{ - DO_SYSCALL_A1(0x4000, 0); - kprintf("This should not work!\n"); - HANG; - for (;;) { - } -} - system_t system; void banner() @@ -121,47 +111,23 @@ void banner() kprintf("\n"); } -void init() +static void init_stage2() NORETURN; +static void init_stage2() { - cli(); - - kmalloc_init(); - vga_init(); - - auto console = make(); - - PIC::initialize(); - gdt_init(); - idt_init(); - - MemoryManager::initialize(); + kprintf("init stage2...\n"); + Keyboard::initialize(); // Anything that registers interrupts goes *after* PIC and IDT for obvious reasons. Syscall::initialize(); - PIT::initialize(); - Keyboard::initialize(); - Task::initialize(); VirtualFileSystem::initializeGlobals(); - memset(&system, 0, sizeof(system)); - - WORD base_memory = (CMOS::read(0x16) << 8) | CMOS::read(0x15); - WORD ext_memory = (CMOS::read(0x18) << 8) | CMOS::read(0x17); - - kprintf("%u kB base memory\n", base_memory); - kprintf("%u kB extended memory\n", ext_memory); - extern void panel_main(); new Task(panel_main, "panel", IPC::Handle::PanelTask, Task::Ring0); //new Task(led_disco, "led-disco", IPC::Handle::Any, Task::Ring0); - scheduleNewTask(); - banner(); - sti(); - Disk::initialize(); #ifdef TEST_VFS @@ -181,7 +147,7 @@ void init() auto dev_hd0 = IDEDiskDevice::create(); auto e2fs = Ext2FileSystem::create(dev_hd0.copyRef()); - e2fs->initialize(); + e2fs->initialize(); vfs->mountRoot(e2fs.copyRef()); @@ -200,7 +166,6 @@ void init() #ifdef TEST_CRASHY_USER_PROCESSES new Task(user_main, "user", IPC::Handle::UserTask, Task::Ring3); - new Task(user_kprintf_main, "user_kprintf", IPC::Handle::UserTask, Task::Ring3); #endif #ifdef TEST_ELF_LOADER @@ -209,7 +174,7 @@ void init() ASSERT(testExecutable); auto testExecutableData = testExecutable->readEntireFile(); ASSERT(testExecutableData); - + ExecSpace space; space.loadELF(move(testExecutableData)); auto* elf_entry = space.symbolPtr("elf_entry"); @@ -225,7 +190,45 @@ void init() //new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0); //new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3); - // The idle task will spend its eternity here for now. + kprintf("init stage2 is done!\n"); + + for (;;) { + asm("hlt"); + } +} + +void init() +{ + cli(); + + kmalloc_init(); + vga_init(); + + auto console = make(); + + PIC::initialize(); + gdt_init(); + idt_init(); + + MemoryManager::initialize(); + + PIT::initialize(); + + memset(&system, 0, sizeof(system)); + WORD base_memory = (CMOS::read(0x16) << 8) | CMOS::read(0x15); + WORD ext_memory = (CMOS::read(0x18) << 8) | CMOS::read(0x17); + + kprintf("%u kB base memory\n", base_memory); + kprintf("%u kB extended memory\n", ext_memory); + + Task::initialize(); + + auto* init2 = new Task(init_stage2, "init", IPC::Handle::InitTask, Task::Ring0); + scheduleNewTask(); + + sti(); + + // This now becomes the idle task :^) for (;;) { asm("hlt"); } diff --git a/Kernel/kassert.h b/Kernel/kassert.h index 97c2c0a0b3e..1ddabe6362e 100644 --- a/Kernel/kassert.h +++ b/Kernel/kassert.h @@ -3,6 +3,6 @@ #include "VGA.h" #define CRASH() do { asm volatile("cli;hlt"); } while(0) -#define ASSERT(x) do { if (!(x)) { vga_set_attr(0x4f); kprintf("ASSERTION FAILED: " #x "\n%s:%u in %s\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); CRASH(); } } while(0) +#define ASSERT(x) do { if (!(x)) { kprintf("ASSERTION FAILED: " #x "\n%s:%u in %s\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); CRASH(); } } while(0) #define RELEASE_ASSERT(x) do { if (!(x)) CRASH(); } while(0) #define ASSERT_NOT_REACHED() ASSERT(false) diff --git a/Kernel/panel.cpp b/Kernel/panel.cpp index 360737f1df5..896b4f1a663 100644 --- a/Kernel/panel.cpp +++ b/Kernel/panel.cpp @@ -16,6 +16,7 @@ panel_main() for( ;; ) { + continue; /* HACK: Avoid getting interrupted while painting since * that could lead to fugly artifacts ;P */ cli(); diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index f0f712a6a58..4542f244f94 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -27,6 +27,9 @@ VirtualFileSystem& VirtualFileSystem::the() VirtualFileSystem::VirtualFileSystem() { +#ifdef VFS_DEBUG + kprintf("[VFS] Constructing VFS\n"); +#endif s_the = this; m_maxNodeCount = 16; m_nodes = reinterpret_cast(kmalloc(sizeof(Node) * maxNodeCount()));