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/PIT.h>
|
||||||
#include <kernel/RTC.h>
|
#include <kernel/RTC.h>
|
||||||
#include <kernel/Serial.h>
|
#include <kernel/Serial.h>
|
||||||
|
#include <kernel/Shell.h>
|
||||||
#include <kernel/tty.h>
|
#include <kernel/tty.h>
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define DISABLE_INTERRUPTS() asm volatile("cli")
|
#define DISABLE_INTERRUPTS() asm volatile("cli")
|
||||||
#define ENABLE_INTERRUPTS() asm volatile("sti")
|
#define ENABLE_INTERRUPTS() asm volatile("sti")
|
||||||
|
|
||||||
multiboot_info_t* s_multiboot_info;
|
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"
|
extern "C"
|
||||||
void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
||||||
{
|
{
|
||||||
|
@ -88,10 +31,6 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
||||||
Serial::initialize();
|
Serial::initialize();
|
||||||
TTY::initialize();
|
TTY::initialize();
|
||||||
|
|
||||||
for (int i = 30; i <= 37; i++)
|
|
||||||
kprint("\e[{}m#", i);
|
|
||||||
kprint("\e[m\n");
|
|
||||||
|
|
||||||
kmalloc_initialize();
|
kmalloc_initialize();
|
||||||
|
|
||||||
PIC::initialize();
|
PIC::initialize();
|
||||||
|
@ -99,19 +38,18 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
||||||
IDT::initialize();
|
IDT::initialize();
|
||||||
|
|
||||||
PIT::initialize();
|
PIT::initialize();
|
||||||
if (!Keyboard::initialize(on_key_press))
|
if (!Keyboard::initialize())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto time = RTC::GetCurrentTime();
|
|
||||||
kprintln("Today is {}", time);
|
|
||||||
|
|
||||||
kprintln("Hello from the kernel!");
|
kprintln("Hello from the kernel!");
|
||||||
|
|
||||||
ENABLE_INTERRUPTS();
|
ENABLE_INTERRUPTS();
|
||||||
|
|
||||||
|
auto& shell = Kernel::Shell::Get();
|
||||||
|
shell.Run();
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Keyboard::update_keyboard();
|
asm("hlt");
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue