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 | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include "Assertions.h" | ||||||
| #include "Types.h" | #include "Types.h" | ||||||
| #include "kstdio.h" |  | ||||||
| 
 | 
 | ||||||
| namespace AK { | namespace AK { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ void Keyboard::handleIRQ() | ||||||
|         case 0x9D: m_modifiers &= ~MOD_CTRL; break; |         case 0x9D: m_modifiers &= ~MOD_CTRL; break; | ||||||
|         case 0x2A: m_modifiers |= MOD_SHIFT; break; |         case 0x2A: m_modifiers |= MOD_SHIFT; break; | ||||||
|         case 0xAA: 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; |         case 0xFA: /* i8042 ack */ break; | ||||||
|         default: |         default: | ||||||
|             if (ch & 0x80) { |             if (ch & 0x80) { | ||||||
|  | @ -55,11 +55,14 @@ void Keyboard::handleIRQ() | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if (!m_modifiers) |             if (!m_modifiers) | ||||||
|                 kprintf("%c", map[ch]); |                 m_queue.enqueue(map[ch]); | ||||||
|             else if (m_modifiers & MOD_SHIFT) |             else if (m_modifiers & MOD_SHIFT) | ||||||
|                 kprintf("%c", shift_map[ch]); |                 m_queue.enqueue(shift_map[ch]); | ||||||
|             else if (m_modifiers & MOD_CTRL) |             else if (m_modifiers & MOD_CTRL) { | ||||||
|                 kprintf("^%c", shift_map[ch]); |                 // FIXME: This is obviously not a good enough way to process ctrl+whatever.
 | ||||||
|  |                 m_queue.enqueue('^'); | ||||||
|  |                 m_queue.enqueue(shift_map[ch]); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         //break;
 |         //break;
 | ||||||
|     } |     } | ||||||
|  | @ -81,3 +84,18 @@ Keyboard::~Keyboard() | ||||||
|     ASSERT_NOT_REACHED(); |     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 | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <AK/Types.h> | #include <AK/Types.h> | ||||||
|  | #include <AK/DoublyLinkedList.h> | ||||||
|  | #include <AK/CircularQueue.h> | ||||||
|  | #include <VirtualFileSystem/CharacterDevice.h> | ||||||
| #include "IRQHandler.h" | #include "IRQHandler.h" | ||||||
| 
 | 
 | ||||||
| class Keyboard final : public IRQHandler { | class Keyboard final : public IRQHandler, public CharacterDevice { | ||||||
| public: | public: | ||||||
|     virtual ~Keyboard() override; |     virtual ~Keyboard() override; | ||||||
|     Keyboard(); |     Keyboard(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |     // ^IRQHandler
 | ||||||
|     virtual void handleIRQ() override; |     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 }; |     byte m_modifiers { 0 }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -156,8 +156,28 @@ byte* MemoryManager::quickMapOnePage(PhysicalAddress physicalAddress) | ||||||
|     return (byte*)(4 * MB); |     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) | bool MemoryManager::unmapRegionsForTask(Task& task) | ||||||
| { | { | ||||||
|  |     for (auto& region : task.m_regions) { | ||||||
|  |         if (!unmapRegion(task, *region)) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -51,6 +51,7 @@ public: | ||||||
|     byte* quickMapOnePage(PhysicalAddress); |     byte* quickMapOnePage(PhysicalAddress); | ||||||
| 
 | 
 | ||||||
|     bool mapRegion(Task&, Task::Region&); |     bool mapRegion(Task&, Task::Region&); | ||||||
|  |     bool unmapRegion(Task&, Task::Region&); | ||||||
|     bool mapRegionsForTask(Task&); |     bool mapRegionsForTask(Task&); | ||||||
|     bool unmapRegionsForTask(Task&); |     bool unmapRegionsForTask(Task&); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ asm( | ||||||
|     "    pushw %ss\n" |     "    pushw %ss\n" | ||||||
|     "    pushw %ss\n" |     "    pushw %ss\n" | ||||||
|     "    pushw %ss\n" |     "    pushw %ss\n" | ||||||
|  |     "    pushw %ss\n" | ||||||
|     "    popw %ds\n" |     "    popw %ds\n" | ||||||
|     "    popw %es\n" |     "    popw %es\n" | ||||||
|     "    popw %fs\n" |     "    popw %fs\n" | ||||||
|  | @ -29,6 +30,7 @@ asm( | ||||||
|     "    mov %esp, syscallRegDump\n" |     "    mov %esp, syscallRegDump\n" | ||||||
|     "    call syscall_entry\n" |     "    call syscall_entry\n" | ||||||
|     "    popw %gs\n" |     "    popw %gs\n" | ||||||
|  |     "    popw %gs\n" | ||||||
|     "    popw %fs\n" |     "    popw %fs\n" | ||||||
|     "    popw %es\n" |     "    popw %es\n" | ||||||
|     "    popw %ds\n" |     "    popw %ds\n" | ||||||
|  | @ -58,15 +60,16 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) | ||||||
|         //kprintf("syscall: sleep(%d)\n", arg1);
 |         //kprintf("syscall: sleep(%d)\n", arg1);
 | ||||||
|         current->sys$sleep(arg1); |         current->sys$sleep(arg1); | ||||||
|         break; |         break; | ||||||
|  |     case Syscall::Spawn: | ||||||
|  |         return current->sys$spawn((const char*)arg1); | ||||||
|     case Syscall::PosixOpen: |     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); |         return current->sys$open((const char*)arg1, (size_t)arg2); | ||||||
|     case Syscall::PosixClose: |     case Syscall::PosixClose: | ||||||
|         kprintf("syscall: close(%d)\n", arg1); |         //kprintf("syscall: close(%d)\n", arg1);
 | ||||||
|         return current->sys$close((int)arg1); |         return current->sys$close((int)arg1); | ||||||
|     case Syscall::PosixRead: |     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); |         return current->sys$read((int)arg1, (void*)arg2, (size_t)arg3); | ||||||
|     case Syscall::PosixSeek: |     case Syscall::PosixSeek: | ||||||
|         // FIXME: This has the wrong signature, should be like lseek()
 |         // FIXME: This has the wrong signature, should be like lseek()
 | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| namespace Syscall { | namespace Syscall { | ||||||
| 
 | 
 | ||||||
| enum Function { | enum Function { | ||||||
|  |     Spawn = 0x1981, | ||||||
|     Sleep = 0x1982, |     Sleep = 0x1982, | ||||||
|     Yield = 0x1983, |     Yield = 0x1983, | ||||||
|     PutCharacter = 1984, |     PutCharacter = 1984, | ||||||
|  |  | ||||||
|  | @ -10,6 +10,8 @@ | ||||||
| #include <ELFLoader/ExecSpace.h> | #include <ELFLoader/ExecSpace.h> | ||||||
| #include "MemoryManager.h" | #include "MemoryManager.h" | ||||||
| 
 | 
 | ||||||
|  | //#define DEBUG_IO
 | ||||||
|  | 
 | ||||||
| Task* current; | Task* current; | ||||||
| Task* s_kernelTask; | Task* s_kernelTask; | ||||||
| 
 | 
 | ||||||
|  | @ -104,6 +106,14 @@ Task::Region* Task::allocateRegion(size_t size, String&& name) | ||||||
|     return m_regions.last().ptr(); |     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) | Task* Task::create(const String& path, uid_t uid, gid_t gid) | ||||||
| { | { | ||||||
|     auto parts = path.split('/'); |     auto parts = path.split('/'); | ||||||
|  | @ -118,6 +128,7 @@ Task* Task::create(const String& path, uid_t uid, gid_t gid) | ||||||
|     if (!elfData) |     if (!elfData) | ||||||
|         return nullptr; |         return nullptr; | ||||||
| 
 | 
 | ||||||
|  |     cli(); | ||||||
|     Task* t = new Task(parts.takeLast(), uid, gid); |     Task* t = new Task(parts.takeLast(), uid, gid); | ||||||
| 
 | 
 | ||||||
|     ExecSpace space; |     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"); |     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); |     s_tasks->prepend(t); | ||||||
|     system.nprocess++; |     system.nprocess++; | ||||||
|     kprintf("Task %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip); |     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.
 |     // NOTE: This is called from an excepton handler, so interrupts are disabled.
 | ||||||
|     crashedTask->setState(Crashing); |     crashedTask->setState(Crashing); | ||||||
|     crashedTask->dumpRegions(); | //  crashedTask->dumpRegions();
 | ||||||
| 
 | 
 | ||||||
|     s_tasks->remove(crashedTask); |     s_tasks->remove(crashedTask); | ||||||
| 
 | 
 | ||||||
|  |     MemoryManager::the().unmapRegionsForTask(*crashedTask); | ||||||
|  | 
 | ||||||
|     if (!scheduleNewTask()) { |     if (!scheduleNewTask()) { | ||||||
|         kprintf("Task::taskDidCrash: Failed to schedule a new task :(\n"); |         kprintf("Task::taskDidCrash: Failed to schedule a new task :(\n"); | ||||||
|         HANG; |         HANG; | ||||||
|  | @ -491,7 +509,16 @@ static bool contextSwitch(Task* t) | ||||||
|     // Some sanity checking to force a crash earlier.
 |     // Some sanity checking to force a crash earlier.
 | ||||||
|     auto csRPL = t->tss().cs & 3; |     auto csRPL = t->tss().cs & 3; | ||||||
|     auto ssRPL = t->tss().ss & 3; |     auto ssRPL = t->tss().ss & 3; | ||||||
|  | 
 | ||||||
|  |     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); |         ASSERT(csRPL == ssRPL); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     if (current) { |     if (current) { | ||||||
|         // If the last task hasn't blocked (still marked as running),
 |         // 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) | ssize_t Task::sys$read(int fd, void* outbuf, size_t nread) | ||||||
| { | { | ||||||
|     Task::checkSanity("Task::sys$read"); |     Task::checkSanity("Task::sys$read"); | ||||||
|  | #ifdef DEBUG_IO | ||||||
|     kprintf("Task::sys$read: called(%d, %p, %u)\n", fd, outbuf, nread); |     kprintf("Task::sys$read: called(%d, %p, %u)\n", fd, outbuf, nread); | ||||||
|  | #endif | ||||||
|     auto* handle = fileHandleIfExists(fd); |     auto* handle = fileHandleIfExists(fd); | ||||||
|  | #ifdef DEBUG_IO | ||||||
|     kprintf("Task::sys$read: handle=%p\n", handle); |     kprintf("Task::sys$read: handle=%p\n", handle); | ||||||
|  | #endif | ||||||
|     if (!handle) { |     if (!handle) { | ||||||
|         kprintf("Task::sys$read: handle not found :(\n"); |         kprintf("Task::sys$read: handle not found :(\n"); | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|  | #ifdef DEBUG_IO | ||||||
|     kprintf("call read on handle=%p\n", handle); |     kprintf("call read on handle=%p\n", handle); | ||||||
|  | #endif | ||||||
|     nread = handle->read((byte*)outbuf, nread); |     nread = handle->read((byte*)outbuf, nread); | ||||||
|     kprintf("called read\n"); | #ifdef DEBUG_IO | ||||||
|     kprintf("Task::sys$read: nread=%u\n", nread); |     kprintf("Task::sys$read: nread=%u\n", nread); | ||||||
|  | #endif | ||||||
|     return nread; |     return nread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -598,7 +632,9 @@ int Task::sys$close(int fd) | ||||||
| int Task::sys$open(const char* path, size_t pathLength) | int Task::sys$open(const char* path, size_t pathLength) | ||||||
| { | { | ||||||
|     Task::checkSanity("sys$open"); |     Task::checkSanity("sys$open"); | ||||||
|  | #ifdef DEBUG_IO | ||||||
|     kprintf("Task::sys$open(): PID=%u, path=%s {%u}\n", m_pid, path, pathLength); |     kprintf("Task::sys$open(): PID=%u, path=%s {%u}\n", m_pid, path, pathLength); | ||||||
|  | #endif | ||||||
|     auto* handle = current->openFile(String(path, pathLength)); |     auto* handle = current->openFile(String(path, pathLength)); | ||||||
|     if (handle) |     if (handle) | ||||||
|         return handle->fd(); |         return handle->fd(); | ||||||
|  | @ -607,14 +643,15 @@ int Task::sys$open(const char* path, size_t pathLength) | ||||||
| 
 | 
 | ||||||
| FileHandle* Task::openFile(String&& path) | 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)); |     auto handle = VirtualFileSystem::the().open(move(path)); | ||||||
|     if (!handle) { |     if (!handle) { | ||||||
|         kprintf("vfs::open() failed\n"); |         kprintf("vfs::open() failed\n"); | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|     handle->setFD(m_fileHandles.size()); |     handle->setFD(m_fileHandles.size()); | ||||||
|  | #ifdef DEBUG_IO | ||||||
|     kprintf("vfs::open() worked! handle=%p, fd=%d\n", handle.ptr(), handle->fd()); |     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
 |     m_fileHandles.append(move(handle)); // FIXME: allow non-move Vector::append
 | ||||||
|     return m_fileHandles.last().ptr(); |     return m_fileHandles.last().ptr(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -90,6 +90,7 @@ public: | ||||||
|     int sys$geterror() { return m_error; } |     int sys$geterror() { return m_error; } | ||||||
|     void sys$sleep(DWORD ticks); |     void sys$sleep(DWORD ticks); | ||||||
|     void sys$exit(int status); |     void sys$exit(int status); | ||||||
|  |     int sys$spawn(const char* path); | ||||||
| 
 | 
 | ||||||
|     struct |     struct | ||||||
|     { |     { | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							|  | @ -78,6 +78,7 @@ asm( \ | ||||||
|     "    pushw %ss\n" \ |     "    pushw %ss\n" \ | ||||||
|     "    pushw %ss\n" \ |     "    pushw %ss\n" \ | ||||||
|     "    pushw %ss\n" \ |     "    pushw %ss\n" \ | ||||||
|  |     "    pushw %ss\n" \ | ||||||
|     "    popw %ds\n" \ |     "    popw %ds\n" \ | ||||||
|     "    popw %es\n" \ |     "    popw %es\n" \ | ||||||
|     "    popw %fs\n" \ |     "    popw %fs\n" \ | ||||||
|  | @ -85,6 +86,7 @@ asm( \ | ||||||
|     "    mov %esp, exception_state_dump\n" \ |     "    mov %esp, exception_state_dump\n" \ | ||||||
|     "    call exception_" # ec "_handler\n" \ |     "    call exception_" # ec "_handler\n" \ | ||||||
|     "    popw %gs\n" \ |     "    popw %gs\n" \ | ||||||
|  |     "    popw %gs\n" \ | ||||||
|     "    popw %fs\n" \ |     "    popw %fs\n" \ | ||||||
|     "    popw %es\n" \ |     "    popw %es\n" \ | ||||||
|     "    popw %ds\n" \ |     "    popw %ds\n" \ | ||||||
|  | @ -107,6 +109,7 @@ asm( \ | ||||||
|     "    pushw %ss\n" \ |     "    pushw %ss\n" \ | ||||||
|     "    pushw %ss\n" \ |     "    pushw %ss\n" \ | ||||||
|     "    pushw %ss\n" \ |     "    pushw %ss\n" \ | ||||||
|  |     "    pushw %ss\n" \ | ||||||
|     "    popw %ds\n" \ |     "    popw %ds\n" \ | ||||||
|     "    popw %es\n" \ |     "    popw %es\n" \ | ||||||
|     "    popw %fs\n" \ |     "    popw %fs\n" \ | ||||||
|  | @ -114,6 +117,7 @@ asm( \ | ||||||
|     "    mov %esp, exception_state_dump\n" \ |     "    mov %esp, exception_state_dump\n" \ | ||||||
|     "    call exception_" # ec "_handler\n" \ |     "    call exception_" # ec "_handler\n" \ | ||||||
|     "    popw %gs\n" \ |     "    popw %gs\n" \ | ||||||
|  |     "    popw %gs\n" \ | ||||||
|     "    popw %fs\n" \ |     "    popw %fs\n" \ | ||||||
|     "    popw %es\n" \ |     "    popw %es\n" \ | ||||||
|     "    popw %ds\n" \ |     "    popw %ds\n" \ | ||||||
|  |  | ||||||
|  | @ -119,6 +119,7 @@ private: | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct RegisterDump { | struct RegisterDump { | ||||||
|  |     WORD ss; | ||||||
|     WORD gs; |     WORD gs; | ||||||
|     WORD fs; |     WORD fs; | ||||||
|     WORD es; |     WORD es; | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ asm( | ||||||
|     "    pushw %ss\n" |     "    pushw %ss\n" | ||||||
|     "    pushw %ss\n" |     "    pushw %ss\n" | ||||||
|     "    pushw %ss\n" |     "    pushw %ss\n" | ||||||
|  |     "    pushw %ss\n" | ||||||
|     "    popw %ds\n" |     "    popw %ds\n" | ||||||
|     "    popw %es\n" |     "    popw %es\n" | ||||||
|     "    popw %fs\n" |     "    popw %fs\n" | ||||||
|  | @ -35,6 +36,7 @@ asm( | ||||||
|     "    mov %esp, state_dump\n" |     "    mov %esp, state_dump\n" | ||||||
|     "    call clock_handle\n" |     "    call clock_handle\n" | ||||||
|     "    popw %gs\n" |     "    popw %gs\n" | ||||||
|  |     "    popw %gs\n" | ||||||
|     "    popw %fs\n" |     "    popw %fs\n" | ||||||
|     "    popw %es\n" |     "    popw %es\n" | ||||||
|     "    popw %ds\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?
 |     //        If this IRQ occurred while in a user task, wouldn't that also push the stack ptr?
 | ||||||
|     current->tss().esp = regs.esp + 12; |     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.ss; | ||||||
|     current->tss().ss = regs.ds; |  | ||||||
| 
 | 
 | ||||||
|     if ((current->tss().cs & 3) != 0) { |     if ((current->tss().cs & 3) != 0) { | ||||||
|         // What do I do now?
 | #if 0 | ||||||
|         kprintf("clk'ed across to ring0\n"); |         kprintf("clock'ed across to ring0\n"); | ||||||
|         HANG; |         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;
 |     // Prepare a new task to run;
 | ||||||
|  |  | ||||||
|  | @ -99,13 +99,12 @@ static void init_stage2() | ||||||
| { | { | ||||||
|     kprintf("init stage2...\n"); |     kprintf("init stage2...\n"); | ||||||
| 
 | 
 | ||||||
|     // Anything that registers interrupts goes *after* PIC and IDT for obvious reasons.
 |  | ||||||
|     Syscall::initialize(); |     Syscall::initialize(); | ||||||
| 
 | 
 | ||||||
|  |     auto keyboard = make<Keyboard>(); | ||||||
|  | 
 | ||||||
|     extern void panel_main(); |     extern void panel_main(); | ||||||
| 
 |  | ||||||
|     new Task(panel_main, "panel", IPC::Handle::PanelTask, Task::Ring0); |     new Task(panel_main, "panel", IPC::Handle::PanelTask, Task::Ring0); | ||||||
| 
 |  | ||||||
|     //new Task(led_disco, "led-disco", IPC::Handle::Any, Task::Ring0);
 |     //new Task(led_disco, "led-disco", IPC::Handle::Any, Task::Ring0);
 | ||||||
| 
 | 
 | ||||||
|     Disk::initialize(); |     Disk::initialize(); | ||||||
|  | @ -125,6 +124,8 @@ static void init_stage2() | ||||||
|     auto dev_random = make<RandomDevice>(); |     auto dev_random = make<RandomDevice>(); | ||||||
|     vfs->registerCharacterDevice(1, 8, *dev_random); |     vfs->registerCharacterDevice(1, 8, *dev_random); | ||||||
| 
 | 
 | ||||||
|  |     vfs->registerCharacterDevice(85, 1, *keyboard); | ||||||
|  | 
 | ||||||
|     auto dev_hd0 = IDEDiskDevice::create(); |     auto dev_hd0 = IDEDiskDevice::create(); | ||||||
|     auto e2fs = Ext2FileSystem::create(dev_hd0.copyRef()); |     auto e2fs = Ext2FileSystem::create(dev_hd0.copyRef()); | ||||||
|     e2fs->initialize(); |     e2fs->initialize(); | ||||||
|  | @ -167,7 +168,9 @@ static void init_stage2() | ||||||
|     } |     } | ||||||
| #endif | #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(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0);
 | ||||||
|     //new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3);
 |     //new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3);
 | ||||||
|  | @ -206,8 +209,6 @@ void init() | ||||||
|     VirtualFileSystem::initializeGlobals(); |     VirtualFileSystem::initializeGlobals(); | ||||||
|     StringImpl::initializeGlobals(); |     StringImpl::initializeGlobals(); | ||||||
| 
 | 
 | ||||||
|     auto keyboard = make<Keyboard>(); |  | ||||||
| 
 |  | ||||||
|     PIT::initialize(); |     PIT::initialize(); | ||||||
| 
 | 
 | ||||||
|     memset(&system, 0, sizeof(system)); |     memset(&system, 0, sizeof(system)); | ||||||
|  |  | ||||||
|  | @ -3,6 +3,6 @@ | ||||||
| #include "kprintf.h" | #include "kprintf.h" | ||||||
| 
 | 
 | ||||||
| #define CRASH() do { asm volatile("ud2"); } while(0) | #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 RELEASE_ASSERT(x) do { if (!(x)) CRASH(); } while(0) | ||||||
| #define ASSERT_NOT_REACHED() ASSERT(false) | #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 = \
 | OBJS = \
 | ||||||
|        stdio.o \
 |        stdio.o \
 | ||||||
|        unistd.o \
 |        unistd.o \
 | ||||||
|  |        string.o \
 | ||||||
|  |        process.o \
 | ||||||
|        entry.o |        entry.o | ||||||
| 
 | 
 | ||||||
| LIBRARY = LibC.a | 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) | int putchar(int ch) | ||||||
| { | { | ||||||
|     return ch; |     Syscall::invoke(Syscall::PutCharacter, ch); | ||||||
|  |     return (byte)ch; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int printf(const char* fmt, ...) | 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 short word; | ||||||
| typedef unsigned char byte; | 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 uid_t; | ||||||
| typedef dword gid_t; | typedef dword gid_t; | ||||||
| typedef dword pid_t; | typedef dword pid_t; | ||||||
| 
 | 
 | ||||||
|  | typedef dword size_t; | ||||||
|  | typedef signed_dword ssize_t; | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| #include "unistd.h" | #include "unistd.h" | ||||||
|  | #include "string.h" | ||||||
| #include <Kernel/Syscall.h> | #include <Kernel/Syscall.h> | ||||||
| 
 | 
 | ||||||
| extern "C" { | extern "C" { | ||||||
|  | @ -18,5 +19,21 @@ uid_t getpid() | ||||||
|     return Syscall::invoke(Syscall::PosixGetpid); |     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(); | uid_t getuid(); | ||||||
| gid_t getgid(); | gid_t getgid(); | ||||||
| pid_t getpid(); | 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 | id | ||||||
|  | sh | ||||||
| *.o | *.o | ||||||
|  |  | ||||||
|  | @ -1,8 +1,10 @@ | ||||||
| OBJS = \
 | OBJS = \
 | ||||||
|        id.o |        id.o \
 | ||||||
|  |        sh.o | ||||||
| 
 | 
 | ||||||
| APPS = \
 | APPS = \
 | ||||||
|        id |        id \
 | ||||||
|  |        sh | ||||||
| 
 | 
 | ||||||
| ARCH_FLAGS = | ARCH_FLAGS = | ||||||
| STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib | STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib | ||||||
|  | @ -25,6 +27,9 @@ all: $(OBJS) $(APPS) | ||||||
| id: id.o | id: id.o | ||||||
| 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | ||||||
| 
 | 
 | ||||||
|  | sh: sh.o | ||||||
|  | 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | ||||||
|  | 
 | ||||||
| .cpp.o: | .cpp.o: | ||||||
| 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< | 	@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