mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +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
Notes:
sideshowbarker
2024-07-19 18:36:29 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/7a7956a5952
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)) {
|
||||
if (m_cursorRow == (m_rows - 1)) {
|
||||
memcpy(m_buffer, m_buffer + 160, 160 * 24);
|
||||
word* linemem = (word*)&m_buffer[24 * 160];
|
||||
for (word i = 0; i < 80; ++i)
|
||||
linemem[i] = 0x0720;
|
||||
if (m_active)
|
||||
vga_scroll_up();
|
||||
} else {
|
||||
++m_cursorRow;
|
||||
}
|
||||
m_cursorColumn = 0;
|
||||
};
|
||||
} else {
|
||||
++m_cursorRow;
|
||||
}
|
||||
m_cursorColumn = 0;
|
||||
}
|
||||
|
||||
void VirtualConsole::setCursor(unsigned row, unsigned column)
|
||||
{
|
||||
m_cursorRow = row;
|
||||
m_cursorColumn = column;
|
||||
if (m_active)
|
||||
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
||||
}
|
||||
|
||||
void VirtualConsole::putCharacterAt(unsigned row, unsigned column, byte ch)
|
||||
{
|
||||
word cur = (row * 160) + (column * 2);
|
||||
m_buffer[cur] = ch;
|
||||
m_buffer[cur + 1] = m_currentAttribute;
|
||||
if (m_active)
|
||||
vga_putch_at(row, column, ch, m_currentAttribute);
|
||||
}
|
||||
|
||||
void VirtualConsole::onChar(byte ch, bool shouldEmit)
|
||||
{
|
||||
if (shouldEmit)
|
||||
emit(ch);
|
||||
|
||||
switch (m_escState) {
|
||||
case ExpectBracket:
|
||||
|
@ -336,32 +359,43 @@ void VirtualConsole::onChar(byte ch)
|
|||
return;
|
||||
case 8: // Backspace
|
||||
if (m_cursorColumn) {
|
||||
--m_cursorColumn;\
|
||||
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
||||
vga_putch_at(m_cursorRow, m_cursorColumn, ' ');
|
||||
setCursor(m_cursorRow, m_cursorColumn - 1);
|
||||
putCharacterAt(m_cursorRow, m_cursorColumn, ' ');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
scrollup();
|
||||
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
||||
scrollUp();
|
||||
setCursor(m_cursorRow, m_cursorColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
vga_putch_at(m_cursorRow, m_cursorColumn, ch);
|
||||
putCharacterAt(m_cursorRow, m_cursorColumn, ch);
|
||||
|
||||
++m_cursorColumn;
|
||||
if (m_cursorColumn >= m_columns)
|
||||
scrollup();
|
||||
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
||||
scrollUp();
|
||||
setCursor(m_cursorRow, m_cursorColumn);
|
||||
}
|
||||
|
||||
void VirtualConsole::onKeyPress(byte ch)
|
||||
{
|
||||
onChar(ch);
|
||||
emit(ch);
|
||||
}
|
||||
|
||||
void VirtualConsole::onConsoleReceive(byte ch)
|
||||
{
|
||||
onChar(ch);
|
||||
onChar(ch, false);
|
||||
}
|
||||
|
||||
void VirtualConsole::onTTYWrite(byte ch)
|
||||
{
|
||||
onChar(ch, false);
|
||||
}
|
||||
|
||||
String VirtualConsole::ttyName() const
|
||||
{
|
||||
char buf[8];
|
||||
ksprintf(buf, "tty%u", m_index);
|
||||
return String(buf);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
m_inode2vnode.remove(node->inode);
|
||||
node->inode.fileSystem()->release();
|
||||
node->inode = InodeIdentifier();
|
||||
node->m_characterDevice = nullptr;
|
||||
if (node->inode.isValid()) {
|
||||
m_inode2vnode.remove(node->inode);
|
||||
node->inode.fileSystem()->release();
|
||||
node->inode = InodeIdentifier();
|
||||
}
|
||||
if (node->m_characterDevice) {
|
||||
m_device2vnode.remove(encodedDevice(node->m_characterDevice->major(), node->m_characterDevice->minor()));
|
||||
node->m_characterDevice = nullptr;
|
||||
}
|
||||
m_nodeFreeList.append(move(node));
|
||||
}
|
||||
|
||||
|
@ -361,6 +389,14 @@ bool VirtualFileSystem::touch(const String& path)
|
|||
return inode.fileSystem()->setModificationTime(inode, ktime(nullptr));
|
||||
}
|
||||
|
||||
OwnPtr<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…
Reference in a new issue