minos/arch/x86/arch.c
auser 59a433f949 minos: report live CPU privilege mode in banner
Adds arch_cpu_mode() to the contract, reading real hardware state:
x86 CS.CPL -> ring0, RISC-V mhartid (M-only CSR) -> M-mode,
ARM CPSR[4:0] -> SVC. Confirms M1 runs fully privileged, no user mode.
2026-09-25 01:05:01 +03:00

81 lines
1.9 KiB
C

/* arch/x86/arch.c — i386 implementation of the arch contract.
* Uses the legacy 16550 UART on COM1 (port 0x3F8), which QEMU wires to
* the -nographic serial. Port-mapped I/O — the CISC flavor. */
#include "arch.h"
#include "console.h"
#define COM1 0x3F8
static inline void outb(unsigned short port, unsigned char val)
{
__asm__ volatile("outb %0, %1" :: "a"(val), "Nd"(port));
}
static inline unsigned char inb(unsigned short port)
{
unsigned char r;
__asm__ volatile("inb %1, %0" : "=a"(r) : "Nd"(port));
return r;
}
void arch_early_init(void)
{
/* Program COM1: 115200 8N1, FIFO on. */
outb(COM1 + 1, 0x00); /* disable interrupts */
outb(COM1 + 3, 0x80); /* DLAB on */
outb(COM1 + 0, 0x01); /* divisor lo -> 115200 */
outb(COM1 + 1, 0x00); /* divisor hi */
outb(COM1 + 3, 0x03); /* 8N1, DLAB off */
outb(COM1 + 2, 0xC7); /* enable+clear FIFO */
outb(COM1 + 4, 0x0B); /* RTS/DSR set */
}
void arch_uart_putc(char c)
{
while ((inb(COM1 + 5) & 0x20) == 0) /* wait THR empty */
;
outb(COM1, (unsigned char)c);
}
/* M1: minimal IDT. We load a valid-but-empty IDT so the CPU has a
* table; M2 will fill gates and handle the timer (IRQ0). */
struct idt_entry {
unsigned short off_lo, sel;
unsigned char zero, flags;
unsigned short off_hi;
} __attribute__((packed));
struct idt_ptr {
unsigned short limit;
unsigned int base;
} __attribute__((packed));
static struct idt_entry idt[256];
void arch_set_trap_vector(void)
{
struct idt_ptr ptr = { sizeof(idt) - 1, (unsigned int)(unsigned long)idt };
__asm__ volatile("lidt %0" :: "m"(ptr));
}
const char *arch_name(void)
{
return "x86 (i386, multiboot)";
}
const char *arch_cpu_mode(void)
{
/* CPL = low 2 bits of CS. 0 = ring0 (kernel), 3 = ring3 (user). */
unsigned short cs;
__asm__ volatile("mov %%cs, %0" : "=r"(cs));
switch (cs & 3) {
case 0: return "ring0";
case 3: return "ring3";
default: return "ring?";
}
}
void arch_halt(void)
{
for (;;)
__asm__ volatile("hlt");
}