Assembly Can';t跳转或调用在0x8000加载的内核

Assembly Can';t跳转或调用在0x8000加载的内核,assembly,x86,nasm,osdev,Assembly,X86,Nasm,Osdev,我正在尝试开发一个操作系统。设计是这样的:我有一个在0x7c00加载的引导加载程序,它加载第二阶段并在0x7e00跳转到它。第二个阶段也是在实模式下,做很多事情,比如加载gdt、启用A20和切换到保护模式。它还以0x8000加载一个非常简单的32位内核。现在的问题是,我无法调用或jmp到0x8000,因为内核似乎没有加载(我在VirtualBox中进行了内存转储)。我已经在第二阶段中完成了一个远JMP来设置CS寄存器。我正在VirtualBox中测试我的操作系统 我的引导加载程序代码: org

我正在尝试开发一个操作系统。设计是这样的:我有一个在0x7c00加载的引导加载程序,它加载第二阶段并在0x7e00跳转到它。第二个阶段也是在实模式下,做很多事情,比如加载gdt、启用A20和切换到保护模式。它还以0x8000加载一个非常简单的32位内核。现在的问题是,我无法调用或jmp到0x8000,因为内核似乎没有加载(我在VirtualBox中进行了内存转储)。我已经在第二阶段中完成了一个远JMP来设置CS寄存器。我正在VirtualBox中测试我的操作系统

我的引导加载程序代码:

org 0x7c00
bits 16
Start:
      jmp Reset
      bpbOEM DB "SKULLOS " 
      bpbBytesPerSector:    DW 512
      bpbSectorsPerCluster:     DB 1
      bpbReservedSectors:   DW 1
      bpbNumberOfFATs:      DB 2
      bpbRootEntries:       DW 224
      bpbTotalSectors:      DW 2880
      bpbMedia:                 DB 0xF0
      bpbSectorsPerFAT:         DW 9
      bpbSectorsPerTrack:   DW 18
      bpbHeadsPerCylinder:  DW 2
      bpbHiddenSectors:         DD 0
      bpbTotalSectorsBig:     DD 0
      bsDriveNumber:            DB 0
      bsUnused:                 DB 0
      bsExtBootSignature:   DB 0x29
      bsSerialNumber:           DD 0xa0a1a2a3
      bsVolumeLabel:            DB "MOS FLOPPY "
      bsFileSystem:             DB "SKFS    "
Set:
      mov al , 02h
      mov ah , 00h
      int 10h
      jmp Print
Print:
      mov al , 'A'
      mov bl , 0Fh
      mov cx , 01h
      mov ah , 09h
      int 10h
      jmp Reset
Reset:
      ; mov dl , 0x00
        mov [0x500] , dl
        mov ah , 0x00
        int 0x13
        jc Reset
        mov ax , 0x7E0 
        mov es , ax
        xor bx , bx
        mov ah , 0x02
        mov al , 1
        mov ch , 0
        mov cl , 2
        mov dh , 0
        mov dl , [0x500]
        int 0x13
        jmp 0x0000 :0x7e00
        times 510-($-$$) db 0
        db 0x55
        db 0xAA
第二阶段代码:

    org 0x7E00
    bits 16
    Start:
          jmp Setup
    ;;;;;;;;;;;;;stack;;;;;;;;;;
    Setup: 
          cli
          xor ax , ax
          mov ds , ax
          mov es , ax
          mov ax , 0x9000
          mov ss , ax
          mov sp , 0xFFFF
          sti
          jmp Set
   ;;;;;;;;;;;;;video;;;;;;;;;;;
   Set: 
          mov al , 03h
          mov ah , 00h
          int 10h
          mov ah , 09h
          mov al , 'A'
          mov bh , 00h
          mov bl , 0x0F
          mov cx , 01h
          int 10h
          jmp loadgdt
   ;;;;;;;;;;;;gdt;;;;;;;;;;;;;;;
   gdt_start:
   null: 
          dd 0
          dd 0
   code:
          dw 0FFFFh
          dw 0
          db 0
          db 10011010b
          db 11001111b
          db 0
   data:
          dw 0FFFFh
          dw 0
          db 0
          db 10010010b
          db 11001111b
          db 0
   end:
   load: dw end - gdt_start -1
         dd null
   ;;;;;;;;;;;;;loadgdt;;;;;;;;;;
   loadgdt:
         lgdt [load]
         jmp A20
   ;;;;;;;;;;;;A20;;;;;;;;;;;;;;;
   A20:
         mov ax , 0x2401
         int 0x15
         jc A20
         jmp Reset
   ;;;;;;;;;;;;;floppy;;;;;;;;;;;
   Reset:
         mov ah , 00h
         mov dl , [0x500]
         int 13h
         jc Reset
         jmp Read
   Read:
         mov ah , 02h
         mov al , 01h
         mov ch , 00h
         mov cl , 03h
         mov dh , 00h
         mov dl , [0x500]
         mov ax , 0x800
         mov es , ax
         xor bx , bx
         int 13h
         jc Read
         jmp Begin
   Begin:  
         mov ah , 09h
         mov al , 'G'
         mov bh , 00h
         mov bl , 0x0F
         mov cx , 01h
         int 10h
         jmp protected
   ;;;;;;;;;;;switching to protected;;;;
   protected: 
             mov ah , 09h
             mov al , 'P'
             mov bh , 00h
             mov bl , 0x0F
             mov cx , 01h
             int 10h
             xor ax, ax
             mov ds, ax    
             cli
             mov eax, cr0
             or eax , 1
             mov cr0 , eax
             jmp (code-gdt_start):transfer_control
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   bits 32 
   transfer_control:
                    mov ax, (data-gdt_start)        
                    mov ds, ax
                    mov ss, ax
                    mov es, ax
                    mov esp, 90000h
                    mov [0xB8000], word 0x0F58  ; Print 'X' 
                    call 0x8000    
                    hlt
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   times 512-($-$$) db 0
内核代码:

org 0x8000
bits 32
jmp Start
Start:
      mov ax , 0x10
      mov ds , ax
      mov ss, ax
      mov es, ax
      mov esp, 90000h
      mov [0xB8002], word 0x0F58   ; Print 'X'
      ret
times 512-($-$$) db 0
目前,仅打印一个“X”。但是,应打印两个“X”。 用于创建软盘的命令:

      dd seek=0 if=boot of=os.img
      dd seek=1 if=second_stage of=os.img
      dd seek=2 if=third_stage of=os.img

阅读问题阶段3 在第二阶段中,加载第三阶段,执行以下操作:

   Read:
         mov ah , 02h      ; Setup AH
         mov al , 01h      ; Setup AL
         mov ch , 00h
         mov cl , 03h
         mov dh , 00h
         mov dl , [0x500]
         mov ax , 0x800    ; Destroy contents of AX 
         mov es , ax       ; Setup ES=0x800
         xor bx , bx
         int 13h
我已经用问题标出了界线。您可以有效地设置AX以准备读取,然后使用0x800覆盖值以设置ES。在设置AH和AL之前移动设置ES。修改代码,使其看起来像:

   Read:
         mov ax , 0x800 
         mov es , ax       ; Setup ES=0x800
         mov ah , 02h      ; Setup AH
         mov al , 01h      ; Setup AL
         mov ch , 00h
         mov cl , 03h
         mov dh , 00h
         mov dl , [0x500]
         xor bx , bx
         int 13h
这可能会阻止第二阶段正确加载第三阶段


其他问题 在引导加载程序的末尾,您有:

    db 0xAA
    db 0x55
这是向后的,应该是:

    db 0x55
    db 0xAA
你可以把它写成:

    dw 0xAA55
问题似乎是,在定义这些字节时,没有考虑到小端性


您可以正确地跳过引导加载程序中的BIOS参数块,但BPB需要从引导扇区中的第4个字节开始。您可以使用
short
修饰符强制使用2字节JMP。然后,您可以在跳转后放置一个
nop
,以便BPB从第4个字节开始

更改:

  jmp Reset
  bpbOEM DB "SKULLOS " 
致:


mov sp,0xFFFF
可能应该是
mov sp,0x0000
。这只是一个小小的吹毛求疵。将堆栈放在字边界(偶数地址)上在8086处理器上性能更好。因为你不在真实模式中很长时间,所以这一点都不重要。通常情况下,您会使用
mov sp,0x0000
,因为首先从sp中减去2,然后将字推送到堆栈上,因此推送的第一个字将位于0x9000:0xfffe。当SP=0x0000时,堆栈将从包装到64k段的顶部开始


如果标签正好在JMP之后,则不需要从一个标签到另一个标签进行JMP。说明如下:

    jmp Set 
Set: 
只会浪费空间和占用CPU周期。我注意到你在很多地方都这样做了。这不是你问题的一部分,只是一个观察。远跳转
jmp(code-gdt_start):传输控制
后跟标签是可以的,因为它用于正确设置CS描述符(对于保护模式)


使用
int 13h
进行磁盘访问时,应使用BIOS传递给引导加载程序的引导驱动器号作为DL值。第一阶段和第二阶段的代码如下:

mov dl , 00h

这总是假定您正在读取第一张软盘(A:)。如果您想在软盘以外的引导驱动器上使用代码a:您需要删除此文件

lgdt正确吗?指定的gdt线性地址在哪里?我修改了代码,没有设置dl寄存器。在第一阶段,我将mov[0x500],dl添加到我的加载函数中。此外,我添加了mov-dl,[0x500]而不是mov-dl,00hI使用dd创建软盘映像。我使用了一个十六进制编辑器,它表明磁盘映像没有问题。非常感谢,它工作得非常好。我现在了解到第二阶段没有正确加载第三阶段,因为我没有按顺序设置寄存器。从现在起,我将不再不必要地从一个标签跳到另一个标签。“jmp Reset指令只有3个字节长。”--这是(由于优化)一个只有2个字节长的短跳转,需要将
nop
作为第3个字节,因此伪BPB从第4个字节开始。正如在另一个答案中一样,您应该使
jmp简短
并添加
nop
。我刚刚意识到这与上一个@ecm问题不同。我回家后会编辑它。@Michael Petch:你好像忘了这个,所以这里有一个提醒。@Michael Petch:你还没有更新运行中的文本,其中显示“jmp Reset指令只有3个字节长。你可以在跳转后放置一个nop,以便BPB从第4个字节开始。”
mov dl , 00h