Failed to load file above 28KB in Unreal Mode
Posted: Fri Jun 19, 2015 3:07 am
I hear that Unreal Mode can access memory above 1 MB and up to 4 GB. So I try to load a 11KB image file when in Unreal Mode and then turn back to Protected Mode and display the picture to screen using VESA, and it works. But when I try to load a 198KB file, my OS goes hang and then crash. Why is that happening? Could anyone explain me why that happened and how can I access up-to 4 GB memory when in Unreal Mode?
This is the screenshot of my OS when loading the small image file.
Below is the source code.
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