用户态触发中断时显存未写入,出现int 13错误码18问题排查
用户态触发中断时显存未写入的问题
问题描述
用户态代码通过int指令触发中断后,中断处理程序本应在屏幕上显示'A',但实际未生效。反而屏幕上出现的是int 13错误码18的提示,问题似乎出在将ds切换为内核段的步骤中。
中断处理程序代码
void irsHandler(intData data) { char* vm = (char*) 0xb8000; vm[0] = 'A'; }
更新信息
GDT定义
gdt_start: ;first entry is always null (each entry is 8 bytes or 64 bits) dd 0x0 ; 4 byte dd 0x0 ; 4 byte ; GDT for code segment. base = 0x00000000, length = 0xfffff gdt_code: dw 0xFFFF ; segment length, bits 0-15 dw 0x0 ; segment base, bits 0-15 db 0x0 ; segment base, bits 16-23 db 10011010b ; flags (8 bits) db 11000000b ; flags (4 bits) + segment length, bits 16-19 db 0x0 ; segment base, bits 24-31 ; GDT for data segment. base and length identical to code segment gdt_data: dw 0xFFFF dw 0x0 db 0x0 db 10010010b db 11000000b db 0x0 U_code: dw 0xFFFF ; segment length, bits 0-15 dw 0x6000 ; segment base, bits 0-15 db 0x00 ; segment base, bits 16-23 db 11111010b ; flags (8 bits) db 11000111b ; flags (4 bits) + segment length, bits 16-19 db 0x00 ; segment base, bits 24-31 ; 用户态数据段 U_data: dw 0xFFFF dw 0x6000 db 0x00 db 11110010b db 11000111b db 0x00 gdt_tss: dw TSS_SIZE-1 ; segment length, bits 0-15 dw tss ; segment base, bits 0-15 db 0x0 ; segment base, bits 16-23 db 10001001b ; access flags (8 bits) db 00000000b ; flags (4 bits) + segment length, bits 16-19 db 0x0 ; segment base, bits 24-31 gdt_end: ; GDT descriptor gdt_descriptor: dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size dd gdt_start ; address (32 bit)
调用C处理程序的汇编Stub
isr_common_stub: pusha ; 将通用寄存器压栈 mov ax, ds ; eax低16位 = ds push eax ; 保存数据段描述符 mov ax, 0x10 ; 内核数据段描述符 mov ds, ax mov es, ax mov fs, ax mov gs, ax call irsHandler ; 调用C处理函数 pop eax mov ds, ax mov es, ax mov fs, ax mov gs, ax popa add esp, 8 ; 清理压入的错误码和ISR编号 sti iret
可能的原因分析
- 栈平衡问题:
add esp,8的操作需要对应中断触发时栈上的内容。如果触发的中断本身没有错误码,却执行了该操作,会导致栈指针偏移错误,后续iret执行时会读取错误的返回地址/段选择子,引发异常。 - TSS配置错误:从用户态进入内核态时,CPU依赖TSS切换到内核栈。如果TSS未正确初始化或加载,会导致栈切换失败,触发异常进而出现int 13错误。
- 中断向量表配置错误:若触发的中断对应的向量未指向
isr_common_stub,可能意外触发了int 13的处理逻辑,而非目标中断程序。 - 段切换异常:切换
ds到内核段(0x10)时,若栈中保存的用户态ds值无效,或切换过程中出现权限冲突,会引发段异常,中断原处理流程。 - 显存访问未生效:即使切换到内核段,若
irsHandler因栈异常或函数调用约定不匹配未被正确执行,写入显存的代码根本没运行,自然不会显示'A'。
内容的提问来源于stack exchange,提问作者Jacob Knuth
相关产品推荐
相关产品推荐

