1 ; To save space, functions that are just called once are
2 ; implemented as macros instead. Four bytes are saved by
3 ; avoiding the call / ret instructions.
6 ; FINDFILE: Searches for the file in the root directory.
10 ; If file not found: CF set
12 ; If file found: CF clear
13 ; AX = first cluster of file
17 ; First, read the whole root directory
18 ; into the temporary buffer.
20 mov ax, word root_dir_start
21 mov dx, word root_dir_start_hi
30 next_entry: mov cx, 11
31 mov si, filename+7c00h
35 mov ax, [es:di+1ah] ; get cluster number from directory entry
39 add di, 20h ; go to next directory entry
40 cmp byte [es:di], 0 ; if the first byte of the name is 0,
41 jnz next_entry ; there is no more files in the directory
47 ; GETDRIVEPARMS: Calculate start of some disk areas.
49 %macro GETDRIVEPARMS 0
51 mov di, word nHidden_hi
52 add si, word resSectors
53 adc di, 0 ; DI:SI = first FAT sector
55 mov word fat_start, si
56 mov word fat_start_hi, di
60 mul word sectPerFat ; DX:AX = total number of FAT sectors
63 adc di, dx ; DI:SI = first root directory sector
64 mov word root_dir_start, si
65 mov word root_dir_start_hi, di
67 ; Calculate how many sectors the root directory occupies.
68 mov bx, bytesPerSector
69 mov cl, 5 ; divide BX by 32
70 shr bx, cl ; BX = directory entries per sector
76 mov nRootDir, ax ; AX = sectors per root directory
79 adc di, 0 ; DI:SI = first data sector
87 ; Reads the FAT chain and stores it in a temporary buffer in the first
88 ; 64 kb. The FAT chain is stored an array of 16-bit cluster numbers,
91 ; The file must fit in conventional memory, so it can't be larger than
92 ; 640 kb. The sector size must be at least 512 bytes, so the FAT chain
93 ; can't be larger than around 3 kb.
95 ; Call with: AX = first cluster in chain
97 ; Returns: CF clear on success, set on error
100 push ax ; store first cluster number
102 ; Load the complete FAT into memory. The FAT can't be larger
103 ; than 128 kb, so it should fit in the temporary buffer.
108 mov ax, word fat_start
109 mov dx, word fat_start_hi
111 pop ax ; restore first cluster number
114 ; Set ES:DI to the temporary storage for the FAT chain.
121 next_clust: stosw ; store cluster number
122 mov si, ax ; SI = cluster number
123 cmp byte extBoot, 29h
125 cmp byte [bp+filesys+4], '6' ; check for FAT-16 system
128 ; This is a FAT-12 disk.
130 fat_12: add si, si ; multiply cluster number by 3...
132 shr si, 1 ; ...and divide by 2
135 ; If the cluster number was even, the cluster value is now in
136 ; bits 0-11 of AX. If the cluster number was odd, the cluster
137 ; value is in bits 4-15, and must be shifted right 4 bits. If
138 ; the number was odd, CF was set in the last shift instruction.
142 shr ax, cl ; shift the cluster number
144 fat_even: and ah, 0fh ; mask off the highest 4 bits
145 cmp ax, 0fffh ; check for EOF
148 ; This is a FAT-16 disk. The maximal size of a 16-bit FAT
149 ; is 128 kb, so it may not fit within a single 64 kb segment.
151 fat_16: mov dx, tempbuf
152 add si, si ; multiply cluster number by two
153 jnc first_half ; if overflow...
154 add dh, 10h ; ...add 64 kb to segment value
156 first_half: mov ds, dx ; DS:SI = pointer to next cluster
157 lodsw ; AX = next cluster
159 cmp ax, 0fff8h ; >= FFF8 = 16-bit EOF
160 next_test: jb next_clust ; continue if not EOF
162 finished: ; Mark end of FAT chain with 0, so we have a single
163 ; EOF marker for both FAT-12 and FAT-16 systems.
171 ; loadFile: Loads the file into memory, one cluster at a time.
174 mov es, tempbuf ; set ES:BX to load address
177 mov si, FATBUF ; set DS:SI to the FAT chain
181 next_cluster: lodsw ; AX = next cluster to read
182 or ax, ax ; if EOF...
183 je boot_success ; ...boot was successful
185 dec ax ; cluster numbers start with 2
188 mov di, word sectPerCluster
189 and di, 0ffh ; DI = sectors per cluster
192 adc dx, data_start_hi ; DX:AX = first sector to read