1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 22:27:35 +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:
Andreas Kling 2018-10-23 10:12:50 +02:00
parent 72514c8b97
commit fe237ee215
29 changed files with 276 additions and 32 deletions

View file

@ -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;
}

View file

@ -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 };
};

View file

@ -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;
}

View file

@ -51,6 +51,7 @@ public:
byte* quickMapOnePage(PhysicalAddress);
bool mapRegion(Task&, Task::Region&);
bool unmapRegion(Task&, Task::Region&);
bool mapRegionsForTask(Task&);
bool unmapRegionsForTask(Task&);

View file

@ -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()

View file

@ -10,6 +10,7 @@
namespace Syscall {
enum Function {
Spawn = 0x1981,
Sleep = 0x1982,
Yield = 0x1983,
PutCharacter = 1984,

View file

@ -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();
}

View file

@ -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.

View file

@ -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" \

View file

@ -119,6 +119,7 @@ private:
};
struct RegisterDump {
WORD ss;
WORD gs;
WORD fs;
WORD es;

View file

@ -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;

View file

@ -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));

View file

@ -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
View file

@ -0,0 +1,5 @@
mkdir mnt
mount -o loop _fs_contents mnt/
cp ../Userland/sh mnt/bin/sh
umount mnt
sync