Initial import of ViperOS

This commit is contained in:
Viper
2026-07-19 12:38:20 +08:00
commit 6813947181
104 changed files with 26710 additions and 0 deletions

View File

@@ -0,0 +1,251 @@
import asm
import intr.gdt as gdt
import intr.idt as idt
import drivers.serial.uart.serial as serial
import drivers.core.cpu.cpu as cpu
import mm.mm as mm
import platform.pch.timer as timer
import viperlib
import t, c
IA32_APIC_BASE: t.CDefine = 0x1B
APIC_BASE_MSR_ENABLE: t.CDefine = 0x800
APIC_BASE_ADDR_MASK: t.CDefine = 0xFFFFF000
LAPIC_ID: t.CDefine = 0x020
LAPIC_VERSION: t.CDefine = 0x030
LAPIC_TPR: t.CDefine = 0x080
LAPIC_EOI: t.CDefine = 0x0B0
LAPIC_LDR: t.CDefine = 0x0D0
LAPIC_SVR: t.CDefine = 0x0F0
LAPIC_ISR0: t.CDefine = 0x100
LAPIC_ICR_LOW: t.CDefine = 0x300
LAPIC_ICR_HIGH: t.CDefine = 0x310
LAPIC_LVT_TIMER: t.CDefine = 0x320
LAPIC_LVT_LINT0: t.CDefine = 0x350
LAPIC_LVT_LINT1: t.CDefine = 0x360
LAPIC_LVT_ERROR: t.CDefine = 0x370
LAPIC_TIMER_INIT: t.CDefine = 0x380
LAPIC_TIMER_CURRENT: t.CDefine = 0x390
LAPIC_TIMER_DIVIDE: t.CDefine = 0x3E0
LAPIC_SVR_ENABLE: t.CDefine = 0x100
LAPIC_LVT_MASKED: t.CDefine = 0x10000
LAPIC_LVT_DELIVERY_EXTINT: t.CDefine = 0x700
LAPIC_LVT_DELIVERY_NMI: t.CDefine = 0x400
LAPIC_LVT_TIMER_PERIODIC: t.CDefine = 0x20000
LAPIC_ICR_INIT: t.CDefine = 0x500
LAPIC_ICR_STARTUP: t.CDefine = 0x600
LAPIC_ICR_ASSERT: t.CDefine = 0x4000
LAPIC_ICR_DEASSERT: t.CDefine = 0x8000
LAPIC_ICR_LEVEL: t.CDefine = 0x8000
MAX_CPUS: t.CDefine = 8
AP_TRAMPOLINE_ADDR: t.CDefine = 0x7000
_lapic_base: t.CStatic | t.CUInt64T = 0
_cpu_count: t.CStatic | t.CUInt32T = 1
_bsp_lapic_id: t.CStatic | t.CUInt32T = 0
_ap_ready: t.CStatic | t.CUInt32T = 0
def read(offset: t.CUInt32T) -> t.CUInt32T:
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
return c.Deref(t.CUInt32T(addr, t.CPtr))
def write(offset: t.CUInt32T, value: t.CUInt32T):
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
c.Set(c.Deref(t.CUInt32T(addr, t.CPtr)), value)
def eoi():
write(LAPIC_EOI, 0)
def get_id() -> t.CUInt32T:
return read(LAPIC_ID) >> 24
@c.Attribute(t.attr.noinline)
def init():
global _lapic_base, _bsp_lapic_id
msr_val: t.CUInt64T = cpu.msr_read(IA32_APIC_BASE)
_lapic_base = msr_val & APIC_BASE_ADDR_MASK
cpu.msr_write(IA32_APIC_BASE, msr_val | APIC_BASE_MSR_ENABLE)
_bsp_lapic_id = read(LAPIC_ID) >> 24
write(LAPIC_SVR, LAPIC_SVR_ENABLE | 0xFF)
write(LAPIC_TPR, 0)
write(LAPIC_LVT_TIMER, LAPIC_LVT_MASKED)
write(LAPIC_LVT_LINT0, LAPIC_LVT_DELIVERY_EXTINT)
write(LAPIC_LVT_LINT1, LAPIC_LVT_DELIVERY_NMI)
write(LAPIC_LVT_ERROR, LAPIC_LVT_MASKED)
write(LAPIC_TIMER_DIVIDE, 0x0B)
write(LAPIC_LDR, 0x01000000)
eoi()
@c.Attribute(t.attr.noinline)
def detect_cpu_count() -> t.CUInt32T:
res: cpu.cpuid_result
cpu.cpuid(0, c.Addr(res))
max_leaf: t.CUInt32T = res.eax
if max_leaf >= 0x0B:
cpu.cpuid_sub(0x0B, 0, c.Addr(res))
num_threads: t.CUInt32T = res.ebx & 0xFFFF
if num_threads > 0 and num_threads <= MAX_CPUS:
return num_threads
cpu.cpuid(1, c.Addr(res))
if res.edx & cpu.CPU_FEATURE_HTT:
count: t.CUInt32T = (res.ebx >> 16) & 0xFF
if count > 0 and count <= MAX_CPUS:
return count
return 1
def _wait_icr():
timeout: t.CUInt32T = 1000000
while timeout > 0:
val: t.CUInt32T = read(LAPIC_ICR_LOW)
if (val & (1 << 12)) == 0:
return
timeout -= 1
def _send_ipi(apic_id: t.CUInt32T, vector: t.CUInt32T, delivery_mode: t.CUInt32T):
_wait_icr()
write(LAPIC_ICR_HIGH, apic_id << 24)
write(LAPIC_ICR_LOW, vector | delivery_mode | LAPIC_ICR_LEVEL | LAPIC_ICR_ASSERT)
_wait_icr()
def ap_entry():
global _ap_ready
my_id: t.CUInt32T = get_id()
buf: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf), 64, "[AP] core %u started (lapic=%u)\n", my_id, my_id)
serial.puts(buf)
_ap_ready = 1
while True:
asm.sti()
asm.hlt()
_trampoline_bin: t.CStatic | t.CArray[t.CUInt8T, 128] = [
0xFA, # cli
0x31, 0xC0, # xor ax, ax
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x0F, 0x01, 0x16, 0x00, 0x7E, # lgdt [0x7E00]
0x0F, 0x20, 0xC0, # mov eax, cr0
0x83, 0xC8, 0x01, # or eax, 1
0x0F, 0x22, 0xC0, # mov cr0, eax
0xEA, 0x1A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x701A
# 32-bit 保护模式开始
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x8E, 0xE0, # mov fs, ax
0x8E, 0xE8, # mov gs, ax
0x8E, 0xD0, # mov ss, ax
0x0F, 0x20, 0xE0, # mov eax, cr4
0x83, 0xC8, 0x20, # or eax, 0x20 (PAE)
0x0F, 0x22, 0xE0, # mov cr4, eax
0x8B, 0x04, 0x25, 0x00, 0x7F, 0x00, 0x00, # mov eax, [0x7F00]
0x0F, 0x22, 0xD8, # mov cr3, eax
0xB9, 0x80, 0x00, 0x00, 0xC0, # mov ecx, 0xC0000080 (EFER)
0x0F, 0x32, # rdmsr
0x83, 0xC8, 0x00, 0x01, 0x00, 0x00, # or eax, 0x100 (LME)
0x0F, 0x79, # wrmsr
0x0F, 0x20, 0xC0, # mov eax, cr0
0x0D, 0x00, 0x00, 0x00, 0x80, # or eax, 0x80000000 (PG)
0x0F, 0x22, 0xC0, # mov cr0, eax
0xEA, 0x5A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x705A
# 64-bit 长模式开始
0x48, 0x8B, 0x24, 0x25, 0x08, 0x7F, 0x00, 0x00, # mov rsp, [0x7F08]
0x0F, 0x01, 0x16, 0x10, 0x7F, # lgdt [0x7F10]
0x0F, 0x01, 0x1E, 0x20, 0x7F, # lidt [0x7F20]
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x8E, 0xE0, # mov fs, ax
0x8E, 0xE8, # mov gs, ax
0x8E, 0xD0, # mov ss, ax
0x48, 0x8B, 0x04, 0x25, 0x28, 0x7F, 0x00, 0x00, # mov rax, [0x7F28]
0xFF, 0xE0 # jmp rax
]
def _setup_trampoline(entry_addr: t.CUInt64T, stack_addr: t.CUInt64T, cr3_val: t.CUInt64T):
dest: t.CUInt8T | t.CPtr = t.CUInt8T(AP_TRAMPOLINE_ADDR, t.CPtr)
src: t.CUInt8T | t.CPtr = c.Addr(_trampoline_bin)
i: t.CInt
for i in range(128):
c.Set(c.Deref(dest + t.CUInt64T(i)), c.Deref(src + t.CUInt64T(i)))
gdt_ptr_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E00
c.Set(c.Deref(t.CUInt16T(gdt_ptr_addr, t.CPtr)), t.CUInt16T(23))
c.Set(c.Deref(t.CUInt64T(gdt_ptr_addr + 2, t.CPtr)), t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0E10))
gdt_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E10
c.Set(c.Deref(t.CUInt64T(gdt_addr, t.CPtr)), t.CUInt64T(0))
c.Set(c.Deref(t.CUInt64T(gdt_addr + 8, t.CPtr)), t.CUInt64T(0x00AF9A000000FFFF))
c.Set(c.Deref(t.CUInt64T(gdt_addr + 16, t.CPtr)), t.CUInt64T(0x00CF92000000FFFF))
c.Set(c.Deref(t.CUInt32T(AP_TRAMPOLINE_ADDR + 0x0F00, t.CPtr)), t.CUInt32T(cr3_val))
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F08, t.CPtr)), stack_addr)
gp_addr: t.CUInt64T = t.CUInt64T(c.Addr(gdt.gp))
gdt_base: t.CUInt64T = c.Deref(t.CUInt64T(gp_addr + 2, t.CPtr))
gdt_limit: t.CUInt16T = c.Deref(t.CUInt16T(gp_addr, t.CPtr))
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F10, t.CPtr)), gdt_limit)
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F12, t.CPtr)), gdt_base)
idt_addr: t.CUInt64T = t.CUInt64T(c.Addr(idt.idp))
idt_base: t.CUInt64T = c.Deref(t.CUInt64T(idt_addr + 2, t.CPtr))
idt_limit: t.CUInt16T = c.Deref(t.CUInt16T(idt_addr, t.CPtr))
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F20, t.CPtr)), idt_limit)
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F22, t.CPtr)), idt_base)
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F28, t.CPtr)), entry_addr)
def start_aps():
global _cpu_count, _ap_ready
if _cpu_count <= 1: return
cr3_val: t.CUInt64T = 0
c.Asm(f"""mov rax, cr3
mov {c.AsmOut(cr3_val, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
stack_size: t.CUInt64T = 8192
i: t.CUInt32T
for i in range(1, _cpu_count):
_ap_ready = 0
stack: t.CVoid | t.CPtr = mm.malloc(stack_size)
if stack is None: continue
stack_top: t.CUInt64T = t.CUInt64T(stack) + stack_size
stack_top = stack_top & ~t.CUInt64T(15)
_setup_trampoline(t.CUInt64T(ap_entry), stack_top, cr3_val)
_send_ipi(i, 0, LAPIC_ICR_INIT)
timer.timer_msleep(10)
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
timer.timer_msleep(1)
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
wait: t.CUInt32T = 0
while _ap_ready == 0 and wait < 5000:
timer.timer_msleep(1)
wait += 1
def early_init():
global _cpu_count, _bsp_lapic_id
features: t.CUInt32T = cpu.detect_features_static()
if features & cpu.CPU_FEATURE_APIC:
init()
_cpu_count = detect_cpu_count()
else:
_cpu_count = 1
def get_cpu_count() -> t.CUInt32T:
return _cpu_count
def get_lapic_id() -> t.CUInt32T:
return get_id()