fix: backspace behavior

This commit is contained in:
Pierre-Emmanuel Gob. 2026-09-18 20:38:04 +02:00
parent a60338054a
commit 0727a2c1d4

View file

@ -2,30 +2,157 @@
* *
* Called once from the stage-2 entry stub after the CPU is in 64-bit long * Called once from the stage-2 entry stub after the CPU is in 64-bit long
* mode with a valid stack, zeroed BSS and identity-mapped memory. Runs at * mode with a valid stack, zeroed BSS and identity-mapped memory. Runs at
* Ring 0 (CPL 0) interrupts disabled. Installs the exception IDT first * Ring 0 (CPL 0) with IF=0 on entry under the stage-2 GDT (CS 0x18);
* so from then on a fault prints diagnostics instead of triple-faulting. * `-mno-red-zone` keeps IRQ pushes off the red zone so interrupt frames
* It never returns; on return the caller halts the CPU. * are safe. Installs the exception IDT first so from then on a fault
* prints diagnostics instead of triple-faulting. `sti` runs exactly once
* after every device is programmed; the main loop keeps IF=1 and sleeps
* in `hlt` (which wakes on each IRQ) — never `cli`-parks, or timer ticks
* and keystrokes would stop. It never returns; on return the caller halts.
*/ */
#include <stdint.h>
#include "console.h" #include "console.h"
#include "idt.h" #include "idt.h"
#include "keyboard.h"
#include "pic.h"
#include "pit.h"
#include "serial.h"
/* A value that only comes out right if the CPU truly executes 64-bit /* A value that only comes out right if the CPU truly executes 64-bit
* arithmetic: every nibble survives the shifts above 32 bits. */ * arithmetic: every nibble survives the shifts above 32 bits. */
#define PROOF_VALUE 0x0123456789ABCDEFULL #define PROOF_VALUE 0x0123456789ABCDEFULL
/* Print an unsigned decimal via console_putchar (no libc printf). */
static void print_dec(uint64_t v)
{
char buf[20];
int n = 0;
if (v == 0) {
console_putchar('0');
return;
}
while (v != 0 && n < (int)sizeof(buf)) {
buf[n++] = (char)('0' + (v % 10U));
v /= 10U;
}
while (n > 0) {
n--;
console_putchar(buf[n]);
}
}
/* Mirror one echoed keystroke to COM1 when the UART looks present. */
static void serial_echo(char c, int ok)
{
char tmp[2];
if (ok == 0) {
return;
}
if (c == '\b') {
/* Erase on a serial terminal: back, blank, back. */
serial_puts("\b \b");
} else if (c == '\n') {
serial_puts("\r\n");
} else {
tmp[0] = c;
tmp[1] = '\0';
serial_puts(tmp);
}
}
void kmain(void) void kmain(void)
{ {
int serial_present;
uint64_t last_uptime;
console_clear(); console_clear();
console_puts("Hello World from Nadir Kernel !\n"); console_puts("Hello World from Nadir Kernel !\n");
console_puts("Running C code in 64-bit long mode (Ring 0).\n"); console_puts("Running C code in 64-bit long mode (Ring 0).\n");
/* WHY this order: pic_remap must precede idt_install_irqs so IRQ
* gates land on valid remapped vectors 32-47 (pre-remap they would
* overlap CPU exceptions 0-15 and a tick would look like a fault);
* devices (serial/PIT/keyboard) are programmed before sti so no IRQ
* fires into a half-wired handler; pic_remap masks everything and
* each device opts in via pic_unmask, so stray lines stay silent. */
idt_init(); idt_init();
console_puts("IDT installed (vectors 0-31).\n"); console_puts("IDT installed (vectors 0-31).\n");
pic_remap();
console_puts("PIC remapped (IRQ 0-15 -> vectors 32-47, masked).\n");
idt_install_irqs();
console_puts("IRQ gates installed (vectors 32-47).\n");
serial_init();
serial_present = serial_ok();
console_puts("Serial COM1 38400 8N1 ready.\n");
if (serial_present != 0) {
serial_puts("Hello World from Nadir Kernel !\n");
serial_puts("Serial COM1 38400 8N1 ready.\n");
}
pit_init();
console_puts("PIT 100Hz on IRQ0 ready.\n");
if (serial_present != 0) {
serial_puts("PIT 100Hz on IRQ0 ready.\n");
}
keyboard_init();
console_puts("Keyboard PS/2 IRQ1 ready.\n");
if (serial_present != 0) {
serial_puts("Keyboard PS/2 IRQ1 ready.\n");
}
/* Explicit opt-in for the two live lines; idempotent even though
* keyboard_init already unmasked IRQ1. */
pic_unmask(0);
pic_unmask(1);
__asm__ volatile("sti");
console_puts("Interrupts enabled (IRQs 0-1).\n");
if (serial_present != 0) {
serial_puts("Interrupts enabled (IRQs 0-1).\n");
}
console_puts("64-bit proof value: "); console_puts("64-bit proof value: ");
console_puthex64(PROOF_VALUE); console_puthex64(PROOF_VALUE);
console_puts("\nHalting.\n"); console_puts("\nHalting in hlt loop (timer + keyboard live).\n");
/* Main loop: hlt sleeps until the next IRQ (IF=1 throughout), then
* one poll pass prints uptime ~1/s and drains echoed keys. */
last_uptime = 0;
for (;;) { for (;;) {
uint64_t now;
__asm__ volatile("hlt"); __asm__ volatile("hlt");
now = pit_ticks();
if ((now - last_uptime) >= 100U) {
uint64_t secs = now / 100U;
uint64_t tenths = (now / 10U) % 10U;
last_uptime = now;
console_puts("uptime ");
print_dec(secs);
console_puts(".");
print_dec(tenths);
console_puts("s (ticks ");
console_puthex64(now);
console_puts(")\n");
if (serial_present != 0) {
serial_puts("uptime (see VGA for value)\n");
}
}
while (keyboard_has_key() != 0) {
char c = keyboard_dequeue();
/* console_putchar erases on '\b' and wraps on '\n'. */
console_putchar(c);
serial_echo(c, serial_present);
}
} }
} }