assembly - 在asm中将保护模式(32位)切换到实模式(16位),低电平
问题描述
我正在创建一个操作系统,我需要在实模式下调用 BIOS,我尝试了这段代码,但它有一个错误: boch 上的错误是
00002172825e[CPU0 ] check_cs: conforming code seg descriptor dpl > cpl
代码是:
global go16
;______________________________________________________________________________________________________
;Switch to 16-bit real Mode
;IN/OUT: nothing
go16:
[BITS 32]
cli ;Clear interrupts
pop edx ;save return location in edx
jmp 0x20:PM16 ;Load CS with selector 0x20
;For go to 16-bit real mode, first we have to go to 16-bit protected mode
[BITS 16]
PM16:
mov ax, 0x28 ;0x28 is 16-bit protected mode selector.
mov ss, ax
mov ds, ax
mov es, ax
mov gs, ax
mov fs, ax
mov sp, 0x7c00+0x200 ;Stack hase base at 0x7c00+0x200
mov eax, cr0
and eax, 0xfffffffe ;Clear protected enable bit in cr0
mov cr0, eax
jmp 0x50:realMode ;Load CS and IP
realMode:
;Load segment registers with 16-bit Values.
mov ax, 0x50
mov ds, ax
mov fs, ax
mov gs, ax
mov ax, 0
mov ss, ax
mov ax, 0
mov es, ax
hlt
mov sp, 0x7c00+0x200
cli
lidt[.idtR] ;Load real mode interrupt vector table
sti
push 0x50 ;New CS
push dx ;New IP (saved in edx)
retf ;Load CS, IP and Start real mode
;Real mode interrupt vector table
.idtR:
dw 0xffff ;Limit
dd 0 ;Base
该程序在 jmp 0x20:PM16 处停止,
因为他不喜欢 0x20 我需要调用 bios 来切换图形模式,因为我不能在我的引导加载程序中这样做 谢谢你的回答 PS:我的 gdt 是:
init_gdt_desc(0x0, 0x0, 0x0, 0x0, &kgdt[0]);
init_gdt_desc(0x0, 0xFFFFF, 0x9B, 0x0D, &kgdt[1]);
init_gdt_desc(0x0, 0xFFFFF, 0x93, 0x0D, &kgdt[2]);
init_gdt_desc(0x0, 0x0, 0x97, 0x0D, &kgdt[3]);
//user segment
init_gdt_desc(0x0, 0xFFFFF, 0xFF, 0x0D, &kgdt[4]); /* ucode */
init_gdt_desc(0x0, 0xFFFFF, 0xF3, 0x0D, &kgdt[5]); /* udata */
init_gdt_desc(0x0, 0x0, 0xF7, 0x0D, &kgdt[6]); /* ustack */
解决方案
对于一个jmp
或call
另一个段,您需要遵守以下特权规则之一:
- 目标 DPL 等于 CPL
- 目标 DPL 小于或等于 CPL,但设置了目标符合位
查看您的选择器,目标 DPL 为 3,CPL 为 0。
所以要使用jmp 0x20:PM16
,改变
init_gdt_desc(0x0, 0xFFFFF, 0xFF, 0x0D, &kgdt[4]); /* ucode */
进入
init_gdt_desc(0x0, 0xFFFFF, 0x9F, 0x0D, &kgdt[4]); /* ucode */
;Real mode interrupt vector table .idtR: dw 0xffff ;Limit dd 0 ;Base
正确的限制是 0x03FF(十进制为 1023)
[编辑]
由于目标是进入实模式,描述符中的BIG位应关闭以选择 16 位,而GRANULARITY位应关闭以将内存访问限制为仅 1MB。
init_gdt_desc(0x0, 0xFFFF, 0x9E, 0x0, &kgdt[4]); /* ucode */
init_gdt_desc(0x0, 0xFFFF, 0x92, 0x0, &kgdt[5]); /* udata */
当前程序中的顺序与您在此处找到的有关从保护模式切换到实模式的顺序不同。
推荐阅读
- mysql - Laravel 模型类
- android - android工具链的颤振医生错误
- spring - 休眠和堆栈跟踪的 Spring Data JPA 问题
- mysql - 根据用户 ID 选择订阅
- html - 通过 *ngFor 创建表列
- file - 为什么 readInt() 在 readInt> 266 时给我一个不正确的值?
- variables - 在 Dreamhost 上存储秘密变量和密钥
- reactjs - 无法使用 ReactJs、Axios、Redux 渲染/显示从 api 获取的数据
- javascript - 使用 RSA 私钥解密 Web 应用程序中的数据
- python - 为什么 PyTorch 优化器可能无法更新其参数?