This is the screenshot of my OS when loading the small image file.
Below is the source code.
Code: Select all
;;;;;;;; kernel.asm ;;;;;;;;
ORG 0x500
BITS 16
start:
disk_buffer equ 24576
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0FFFFh
mov [bootdev], dl
mov ah, 8
int 13h
and cx, 3Fh
mov [SecsPerTrack], cx
movzx dx, dh
add dx, 1
mov [Sides], dx
mov ah, 4fh
mov al, 02h
mov bx, 101h
int 10h
mov ax, 4F01h
mov cx, 101h
mov di, VESAModeInfo
int 10h
in al, 0x92
or al, 2
out 0x92, al
cli
;meload table descriptor atau GDT
lgdt[gdt_descriptor]
;meng-OR cr0 dengan 1
mov eax, cr0
or eax, 1
mov cr0, eax
;lompat ke protected mode
jmp 08h:protected_mode
BITS 32
protected_mode:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0FFFFh ; stack begins from 90000h
mov eax, text1
mov ebx, 36864
call load_file_pm
mov edi, [PhysBasePtr]
mov ebp, edi
add ebp, 307201
mov si, 36864+80h
.decode:
mov cx, 1
lodsb
cmp al, 192
jb .single
and al, 63
mov cl, al
lodsb
.single:
rep stosb
cmp edi, ebp
jb .decode
.done1:
mov dx, 3c8h
mov al, 0
out dx, al
inc dx
mov cx, 768
.setpal:
lodsb
shr al, 2
out dx, al
loop .setpal
jmp $
gdt_descriptor:
dw 5*8 - 1
dd gdt_start
gdt_start:
;Null descriptor
dq 0
gdt_code_descriptor:
dw 0xffff
dw 0
db 0
db 10011010b
db 11001111b
db 0
gdt_data_descriptor:
dw 0xffff
dw 0
db 0
db 10010010b
db 11001111b
db 0
;16-bit code (0x18)
gdt_real_mode_code_descriptor:
dw 0xffff
dw 0x0000
db 0x00
db 0x9a
db 0xf
db 0x00
;16-bit data (0x20)
gdt_real_mode_data_descriptor:
dw 0xffff
dw 0x0000
db 0x00
db 0x92
db 0x0f
db 0x00
VESAModeInfo:
ModeAttributes dw 0
WinAAttributes db 0
WinBAttributes db 0
WinGranularity dw 0
WinSize dw 0
WinASegment dw 0
WinBSegment dw 0
WinFuncPtr dd 0
BytesPerScanLine dw 0
XResolution dw 0
YResolution dw 0
XCharSize db 0
YCharSize db 0
NumberOfPlanes db 0
BitsPerPixel db 0
NumberOfBanks db 0
MemoryModel db 0
BankSize db 0
NumberOfImagesPages db 0
db 1
RedMaskSize db 0
RedFieldPosition db 0
GreenMaskSize db 0
GreenFieldPosition db 0
BlueMaskSize db 0
BlueFieldPosition db 0
RsvdMaskSize db 0
RsvdFieldPosition db 0
DirectColorModeInfo db 0
PhysBasePtr dd 0
OffScreenMemOffset dd 0
OffScreenMemSize dw 0
times 206 db 0
text1 db "a.pcx", 0
%INCLUDE "function/disk.asm"
Code: Select all
;;;;;;;; disk.asm ;;;;;;;;
load_file_pm:
mov [filename], eax ;filename
mov [loadPosition], ebx ;loadPosition
jmp ready_to_move_to_real_mode
return_now:
ret
ready_to_move_to_real_mode:
jmp 0x18:move_to_real_mode
BITS 16
move_to_real_mode:
mov eax, 0x20
mov ds, eax
mov es, ax
mov fs, eax
mov gs, eax
mov ss, eax
mov eax, cr0
dec eax
mov cr0, eax
jmp 0:real_mode
BITS 16
real_mode:
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
sti
;;======16 bit code======
jmp loadfile2
ready_to_return:
jmp return_now
loadfile2:
mov eax, [filename]
mov ebx, [loadPosition]
call load_file
jmp far_skip
convert_lba_to_hts:
push bx
push ax
mov bx, ax
mov dx, 0
div word [SecsPerTrack]
add dl, 01h
mov cl, dl
mov ax, bx
mov dx, 0
div word [SecsPerTrack]
mov dx, 0
div word [Sides]
mov dh, dl
mov ch, al
pop ax
pop bx
mov dl, [bootdev]
ret
Sides dw 2
SecsPerTrack dw 18
bootdev db 0
os_string_compare:
pusha
.more:
mov al, [si] ; Retrieve string contents
mov bl, [di]
cmp al, bl ; Compare characters at current location
jne .not_same
cmp al, 0 ; End of first string? Must also be end of second
je .terminated
inc si
inc di
jmp .more
.not_same: ; If unequal lengths with same beginning, the byte
popa ; comparison fails at shortest string terminator
clc ; Clear carry flag
ret
.terminated: ; Both strings terminated at the same position
popa
stc ; Set carry flag
ret
restart:
mov ax, 0
int 19h
reset_floppy_disk:
push ax
push dx
mov ax, 0
mov dl, [bootdev]
stc
int 13h
pop dx
pop ax
ret
os_string_length:
pusha
mov bx, ax ; Move location of string to BX
mov cx, 0 ; Counter
.more:
cmp byte [bx], 0 ; Zero (end of string) yet?
je .done
inc bx ; If not, keep adding
inc cx
jmp .more
.done:
mov word [.tmp_counter], cx ; Store count before restoring other registers
popa
mov ax, [.tmp_counter] ; Put count back into AX before returning
ret
.tmp_counter dw 0
os_string_uppercase:
pusha
mov esi, eax ; Use SI to access string
.more:
cmp BYTE [esi], 0 ; Zero-termination of string?
je .done ; If so, quit
cmp BYTE [esi], 'a' ; In the lower case A to Z range?
jb .noatoz
cmp BYTE [esi], 'z'
ja .noatoz
sub BYTE [esi], 20h ; If so, convert input char to upper case
inc esi
jmp .more
.noatoz:
inc esi
jmp .more
.done:
popa
ret
int_filename_convert:
pusha
mov esi, eax
call os_string_length
cmp eax, 12 ;14 ; Filename too long?
jg .failure ; Fail if so
cmp eax, 0
je .failure ; Similarly, fail if zero-char string
mov edx, eax ; Store string length for now
mov edi, .dest_string
mov ecx, 0
.copy_loop:
lodsb
cmp al, '.'
je .extension_found
stosb
inc ecx
cmp ecx, edx
jg .failure ; No extension found = wrong
jmp .copy_loop
.extension_found:
cmp ecx, 0
je .failure ; Fail if extension dot is first char
cmp ecx, 8
je .do_extension ; Skip spaces if first bit is 8 chars
; Now it's time to pad out the rest of the first part of the filename
; with spaces, if necessary
.add_spaces:
mov BYTE [edi], ' '
inc edi
inc ecx
cmp ecx, 8
jl .add_spaces
; Finally, copy over the extension
.do_extension:
lodsb ; 3 characters
cmp al, 0
je .failure
stosb
lodsb
cmp al, 0
je .failure
stosb
lodsb
cmp al, 0
je .failure
stosb
mov BYTE [edi], 0 ; Zero-terminate filename
popa
mov eax, .dest_string
clc ; Clear carry for success
ret
.failure:
popa
stc ; Set carry for failure
ret
.dest_string: times 13 db 0
load_file:
call os_string_uppercase
call int_filename_convert
mov [.filename_loc], eax ; Store filename location
mov [.load_position], ebx ; And where to load the file!
mov eax, 0 ; Needed for some older BIOSes
call reset_floppy_disk ; In case floppy has been changed
jnc .floppy_ok ; Did the floppy reset OK?
mov eax, .err_msg_floppy_reset ; If not, bail out
jmp restart
.floppy_ok: ; Ready to read first block of data
mov eax, 19 ; Root dir starts at logical sector 19
call convert_lba_to_hts
mov ebx, disk_buffer ; ES:BX should point to our buffer
mov ah, 2 ; Params for int 13h: read floppy sectors
mov al, 14 ; 14 root directory sectors
pusha ; Prepare to enter loop
.read_root_dir:
popa
pusha
stc ; A few BIOSes clear, but don't set properly
int 13h ; Read sectors
jnc .search_root_dir ; No errors = continue
call reset_floppy_disk ; Problem = reset controller and try again
jnc .read_root_dir
popa
jmp .root_problem ; Double error = exit
.search_root_dir:
popa
mov ecx, DWORD 224 ; Search all entries in root dir
mov ebx, -32 ; Begin searching at offset 0 in root dir
.next_root_entry:
add ebx, 32 ; Bump searched entries by 1 (offset + 32 bytes)
mov edi, disk_buffer ; Point root dir at next entry
add edi, ebx
mov al, [edi] ; First character of name
cmp al, 0 ; Last file name already checked?
je .root_problem
cmp al, 229 ; Was this file deleted?
je .next_root_entry ; If yes, skip it
mov al, [edi+11] ; Get the attribute byte
cmp al, 0Fh ; Is this a special Windows entry?
je .next_root_entry
test al, 18h ; Is this a directory entry or volume label?
jnz .next_root_entry
mov BYTE [edi+11], 0 ; Add a terminator to directory name entry
mov eax, edi ; Convert root buffer name to upper case
call os_string_uppercase
mov esi, [.filename_loc] ; DS:SI = location of filename to load
call os_string_compare ; Current entry same as requested?
jc .found_file_to_load
loop .next_root_entry
.root_problem:
mov ebx, 0 ; If file not found or major disk error,
stc ; return with size = 0 and carry set
ret
.found_file_to_load: ; Now fetch cluster and load FAT into RAM
mov eax, [edi+28] ; Store file size to return to calling routine
mov DWORD [.file_size], eax
cmp eax, 0 ; If the file size is zero, don't bother trying
je .end ; to read more clusters
movzx eax, WORD [edi+26] ; Now fetch cluster and load FAT into RAM
mov DWORD [.cluster], eax
mov eax, 1 ; Sector 1 = first sector of first FAT
call convert_lba_to_hts
mov ebx, disk_buffer ; ES:BX points to our buffer
mov ah, 2 ; int 13h params: read sectors
mov al, 9 ; And read 9 of them
pusha
.read_fat:
popa ; In case registers altered by int 13h
pusha
stc
int 13h
jnc .read_fat_ok
call reset_floppy_disk
jnc .read_fat
popa
jmp .root_problem
.read_fat_ok:
popa
.load_file_sector:
mov eax, DWORD [.cluster] ; Convert sector to logical
add eax, 31
call convert_lba_to_hts ; Make appropriate params for int 13h
mov ebx, [.load_position]
mov ah, 02 ; AH = read sectors, AL = just read 1
mov al, 01
stc
int 13h
jnc .calculate_next_cluster ; If there's no error...
call reset_floppy_disk ; Otherwise, reset floppy and retry
jnc .load_file_sector
mov eax, .err_msg_floppy_reset ; Reset failed, bail out
jmp restart
.calculate_next_cluster:
mov eax, [.cluster]
mov ebx, 3
mul ebx
mov ebx, 2
div ebx ; DX = [CLUSTER] mod 2
mov esi, disk_buffer ; AX = word in FAT for the 12 bits
add esi, eax
movzx eax, WORD [esi]
or edx, edx ; If DX = 0 [CLUSTER] = even, if DX = 1 then odd
jz .even ; If [CLUSTER] = even, drop last 4 bits of word
; with next cluster; if odd, drop first 4 bits
.odd:
shr eax, 4 ; Shift out first 4 bits (belong to another entry)
jmp .calculate_cluster_cont ; Onto next sector!
.even:
and eax, 0FFFh ; Mask out top (last) 4 bits
.calculate_cluster_cont:
mov DWORD [.cluster], eax ; Store cluster
cmp eax, 0FF8h
jae .end
add DWORD [.load_position], 512
jmp .load_file_sector ; Onto next sector!
.end:
mov ebx, [.file_size] ; Get file size to pass back in BX
clc ; Carry clear = good load
ret
.bootd db 0 ; Boot device number
.cluster dd 0 ; Cluster of the file we want to load
.pointer dd 0 ; Pointer into disk_buffer, for loading 'file2load'
.filename_loc dd 0 ; Temporary store of filename location
.load_position dd 0 ; Where we'll load the file
.file_size dd 0 ; Size of the file
.string_buff: times 12 db 0 ; For size (integer) printing
.err_msg_floppy_reset db 'os_load_file: Floppy failed to reset', 0
far_skip:
cli
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x8:pmode
BITS 32
pmode:
mov ax, 0x10
mov ds, ax
jmp ready_to_return
filename dd 0 ;filename
loadPosition dd 0 ;loadPosition