1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:48:10 +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:
Andreas Kling 2018-10-30 15:33:37 +01:00
parent 68739dc43e
commit 7a7956a595
24 changed files with 251 additions and 103 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -36,6 +36,7 @@ enum Function {
PosixUname = 0x2004, PosixUname = 0x2004,
SetMmapName = 0x2005, SetMmapName = 0x2005,
PosixReadlink = 0x2006, PosixReadlink = 0x2006,
PosixWrite = 0x2007,
}; };
void initialize(); void initialize();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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());
m_inode2vnode.remove(node->inode); if (node->inode.isValid()) {
node->inode.fileSystem()->release(); m_inode2vnode.remove(node->inode);
node->inode = InodeIdentifier(); node->inode.fileSystem()->release();
node->m_characterDevice = nullptr; 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)); 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);

View file

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