Kernel: Add basic Shell to test functionality
This commit is contained in:
parent
f8224e55b1
commit
711ba19a82
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/String.h>
|
||||
#include <kernel/Keyboard.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Shell
|
||||
{
|
||||
public:
|
||||
Shell(const Shell&) = delete;
|
||||
|
||||
static Shell& Get();
|
||||
|
||||
void Run();
|
||||
|
||||
private:
|
||||
Shell();
|
||||
void PrintPrompt();
|
||||
void ProcessCommand(BAN::StringView);
|
||||
void KeyEventCallback(Keyboard::KeyEvent);
|
||||
|
||||
private:
|
||||
BAN::String m_buffer;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Keyboard.h>
|
||||
#include <kernel/RTC.h>
|
||||
#include <kernel/Shell.h>
|
||||
#include <kernel/tty.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static Shell* s_instance = nullptr;
|
||||
|
||||
Shell& Shell::Get()
|
||||
{
|
||||
if (!s_instance)
|
||||
s_instance = new Shell();
|
||||
return *s_instance;
|
||||
}
|
||||
|
||||
Shell::Shell()
|
||||
{
|
||||
Keyboard::register_key_event_callback([](Keyboard::KeyEvent event) { Shell::Get().KeyEventCallback(event); });
|
||||
m_buffer.Reserve(128);
|
||||
}
|
||||
|
||||
void Shell::PrintPrompt()
|
||||
{
|
||||
kprint("\e[32muser\e[m# ");
|
||||
}
|
||||
|
||||
void Shell::Run()
|
||||
{
|
||||
PrintPrompt();
|
||||
for (;;)
|
||||
{
|
||||
asm volatile("hlt");
|
||||
Keyboard::update_keyboard();
|
||||
}
|
||||
}
|
||||
|
||||
void Shell::ProcessCommand(BAN::StringView command)
|
||||
{
|
||||
auto arguments = command.Split(' ');
|
||||
if (arguments.Empty())
|
||||
return;
|
||||
|
||||
if (arguments.Front() == "date")
|
||||
{
|
||||
if (arguments.Size() != 1)
|
||||
{
|
||||
kprintln("'date' does not support command line arguments");
|
||||
return;
|
||||
}
|
||||
auto time = RTC::GetCurrentTime();
|
||||
kprintln("{}", time);
|
||||
return;
|
||||
}
|
||||
|
||||
if (arguments.Front() == "echo")
|
||||
{
|
||||
if (arguments.Size() > 1)
|
||||
{
|
||||
kprint("{}", arguments[1]);
|
||||
for (size_t i = 2; i < arguments.Size(); i++)
|
||||
kprint(" {}", arguments[i]);
|
||||
}
|
||||
kprintln();
|
||||
return;
|
||||
}
|
||||
|
||||
if (arguments.Front() == "clear")
|
||||
{
|
||||
if (arguments.Size() != 1)
|
||||
{
|
||||
kprintln("'clear' does not support command line arguments");
|
||||
return;
|
||||
}
|
||||
TTY::clear();
|
||||
TTY::set_cursor_pos(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (arguments.Front() == "reboot")
|
||||
{
|
||||
if (arguments.Size() != 1)
|
||||
{
|
||||
kprintln("'reboot' does not support command line arguments");
|
||||
return;
|
||||
}
|
||||
uint8_t good = 0x02;
|
||||
while (good & 0x02)
|
||||
good = IO::inb(0x64);
|
||||
IO::outb(0x64, 0xFE);
|
||||
asm volatile("cli; hlt");
|
||||
return;
|
||||
}
|
||||
|
||||
kprintln("unrecognized command '{}'", arguments.Front());
|
||||
}
|
||||
|
||||
void Shell::KeyEventCallback(Keyboard::KeyEvent event)
|
||||
{
|
||||
if (!event.pressed)
|
||||
return;
|
||||
|
||||
switch (event.key)
|
||||
{
|
||||
case Keyboard::Key::Backspace:
|
||||
{
|
||||
if (!m_buffer.Empty())
|
||||
{
|
||||
kprint("\b \b", 3);
|
||||
m_buffer.PopBack();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Keyboard::Key::Enter:
|
||||
case Keyboard::Key::NumpadEnter:
|
||||
{
|
||||
kprint("\n");
|
||||
ProcessCommand(m_buffer);
|
||||
m_buffer.Clear();
|
||||
PrintPrompt();
|
||||
break;
|
||||
}
|
||||
|
||||
case Keyboard::Key::Tab:
|
||||
event.key = Keyboard::Key::Space;
|
||||
// fall through
|
||||
|
||||
default:
|
||||
{
|
||||
char ascii = Keyboard::key_event_to_ascii(event);
|
||||
if (ascii)
|
||||
{
|
||||
kprint("{}", ascii);
|
||||
m_buffer.PushBack(ascii);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -10,71 +10,14 @@
|
|||
#include <kernel/PIT.h>
|
||||
#include <kernel/RTC.h>
|
||||
#include <kernel/Serial.h>
|
||||
#include <kernel/Shell.h>
|
||||
#include <kernel/tty.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DISABLE_INTERRUPTS() asm volatile("cli")
|
||||
#define ENABLE_INTERRUPTS() asm volatile("sti")
|
||||
|
||||
multiboot_info_t* s_multiboot_info;
|
||||
|
||||
char ascii_buffer[32] {};
|
||||
static bool has_command(const char* cmd)
|
||||
{
|
||||
size_t len = strlen(cmd);
|
||||
return memcmp(ascii_buffer + sizeof(ascii_buffer) - len - 1, cmd, len) == 0;
|
||||
}
|
||||
void on_key_press(Keyboard::KeyEvent event)
|
||||
{
|
||||
if (event.pressed)
|
||||
{
|
||||
char ascii = Keyboard::key_event_to_ascii(event);
|
||||
|
||||
if (ascii)
|
||||
{
|
||||
memmove(ascii_buffer, ascii_buffer + 1, sizeof(ascii_buffer) - 1);
|
||||
ascii_buffer[sizeof(ascii_buffer) - 1] = ascii;
|
||||
kprint("{}", ascii);
|
||||
}
|
||||
|
||||
if (event.key == Keyboard::Key::Escape)
|
||||
{
|
||||
kprint("time since boot: {} ms\n", PIT::ms_since_boot());
|
||||
return;
|
||||
}
|
||||
else if (event.key == Keyboard::Key::Backspace)
|
||||
{
|
||||
memmove(ascii_buffer + 2, ascii_buffer, sizeof(ascii_buffer) - 2);
|
||||
kprint(" \b");
|
||||
}
|
||||
else if (event.key == Keyboard::Key::Enter)
|
||||
{
|
||||
if (has_command("clear"))
|
||||
{
|
||||
TTY::clear();
|
||||
TTY::set_cursor_pos(0, 0);
|
||||
}
|
||||
else if (has_command("led_disco"))
|
||||
{
|
||||
TTY::clear();
|
||||
TTY::set_cursor_pos(0, 0);
|
||||
kprintln("\e[32mLED DISCO\e[m");
|
||||
Keyboard::led_disco();
|
||||
}
|
||||
else if (has_command("reboot"))
|
||||
{
|
||||
uint8_t good = 0x02;
|
||||
while (good & 0x02)
|
||||
good = IO::inb(0x64);
|
||||
IO::outb(0x64, 0xFE);
|
||||
asm volatile("cli; hlt");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
||||
{
|
||||
|
@ -87,11 +30,7 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
|||
|
||||
Serial::initialize();
|
||||
TTY::initialize();
|
||||
|
||||
for (int i = 30; i <= 37; i++)
|
||||
kprint("\e[{}m#", i);
|
||||
kprint("\e[m\n");
|
||||
|
||||
|
||||
kmalloc_initialize();
|
||||
|
||||
PIC::initialize();
|
||||
|
@ -99,19 +38,18 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
|||
IDT::initialize();
|
||||
|
||||
PIT::initialize();
|
||||
if (!Keyboard::initialize(on_key_press))
|
||||
if (!Keyboard::initialize())
|
||||
return;
|
||||
|
||||
auto time = RTC::GetCurrentTime();
|
||||
kprintln("Today is {}", time);
|
||||
|
||||
kprintln("Hello from the kernel!");
|
||||
|
||||
ENABLE_INTERRUPTS();
|
||||
|
||||
auto& shell = Kernel::Shell::Get();
|
||||
shell.Run();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Keyboard::update_keyboard();
|
||||
asm("hlt");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue