mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 21:42:43 +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, ' ' |     0, 0, 0, ' ' | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | void Keyboard::emit(byte ch) | ||||||
|  | { | ||||||
|  |     if (m_client) | ||||||
|  |         m_client->onKeyPress(ch); | ||||||
|  |     m_queue.enqueue(ch); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void Keyboard::handleIRQ() | void Keyboard::handleIRQ() | ||||||
| { | { | ||||||
|  | @ -50,7 +56,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 */ m_queue.enqueue('\n'); break; |         case 0x1C: /* enter */ emit('\n'); break; | ||||||
|         case 0xFA: /* i8042 ack */ break; |         case 0xFA: /* i8042 ack */ break; | ||||||
|         default: |         default: | ||||||
|             if (ch & 0x80) { |             if (ch & 0x80) { | ||||||
|  | @ -69,31 +75,33 @@ void Keyboard::handleIRQ() | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if (!m_modifiers) { |             if (!m_modifiers) { | ||||||
|                 if (m_client) |                 emit(map[ch]); | ||||||
|                     m_client->onKeyPress(map[ch]); |  | ||||||
|                 m_queue.enqueue(map[ch]); |  | ||||||
|             } else if (m_modifiers & MOD_SHIFT) { |             } else if (m_modifiers & MOD_SHIFT) { | ||||||
|                 if (m_client) |                 emit(shift_map[ch]); | ||||||
|                     m_client->onKeyPress(shift_map[ch]); |  | ||||||
|                 m_queue.enqueue(shift_map[ch]); |  | ||||||
|             } else if (m_modifiers & MOD_CTRL) { |             } else if (m_modifiers & MOD_CTRL) { | ||||||
|                 // FIXME: This is obviously not a good enough way to process ctrl+whatever.
 |                 // FIXME: This is obviously not a good enough way to process ctrl+whatever.
 | ||||||
|                 if (m_client) { |                 emit('^'); | ||||||
|                     m_client->onKeyPress('^'); |                 emit(shift_map[ch]); | ||||||
|                     m_client->onKeyPress(shift_map[ch]); |  | ||||||
|                 } |  | ||||||
|                 m_queue.enqueue('^'); |  | ||||||
|                 m_queue.enqueue(shift_map[ch]); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         //break;
 |         //break;
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static Keyboard* s_the; | ||||||
|  | 
 | ||||||
|  | Keyboard& Keyboard::the() | ||||||
|  | { | ||||||
|  |     ASSERT(s_the); | ||||||
|  |     return *s_the; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Keyboard::Keyboard() | Keyboard::Keyboard() | ||||||
|     : IRQHandler(IRQ_KEYBOARD) |     : IRQHandler(IRQ_KEYBOARD) | ||||||
|     , CharacterDevice(85, 1) |     , CharacterDevice(85, 1) | ||||||
| { | { | ||||||
|  |     s_the = this; | ||||||
|  | 
 | ||||||
|     // Empty the buffer of any pending data.
 |     // Empty the buffer of any pending data.
 | ||||||
|     // I don't care what you've been pressing until now!
 |     // I don't care what you've been pressing until now!
 | ||||||
|     while (IO::in8(I8042_STATUS ) & DATA_AVAILABLE) |     while (IO::in8(I8042_STATUS ) & DATA_AVAILABLE) | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ public: | ||||||
|     virtual ~Keyboard() override; |     virtual ~Keyboard() override; | ||||||
|     Keyboard(); |     Keyboard(); | ||||||
| 
 | 
 | ||||||
|     void setClient(KeyboardClient*); |     void setClient(KeyboardClient* client) { m_client = client; } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     // ^IRQHandler
 |     // ^IRQHandler
 | ||||||
|  | @ -30,6 +30,8 @@ private: | ||||||
|     virtual ssize_t write(const byte* buffer, size_t) override; |     virtual ssize_t write(const byte* buffer, size_t) override; | ||||||
|     virtual bool hasDataAvailableForRead() const override; |     virtual bool hasDataAvailableForRead() const override; | ||||||
| 
 | 
 | ||||||
|  |     void emit(byte); | ||||||
|  | 
 | ||||||
|     KeyboardClient* m_client { nullptr }; |     KeyboardClient* m_client { nullptr }; | ||||||
|     CircularQueue<byte, 16> m_queue; |     CircularQueue<byte, 16> m_queue; | ||||||
|     byte m_modifiers { 0 }; |     byte m_modifiers { 0 }; | ||||||
|  |  | ||||||
|  | @ -201,15 +201,16 @@ ByteBuffer procfs$summary() | ||||||
|     auto tasks = Task::allTasks(); |     auto tasks = Task::allTasks(); | ||||||
|     auto buffer = ByteBuffer::createUninitialized(tasks.size() * 256); |     auto buffer = ByteBuffer::createUninitialized(tasks.size() * 256); | ||||||
|     char* ptr = (char*)buffer.pointer(); |     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) { |     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->pid(), | ||||||
|             task->uid(), |             task->uid(), | ||||||
|             toString(task->state()), |             toString(task->state()), | ||||||
|             task->parentPID(), |             task->parentPID(), | ||||||
|             task->timesScheduled(), |             task->timesScheduled(), | ||||||
|             task->fileHandleCount(), |             task->fileHandleCount(), | ||||||
|  |             task->tty() ? task->tty()->ttyName().characters() : "n/a", | ||||||
|             task->name().characters()); |             task->name().characters()); | ||||||
|     } |     } | ||||||
|     *ptr = '\0'; |     *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); |         return current->sys$getcwd((char*)arg1, (size_t)arg2); | ||||||
|     case Syscall::PosixOpen: |     case Syscall::PosixOpen: | ||||||
|         return current->sys$open((const char*)arg1, (int)arg2); |         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: |     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); | ||||||
|  |  | ||||||
|  | @ -36,6 +36,7 @@ enum Function { | ||||||
|     PosixUname = 0x2004, |     PosixUname = 0x2004, | ||||||
|     SetMmapName = 0x2005, |     SetMmapName = 0x2005, | ||||||
|     PosixReadlink = 0x2006, |     PosixReadlink = 0x2006, | ||||||
|  |     PosixWrite = 0x2007, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void initialize(); | void initialize(); | ||||||
|  |  | ||||||
|  | @ -11,15 +11,30 @@ TTY::~TTY() | ||||||
| 
 | 
 | ||||||
| ssize_t TTY::read(byte* buffer, size_t size) | 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) | ssize_t TTY::write(const byte* buffer, size_t size) | ||||||
| { | { | ||||||
|  |     for (size_t i = 0; i < size; ++i) | ||||||
|  |         onTTYWrite(buffer[i]); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool TTY::hasDataAvailableForRead() const | 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 ssize_t write(const byte*, size_t) override; | ||||||
|     virtual bool hasDataAvailableForRead() const override; |     virtual bool hasDataAvailableForRead() const override; | ||||||
| 
 | 
 | ||||||
|  |     virtual String ttyName() const = 0; | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|     TTY(unsigned major, unsigned minor); |     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 Task::sys$spawn(const char* path, const char** args) | ||||||
| { | { | ||||||
|     int error = 0; |     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) |     if (child) | ||||||
|         return child->pid(); |         return child->pid(); | ||||||
|     return error; |     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('/'); |     auto parts = path.split('/'); | ||||||
|     if (parts.isEmpty()) { |     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.
 |     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); |     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_ring(ring) | ||||||
|     , m_cwd(move(cwd)) |     , m_cwd(move(cwd)) | ||||||
|     , m_executable(move(executable)) |     , m_executable(move(executable)) | ||||||
|     , m_parentPID(parentPID) |  | ||||||
|     , m_tty(tty) |     , m_tty(tty) | ||||||
|  |     , m_parentPID(parentPID) | ||||||
| { | { | ||||||
|     if (tty) { |     if (tty) { | ||||||
|         m_fileHandles.append(tty->open(O_RDONLY)); // stdin
 |         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); |     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) | ssize_t Task::sys$read(int fd, void* outbuf, size_t nread) | ||||||
| { | { | ||||||
|     VALIDATE_USER_BUFFER(outbuf, 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 | #ifdef DEBUG_IO | ||||||
|     kprintf("Task::sys$read: handle=%p\n", handle); |     kprintf("Task::sys$read: handle=%p\n", handle); | ||||||
| #endif | #endif | ||||||
|     if (!handle) { |     if (!handle) | ||||||
|         kprintf("Task::sys$read: handle not found :(\n"); |         return -EBADF; | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
| #ifdef DEBUG_IO |  | ||||||
|     kprintf("call read on handle=%p\n", handle); |  | ||||||
| #endif |  | ||||||
|     if (handle->isBlocking()) { |     if (handle->isBlocking()) { | ||||||
|         if (!handle->hasDataAvailableForRead()) { |         if (!handle->hasDataAvailableForRead()) { | ||||||
|             m_fdBlockedOnRead = fd; |             m_fdBlockedOnRead = fd; | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ class Task : public InlineLinkedListNode<Task> { | ||||||
|     struct Subregion; |     struct Subregion; | ||||||
| public: | public: | ||||||
|     static Task* createKernelTask(void (*entry)(), String&& name); |     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(); |     ~Task(); | ||||||
| 
 | 
 | ||||||
|     static Vector<Task*> allTasks(); |     static Vector<Task*> allTasks(); | ||||||
|  | @ -90,7 +90,8 @@ public: | ||||||
|     pid_t sys$getpid(); |     pid_t sys$getpid(); | ||||||
|     int sys$open(const char* path, int options); |     int sys$open(const char* path, int options); | ||||||
|     int sys$close(int fd); |     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$lstat(const char*, Unix::stat*); | ||||||
|     int sys$seek(int fd, int offset); |     int sys$seek(int fd, int offset); | ||||||
|     int sys$kill(pid_t pid, int sig); |     int sys$kill(pid_t pid, int sig); | ||||||
|  | @ -115,6 +116,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     static void taskDidCrash(Task*); |     static void taskDidCrash(Task*); | ||||||
| 
 | 
 | ||||||
|  |     const TTY* tty() const { return m_tty; } | ||||||
|  | 
 | ||||||
|     size_t regionCount() const { return m_regions.size(); } |     size_t regionCount() const { return m_regions.size(); } | ||||||
|     const Vector<RetainPtr<Region>>& regions() const { return m_regions; } |     const Vector<RetainPtr<Region>>& regions() const { return m_regions; } | ||||||
|     size_t subregionCount() const { return m_regions.size(); } |     size_t subregionCount() const { return m_regions.size(); } | ||||||
|  |  | ||||||
|  | @ -31,16 +31,11 @@ void vga_clear() | ||||||
|         vga_clear_row(i); |         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); |     word cur = (row * 160) + (column * 2); | ||||||
|     vga_mem[cur] = ch; |     vga_mem[cur] = ch; | ||||||
|     vga_mem[cur + 1] = current_attr; |     vga_mem[cur + 1] = attr; | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void vga_set_attr(BYTE attr) |  | ||||||
| { |  | ||||||
|     current_attr = attr; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| byte vga_get_attr() | byte vga_get_attr() | ||||||
|  |  | ||||||
|  | @ -3,12 +3,10 @@ | ||||||
| #include "types.h" | #include "types.h" | ||||||
| 
 | 
 | ||||||
| void vga_init(); | void vga_init(); | ||||||
| BYTE vga_get_attr(); |  | ||||||
| void vga_set_attr(BYTE); |  | ||||||
| void vga_set_cursor(WORD); | void vga_set_cursor(WORD); | ||||||
| void vga_set_cursor(BYTE row, BYTE column); | void vga_set_cursor(BYTE row, BYTE column); | ||||||
| WORD vga_get_cursor(); | 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_scroll_up(); | ||||||
| void vga_clear(); | void vga_clear(); | ||||||
| void vga_clear_row(word); | void vga_clear_row(word); | ||||||
|  |  | ||||||
|  | @ -3,16 +3,17 @@ | ||||||
| #include "kmalloc.h" | #include "kmalloc.h" | ||||||
| #include "i386.h" | #include "i386.h" | ||||||
| #include "StdLib.h" | #include "StdLib.h" | ||||||
|  | #include "Keyboard.h" | ||||||
| #include <AK/String.h> | #include <AK/String.h> | ||||||
| 
 | 
 | ||||||
| static byte* s_vgaBuffer = (byte*)0xb8000; | static byte* s_vgaBuffer = (byte*)0xb8000; | ||||||
| static VirtualConsole* s_consoles[6]; | static VirtualConsole* s_consoles[6]; | ||||||
| static unsigned s_activeConsole; | static int s_activeConsole; | ||||||
| 
 | 
 | ||||||
| void VirtualConsole::initialize() | void VirtualConsole::initialize() | ||||||
| { | { | ||||||
|     memset(s_consoles, 0, sizeof(s_consoles)); |     memset(s_consoles, 0, sizeof(s_consoles)); | ||||||
|     s_activeConsole = 0; |     s_activeConsole = -1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| VirtualConsole::VirtualConsole(unsigned index, InitialContents initialContents) | VirtualConsole::VirtualConsole(unsigned index, InitialContents initialContents) | ||||||
|  | @ -40,7 +41,7 @@ VirtualConsole::~VirtualConsole() | ||||||
| 
 | 
 | ||||||
| void VirtualConsole::switchTo(unsigned index) | void VirtualConsole::switchTo(unsigned index) | ||||||
| { | { | ||||||
|     if (index == s_activeConsole) |     if ((int)index == s_activeConsole) | ||||||
|         return; |         return; | ||||||
|     dbgprintf("[VC] Switch to %u\n", index); |     dbgprintf("[VC] Switch to %u\n", index); | ||||||
|     ASSERT(index < 6); |     ASSERT(index < 6); | ||||||
|  | @ -49,6 +50,7 @@ void VirtualConsole::switchTo(unsigned index) | ||||||
|     s_consoles[s_activeConsole]->setActive(false); |     s_consoles[s_activeConsole]->setActive(false); | ||||||
|     s_activeConsole = index; |     s_activeConsole = index; | ||||||
|     s_consoles[s_activeConsole]->setActive(true); |     s_consoles[s_activeConsole]->setActive(true); | ||||||
|  |     Console::the().setImplementation(s_consoles[s_activeConsole]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void VirtualConsole::setActive(bool b) | void VirtualConsole::setActive(bool b) | ||||||
|  | @ -60,14 +62,14 @@ void VirtualConsole::setActive(bool b) | ||||||
| 
 | 
 | ||||||
|     m_active = b; |     m_active = b; | ||||||
|     if (!m_active) { |     if (!m_active) { | ||||||
|         dbgprintf("%u becomes inactive, copying to buffer\n", m_index); |  | ||||||
|         memcpy(m_buffer, s_vgaBuffer, 80 * 25 * 2); |         memcpy(m_buffer, s_vgaBuffer, 80 * 25 * 2); | ||||||
|         return; |         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); |     memcpy(s_vgaBuffer, m_buffer, 80 * 25 * 2); | ||||||
|     vga_set_cursor(m_cursorRow, m_cursorColumn); |     vga_set_cursor(m_cursorRow, m_cursorColumn); | ||||||
|  | 
 | ||||||
|  |     Keyboard::the().setClient(this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline bool isParameter(byte ch) | inline bool isParameter(byte ch) | ||||||
|  | @ -205,7 +207,6 @@ void VirtualConsole::escape$m(const Vector<unsigned>& params) | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     vga_set_attr(m_currentAttribute); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void VirtualConsole::escape$s(const Vector<unsigned>&) | 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>&) | void VirtualConsole::escape$u(const Vector<unsigned>&) | ||||||
| { | { | ||||||
|     m_cursorRow = m_savedCursorRow; |     setCursor(m_savedCursorRow, m_savedCursorColumn); | ||||||
|     m_cursorColumn = m_savedCursorColumn; |  | ||||||
|     vga_set_cursor(m_cursorRow, m_cursorColumn); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void VirtualConsole::escape$H(const Vector<unsigned>& params) | void VirtualConsole::escape$H(const Vector<unsigned>& params) | ||||||
|  | @ -229,9 +228,7 @@ void VirtualConsole::escape$H(const Vector<unsigned>& params) | ||||||
|         row = params[0]; |         row = params[0]; | ||||||
|     if (params.size() >= 2) |     if (params.size() >= 2) | ||||||
|         col = params[1]; |         col = params[1]; | ||||||
|     m_cursorRow = row - 1; |     setCursor(row - 1, col - 1); | ||||||
|     m_cursorColumn = col - 1; |  | ||||||
|     vga_set_cursor(row - 1, col - 1); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void VirtualConsole::escape$J(const Vector<unsigned>& params) | void VirtualConsole::escape$J(const Vector<unsigned>& params) | ||||||
|  | @ -284,16 +281,42 @@ void VirtualConsole::executeEscapeSequence(byte final) | ||||||
|     m_intermediates.clear(); |     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(); |             vga_scroll_up(); | ||||||
|     } else { |     } else { | ||||||
|         ++m_cursorRow; |         ++m_cursorRow; | ||||||
|     } |     } | ||||||
|     m_cursorColumn = 0; |     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) { |     switch (m_escState) { | ||||||
|     case ExpectBracket: |     case ExpectBracket: | ||||||
|  | @ -336,32 +359,43 @@ void VirtualConsole::onChar(byte ch) | ||||||
|         return; |         return; | ||||||
|     case 8: // Backspace
 |     case 8: // Backspace
 | ||||||
|         if (m_cursorColumn) { |         if (m_cursorColumn) { | ||||||
|             --m_cursorColumn;\ |             setCursor(m_cursorRow, m_cursorColumn - 1); | ||||||
|             vga_set_cursor(m_cursorRow, m_cursorColumn); |             putCharacterAt(m_cursorRow, m_cursorColumn, ' '); | ||||||
|             vga_putch_at(m_cursorRow, m_cursorColumn, ' '); |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     case '\n': |     case '\n': | ||||||
|         scrollup(); |         scrollUp(); | ||||||
|         vga_set_cursor(m_cursorRow, m_cursorColumn); |         setCursor(m_cursorRow, m_cursorColumn); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     vga_putch_at(m_cursorRow, m_cursorColumn, ch); |     putCharacterAt(m_cursorRow, m_cursorColumn, ch); | ||||||
| 
 | 
 | ||||||
|     ++m_cursorColumn; |     ++m_cursorColumn; | ||||||
|     if (m_cursorColumn >= m_columns) |     if (m_cursorColumn >= m_columns) | ||||||
|         scrollup(); |         scrollUp(); | ||||||
|     vga_set_cursor(m_cursorRow, m_cursorColumn); |     setCursor(m_cursorRow, m_cursorColumn); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void VirtualConsole::onKeyPress(byte ch) | void VirtualConsole::onKeyPress(byte ch) | ||||||
| { | { | ||||||
|     onChar(ch); |     emit(ch); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void VirtualConsole::onConsoleReceive(byte 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: | private: | ||||||
|     // ^KeyboardClient
 |     // ^KeyboardClient
 | ||||||
|     void onKeyPress(byte) override; |     virtual void onKeyPress(byte) override; | ||||||
| 
 | 
 | ||||||
|     // ^ConsoleImplementation
 |     // ^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; |     byte* m_buffer; | ||||||
|     unsigned m_index; |     unsigned m_index; | ||||||
|     bool m_active { false }; |     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$H(const Vector<unsigned>&); | ||||||
|     void escape$J(const Vector<unsigned>&); |     void escape$J(const Vector<unsigned>&); | ||||||
|     void escape$m(const Vector<unsigned>&); |     void escape$m(const Vector<unsigned>&); | ||||||
|  | @ -56,6 +64,4 @@ private: | ||||||
|     EscapeState m_escState { Normal }; |     EscapeState m_escState { Normal }; | ||||||
|     Vector<byte> m_parameters; |     Vector<byte> m_parameters; | ||||||
|     Vector<byte> m_intermediates; |     Vector<byte> m_intermediates; | ||||||
| 
 |  | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -192,6 +192,8 @@ void exception_13_handler() | ||||||
| EH_ENTRY(14); | EH_ENTRY(14); | ||||||
| void exception_14_handler() | void exception_14_handler() | ||||||
| { | { | ||||||
|  |     ASSERT(current); | ||||||
|  | 
 | ||||||
|     dword faultAddress; |     dword faultAddress; | ||||||
|     asm ("movl %%cr2, %%eax":"=a"(faultAddress)); |     asm ("movl %%cr2, %%eax":"=a"(faultAddress)); | ||||||
| 
 | 
 | ||||||
|  | @ -249,7 +251,6 @@ void exception_14_handler() | ||||||
| #define EH(i, msg) \ | #define EH(i, msg) \ | ||||||
|     static void _exception ## i () \ |     static void _exception ## i () \ | ||||||
|     { \ |     { \ | ||||||
|         vga_set_attr(0x0a); \ |  | ||||||
|         kprintf(msg"\n"); \ |         kprintf(msg"\n"); \ | ||||||
|         DWORD cr0, cr2, cr3, cr4; \ |         DWORD cr0, cr2, cr3, cr4; \ | ||||||
|         asm ("movl %%cr0, %%eax":"=a"(cr0)); \ |         asm ("movl %%cr0, %%eax":"=a"(cr0)); \ | ||||||
|  |  | ||||||
|  | @ -37,9 +37,11 @@ system_t system; | ||||||
| VirtualConsole* tty0; | VirtualConsole* tty0; | ||||||
| VirtualConsole* tty1; | VirtualConsole* tty1; | ||||||
| VirtualConsole* tty2; | VirtualConsole* tty2; | ||||||
|  | Keyboard* keyboard; | ||||||
| 
 | 
 | ||||||
| void banner() | void banner() | ||||||
| { | { | ||||||
|  |     InterruptDisabler disabler; | ||||||
|     kprintf("\n\033[33;1mWelcome to \033[36;1mSerenity OS!\033[0m\n\n"); |     kprintf("\n\033[33;1mWelcome to \033[36;1mSerenity OS!\033[0m\n\n"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -107,8 +109,6 @@ static void init_stage2() | ||||||
| 
 | 
 | ||||||
|     Syscall::initialize(); |     Syscall::initialize(); | ||||||
| 
 | 
 | ||||||
|     auto keyboard = make<Keyboard>(); |  | ||||||
| 
 |  | ||||||
|     Disk::initialize(); |     Disk::initialize(); | ||||||
| 
 | 
 | ||||||
| #ifdef TEST_VFS | #ifdef TEST_VFS | ||||||
|  | @ -189,11 +189,13 @@ static void init_stage2() | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     int error; |  | ||||||
|     auto* shTask = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error); |  | ||||||
| 
 |  | ||||||
|     banner(); |     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 | #if 0 | ||||||
|     // It would be nice to exit this process, but right now it instantiates all kinds of things.
 |     // 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.
 |     // At the very least it needs to be made sure those things stick around as appropriate.
 | ||||||
|  | @ -216,21 +218,20 @@ void init() | ||||||
|     kmalloc_init(); |     kmalloc_init(); | ||||||
|     vga_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(); |     RTC::initialize(); | ||||||
|     PIC::initialize(); |     PIC::initialize(); | ||||||
|     gdt_init(); |     gdt_init(); | ||||||
|     idt_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(); |     MemoryManager::initialize(); | ||||||
| 
 | 
 | ||||||
|     VirtualFileSystem::initializeGlobals(); |     VirtualFileSystem::initializeGlobals(); | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| #include "types.h" | #include "types.h" | ||||||
| #include "string.h" | #include "string.h" | ||||||
| #include "errno.h" | #include "errno.h" | ||||||
|  | #include "unistd.h" | ||||||
| #include <Kernel/Syscall.h> | #include <Kernel/Syscall.h> | ||||||
| #include <AK/printf.cpp> | #include <AK/printf.cpp> | ||||||
| 
 | 
 | ||||||
|  | @ -10,13 +11,14 @@ extern "C" { | ||||||
| 
 | 
 | ||||||
| int putchar(int ch) | int putchar(int ch) | ||||||
| { | { | ||||||
|     Syscall::invoke(Syscall::PutCharacter, ch); |     write(0, &ch, 1); | ||||||
|  |     //Syscall::invoke(Syscall::PutCharacter, ch);
 | ||||||
|     return (byte)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, ...) | 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); |     __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 close(int fd) | ||||||
| { | { | ||||||
|     int rc = Syscall::invoke(Syscall::PosixClose, fd); |     int rc = Syscall::invoke(Syscall::PosixClose, fd); | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ gid_t getgid(); | ||||||
| pid_t getpid(); | pid_t getpid(); | ||||||
| int open(const char* path, int options); | int open(const char* path, int options); | ||||||
| ssize_t read(int fd, void* buf, size_t count); | 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); | int close(int fd); | ||||||
| pid_t waitpid(pid_t, int* wstatus, int options); | pid_t waitpid(pid_t, int* wstatus, int options); | ||||||
| int chdir(const char* path); | int chdir(const char* path); | ||||||
|  |  | ||||||
|  | @ -159,7 +159,7 @@ int main(int, char**) | ||||||
|     int linedx = 0; |     int linedx = 0; | ||||||
|     linebuf[0] = '\0'; |     linebuf[0] = '\0'; | ||||||
| 
 | 
 | ||||||
|     int fd = open("/dev/keyboard", O_RDONLY); |     int fd = 0; // open("/dev/keyboard", O_RDONLY);
 | ||||||
|     if (fd == -1) { |     if (fd == -1) { | ||||||
|         printf("failed to open /dev/keyboard :(\n"); |         printf("failed to open /dev/keyboard :(\n"); | ||||||
|         return 1; |         return 1; | ||||||
|  |  | ||||||
|  | @ -6,5 +6,5 @@ CharacterDevice::~CharacterDevice() | ||||||
| 
 | 
 | ||||||
| OwnPtr<FileHandle> CharacterDevice::open(int options) | 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; |     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() | bool FileHandle::hasDataAvailableForRead() | ||||||
| { | { | ||||||
|     if (m_vnode->isCharacterDevice()) |     if (m_vnode->isCharacterDevice()) | ||||||
|  |  | ||||||
|  | @ -10,7 +10,8 @@ public: | ||||||
|     ~FileHandle(); |     ~FileHandle(); | ||||||
| 
 | 
 | ||||||
|     Unix::off_t seek(Unix::off_t, int whence); |     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*); |     int stat(Unix::stat*); | ||||||
| 
 | 
 | ||||||
|     bool hasDataAvailableForRead(); |     bool hasDataAvailableForRead(); | ||||||
|  |  | ||||||
|  | @ -89,6 +89,21 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node> | ||||||
|     return vnode; |     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 VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr<Node> | ||||||
| { | { | ||||||
|     auto it = m_inode2vnode.find(inode); |     auto it = m_inode2vnode.find(inode); | ||||||
|  | @ -97,6 +112,14 @@ auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr<Node | ||||||
|     return makeNode(inode); |     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) | bool VirtualFileSystem::mount(RetainPtr<FileSystem>&& fileSystem, const String& path) | ||||||
| { | { | ||||||
|     ASSERT(fileSystem); |     ASSERT(fileSystem); | ||||||
|  | @ -161,10 +184,15 @@ void VirtualFileSystem::freeNode(Node* node) | ||||||
| { | { | ||||||
|     ASSERT(node); |     ASSERT(node); | ||||||
|     ASSERT(node->inUse()); |     ASSERT(node->inUse()); | ||||||
|  |     if (node->inode.isValid()) { | ||||||
|         m_inode2vnode.remove(node->inode); |         m_inode2vnode.remove(node->inode); | ||||||
|         node->inode.fileSystem()->release(); |         node->inode.fileSystem()->release(); | ||||||
|         node->inode = InodeIdentifier(); |         node->inode = InodeIdentifier(); | ||||||
|  |     } | ||||||
|  |     if (node->m_characterDevice) { | ||||||
|  |         m_device2vnode.remove(encodedDevice(node->m_characterDevice->major(), node->m_characterDevice->minor())); | ||||||
|         node->m_characterDevice = nullptr; |         node->m_characterDevice = nullptr; | ||||||
|  |     } | ||||||
|     m_nodeFreeList.append(move(node)); |     m_nodeFreeList.append(move(node)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -361,6 +389,14 @@ bool VirtualFileSystem::touch(const String& path) | ||||||
|     return inode.fileSystem()->setModificationTime(inode, ktime(nullptr)); |     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) | OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, int& error, int options, InodeIdentifier base) | ||||||
| { | { | ||||||
|     auto inode = resolvePath(path, error, base, options); |     auto inode = resolvePath(path, error, base, options); | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ public: | ||||||
|         InodeIdentifier inode; |         InodeIdentifier inode; | ||||||
|         const InodeMetadata& metadata() const; |         const InodeMetadata& metadata() const; | ||||||
| 
 | 
 | ||||||
|         bool inUse() const { return inode.isValid(); } |         bool inUse() const { return inode.isValid() || m_characterDevice; } | ||||||
| 
 | 
 | ||||||
|         bool isCharacterDevice() const { return m_characterDevice; } |         bool isCharacterDevice() const { return m_characterDevice; } | ||||||
|         CharacterDevice* characterDevice() { return m_characterDevice; } |         CharacterDevice* characterDevice() { return m_characterDevice; } | ||||||
|  | @ -91,6 +91,7 @@ public: | ||||||
|     bool mountRoot(RetainPtr<FileSystem>&&); |     bool mountRoot(RetainPtr<FileSystem>&&); | ||||||
|     bool mount(RetainPtr<FileSystem>&&, const String& path); |     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> open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier()); | ||||||
|     OwnPtr<FileHandle> create(const String& path, InodeIdentifier base = InodeIdentifier()); |     OwnPtr<FileHandle> create(const String& path, InodeIdentifier base = InodeIdentifier()); | ||||||
|     OwnPtr<FileHandle> mkdir(const String& path, InodeIdentifier base = InodeIdentifier()); |     OwnPtr<FileHandle> mkdir(const String& path, InodeIdentifier base = InodeIdentifier()); | ||||||
|  | @ -117,7 +118,9 @@ private: | ||||||
|     void freeNode(Node*); |     void freeNode(Node*); | ||||||
| 
 | 
 | ||||||
|     RetainPtr<Node> makeNode(InodeIdentifier); |     RetainPtr<Node> makeNode(InodeIdentifier); | ||||||
|  |     RetainPtr<Node> makeNode(CharacterDevice&); | ||||||
|     RetainPtr<Node> getOrCreateNode(InodeIdentifier); |     RetainPtr<Node> getOrCreateNode(InodeIdentifier); | ||||||
|  |     RetainPtr<Node> getOrCreateNode(CharacterDevice&); | ||||||
| 
 | 
 | ||||||
|     Mount* findMountForHost(InodeIdentifier); |     Mount* findMountForHost(InodeIdentifier); | ||||||
|     Mount* findMountForGuest(InodeIdentifier); |     Mount* findMountForGuest(InodeIdentifier); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling