无法加载我的 OS 内核

Cannot load my OS kernel

我正在尝试在 C 中开发内核。我的内核支持os显示一个非常简单的欢迎信息。我的引导加载程序的第二阶段在 0x8000 处加载内核,并将内核移动到 0x100000。我的内核由两部分组成。 third_stage.asm 调用了 os.c 中的 main 函数。问题是我不断收到 guru meditation 错误。

我的bootloader(boot)的代码可以在我之前的.

中找到

我第二阶段的代码:

  org 0x7E00
  bits 16
  ;;;;;;;;;;;;;stack;;;;;;;;;;
  Setup: 
        cli
        xor ax , ax
        mov ds , ax
        mov es , ax
        mov ax , 0x9000
        mov ss , ax
        mov sp , 0x0000
        sti
 ;;;;;;;;;;;;;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]
    ;;;;;;;;;;;;A20;;;;;;;;;;;;;;;
    A20:
         mov ax , 0x2401
         int 0x15
         jc A20
    ;;;;;;;;;;;;;floppy;;;;;;;;;;;
    Reset:
          mov ah , 00h
          mov dl , [0x500]
          int 13h
          jc Reset
    Read:
          mov ax , 0x800 
          mov es , ax       ; Setup ES=0x800
          mov ah , 02h      ; Setup AH
          mov al , 0fh      ; Setup AL
          mov ch , 00h
          mov cl , 03h
          mov dh , 00h
          mov dl , [0x500]
          xor bx , bx
          int 13h
          jc Read
   Begin:  
           mov ah , 09h
           mov al , 'G'
           mov bh , 00h
           mov bl , 0x0F
           mov cx , 01h
           int 10h
   ;;;;;;;;;;;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' 
           CopyImage: 
                            mov eax , dword 0x0f
                            mov ebx , dword 0x200
                            mul ebx
                            mov ebx , 4
                            div ebx
                            cld
                            mov esi , 0x8000
                            mov edi , 0x100000
                            mov ecx , eax
                            rep movsd
                            jmp 0x100000  
          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
           times 512-($-$$) db 0

third_stage的代码:

bits 32
global _start
extern main
_start:
       mov ax , 0x10
       mov ds , ax
       mov ss, ax
       mov es, ax
       mov esp, 90000h
       mov [0xB8002], word 0x0F58   ; Print 'X'
       call main      
       hlt   

os.c的代码:

//reserved - 0x500(drive number), 0x501(keyboard buffer), 0x502(screen X) , 0x503(screen y) 
volatile char * buffer = (volatile char*)0x501 ;
volatile char * x = (volatile char*)0x502 ;
volatile char * y = (volatile char*)0x503 ;
void newline() {
if(*y < 24) {
*y++ ;
*x = 0 ;
}
else {
*y = 25 ;
*x = 80 ;
}
}
void clrscr() {
volatile char * display = (volatile char*)0xb8000 ; 
for(display = 0xb8000 ; display <= 0xbffff;display++) {
*display = 0  ;
} 
}
 void println(char output[]) {
 char * x = (char*)0x502 ;
 char * y = (char*)0x503 ;
 int arg = 0 ;
 if(*x == 80 && *y == 25) {
 clrscr() ;
 *x = 0 ;
 *y = 0 ;
 }
 volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
 while(output[arg] != '[=13=]') {
  if(*x == 80 && *y == 25) {
  clrscr() ;
   *x = 0 ;
   *y = 0 ;
    arg = 0 ;
    display = 0xb8000 ;
 }
   else if(*x == 80) {
   *y++ ;
   *x = 0 ;
    }
   *display = output[arg] ;
    display++ ;
   *display = 0x0f ;
    display++ ;
    arg++ ;
    *x++ ;
    }
    newline() ; 
    }
    void print(char output[]) {
    int arg = 0 ;
    if(*x == 80 && *y == 25) {
    clrscr() ;
    *x = 0 ;
    *y = 0 ;
    }
    volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
   while(output[arg] != '[=13=]') {
   if(*x == 80 && *y == 25) {
   clrscr() ;
   *x = 0 ;
   *y = 0 ;
   arg = 0 ;
   display = 0xb8000 ; 
   }
   else if(*x == 80) {
   *y++ ;
   *x = 0 ;
   }
   *display = output[arg] ;
    display++ ;
   *display = 0x0f ;
    display++ ;
    arg++ ;
    *x++ ;
  } 
  }
  void printc(char output) {
   char * x = (char*)0x502 ;
   char * y = (char*)0x503 ;
   if(*x == 80 && *y == 25) {
   clrscr() ;
    *x = 0 ;
    *y = 0 ;
    }
     else if(*x == 80) {
     *y++ ;
     *x = 0 ;
    }
    volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
    *display = output ;
     display++ ;
    *display = 0x0f ;
     display++ ;
     *x++ ;
     if(*x == 80) {
     *y++ ;
     *x = 0 ;
     }
     }
     void backspace() {
     if(*x == 0 && *y == 0) {

     }
     else if(*x == 0) {
     *x = 79 ;
     *y-- ;
      volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
      *display = 0 ;
       display++ ;
      *display = 0 ;
     }
      else {
      *x-- ;
      volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
      *display = 0 ;
       display++ ;
       *display = 0 ;
     }
     }
     char * scanln() {
     static char input[512] ;
     char scancode[0xd9] ;
     char shift_scancode[0xd9] ;
     *buffer = 0 ;
      int arg = 0 ;
      scancode[0x1c] = 'a' ;
      scancode[0x32] = 'b' ;
      scancode[0x21] = 'c' ;
      scancode[0x23] = 'd' ;
      scancode[0x24] = 'e' ;
      scancode[0x2b] = 'f' ;
      scancode[0x34] = 'g' ;
      scancode[0x33] = 'h' ;
      scancode[0x43] = 'i' ;
      scancode[0x3b] = 'j' ;
      scancode[0x42] = 'k' ;
      scancode[0x4b] = 'l' ;
      scancode[0x3a] = 'm' ;
      scancode[0x31] = 'n' ;
      scancode[0x44] = 'o' ;
      scancode[0x4d] = 'p' ;
      scancode[0x15] = 'q' ;
      scancode[0x2d] = 'r' ;
      scancode[0x1b] = 's' ;
      scancode[0x2c] = 't' ;
      scancode[0x3c] = 'u' ;
      scancode[0x2a] = 'v' ;
      scancode[0x1d] = 'w' ;
      scancode[0x22] = 'x' ;
      scancode[0x35] = 'y' ;
      scancode[0x1a] = 'z' ;
      scancode[0x45] = '0' ;
      scancode[0x16] = '1' ;
      scancode[0x1e] = '2' ; 
      scancode[0x26] = '3' ;
      scancode[0x25] = '4' ;
      scancode[0x2e] = '5' ;
      scancode[0x36] = '6' ;
      scancode[0x3d] = '7' ;
      scancode[0x3e] = '8' ;
      scancode[0x46] = '9' ;
      scancode[0x0e] = '`' ;
      scancode[0x4e] = '-' ;
      scancode[0x55] = '=' ;
      scancode[0x5d] = '\' ;
      scancode[0x54] = '[' ;
      scancode[0x5b] = ']' ;
      scancode[0x4c] = ';' ;
      scancode[0x52] = '\'' ;
      scancode[0x41] = ',' ;
      scancode[0x49] = '.' ;
      scancode[0x4a] = '/' ;
      scancode[0x29] = ' ' ;
      shift_scancode[0x1c] = 'A' ;
      shift_scancode[0x32] = 'B' ;
      shift_scancode[0x21] = 'C' ;
      shift_scancode[0x23] = 'D' ;
      shift_scancode[0x24] = 'E' ;
      shift_scancode[0x2b] = 'F' ;
      shift_scancode[0x34] = 'G' ;
      shift_scancode[0x33] = 'H' ;
      shift_scancode[0x43] = 'I' ;
      shift_scancode[0x3b] = 'J' ;
      shift_scancode[0x42] = 'K' ;
      shift_scancode[0x4b] = 'L' ;
      shift_scancode[0x3a] = 'M' ;
      shift_scancode[0x31] = 'N' ;
       shift_scancode[0x44] = 'O' ;
      shift_scancode[0x4d] = 'P' ;
      shift_scancode[0x15] = 'Q' ;
      shift_scancode[0x2d] = 'R' ;
      shift_scancode[0x1b] = 'S' ;
      shift_scancode[0x2c] = 'T' ;
      shift_scancode[0x3c] = 'U' ;
      shift_scancode[0x2a] = 'V' ;
       shift_scancode[0x1d] = 'W' ;
      shift_scancode[0x22] = 'X' ;
      shift_scancode[0x35] = 'Y' ;
      shift_scancode[0x1a] = 'Z' ;
      shift_scancode[0x45] = ')' ;
      shift_scancode[0x16] = '!' ;
      shift_scancode[0x1e] = '@' ;
      shift_scancode[0x26] = '#' ;
      shift_scancode[0x25] = '$' ;
      shift_scancode[0x2e] = '%' ;
      shift_scancode[0x36] = '^' ;
      shift_scancode[0x3d] = '&' ;
      shift_scancode[0x3e] = '*' ;
      shift_scancode[0x46] = '(' ;
      shift_scancode[0x0e] = '~' ;
      shift_scancode[0x4e] = '_' ;
       shift_scancode[0x55] = '+' ;
      shift_scancode[0x5d] = '|' ;
      shift_scancode[0x54] = '{' ;
       shift_scancode[0x5b] = '}' ;
      shift_scancode[0x4c] = ':' ;
      shift_scancode[0x52] = '"' ;
      shift_scancode[0x41] = '<' ;
      shift_scancode[0x49] = '>' ;
       shift_scancode[0x4a] = '?' ;
      shift_scancode[0x29] = ' ' ;
      while(*buffer != 0x5a) {
      if(*buffer == 0x12) {
       *buffer = 0 ;
      if(shift_scancode[(int)*buffer] != 0) {
      input[arg] = shift_scancode[(int)*buffer] ;
      printc(shift_scancode[(int)*buffer]) ;
      *buffer = 0  ;
      arg++ ;
    }
    if(*buffer == 0xf0) {
    *buffer = 0 ;
    *buffer = 0 ;
   } 
   }
    else if(*buffer == 0xf0) {
    *buffer = 0 ;
     *buffer = 0 ;
   }
   else if(*buffer == 0x66) {
   arg-- ;
   if(arg >= 0) {
    backspace() ;
    }
     else {
     arg = 0 ;
    }
    }
    else if(scancode[(int)*buffer] != 0) {
    input[arg] = scancode[(int)*buffer] ;
     printc(scancode[(int)*buffer]) ;
    *buffer = 0 ;
     arg++ ;
    }
    }
    input[arg] = '[=13=]' ;
    *buffer = 0 ;
    *buffer = 0 ;
     return input ;
    }
    void main() {
    char * x = (char*)0x502 ;
    char * y = (char*)0x503 ;
    *x = 0 ;
    *y = 0 ;
    println("------------------------------Welcome to Skull OS------------------------------") ;
    println("Boot Successful") ;
   }      

用于制作 os 的命令是:

nasm third_stage.asm -f elf -o third_stage.o
gcc -m32 -ffreestanding -c os.c -o os.o
ld -m elf_i386 -o os.bin -Ttext 0x100000 os.o third_stage.o --oformat binary
dd seek=0 if=boot of=os.img
dd seek=1 if=second_stage of=os.img
dd seek=2 if=os.bin of=os.img
dd seek=17 if=/dev/zero of=os.img count=1 bs=512

一开始我试图在 0x8000 加载我的 OS 但执行只是中途停止。我的 OS 正在 VirtualBox 下进行测试。

第 2 阶段的一个潜在问题是这段代码:

       CopyImage: 
                        mov eax , dword 0x0f
                        mov ebx , dword 0x200
                        mul ebx
                        mov ebx , 4
                        div ebx

DIV EBXEDX:EAX 中的 64 位整数除以 EBX。您没有正确初始化 EDXEDXEDX:EAX 中 64 位数字的高 32 位,所以你可能想要将 EDX 设置为 0。您可以在计算 EAX 的值后通过添加 xor edx, edx 指令来修复它。这会将零置入 EDX。所以代码可能如下所示:

       CopyImage: 
                        mov eax , dword 0x0f
                        mov ebx , dword 0x200
                        mul ebx
                        xor edx, edx                   ; zero extend EAX into EDX
                        mov ebx , 4
                        div ebx

而不是使用 DIV 你可以将 EAX 向右移动 2 位,这与除法相同4. 像 shr eax, 2 这样的命令会起作用。但这一切都太过分了。汇编器可以在汇编时计算这个值。上面的所有代码都可以简化为这条指令:

                        mov eax, (0x0f * 0x200)/4

这会将值 0x780 移动到 EAX.


我认为你更大的问题之一是你如何 link 你的内核到 os.bin。你这样做:

ld -m elf_i386 -o os.bin -Ttext 0x100000 os.o third_stage.o --oformat binary

不幸的是,当使用 --oformat binary 时,_start 标签将不会用于确定出现在最终二进制文件中的第一条指令。同样,对象将按照它们出现的顺序由 LD 处理。在您的情况下,os.o third_stage.o 会将 os.o 中的代码放在二进制文件中 third_stage.o 中的代码之前。您需要 third_stage.o 中的代码首先出现,因为这些是您要在 0x100000 处加载的指令。你应该这样做:

ld -m elf_i386 -o os.bin -Ttext 0x100000 third_stage.o os.o --oformat binary

此错误似乎与 VirtualBox 的 Guru Meditation 错误有关。如果没有这个修复,我可以重现错误,并且通过修复内核确实加载并说它是一个成功的引导。