mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 09:52:44 +00:00 
			
		
		
		
	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.
			
			
This commit is contained in:
		
							parent
							
								
									72514c8b97
								
							
						
					
					
						commit
						fe237ee215
					
				
					 29 changed files with 276 additions and 32 deletions
				
			
		|  | @ -1,7 +1,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "Assertions.h" | ||||
| #include "Types.h" | ||||
| #include "kstdio.h" | ||||
| 
 | ||||
| namespace AK { | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
|  |  | |||
|  | @ -1,16 +1,25 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <AK/Types.h> | ||||
| #include <AK/DoublyLinkedList.h> | ||||
| #include <AK/CircularQueue.h> | ||||
| #include <VirtualFileSystem/CharacterDevice.h> | ||||
| #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<byte, 16> m_queue; | ||||
|     byte m_modifiers { 0 }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -51,6 +51,7 @@ public: | |||
|     byte* quickMapOnePage(PhysicalAddress); | ||||
| 
 | ||||
|     bool mapRegion(Task&, Task::Region&); | ||||
|     bool unmapRegion(Task&, Task::Region&); | ||||
|     bool mapRegionsForTask(Task&); | ||||
|     bool unmapRegionsForTask(Task&); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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()
 | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| namespace Syscall { | ||||
| 
 | ||||
| enum Function { | ||||
|     Spawn = 0x1981, | ||||
|     Sleep = 0x1982, | ||||
|     Yield = 0x1983, | ||||
|     PutCharacter = 1984, | ||||
|  |  | |||
|  | @ -10,6 +10,8 @@ | |||
| #include <ELFLoader/ExecSpace.h> | ||||
| #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(); | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
|     { | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							|  | @ -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" \ | ||||
|  |  | |||
|  | @ -119,6 +119,7 @@ private: | |||
| }; | ||||
| 
 | ||||
| struct RegisterDump { | ||||
|     WORD ss; | ||||
|     WORD gs; | ||||
|     WORD fs; | ||||
|     WORD es; | ||||
|  |  | |||
|  | @ -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;
 | ||||
|  |  | |||
|  | @ -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<Keyboard>(); | ||||
| 
 | ||||
|     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<RandomDevice>(); | ||||
|     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<Keyboard>(); | ||||
| 
 | ||||
|     PIT::initialize(); | ||||
| 
 | ||||
|     memset(&system, 0, sizeof(system)); | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
							
								
								
									
										5
									
								
								Kernel/sync-sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								Kernel/sync-sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| mkdir mnt | ||||
| mount -o loop _fs_contents mnt/ | ||||
| cp ../Userland/sh mnt/bin/sh | ||||
| umount mnt | ||||
| sync | ||||
|  | @ -1,6 +1,8 @@ | |||
| OBJS = \
 | ||||
|        stdio.o \
 | ||||
|        unistd.o \
 | ||||
|        string.o \
 | ||||
|        process.o \
 | ||||
|        entry.o | ||||
| 
 | ||||
| LIBRARY = LibC.a | ||||
|  |  | |||
							
								
								
									
										12
									
								
								LibC/process.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								LibC/process.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #include "process.h" | ||||
| #include <Kernel/Syscall.h> | ||||
| 
 | ||||
| extern "C" { | ||||
| 
 | ||||
| int spawn(const char* path) | ||||
| { | ||||
|     return Syscall::invoke(Syscall::Spawn, (dword)path); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										8
									
								
								LibC/process.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								LibC/process.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| #pragma once | ||||
| 
 | ||||
| extern "C" { | ||||
| 
 | ||||
| int spawn(const char* path); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | @ -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, ...) | ||||
|  |  | |||
							
								
								
									
										14
									
								
								LibC/string.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								LibC/string.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| #include "string.h" | ||||
| 
 | ||||
| extern "C" { | ||||
| 
 | ||||
| size_t strlen(const char* str) | ||||
| { | ||||
|     size_t len = 0; | ||||
|     while (*(str++)) | ||||
|         ++len; | ||||
|     return len; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										10
									
								
								LibC/string.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								LibC/string.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "types.h" | ||||
| 
 | ||||
| extern "C" { | ||||
| 
 | ||||
| size_t strlen(const char*); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | @ -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; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #include "unistd.h" | ||||
| #include "string.h" | ||||
| #include <Kernel/Syscall.h> | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										1
									
								
								Userland/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								Userland/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,2 +1,3 @@ | |||
| id | ||||
| sh | ||||
| *.o | ||||
|  |  | |||
|  | @ -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 $< | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										56
									
								
								Userland/sh.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								Userland/sh.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| #include <LibC/stdio.h> | ||||
| #include <LibC/unistd.h> | ||||
| #include <LibC/process.h> | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling