mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 09:04:59 +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