2015-03-02 58 views
0

我有一個問題,從一個名爲「stage2.bin」的編譯二進制文件中調用內核「kernel.bin」,我搞砸了調用與內存位置的內核(引導程序調用stage2' 2000h' - stage2在'???? h'處調用內核)。 我使用fat12(FileSystem),我想用保護模式調用內核! 我錯在哪裏?調用內核promblem程序集x86

我使用Windows上的NASM進行編譯。

編輯:內核在'9000h'打電話!

STAGE2.BIN

[BITS 16] 
[ORG 0] 
    jmp short start 
    nop ; required nop as some BIOS'es need it 
;---------------------------------------------------------------------------- 
; BIOS PARAMETER BLOCK (definitions for protected mode) 
;---------------------------------------------------------------------------- 
; FIELD SIZE (bytes) 
    OEMLabel  db "-NETBOX-" ; Disk label 
    BytesPerSector  dw 512  ; Bytes per sector 
    SectorsPerCluster db 1  ; Sectors per cluster 
    ReservedForBoot  dw 1  ; Reserved sectors for boot record 
    NumberOfFats  db 2  ; Number of copies of the FAT 
    RootDirEntries  dw 224  ; Number of entries in root dir 
         ; (224 * 32 = 7168 = 14 sectors to read) 
    LogicalSectors  dw 2880  ; Number of logical sectors 
    MediumByte  db 0F0h  ; Medium descriptor byte 
    SectorsPerFat  dw 9  ; Sectors per FAT 
    SectorsPerTrack  dw 18  ; Sectors per track (36/cylinder) 
    Sides   dw 2  ; Number of sides/heads 
    HiddenSectors  dd 0  ; Number of hidden sectors 
    LargeSectors  dd 0  ; Number of LBA sectors 
    DriveNo   dw 0  ; Drive No: 0 
    Signature  db 41  ; Drive signature: 41 for floppy 
    VolumeID  dd 00000000h ; Volume ID: any number 
    VolumeLabel  db "NETBOX BOOT"; Volume Label: any 11 chars 
    FileSystem  db "FAT12 " ; File system type: don't change! 
;---------------------------------------------------------------------------- 
; CODE 
;---------------------------------------------------------------------------- 
; ------------------------------------------ 
; Functions used in the boot-loading process 
; ------------------------------------------ 
start: 
    cli ; diable interrupts 
    mov ax, 0x2000 
    mov ds, ax ; setup ds register 
    mov ax, 0x9000 
    mov es, ax ; setup a stack 
    mov sp, 0x2000 ; 8 kb 
    sti ; enable interrupts 
    mov [bootdev], dl ; save boot drive 
; relocate code 
    ; mov ax, 0x8000 
    ; mov es, ax 
    ; mov di, 0 ; destination address 
    ; mov si, 0 ; source address. 
    ; mov cx, 512 ; length is 512 bytes 
    ; cld ; direction forward 
    ; rep movsb ; move the boot sector 
    ; jmp 0x8000:relocation_ok ; transfer control to new location 
;--------------------------- 
; relocation_ok: 
; relocate bios data area 
    ; mov ax, 0x7000 
    ; mov es, ax 
    ; mov di, 0 ; destination 
    ; mov ax, 0x0040 
    ; mov ds, ax 
    ; mov si, 0 ; source 
    ; mov cx, 256 ; length is 256 bytes 
    ; cld ; set direction forward 
    ; rep movsb ; move bios data area 
    ; mov ax, 0x8000 
    ; mov ds, ax ; setup ds to match new location 
;--------------------------- 

; First, we need to load the root directory from the disk. Technical details: 
; Start of root = ReservedForBoot + NumberOfFats * SectorsPerFat = logical 19 
; Number of root = RootDirEntries * 32 bytes/entry/512 bytes/sector = 14 
; Start of user data = (start of root) + (number of root) = logical 33 

floppy_ok:    ; Ready to read first block of data 
    mov ax, 19   ; Root dir starts at logical sector 19 
    call l2hts 

    mov si, buffer   ; Set ES:BX to point to our buffer (see end of code) 
    mov bx, ds 
    mov es, bx 
    mov bx, si 

    mov ah, 2   ; Params for int 13h: read floppy sectors 
    mov al, 14   ; And read 14 of them 

    pusha    ; Prepare to enter loop 

pmode:   ; protected mode section 
call clear_screen 
    popa    ; In case registers are altered by int 13h 
    pusha 

    stc    ; A few BIOSes do not set properly on error 
    int 13h    ; Read sectors using BIOS 

    jnc search_dir   ; If read went OK, skip ahead 
    call reset_floppy 
    jnc pmode 
    mov si, driveerr 
    call print_string 
    hlt 
;drive_ok: 
; mov ax, 0x200 
; mov es, ax 
; mov bx, 0 ; kernel image destination 
; mov al, 1 ; read 1 sector 
; mov cl, 2 ; starting at sector 2 
; call bios_read_sectors 
search_dir: 
    popa 

    mov ax, ds   ; Root dir is now in [buffer] 
    mov es, ax   ; Set DI to this info 
    mov di, buffer 

    mov cx, word [RootDirEntries] ; Search all (224) entries 
    mov ax, 0   ; Searching at offset 0 

next_root_entry: 
    xchg cx, dx   ; We use CX in the inner loop... 

    mov si, kern_filename  ; Start searching for kernel filename 
    mov cx, 11 
    rep cmpsb 
    je found_file_to_load  ; Pointer DI will be at offset 11 

    add ax, 32   ; Bump searched entries by 1 (32 bytes per entry) 

    mov di, buffer   ; Point to next entry 
    add di, ax 

    xchg dx, cx   ; Get the original CX back 
    loop next_root_entry 

    mov si, file_not_found  ; If kernel is not found, bail out 
    call print_string 
    hlt 

found_file_to_load:   ; Fetch cluster and load FAT into RAM 
    mov ax, word [es:di+0Fh] ; Offset 11 + 15 = 26, contains 1st cluster 
    mov word [cluster], ax 

    mov ax, 1   ; Sector 1 = first sector of first FAT 
    call l2hts 

    mov di, buffer   ; ES:BX points to our buffer 
    mov bx, di 

    mov ah, 2   ; int 13h params: read (FAT) sectors 
    mov al, 9   ; All 9 sectors of 1st FAT 

    pusha    ; Prepare to enter loop 

read_fat: 
    popa    ; In case registers are altered by int 13h 
    pusha 

    stc 
    int 13h    ; Read sectors using the BIOS 

    jnc read_fat_ok   ; If read went OK, skip ahead 
    call reset_floppy  ; Otherwise, reset floppy controller and try again 
    jnc read_fat   ; Floppy reset OK? 

; ****************************************************************** 
fatal_disk_error: 
; ****************************************************************** 
    mov si, disk_error  ; If not, print error message and reboot 
    call print_string 
    hlt   ; Fatal double error 

read_fat_ok: 
    popa 

    mov ax, 2000h   ; Segment where we'll load the kernel 
    mov es, ax 
    mov bx, 0 

    mov ah, 2   ; int 13h floppy read params 
    mov al, 1 

    push ax    ; Save in case we (or int calls) lose it 


; Now we must load the FAT from the disk. Here's how we find out where it starts: 
; FAT cluster 0 = media descriptor = 0F0h 
; FAT cluster 1 = filler cluster = 0FFh 
; Cluster start = ((cluster number) - 2) * SectorsPerCluster + (start of user) 
;    = (cluster number) + 31 

load_file_sector: 
    mov ax, word [cluster]  ; Convert sector to logical 
    add ax, 31 

    call l2hts   ; Make appropriate params for int 13h 

    mov ax, 2000h   ; Set buffer past what we've already read 
    mov es, ax 
    mov bx, word [pointer] 

    pop ax    ; Save in case we (or int calls) lose it 
    push ax 

    stc 
    int 13h 

    jnc calculate_next_cluster ; If there's no error... 

    call reset_floppy  ; Otherwise, reset floppy and retry 
    jmp load_file_sector 

    ; In the FAT, cluster values are stored in 12 bits, so we have to 
    ; do a bit of maths to work out whether we're dealing with a byte 
    ; and 4 bits of the next byte -- or the last 4 bits of one byte 
    ; and then the subsequent byte! 

calculate_next_cluster: 
    mov ax, [cluster] 
    mov dx, 0 
    mov bx, 3 
    mul bx 
    mov bx, 2 
    div bx    ; DX = [cluster] mod 2 
    mov si, buffer 
    add si, ax   ; AX = word in FAT for the 12 bit entry 
    mov ax, word [ds:si] 

    or dx, dx   ; If DX = 0 [cluster] is even; if DX = 1 then it's odd 

    jz even    ; If [cluster] is even, drop last 4 bits of word 
        ; with next cluster; if odd, drop first 4 bits 

odd: 
    shr ax, 4   ; Shift out first 4 bits (they belong to another entry) 
    jmp short next_cluster_cont 


even: 
    and ax, 0FFFh   ; Mask out final 4 bits 


next_cluster_cont: 
    mov word [cluster], ax  ; Store cluster 

    cmp ax, 0FF8h   ; FF8h = end of file marker in FAT12 
    jae end 

    add word [pointer], 512  ; Increase buffer pointer 1 sector length 
    jmp load_file_sector 

end:     ; We've got the file to load! 
    pop ax    ; Clean up the stack (AX was pushed earlier) 
    mov dl, byte [bootdev]  ; Provide kernel with boot device info 

    ;jmp 2000h:0000h   ; Jump to entry point of loaded kernel! 

; ENABLE THE A20 LINE: 
; In order to use the full amount of RAM plugged in your computer you have to enable the a20 
; addressline. This can be done by enabling a line of the floppy controller. The state of this line 
; can be changed by setting the appropriate bit. This bit is the second bit of the AT keyboard 
; controller output port (port 064h). So in theory we can enable the a20 address line by simply 
; setting this second bit. 
cli ; disable interrupts 
mov bl, 0xd0 ; read current status command 
call kbd_send_ctrl_cmd 
call kbd_read_data 
or al, 2 ; set the a20 enable bit 
push ax 
mov bl, 0xd1 ; write current status command 
call kbd_send_ctrl_cmd 
pop bx 
call kbd_write_data ; write the new status 
mov bl, 0xd0 ; read current status command 
call kbd_send_ctrl_cmd 
call kbd_read_data ; read the current status 
and al, 2 
sti ; enable interrupts 
jnz a20_ok 
mov si, a20err 
call print_string 
hlt 
a20_ok: 
; setup global descriptor table 
mov ax, 0 
mov es, ax 
mov di, 0x800 ; destination 
mov si, gdt ; source 
mov cx, 24 ; length 
cld ; forward direction 
rep movsb ; move gtd to its new location 
lgdt [gdtptr] ; load gdt register 
; Disable ALL interrupts 
cli ; disable interrupts 
mov al, 11111111b ; select to mask of all IRQs 
out 0x21, al ; write it to the PIC controller 
;Disable NMI 
in al, 0x70 ; read a value 
or al, 10000000b ; set the nmi disable bit 
out 0x70, al ; write it back again 
; Enter protected mode 
mov eax, cr0 
or al, 1 ; set protected mode bit 
mov cr0, eax 
; Transfer control to kernel 
mov ax, 0x10 
mov ds, ax ; load global data selector into ds 
jmp 0x08:0x2000 ; transfer control to test kernel 
ret 
;---------------------------------------------------------------------------- 
; Functions 
;---------------------------------------------------------------------------- 
print_string:    ; Output string in SI to screen 
    pusha 

    mov ah, 0Eh   ; int 10h teletype function 

.repeat: 
    lodsb    ; Get char from string 
    cmp al, 0 
    je .done   ; If char is zero, end of string 
    int 10h    ; Otherwise, print it 
    jmp short .repeat 

.done: 
    popa 
    ret 

clear_screen: 
    mov al, 3 ; select video mode 3 - color text 
    mov ah, 0 ; set video mode function 
    int 0x10 ; call bios video services 
    ret 
reboot: 
    mov si, pm 
    call print_string 
    mov ah, 0 ; read keypress function 
    int 0x16 ; call bios keyboard services 
    jmp 0xFFFF:0x0000 

reset_floppy:  ; IN: [bootdev] = boot device; OUT: carry set on error 
    push ax 
    push dx 
    mov ax, 0 
    mov dl, byte [bootdev] 
    stc 
    int 13h 
    pop dx 
    pop ax 
    ret 

l2hts:   ; Calculate head, track and sector settings for int 13h 
      ; IN: logical sector in AX, OUT: correct registers for int 13h 
    push bx 
    push ax 

    mov bx, ax   ; Save logical sector 

    mov dx, 0   ; First the sector 
    div word [SectorsPerTrack] 
    add dl, 01h   ; Physical sectors start at 1 
    mov cl, dl   ; Sectors belong in CL for int 13h 
    mov ax, bx 

    mov dx, 0   ; Now calculate the head 
    div word [SectorsPerTrack] 
    mov dx, 0 
    div word [Sides] 
    mov dh, dl   ; Head/side 
    mov ch, al   ; Track 

    pop ax 
    pop bx 

    mov dl, byte [bootdev]  ; Set correct device 

    ret 

kbd_wait_cmd: 
    in al, 0x64 ; read the controller status port 
    and al, 2 ; check if the controller is ready 
    jnz kbd_wait_cmd ; to accept the next command (or 
    ret ; piece of data) 
kbd_wait_data: 
    in al, 0x64 ; read the controller status port 
    and al, 1 ; check if the data is ready 
    jz kbd_wait_data 
    ret 
kbd_send_ctrl_cmd: 
; input : bl = command 
    call kbd_wait_cmd 
    mov al, bl 
    out 0x64, al ; send the command to the control 
    ret ; register 
kbd_read_data: 
; output : al = data 
    call kbd_wait_data 
    in al, 0x60 ; read data from input/output port 
    ret 
kbd_write_data: 
; input bl = data 
    call kbd_wait_cmd 
    mov al, bl 
    out 0x60, al ; write data to input/output port 
    ret 
;---------------------------------------------------------------------------- 
; data 
;---------------------------------------------------------------------------- 
; messages (with carriage return and line feed and zero terminated) 
    driveerr db 'Error - Protect Mode', 0 
    pm db 'rb', 0 ; reboot message 
    a20err db 'Error - Gate A20', 0 ; A20 ERROR 
    kern_filename db "KERNEL BIN" ; MikeOS kernel filename 

    disk_error db "Floppy error! Press any key...", 0 
    file_not_found db "KERNEL.BIN not found!", 0 

    bootdev  db 0 ; Boot device number 
    cluster  dw 0 ; Cluster of the file we want to load 
    pointer  dw 0 ; Pointer into Buffer, for loading kernel 

; global descriptor table 
; null selector (required) 
gdt dw 0, 0, 0, 0 
; kernel code selector 
dw 0xffff ; segment limit (4 gb total) 
dw 0 ; base address (bits 0-15) 
db 0 ; base address (bits (16-24) 
db 10011000b ; dpl 0, code (execute only) 
db 11001111b ; granlurarity (4k), 32-bit, limit high nibble = f 
db 0 ; base address (bits 24-32) 
; kernel data selector 
dw 0xffff ; segment limit (4 gb total) 
dw 0 ; base address (bits 0-15) 
db 0 ; base address (bits (16-24) 
db 10010010b ; dpl 0, data (read/write) 
db 11001111b ; granlurarity (4k), 32-bit, limit high nibble = f 
db 0 ; base address (bits 24-32) 
gdtptr dw 0x7ff ; limit (256 slots) 
dd 0x800 ; base (physical address) 

buffer:    ; Disk buffer begins (8k after this, stack starts) 

KERNEL.BIN

[bits 32] 
[org 0x2000] 
mov ax, 0x10 
mov ds, ax 
mov es, ax 
mov esi, kernelmsg 
call pmode_print_string 
mov esi, presskeymsg 
call pmode_print_string 
dummy: 
jmp dummy 
;---------------------------------------------------------------------------- 
; function 
;---------------------------------------------------------------------------- 
xposition db 0 
yposition db 1 
pmode_print_character: 
; input al : character 
; ah : attribute 
pushad ; save registers 
cmp al, 10 ; line feed 
jnz not_line_feed 
add byte [yposition], 1 
jmp pmode_print_character_done 
not_line_feed: 
cmp al, 13 ; carriage return 
jnz not_carriage_return 
mov byte [xposition], 0 
jmp pmode_print_character_done 
not_carriage_return: 
mov ecx, eax ; save character and attribute 
mov ebx, 0 
mov bl, [xposition] 
shl bl, 1 ; calculate x offset 
mov eax, 0 
mov al, [yposition] 
mov edx, 160 
mul edx ; calculate y offset 
mov edi, 0xb8000 ; start of video memory 
add edi, eax ; add y offset 
add edi, ebx ; add x offset 
mov ax, cx ; restore character and attribute 
cld ; forward direction 
stosw ; write character and attribute 
add byte [xposition], 1 
pmode_print_character_done: 
call hardware_move_cursor 
popad ; restore registers 
ret 
pmode_print_string: 
; input ds:esi = points to zero terminated string 
lodsb 
cmp al, 0 
jz pmode_print_string_done 
mov ah, 0x0F ; white text, black background 
call pmode_print_character 
jmp pmode_print_string 
pmode_print_string_done: 
ret 
hardware_move_cursor: 
pushad ; save registers 
mov ebx, 0 
mov bl, [xposition] ; get x offset 
mov eax, 0 
mov al, [yposition] 
mov edx, 80 
mul edx ; calculate y offset 
add ebx, eax ; calculate index 
; select to write low byte of index 
mov al, 0xf 
mov dx, 0x03d4 
out dx, al 
; write it 
mov al, bl 
mov dx, 0x03d5 
out dx, al 
; select to write high byte of index 
mov al, 0xe 
mov dx, 0x03d4 
out dx, al 
; write it 
mov al, bh 
mov dx, 0x03d5 
out dx, al 
popad ; restore registers 
ret 
;---------------------------------------------------------------------------- 
; data 
;---------------------------------------------------------------------------- 
kernelmsg db 'Protected mode test kernel loaded successfully', 13, 10, 0 
presskeymsg db 'Please remove disk and reboot', 0 
+0

'我有一個problem'很少是一個很好的問題描述,請更具體。此外,這是先進的東西,你期望能夠使用調試器。 – Jester 2015-03-02 18:28:33

+0

問題是在內存中調用內核'9000h'! **調用錯誤**和**重定位代碼錯誤** – 2015-03-02 19:07:33

+0

對我來說,顯示的代碼看起來像它是從像[brokenthorn](http://www.brokenthorn.com/Resources/OSDevIndex.html)這樣的教程改編的。編寫引導程序是一項非常複雜的任務,如果沒有關於該主題的理論知識,就無法完成。如果我的假設是真的,我會建議[osdev.org](http://wiki.osdev.org/)獲取上述知識。如果我錯了,並且你自己寫了這些代碼,我很抱歉說...... – ababababanababab 2015-03-23 21:29:44

回答

0

如何你想到的是,以下代碼設置堆棧?你正在給ES寫信而不是SS!

mov ax, 0x9000 
mov es, ax ; setup a stack 
mov sp, 0x2000 ; 8 kb 

KERNEL.BIN應該是在內存地址0x2000和下一代碼加載它高得多。

mov ax, 2000h   ; Segment where we'll load the kernel 
mov es, ax 

將其更改爲mov ax,0200hmov es,ax