Mam problem. Napisałem sobie taki prosty OS loader, który ma zaladować 32-bitowy kernel, wejść w PMODE i skoczyć do niego. Oto jego kod:
; INIT MILYGES OS
InitAdress EQU 0x800
InitSegment EQU 0x80
KernelAdress EQU 0x19000
KernelSegment EQU 0x9000
RootDirOffset EQU 0xC800
FATOffset EQU 0x7800
%macro prologue 1
push ebp
push bp
mov ebp,esp
sub esp,%1
%endmacro
%macro epilogue 0
mov esp,ebp
pop bp
pop ebp
%endmacro
%macro MoveData 5
push dword %1
push dword %2
push dword %3
push dword %4
push dword %5
call _MoveData
add esp, 20
%endmacro
%macro Mul16EAX 1
push edx
mul %1
xchg eax,edx ; now moving the MSB in dx to eax
shl eax,16
mov ax,dx
pop edx
%endm
%macro Mul32EAX 1
push edx
mul %1
xchg eax,edx ; now moving the MSB in dx to eax
shl eax,16
mov ax,dx
pop edx
%endm
;input Dividend , divisor
;output : quotient - ax , modulo - dx
%macro Div32EAX 2
push ecx
mov eax, %1
mov edx, %1
shr edx, 16
mov ecx, %2
div cx
pop ecx
%endm
; INIT CODE
[BITS 16]
[ORG 0x0000]
jmp main16
[BITS 32]
[SECTION .data] ;32-bit data
;=====================================================
;Global Descriptor Table
;=====================================================
gdt_descr:
dw 256*8-1
dd _gdt
GLOBAL _gdt
_gdt:
dd 0,0
dd 0x0000FFFF,0x00CF9A00
dd 0x0000FFFF,0x00CF9200
dd 0,0
times 254 dd 0,0
;=====================================================
;Interrupt Descriptor Table
;=====================================================
idt_descr:
dw 256*8-1
dd _idt
GLOBAL _idt
_idt:
times 256 dd 0,0
[BITS 16]
main16:
CLI
MOV AX, InitSegment
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
; Create stack
MOV AX, 0x0000
MOV SS, AX
MOV SP, 0xFFFF
;loading orig boot parameters from 0x7C00
push ds
mov cx,62
mov ax,7c0h
mov ds,ax
mov di,OEM_ID
mov si,3
cld
rep movsb
pop ds
STI
MOV BX, msg_intro
CALL print
MOV BX, msg_linea20
CALL print
CALL setup_a20
MOV BX, msg_ok
CALL print
xor eax, eax
mov al, byte [SectorsPerCluster] ;size of cluster
Mul16EAX word [BytesPerSector]
mov word [BytesPerCluster], ax
MOV BX, msg_loading
CALL print
;=======================================================================
;LOAD KERNEL TO MEMORY
;=======================================================================
LOAD_ROOT:
;compute size of root directory and store in ?cx?
xor cx, cx
xor dx, dx
mov ax, 0x0020 ; 32 byte directory entry
mul WORD [MaxRootEntries] ; total size of directory
div WORD [BytesPerSector] ; sectors used by directory
xchg ax, cx
;compute location of root directory and store in ?ax?
mov al, BYTE [TotalFATs] ; number of FATs
mul WORD [SectorsPerFAT] ; sectors used by FATs
add ax, WORD [ReservedSectors] ; adjust for bootsector
mov WORD [datasector], ax ; base of root directory
add WORD [datasector], cx
;read root directory into memory
mov bx, RootDirOffset ; copy root dir above code
call ReadSectors
;browse root directory for binary image
mov cx, WORD [MaxRootEntries] ; load loop counter
mov di, RootDirOffset ; locate first root entry
.LOOP:
push cx
push di
mov cx, 0x000B ; eleven character name
mov si, ImageName ; image name to find
rep cmpsb ; test for entry match
pop di
pop cx
je LOAD_FAT
add di, 0x0020 ; queue next directory entry
loop .LOOP
jmp FAILURE
LOAD_FAT:
mov eax, dword [di + 0x001c] ; file size
mov [FileSize], eax
mov dx, WORD [di + 0x001A]
mov WORD [cluster], dx ; file?s first cluster
;compute size of FAT and store in ?cx?
xor ax, ax
mov al, BYTE [TotalFATs] ; number of FATs
mul WORD [SectorsPerFAT] ; sectors used by FATs
mov cx, ax
;compute location of FAT and store in ?ax?
mov ax, WORD [ReservedSectors] ; adjust for bootsector
;read FAT into memory
mov bx, FATOffset ; copy FAT above bootcode
call ReadSectors
;------------------Reading Kernel DLL into memory------------------
mov ax, KernelSegment ; destination of image CS
mov es, ax
mov bx, 0x0000 ; destination for image IP
push bx
mov byte [ShowProgress],1
LOAD_IMAGE:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call ClusterLBA ; convert cluster to LBA
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; sectors to read
call ReadSectors
cmp bx, 1024 ; Segment override (64kb)
jne .SegmentOk
mov ax, es ; next segment ( add 64)
add ax, 64
mov es, ax
mov bx, 0
.SegmentOk:
push bx ;compute next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 0x0001 ;
;divide by two
add cx, dx ; sum for (3/2)
mov bx, FATOffset ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 0x0001
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high twelve bits
.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file
jb LOAD_IMAGE
JMP DONE
;ON ERROR
FAILURE:
MOV BX, msg_error
CALL print
MOV BX, msg_reboot
CALL print
MOV AX, 10H
INT 16H
INT 19H
;=======================================================================
;Exec Kernel
;=======================================================================
DONE:
MOV BX, msg_ok
CALL print
MOV BX, msg_gdt
CALL print
LGDT [gdt_descr]
MOV BX, msg_ok
CALL print
MOV BX, msg_idt
CALL print
MOV BX, msg_ok
CALL print
CLI
LIDT [idt_descr]
MOV EAX, CR0
OR EAX, 1
MOV CR0, EAX
PUSH 0x0000
PUSH dword KernelAdress
RETF
;===============================================================
; PROCEDURES
;===============================================================
;*************************************************************************
; PROCEDURE ReadSectors
; reads ?cx? sectors from disk starting at ?ax? into
;memory location ?es:bx?
;*************************************************************************
ReadSectors:
.MAIN:
mov di, 0x0005 ; five retries for error
.SECTORLOOP:
push ax
push bx
push cx
call LBACHS
mov ah, 0x02 ; BIOS read sector
mov al, 0x01 ; read one sector
mov ch, BYTE [absoluteTrack] ; track
mov cl, BYTE [absoluteSector] ; sector
mov dh, BYTE [absoluteHead] ; head
mov dl, BYTE [DriveNumber] ; drive
int 0x13 ; invoke BIOS
jnc .SUCCESS ; test for read error
xor ax, ax ; BIOS reset disk
int 0x13 ; invoke BIOS
dec di ; decrement error counter
pop cx
pop bx
pop ax
jnz .SECTORLOOP ; attempt to read again
int 0x18
.SUCCESS:
cmp byte [ShowProgress],0
je .PROGRESSDONE
mov bx, msg_process
call print
.PROGRESSDONE:
pop cx
pop bx
pop ax
add bx, WORD [BytesPerSector] ; queue next buffer
inc ax ; queue next sector
loop .MAIN ; read next sector
ret
;
;
;
; PutI2- Recursive routine to actually print the value in AX as an integer.
;
Puti2:
push dx
mov bx, 10
xor dx, dx
div bx
or ax, ax ;See if ax=0
jz .Done
push dx
call Puti2
pop dx
.Done:
mov al, dl
or al, '0'
mov byte [si], al
inc si
pop dx
ret
;*************************************************************************
; PROCEDURE ClusterLBA
; convert FAT cluster into LBA addressing scheme
; LBA = (cluster - 2) * sectors per cluster
;*************************************************************************
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
;*************************************************************************
; PROCEDURE LBACHS
; convert ?ax? LBA addressing scheme to CHS addressing scheme
; absolute sector = (logical sector / sectors per track) + 1
; absolute head = (logical sector / sectors per track) MOD number of heads
; absolute track = logical sector / (sectors per track * number of heads)
;*************************************************************************
LBACHS:
xor dx, dx ; prepare dx:ax for operation
div WORD [SectorsPerTrack] ; calculate
inc dl ; adjust for sector 0
mov BYTE [absoluteSector], dl
xor dx, dx ; prepare dx:ax for operation
div WORD [NumHeads] ; calculate
mov BYTE [absoluteHead], dl
mov BYTE [absoluteTrack], al
ret
;*************************************************************************
;print TEXT
print: ;BX - pointer to text
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AH, 0x0E
print_loop:
MOV AL, [BX]
CMP AL, 0x00
JE print_end
INC BX
PUSH BX
MOV BH, 0x00
MOV BL, 0x07
INT 10H
POP BX
JMP print_loop
print_end:
POP DX
POP CX
POP BX
POP AX
RET
;UNLOCK A20 LINE
setup_a20:
CALL empty_8042
MOV AL, 0xD1
OUT 0x64, AL
CALL empty_8042
MOV AL, 0xDF
OUT 0x60, AL
CALL empty_8042
JMP setup_a20_end
empty_8042:
DW 0xEB, 0xEB
IN AL, 0x64
TEST AL, 2
JNZ empty_8042
RET
setup_a20_end:
RET
;16-BIT DATA
absoluteSector db 0x00
absoluteHead db 0x00
absoluteTrack db 0x00
datasector dw 0x0000
cluster dw 0x0000
ImageName db "KERNEL SYS"
msg_intro db 10,13,"MILYGES OS INIT v1.0",10,13,0
msg_linea20 db "Unloking line A20..........",0
msg_loading db "Loading kernel",0
msg_gdt db "Loading GDT................",0
msg_idt db "Loading IDT................",0
msg_execkernel db "Starting kernel............",10,13,0
msg_ok db "OK",10,13,0
msg_error db "ERROR",10,13,0
msg_reboot db 10,13,10,13,"Press any key to reboot...",10,13,0
msg_process db ".",0
ShowProgress db 1
FileSize dd 0
ReadFileSize dd 0
BytesPerCluster dw 0
Buffer db " ",0
OEM_ID db "MILYGES "
BytesPerSector dw 0x0200
SectorsPerCluster db 0x01
ReservedSectors dw 0x0001
TotalFATs db 0x02
MaxRootEntries dw 0x00E0
TotalSectorsSmall dw 0x0B40
MediaDescriptor db 0xF0
SectorsPerFAT dw 0x0009
SectorsPerTrack dw 0x0012
NumHeads dw 0x0002
HiddenSectors dd 0x00000000
TotalSectorsLarge dd 0x00000000
DriveNumber db 0x00
Flags db 0x00
Signature db 0x29
VolumeID dd 0xFFFFFFFF
VolumeLabel db "MILYGES OS "
SystemID db "FAT12 "
Moje pytanie brzmi: Dlaczego podczas skoku do punkty wejścia kernela komputer się restartuje????