OS loader

0

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????

0

pewnie jak to zwykle bywa skacze nie tam gdzie powinien... zrob tak aby kod byl ladowany w pierwszy segment 16bit dzieki czemu adresy logiczny i fizyczny beda takie same, to powinno zadzialac wtedy :P

0

A jeśli mój kernel ma więcej niż jeden segment w pamięci. Te loadery, które widziałem, nie ładują plików, których rozmiar jest widziałe, nie ładują pkików większych niż ok 2KB. Mój kernel ma 7KB. Co wtedy???

0

hmm no to sprawa sie komplikuje... ja bym zrobil tak:
w asmie napisal fisrt stage loader czyli zwyklego boota ktory ładuje tzw: second stage loader czyli program ktory moze byc troche wieksszy i laduje on dopiero kernel, mozna by go s<ort>prubowac</ort> napisac w c..

PS. nie wiem skund ci sie wzielo 2kb jak funkcje biosa moga spokojnie zaladowac pojedynczy plik do segmentu o dlugosci 64kb...

0

Dzięki wszystkim. Już działa. nie długo do porbrania z <url>www.milyges.prv.pl</url>

1 użytkowników online, w tym zalogowanych: 0, gości: 1