diff --git a/AK/CircularQueue.h b/AK/CircularQueue.h index 45942a114d..7026d63cb9 100644 --- a/AK/CircularQueue.h +++ b/AK/CircularQueue.h @@ -1,7 +1,7 @@ #pragma once +#include "Assertions.h" #include "Types.h" -#include "kstdio.h" namespace AK { diff --git a/Kernel/Keyboard.cpp b/Kernel/Keyboard.cpp index 9436bae64b..c233b3c59f 100644 --- a/Kernel/Keyboard.cpp +++ b/Kernel/Keyboard.cpp @@ -47,7 +47,7 @@ void Keyboard::handleIRQ() case 0x9D: m_modifiers &= ~MOD_CTRL; break; case 0x2A: m_modifiers |= MOD_SHIFT; break; case 0xAA: m_modifiers &= ~MOD_SHIFT; break; - case 0x1C: /* enter */ kprintf("\n"); break; + case 0x1C: /* enter */ m_queue.enqueue('\n'); break; case 0xFA: /* i8042 ack */ break; default: if (ch & 0x80) { @@ -55,11 +55,14 @@ void Keyboard::handleIRQ() break; } if (!m_modifiers) - kprintf("%c", map[ch]); + m_queue.enqueue(map[ch]); else if (m_modifiers & MOD_SHIFT) - kprintf("%c", shift_map[ch]); - else if (m_modifiers & MOD_CTRL) - kprintf("^%c", shift_map[ch]); + m_queue.enqueue(shift_map[ch]); + else if (m_modifiers & MOD_CTRL) { + // FIXME: This is obviously not a good enough way to process ctrl+whatever. + m_queue.enqueue('^'); + m_queue.enqueue(shift_map[ch]); + } } //break; } @@ -81,3 +84,18 @@ Keyboard::~Keyboard() ASSERT_NOT_REACHED(); } +ssize_t Keyboard::read(byte* buffer, size_t size) +{ + ssize_t nread = 0; + while (nread < size) { + if (m_queue.isEmpty()) + break; + buffer[nread++] = m_queue.dequeue(); + } + return nread; +} + +ssize_t Keyboard::write(const byte* data, size_t size) +{ + return 0; +} diff --git a/Kernel/Keyboard.h b/Kernel/Keyboard.h index 02aa5cec06..21da8eb573 100644 --- a/Kernel/Keyboard.h +++ b/Kernel/Keyboard.h @@ -1,16 +1,25 @@ #pragma once #include +#include +#include +#include #include "IRQHandler.h" -class Keyboard final : public IRQHandler { +class Keyboard final : public IRQHandler, public CharacterDevice { public: virtual ~Keyboard() override; Keyboard(); private: + // ^IRQHandler virtual void handleIRQ() override; + // ^CharacterDevice + virtual ssize_t read(byte* buffer, size_t) override; + virtual ssize_t write(const byte* buffer, size_t) override; + + CircularQueue m_queue; byte m_modifiers { 0 }; }; diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index 019242a741..698427b59e 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -156,8 +156,28 @@ byte* MemoryManager::quickMapOnePage(PhysicalAddress physicalAddress) return (byte*)(4 * MB); } +bool MemoryManager::unmapRegion(Task& task, Task::Region& region) +{ + auto& zone = *region.zone; + for (size_t i = 0; i < zone.m_pages.size(); ++i) { + auto laddr = region.linearAddress.offset(i * PAGE_SIZE); + auto pte = ensurePTE(laddr); + pte.setPhysicalPageBase(0); + pte.setPresent(false); + pte.setWritable(false); + pte.setUserAllowed(false); + +// kprintf("MM: >> Unmapped L%x => P%x <<\n", laddr, zone.m_pages[i].get()); + } + return true; +} + bool MemoryManager::unmapRegionsForTask(Task& task) { + for (auto& region : task.m_regions) { + if (!unmapRegion(task, *region)) + return false; + } return true; } diff --git a/Kernel/MemoryManager.h b/Kernel/MemoryManager.h index a597280add..35f83ab306 100644 --- a/Kernel/MemoryManager.h +++ b/Kernel/MemoryManager.h @@ -51,6 +51,7 @@ public: byte* quickMapOnePage(PhysicalAddress); bool mapRegion(Task&, Task::Region&); + bool unmapRegion(Task&, Task::Region&); bool mapRegionsForTask(Task&); bool unmapRegionsForTask(Task&); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 7ad1f2507d..4ba373daca 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -22,6 +22,7 @@ asm( " pushw %ss\n" " pushw %ss\n" " pushw %ss\n" + " pushw %ss\n" " popw %ds\n" " popw %es\n" " popw %fs\n" @@ -29,6 +30,7 @@ asm( " mov %esp, syscallRegDump\n" " call syscall_entry\n" " popw %gs\n" + " popw %gs\n" " popw %fs\n" " popw %es\n" " popw %ds\n" @@ -58,15 +60,16 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) //kprintf("syscall: sleep(%d)\n", arg1); current->sys$sleep(arg1); break; + case Syscall::Spawn: + return current->sys$spawn((const char*)arg1); case Syscall::PosixOpen: - Task::checkSanity("syscall"); - kprintf("syscall: open('%s', %u)\n", arg1, arg2); + //kprintf("syscall: open('%s', %u)\n", arg1, arg2); return current->sys$open((const char*)arg1, (size_t)arg2); case Syscall::PosixClose: - kprintf("syscall: close(%d)\n", arg1); + //kprintf("syscall: close(%d)\n", arg1); return current->sys$close((int)arg1); case Syscall::PosixRead: - kprintf("syscall: read(%d, %p, %u)\n", arg1, arg2, arg3); + //kprintf("syscall: read(%d, %p, %u)\n", arg1, arg2, arg3); return current->sys$read((int)arg1, (void*)arg2, (size_t)arg3); case Syscall::PosixSeek: // FIXME: This has the wrong signature, should be like lseek() diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index a11061e552..095fc507e7 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -10,6 +10,7 @@ namespace Syscall { enum Function { + Spawn = 0x1981, Sleep = 0x1982, Yield = 0x1983, PutCharacter = 1984, diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index cab2b17ea6..10f111ea50 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -10,6 +10,8 @@ #include #include "MemoryManager.h" +//#define DEBUG_IO + Task* current; Task* s_kernelTask; @@ -104,6 +106,14 @@ Task::Region* Task::allocateRegion(size_t size, String&& name) return m_regions.last().ptr(); } +int Task::sys$spawn(const char* path) +{ + auto* child = Task::create(path, m_uid, m_gid); + if (child) + return child->pid(); + return -1; +} + Task* Task::create(const String& path, uid_t uid, gid_t gid) { auto parts = path.split('/'); @@ -118,6 +128,7 @@ Task* Task::create(const String& path, uid_t uid, gid_t gid) if (!elfData) return nullptr; + cli(); Task* t = new Task(parts.takeLast(), uid, gid); ExecSpace space; @@ -137,9 +148,14 @@ Task* Task::create(const String& path, uid_t uid, gid_t gid) } t->m_tss.eip = (dword)space.symbolPtr("_start"); + if (!t->m_tss.eip) { + delete t; + return nullptr; + } + + MemoryManager::the().unmapRegionsForTask(*t); + MemoryManager::the().mapRegionsForTask(*current); - // Add this task to head of task list (meaning it's next to run too, ATM.) - cli(); s_tasks->prepend(t); system.nprocess++; kprintf("Task %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip); @@ -357,10 +373,12 @@ void Task::taskDidCrash(Task* crashedTask) { // NOTE: This is called from an excepton handler, so interrupts are disabled. crashedTask->setState(Crashing); - crashedTask->dumpRegions(); +// crashedTask->dumpRegions(); s_tasks->remove(crashedTask); + MemoryManager::the().unmapRegionsForTask(*crashedTask); + if (!scheduleNewTask()) { kprintf("Task::taskDidCrash: Failed to schedule a new task :(\n"); HANG; @@ -491,7 +509,16 @@ static bool contextSwitch(Task* t) // Some sanity checking to force a crash earlier. auto csRPL = t->tss().cs & 3; auto ssRPL = t->tss().ss & 3; - ASSERT(csRPL == ssRPL); + + if (csRPL != ssRPL) { + kprintf("Fuckup! Switching from %s(%u) to %s(%u) has RPL mismatch\n", + current->name().characters(), current->pid(), + t->name().characters(), t->pid() + ); + kprintf("code: %w:%x\n", t->tss().cs, t->tss().eip); + kprintf(" stk: %w:%x\n", t->tss().ss, t->tss().esp); + ASSERT(csRPL == ssRPL); + } if (current) { // If the last task hasn't blocked (still marked as running), @@ -572,17 +599,24 @@ int Task::sys$seek(int fd, int offset) ssize_t Task::sys$read(int fd, void* outbuf, size_t nread) { Task::checkSanity("Task::sys$read"); +#ifdef DEBUG_IO kprintf("Task::sys$read: called(%d, %p, %u)\n", fd, outbuf, nread); +#endif auto* handle = fileHandleIfExists(fd); +#ifdef DEBUG_IO kprintf("Task::sys$read: handle=%p\n", handle); +#endif if (!handle) { kprintf("Task::sys$read: handle not found :(\n"); return -1; } +#ifdef DEBUG_IO kprintf("call read on handle=%p\n", handle); +#endif nread = handle->read((byte*)outbuf, nread); - kprintf("called read\n"); +#ifdef DEBUG_IO kprintf("Task::sys$read: nread=%u\n", nread); +#endif return nread; } @@ -598,7 +632,9 @@ int Task::sys$close(int fd) int Task::sys$open(const char* path, size_t pathLength) { Task::checkSanity("sys$open"); +#ifdef DEBUG_IO kprintf("Task::sys$open(): PID=%u, path=%s {%u}\n", m_pid, path, pathLength); +#endif auto* handle = current->openFile(String(path, pathLength)); if (handle) return handle->fd(); @@ -607,14 +643,15 @@ int Task::sys$open(const char* path, size_t pathLength) FileHandle* Task::openFile(String&& path) { - kprintf("calling vfs::open with vfs=%p, path='%s'\n", &VirtualFileSystem::the(), path.characters()); auto handle = VirtualFileSystem::the().open(move(path)); if (!handle) { kprintf("vfs::open() failed\n"); return nullptr; } handle->setFD(m_fileHandles.size()); +#ifdef DEBUG_IO kprintf("vfs::open() worked! handle=%p, fd=%d\n", handle.ptr(), handle->fd()); +#endif m_fileHandles.append(move(handle)); // FIXME: allow non-move Vector::append return m_fileHandles.last().ptr(); } diff --git a/Kernel/Task.h b/Kernel/Task.h index 2e230bf2ef..10c115e082 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -90,6 +90,7 @@ public: int sys$geterror() { return m_error; } void sys$sleep(DWORD ticks); void sys$exit(int status); + int sys$spawn(const char* path); struct { diff --git a/Kernel/_fs_contents b/Kernel/_fs_contents index db5b3cfb2f..344bc92002 100644 Binary files a/Kernel/_fs_contents and b/Kernel/_fs_contents differ diff --git a/Kernel/i386.cpp b/Kernel/i386.cpp index 91d676abed..047212f877 100644 --- a/Kernel/i386.cpp +++ b/Kernel/i386.cpp @@ -78,6 +78,7 @@ asm( \ " pushw %ss\n" \ " pushw %ss\n" \ " pushw %ss\n" \ + " pushw %ss\n" \ " popw %ds\n" \ " popw %es\n" \ " popw %fs\n" \ @@ -85,6 +86,7 @@ asm( \ " mov %esp, exception_state_dump\n" \ " call exception_" # ec "_handler\n" \ " popw %gs\n" \ + " popw %gs\n" \ " popw %fs\n" \ " popw %es\n" \ " popw %ds\n" \ @@ -107,6 +109,7 @@ asm( \ " pushw %ss\n" \ " pushw %ss\n" \ " pushw %ss\n" \ + " pushw %ss\n" \ " popw %ds\n" \ " popw %es\n" \ " popw %fs\n" \ @@ -114,6 +117,7 @@ asm( \ " mov %esp, exception_state_dump\n" \ " call exception_" # ec "_handler\n" \ " popw %gs\n" \ + " popw %gs\n" \ " popw %fs\n" \ " popw %es\n" \ " popw %ds\n" \ diff --git a/Kernel/i386.h b/Kernel/i386.h index 24481f6885..b9dc62a42b 100644 --- a/Kernel/i386.h +++ b/Kernel/i386.h @@ -119,6 +119,7 @@ private: }; struct RegisterDump { + WORD ss; WORD gs; WORD fs; WORD es; diff --git a/Kernel/i8253.cpp b/Kernel/i8253.cpp index 0b77366d9e..cfa24a3aef 100644 --- a/Kernel/i8253.cpp +++ b/Kernel/i8253.cpp @@ -28,6 +28,7 @@ asm( " pushw %ss\n" " pushw %ss\n" " pushw %ss\n" + " pushw %ss\n" " popw %ds\n" " popw %es\n" " popw %fs\n" @@ -35,6 +36,7 @@ asm( " mov %esp, state_dump\n" " call clock_handle\n" " popw %gs\n" + " popw %gs\n" " popw %fs\n" " popw %es\n" " popw %ds\n" @@ -117,13 +119,18 @@ 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; + current->tss().ss = regs.ss; if ((current->tss().cs & 3) != 0) { - // What do I do now? - kprintf("clk'ed across to ring0\n"); - HANG; +#if 0 + kprintf("clock'ed across to ring0\n"); + kprintf("code: %w:%x\n", current->tss().cs, current->tss().eip); + kprintf(" stk: %w:%x\n", current->tss().ss, current->tss().esp); + kprintf("astk: %w:%x\n", regs.ss_if_crossRing, regs.esp_if_crossRing); + //HANG; +#endif + current->tss().ss = regs.ss_if_crossRing; + current->tss().esp = regs.esp_if_crossRing; } // Prepare a new task to run; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index b35f34bcb6..19d5aa7361 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -99,13 +99,12 @@ static void init_stage2() { kprintf("init stage2...\n"); - // Anything that registers interrupts goes *after* PIC and IDT for obvious reasons. Syscall::initialize(); + auto keyboard = make(); + 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); Disk::initialize(); @@ -125,6 +124,8 @@ static void init_stage2() auto dev_random = make(); vfs->registerCharacterDevice(1, 8, *dev_random); + vfs->registerCharacterDevice(85, 1, *keyboard); + auto dev_hd0 = IDEDiskDevice::create(); auto e2fs = Ext2FileSystem::create(dev_hd0.copyRef()); e2fs->initialize(); @@ -167,7 +168,9 @@ static void init_stage2() } #endif - auto* idTask = Task::create("/bin/id", (uid_t)209, (gid_t)1985); + //auto* idTask = Task::create("/bin/id", (uid_t)209, (gid_t)1985); + + auto* shTask = Task::create("/bin/sh", (uid_t)100, (gid_t)100); //new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0); //new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3); @@ -206,8 +209,6 @@ void init() VirtualFileSystem::initializeGlobals(); StringImpl::initializeGlobals(); - auto keyboard = make(); - PIT::initialize(); memset(&system, 0, sizeof(system)); diff --git a/Kernel/kassert.h b/Kernel/kassert.h index 5196f14df7..d848ddf763 100644 --- a/Kernel/kassert.h +++ b/Kernel/kassert.h @@ -3,6 +3,6 @@ #include "kprintf.h" #define CRASH() do { asm volatile("ud2"); } 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 ASSERT(x) do { if (!(x)) { asm volatile("cli"); 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/sync-sh b/Kernel/sync-sh new file mode 100755 index 0000000000..3a32e3b5cb --- /dev/null +++ b/Kernel/sync-sh @@ -0,0 +1,5 @@ +mkdir mnt +mount -o loop _fs_contents mnt/ +cp ../Userland/sh mnt/bin/sh +umount mnt +sync diff --git a/LibC/Makefile b/LibC/Makefile index 592a212efe..47485d29fd 100644 --- a/LibC/Makefile +++ b/LibC/Makefile @@ -1,6 +1,8 @@ OBJS = \ stdio.o \ unistd.o \ + string.o \ + process.o \ entry.o LIBRARY = LibC.a diff --git a/LibC/process.cpp b/LibC/process.cpp new file mode 100644 index 0000000000..045b3e3eeb --- /dev/null +++ b/LibC/process.cpp @@ -0,0 +1,12 @@ +#include "process.h" +#include + +extern "C" { + +int spawn(const char* path) +{ + return Syscall::invoke(Syscall::Spawn, (dword)path); +} + +} + diff --git a/LibC/process.h b/LibC/process.h new file mode 100644 index 0000000000..2a35644085 --- /dev/null +++ b/LibC/process.h @@ -0,0 +1,8 @@ +#pragma once + +extern "C" { + +int spawn(const char* path); + +} + diff --git a/LibC/stdio.cpp b/LibC/stdio.cpp index dd5b26f9a5..31f0d14d41 100644 --- a/LibC/stdio.cpp +++ b/LibC/stdio.cpp @@ -141,7 +141,8 @@ extern "C" { int putchar(int ch) { - return ch; + Syscall::invoke(Syscall::PutCharacter, ch); + return (byte)ch; } int printf(const char* fmt, ...) diff --git a/LibC/string.cpp b/LibC/string.cpp new file mode 100644 index 0000000000..252dc65657 --- /dev/null +++ b/LibC/string.cpp @@ -0,0 +1,14 @@ +#include "string.h" + +extern "C" { + +size_t strlen(const char* str) +{ + size_t len = 0; + while (*(str++)) + ++len; + return len; +} + +} + diff --git a/LibC/string.h b/LibC/string.h new file mode 100644 index 0000000000..21e4ccf287 --- /dev/null +++ b/LibC/string.h @@ -0,0 +1,10 @@ +#pragma once + +#include "types.h" + +extern "C" { + +size_t strlen(const char*); + +} + diff --git a/LibC/types.h b/LibC/types.h index 5bb4538f41..fc990e79f7 100644 --- a/LibC/types.h +++ b/LibC/types.h @@ -6,9 +6,16 @@ typedef unsigned int dword; typedef unsigned short word; typedef unsigned char byte; +typedef signed int signed_dword; +typedef signed short signed_word; +typedef signed char signed_byte; + typedef dword uid_t; typedef dword gid_t; typedef dword pid_t; +typedef dword size_t; +typedef signed_dword ssize_t; + } diff --git a/LibC/unistd.cpp b/LibC/unistd.cpp index 2a7efa95c2..6efa2da1b2 100644 --- a/LibC/unistd.cpp +++ b/LibC/unistd.cpp @@ -1,4 +1,5 @@ #include "unistd.h" +#include "string.h" #include extern "C" { @@ -18,5 +19,21 @@ uid_t getpid() return Syscall::invoke(Syscall::PosixGetpid); } +int open(const char* path) +{ + size_t length = strlen(path); + return Syscall::invoke(Syscall::PosixOpen, (dword)path, (dword)length); +} + +ssize_t read(int fd, void* buf, size_t count) +{ + return Syscall::invoke(Syscall::PosixRead, (dword)fd, (dword)buf, (dword)count); +} + +int close(int fd) +{ + return Syscall::invoke(Syscall::PosixClose, fd); +} + } diff --git a/LibC/unistd.h b/LibC/unistd.h index bffc5840b5..2395eadf13 100644 --- a/LibC/unistd.h +++ b/LibC/unistd.h @@ -7,6 +7,9 @@ extern "C" { uid_t getuid(); gid_t getgid(); pid_t getpid(); +int open(const char* path); +ssize_t read(int fd, void* buf, size_t count); +int close(int fd); } diff --git a/Userland/.gitignore b/Userland/.gitignore index b28508b26e..89dadc36dd 100644 --- a/Userland/.gitignore +++ b/Userland/.gitignore @@ -1,2 +1,3 @@ id +sh *.o diff --git a/Userland/Makefile b/Userland/Makefile index a3506661b3..0266a2edd0 100644 --- a/Userland/Makefile +++ b/Userland/Makefile @@ -1,8 +1,10 @@ OBJS = \ - id.o + id.o \ + sh.o APPS = \ - id + id \ + sh ARCH_FLAGS = STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib @@ -25,6 +27,9 @@ all: $(OBJS) $(APPS) id: id.o $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a +sh: sh.o + $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a + .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Userland/sh.cpp b/Userland/sh.cpp new file mode 100644 index 0000000000..5dd3b123c5 --- /dev/null +++ b/Userland/sh.cpp @@ -0,0 +1,56 @@ +#include +#include +#include + +static void prompt() +{ + if (getuid() == 0) + printf("# "); + else + printf("$ "); +} + +static int runcmd(char* cmd) +{ + //printf("command: '%s'\n", cmd); + int ret = spawn(cmd); + if (ret == -1) { + printf("spawn failed: %s\n", cmd); + } + return 0; +} + +int main(int c, char** v) +{ + char linebuf[128]; + int linedx = 0; + linebuf[0] = '\0'; + + int fd = open("/dev/keyboard"); + if (fd == -1) { + printf("failed to open /dev/keyboard :(\n"); + return 1; + } + prompt(); + for (;;) { + char keybuf[16]; + ssize_t nread = read(fd, keybuf, sizeof(keybuf)); + if (nread < 0) { + printf("failed to read :(\n"); + return 2; + } + for (ssize_t i = 0; i < nread; ++i) { + putchar(keybuf[i]); + if (keybuf[i] != '\n') { + linebuf[linedx++] = keybuf[i]; + linebuf[linedx] = '\0'; + } else { + runcmd(linebuf); + linebuf[0] = '\0'; + linedx = 0; + prompt(); + } + } + } + return 0; +} diff --git a/VirtualFileSystem/small.fs b/VirtualFileSystem/small.fs index f28df55b1e..5d852a7478 100644 Binary files a/VirtualFileSystem/small.fs and b/VirtualFileSystem/small.fs differ