1 ; =============================================================================
2 ; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT
6 ; =============================================================================
10 ; Read first sector of HDD into memory
18 cmp byte [cfg_mbr
], 0x01 ; Did we boot from a MBR drive
19 jne hdd_setup_no_mbr
; If not then we already have the correct sector
21 ; Grab the partition offset value for the first partition
23 mov [fat16_PartitionOffset
], eax
25 ; Read the first sector of the first partition
33 ; Get the values we need to start using fat16
35 mov [fat16_BytesPerSector
], ax ; This will probably be 512
37 mov [fat16_SectorsPerCluster
], al ; This will be 128 or less (Max cluster size is 64KiB)
39 mov [fat16_ReservedSectors
], ax
40 mov [fat16_FatStart
], eax
42 mov [fat16_Fats
], al ; This will probably be 2
44 mov [fat16_RootDirEnts
], ax
46 mov [fat16_SectorsPerFat
], ax
48 ; Find out how many sectors are on the disk
52 jne lessthan65536sectors
55 mov [fat16_TotalSectors
], eax
57 ; Calculate the size in MiB
59 mov eax, [fat16_TotalSectors
]
61 shr rax
, 11 ; rax = rax * 512 / 1048576
62 mov [hd1_size
], eax ; in mebibytes (MiB)
64 ; Create a string of the harddrive size
70 mov ax, [fat16_SectorsPerFat
]
71 shl ax, 1 ; quick multiply by two
72 add ax, [fat16_ReservedSectors
]
73 mov [fat16_RootStart
], eax
74 mov bx, [fat16_RootDirEnts
]
75 shr ebx, 4 ; bx = (bx * 32) / 512
76 add ebx, eax ; BX now holds the datastart sector number
77 mov [fat16_DataStart
], ebx
82 ; -----------------------------------------------------------------------------
83 ; readsectors -- Read sectors on the hard drive
84 ; IN: RAX = starting sector to read
85 ; RCX = number of sectors to read (1 - 256)
86 ; RDI = memory location to store sectors
87 ; OUT: RAX = RAX + number of sectors that were read
88 ; RCX = number of sectors that were read (0 on error)
89 ; RDI = RDI + (number of sectors * 512)
90 ; All other registers preserved
97 push rcx
; Save RCX for use in the read loop
98 mov rbx
, rcx
; Store number of sectors to read
100 jg readsectors_fail
; Over 256? Fail!
101 jne readsectors_skip
; Not 256? No need to modify CL
102 xor rcx
, rcx
; 0 translates to 256
105 push rax
; Save RAX since we are about to overwrite it
106 mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0
107 mov al, cl ; Read CL sectors
109 pop rax
; Restore RAX which is our sector number
110 inc dx ; 0x01F3 - LBA Low Port 7:0
112 inc dx ; 0x01F4 - LBA Mid Port 15:8
115 inc dx ; 0x01F5 - LBA High Port 23:16
118 inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24)
120 and al, 00001111b ; Clear bits 4-7 just to be safe
121 or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master)
123 inc dx ; 0x01F7 - Command Port
124 mov al, 0x20 ; Read sector(s). 0x24 if LBA48
129 in al, dx ; Read status from 0x01F7
130 test al, 0x80 ; BSY flag set?
131 jne readsectors_retry
132 test al, 0x08 ; DRQ set?
133 jne readsectors_dataready
137 readsectors_nextsector:
138 in al, dx ; Read status from 0x01F7
139 test al, 0x80 ; BSY flag set?
140 jne readsectors_nextsector
141 test al, 0x21 ; ERR or DF set?
144 readsectors_dataready:
145 sub dx, 7 ; Data port (0x1F0)
147 rep insw ; Copy a 512 byte sector to RDI
148 add dx, 7 ; Set DX back to status register (0x01F7)
149 in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ
154 dec rbx
; RBX is the "sectors to read" counter
156 jne readsectors_nextsector
172 xor rcx
, rcx
; Set RCX to 0 since nothing was read
174 ; -----------------------------------------------------------------------------
177 ; =============================================================================