144 lines
4.9 KiB
C
144 lines
4.9 KiB
C
/*
|
||
* kernel.c – Kernel entry point and interactive shell loop.
|
||
*
|
||
* kmain() is called by the UEFI loader (main.c) after the ELF kernel
|
||
* has been mapped into memory. It initialises subsystems (IDT, memory,
|
||
* tasks), prints a welcome banner, and enters an interactive read-
|
||
* eval-print loop that dispatches typed commands via commands.c.
|
||
*
|
||
* While waiting for keyboard input, the shell yields to the cooperative
|
||
* scheduler so that background tasks can make progress.
|
||
*/
|
||
|
||
#include <efi.h>
|
||
|
||
#include "boot_info.h"
|
||
#include "commands.h"
|
||
#include "idt.h"
|
||
#include "memory.h"
|
||
#include "task.h"
|
||
|
||
/* Null-safe print helper used throughout the kernel. */
|
||
#define SAFE_PRINT(Boot, ...) \
|
||
do { \
|
||
if ((Boot) != NULL && (Boot)->print != NULL) { \
|
||
(Boot)->print(__VA_ARGS__); \
|
||
} \
|
||
} while (0)
|
||
|
||
/* ================================================================
|
||
* Kernel entry point
|
||
* ================================================================ */
|
||
|
||
void kmain(BootInfo *Boot)
|
||
{
|
||
EFI_INPUT_KEY Key;
|
||
EFI_STATUS Status;
|
||
UINTN read_errors = 0;
|
||
|
||
if (Boot == NULL) {
|
||
return;
|
||
}
|
||
|
||
if (Boot->clear_screen != NULL) {
|
||
Status = Boot->clear_screen();
|
||
if (EFI_ERROR(Status)) {
|
||
SAFE_PRINT(Boot, L"clear_screen failed: %r\n\r", Status);
|
||
}
|
||
}
|
||
|
||
if (Boot->set_attribute != NULL) {
|
||
Status = Boot->set_attribute(EFI_TEXT_ATTR(EFI_LIGHTGREEN, EFI_BLACK));
|
||
if (EFI_ERROR(Status)) {
|
||
SAFE_PRINT(Boot, L"set_attribute failed: %r\n\r", Status);
|
||
}
|
||
}
|
||
|
||
/* ---- Subsystem initialisation ---- */
|
||
idt_init(Boot);
|
||
memory_init(Boot);
|
||
task_init(Boot);
|
||
|
||
/* ---- Welcome banner ---- */
|
||
SAFE_PRINT(Boot, L" Welcome to Simple UEFI Operating System!\n\r");
|
||
SAFE_PRINT(Boot, L"================================================\n\r");
|
||
SAFE_PRINT(Boot, L"\n\r");
|
||
SAFE_PRINT(Boot, L"System Information:\n\r");
|
||
if (Boot->SystemTable != NULL) {
|
||
SAFE_PRINT(Boot, L" UEFI Firmware Vendor: %s\n\r",
|
||
Boot->SystemTable->FirmwareVendor);
|
||
SAFE_PRINT(Boot, L" UEFI Firmware Revision: %d.%d\n\r",
|
||
Boot->SystemTable->FirmwareRevision >> 16,
|
||
Boot->SystemTable->FirmwareRevision & 0xFFFF);
|
||
} else {
|
||
SAFE_PRINT(Boot, L" UEFI System Table: Unavailable\n\r");
|
||
}
|
||
SAFE_PRINT(Boot, L"\n\r");
|
||
|
||
SAFE_PRINT(Boot, L"Available Services:\n\r");
|
||
SAFE_PRINT(Boot, L" - Console Input/Output: %s\n\r",
|
||
(Boot->read_key != NULL && Boot->print != NULL) ? L"Active" : L"Unavailable");
|
||
SAFE_PRINT(Boot, L" - Runtime Services: %s\n\r",
|
||
(Boot->SystemTable != NULL &&
|
||
Boot->SystemTable->RuntimeServices != NULL) ? L"Active" : L"Unavailable");
|
||
SAFE_PRINT(Boot, L" - Boot Services: %s\n\r",
|
||
(Boot->SystemTable != NULL &&
|
||
Boot->SystemTable->BootServices != NULL) ? L"Active" : L"Unavailable");
|
||
SAFE_PRINT(Boot, L"\n\r");
|
||
SAFE_PRINT(Boot, L"Type 'help' for a list of commands.\n\r\n\r");
|
||
|
||
/* ---- Interactive shell loop ---- */
|
||
CHAR16 line[128];
|
||
UINTN len = 0;
|
||
|
||
SAFE_PRINT(Boot, L"-> ");
|
||
|
||
while (TRUE) {
|
||
/* Try non-blocking read first; yield to other tasks while idle */
|
||
if (Boot->try_read_key != NULL) {
|
||
Status = Boot->try_read_key(&Key);
|
||
if (Status == EFI_NOT_READY) {
|
||
task_yield();
|
||
continue;
|
||
}
|
||
} else if (Boot->read_key != NULL) {
|
||
Status = Boot->read_key(&Key);
|
||
} else {
|
||
SAFE_PRINT(Boot, L"Console input unavailable.\n\r");
|
||
break;
|
||
}
|
||
|
||
if (EFI_ERROR(Status)) {
|
||
read_errors++;
|
||
if (read_errors == 1 || (read_errors % 64) == 0) {
|
||
SAFE_PRINT(Boot, L"read_key failed: %r\n\r", Status);
|
||
}
|
||
continue;
|
||
}
|
||
read_errors = 0;
|
||
|
||
if (Key.UnicodeChar == L'\r' || Key.UnicodeChar == L'\n') {
|
||
/* Enter pressed: execute the buffered command */
|
||
line[len] = L'\0';
|
||
SAFE_PRINT(Boot, L"\n\r");
|
||
execute_command(Boot, line);
|
||
|
||
/* Reset for next command */
|
||
len = 0;
|
||
SAFE_PRINT(Boot, L"-> ");
|
||
} else if (Key.ScanCode == 0x08 || Key.UnicodeChar == L'\b' || Key.UnicodeChar == 0x7F) {
|
||
/* Backspace */
|
||
if (len > 0) {
|
||
len--;
|
||
SAFE_PRINT(Boot, L"\b \b");
|
||
}
|
||
} else if (Key.UnicodeChar >= 32 && Key.UnicodeChar < 127) {
|
||
/* Printable ASCII */
|
||
if (len < (sizeof(line) / sizeof(line[0]) - 1)) {
|
||
line[len++] = Key.UnicodeChar;
|
||
SAFE_PRINT(Boot, L"%c", Key.UnicodeChar);
|
||
}
|
||
}
|
||
}
|
||
}
|