Failed to load file above 28KB in Unreal Mode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
danasap90
Posts: 3
Joined: Fri Jun 19, 2015 1:48 am

Failed to load file above 28KB in Unreal Mode

Post by danasap90 »

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.

Image

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
Attachments
smallfile.zip
(11.38 KiB) Downloaded 61 times
bigfile.zip
(15.5 KiB) Downloaded 32 times
Last edited by danasap90 on Fri Jun 19, 2015 4:18 am, edited 2 times in total.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Failed to load file above 28KB in Unreal Mode

Post by Brendan »

Hi,

To enable unreal mode; you enable protected mode very briefly and load one or maybe more data segment registers so that it's limit is 4 GiB, then disable protected mode and load the same segment registers/s with values that are sane for real mode (which doesn't change the existing 4 GiB limit); maybe like this:

Code: Select all

    lgdt [something]  ;Load a GDT with something
    mov cx,0x0010     ;cx = GDT entry for 4 GiB data segment
    mov eax,cr0       ;eax = original CR0
    lea ebx,[eax+1]   ;ebx = original CR0 with "protected mode enable" bit set
    xor dx,dx         ;dx = 0

    cli
    mov cr0,ebx       ;Enable protected mode
    jmp .flush1       ;Flush CPU's pipeline (for old CPUs)
.flush1:
    mov es,cx         ;Change ES limit to 4 GiB
    mov cr0,eax       ;Disable protected mode
    jmp .flush2       ;Flush CPU's pipeline (for old CPUs)
.flush2:
    mov es,dx         ;Load 0x0000 into ES so it's sane for real mode (without effecting its 4 GiB limit)
    sti
There's no reason to touch CS or switch to 32-bit code; and you definitely do not want to jump to a jump that jumps to a return that returns to 16 bit code while CPU is still expecting 32-bit code.

Also note that just because you're in unreal mode doesn't mean the BIOS knows or cares, and doesn't mean the BIOS is capable of loading data above 1 MiB. For example, the BIOS might get the value you left in ES and do "address_for_DMA = ES << 4 + BX" (where ES limit and the highest 16 bits of EBX are completely ignored for this calculation) and setup a DMA transfer. You still have to load data below 1 MiB and then (using unreal mode) copy that data elsewhere.

Finally; while it is normally safe to assume BIOS won't "unset" or interfere with your unreal mode segments after you've set it up (mostly because "plain vanilla BIOS" is designed to run in both real mode and virtual8086 mode) it is possible for various hacks (e.g. something that ran before your boot code that hooked "int 0x13" and uses network to emulate a disk) to mess things up. For this reason you should switch to unreal mode immediately before using it or immediately after using BIOS (just to make extra sure).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Failed to load file above 28KB in Unreal Mode

Post by Octocontrabass »

Your code has many, many bugs.

I will focus on the one you asked about.
danasap90 wrote:

Code: Select all

mov ebx, 36864
call load_file_pm

Code: Select all

  mov ebx, [.load_position]
  mov ah, 02                            ; AH = read sectors, AL = just read 1
  mov al, 01
  stc
  int 13h

Code: Select all

  add DWORD [.load_position], 512
The BIOS function uses BX, not EBX.

What will BX be when EBX is 65536?
danasap90
Posts: 3
Joined: Fri Jun 19, 2015 1:48 am

Re: Failed to load file above 28KB in Unreal Mode

Post by danasap90 »

Thanks Brendan and Octocontrabass, but I've found a new way to allow a file with size above 28KB to be loaded by using ATA.

Below is the screenshot of my OS:

Image

Below is the code:

Code: Select all

;;;;;;; kernel.asm ;;;;;;;;
ORG 0x500

BITS 16

start:

mov ax, 0
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0FFFFh

mov [bootdev], dl
push es
mov ah, 8
int 13h
pop es
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
lgdt[gdt_descriptor]
mov eax, cr0
or eax, 1
mov cr0, eax

jmp 0x8:pmode

BITS 32

pmode:

mov eax, 0x10
mov ds, eax
mov fs, eax
mov es, ax
mov gs, eax
mov ss, eax
mov sp, 0FFFFh

mov ax, text1
mov ebx, 100000
call load_file_pm

mov edi, [PhysBasePtr]
mov ebp, edi
add ebp, 307201
mov esi, 100000+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 $

gambar_persegi:
pusha
mov [.x], eax
mov [.y], ebx
mov [.width], ecx
mov [.height], edx
mov eax, esi
call convert_15
mov [.color], eax
mov eax, [.y]
mov ebx, 2
mov edx, 0
div ebx
mov [.y], eax
mov eax, [.x]
mov ebx, 2
mov edx, 0
div ebx
mov [.x], eax
mov eax, [.x]
mov ebx, [.y]
call get_offset
mov ecx, [.color]
mov edx, 0
mov ebp, 0
.loop1:
cmp edx, [.height]
je .done1
pusha
mov edi, [PhysBasePtr]
add edi, eax
mov eax, [.color]
mov ecx, [.width]
rep stosw
popa
add edx, 1
add eax, 1600
jmp .loop1
.done1:
popa
ret

.x dd 0
.y dd 0
.width dd 0
.height dd 0
.color dd 0
.a dd 0
.b dd 0

;convert 24-bit RGB color 8-bit RGB color
convert_8:
xor edx, edx
mov [.color], eax
shr eax, 16
and eax, 0xff
mov ebx, 6
mul ebx
mov ebx, 256
div ebx
mov ebx, 36
mul ebx
mov [.red], eax
mov eax, [.color]
shr eax, 8
and eax, 0xff
mov ebx, 6
mul ebx
mov ebx, 256
div ebx
mov ebx, 6
mul ebx
mov [.green], eax
mov eax, [.color]
and eax, 0xff
mov ebx, 6
mul ebx
mov ebx, 256
div ebx
mov [.blue], eax
mov eax, [.red]
mov ebx, [.green]
add eax, ebx
mov ebx, [.blue]
add eax, ebx
mov [.color], eax
mov eax, [.color]
ret

.color dd 0
.red dw 0
.green dw 0
.blue dw 0

;convert 24-bit RGB color 15-bit RGB color
convert_15:
xor edx, edx
mov [.color], eax
shr eax, 16
and eax, 0xff
mov ebx, 8
div ebx
mov ebx, 1024
mul ebx
mov [.red], eax
mov eax, [.color]
shr eax, 8
and eax, 0xff
mov ebx, 8
div ebx
mov ebx, 32
mul ebx
mov [.green], eax
mov eax, [.color]
and eax, 0xff
mov ebx, 8
div ebx
mov [.blue], eax
mov eax, [.red]
mov ebx, [.green]
add eax, ebx
mov ebx, [.blue]
add eax, ebx
mov [.color], eax
mov eax, [.color]
ret

.color dd 0
.red dw 0
.green dw 0
.blue dw 0

gambar_garis:
pusha
mov [.x1], eax
mov [.y1], ebx
mov [.x2], ecx
mov [.y2], edx
mov [.color], esi
mov eax, [.x2]
mov ebx, [.x1]
sub eax, ebx
mov [.dx], eax
mov ebx, 2
mul ebx
mov [.2dx], eax
mov eax, [.y2]
mov ebx, [.y1]
sub eax, ebx
mov [.dy], eax
mov ebx, 2
mul ebx
mov [.2dy], eax
mov eax, [.2dy]
mov ebx, [.2dx]
sub eax, ebx
mov [.a], eax
mov eax, [.x1]
mov ebx, 2
mov edx, 0
div ebx
push eax
mov eax, [.y1]
mov ebx, 2
mov edx, 0
div ebx
mov ebx, eax
pop eax
mov ecx, [.color]
call get_offset
call put_pixel
mov [.b], eax
mov ebp, 0
mov eax, [.2dy] ;2∆y
mov ebx, [.dx] ;∆x
sub eax, ebx
.f1:
cmp ebp, [.dx] ;∆x
je .done1
cmp eax, 0
jl .f2
mov ebx, [.a] ;2∆y-2∆x
add eax, ebx
push eax
mov eax, [.b]
add eax, 2
add eax, 1600
call put_pixel
mov [.b], eax
pop eax
add ebp, 1
jmp .f1

.f2:
mov ebx, [.2dy] ;2∆y
add eax, ebx
push eax
mov eax, [.b]
add eax, 2
call put_pixel
mov [.b], eax
pop eax
add ebp, 1
jmp .f1

.done1:
popa
ret

.color dd 0
.x1 dd 0
.y1 dd 0
.x2 dd 0
.y2 dd 0
.dx dd 0
.dy dd 0
.2dy dd 0
.2dx dd 0
.a dd 0 ;2∆y-2∆x
.pK dd 0
.b dd 0 ;variabel untuk menyimpan posisi pixel

put_pixel:
pusha
mov [.x], eax
mov [.y], ebx
mov [.color], ecx
mov ebx, [.x]
mov eax, [.color]
mov ecx, 1
mov edi, [PhysBasePtr]
add edi, ebx
rep stosw
popa
ret

.x dd 0
.y dd 0
.color dd 0

get_offset:
pusha
mov [.x], eax
mov [.y], ebx
mov [.color], ecx
mov eax, 800
mov ebx, [.y]
mul ebx
mov ebx, [.x]
add eax, ebx
mov ebx, 4
mul ebx
mov [.x], eax
popa
mov eax, [.x]
ret

.x dd 0
.y dd 0
.color dd 0

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 "library/disk.asm"

Code: Select all

;;;;;;;;;;;; disk.asm ;;;;;;;;;;;;
load_file_pm:
pusha
mov [.text1], ax
mov [.loadPosition], ebx
mov eax, 19
mov cl, 14
mov edi, 24576
call ata_lba_read
mov edi, 24576
mov ax, 0
xor dx, dx
mov cx, 224
.loop1:
xchg dx, cx
mov si, [.text1]
mov cx, 11
rep cmpsb
je .done1
add ax, 32
mov edi, 24576
add di, ax
xchg dx, cx
loop .loop1
clc
popa
ret
.done1:
sub di, 11
mov ax, word [es:di+26]
mov word [.cluster], ax
mov ax, word [es:di+28]
mov word [.fileSize], ax
mov eax, 1
mov cl, 9
mov edi, 24576
call ata_lba_read
.load_file_sector:
mov ax, [.cluster]
add ax, 31
movzx eax, ax
mov cl, 1
mov edi, 40000
call ata_lba_read
mov esi, 40000
mov edi, [.loadPosition]
add edi, dword [.file_pointer]
mov cx, 512
a32 rep movsb
mov ax, [.cluster]
mov bx, 3
mul bx
xor dx, dx
mov bx, 2
div bx
mov si, 24576
add si, ax
mov ax, word [ds:si]
or dx, dx
jz .even
.odd:
shr ax, 4
jmp .f1
.even:
and ax, 0FFFh
.f1:
mov word [.cluster], ax
cmp ax, 0FF8h
jae .done
add word [.pointer], 1
add dword [.file_pointer], 512
jmp .load_file_sector
.done:
mov bx, word [.fileSize]
popa
stc
ret

.text1 dw 0
.loadPosition dd 0
.pointer dw 0
.file_pointer dd 0
.cluster dw 0
.fileSize dw 0

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

%INCLUDE "library/pio_mode_function.asm"

Code: Select all

;;;;;;;;;;; pio_mode_function.asm ;;;;;;;;;;;
;@param DH = Head
;@param BH = Sector Count
;@param CL = Sector Index
;@param CH = Cylinder low 8-bits number
;@param BL = Cylinder high 8-bits number
;@param EDI = The address of buffer
ata_chs_read:
pusha
mov [.head], dh
mov [.cylinder1], ch
mov [.cylinder2], bl
mov [.sectorCount], bh
mov [.sectorIndex], cl
push eax
push ebx
push ecx
push edx
push edi
mov edx, 1f6h
mov al, [.head]		;head
and al, 00001111b
or al, 10100000b
out dx, al
mov edx, 1f2h
mov al, [.sectorCount]	;sector count
out dx, al
mov edx, 1f3h
mov al, [.sectorIndex]	;sector index
out dx, al
mov edx, 1f4h
mov al, [.cylinder1]	;cylinder low port
out dx, al
mov edx, 1f5h
mov eax, ebx
mov cl, 24
shr eax, cl
mov al, [.cylinder2]	;cylinder high port
out dx, al
mov edx, 1f7h
mov al, 20h
out dx, al

.still_going:
in al, dx
test al, 8
jz .still_going

mov eax, 512/2
xor bx, bx
mov bl, [.sectorCount]	;sector count
mul bx
mov ecx, eax
mov edx, 1f0h
rep insw

pop edi
pop edx
pop ecx
pop ebx
pop eax
popa
ret

.head db 0
.cylinder1 db 0
.cylinder2 db 0
.sectorCount db 0
.sectorIndex db 0

;@param EAX = LBA Address
;@param CL = Number of Sectors to Read
;@param EDI = The address of buffer
ata_lba_read:
pusha
and eax, 0x0FFFFFFF
push eax
push ebx
push ecx
push edx
push edi

mov ebx, eax

mov edx, 0x01f6
shr eax, 24
or al, 11100000b
out dx, al

mov edx, 0x01f2
mov al, cl
out dx, al

mov edx, 0x1f3
mov eax, ebx
out dx, al

mov edx, 0x1f4
mov eax, ebx
shr eax, 8
out dx, al

mov edx, 0x1f5
mov eax, ebx
shr eax, 16
out dx, al

mov edx, 0x1f7
mov al, 0x20
out dx, al

.still_going:
in al, dx
test al, 8
jz .still_going

mov eax, 256
xor bx, bx
mov bl, cl
mul bx
mov ecx, eax
mov edx, 0x1f0
rep insw

pop edi
pop edx
pop ecx
pop ebx
pop eax
popa
ret
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Failed to load file above 28KB in Unreal Mode

Post by Brendan »

Hi,
danasap90 wrote:Thanks Brendan and Octocontrabass, but I've found a new way to allow a file with size above 28KB to be loaded by using ATA.
Never do this.

It will fail for AHCI, it will fail for ancient IDE drives, it will fail for all SCSI drives, it will fail for all USB devices (including USB hard drives and USB flash), it will fail for all emulated drives (including "El Torito, hard disk emulation" CDs and various/rare network attached storage solutions), and it will fail for things like "firmware RAID".

It will also fail in several cases where the disk actually is "old PATA". Specifically, it will fail if the first hard disk happens to be "primary slave" or "secondary master". It will even fail if the first drive is "primary master" but the user happened to install your OS on the second hard disk.

Finally; even when it "should work maybe" there's probably 100 different conditions that you simply didn't check for; including basic things like time-outs, and using the "identify" command to determine the disk's capabilities and actual geometry.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Czernobyl
Member
Member
Posts: 47
Joined: Sun Dec 26, 2010 1:04 pm

Re: Failed to load file above 28KB in Unreal Mode

Post by Czernobyl »

Not what you (O.P.) asked but, I can't help noticing :

|| mov sp, 0FFFFh

In all your posted code fragments. Unless you are using very special
trickery, seems like an odd (pun intended) idea !

Init SP <- FFFEh , FFF0h or even better and simpler, zero it !

Just sayin' of course...
Post Reply