根因:bootloader 只按 kernel 文件大小 AllocatePages(.bss 不占文件),于是 .bss 尾部(ticks/_perf_* 等全局量)与主线程栈区(0x60000~0x80000)在 memmap 里仍是 EfiConventionalMemory,被内核 mm 的堆 arena 当作空闲内存占用 → 内核全局量被写坏、 堆元数据被反向破坏,最终桌面线程栈上的 va_list 被改坏,vsnprintf 读 %d 变参时 #GP(rip=0x130d45, err=0x0)。 - linker.ld: .bss 末尾加 LONG(0) 强制 PROGBITS,使 kernel.bin 的 FileSize 涵盖 .bss,bootloader 的 PagesNeeded 得以预留整块内核镜像(含 .bss) - mm.init: 新增 KernelAddr/KernelEnd,挑 arena 时把与内核镜像 [kernel_PhysAddr, __bss_end) 重叠的 region 起点抬到镜像末端(不整段丢弃) - main.vp: 取 __bss_end 并传入 mm.init - boot.c: ExitBootServices 前用 AllocatePages(AllocateAddress, EfiLoaderData) 占位内核栈区 0x60000~0x80000,使其在 memmap 中标记已用 另含在途整理:多处补显式收窄转换(uint8()/uint16() 等)、kbd_svc 构造改为 kbd_svc.__init__() 等。
120 lines
3.6 KiB
Plaintext
120 lines
3.6 KiB
Plaintext
import asm
|
||
|
||
|
||
# PIC端口定义
|
||
define PIC1_COMMAND = 0x20
|
||
define PIC1_DATA = 0x21
|
||
define PIC2_COMMAND = 0xA0
|
||
define PIC2_DATA = 0xA1
|
||
|
||
# ICW1 - 初始化命令字1
|
||
define ICW1_ICW4 = 0x01 # 需要ICW4
|
||
define ICW1_SINGLE = 0x02 # 单级模式
|
||
define ICW1_INTERVAL4 = 0x04 # 间隔4字节
|
||
define ICW1_LEVEL = 0x08 # 电平触发模式
|
||
define ICW1_INIT = 0x10 # 初始化
|
||
|
||
# ICW4 - 初始化命令字4
|
||
define ICW4_8086 = 0x01 # 8086/88模式
|
||
define ICW4_AUTO = 0x02 # 自动EOI
|
||
define ICW4_BUF_SLAVE = 0x08 # 缓冲模式(从片)
|
||
define ICW4_BUF_MASTER = 0x0C # 缓冲模式(主片)
|
||
define ICW4_SFNM = 0x10 # 特殊全嵌套模式
|
||
|
||
# OCW2 - 操作命令字2
|
||
define OCW2_EOI = 0x20 # 结束中断
|
||
|
||
# OCW3 - 操作命令字3
|
||
define OCW3_READ_ISR = 0x0B # 读取中断服务寄存器(ISR)
|
||
|
||
# 初始化PIC
|
||
def init():
|
||
# 发送ICW1:开始初始化,需要ICW4
|
||
asm.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4)
|
||
asm.io_wait()
|
||
asm.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4)
|
||
asm.io_wait()
|
||
|
||
# 发送ICW2:中断向量偏移
|
||
asm.outb(PIC1_DATA, 0x20) # IRQ0-7映射到0x20-0x27
|
||
asm.io_wait()
|
||
asm.outb(PIC2_DATA, 0x28) # IRQ8-15映射到0x28-0x2F
|
||
asm.io_wait()
|
||
|
||
# 发送ICW3:级联信息
|
||
asm.outb(PIC1_DATA, 0x04) # 主PIC的IRQ2连接从PIC
|
||
asm.io_wait()
|
||
asm.outb(PIC2_DATA, 0x02) # 从PIC连接到主PIC的IRQ2
|
||
asm.io_wait()
|
||
|
||
# 发送ICW4:8086模式
|
||
asm.outb(PIC1_DATA, ICW4_8086)
|
||
asm.io_wait()
|
||
asm.outb(PIC2_DATA, ICW4_8086)
|
||
asm.io_wait()
|
||
|
||
# 设置初始屏蔽字:只启用IRQ0(定时器)、IRQ1(键盘)、IRQ2(级联)
|
||
# 主PIC: 屏蔽所有除了IRQ0, IRQ1, IRQ2 (0xF8 = 11111000)
|
||
# 从PIC: 屏蔽所有 (0xFF = 11111111),鼠标中断由驱动程序自己启用
|
||
asm.outb(PIC1_DATA, 0xF8) # 启用IRQ0, IRQ1, IRQ2
|
||
asm.io_wait()
|
||
asm.outb(PIC2_DATA, 0xFF) # 屏蔽所有从PIC中断
|
||
asm.io_wait()
|
||
|
||
# 发送EOI信号
|
||
def eoi(irq: uint8):
|
||
if irq >= 8: asm.outb(PIC2_COMMAND, OCW2_EOI)
|
||
asm.outb(PIC1_COMMAND, OCW2_EOI)
|
||
|
||
|
||
# 检查是否是虚假中断(spurious interrupt)
|
||
# 返回 1 表示是虚假中断,0 表示是真实中断
|
||
def isSpurious(irq: int) -> int:
|
||
# 边界检查
|
||
if irq < 0 or irq > 15: return 0
|
||
isr: uint8
|
||
if irq < 8:
|
||
# 发送OCW3,读取ISR(Interrupt Service Register)
|
||
asm.outb(PIC1_COMMAND, OCW3_READ_ISR)
|
||
asm.io_wait()
|
||
isr = asm.inb(PIC1_COMMAND)
|
||
# 如果ISR中对应位为0,说明是虚假中断
|
||
return not (isr & (1 << irq))
|
||
else:
|
||
# 发送OCW3,读取从PIC的ISR
|
||
asm.outb(PIC2_COMMAND, OCW3_READ_ISR)
|
||
asm.io_wait()
|
||
isr = asm.inb(PIC2_COMMAND)
|
||
# 如果ISR中对应位为0,说明是虚假中断
|
||
return not (isr & (1 << (irq - 8)))
|
||
|
||
# 设置IRQ屏蔽
|
||
def setMask(irq: uint8):
|
||
# 边界检查
|
||
if irq > 15: return
|
||
port: uint16
|
||
value: uint8
|
||
if irq < 8:
|
||
port = PIC1_DATA
|
||
else:
|
||
port = PIC2_DATA
|
||
irq -= 8
|
||
value = uint8(asm.inb(port) | (1 << irq))
|
||
asm.outb(port, value)
|
||
asm.io_wait() # 确保命令生效
|
||
|
||
# 清除IRQ屏蔽
|
||
def clearMask(irq: uint8):
|
||
# 边界检查
|
||
if irq > 15: return
|
||
port: uint16
|
||
value: uint8
|
||
if irq < 8:
|
||
port = PIC1_DATA
|
||
else:
|
||
port = PIC2_DATA
|
||
irq -= 8
|
||
value = uint8(asm.inb(port) & ~(1 << irq))
|
||
asm.outb(port, value)
|
||
asm.io_wait() # 确保命令生效
|