| @@ -1,323 +1,356 @@ | | | @@ -1,323 +1,356 @@ |
1 | /* $NetBSD: fatboot.S,v 1.3 2008/04/29 06:53:02 martin Exp $ */ | | 1 | /* $NetBSD: fatboot.S,v 1.4 2012/03/10 23:59:36 dsl Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2007 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by David Laight. | | 8 | * by David Laight. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * i386 partition boot code | | 33 | * i386 partition boot code |
34 | * This version reads boot directly from a FAT16 filesystem on LBA | | 34 | * This version reads boot directly from a FAT16 filesystem on LBA |
35 | * Addressable media - eg USB media. | | 35 | * Addressable media - eg USB media. |
36 | * | | 36 | * |
37 | * The code is read to address 0:7c00 by the mbr code (in sector zero). | | 37 | * The code is read to address 0:7c00 by the mbr code (in sector zero). |
38 | * | | 38 | * |
39 | * We assume that the partition contains a 'boot parameter block' that | | 39 | * We assume that the partition contains a 'boot parameter block' that |
40 | * correctly identifies the filesystem. | | 40 | * correctly identifies the filesystem. |
41 | * | | 41 | * |
42 | * On entry and exit the BIOS drive number is in %dl. | | 42 | * On entry and exit the BIOS drive number is in %dl. |
43 | */ | | 43 | */ |
44 | | | 44 | |
45 | #include <machine/asm.h> | | 45 | #include <machine/asm.h> |
46 | #include <sys/bootblock.h> | | 46 | #include <sys/bootblock.h> |
47 | | | 47 | |
48 | #ifndef FAT_ENTRY_SIZE | | 48 | #ifndef FAT_ENTRY_SIZE |
49 | #error FAT_ENTRY_SIZE not defined | | 49 | #error FAT_ENTRY_SIZE not defined |
50 | #endif | | 50 | #endif |
51 | | | 51 | |
52 | /* Support for FAT32 could be added - but hasn't been yet. */ | | 52 | /* Support for FAT32 could be added - but hasn't been yet. */ |
53 | #if FAT_ENTRY_SIZE != 16 | | 53 | #if FAT_ENTRY_SIZE != 16 && FAT_ENTRY_SIZE != 12 |
54 | #error Unsupported FAT_ENTRY_SIZE value | | 54 | #error Unsupported FAT_ENTRY_SIZE value |
55 | #endif | | 55 | #endif |
56 | | | 56 | |
| | | 57 | #define FAT_SIZE_STR (('0'+ FAT_ENTRY_SIZE / 10) | ('0' + FAT_ENTRY_SIZE % 10) << 8) |
| | | 58 | |
57 | #define PBR_AFTERBPB 62 /* BPB size in floppy master BR */ | | 59 | #define PBR_AFTERBPB 62 /* BPB size in floppy master BR */ |
58 | | | 60 | |
59 | #ifdef TERSE_ERROR | | 61 | #ifdef TERSE_ERROR |
60 | /* | | 62 | /* |
61 | * Error codes. Done this way to save space. | | 63 | * Error codes. Done this way to save space. |
62 | */ | | 64 | */ |
63 | #define ERR_READ 'R' /* Read error */ | | 65 | #define ERR_READ 'R' /* Read error */ |
64 | #define ERR_NO_BOOT 'B' /* No /boot */ | | 66 | #define ERR_NO_BOOT 'B' /* No /boot */ |
65 | #define ERR_NOT_FAT16 'F' /* Not a FAT16 filesystem */ | | 67 | #define ERR_NOT_FAT16 'F' /* Not a FAT16 filesystem */ |
66 | #define ERR_NO_BOOT_MAGIC_2 'M' /* No magic in loaded /boot */ | | 68 | #define ERR_NO_BOOT_MAGIC_2 'M' /* No magic in loaded /boot */ |
67 | | | 69 | |
68 | #define set_err(err) movb $err, %al | | 70 | #define set_err(err) movb $err, %al |
69 | | | 71 | |
70 | #else | | 72 | #else |
71 | #define set_err(err) mov $err, %ax | | 73 | #define set_err(err) mov $err, %ax |
72 | #endif | | 74 | #endif |
73 | | | 75 | |
74 | .text | | 76 | .text |
75 | .code16 | | 77 | .code16 |
76 | ENTRY(start) | | 78 | ENTRY(start) |
77 | jmp start0 | | 79 | jmp start0 |
78 | nop | | 80 | nop |
79 | oem_name: .ascii "NetBSD40" /* 8 bytes */ | | 81 | oem_name: .ascii "NetBSD40" /* 8 bytes */ |
80 | /* FAT16 BIOS/BOOT Parameter Block - see struct mbr_bpbFAT16 in bootblock.h */ | | 82 | /* FAT16 BIOS/BOOT Parameter Block - see struct mbr_bpbFAT16 in bootblock.h */ |
81 | #define bpb_bytes_per_sec /* .word 0 */ 0x0b /* bytes per sector */ | | 83 | #define bpb_bytes_per_sec /* .word 0 */ 0x0b /* bytes per sector */ |
82 | #define bpb_sec_per_clust /* .byte 0 */ 0x0d /* sectors per cluster */ | | 84 | #define bpb_sec_per_clust /* .byte 0 */ 0x0d /* sectors per cluster */ |
83 | #define bpb_res_sectors /* .word 0 */ 0x0e /* number of reserved sectors */ | | 85 | #define bpb_res_sectors /* .word 0 */ 0x0e /* number of reserved sectors */ |
84 | #define bpb_FATs /* .byte 0 */ 0x10 /* number of FATs */ | | 86 | #define bpb_FATs /* .byte 0 */ 0x10 /* number of FATs */ |
85 | #define bpb_root_dir_ents /* .word 0 */ 0x11 /* number of root dir entries */ | | 87 | #define bpb_root_dir_ents /* .word 0 */ 0x11 /* number of root dir entries */ |
86 | #define bpb_sectors /* .word 0 */ 0x13 /* total number of sectors */ | | 88 | #define bpb_sectors /* .word 0 */ 0x13 /* total number of sectors */ |
87 | #define bpb_media /* .byte 0 */ 0x15 /* media descriptor */ | | 89 | #define bpb_media /* .byte 0 */ 0x15 /* media descriptor */ |
88 | #define bpb_FAT_secs /* .word 0 */ 0x16 /* number of sectors per FAT */ | | 90 | #define bpb_FAT_secs /* .word 0 */ 0x16 /* number of sectors per FAT */ |
89 | #define bpb_sec_per_track /* .word 0 */ 0x18 /* sectors per track */ | | 91 | #define bpb_sec_per_track /* .word 0 */ 0x18 /* sectors per track */ |
90 | #define bpb_heads /* .word 0 */ 0x1a /* number of heads */ | | 92 | #define bpb_heads /* .word 0 */ 0x1a /* number of heads */ |
91 | #define bpb_hidden_secs /* .long 0 */ 0x1c /* # of hidden sectors */ | | 93 | #define bpb_hidden_secs /* .long 0 */ 0x1c /* # of hidden sectors */ |
92 | #define bpb_huge_sectors /* .long 0 */ 0x20 /* # of sectors if !bpbSectors*/ | | 94 | #define bpb_huge_sectors /* .long 0 */ 0x20 /* # of sectors if !bpbSectors*/ |
93 | /* Extended boot area */ | | 95 | /* Extended boot area */ |
94 | #define bs_drive_number /* .byte 0 */ 0x24 /* but we believe the BIOS ! */ | | 96 | #define bs_drive_number /* .byte 0 */ 0x24 /* but we believe the BIOS ! */ |
95 | #define bs_reserved_1 /* .byte 0 */ 0x25 /* */ | | 97 | #define bs_reserved_1 /* .byte 0 */ 0x25 /* */ |
96 | #define bs_boot_sig /* .byte 0 */ 0x26 /* */ | | 98 | #define bs_boot_sig /* .byte 0 */ 0x26 /* */ |
97 | #define bs_volume_id /* .long 0 */ 0x27 /* Volume ID number */ | | 99 | #define bs_volume_id /* .long 0 */ 0x27 /* Volume ID number */ |
98 | #define bs_volume_label /* .space 11*/ 0x2b /* Volume label */ | | 100 | #define bs_volume_label /* .space 11*/ 0x2b /* Volume label */ |
99 | #define bs_file_sys_type /* .space 8 */ 0x36 /* "FAT16 " */ | | 101 | #define bs_file_sys_type /* .space 8 */ 0x36 /* "FAT16 " */ |
100 | | | 102 | |
101 | /* Some locals overlaying the end of the above */ | | 103 | /* Some locals overlaying the end of the above */ |
102 | #define sec_p_cl_w 0x2c /* 16bit bpb_sec_per_clust */ | | 104 | #define sec_p_cl_w 0x2c /* 16bit bpb_sec_per_clust */ |
103 | #define fat_sector 0x30 /* start of FAT in sectors */ | | 105 | #define fat_sector 0x30 /* start of FAT in sectors */ |
104 | | | 106 | |
105 | . = start + PBR_AFTERBPB /* skip BPB */ | | 107 | . = start + PBR_AFTERBPB /* skip BPB */ |
106 | start0: | | 108 | start0: |
107 | xor %eax, %eax /* don't trust values of ds, es or ss */ | | 109 | xor %eax, %eax /* don't trust values of ds, es or ss */ |
108 | mov %ax, %ds | | 110 | mov %ax, %ds |
109 | mov %ax, %es | | 111 | mov %ax, %es |
110 | mov %ax, %ss | | 112 | mov %ax, %ss |
111 | mov $start, %sp | | 113 | mov $start, %sp |
112 | mov %sp, %bp /* to access the pbp */ | | 114 | mov %sp, %bp /* to access the pbp */ |
113 | push %dx /* save drive at -2(%bp) */ | | 115 | push %dx /* save drive at -2(%bp) */ |
114 | | | 116 | |
| | | 117 | /* We put the LBA bios command block on stack. |
| | | 118 | * Since we only want a 32bit sector number, stack a zero */ |
| | | 119 | push %cs /* %cs is zero */ |
| | | 120 | push %cs /* 64-bit for LBA read */ |
| | | 121 | |
115 | set_err(ERR_NOT_FAT16) | | 122 | set_err(ERR_NOT_FAT16) |
116 | cmpl $'A'|'T'<<8|'1'<<16|'6'<<24, bs_file_sys_type+1(%bp) | | 123 | cmpl $'A'|'T'<<8|FAT_SIZE_STR<<16, bs_file_sys_type+1(%bp) |
117 | jne error | | 124 | jne error |
118 | | | 125 | |
119 | /* Add 'reserved' (inside ptn) to 'hidden' (ptn offset) */ | | 126 | /* Add 'reserved' (inside ptn) to 'hidden' (ptn offset) */ |
120 | mov bpb_res_sectors(%bp), %ax | | 127 | mov bpb_res_sectors(%bp), %ax |
121 | addl bpb_hidden_secs(%bp), %eax | | 128 | addl bpb_hidden_secs(%bp), %eax |
122 | mov %eax, fat_sector(%bp) /* To get first sector of FAT */ | | 129 | mov %eax, fat_sector(%bp) /* To get first sector of FAT */ |
123 | | | 130 | |
| | | 131 | #if FAT_ENTRY_SIZE == 12 |
| | | 132 | /* Read the entire FAT */ |
| | | 133 | push %eax |
| | | 134 | push %ds |
| | | 135 | push $fat_buffer |
| | | 136 | push $12 /* 12 sectors is assumed 6k */ |
| | | 137 | call read_lba |
| | | 138 | #endif |
| | | 139 | |
124 | /* Determine base of root directory */ | | 140 | /* Determine base of root directory */ |
125 | movzbw bpb_FATs(%bp), %ax /* Count of FATs */ | | 141 | movzbw bpb_FATs(%bp), %ax /* Count of FATs */ |
126 | mulw bpb_FAT_secs(%bp) /* FAT size in %dx:%ax */ | | 142 | mulw bpb_FAT_secs(%bp) /* FAT size in %dx:%ax */ |
127 | shl $16,%edx | | 143 | shl $16,%edx |
128 | xchg %ax,%dx /* FAT size now in %edx */ | | 144 | xchg %ax,%dx /* FAT size now in %edx */ |
129 | addl fat_sector(%bp), %edx /* Directory is after FATs */ | | 145 | addl fat_sector(%bp), %edx /* Directory is after FATs */ |
130 | push %cs /* %cs is zero */ | | | |
131 | push %cs /* 64-bit for LBA read */ | | | |
132 | pushl %edx /* Sector number of root dir */ | | 146 | pushl %edx /* Sector number of root dir */ |
133 | | | 147 | |
134 | push $0x1000 /* Read to 0x10000:0 */ | | 148 | push $0x1000 /* Read to 0x10000:0 */ |
135 | pop %es /* Which we need in %es later */ | | 149 | pop %es /* Which we need in %es later */ |
136 | push %es | | 150 | push %es |
137 | push %cs /* Offset zero */ | | 151 | push %cs /* Offset zero */ |
138 | | | 152 | |
139 | /* Convert the root directory size to sectors */ | | 153 | /* Convert the root directory size to sectors */ |
140 | push %dx | | 154 | push %dx |
141 | mov bpb_root_dir_ents(%bp), %ax | | 155 | mov bpb_root_dir_ents(%bp), %ax |
142 | mov $0x20, %dx | | 156 | mov $0x20, %dx |
143 | mul %dx | | 157 | mul %dx |
144 | divw bpb_bytes_per_sec(%bp) | | 158 | divw bpb_bytes_per_sec(%bp) |
145 | add $0xffff, %dx /* Set carry if remainder non-zero */ | | 159 | add $0xffff, %dx /* Set carry if remainder non-zero */ |
146 | adc $0, %ax /* and round up the division */ | | 160 | adc $0, %ax /* and round up the division */ |
147 | pop %dx | | 161 | pop %dx |
148 | | | 162 | |
149 | /* Read in the entire root directory */ | | 163 | /* Read in the entire root directory */ |
150 | push %ax /* Sectors in root directory */ | | 164 | push %ax /* Sectors in root directory */ |
151 | cwtl | | 165 | cwtl |
152 | addl %eax, %edx /* %edx now sector of first file */ | | 166 | addl %eax, %edx /* %edx now sector of first cluster */ |
153 | call read_lba /* Read entire directory */ | | 167 | call read_lba /* Read entire directory */ |
154 | | | 168 | |
155 | /* Scan directory for our file */ | | 169 | /* Scan directory for our file */ |
156 | xor %di, %di | | 170 | xor %di, %di |
157 | scan_dir: | | 171 | scan_dir: |
158 | mov $boot_filename, %si | | 172 | mov $boot_filename, %si |
159 | mov $11, %cx | | 173 | mov $11, %cx |
160 | repz cmpsb | | 174 | repz cmpsb |
161 | je found_boot | | 175 | je found_boot |
162 | or $31,%di | | 176 | or $31,%di |
163 | inc %di | | 177 | inc %di |
164 | cmp %ch, %es:(%di) /* %ch is zero - test end of dir */ | | 178 | cmp %ch, %es:(%di) /* %ch is zero - test end of dir */ |
165 | jz 1f | | 179 | jz 1f |
166 | decw bpb_root_dir_ents(%bp) | | 180 | decw bpb_root_dir_ents(%bp) |
167 | jnz scan_dir | | 181 | jnz scan_dir |
168 | 1: set_err(ERR_NO_BOOT) | | 182 | 1: set_err(ERR_NO_BOOT) |
169 | | | 183 | |
170 | error: | | 184 | error: |
171 | #ifdef TERSE_ERROR | | 185 | #ifdef TERSE_ERROR |
172 | movb %al, errcod | | 186 | movb %al, errcod |
173 | movw $errtxt, %si | | 187 | movw $errtxt, %si |
174 | call message | | 188 | call message |
175 | #else | | 189 | #else |
176 | push %ax | | 190 | push %ax |
177 | movw $errtxt, %si | | 191 | movw $errtxt, %si |
178 | call message | | 192 | call message |
179 | pop %si | | 193 | pop %si |
180 | call message | | 194 | call message |
181 | movw $newline, %si | | 195 | movw $newline, %si |
182 | call message | | 196 | call message |
183 | #endif | | 197 | #endif |
184 | 1: sti | | 198 | 1: sti |
185 | hlt | | 199 | hlt |
186 | jmp 1b | | 200 | jmp 1b |
187 | | | 201 | |
188 | found_boot: | | 202 | found_boot: |
189 | movzbl bpb_sec_per_clust(%bp), %eax | | 203 | movzbl bpb_sec_per_clust(%bp), %eax |
190 | movw %ax, sec_p_cl_w(%bp) | | 204 | movw %ax, sec_p_cl_w(%bp) |
191 | add %ax, %ax | | 205 | add %ax, %ax |
192 | subl %eax, %edx /* 1st file sector is cluster 2 */ | | 206 | subl %eax, %edx /* 1st file sector is cluster 2 */ |
193 | 1: inc %cl /* Convert power of 2 ... */ | | 207 | 1: inc %cl /* Convert power of 2 ... */ |
194 | shr $1, %ax /* ... to shift */ | | 208 | shr $1, %ax /* ... to shift */ |
195 | jnz 1b | | 209 | jnz 1b |
196 | dec %cx | | 210 | dec %cx |
197 | dec %cx | | 211 | dec %cx |
198 | movw %es:15(%di), %ax /* Cluster number for file start */ | | 212 | movw %es:(26-11)(%di), %ax /* Cluster number for file start */ |
199 | push %es /* We increment the 'segment' ... */ | | 213 | push %es /* We increment the 'segment' ... */ |
200 | pop %di /* ... after each read, offset is 0 */ | | 214 | pop %di /* ... after each read, offset is 0 */ |
201 | | | 215 | |
202 | read_data_block: | | 216 | read_data_block: |
203 | mov %ax, %bx /* Save cluster number */ | | 217 | mov %ax, %bx /* Save cluster number */ |
204 | shl %cl, %eax /* Convert to sector number */ | | 218 | shl %cl, %eax /* Convert to sector number */ |
205 | add %eax, %edx | | 219 | jz error /* Sanity bail-out */ |
206 | pushl %edx /* Sector to read */ | | 220 | add %edx, %eax |
207 | sub %eax, %edx /* Recover base segment */ | | 221 | pushl %eax /* Sector to read */ |
208 | push %di /* Target address segment! */ | | 222 | push %di /* Target address segment! */ |
209 | push $0 | | 223 | push $0 |
210 | push sec_p_cl_w(%bp) | | 224 | push sec_p_cl_w(%bp) |
211 | call read_lba /* Read a cluster */ | | 225 | call read_lba /* Read a cluster */ |
212 | | | 226 | |
213 | /* Update read ptr for next cluster */ | | 227 | /* Update read ptr for next cluster */ |
214 | mov bpb_bytes_per_sec(%bp), %ax | | 228 | mov bpb_bytes_per_sec(%bp), %ax |
215 | shr $4, %ax /* x86 segment count */ | | 229 | shr $4, %ax /* x86 segment count */ |
216 | shl %cl, %ax /* for a cluster */ | | 230 | shl %cl, %ax /* for a cluster */ |
217 | add %ax, %di | | 231 | add %ax, %di |
218 | | | 232 | |
219 | /* Lookup FAT slot number in FAT table */ | | 233 | /* Lookup FAT slot number in FAT table */ |
220 | mov %bx, %ax /* Recover cluster number */ | | 234 | mov %bx, %ax /* Recover cluster number */ |
| | | 235 | #if FAT_ENTRY_SIZE == 12 |
| | | 236 | shr $1, %ax |
| | | 237 | jc 1f |
| | | 238 | add %ax, %bx |
| | | 239 | mov fat_buffer(%bx), %ax |
| | | 240 | and $0xf,%ah |
| | | 241 | jmp 2f |
| | | 242 | 1: add %ax, %bx |
| | | 243 | mov fat_buffer(%bx), %ax |
| | | 244 | shr $4, %ax |
| | | 245 | 2: |
| | | 246 | cmp $0x0fff, %ax |
| | | 247 | jb read_data_block |
| | | 248 | #else |
221 | push %dx | | 249 | push %dx |
222 | xor %dx, %dx | | 250 | xor %dx, %dx |
223 | divw bpb_bytes_per_sec(%bp) | | 251 | divw bpb_bytes_per_sec(%bp) |
224 | mov %dx, %bx /* Entry in FAT block */ | | 252 | mov %dx, %bx /* Entry in FAT block */ |
225 | pop %dx | | 253 | pop %dx |
226 | cmp %ax, fat_cache | | 254 | cmp %ax, fat_cache |
227 | je lookup_fat | | 255 | je lookup_fat |
228 | | | 256 | |
229 | /* We must read a different chuck of the FAT */ | | 257 | /* We must read a different chuck of the FAT */ |
230 | mov %ax, fat_cache | | 258 | mov %ax, fat_cache |
231 | cwtl | | 259 | cwtl |
232 | shl $1, %ax | | 260 | shl $1, %ax |
233 | addl fat_sector(%bp), %eax | | 261 | addl fat_sector(%bp), %eax |
234 | push %eax | | 262 | push %eax |
235 | push %ds | | 263 | push %ds |
236 | push $fat_buffer | | 264 | push $fat_buffer |
237 | push $2 /* Always read 2 sectors of FAT */ | | 265 | push $2 /* Always read 2 sectors of FAT */ |
238 | call read_lba | | 266 | call read_lba |
239 | | | 267 | |
240 | /* Now use low part of cluster number to index FAT sector */ | | 268 | /* Now use low part of cluster number to index FAT sector */ |
241 | lookup_fat: | | 269 | lookup_fat: |
242 | add %bx, %bx /* 2 bytes per entry... */ | | 270 | add %bx, %bx /* 2 bytes per entry... */ |
243 | movzwl fat_buffer(%bx), %eax /* Next FAT slot */ | | 271 | movzwl fat_buffer(%bx), %eax /* Next FAT slot */ |
244 | cmp $0xfff0, %ax | | 272 | cmp $0xfff0, %ax |
245 | jb read_data_block | | 273 | jb read_data_block |
| | | 274 | #endif |
246 | | | 275 | |
247 | /* Found end of FAT chain - must be EOF - leap into loaded code */ | | 276 | /* Found end of FAT chain - must be EOF - leap into loaded code */ |
248 | mov $0x1000, %ax | | 277 | mov $0x1000, %ax |
249 | mov %ax, %es | | 278 | mov %ax, %es |
250 | cmpl $X86_BOOT_MAGIC_2, %es:4 | | 279 | cmpl $X86_BOOT_MAGIC_2, %es:4 |
251 | je magic_ok | | 280 | je magic_ok |
252 | set_err(ERR_NO_BOOT_MAGIC_2) | | 281 | set_err(ERR_NO_BOOT_MAGIC_2) |
253 | err1: jmp error | | 282 | err1: jmp error |
254 | | | 283 | |
255 | /* Set parameters expected by /boot */ | | 284 | /* Set parameters expected by /boot */ |
256 | magic_ok: | | 285 | magic_ok: |
257 | mov bpb_hidden_secs(%bp), %ebx /* ptn base sector */ | | 286 | mov bpb_hidden_secs(%bp), %ebx /* ptn base sector */ |
258 | movb -2(%bp), %dl /* disk number (could pop %dx) */ | | 287 | movb -2(%bp), %dl /* disk number */ |
259 | mov $boot_params + 4, %si | | 288 | mov $boot_params + 4, %si |
260 | push %es | | 289 | push %es |
261 | push $0 | | 290 | push $0 |
262 | lret | | 291 | lret |
263 | | | 292 | |
264 | /* Read disk using on-stack int13-extension parameter block */ | | 293 | /* Read disk using on-stack int13-extension parameter block */ |
265 | read_lba: | | 294 | read_lba: |
266 | pop %ax /* Save rtn addr */ | | 295 | pop %ax /* Save rtn addr */ |
267 | pushw $16 /* Stack ctl block length */ | | 296 | pushw $16 /* Stack ctl block length */ |
268 | mov %sp, %si /* Address ctl block */ | | 297 | mov %sp, %si /* Address ctl block */ |
269 | push %ax /* restack rtn addr */ | | 298 | push %ax /* restack rtn addr */ |
270 | pushal /* Save everything except %si and %ax*/ | | 299 | pushal /* Save everything except %si and %ax*/ |
271 | mov -2(%bp), %dl /* Disk # saved on entry */ | | 300 | mov -2(%bp), %dl /* Disk # saved on entry */ |
272 | movb $0x42, %ah | | 301 | movb $0x42, %ah |
273 | int $0x13 | | 302 | int $0x13 |
274 | popal | | 303 | popal |
275 | | | 304 | |
276 | set_err(ERR_READ) | | 305 | set_err(ERR_READ) |
277 | jc err1 | | 306 | jc err1 |
278 | ret $12 /* Discard all except high LBA zeros */ | | 307 | ret $12 /* Discard all except high LBA zeros */ |
279 | | | 308 | |
280 | /* | | 309 | /* |
281 | * I hate #including source files, but pbr_magic below has to be at | | 310 | * I hate #including source files, but pbr_magic below has to be at |
282 | * the correct absolute address. | | 311 | * the correct absolute address. |
283 | * Clearly this could be done with a linker script. | | 312 | * Clearly this could be done with a linker script. |
284 | */ | | 313 | */ |
285 | | | 314 | |
286 | #include <message.S> | | 315 | #include <message.S> |
287 | #if 0 | | 316 | #if 0 |
288 | #include <dump_eax.S> | | 317 | #include <dump_eax.S> |
| | | 318 | dump_eax_buff = start |
289 | #endif | | 319 | #endif |
290 | | | 320 | |
291 | errtxt: .ascii "Error " /* runs into newline... */ | | 321 | errtxt: .ascii "Error " /* runs into newline... */ |
292 | errcod: .byte 0 /* ... if errcod set */ | | 322 | errcod: .byte 0 /* ... if errcod set */ |
293 | newline: | | 323 | newline: |
294 | .asciz "\r\n" | | 324 | .asciz "\r\n" |
295 | | | 325 | |
296 | #ifndef TERSE_ERROR | | 326 | #ifndef TERSE_ERROR |
297 | ERR_READ: .asciz "Disk read" | | 327 | ERR_READ: .asciz "Disk read" |
298 | ERR_NO_BOOT: .asciz "No /boot" | | 328 | ERR_NO_BOOT: .asciz "No /boot" |
299 | ERR_NOT_FAT16: .asciz "Not FAT16 ptn" | | 329 | ERR_NOT_FAT16: .ascii "Not FAT" |
| | | 330 | .word FAT_SIZE_STR |
| | | 331 | .asciz " ptn" |
300 | ERR_NO_BOOT_MAGIC_2: .asciz "No magic in /boot" | | 332 | ERR_NO_BOOT_MAGIC_2: .asciz "No magic in /boot" |
301 | #endif | | 333 | #endif |
302 | | | 334 | |
303 | boot_filename: .ascii "BOOT " | | 335 | boot_filename: .ascii "BOOT " |
304 | | | 336 | |
305 | space: | | 337 | space: |
306 | pbr_space = boot_params - . | | 338 | pbr_space = boot_params - . |
307 | | | 339 | |
308 | /* | | 340 | /* |
309 | * Add magic number, with a zero sized patchable area - just in case something | | 341 | * Add magic number, with a zero sized patchable area - just in case something |
310 | * finds it and tries to update the area. | | 342 | * finds it and tries to update the area. |
311 | * Boot options can be set using 'installboot -e boot' so we don't need to | | 343 | * Boot options can be set using 'installboot -e boot' so we don't need to |
312 | * use any of our valuable bytes. | | 344 | * use any of our valuable bytes. |
313 | */ | | 345 | */ |
314 | | | 346 | |
315 | . = _C_LABEL(start) + 0x1fe - 2 - 4 - 4 | | 347 | . = _C_LABEL(start) + 0x1fe - 2 - 4 - 4 |
316 | boot_params: | | 348 | boot_params: |
317 | .long X86_BOOT_MAGIC_FAT | | 349 | .long X86_BOOT_MAGIC_FAT |
318 | .long 1f - . | | 350 | .long 1f - . |
319 | 1: | | 351 | 1: |
320 | fat_cache: .word 0xffff /* Sector number in buffer */ | | 352 | fat_cache: .word 0xffff /* Sector number in buffer */ |
321 | . = _C_LABEL(start) + 0x1fe | | 353 | . = _C_LABEL(start) + 0x1fe |
322 | .word 0xaa55 | | 354 | .word 0xaa55 |
323 | fat_buffer: /* 2 sectors worth of FAT table */ | | 355 | fat_buffer: /* 2 sectors worth of FAT table */ |
| | | 356 | /* 6k for FAT12 */ |