调用内核问题程序集 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,0200h
mov es,ax
我在从名为 "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,0200h
mov es,ax