diff --git a/Kernel/Keyboard.cpp b/Kernel/Keyboard.cpp index 9a34c2f88c..bcde36a17f 100644 --- a/Kernel/Keyboard.cpp +++ b/Kernel/Keyboard.cpp @@ -38,6 +38,12 @@ static char shift_map[0x100] = 0, 0, 0, ' ' }; +void Keyboard::emit(byte ch) +{ + if (m_client) + m_client->onKeyPress(ch); + m_queue.enqueue(ch); +} void Keyboard::handleIRQ() { @@ -50,7 +56,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 */ m_queue.enqueue('\n'); break; + case 0x1C: /* enter */ emit('\n'); break; case 0xFA: /* i8042 ack */ break; default: if (ch & 0x80) { @@ -69,31 +75,33 @@ void Keyboard::handleIRQ() } } if (!m_modifiers) { - if (m_client) - m_client->onKeyPress(map[ch]); - m_queue.enqueue(map[ch]); + emit(map[ch]); } else if (m_modifiers & MOD_SHIFT) { - if (m_client) - m_client->onKeyPress(shift_map[ch]); - m_queue.enqueue(shift_map[ch]); + emit(shift_map[ch]); } else if (m_modifiers & MOD_CTRL) { // FIXME: This is obviously not a good enough way to process ctrl+whatever. - if (m_client) { - m_client->onKeyPress('^'); - m_client->onKeyPress(shift_map[ch]); - } - m_queue.enqueue('^'); - m_queue.enqueue(shift_map[ch]); + emit('^'); + emit(shift_map[ch]); } } //break; } } +static Keyboard* s_the; + +Keyboard& Keyboard::the() +{ + ASSERT(s_the); + return *s_the; +} + Keyboard::Keyboard() : IRQHandler(IRQ_KEYBOARD) , CharacterDevice(85, 1) { + s_the = this; + // Empty the buffer of any pending data. // I don't care what you've been pressing until now! while (IO::in8(I8042_STATUS ) & DATA_AVAILABLE) diff --git a/Kernel/Keyboard.h b/Kernel/Keyboard.h index 21334cf714..3b8e75c747 100644 --- a/Kernel/Keyboard.h +++ b/Kernel/Keyboard.h @@ -19,7 +19,7 @@ public: virtual ~Keyboard() override; Keyboard(); - void setClient(KeyboardClient*); + void setClient(KeyboardClient* client) { m_client = client; } private: // ^IRQHandler @@ -30,6 +30,8 @@ private: virtual ssize_t write(const byte* buffer, size_t) override; virtual bool hasDataAvailableForRead() const override; + void emit(byte); + KeyboardClient* m_client { nullptr }; CircularQueue m_queue; byte m_modifiers { 0 }; diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp index e56320df2c..ff8495a723 100644 --- a/Kernel/ProcFileSystem.cpp +++ b/Kernel/ProcFileSystem.cpp @@ -201,15 +201,16 @@ ByteBuffer procfs$summary() auto tasks = Task::allTasks(); auto buffer = ByteBuffer::createUninitialized(tasks.size() * 256); char* ptr = (char*)buffer.pointer(); - ptr += ksprintf(ptr, "PID OWNER STATE PPID NSCHED FDS NAME\n"); + ptr += ksprintf(ptr, "PID OWNER STATE PPID NSCHED FDS TTY NAME\n"); for (auto* task : tasks) { - ptr += ksprintf(ptr, "% 5u % 4u % 8s % 5u % 10u % 3u %s\n", + ptr += ksprintf(ptr, "% 5u % 4u % 8s % 5u % 10u % 3u % 4s %s\n", task->pid(), task->uid(), toString(task->state()), task->parentPID(), task->timesScheduled(), task->fileHandleCount(), + task->tty() ? task->tty()->ttyName().characters() : "n/a", task->name().characters()); } *ptr = '\0'; diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 279d84a451..8fd578166c 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -70,6 +70,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) return current->sys$getcwd((char*)arg1, (size_t)arg2); case Syscall::PosixOpen: return current->sys$open((const char*)arg1, (int)arg2); + case Syscall::PosixWrite: + return current->sys$write((int)arg1, (const void*)arg2, (size_t)arg3); case Syscall::PosixClose: //kprintf("syscall: close(%d)\n", arg1); return current->sys$close((int)arg1); diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index b35c95b233..7cdfecaea4 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -36,6 +36,7 @@ enum Function { PosixUname = 0x2004, SetMmapName = 0x2005, PosixReadlink = 0x2006, + PosixWrite = 0x2007, }; void initialize(); diff --git a/Kernel/TTY.cpp b/Kernel/TTY.cpp index e3196a0015..c2f4c10ec6 100644 --- a/Kernel/TTY.cpp +++ b/Kernel/TTY.cpp @@ -11,15 +11,30 @@ TTY::~TTY() ssize_t TTY::read(byte* buffer, size_t size) { - return 0; + ssize_t nread = min(m_buffer.size(), size); + memcpy(buffer, m_buffer.data(), nread); + if (nread == m_buffer.size()) + m_buffer.clear(); + else { + dbgprintf("had %u, read %u\n", m_buffer.size(), nread); + ASSERT_NOT_REACHED(); + } + return nread; } ssize_t TTY::write(const byte* buffer, size_t size) { + for (size_t i = 0; i < size; ++i) + onTTYWrite(buffer[i]); return 0; } bool TTY::hasDataAvailableForRead() const { - return false; + return !m_buffer.isEmpty(); +} + +void TTY::emit(byte ch) +{ + m_buffer.append(ch); } diff --git a/Kernel/TTY.h b/Kernel/TTY.h index fe42643b37..7b00f4ba90 100644 --- a/Kernel/TTY.h +++ b/Kernel/TTY.h @@ -10,7 +10,15 @@ public: virtual ssize_t write(const byte*, size_t) override; virtual bool hasDataAvailableForRead() const override; + virtual String ttyName() const = 0; + protected: TTY(unsigned major, unsigned minor); + void emit(byte); + + virtual void onTTYWrite(byte) = 0; + +private: + Vector m_buffer; }; diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 63bbfcb1f5..f948d431e1 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -214,13 +214,13 @@ int Task::sys$gethostname(char* buffer, size_t size) int Task::sys$spawn(const char* path, const char** args) { int error = 0; - auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid, error, args); + auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid, error, args, m_tty); if (child) return child->pid(); return error; } -Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t parentPID, int& error, const char** args) +Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t parentPID, int& error, const char** args, TTY* tty) { auto parts = path.split('/'); if (parts.isEmpty()) { @@ -262,7 +262,7 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren } InterruptDisabler disabler; // FIXME: Get rid of this, jesus christ. This "critical" section is HUGE. - Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3, move(cwd), handle->vnode()); + Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3, move(cwd), handle->vnode(), tty); t->m_arguments = move(taskArguments); @@ -372,8 +372,8 @@ Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring, , m_ring(ring) , m_cwd(move(cwd)) , m_executable(move(executable)) - , m_parentPID(parentPID) , m_tty(tty) + , m_parentPID(parentPID) { if (tty) { m_fileHandles.append(tty->open(O_RDONLY)); // stdin @@ -753,6 +753,25 @@ int Task::sys$seek(int fd, int offset) return handle->seek(offset, SEEK_SET); } +ssize_t Task::sys$write(int fd, const void* data, size_t size) +{ + VALIDATE_USER_BUFFER(data, size); +#ifdef DEBUG_IO + kprintf("Task::sys$write: called(%d, %p, %u)\n", fd, data, size); +#endif + auto* handle = fileHandleIfExists(fd); +#ifdef DEBUG_IO + kprintf("Task::sys$write: handle=%p\n", handle); +#endif + if (!handle) + return -EBADF; + auto nwritten = handle->write((const byte*)data, size); +#ifdef DEBUG_IO + kprintf("Task::sys$write: nwritten=%u\n", nwritten); +#endif + return nwritten; +} + ssize_t Task::sys$read(int fd, void* outbuf, size_t nread) { VALIDATE_USER_BUFFER(outbuf, nread); @@ -763,13 +782,8 @@ ssize_t Task::sys$read(int fd, void* outbuf, size_t nread) #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 + if (!handle) + return -EBADF; if (handle->isBlocking()) { if (!handle->hasDataAvailableForRead()) { m_fdBlockedOnRead = fd; diff --git a/Kernel/Task.h b/Kernel/Task.h index 73cc504a79..d8661c9acd 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -20,7 +20,7 @@ class Task : public InlineLinkedListNode { struct Subregion; public: static Task* createKernelTask(void (*entry)(), String&& name); - static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr); + static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr, TTY* = nullptr); ~Task(); static Vector allTasks(); @@ -90,7 +90,8 @@ public: pid_t sys$getpid(); int sys$open(const char* path, int options); int sys$close(int fd); - int sys$read(int fd, void* outbuf, size_t nread); + ssize_t sys$read(int fd, void* outbuf, size_t nread); + ssize_t sys$write(int fd, const void*, size_t); int sys$lstat(const char*, Unix::stat*); int sys$seek(int fd, int offset); int sys$kill(pid_t pid, int sig); @@ -115,6 +116,8 @@ public: static void taskDidCrash(Task*); + const TTY* tty() const { return m_tty; } + size_t regionCount() const { return m_regions.size(); } const Vector>& regions() const { return m_regions; } size_t subregionCount() const { return m_regions.size(); } diff --git a/Kernel/VGA.cpp b/Kernel/VGA.cpp index ebb39a5c4a..d048fe01d4 100644 --- a/Kernel/VGA.cpp +++ b/Kernel/VGA.cpp @@ -31,16 +31,11 @@ void vga_clear() vga_clear_row(i); } -void vga_putch_at(byte row, byte column, byte ch) +void vga_putch_at(byte row, byte column, byte ch, byte attr) { word cur = (row * 160) + (column * 2); vga_mem[cur] = ch; - vga_mem[cur + 1] = current_attr; -} - -void vga_set_attr(BYTE attr) -{ - current_attr = attr; + vga_mem[cur + 1] = attr; } byte vga_get_attr() diff --git a/Kernel/VGA.h b/Kernel/VGA.h index 2c34affe3f..f477a61090 100644 --- a/Kernel/VGA.h +++ b/Kernel/VGA.h @@ -3,12 +3,10 @@ #include "types.h" void vga_init(); -BYTE vga_get_attr(); -void vga_set_attr(BYTE); void vga_set_cursor(WORD); void vga_set_cursor(BYTE row, BYTE column); WORD vga_get_cursor(); -void vga_putch_at(byte row, byte column, byte ch); +void vga_putch_at(byte row, byte column, byte ch, byte attr); void vga_scroll_up(); void vga_clear(); void vga_clear_row(word); diff --git a/Kernel/VirtualConsole.cpp b/Kernel/VirtualConsole.cpp index 8d9e4a8ae3..d8d36f2f50 100644 --- a/Kernel/VirtualConsole.cpp +++ b/Kernel/VirtualConsole.cpp @@ -3,16 +3,17 @@ #include "kmalloc.h" #include "i386.h" #include "StdLib.h" +#include "Keyboard.h" #include static byte* s_vgaBuffer = (byte*)0xb8000; static VirtualConsole* s_consoles[6]; -static unsigned s_activeConsole; +static int s_activeConsole; void VirtualConsole::initialize() { memset(s_consoles, 0, sizeof(s_consoles)); - s_activeConsole = 0; + s_activeConsole = -1; } VirtualConsole::VirtualConsole(unsigned index, InitialContents initialContents) @@ -40,7 +41,7 @@ VirtualConsole::~VirtualConsole() void VirtualConsole::switchTo(unsigned index) { - if (index == s_activeConsole) + if ((int)index == s_activeConsole) return; dbgprintf("[VC] Switch to %u\n", index); ASSERT(index < 6); @@ -49,6 +50,7 @@ void VirtualConsole::switchTo(unsigned index) s_consoles[s_activeConsole]->setActive(false); s_activeConsole = index; s_consoles[s_activeConsole]->setActive(true); + Console::the().setImplementation(s_consoles[s_activeConsole]); } void VirtualConsole::setActive(bool b) @@ -60,14 +62,14 @@ void VirtualConsole::setActive(bool b) m_active = b; if (!m_active) { - dbgprintf("%u becomes inactive, copying to buffer\n", m_index); memcpy(m_buffer, s_vgaBuffer, 80 * 25 * 2); return; } - dbgprintf("%u becomes active, copying from buffer, set cursor %u,%u\n", m_index, m_cursorRow, m_cursorColumn); memcpy(s_vgaBuffer, m_buffer, 80 * 25 * 2); vga_set_cursor(m_cursorRow, m_cursorColumn); + + Keyboard::the().setClient(this); } inline bool isParameter(byte ch) @@ -205,7 +207,6 @@ void VirtualConsole::escape$m(const Vector& params) break; } } - vga_set_attr(m_currentAttribute); } void VirtualConsole::escape$s(const Vector&) @@ -216,9 +217,7 @@ void VirtualConsole::escape$s(const Vector&) void VirtualConsole::escape$u(const Vector&) { - m_cursorRow = m_savedCursorRow; - m_cursorColumn = m_savedCursorColumn; - vga_set_cursor(m_cursorRow, m_cursorColumn); + setCursor(m_savedCursorRow, m_savedCursorColumn); } void VirtualConsole::escape$H(const Vector& params) @@ -229,9 +228,7 @@ void VirtualConsole::escape$H(const Vector& params) row = params[0]; if (params.size() >= 2) col = params[1]; - m_cursorRow = row - 1; - m_cursorColumn = col - 1; - vga_set_cursor(row - 1, col - 1); + setCursor(row - 1, col - 1); } void VirtualConsole::escape$J(const Vector& params) @@ -284,16 +281,42 @@ void VirtualConsole::executeEscapeSequence(byte final) m_intermediates.clear(); } -void VirtualConsole::onChar(byte ch) +void VirtualConsole::scrollUp() { - auto scrollup = [&] { - if (m_cursorRow == (m_rows - 1)) { + if (m_cursorRow == (m_rows - 1)) { + memcpy(m_buffer, m_buffer + 160, 160 * 24); + word* linemem = (word*)&m_buffer[24 * 160]; + for (word i = 0; i < 80; ++i) + linemem[i] = 0x0720; + if (m_active) vga_scroll_up(); - } else { - ++m_cursorRow; - } - m_cursorColumn = 0; - }; + } else { + ++m_cursorRow; + } + m_cursorColumn = 0; +} + +void VirtualConsole::setCursor(unsigned row, unsigned column) +{ + m_cursorRow = row; + m_cursorColumn = column; + if (m_active) + vga_set_cursor(m_cursorRow, m_cursorColumn); +} + +void VirtualConsole::putCharacterAt(unsigned row, unsigned column, byte ch) +{ + word cur = (row * 160) + (column * 2); + m_buffer[cur] = ch; + m_buffer[cur + 1] = m_currentAttribute; + if (m_active) + vga_putch_at(row, column, ch, m_currentAttribute); +} + +void VirtualConsole::onChar(byte ch, bool shouldEmit) +{ + if (shouldEmit) + emit(ch); switch (m_escState) { case ExpectBracket: @@ -336,32 +359,43 @@ void VirtualConsole::onChar(byte ch) return; case 8: // Backspace if (m_cursorColumn) { - --m_cursorColumn;\ - vga_set_cursor(m_cursorRow, m_cursorColumn); - vga_putch_at(m_cursorRow, m_cursorColumn, ' '); + setCursor(m_cursorRow, m_cursorColumn - 1); + putCharacterAt(m_cursorRow, m_cursorColumn, ' '); return; } break; case '\n': - scrollup(); - vga_set_cursor(m_cursorRow, m_cursorColumn); + scrollUp(); + setCursor(m_cursorRow, m_cursorColumn); return; } - vga_putch_at(m_cursorRow, m_cursorColumn, ch); + putCharacterAt(m_cursorRow, m_cursorColumn, ch); ++m_cursorColumn; if (m_cursorColumn >= m_columns) - scrollup(); - vga_set_cursor(m_cursorRow, m_cursorColumn); + scrollUp(); + setCursor(m_cursorRow, m_cursorColumn); } void VirtualConsole::onKeyPress(byte ch) { - onChar(ch); + emit(ch); } void VirtualConsole::onConsoleReceive(byte ch) { - onChar(ch); + onChar(ch, false); +} + +void VirtualConsole::onTTYWrite(byte ch) +{ + onChar(ch, false); +} + +String VirtualConsole::ttyName() const +{ + char buf[8]; + ksprintf(buf, "tty%u", m_index); + return String(buf); } diff --git a/Kernel/VirtualConsole.h b/Kernel/VirtualConsole.h index 203bb99241..79b4f0b510 100644 --- a/Kernel/VirtualConsole.h +++ b/Kernel/VirtualConsole.h @@ -19,17 +19,25 @@ public: private: // ^KeyboardClient - void onKeyPress(byte) override; + virtual void onKeyPress(byte) override; // ^ConsoleImplementation - void onConsoleReceive(byte) override; + virtual void onConsoleReceive(byte) override; - void onChar(byte); + // ^TTY + virtual void onTTYWrite(byte) override; + virtual String ttyName() const override; + + void onChar(byte, bool shouldEmit); byte* m_buffer; unsigned m_index; bool m_active { false }; + void scrollUp(); + void setCursor(unsigned row, unsigned column); + void putCharacterAt(unsigned row, unsigned column, byte ch); + void escape$H(const Vector&); void escape$J(const Vector&); void escape$m(const Vector&); @@ -56,6 +64,4 @@ private: EscapeState m_escState { Normal }; Vector m_parameters; Vector m_intermediates; - }; - diff --git a/Kernel/i386.cpp b/Kernel/i386.cpp index 5a771a12c9..d2c968fa06 100644 --- a/Kernel/i386.cpp +++ b/Kernel/i386.cpp @@ -192,6 +192,8 @@ void exception_13_handler() EH_ENTRY(14); void exception_14_handler() { + ASSERT(current); + dword faultAddress; asm ("movl %%cr2, %%eax":"=a"(faultAddress)); @@ -249,7 +251,6 @@ void exception_14_handler() #define EH(i, msg) \ static void _exception ## i () \ { \ - vga_set_attr(0x0a); \ kprintf(msg"\n"); \ DWORD cr0, cr2, cr3, cr4; \ asm ("movl %%cr0, %%eax":"=a"(cr0)); \ diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 59d2e83444..a074614ef5 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -37,9 +37,11 @@ system_t system; VirtualConsole* tty0; VirtualConsole* tty1; VirtualConsole* tty2; +Keyboard* keyboard; void banner() { + InterruptDisabler disabler; kprintf("\n\033[33;1mWelcome to \033[36;1mSerenity OS!\033[0m\n\n"); } @@ -107,8 +109,6 @@ static void init_stage2() Syscall::initialize(); - auto keyboard = make(); - Disk::initialize(); #ifdef TEST_VFS @@ -189,11 +189,13 @@ static void init_stage2() } #endif - int error; - auto* shTask = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error); - banner(); + int error; + auto* sh0 = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty0); + auto* sh1 = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty1); + auto* sh2 = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty2); + #if 0 // It would be nice to exit this process, but right now it instantiates all kinds of things. // At the very least it needs to be made sure those things stick around as appropriate. @@ -216,21 +218,20 @@ void init() kmalloc_init(); vga_init(); - VirtualConsole::initialize(); - tty0 = new VirtualConsole(0, VirtualConsole::AdoptCurrentVGABuffer); - tty1 = new VirtualConsole(1); - tty2 = new VirtualConsole(2); - tty0->setActive(true); - tty1->setActive(false); - tty2->setActive(false); - auto console = make(); - console->setImplementation(tty0); - RTC::initialize(); PIC::initialize(); gdt_init(); idt_init(); + keyboard = new Keyboard; + + auto console = make(); + VirtualConsole::initialize(); + tty0 = new VirtualConsole(0, VirtualConsole::AdoptCurrentVGABuffer); + tty1 = new VirtualConsole(1); + tty2 = new VirtualConsole(2); + VirtualConsole::switchTo(0); + MemoryManager::initialize(); VirtualFileSystem::initializeGlobals(); diff --git a/LibC/stdio.cpp b/LibC/stdio.cpp index ed0a169ab8..b567c5df5c 100644 --- a/LibC/stdio.cpp +++ b/LibC/stdio.cpp @@ -3,6 +3,7 @@ #include "types.h" #include "string.h" #include "errno.h" +#include "unistd.h" #include #include @@ -10,13 +11,14 @@ extern "C" { int putchar(int ch) { - Syscall::invoke(Syscall::PutCharacter, ch); + write(0, &ch, 1); + //Syscall::invoke(Syscall::PutCharacter, ch); return (byte)ch; } -static void sys_putch(char*, char ch) +static void sys_putch(char*&, char ch) { - Syscall::invoke(Syscall::PutCharacter, ch); + putchar(ch); } int printf(const char* fmt, ...) diff --git a/LibC/unistd.cpp b/LibC/unistd.cpp index b554fcb549..75c543259d 100644 --- a/LibC/unistd.cpp +++ b/LibC/unistd.cpp @@ -32,6 +32,12 @@ ssize_t read(int fd, void* buf, size_t count) __RETURN_WITH_ERRNO(rc, rc, -1); } +ssize_t write(int fd, const void* buf, size_t count) +{ + int rc = Syscall::invoke(Syscall::PosixWrite, (dword)fd, (dword)buf, (dword)count); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + int close(int fd) { int rc = Syscall::invoke(Syscall::PosixClose, fd); diff --git a/LibC/unistd.h b/LibC/unistd.h index e4dcfd4ca3..ed78603d97 100644 --- a/LibC/unistd.h +++ b/LibC/unistd.h @@ -9,6 +9,7 @@ gid_t getgid(); pid_t getpid(); int open(const char* path, int options); ssize_t read(int fd, void* buf, size_t count); +ssize_t write(int fd, const void* buf, size_t count); int close(int fd); pid_t waitpid(pid_t, int* wstatus, int options); int chdir(const char* path); diff --git a/Userland/sh.cpp b/Userland/sh.cpp index 3592587078..b5ce26e329 100644 --- a/Userland/sh.cpp +++ b/Userland/sh.cpp @@ -159,7 +159,7 @@ int main(int, char**) int linedx = 0; linebuf[0] = '\0'; - int fd = open("/dev/keyboard", O_RDONLY); + int fd = 0; // open("/dev/keyboard", O_RDONLY); if (fd == -1) { printf("failed to open /dev/keyboard :(\n"); return 1; diff --git a/VirtualFileSystem/CharacterDevice.cpp b/VirtualFileSystem/CharacterDevice.cpp index 81405925e9..b249921bad 100644 --- a/VirtualFileSystem/CharacterDevice.cpp +++ b/VirtualFileSystem/CharacterDevice.cpp @@ -6,5 +6,5 @@ CharacterDevice::~CharacterDevice() OwnPtr CharacterDevice::open(int options) { - //VirtualFileSystem::the().open() + return VirtualFileSystem::the().open(*this, options); } diff --git a/VirtualFileSystem/FileHandle.cpp b/VirtualFileSystem/FileHandle.cpp index e6af798017..d68ef5343b 100644 --- a/VirtualFileSystem/FileHandle.cpp +++ b/VirtualFileSystem/FileHandle.cpp @@ -101,6 +101,16 @@ Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count) return nread; } +Unix::ssize_t FileHandle::write(const byte* data, Unix::size_t size) +{ + if (m_vnode->isCharacterDevice()) { + // FIXME: What should happen to m_currentOffset? + return m_vnode->characterDevice()->write(data, size); + } + // FIXME: Implement non-device writes. + ASSERT_NOT_REACHED(); +} + bool FileHandle::hasDataAvailableForRead() { if (m_vnode->isCharacterDevice()) diff --git a/VirtualFileSystem/FileHandle.h b/VirtualFileSystem/FileHandle.h index 9e8407f002..e442bf1224 100644 --- a/VirtualFileSystem/FileHandle.h +++ b/VirtualFileSystem/FileHandle.h @@ -10,7 +10,8 @@ public: ~FileHandle(); Unix::off_t seek(Unix::off_t, int whence); - Unix::ssize_t read(byte* buffer, Unix::size_t count); + Unix::ssize_t read(byte*, Unix::size_t); + Unix::ssize_t write(const byte* data, Unix::size_t); int stat(Unix::stat*); bool hasDataAvailableForRead(); diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index c69628cffc..ea2bf78d02 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -89,6 +89,21 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr return vnode; } +auto VirtualFileSystem::makeNode(CharacterDevice& device) -> RetainPtr +{ + auto vnode = allocateNode(); + ASSERT(vnode); + +#ifdef VFS_DEBUG + kprintf("makeNode: device=%p (%u,%u)\n", &device, device.major(), device.minor()); +#endif + + m_device2vnode.set(encodedDevice(device.major(), device.minor()), vnode.ptr()); + vnode->m_characterDevice = &device; + + return vnode; +} + auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr { auto it = m_inode2vnode.find(inode); @@ -97,6 +112,14 @@ auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr RetainPtr +{ + auto it = m_device2vnode.find(encodedDevice(device.major(), device.minor())); + if (it != m_device2vnode.end()) + return (*it).value; + return makeNode(device); +} + bool VirtualFileSystem::mount(RetainPtr&& fileSystem, const String& path) { ASSERT(fileSystem); @@ -161,10 +184,15 @@ void VirtualFileSystem::freeNode(Node* node) { ASSERT(node); ASSERT(node->inUse()); - m_inode2vnode.remove(node->inode); - node->inode.fileSystem()->release(); - node->inode = InodeIdentifier(); - node->m_characterDevice = nullptr; + if (node->inode.isValid()) { + m_inode2vnode.remove(node->inode); + node->inode.fileSystem()->release(); + node->inode = InodeIdentifier(); + } + if (node->m_characterDevice) { + m_device2vnode.remove(encodedDevice(node->m_characterDevice->major(), node->m_characterDevice->minor())); + node->m_characterDevice = nullptr; + } m_nodeFreeList.append(move(node)); } @@ -361,6 +389,14 @@ bool VirtualFileSystem::touch(const String& path) return inode.fileSystem()->setModificationTime(inode, ktime(nullptr)); } +OwnPtr VirtualFileSystem::open(CharacterDevice& device, int options) +{ + auto vnode = getOrCreateNode(device); + if (!vnode) + return nullptr; + return make(move(vnode)); +} + OwnPtr VirtualFileSystem::open(const String& path, int& error, int options, InodeIdentifier base) { auto inode = resolvePath(path, error, base, options); diff --git a/VirtualFileSystem/VirtualFileSystem.h b/VirtualFileSystem/VirtualFileSystem.h index e2860c669a..34f6d9ad08 100644 --- a/VirtualFileSystem/VirtualFileSystem.h +++ b/VirtualFileSystem/VirtualFileSystem.h @@ -51,7 +51,7 @@ public: InodeIdentifier inode; const InodeMetadata& metadata() const; - bool inUse() const { return inode.isValid(); } + bool inUse() const { return inode.isValid() || m_characterDevice; } bool isCharacterDevice() const { return m_characterDevice; } CharacterDevice* characterDevice() { return m_characterDevice; } @@ -91,6 +91,7 @@ public: bool mountRoot(RetainPtr&&); bool mount(RetainPtr&&, const String& path); + OwnPtr open(CharacterDevice&, int options); OwnPtr open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier()); OwnPtr create(const String& path, InodeIdentifier base = InodeIdentifier()); OwnPtr mkdir(const String& path, InodeIdentifier base = InodeIdentifier()); @@ -117,7 +118,9 @@ private: void freeNode(Node*); RetainPtr makeNode(InodeIdentifier); + RetainPtr makeNode(CharacterDevice&); RetainPtr getOrCreateNode(InodeIdentifier); + RetainPtr getOrCreateNode(CharacterDevice&); Mount* findMountForHost(InodeIdentifier); Mount* findMountForGuest(InodeIdentifier);