Core integer types header file reorganization stage 1/2: Create and/or modify
[dragonfly.git] / sys / i386 / boot / biosboot / start.S
1 /*
2  * Mach Operating System
3  * Copyright (c) 1992, 1991 Carnegie Mellon University
4  * All Rights Reserved.
5  * 
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  * 
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  * 
16  * Carnegie Mellon requests users of this software to return to
17  * 
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  * 
23  * any improvements or extensions that they make and grant Carnegie Mellon
24  * the rights to redistribute these changes.
25  *
26  *      from: Mach, Revision 2.2  92/04/04  11:36:29  rpd
27  * $FreeBSD: src/sys/i386/boot/biosboot/start.S,v 1.13 1999/08/28 00:43:14 peter Exp $
28  * $DragonFly: src/sys/i386/boot/biosboot/Attic/start.S,v 1.2 2003/06/17 04:28:34 dillon Exp $
29  */
30
31 /*
32   Copyright 1988, 1989, 1990, 1991, 1992 
33    by Intel Corporation, Santa Clara, California.
34
35                 All Rights Reserved
36
37 Permission to use, copy, modify, and distribute this software and
38 its documentation for any purpose and without fee is hereby
39 granted, provided that the above copyright notice appears in all
40 copies and that both the copyright notice and this permission notice
41 appear in supporting documentation, and that the name of Intel
42 not be used in advertising or publicity pertaining to distribution
43 of the software without specific, written prior permission.
44
45 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
46 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
47 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
48 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
49 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
50 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
51 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
52 */
53 #include        "asm.h"
54
55         .file   "start.S"
56
57 SIGNATURE=      0xaa55
58 LOADSZ=         15      /* size of unix boot */
59 PARTSTART=      0x1be   /* starting address of partition table */
60 NUMPART=        4       /* number of partitions in partition table */
61 PARTSZ=         16      /* each partition table entry is 16 bytes */
62 BSDPART=        0xA5    /* value of boot_ind, means bootable partition */
63 BOOTABLE=       0x80    /* value of boot_ind, means bootable partition */
64 NAMEBLOCKMAGIC= 0xfadefeed /* value of magicnumebr for block2   */
65
66 /*
67  * This DEBUGMSG(msg) macro may be useful for debugging.  Its use is
68  * restricted to this file since it only works in real mode.
69  */
70 #define DEBUGMSG(msg)           \
71         data32                  ; \
72         mov     $msg, %esi      ; \
73         data32                  ; \
74         call    message
75
76         .text   
77
78 ENTRY(boot1)
79
80         /*
81          * XXX I have encountered at least one machine (a no-name laptop
82          * with an AMI WinBIOS) that will refuse to run the bootblock
83          * unless this short jump and nop are here. I'm not certain, but
84          * this may be a case of the BIOS performing some kind of simple
85          * virus detection.
86          */
87         jmp pacify_braindead_bios
88         nop
89 pacify_braindead_bios:
90
91         /*
92          * start (aka boot1) is loaded at 0x0:0x7c00 but we want 0x7c0:0
93          * ljmp to the next instruction to adjust %cs
94          */
95         data32
96         ljmp $0x7c0, $start
97
98 start:
99         /* set up %ds */
100         mov     %cs, %ax
101         mov     %ax, %ds
102
103         /* set up %ss and %esp */
104         data32
105         mov     $BOOTSEG, %eax
106         mov     %ax, %ss
107         /*
108          * make a little room on the stack for
109          * us to save the default bootstring we might find..
110          * effectively, we push the bootstring.
111          */
112         data32
113         mov     $BOOTSTACK-64, %esp
114
115         /* set up %es, (where we will load boot2 to) */
116         mov     %ax, %es
117
118
119         /* bootstrap passes us drive number in %dl */
120         cmpb    $0x80, %dl
121         data32
122         jae     hd
123
124 fd:
125         /*
126          * XXX some bootstraps don't pass the drive number in %dl.
127          * This is a problem mainly when we are block 0 on a floppy.
128          * Force drive 0 for floppies.
129          * XXX %dl was assumed valid in the test that led here.
130          */
131         mov     $0x0, %dl
132
133         /* reset the disk system */
134         movb    $0x0, %ah
135         int     $0x13
136         data32
137         mov     $0x0001, %ecx   /* cyl 0, sector 1 */
138         movb    $0, %dh         /* head */
139         data32
140         jmp     load
141
142 hd:     /**** load sector 0 into the BOOTSEG ****/
143         data32
144         mov     $0x0201, %eax
145         xor     %ebx, %ebx      /* %bx = 0 */
146         data32
147         mov     $0x0001, %ecx
148         data32
149         andl    $0xff, %edx
150         /*mov   $0x0080, %edx*/
151         int     $0x13
152         data32
153         jb      read_error
154
155         /* find the first 386BSD partition */
156         data32
157         mov     $PARTSTART, %ebx
158         data32
159         mov     $NUMPART, %ecx
160 again:
161         addr32
162         movb    %es:4(%ebx), %al
163         cmpb    $BSDPART, %al
164         data32
165         je      found
166         data32
167         add     $PARTSZ, %ebx
168         data32
169         loop    again
170         data32
171         mov     $enoboot, %esi
172         data32
173         jmp     err_stop
174
175
176 /*
177  * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
178  *      Call with       %ah = 0x2
179  *                      %al = number of sectors
180  *                      %ch = cylinder
181  *                      %cl = sector
182  *                      %dh = head
183  *                      %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
184  *                      %es:%bx = segment:offset of buffer
185  *      Return:
186  *                      %al = 0x0 on success; err code on failure
187  */
188
189 found:
190         addr32
191         movb    %es:1(%ebx), %dh /* head */
192         addr32
193         movl    %es:2(%ebx), %ecx /*sect, cyl (+ 2 bytes junk in top word) */
194
195 load:
196 #ifdef NAMEBLOCK
197 /*
198  * Load the second sector and see if it is a boot instruction block.
199  * If it is then scan the contents for the first valid string and copy it to 
200  * the location of the default boot string.. then zero it out.
201  * Finally write the block back to disk with the zero'd out entry..
202  * I hate writing at this stage but we need this to be persistant.
203  * If the boot fails, then the next boot will get the next string.
204  * /etc/rc will regenerate a complete block2 iff the boot succeeds.
205  *
206  * Format of block 2 is:
207  * [NAMEBLOCKMAGIC] <--0xdeafc0de
208  * [nulls]
209  * [bootstring]NULL  <---e.g. 0:wd(0,a)/kernel.experimental
210  * [bootstring]NULL  <---e.g. 0:wd(0,a)/kernel.old
211  * ....
212  * [bootstring]NULL  <---e.g. 0:wd(0,f)/kernel
213  * FF FF FF
214  */
215 where:
216         /*
217          * save things we might smash
218          * (that are not smashed immedatly after us anyway.)
219          */
220         data32
221         push    %ecx    /* preserve 'cyl,sector ' */
222         data32
223         push    %edx
224 /* 
225  * Load the second sector
226  * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
227  *      Call with       %ah = 0x2
228  *                      %al = number of sectors
229  *                      %ch = cylinder
230  *                      %cl = sector
231  *                      %dh = head
232  *                      %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
233  *                      %es:%bx = segment:offset of buffer
234  *      Return:
235  *                      %al = 0x0 on success; err code on failure
236  */
237         data32
238         movl    $0x0201, %eax   /function 2 (read) 1 sector */
239         xor     %ebx, %ebx      /* %bx = 0 */ /* buffer address (ES:0) */
240         data32
241         movl    $0x0002, %ecx   /* sector 2, cylinder 0 */
242         data32
243         andl    $0x00ff, %edx   /* head 0, drive N */
244         int     $0x13
245         data32
246         jb      read_error
247         /*
248          * confirm that it is one for us
249          */
250         data32
251         xorl    %ebx, %ebx      /* magic number at start of buffer */
252         data32
253         addr32
254         movl    %es:(%ebx), %eax
255         data32
256         cmpl    $NAMEBLOCKMAGIC, %eax
257         data32
258         jne     notours         /* not ours so return to caller */
259         /*
260          * scan for a bootstring
261          * Skip the magic number, and scan till we find a non-null,
262          * or a -1
263          */
264         incl    %ebx    /* quicker and smaller */
265         incl    %ebx
266         incl    %ebx
267 scan:
268         incl    %ebx
269         addr32
270         movb    %es:(%ebx), %al /* load the next byte */
271         testb   %al, %al        /* and if it is null */
272         data32                  /* keep scanning (past deleted entries) */
273         jz scan
274         incb    %al             /* now look for -1 */
275         data32
276         jz      notours         /* if we reach the 0xFF then we have finished */
277
278         /*
279          * save our settings.. we need them twice..
280          */
281         data32
282         push    %ebx
283         /*
284          * copy it to the default string location
285          * which is just above the stack for 64 bytes.
286          */
287         data32
288         movl    $BOOTSTACK-64, %ecx     /* 64 bytes at the top of the stack */
289 nxtbyte:
290         addr32
291         movb    %es:(%ebx), %al /* get the next byte in */
292         addr32
293         movb    %al, %es:(%ecx) /* and transfer it to the name buffer */
294         incl    %ebx            /* get on with the next byte */
295         incl    %ecx            /* get on with the next byte */
296         testb   %al, %al        /* if it was 0 then quit this */
297         data32
298         jnz nxtbyte             /* and looop if more to do */ 
299         
300         /*
301          * restore the saved settings and
302          * zero it out so next time we don't try it again
303          */
304         data32
305         pop     %ebx            /* get back our starting location */
306 #ifdef  NAMEBLOCK_WRITEBACK
307 nxtbyte2:
308         addr32
309         movb    %es:(%ebx), %al /* get the byte */
310         addr32
311         movb    $0,  %es:(%ebx) /* zero it out */
312         data32
313         incl    %ebx            /* point to the next byte */
314         testb   %al, %al        /* check if we have finished.. */
315         data32
316         jne nxtbyte2
317 /* 
318  * Write the second sector back
319  * Load the second sector
320  * BIOS call "INT 0x13 Function 0x3" to write sectors from memory to disk
321  *      Call with       %ah = 0x3
322  *                      %al = number of sectors
323  *                      %ch = cylinder
324  *                      %cl = sector
325  *                      %dh = head
326  *                      %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
327  *                      %es:%bx = segment:offset of buffer
328  *      Return:
329  *                      %al = 0x0 on success; err code on failure
330  */
331         data32
332         movl    $0x0301, %eax   /* write 1 sector */
333         xor     %ebx, %ebx      /* buffer is at offset 0 */ 
334         data32
335         movl    $0x0002, %ecx   /* block 2 */
336         data32
337         andl    $0xff, %edx     /* head 0 */
338         int     $0x13
339         data32
340         jnb     notours
341         data32
342         mov     $eread, %esi
343         jmp     err_stop
344 #endif  /* NAMEBLOCK_WRITEBACK */
345         /*
346          * return to the main-line
347          */
348 notours:
349         data32
350         pop     %edx
351         data32
352         pop     %ecx
353 #endif
354         movb    $0x2, %ah       /* function 2 */
355         movb    $LOADSZ, %al    /* number of blocks */
356         xor     %ebx, %ebx      /* %bx = 0, put it at 0 in the BOOTSEG */
357         int     $0x13
358         data32
359         jb      read_error
360
361         /*
362          * ljmp to the second stage boot loader (boot2).
363          * After ljmp, %cs is BOOTSEG and boot1 (512 bytes) will be used
364          * as an internal buffer "intbuf".
365          */
366
367         data32
368         ljmp    $BOOTSEG, $ EXT(boot2)
369
370 /*
371  * read_error
372  */
373 read_error:
374         data32
375         mov     $eread, %esi
376 err_stop:
377         data32
378         call    message
379         data32
380         jmp     stop
381
382 /*
383  * message: write the error message in %ds:%esi to console
384  */
385 message:
386         /*
387          * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
388          *      %ah = 0xe       %al = character
389          *      %bh = page      %bl = foreground color (graphics modes)
390          */
391
392         data32
393         push    %eax
394         data32
395         push    %ebx
396         data32
397         mov     $0x0001, %ebx
398         cld
399
400 nextb:
401         lodsb                   /* load a byte into %al */
402         cmpb    $0x0, %al
403         data32
404         je      done
405         movb    $0xe, %ah
406         int     $0x10           /* display a byte */
407         data32
408         jmp     nextb
409 done:
410         data32
411         pop     %ebx
412         data32
413         pop     %eax
414         data32
415         ret
416
417 stop:   hlt
418         data32
419         jmp     stop            /* halt doesnt actually halt forever */
420
421 /* error messages */
422
423
424 #ifdef  DEBUG
425 one:    String          "1-\0"
426 two:    String          "2-\0"
427 three:  String          "3-\0"
428 four:   String          "4-\0"
429 #endif  DEBUG
430 #ifdef  NAMEBLOCK_WRITEBACK
431 ewrite: String          "Write error\r\n\0"
432 #endif  /* NAMEBLOCK_WRITEBACK */
433 eread:  String          "Read error\r\n\0"
434 enoboot: String         "No bootable partition\r\n\0"
435 endofcode:
436 /*
437  * Dummy partition table in case we are block 0.  The ending c/h/s values
438  * of the non-null partition are almost arbitary.  The length of this
439  * partition is bogus for backwards compatibility and as a signature.
440  * A real partition table shouldn't be as weird and broken as this one,
441  * and the isa slice initialization routine interprets this table as
442  * saying that the whole disk is used for FreeBSD.
443  */
444 /* flag, head, sec, cyl, typ, ehead, esect, ecyl, start, len */
445         . = EXT(boot1) + PARTSTART
446 strttbl:
447         .byte 0x0,0,0,0,0,0,0,0
448         .long 0,0
449         .byte 0x0,0,0,0,0,0,0,0
450         .long 0,0
451         .byte 0x0,0,0,0,0,0,0,0
452         .long 0,0
453         .byte BOOTABLE,0,1,0,BSDPART,255,255,255
454         .long 0,50000
455 /* the last 2 bytes in the sector 0 contain the signature */
456         . = EXT(boot1) + 0x1fe
457         .value  SIGNATURE
458 ENTRY(disklabel)
459         . = EXT(boot1) + 0x400