mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:12:45 +00:00 
			
		
		
		
	Virtual consoles kinda work!
We now make three VirtualConsoles at boot: tty0, tty1, and tty2. We launch an instance of /bin/sh in each one. You switch between them with Alt+1/2/3 How very very cool :^)
This commit is contained in:
		
							parent
							
								
									68739dc43e
								
							
						
					
					
						commit
						7a7956a595
					
				
					 24 changed files with 251 additions and 103 deletions
				
			
		|  | @ -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) | ||||
|  |  | |||
|  | @ -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<byte, 16> m_queue; | ||||
|     byte m_modifiers { 0 }; | ||||
|  |  | |||
|  | @ -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'; | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -36,6 +36,7 @@ enum Function { | |||
|     PosixUname = 0x2004, | ||||
|     SetMmapName = 0x2005, | ||||
|     PosixReadlink = 0x2006, | ||||
|     PosixWrite = 0x2007, | ||||
| }; | ||||
| 
 | ||||
| void initialize(); | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
|  |  | |||
|  | @ -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<byte> m_buffer; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ class Task : public InlineLinkedListNode<Task> { | |||
|     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<Task*> 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<RetainPtr<Region>>& regions() const { return m_regions; } | ||||
|     size_t subregionCount() const { return m_regions.size(); } | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -3,16 +3,17 @@ | |||
| #include "kmalloc.h" | ||||
| #include "i386.h" | ||||
| #include "StdLib.h" | ||||
| #include "Keyboard.h" | ||||
| #include <AK/String.h> | ||||
| 
 | ||||
| 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<unsigned>& params) | |||
|             break; | ||||
|         } | ||||
|     } | ||||
|     vga_set_attr(m_currentAttribute); | ||||
| } | ||||
| 
 | ||||
| void VirtualConsole::escape$s(const Vector<unsigned>&) | ||||
|  | @ -216,9 +217,7 @@ void VirtualConsole::escape$s(const Vector<unsigned>&) | |||
| 
 | ||||
| void VirtualConsole::escape$u(const Vector<unsigned>&) | ||||
| { | ||||
|     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<unsigned>& params) | ||||
|  | @ -229,9 +228,7 @@ void VirtualConsole::escape$H(const Vector<unsigned>& 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<unsigned>& 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)) { | ||||
|         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; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
|  |  | |||
|  | @ -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<unsigned>&); | ||||
|     void escape$J(const Vector<unsigned>&); | ||||
|     void escape$m(const Vector<unsigned>&); | ||||
|  | @ -56,6 +64,4 @@ private: | |||
|     EscapeState m_escState { Normal }; | ||||
|     Vector<byte> m_parameters; | ||||
|     Vector<byte> m_intermediates; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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)); \ | ||||
|  |  | |||
|  | @ -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<Keyboard>(); | ||||
| 
 | ||||
|     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>(); | ||||
|     console->setImplementation(tty0); | ||||
| 
 | ||||
|     RTC::initialize(); | ||||
|     PIC::initialize(); | ||||
|     gdt_init(); | ||||
|     idt_init(); | ||||
| 
 | ||||
|     keyboard = new Keyboard; | ||||
| 
 | ||||
|     auto console = make<Console>(); | ||||
|     VirtualConsole::initialize(); | ||||
|     tty0 = new VirtualConsole(0, VirtualConsole::AdoptCurrentVGABuffer); | ||||
|     tty1 = new VirtualConsole(1); | ||||
|     tty2 = new VirtualConsole(2); | ||||
|     VirtualConsole::switchTo(0); | ||||
| 
 | ||||
|     MemoryManager::initialize(); | ||||
| 
 | ||||
|     VirtualFileSystem::initializeGlobals(); | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| #include "types.h" | ||||
| #include "string.h" | ||||
| #include "errno.h" | ||||
| #include "unistd.h" | ||||
| #include <Kernel/Syscall.h> | ||||
| #include <AK/printf.cpp> | ||||
| 
 | ||||
|  | @ -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, ...) | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -6,5 +6,5 @@ CharacterDevice::~CharacterDevice() | |||
| 
 | ||||
| OwnPtr<FileHandle> CharacterDevice::open(int options) | ||||
| { | ||||
|     //VirtualFileSystem::the().open()
 | ||||
|     return VirtualFileSystem::the().open(*this, options); | ||||
| } | ||||
|  |  | |||
|  | @ -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()) | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -89,6 +89,21 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node> | |||
|     return vnode; | ||||
| } | ||||
| 
 | ||||
| auto VirtualFileSystem::makeNode(CharacterDevice& device) -> RetainPtr<Node> | ||||
| { | ||||
|     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<Node> | ||||
| { | ||||
|     auto it = m_inode2vnode.find(inode); | ||||
|  | @ -97,6 +112,14 @@ auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr<Node | |||
|     return makeNode(inode); | ||||
| } | ||||
| 
 | ||||
| auto VirtualFileSystem::getOrCreateNode(CharacterDevice& device) -> RetainPtr<Node> | ||||
| { | ||||
|     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>&& fileSystem, const String& path) | ||||
| { | ||||
|     ASSERT(fileSystem); | ||||
|  | @ -161,10 +184,15 @@ void VirtualFileSystem::freeNode(Node* node) | |||
| { | ||||
|     ASSERT(node); | ||||
|     ASSERT(node->inUse()); | ||||
|     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<FileHandle> VirtualFileSystem::open(CharacterDevice& device, int options) | ||||
| { | ||||
|     auto vnode = getOrCreateNode(device); | ||||
|     if (!vnode) | ||||
|         return nullptr; | ||||
|     return make<FileHandle>(move(vnode)); | ||||
| } | ||||
| 
 | ||||
| OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, int& error, int options, InodeIdentifier base) | ||||
| { | ||||
|     auto inode = resolvePath(path, error, base, options); | ||||
|  |  | |||
|  | @ -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<FileSystem>&&); | ||||
|     bool mount(RetainPtr<FileSystem>&&, const String& path); | ||||
| 
 | ||||
|     OwnPtr<FileHandle> open(CharacterDevice&, int options); | ||||
|     OwnPtr<FileHandle> open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier()); | ||||
|     OwnPtr<FileHandle> create(const String& path, InodeIdentifier base = InodeIdentifier()); | ||||
|     OwnPtr<FileHandle> mkdir(const String& path, InodeIdentifier base = InodeIdentifier()); | ||||
|  | @ -117,7 +118,9 @@ private: | |||
|     void freeNode(Node*); | ||||
| 
 | ||||
|     RetainPtr<Node> makeNode(InodeIdentifier); | ||||
|     RetainPtr<Node> makeNode(CharacterDevice&); | ||||
|     RetainPtr<Node> getOrCreateNode(InodeIdentifier); | ||||
|     RetainPtr<Node> getOrCreateNode(CharacterDevice&); | ||||
| 
 | ||||
|     Mount* findMountForHost(InodeIdentifier); | ||||
|     Mount* findMountForGuest(InodeIdentifier); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling