rev |
line source |
pascal@955
|
1 --- gpxe-0.9.3/src/arch/i386/prefix/lkrnprefix.S
|
pascal@955
|
2 +++ gpxe-0.9.3/src/arch/i386/prefix/lkrnprefix.S
|
pascal@955
|
3 @@ -50,40 +50,343 @@
|
pascal@955
|
4 .arch i386
|
pascal@955
|
5 .org 0
|
pascal@955
|
6 .section ".prefix", "ax", @progbits
|
pascal@955
|
7 -/*
|
pascal@955
|
8 - This is a minimal boot sector. If anyone tries to execute it (e.g., if
|
pascal@955
|
9 - a .lilo file is dd'ed to a floppy), print an error message.
|
pascal@955
|
10 -*/
|
pascal@955
|
11
|
pascal@955
|
12 -bootsector:
|
pascal@955
|
13 - jmp $BOOTSEG, $1f /* reload cs:ip to match relocation addr */
|
pascal@955
|
14 -1:
|
pascal@955
|
15 - movw $0x2000, %di /* 0x2000 is arbitrary value >= length
|
pascal@955
|
16 - of bootsect + room for stack */
|
pascal@955
|
17 + call here
|
pascal@955
|
18 +here:
|
pascal@955
|
19 + pop %ax
|
pascal@955
|
20 + cmpw $0x103, %ax /* COM entry point is cs:0x100 */
|
pascal@955
|
21 + jne bootsector
|
pascal@955
|
22 +
|
pascal@955
|
23 +/* We need a real mode stack that won't be stomped on by Etherboot
|
pascal@955
|
24 + which starts at 0x20000. Choose something that's sufficiently high,
|
pascal@955
|
25 + but not in DOC territory. Note that we couldn't do this in a real
|
pascal@955
|
26 + .com program since stack variables are in the same segment as the
|
pascal@955
|
27 + code and data, but this isn't really a .com program, it just looks
|
pascal@955
|
28 + like one to make DOS load it into memory. It still has the 64kB
|
pascal@955
|
29 + limitation of .com files though. */
|
pascal@955
|
30 +#define STACK_SEG 0x7000
|
pascal@955
|
31 +#define STACK_SIZE 0x4000
|
pascal@955
|
32 + /* Set up temporary stack */
|
pascal@955
|
33 + movw $STACK_SEG, %ax
|
pascal@955
|
34 + movw %ax, %ss
|
pascal@955
|
35 + movw $STACK_SIZE, %sp
|
pascal@955
|
36 +
|
pascal@955
|
37 + /* Calculate segment address of image start */
|
pascal@955
|
38 + pushw %cs
|
pascal@955
|
39 + popw %ax
|
pascal@955
|
40 + addw $(0x100/16), %ax
|
pascal@955
|
41 + jmp go_setup_code
|
pascal@955
|
42 +
|
pascal@955
|
43 +bootsector:
|
pascal@955
|
44 + jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */
|
pascal@955
|
45 +go:
|
pascal@955
|
46 + movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */
|
pascal@955
|
47 + /* of bootsect + room for stack + 12 for */
|
pascal@955
|
48 + /* saved disk parm block */
|
pascal@955
|
49
|
pascal@955
|
50 movw $BOOTSEG, %ax
|
pascal@955
|
51 movw %ax,%ds
|
pascal@955
|
52 movw %ax,%es
|
pascal@955
|
53 -
|
pascal@955
|
54 - cli
|
pascal@955
|
55 - movw %ax, %ss /* put stack at BOOTSEG:0x2000. */
|
pascal@955
|
56 + movw %ax,%ss /* put stack at initial position */
|
pascal@955
|
57 movw %di,%sp
|
pascal@955
|
58 - sti
|
pascal@955
|
59
|
pascal@955
|
60 - movw $why_end-why, %cx
|
pascal@955
|
61 - movw $why, %si
|
pascal@955
|
62 +/* Many BIOS's default disk parameter tables will not recognize multi-sector
|
pascal@955
|
63 + * reads beyond the maximum sector number specified in the default diskette
|
pascal@955
|
64 + * parameter tables - this may mean 7 sectors in some cases.
|
pascal@955
|
65 + *
|
pascal@955
|
66 + * Since single sector reads are slow and out of the question, we must take care
|
pascal@955
|
67 + * of this by creating new parameter tables (for the first disk) in RAM. We
|
pascal@955
|
68 + * will set the maximum sector count to 36 - the most we will encounter on an
|
pascal@955
|
69 + * ED 2.88. High doesn't hurt. Low does.
|
pascal@955
|
70 + *
|
pascal@955
|
71 + * Segments are as follows: ds=es=ss=cs - BOOTSEG
|
pascal@955
|
72 + */
|
pascal@955
|
73
|
pascal@955
|
74 - movw $0x0007, %bx /* page 0, attribute 7 (normal) */
|
pascal@955
|
75 - movb $0x0e, %ah /* write char, tty mode */
|
pascal@955
|
76 -prloop:
|
pascal@955
|
77 + xorw %cx,%cx
|
pascal@955
|
78 + movw %cx,%es /* access segment 0 */
|
pascal@955
|
79 + movw $0x78, %bx /* 0:bx is parameter table address */
|
pascal@955
|
80 + pushw %ds /* save ds */
|
pascal@955
|
81 +/* 0:bx is parameter table address */
|
pascal@955
|
82 + ldsw %es:(%bx),%si /* loads ds and si */
|
pascal@955
|
83 +
|
pascal@955
|
84 + movw %ax,%es /* ax is BOOTSECT (loaded above) */
|
pascal@955
|
85 + movb $6, %cl /* copy 12 bytes */
|
pascal@955
|
86 + cld
|
pascal@955
|
87 + pushw %di /* keep a copy for later */
|
pascal@955
|
88 + rep
|
pascal@955
|
89 + movsw /* ds:si is source, es:di is dest */
|
pascal@955
|
90 + popw %di
|
pascal@955
|
91 +
|
pascal@955
|
92 + movb $36,%es:4(%di)
|
pascal@955
|
93 +
|
pascal@955
|
94 + movw %cx,%ds /* access segment 0 */
|
pascal@955
|
95 + xchgw %di,(%bx)
|
pascal@955
|
96 + movw %es,%si
|
pascal@955
|
97 + xchgw %si,2(%bx)
|
pascal@955
|
98 + popw %ds /* restore ds */
|
pascal@955
|
99 + movw %di, dpoff /* save old parameters */
|
pascal@955
|
100 + movw %si, dpseg /* to restore just before finishing */
|
pascal@955
|
101 + pushw %ds
|
pascal@955
|
102 + popw %es /* reload es */
|
pascal@955
|
103 +
|
pascal@955
|
104 +/* Note that es is already set up. Also cx is 0 from rep movsw above. */
|
pascal@955
|
105 +
|
pascal@955
|
106 + xorb %ah,%ah /* reset FDC */
|
pascal@955
|
107 + xorb %dl,%dl
|
pascal@955
|
108 + int $0x13
|
pascal@955
|
109 +
|
pascal@955
|
110 +/* Get disk drive parameters, specifically number of sectors/track.
|
pascal@955
|
111 + *
|
pascal@955
|
112 + * It seems that there is no BIOS call to get the number of sectors. Guess
|
pascal@955
|
113 + * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
|
pascal@955
|
114 + * 15 if sector 15 can be read. Otherwise guess 9.
|
pascal@955
|
115 + */
|
pascal@955
|
116 +
|
pascal@955
|
117 + movw $disksizes, %si /* table of sizes to try */
|
pascal@955
|
118 +
|
pascal@955
|
119 +probe_loop:
|
pascal@955
|
120 lodsb
|
pascal@955
|
121 + orb %al, %al
|
pascal@955
|
122 + je got_sectors /* if all else fails, try 9 */
|
pascal@955
|
123 + cbtw /* extend to word */
|
pascal@955
|
124 + movw %ax, sectors
|
pascal@955
|
125 + xchgw %cx,%ax /* cx = track and sector */
|
pascal@955
|
126 + xorw %dx,%dx /* drive 0, head 0 */
|
pascal@955
|
127 + movw $0x0200, %bx /* address after boot sector */
|
pascal@955
|
128 + /* (512 bytes from origin, es = cs) */
|
pascal@955
|
129 + movw $0x0201, %ax /* service 2, 1 sector */
|
pascal@955
|
130 + int $0x13
|
pascal@955
|
131 + jc probe_loop /* try next value */
|
pascal@955
|
132 +
|
pascal@955
|
133 +got_sectors:
|
pascal@955
|
134 + movw $msg1end-msg1, %cx
|
pascal@955
|
135 + movw $msg1, %si
|
pascal@955
|
136 + call print_str
|
pascal@955
|
137 +
|
pascal@955
|
138 +/* ok, we've written the Loading... message, now we want to load the system */
|
pascal@955
|
139 +
|
pascal@955
|
140 + pushw %es /* = ds */
|
pascal@955
|
141 + movw $SYSSEG, %ax
|
pascal@955
|
142 + movw %ax,%es /* segment of SYSSEG<<4 */
|
pascal@955
|
143 + pushw %es
|
pascal@955
|
144 + call read_it
|
pascal@955
|
145 +
|
pascal@955
|
146 +/* This turns off the floppy drive motor, so that we enter the kernel in a
|
pascal@955
|
147 + * known state, and don't have to worry about it later.
|
pascal@955
|
148 + */
|
pascal@955
|
149 + movw $0x3f2, %dx
|
pascal@955
|
150 + xorb %al,%al
|
pascal@955
|
151 + outb %al,%dx
|
pascal@955
|
152 +
|
pascal@955
|
153 + call print_nl
|
pascal@955
|
154 + pop %es /* = SYSSEG */
|
pascal@955
|
155 + pop %es /* balance push/pop es */
|
pascal@955
|
156 +sigok:
|
pascal@955
|
157 +
|
pascal@955
|
158 +/* Restore original disk parameters */
|
pascal@955
|
159 + movw $0x78, %bx
|
pascal@955
|
160 + movw dpoff, %di
|
pascal@955
|
161 + movw dpseg, %si
|
pascal@955
|
162 + xorw %ax,%ax
|
pascal@955
|
163 + movw %ax,%ds
|
pascal@955
|
164 + movw %di,(%bx)
|
pascal@955
|
165 + movw %si,2(%bx)
|
pascal@955
|
166 +
|
pascal@955
|
167 +/* after that (everything loaded), we call to the .ROM file loaded. */
|
pascal@955
|
168 +
|
pascal@955
|
169 + movw $SYSSEG, %ax
|
pascal@955
|
170 + jmp go_setup_code
|
pascal@955
|
171 +
|
pascal@955
|
172 +/* This routine loads the system at address SYSSEG<<4, making sure no 64kB
|
pascal@955
|
173 + * boundaries are crossed. We try to load it as fast as possible, loading whole
|
pascal@955
|
174 + * tracks whenever we can.
|
pascal@955
|
175 + *
|
pascal@955
|
176 + * in: es - starting address segment (normally SYSSEG)
|
pascal@955
|
177 + */
|
pascal@955
|
178 +read_it:
|
pascal@955
|
179 + movw $0,sread /* read whole image incl boot sector */
|
pascal@955
|
180 + movw %es,%ax
|
pascal@955
|
181 + testw $0x0fff, %ax
|
pascal@955
|
182 +die: jne die /* es must be at 64kB boundary */
|
pascal@955
|
183 + xorw %bx,%bx /* bx is starting address within segment */
|
pascal@955
|
184 +rp_read:
|
pascal@955
|
185 + movw %es,%ax
|
pascal@955
|
186 + movw %bx,%dx
|
pascal@955
|
187 + movb $4, %cl
|
pascal@955
|
188 + shrw %cl,%dx /* bx is always divisible by 16 */
|
pascal@955
|
189 + addw %dx,%ax
|
pascal@955
|
190 +.equ SYSSIZE, _load_size_pgh - 32
|
pascal@955
|
191 + cmpw $SYSSEG+SYSSIZE, %ax /* have we loaded all yet? */
|
pascal@955
|
192 + jb ok1_read
|
pascal@955
|
193 + ret
|
pascal@955
|
194 +ok1_read:
|
pascal@955
|
195 + movw sectors, %ax
|
pascal@955
|
196 + subw sread, %ax
|
pascal@955
|
197 + movw %ax,%cx
|
pascal@955
|
198 + shlw $9, %cx /* 80186 opcode */
|
pascal@955
|
199 + addw %bx,%cx
|
pascal@955
|
200 + jnc ok2_read
|
pascal@955
|
201 + je ok2_read
|
pascal@955
|
202 + xorw %ax,%ax
|
pascal@955
|
203 + subw %bx,%ax
|
pascal@955
|
204 + shrw $9, %ax /* 80186 opcode */
|
pascal@955
|
205 +ok2_read:
|
pascal@955
|
206 + call read_track
|
pascal@955
|
207 + movw %ax,%cx
|
pascal@955
|
208 + addw sread, %ax
|
pascal@955
|
209 + cmpw sectors, %ax
|
pascal@955
|
210 + jne ok3_read
|
pascal@955
|
211 + movw $1, %ax
|
pascal@955
|
212 + subw head, %ax
|
pascal@955
|
213 + jne ok4_read
|
pascal@955
|
214 + incw track
|
pascal@955
|
215 +ok4_read:
|
pascal@955
|
216 + movw %ax, head
|
pascal@955
|
217 + xorw %ax,%ax
|
pascal@955
|
218 +ok3_read:
|
pascal@955
|
219 + movw %ax, sread
|
pascal@955
|
220 + shlw $9, %cx /* 80186 opcode */
|
pascal@955
|
221 + addw %cx,%bx
|
pascal@955
|
222 + jnc rp_read
|
pascal@955
|
223 + movw %es,%ax
|
pascal@955
|
224 + addb $0x10, %ah
|
pascal@955
|
225 + movw %ax,%es
|
pascal@955
|
226 + xorw %bx,%bx
|
pascal@955
|
227 + jmp rp_read
|
pascal@955
|
228 +
|
pascal@955
|
229 +read_track:
|
pascal@955
|
230 + pusha /* 80186 opcode */
|
pascal@955
|
231 + pushw %ax
|
pascal@955
|
232 + pushw %bx
|
pascal@955
|
233 + pushw %bp /* just in case the BIOS is buggy */
|
pascal@955
|
234 + movb $0x2e, %al /* 0x2e = . */
|
pascal@955
|
235 + call print_char
|
pascal@955
|
236 + popw %bp
|
pascal@955
|
237 + popw %bx
|
pascal@955
|
238 + popw %ax
|
pascal@955
|
239 +
|
pascal@955
|
240 + movw sread, %cx
|
pascal@955
|
241 + incw %cx
|
pascal@955
|
242 + movb track, %ch
|
pascal@955
|
243 + movw $0x0100, %dx
|
pascal@955
|
244 + andb head, %dh
|
pascal@955
|
245 + movb $2, %ah
|
pascal@955
|
246 +
|
pascal@955
|
247 + pushw %dx /* save for error dump */
|
pascal@955
|
248 + pushw %cx
|
pascal@955
|
249 + pushw %bx
|
pascal@955
|
250 + pushw %ax
|
pascal@955
|
251 +
|
pascal@955
|
252 + int $0x13
|
pascal@955
|
253 + jc bad_rt
|
pascal@955
|
254 + addw $8, %sp
|
pascal@955
|
255 + popa /* 80186 opcode */
|
pascal@955
|
256 + ret
|
pascal@955
|
257 +
|
pascal@955
|
258 +bad_rt: pushw %ax /* save error code */
|
pascal@955
|
259 + call print_all /* ah = error, al = read */
|
pascal@955
|
260 +
|
pascal@955
|
261 + xorb %ah,%ah
|
pascal@955
|
262 + xorb %dl,%dl
|
pascal@955
|
263 + int $0x13
|
pascal@955
|
264 +
|
pascal@955
|
265 + addw $10, %sp
|
pascal@955
|
266 + popa /* 80186 opcode */
|
pascal@955
|
267 + jmp read_track
|
pascal@955
|
268 +
|
pascal@955
|
269 +/* print_all is for debugging purposes. It will print out all of the registers.
|
pascal@955
|
270 + * The assumption is that this is called from a routine, with a stack frame like
|
pascal@955
|
271 + * dx
|
pascal@955
|
272 + * cx
|
pascal@955
|
273 + * bx
|
pascal@955
|
274 + * ax
|
pascal@955
|
275 + * error
|
pascal@955
|
276 + * ret <- sp
|
pascal@955
|
277 + */
|
pascal@955
|
278 +
|
pascal@955
|
279 +print_all:
|
pascal@955
|
280 + call print_nl /* nl for readability */
|
pascal@955
|
281 + /* print_nl update ah and bx */
|
pascal@955
|
282 + movw $5, %cx /* error code + 4 registers */
|
pascal@955
|
283 + movw %sp,%bp
|
pascal@955
|
284 +
|
pascal@955
|
285 +print_loop:
|
pascal@955
|
286 + pushw %cx /* save count left */
|
pascal@955
|
287 +
|
pascal@955
|
288 + cmpb $5, %cl
|
pascal@955
|
289 + jae no_reg /* see if register name is needed */
|
pascal@955
|
290 +
|
pascal@955
|
291 + movb $0x5+0x41-1, %al
|
pascal@955
|
292 + subb %cl,%al
|
pascal@955
|
293 + int $0x10
|
pascal@955
|
294 +
|
pascal@955
|
295 + movb $0x58, %al /* 'X' */
|
pascal@955
|
296 int $0x10
|
pascal@955
|
297 +
|
pascal@955
|
298 + movb $0x3A, %al /* ':' */
|
pascal@955
|
299 + int $0x10
|
pascal@955
|
300 +
|
pascal@955
|
301 +no_reg:
|
pascal@955
|
302 + addw $2, %bp /* next register */
|
pascal@955
|
303 + call print_hex /* print it */
|
pascal@955
|
304 + movb $0x20, %al /* print a space */
|
pascal@955
|
305 + int $0x10
|
pascal@955
|
306 + popw %cx
|
pascal@955
|
307 + loop print_loop
|
pascal@955
|
308 + /* nl for readability */
|
pascal@955
|
309 +print_nl:
|
pascal@955
|
310 + movb $0xd, %al /* CR */
|
pascal@955
|
311 + call print_char
|
pascal@955
|
312 + movb $0xa, %al /* LF */
|
pascal@955
|
313 + jmp print_char
|
pascal@955
|
314 +
|
pascal@955
|
315 +
|
pascal@955
|
316 +print_str:
|
pascal@955
|
317 +prloop:
|
pascal@955
|
318 + lodsb
|
pascal@955
|
319 + call print_char
|
pascal@955
|
320 loop prloop
|
pascal@955
|
321 -freeze: jmp freeze
|
pascal@955
|
322 + ret
|
pascal@955
|
323 +
|
pascal@955
|
324 +/* print_hex prints the word pointed to by ss:bp in hexadecimal. */
|
pascal@955
|
325 +
|
pascal@955
|
326 +print_hex:
|
pascal@955
|
327 + movw (%bp),%dx /* load word into dx */
|
pascal@955
|
328 + movb $4, %cl
|
pascal@955
|
329 + call print_2digits
|
pascal@955
|
330 +print_2digits:
|
pascal@955
|
331 + call print_digit
|
pascal@955
|
332 +/* fall through */
|
pascal@955
|
333 +print_digit:
|
pascal@955
|
334 + rol %cl,%dx /* rotate to use lowest 4 bits */
|
pascal@955
|
335 + movb $0x0f, %al /* mask for nybble */
|
pascal@955
|
336 + andb %dl,%al
|
pascal@955
|
337 + addb $0x90, %al /* convert al to ascii hex */
|
pascal@955
|
338 + daa /* (four instructions) */
|
pascal@955
|
339 + adcb $0x40, %al
|
pascal@955
|
340 + daa
|
pascal@955
|
341 +print_char:
|
pascal@955
|
342 + movb $0x0e, %ah /* write char, tty mode */
|
pascal@955
|
343 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
|
pascal@955
|
344 + int $0x10
|
pascal@955
|
345 + ret
|
pascal@955
|
346 +
|
pascal@955
|
347 +sread: .word 0 /* sectors read of current track */
|
pascal@955
|
348 +head: .word 0 /* current head */
|
pascal@955
|
349 +track: .word 0 /* current track */
|
pascal@955
|
350 +
|
pascal@955
|
351 +sectors:
|
pascal@955
|
352 + .word 0
|
pascal@955
|
353
|
pascal@955
|
354 -why: .ascii "This image cannot be loaded from a floppy disk.\r\n"
|
pascal@955
|
355 -why_end:
|
pascal@955
|
356 +dpseg: .word 0
|
pascal@955
|
357 +dpoff: .word 0
|
pascal@955
|
358
|
pascal@955
|
359 +disksizes:
|
pascal@955
|
360 + .byte 36,18,15,9,0
|
pascal@955
|
361 +
|
pascal@955
|
362 +msg1:
|
pascal@955
|
363 + .ascii "Loading ROM image"
|
pascal@955
|
364 +msg1end:
|
pascal@955
|
365
|
pascal@955
|
366 .org 497
|
pascal@955
|
367 setup_sects:
|
pascal@955
|
368 @@ -123,14 +426,23 @@
|
pascal@955
|
369 executing the Etherboot image that's loaded at SYSSEG:0 and
|
pascal@955
|
370 whose entry point is SYSSEG:0.
|
pascal@955
|
371 */
|
pascal@955
|
372 -setup_code:
|
pascal@955
|
373 +setup_code:
|
pascal@955
|
374 + movw $(SYSSEG-(PREFIXSIZE/16)), %ax
|
pascal@955
|
375 /* Etherboot expects to be contiguous in memory once loaded.
|
pascal@955
|
376 * LILO doesn't do this, but since we don't need any
|
pascal@955
|
377 * information that's left in the prefix, it doesn't matter:
|
pascal@955
|
378 * we just have to ensure that %cs:0000 is where the start of
|
pascal@955
|
379 * the Etherboot image *would* be.
|
pascal@955
|
380 */
|
pascal@955
|
381 - ljmp $(SYSSEG-(PREFIXSIZE/16)), $run_etherboot
|
pascal@955
|
382 +go_setup_code:
|
pascal@955
|
383 + xorw %cx, %cx
|
pascal@955
|
384 + pushw %cx
|
pascal@955
|
385 + pushw %cx /* No parameters to preserve for exit path */
|
pascal@955
|
386 + pushw %cx /* Use prefix exit path mechanism */
|
pascal@955
|
387 + pushw %ax
|
pascal@955
|
388 + pushw $run_etherboot
|
pascal@955
|
389 + /* Calculated lcall to _start with %cs:0000 = image start */
|
pascal@955
|
390 + lret
|
pascal@955
|
391
|
pascal@955
|
392
|
pascal@955
|
393 .org PREFIXSIZE
|