1; // TODO: This code only works for the 286+ so you must detect for 8088's somewhere in your code.
3[bits 32] ; Function for reading disk contents to memory
4global read_disk ; Function using legacy PIO mode + polling, should be used early during boot only!
7read_disk: ; First parameter (pointer): [ESP + 8] - LBA address of the first sector to read.
8 ; Second parameter (boolean): [ESP + 12] - Master or slave drive to use. // TODO: make use of it, setup drive check!
9 ; Third parameter (word): [ESP + 16] - Bytes number to read (must be even).
10 ; Fourth parameter (word): [ESP + 20] - Offset to read (must be even).
11 ; Last parameter (pointer): [ESP + 24] - Pointer to RAM where to load data from disk.
12 push ebp ; Save stack base.
13 mov ebp, esp ; Set register base to register top.
14 ; Function won't be able to interfere with previous stack entries.
15 pusha ; Save all registers. They will be restored afterwards.
17 ; Calculate number of sectors to read (ceil).
18 mov ebx, [ebp+16] ; Store offset in ebx.
19 add ebx, [ebp+20] ; Add length to ebx - ceil(ebx) will be number of sectors to read.
20 shl ebx, 9 ; Divide ebx by sector size.
21 test ebx, 0x1ff ; Calculate eax by sector size division remainder. // TODO: check sector size!
22 jz .setup_reading ; Setup reading if remainder equals zero.
23 add ebx, 1 ; Add 1 to ceil otherwise.
27 mov edx, 0x01F6 ; Port to send drive and bit 24 - 27 of LBA.
28 mov eax, [ebp+8] ; Copy LBA to eax.
29 shr eax, 24 ; Get bit 24 - 27 in al.
30 or al, 0xe0 ; Set bit 6 in al for LBA mode.
31 out dx, al ; Send eax value to port.
33 mov edx, 0x01f2 ; Port to send number of sectors.
34 mov al, bl ; Get number of sectors from ebx.
37 mov edx, 0x1f3 ; Port to send bit 0 - 7 of LBA.
38 mov eax, [ebp+8] ; Copy LBA to eax.
41 mov edx, 0x1f4 ; Port to send bit 8 - 15 of LBA.
42 mov eax, [ebp+8] ; Copy LBA to eax.
43 shr eax, 8 ; Get bit 8 - 15 in al.
46 mov edx, 0x1f5 ; Port to send bit 16 - 23 of LBA.
47 mov eax, [ebp+8] ; Copy LBA to eax.
48 shr eax, 16 ; Get bit 16 - 23 in al.
51 mov edx, 0x1f7 ; Command port.
52 mov al, 0x20 ; Read with retry command.
57 in al, dx ; Read status port.
58 test al, 0x80 ; Check for BSY status flag.
59 jz .ready ; Start reading if flag isn't set.
61 test al, 0x1 ; Check for ERR flag.
62 jnz .general_error ; Jump to general error handler if it's set.
63 test al, 0x20 ; Check for DF flag.
64 jnz .drive_fault_error ; Jump to drive fault handler if it's set.
66 jmp .busy ; Loop otherwise.
69 mov dx, 0x1f1 ; Port to receive error message.
70 in ax, dx ; Read error code from port.
74 mov ax, 0x10 ; Drive fault doesn't have error code, so we'll set it to first bit of second byte.
79 in al, dx ; Read status port.
80 test al, 0x8 ; Check for DRQ status flag.
81 jz .ready ; Loop some more if flag isn't set.
82 mov dx, 0x1f0 ; Data port, data comes in and out of here.
83 ; NB! This is a word port only. We can't read a single byte from here. Only a word.
85 mov ecx, [ebp+20] ; Copy offset to ecx.
86 shr ecx, 1 ; Divide offset by 2 - calculate offset in words.
87 cmp ecx, 0 ; If offset equals zero start reading data.
91 in ax, dx ; If offset doesn't equal zero, drain offset data.
95 mov ecx, [ebp+16] ; Copy data length to ecx.
96 shr ecx, 1 ; Divide data length by 2 - calculate data length in words.
97 mov edi, [ebp+24] ; Copy data loading address to edi.
98 rep insw ; Copy all data there.
100 mov ecx, ebx ; Copy number of sectors from ebx to ecx.
101 shr ecx, 9 ; Multiply ecx by sector size.
102 sub ecx, [ebp+16] ; Substract offset from ecx.
103 sub ecx, [ebp+20] ; Substract data length from ecx.
104 ; Remaining data length in the last read sector is stored in ecx.
105 shr ecx, 1 ; Divide remaining data length by 2 - calculate remaining data length in words.
106 cmp ecx, 0 ; If remaining data length equals zero return.
110 in ax, dx ; If remaining data length doesn't equal zero, drain remaining data.
113 mov ax, 0 ; Move zero (successful code) to eax.
117 mov [esp+14], ax ; Change saved eax to current.
118 ; This allows us to return error or successful execution code.
119 popa ; Restore all registers.
120 mov esp, ebp ; Restore stack.
121 pop ebp ; Restore stack base.