Merge from Etherboot 5.4
[people/xl0/gpxe-arm.git] / src / arch / i386 / prefix / hdprefix.S
1 /****************************************************************\
2
3 hdprefix.S Copyright (C) 2005 Per Dalgas Jakobsen
4
5 This code has been inspired/derived by the OSLoader by Vladislav Aleksandrov.
6 http://www.programmersheaven.com/zone5/cat469/40546.htm.
7
8 This software may be used and distributed according to the terms
9 of the GNU Public License (GPL), incorporated herein by reference.
10
11 hdprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines.
12
13 Actions performed by hdprefix:
14 1) Load the MBR to LOADSEG:0
15 2) Check which partition is active (or try first partition if none active)
16 3) Check wether LBA is supported.
17 3a) LBA
18 3a1) Load PAYLOAD_SECTS sectors from chosen partition to LOADSEG:0
19 3b) CHS (standard)
20 3b1) Load PAYLOAD_SECTS sectors from chosen partition to LOADSEG:0
21 4) Check loaded bootsector for BOOTMAGIC code.
22 5) Jump to payload LOADSEG:ENTRYPOINT.
23
24 Output with failure points (!#):
25 ---
26 Loading (!1)partition #
27 Std. BIOS(!2) | Ext. BIOS(!3)
28 Booting...(!4)
29 (!5)
30 ---
31
32 !1: Failed to load MBR with Int13,ah=2.
33 !2: Failed to load bootrecord+payload with Int13,ah=2.
34 !3: Failed to load bootrecord+payload with Int13,ah=42.
35 !4: Invalid BOOTMAGIC in loaded bootrecord.
36 !5: Jumping to payload.
37
38 \*****************************************************************/
39  
40 .equ    BOOTSEG,        0x07c0
41 .equ    LOADSEG,        0x1000
42 .equ    ENTRYPOINT,     _start
43
44 .equ    BOOTMAGIC,      0x0aa55
45
46 .equ    partition_table,        0x1be
47 .equ    partition_rec_size,     0x10
48
49 .equ    boot_ind,       0       /* 80h=active */
50 .equ    start_head,     1
51 .equ    start_sector,   2       /* bits 0-5 */
52 .equ    start_cyl,      3       /* bits 8,9 in bits 6,7 of sector */
53 .equ    os_ind,         4       /* os indicator */
54 .equ    end_head,       5
55 .equ    end_sector,     6       /* bits 0-5 */
56 .equ    end_track,      7       /* bits 8,9 in bits 6,7 of sector */
57 .equ    nsect,          8       /* sectors preceding partition */
58 .equ    lenght,         0x0c    /* length of partition in sectors */
59
60 /-------------------------------------------------------------
61
62         .arch i386
63         .text
64         .section ".prefix", "ax", @progbits
65         .code16
66          
67 bootstart:
68         jmp     $BOOTSEG,$_go           /* reload cs:ip */
69
70
71 /****************************************************************/
72 /* support routines.                                            */
73 /*--------------------------------------------------------------*/
74 _failed:
75         movw    $BOOTSEG,%ax
76         movw    %ax,%ds
77         movw    $_failed_msg_end-_failed_msg,%cx
78         movw    $_failed_msg,%si
79         call    _print_str
80
81         /* stop execution - should probably have option to auto-reboot after delay. */
82 _failed_loop:
83         jmp     _failed_loop
84
85 /*--------------------------------------------------------------*/
86 _print_str:
87         /* cx = count, ds:si = string. */
88         movw    $0x0007,%bx
89         movb    $0x0e,%ah
90 _print_loop:
91         lodsb
92         int     $0x10
93         loop    _print_loop
94         ret
95
96 /*--------------------------------------------------------------*/                      
97 _print_char:
98         /* al = char. */
99         movw    $0x0007,%bx
100         movb    $0x0e,%ah
101         int     $0x10
102         ret
103
104 /*--------------------------------------------------------------*/
105 _print_nl:
106         /* - */
107         movb    $0x0d,%al
108         call    _print_char
109         movb    $0x0a,%al
110         call    _print_char
111         ret
112
113 /*--------------------------------------------------------------*/
114 _print_hex:
115         /* dx = value */
116         movb    $0x0e,%ah       /* write char, tty mode */
117         movw    $0x0007,%bx     /* page 0, attribute 7 (normal) */
118         call    _print_digit
119         call    _print_digit
120         call    _print_digit
121         /* fall through */
122 _print_digit:
123         rolw    $4,%dx          /* rotate so that lowest 4 bits are used */
124         movb    $0x0f,%al       /* mask for nibble */
125         andb    %dl,%al
126         addb    $0x90,%al       /* convert al to ascii hex (four instructions) */
127         daa
128         adcb    $0x40,%al
129         daa
130         int     $0x10
131         ret
132
133 /****************************************************************/
134
135
136 _go:
137         cli
138         movw    $BOOTSEG,%ax
139         movw    %ax,%ds
140         movw    %ax,%ss
141         movw    $0x2000,%sp     /* good large stack. */
142         sti
143         cld
144         movw    $LOADSEG,%ax
145         movw    %ax,%es
146
147         movw    $_load_msg_end-_load_msg,%cx
148         movw    $_load_msg,%si
149         call    _print_str
150
151 /*--- load MBR so we can use its partition table. ---*/
152         xorw    %bx,%bx
153         movw    $0x0001,%cx     /* chs: 0,0,1 */
154         movb    %bh,%dh         /* - */
155         movb    $0x80,%dl
156         movw    $0x0201,%ax     /* read one sector (MBR) */
157         int     $0x13
158         jc      _failed
159
160 /*--- find the active partition ---*/
161         movw    $_part_msg_end-_part_msg,%cx
162         movw    $_part_msg,%si
163         call    _print_str
164
165         movw    $partition_table,%di
166         movw    $4,%cx
167 _partition_loop:
168         cmpb    $0x80,%es:(%di)         /* active? */
169         je      _partition_found
170         addw    $partition_rec_size,%di
171         loop    _partition_loop
172
173         /*- no partitions marked active - use 1. partition. */
174         movw    $partition_table,%di
175         movw    $4,%cx
176
177 _partition_found:
178         movb    $'5',%al                        /* convert to ascii */
179         subb    %cl,%al
180         call    _print_char
181         call    _print_nl
182
183 /*--- check for lba support ---*/
184         movw    $0x55aa,%bx
185         movb    $0x80,%dl
186         movb    $0x41,%ah
187         int     $0x13
188         jc      __bios
189         cmpw    $0x0aa55,%bx
190         jnz     __bios
191         testb   $1,%cl
192         jz      __bios
193
194 /*--- use lba bios calls to read sectors ---*/
195 _lba:
196         movw    $_extbios_msg_end-_extbios_msg,%cx
197         movw    $_extbios_msg,%si
198         call    _print_str
199
200         movw    %es:nsect(%di),%ax
201         movw    %ax,_bios_lba_low
202         movw    %es:nsect+2(%di),%ax
203         movw    %ax,_bios_lba_high
204         movb    $0x80,%dl
205         movw    $_disk_address_packet,%si
206         movw    $0x4200,%ax     /* read */
207         int     $0x13
208         jc      _failed
209         jmp     __loaded
210
211 /*--- use standard bios calls to read sectors ---*/
212 __bios:
213         movw    $_stdbios_msg_end-_stdbios_msg,%cx
214         movw    $_stdbios_msg,%si
215         call    _print_str
216
217         movw    _disk_address_packet+2(,1),%ax  /* only low byte is used. */
218         xorw    %bx,%bx
219         movw    %es:start_sector(%di),%cx
220         movb    %es:start_head(%di),%dh
221         movb    $0x80,%dl
222         movb    $0x02,%ah
223         int     $0x13
224         jc      _failed
225
226 __loaded:
227         movw    $_boot_msg_end-_boot_msg,%cx
228         movw    $_boot_msg,%si
229         call    _print_str
230
231         /* check if it has a valid bootrecord. */
232         cmpw    $BOOTMAGIC,%es:510(,1)
233         jne     _failed
234         call    _print_nl
235
236         /* call the payload. */
237         pushl   $0              /* No parameters to preserve for exit path */
238         pushw   $0              /* Use prefix exit path mechanism */
239         jmp     $LOADSEG,$ENTRYPOINT
240
241         .section ".text16", "ax", @progbits
242         .globl  prefix_exit
243 prefix_exit:
244         int     $0x19           /* should try to boot machine */
245         .globl  prefix_exit_end
246 prefix_exit_end:
247         .previous
248          
249
250 /*--------------------------------------------------------------*/
251
252 _load_msg:      .ascii  "Loading "
253 _load_msg_end:
254 _part_msg:      .ascii  "partition "
255 _part_msg_end:
256 _boot_msg:      .ascii  "Booting..."
257 _boot_msg_end:
258 _stdbios_msg:   .ascii  "Std. BIOS\r\n"
259 _stdbios_msg_end:
260 _extbios_msg:   .ascii  "Ext. BIOS\r\n"
261 _extbios_msg_end:
262 _failed_msg:    .ascii  "FAILED!!!\r\n"
263 _failed_msg_end:
264
265
266 /*--------------------------------------------------------------*/
267
268 _disk_address_packet:
269                 .byte   0x10            /* size of the packet */
270                 .byte   0               /* reserved */
271                 .word   _verbatim_size_sct      /* number of sectors to read */
272                 .word   0x0000          /* offset */
273                 .word   LOADSEG         /* segment of buffer */
274 _bios_lba_low:  .word   0
275 _bios_lba_high: .word   0
276                 .word   0
277                 .word   0
278
279         .rept 32
280                 .byte   0
281         .endr
282
283
284 /*--- Partition table ------------------------------------------*/
285
286         .org 446, 0
287         .rept 64
288                 .byte   0
289         .endr
290
291
292 /*--- Magic code -----------------------------------------------*/
293         .org 510, 0
294                 .word BOOTMAGIC
295
296 /*** END ********************************************************/