调用内核问题程序集 x86

calling kernel promblem assembly x86

我在从名为 "stage2.bin" 的已编译二进制文件调用内核 "kernel.bin" 时遇到问题,我搞砸了使用内存位置调用内核(bootsector call stage2 at '2000h' - - 并且 stage2 在 '????h' 处调用内核)。 我使用 fat12(FileSystem),我想用保护模式调用内核! 我哪里错了?

我在 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

您认为以下代码如何建立堆栈?您正在写给 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