Initial import of ViperOS
This commit is contained in:
251
VKernel/Kernel/drivers/core/cpu/apic.py
Normal file
251
VKernel/Kernel/drivers/core/cpu/apic.py
Normal 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()
|
||||
346
VKernel/Kernel/drivers/core/cpu/cpu.py
Normal file
346
VKernel/Kernel/drivers/core/cpu/cpu.py
Normal file
@@ -0,0 +1,346 @@
|
||||
import fpu
|
||||
import asm
|
||||
import intr.gdt as gdt
|
||||
import string
|
||||
import t, c
|
||||
|
||||
IA32_KERNEL_GS_BASE: t.CDefine = 0xC0000102
|
||||
KERN_STACK_SIZE: t.CDefine = 8192
|
||||
|
||||
|
||||
CPU_FEATURE_FPU: t.CDefine = (1 << 0)
|
||||
CPU_FEATURE_PSE: t.CDefine = (1 << 1)
|
||||
CPU_FEATURE_MSR: t.CDefine = (1 << 2)
|
||||
CPU_FEATURE_PAE: t.CDefine = (1 << 3)
|
||||
CPU_FEATURE_MCE: t.CDefine = (1 << 4)
|
||||
CPU_FEATURE_CX8: t.CDefine = (1 << 5)
|
||||
CPU_FEATURE_APIC: t.CDefine = (1 << 6)
|
||||
CPU_FEATURE_SEP: t.CDefine = (1 << 7)
|
||||
CPU_FEATURE_MTRR: t.CDefine = (1 << 8)
|
||||
CPU_FEATURE_PGE: t.CDefine = (1 << 9)
|
||||
CPU_FEATURE_MCA: t.CDefine = (1 << 10)
|
||||
CPU_FEATURE_CMOV: t.CDefine = (1 << 11)
|
||||
CPU_FEATURE_PAT: t.CDefine = (1 << 12)
|
||||
CPU_FEATURE_PSE36: t.CDefine = (1 << 13)
|
||||
CPU_FEATURE_PSN: t.CDefine = (1 << 14)
|
||||
CPU_FEATURE_CLFSH: t.CDefine = (1 << 15)
|
||||
CPU_FEATURE_DS: t.CDefine = (1 << 16)
|
||||
CPU_FEATURE_ACPI: t.CDefine = (1 << 17)
|
||||
CPU_FEATURE_MMX: t.CDefine = (1 << 18)
|
||||
CPU_FEATURE_FXSR: t.CDefine = (1 << 19)
|
||||
CPU_FEATURE_SSE: t.CDefine = (1 << 20)
|
||||
CPU_FEATURE_SSE2: t.CDefine = (1 << 21)
|
||||
CPU_FEATURE_SS: t.CDefine = (1 << 22)
|
||||
CPU_FEATURE_HTT: t.CDefine = (1 << 23)
|
||||
CPU_FEATURE_TM: t.CDefine = (1 << 24)
|
||||
CPU_FEATURE_PBE: t.CDefine = (1 << 25)
|
||||
|
||||
class cpu_info(t.CStruct):
|
||||
vendor_id: t.CArray[t.CChar, 13]
|
||||
brand_string: t.CArray[t.CChar, 48]
|
||||
features: t.CUInt32T
|
||||
family: t.CUInt32T
|
||||
model: t.CUInt32T
|
||||
stepping: t.CUInt32T
|
||||
cpu_type: t.CUInt32T
|
||||
ext_model: t.CUInt32T
|
||||
ext_family: t.CUInt32T
|
||||
cpu_freq: t.CUInt64T
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class _tss:
|
||||
reserved0: t.CUInt64T
|
||||
rsp0: t.CUInt64T
|
||||
rsp1: t.CUInt64T
|
||||
rsp2: t.CUInt64T
|
||||
reserved1: t.CUInt64T
|
||||
ist1: t.CUInt64T
|
||||
ist2: t.CUInt64T
|
||||
ist3: t.CUInt64T
|
||||
ist4: t.CUInt64T
|
||||
ist5: t.CUInt64T
|
||||
ist6: t.CUInt64T
|
||||
ist7: t.CUInt64T
|
||||
reserved2: t.CUInt64T
|
||||
reserved3: t.CUInt16T
|
||||
io_map_base: t.CUInt16T
|
||||
|
||||
class cpuid_result(t.CStruct):
|
||||
eax: t.CUInt32T
|
||||
ebx: t.CUInt32T
|
||||
ecx: t.CUInt32T
|
||||
edx: t.CUInt32T
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _rdmsr_naked():
|
||||
c.Asm(f"""rdmsr
|
||||
shl rdx, 32
|
||||
or rax, rdx
|
||||
ret""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _wrmsr_naked():
|
||||
# msr_write sets ecx=msr, r8=value. wrmsr needs ECX=msr, EDX:EAX=value.
|
||||
# Old code did `mov rax,rcx` (rax=msr) which wrote (value>>32):msr to MSR,
|
||||
# corrupting IA32_KERNEL_GS_BASE -> swapgs -> #GP on gs:[0]. Fixed below.
|
||||
c.Asm(f"""mov rax, r8
|
||||
mov rdx, r8
|
||||
shr rdx, 32
|
||||
wrmsr
|
||||
ret""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
def msr_read(msr: t.CUInt32T) -> t.CUInt64T:
|
||||
result: t.CUInt64T = 0
|
||||
func: t.CVoid | t.CPtr = _rdmsr_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}
|
||||
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
|
||||
return result
|
||||
|
||||
def msr_write(msr: t.CUInt32T, value: t.CUInt64T):
|
||||
func: t.CVoid | t.CPtr = _wrmsr_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_R8])
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _cpuid_naked():
|
||||
c.Asm(f"""push rbx
|
||||
mov eax, ecx
|
||||
cpuid
|
||||
mov dword ptr [rdx], eax
|
||||
mov dword ptr [rdx + 4], ebx
|
||||
mov dword ptr [rdx + 8], ecx
|
||||
mov dword ptr [rdx + 12], edx
|
||||
pop rbx
|
||||
ret""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _cpuid_sub_naked():
|
||||
c.Asm(f"""push rbx
|
||||
mov eax, ecx
|
||||
mov ecx, r8d
|
||||
cpuid
|
||||
mov dword ptr [rdx], eax
|
||||
mov dword ptr [rdx + 4], ebx
|
||||
mov dword ptr [rdx + 8], ecx
|
||||
mov dword ptr [rdx + 12], edx
|
||||
pop rbx
|
||||
ret""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def cpuid(leaf: t.CUInt32T, out: cpuid_result | t.CPtr):
|
||||
func: t.CVoid | t.CPtr = _cpuid_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_R8,
|
||||
t.ASM_DESCR.CLOBBER_R9, t.ASM_DESCR.CLOBBER_R10,
|
||||
t.ASM_DESCR.CLOBBER_R11])
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def cpuid_sub(leaf: t.CUInt32T, sub: t.CUInt32T, out: cpuid_result | t.CPtr):
|
||||
func: t.CVoid | t.CPtr = _cpuid_sub_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8d, {c.AsmInp(sub, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_R8,
|
||||
t.ASM_DESCR.CLOBBER_R9, t.ASM_DESCR.CLOBBER_R10,
|
||||
t.ASM_DESCR.CLOBBER_R11])
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def detect_features_static() -> t.CUInt32T:
|
||||
features: t.CUInt32T = 0
|
||||
res: cpuid_result
|
||||
cpuid(1, c.Addr(res))
|
||||
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
|
||||
if res.edx & (1 << 3): features |= CPU_FEATURE_PSE
|
||||
if res.edx & (1 << 5): features |= CPU_FEATURE_MSR
|
||||
if res.edx & (1 << 6): features |= CPU_FEATURE_PAE
|
||||
if res.edx & (1 << 7): features |= CPU_FEATURE_MCE
|
||||
if res.edx & (1 << 8): features |= CPU_FEATURE_CX8
|
||||
if res.edx & (1 << 9): features |= CPU_FEATURE_APIC
|
||||
if res.edx & (1 << 11): features |= CPU_FEATURE_SEP
|
||||
if res.edx & (1 << 12): features |= CPU_FEATURE_MTRR
|
||||
if res.edx & (1 << 13): features |= CPU_FEATURE_PGE
|
||||
if res.edx & (1 << 14): features |= CPU_FEATURE_MCA
|
||||
if res.edx & (1 << 15): features |= CPU_FEATURE_CMOV
|
||||
if res.edx & (1 << 16): features |= CPU_FEATURE_PAT
|
||||
if res.edx & (1 << 17): features |= CPU_FEATURE_PSE36
|
||||
if res.edx & (1 << 18): features |= CPU_FEATURE_PSN
|
||||
if res.edx & (1 << 19): features |= CPU_FEATURE_CLFSH
|
||||
if res.edx & (1 << 21): features |= CPU_FEATURE_DS
|
||||
if res.edx & (1 << 22): features |= CPU_FEATURE_ACPI
|
||||
if res.edx & (1 << 23): features |= CPU_FEATURE_MMX
|
||||
if res.edx & (1 << 24): features |= CPU_FEATURE_FXSR
|
||||
if res.edx & (1 << 25): features |= CPU_FEATURE_SSE
|
||||
if res.edx & (1 << 26): features |= CPU_FEATURE_SSE2
|
||||
if res.edx & (1 << 27): features |= CPU_FEATURE_SS
|
||||
if res.edx & (1 << 28): features |= CPU_FEATURE_HTT
|
||||
if res.edx & (1 << 29): features |= CPU_FEATURE_TM
|
||||
if res.edx & (1 << 30): features |= CPU_FEATURE_PBE
|
||||
return features
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class per_cpu_data:
|
||||
user_rsp: t.CUInt64T
|
||||
kernel_rsp0: t.CUInt64T
|
||||
current_pid: t.CInt
|
||||
_pad0: t.CUInt32T
|
||||
_pad1: t.CUInt64T
|
||||
|
||||
_per_cpu: per_cpu_data
|
||||
|
||||
@t.Object
|
||||
class _CPUObject:
|
||||
tss: _tss
|
||||
features: t.CUInt32T
|
||||
def __init__(self):
|
||||
self.__init_tss__()
|
||||
|
||||
def __init_tss__(self):
|
||||
global _per_cpu
|
||||
string.memset(c.Addr(self.tss), 0, self.tss.__sizeof__())
|
||||
self.tss.io_map_base = self.tss.__sizeof__()
|
||||
string.memset(c.Addr(_per_cpu), 0, per_cpu_data.__sizeof__())
|
||||
gdt.setTSS64(5, t.CUInt64T(c.Addr(self.tss)), self.tss.__sizeof__() - 1)
|
||||
gdt.flush()
|
||||
# IA32_KERNEL_GS_BASE holds the per_cpu address for swapgs.
|
||||
# When entering from Ring 3, swapgs swaps IA32_GS_BASE (0) with
|
||||
# IA32_KERNEL_GS_BASE (_per_cpu), making gs: accessible in kernel.
|
||||
# When returning to Ring 3, swapgs swaps back, restoring GS base to 0.
|
||||
msr_write(IA32_KERNEL_GS_BASE, t.CUInt64T(c.Addr(_per_cpu)))
|
||||
|
||||
def getInfo(self, info: cpu_info | t.CPtr):
|
||||
if not info: return
|
||||
res: cpuid_result
|
||||
cpuid(0, c.Addr(res))
|
||||
(t.CUInt32T(info.vendor_id, t.CPtr))[0] = res.ebx
|
||||
(t.CUInt32T(info.vendor_id, t.CPtr))[1] = res.edx
|
||||
(t.CUInt32T(info.vendor_id, t.CPtr))[2] = res.ecx
|
||||
info.vendor_id[12] = '\0'
|
||||
info.features = self.detectFeatures()
|
||||
cpuid(1, c.Addr(res))
|
||||
info.stepping = (res.eax >> 0) & 0x0F
|
||||
info.model = (res.eax >> 4) & 0x0F
|
||||
info.family = (res.eax >> 8) & 0x0F
|
||||
info.cpu_type = (res.eax >> 12) & 0x03
|
||||
info.ext_model = (res.eax >> 16) & 0x0F
|
||||
info.ext_family = (res.eax >> 20) & 0xFF
|
||||
for i in range(4):
|
||||
cpuid(0x80000002 + i, c.Addr(res))
|
||||
base: t.CUInt32T | t.CPtr = t.CUInt32T(info.brand_string, t.CPtr)
|
||||
base[i * 4 + 0] = res.eax
|
||||
base[i * 4 + 1] = res.ebx
|
||||
base[i * 4 + 2] = res.ecx
|
||||
base[i * 4 + 3] = res.edx
|
||||
info.brand_string[47] = '\0'
|
||||
info.cpu_freq = 2000000000
|
||||
|
||||
def detectFeatures(self) -> t.CUInt32T:
|
||||
features: t.CInt32T = 0
|
||||
res: cpuid_result
|
||||
cpuid(1, c.Addr(res))
|
||||
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
|
||||
if res.edx & (1 << 3): features |= CPU_FEATURE_PSE
|
||||
if res.edx & (1 << 5): features |= CPU_FEATURE_MSR
|
||||
if res.edx & (1 << 6): features |= CPU_FEATURE_PAE
|
||||
if res.edx & (1 << 7): features |= CPU_FEATURE_MCE
|
||||
if res.edx & (1 << 8): features |= CPU_FEATURE_CX8
|
||||
if res.edx & (1 << 9): features |= CPU_FEATURE_APIC
|
||||
if res.edx & (1 << 11): features |= CPU_FEATURE_SEP
|
||||
if res.edx & (1 << 12): features |= CPU_FEATURE_MTRR
|
||||
if res.edx & (1 << 13): features |= CPU_FEATURE_PGE
|
||||
if res.edx & (1 << 14): features |= CPU_FEATURE_MCA
|
||||
if res.edx & (1 << 15): features |= CPU_FEATURE_CMOV
|
||||
if res.edx & (1 << 16): features |= CPU_FEATURE_PAT
|
||||
if res.edx & (1 << 17): features |= CPU_FEATURE_PSE36
|
||||
if res.edx & (1 << 18): features |= CPU_FEATURE_PSN
|
||||
if res.edx & (1 << 19): features |= CPU_FEATURE_CLFSH
|
||||
if res.edx & (1 << 21): features |= CPU_FEATURE_DS
|
||||
if res.edx & (1 << 22): features |= CPU_FEATURE_ACPI
|
||||
if res.edx & (1 << 23): features |= CPU_FEATURE_MMX
|
||||
if res.edx & (1 << 24): features |= CPU_FEATURE_FXSR
|
||||
if res.edx & (1 << 25): features |= CPU_FEATURE_SSE
|
||||
if res.edx & (1 << 26): features |= CPU_FEATURE_SSE2
|
||||
if res.edx & (1 << 27): features |= CPU_FEATURE_SS
|
||||
if res.edx & (1 << 28): features |= CPU_FEATURE_HTT
|
||||
if res.edx & (1 << 29): features |= CPU_FEATURE_TM
|
||||
if res.edx & (1 << 30): features |= CPU_FEATURE_PBE
|
||||
return features
|
||||
|
||||
def enableInterrupts(self):
|
||||
c.Asm("sti", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def disableInterrupts(self):
|
||||
c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def enableNmis(self):
|
||||
current: t.CUInt8T = asm.inb(0x70)
|
||||
asm.outb(0x70, current & 0x7F)
|
||||
|
||||
def disableNmis(self):
|
||||
current: t.CUInt8T = asm.inb(0x70)
|
||||
asm.outb(0x70, current | 0x80)
|
||||
|
||||
def readCR0(self) -> t.CUInt64T:
|
||||
cr0: t.CUInt64T
|
||||
c.Asm(f"""mov rax, cr0
|
||||
mov {c.AsmOut(cr0, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return cr0
|
||||
|
||||
def writeCR0(self, value: t.CUInt64T):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr0, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def readCR3(self) -> t.CUInt64T:
|
||||
cr3: t.CUInt64T
|
||||
c.Asm(f"""mov rax, cr3
|
||||
mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return cr3
|
||||
|
||||
def writeCR3(self, value: t.CUInt64T):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr3, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def readCR4(self) -> t.CUInt64T:
|
||||
cr4: t.CUInt64T
|
||||
c.Asm(f"""mov rax, cr4
|
||||
mov {c.AsmOut(cr4, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return cr4
|
||||
|
||||
def writeCR4(self, value: t.CUInt64T):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr4, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def readMSR(self, msr: t.CUInt32T) -> t.CUInt64T:
|
||||
return msr_read(msr)
|
||||
|
||||
def writeMSR(self, msr: t.CUInt32T, value: t.CUInt64T):
|
||||
msr_write(msr, value)
|
||||
|
||||
def setTSSRSP0(self, rsp0: t.CUInt64T):
|
||||
global _per_cpu
|
||||
self.tss.rsp0 = rsp0
|
||||
_per_cpu.kernel_rsp0 = rsp0
|
||||
|
||||
def set_kernel_rsp0(rsp0: t.CUInt64T):
|
||||
global _per_cpu
|
||||
_per_cpu.kernel_rsp0 = rsp0
|
||||
50
VKernel/Kernel/drivers/core/cpu/fpu.py
Normal file
50
VKernel/Kernel/drivers/core/cpu/fpu.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import cpu
|
||||
import t, c
|
||||
|
||||
|
||||
# FPU上下文结构体
|
||||
@c.Attribute(t.attr.aligned(16))
|
||||
class fpu_context:
|
||||
data: t.CUInt8T[512] # FXSAVE区域大小
|
||||
|
||||
|
||||
@t.Object
|
||||
class _FPUObject:
|
||||
CPUObject: cpu._CPUObject | t.CPtr
|
||||
# 初始化FPU
|
||||
def __init__(self, CPUObject: cpu._CPUObject | t.CPtr):
|
||||
self.enable()
|
||||
self.CPUObject = CPUObject
|
||||
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
# 启用FPU
|
||||
def enable(self):
|
||||
cr0: t.CUInt64T = self.CPUObject.readCR0()
|
||||
# 清除EM位(禁用仿真),设置MP位(监控协处理器)
|
||||
cr0 &= ~(1 << 2); # 清除EM位
|
||||
cr0 |= (1 << 1); # 设置MP位
|
||||
# 写入CR0寄存器
|
||||
self.CPUObject.writeCR0(cr0)
|
||||
# 读取CR4寄存器
|
||||
cr4: t.CUInt64T = self.CPUObject.readCR4()
|
||||
# 设置OSFXSR位和OSXMMEXCPT位,启用SSE
|
||||
cr4 |= (1 << 9) | (1 << 10)
|
||||
# 写入CR4寄存器
|
||||
self.CPUObject.writeCR4(cr4)
|
||||
# 初始化FPU
|
||||
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
# 禁用FPU
|
||||
def disable(self):
|
||||
cr0: t.CUInt64T = self.CPUObject.readCR0()
|
||||
# 设置EM位(启用仿真),清除MP位(禁用监控协处理器)
|
||||
cr0 |= (1 << 2) # 设置EM位
|
||||
cr0 &= ~(1 << 1) # 清除MP位
|
||||
# 写入CR0寄存器
|
||||
self.CPUObject.writeCR0(cr0)
|
||||
# 保存FPU上下文
|
||||
def save_context(self, context: fpu_context | t.CPtr):
|
||||
# 保存FPU状态到内存
|
||||
c.Asm(f"fxsave [{c.AsmInp(context, t.ASM_DESCR.REG_ANY)}]", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
# 恢复FPU上下文
|
||||
def restore_context(self, context: t.CConst | fpu_context | t.CPtr):
|
||||
# 从内存恢复FPU状态
|
||||
c.Asm(f"fxrstor [{c.AsmInp(context, t.ASM_DESCR.REG_ANY)}]", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
Reference in New Issue
Block a user