From fe237ee215fafd2012e6f4e5da88e3c2b8f9d33d Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 23 Oct 2018 10:12:50 +0200 Subject: [PATCH] Lots of hacking: - Turn Keyboard into a CharacterDevice (85,1) at /dev/keyboard. - Implement MM::unmapRegionsForTask() and MM::unmapRegion() - Save SS correctly on interrupt. - Add a simple Spawn syscall for launching another process. - Move a bunch of IO syscall debug output behind DEBUG_IO. - Have ASSERT do a "cli" immediately when failing. This makes the output look proper every time. - Implement a bunch of syscalls in LibC. - Add a simple shell ("sh"). All it can do now is read a line of text from /dev/keyboard and then try launching the specified executable by calling spawn(). There are definitely bugs in here, but we're moving on forward. --- AK/CircularQueue.h | 2 +- Kernel/Keyboard.cpp | 28 +++++++++++++++---- Kernel/Keyboard.h | 11 +++++++- Kernel/MemoryManager.cpp | 20 +++++++++++++ Kernel/MemoryManager.h | 1 + Kernel/Syscall.cpp | 11 +++++--- Kernel/Syscall.h | 1 + Kernel/Task.cpp | 49 ++++++++++++++++++++++++++++---- Kernel/Task.h | 1 + Kernel/_fs_contents | Bin 1024000 -> 1024000 bytes Kernel/i386.cpp | 4 +++ Kernel/i386.h | 1 + Kernel/i8253.cpp | 17 +++++++---- Kernel/init.cpp | 13 +++++---- Kernel/kassert.h | 2 +- Kernel/sync-sh | 5 ++++ LibC/Makefile | 2 ++ LibC/process.cpp | 12 ++++++++ LibC/process.h | 8 ++++++ LibC/stdio.cpp | 3 +- LibC/string.cpp | 14 ++++++++++ LibC/string.h | 10 +++++++ LibC/types.h | 7 +++++ LibC/unistd.cpp | 17 +++++++++++ LibC/unistd.h | 3 ++ Userland/.gitignore | 1 + Userland/Makefile | 9 ++++-- Userland/sh.cpp | 56 +++++++++++++++++++++++++++++++++++++ VirtualFileSystem/small.fs | Bin 2048000 -> 2048000 bytes 29 files changed, 276 insertions(+), 32 deletions(-) create mode 100755 Kernel/sync-sh create mode 100644 LibC/process.cpp create mode 100644 LibC/process.h create mode 100644 LibC/string.cpp create mode 100644 LibC/string.h create mode 100644 Userland/sh.cpp 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 db5b3cfb2f3358430ca1cf5f1bad4fba1af69283..344bc920023630414f0ac97177141b3b830e0b44 100644 GIT binary patch delta 3692 zcmZoTVApWKZUYYs>s)3AhS14^EYh44BF;r`iZ~Z7z1ft-nUTqpaU)|J(ao1|9|m z28oS~;Y^#98Tm9E85kH?7#J>DoQu8)#SnE&C>jJN8yXl-6yRWaTDs%kL`I3p4Te0D zUDoHKK^R>F>-2}J9KsU?bS6JBl$oT)V);XqfdQltG z_~>5EnaC(H$+!WovEJfbGz=q@BUtQUjfHX#zav}MVsS1Sh7oEJEDo@)tk})9$htZ# z&PBs8LM?*D3f5)4WpNm?t{oQVqW4;yi-yq<^$-%|Nybo+*NT0N+d;ZipaF8w;#~Au zi*wO18loOTB6Mx$j1ffE1&eMFjZlkVLF{VQlT_JUXgou6Qo;vu0R|4n_>9z?oP51} zWd;TY9tLKnl+?1#?1`fJLOcvijF~A645|za40o8B7>hGDGG1bCy3%%qvF!>|+ZE=v zD=ckSSlh0!ExW>=!>Bx&F+to}4QvVvb6#mqjs}#SR+^Ke$-uxMz`({_l$e*2pUc3Y z1(mBxEy~wrU|`t7%)y+UTA7reShQL3!cyjGG8_u^4FV9?n}8_|24w~%hUPasFaG@h z|G)J>DOd9wo(z!GYYq^LnSp@;EY*BOp!o>T;qcxX6^`a7AO4sB3GI9u9v0mAW(@-a z!?D(k|Ns9p>;P#5EAMO#`TzgFL#Y(V5I!VB>UV$w`{gp2km0x9y%GQa|KAC6R_Cv7 zus)~}0bnOpuyp=@Z4EL6jP8}jR**#J2e3YeQh|VgunZ?8lc9bAOB)_|y}vj0OLSa( zY;XFH_`{utb{t@5U^v^rzwOZWN*xYEHmTs|HyoXZ!KynC?r4={VCcMcwxRh5NA&ar z1rAB^&OGJHha@8- z+w|Ms9QxCxd^ilIvng>1OjiRDQ6TOz6AqzzP}IRNGlMvc38tADB)~L`U}lhlF~Kx5 zgAAC45zGv-FeaF0W{?BZFoKyuo&l5$V0;#akJD%SaB$XxQZT4Y6@kfs3*L|aVcJ27 zgpompK?O}7lrmsKEDRt2TfsO`{Vr(y04SfAfq_AYfsG*o!mnrG01NOiv_b?Jet-&G z26l#cC?6uv%aDe`=Vr)-^0~nJMHz~re2~M17=#(BpnOm`3NZ*Uz=HcPSUn3v3s~Nl zfkA;8&ROmlS2@rGw>C^Gb>;!K{L!{N&W);^`YqIh5+bNroZ5xFoTtgaMS07;+Oc z^B9T?iZb&`(inzULU7;2yj8bK0D3}EjvDKIdc0`XND z7_LI)Z-Mwq3=A(pG!p}Z2S{9qfq|8Yfq_wkfx!SuhePQMD7_6z2ZGcKGcZU%`Cd#6 z+F*@kP=OXGeGE#ogDlcw04EG4jp=&k9J@hr$H)e55io#gP?`YIpf&@D1}9QB1_n?f z2Ju004x&MM1Vk%<+`tA291tH=q=RT3sJH=?29?ktaSJHl21=VbKpCJ^4N?FO1U3c+ zP^g0VpwtbbL!jzFshg2)x|J-4ibzpvj$TP>MTs7ALgBFBs7e4wFhmZV2p~*Ij6>Ma zl%R(&1CnN-vY?WOL9Zx3C9xzC*?7I;k|IMr!|5Fs9A_A{rXN)05TBl7$-$$$fQNwr z6c`{3D$ZFLAmMBcayJ750~<7r$1yN4{GEL8mawfk0|Nsm0|Nsn1VEApco-N!wH3$& zkZuqLMTZ}n3DJxU47?x{L=(_tG8h>ceoR)pC0rkaX0`?|0|O{3KxTtd0nF?|G!qh7 zAh{Og9uS5VY@i|m*{u;s=7Gdv=7EzFD5Jx?+rZAizyWqFs1N`d2b1Z5%gjV`#00p^ zDm0lH>yolFmk|b{RWjW0);yR0|Pe) z0|VRikLn!4qJoSJ;3@_tCCI_R5CWE}*Mv%ek{n251_uKJDDpvU5C+)`qE#7D6Wa`4 z25<`p6keb_4N?b6Y&K}-9l>Fq1;o5KcdUCnKw5WH|Pu_qDBb-{7mX( delta 1184 zcmZoTVApWKZUYYs>k?)LhM38MEYh5}E}f0Of9Y(rz-ChxXGX?j8yVY~CUNkvE@6&g z;Mpw5VIaU*KatUDbB#m?Gmkd|0&EtPdCxrgzkH`+@zJx<`A`gzXJ=r7Fc`QQ7#Jir zGKMp4QfB0nXoQIJ??-3=X=Ipu@Rm1=_Pm1!CNfG)ZZPDLEIE2M8iXP0nc&8;On<1# zAv{q)XYvz6naK^RETSM4Li^7~w;w@ZhE;B0i~5d?;)+JE)vl8KBG zlZ+cSH<&eOE)-y%l<+}ZhJk}IJ|i_JCtojLnSp_Uhk=PPGlgL@d!lGQ+Y4q8XCvc1 z=B6ucR~Xx_FtuG_Zo9(Lc7?U=3fr

^Y1Dn-AXl&pb_rLqWKL2joNs1`{x)!63mP zzTH@dqnu5$G&99kwNytT9ZDB~X)Xqa?e~p1${DAh^W_kjo@T|qNIK=7&86?2QK?oLxkN-ig1o0Rd7#M^YSQxZH90mpk4ltjK!41m)!32_LWiW#B zA@bY|mMDBq1_vnL6|A3$0Yrm@6qp$pgr>Kea;Qz;YRVy7pPQJO$532Ql$lqO29gIw z2$KW@gA4-$1CuBN1IS%W;tXK-Fmf_57=XmZ7#KVl7#JA27#LWY7#J9N7#IwobU2jG zfYRHbbRbAQHv@wNl)ND(duh8-Zg85kIN85kHq>Og_N8_hfgcI@VDhnN=y zH}DLSf&54Yo<=jUhMj>y0O}|Z1+o}K--N1T25}e|7<#5F+Hi;q-iIa{G~p*u)lkI@ zJ<|(qIMjK2*cli$FfuTRF)%QQOrIOcAtss().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 f28df55b1e16a4069a594f8bfbed7a8a2e7f6eaf..5d852a74780160aff3e6a938310da960dc8443c0 100644 GIT binary patch delta 248 zcmZo@sBLJd-N3`b+R4tq@L;nb%Wr1ZPWA^3+?xeCzRNSpPh>3L+@R6SJo&#q=R{7C z%?dhIER5WnXB)iYQ(<9X_~mde8ipCbfQf+#OhX9Q&59iN{hT^m^2yEd@3cWq#A@7lo8-nD_Vy=wzkd)Ef;_O1;) z?Ohvq+q*XKwRdgcZ|~Y5(B8E{u)S-8PM delta 242 zcmZo@sBLJd-N3`b+QrVm@Nlyr%Wr1ZF7}5ET$=?szRNT6Ph>3L+@R6S%ve8>QD(D( zP8ACy*XG#Oz}4QhfxEqH15bO`2Hy6r z4Selg8~EG1HVCwLZ4hkl+91^4wL!SOYlBF8*9Ot{t_@=CT^q#PyEaI)cWsbt@7f^M W-nBuxy=#L^d)Efp?Ohw>%K8CQ-d{Zc