【问题标题】:Switch protcted mode (32bits) to real mode (16bits) in asm, low level在 asm 中将保护模式(32 位)切换到实模式(16 位),低电平
【发布时间】:2021-04-22 03:39:52
【问题描述】:

我正在创建一个操作系统,我需要在实模式下调用 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 */

【问题讨论】:

  • 不是一个完整的例子。而且“有错误”太不具体了:会发生什么以及您期望什么?
  • cli 然后hlt 可能会停止(冻结)机器,直到发生 NMI。 mov cr0, eax 应该在 and eax 之后。
  • 这对我们来说是一个谜吗?看起来你已经拼凑了一些东西,并希望从中产生一些好的东西。
  • 在将ds 设置为0x10 后,您知道mov [savcr0], eax 在做什么吗?
  • 为什么在设置SP寄存器之前有一个hlt?为什么不继续将SSSP 设置在一起?

标签: assembly operating-system x86-16 bios low-level


【解决方案1】:

对于将jmpcall 转移到不同的分段,您需要遵守以下特权规则之一:

  • 目标 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 */

您当前程序中的事情顺序与您在here 中找到的关于从保护模式切换到实模式的顺序不同。

【讨论】:

  • 谢谢,但现在我有一个新错误00002173089e[CPU0 ] fetch_raw_descriptor: GDT: index (50bf)a17 > limit (7f8) os can't launch go16 I don't know why
  • 查看编辑并找出新的描述符告诉你什么。
  • "将内存访问限制为仅 1MB" -- 在 Real 86 模式中,限制实际上应设置为 64 KiB,每个 16 位段。
  • 谢谢,现在我可以打开 PM16 功能但是当我做 jmp 0x50:realMode 我有一个新错误 math_abort: MSDOS compatibility FPU exception
  • @KonectTeam 甚至无法推测此最新错误,因为我们无法看到您对代码进行了(或未进行)哪些更改。我建议您发布一个包含所有相关代码的新问题,并且肯定比当前问题更多(BTW 并没有受到一些人的欢迎,因为它包含的内容不足以让我们使用)。记住“更好的问题给出更好的答案”
猜你喜欢
  • 2018-08-07
  • 1970-01-01
  • 2018-11-27
  • 1970-01-01
  • 1970-01-01
  • 2016-03-29
  • 2018-11-28
  • 2014-07-29
  • 2015-03-08
相关资源
最近更新 更多