• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* -----------------------------------------------------------------------
2 *
3 *   Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
4 *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
5 *
6 *   Permission is hereby granted, free of charge, to any person
7 *   obtaining a copy of this software and associated documentation
8 *   files (the "Software"), to deal in the Software without
9 *   restriction, including without limitation the rights to use,
10 *   copy, modify, merge, publish, distribute, sublicense, and/or
11 *   sell copies of the Software, and to permit persons to whom
12 *   the Software is furnished to do so, subject to the following
13 *   conditions:
14 *
15 *   The above copyright notice and this permission notice shall
16 *   be included in all copies or substantial portions of the Software.
17 *
18 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 *   OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * ----------------------------------------------------------------------- */
28
29/*
30 * Modified MBR code used on an ISO image in hybrid mode.
31 *
32 * This doesn't follow the El Torito spec at all -- it is just a stub
33 * loader of a hard-coded offset, but that's good enough to load
34 * ISOLINUX.
35 */
36
37#include "adjust.h"
38
39	.code16
40	.text
41
42HYBRID_MAGIC			= 0x7078c0fb
43isolinux_hybrid_signature	= 0x7c00+64
44isolinux_start_hybrid		= 0x7c00+64+4
45
46	.globl	bootsec
47/* Important: the top 6 words on the stack are passed to isolinux.bin */
48stack		= 0x7c00
49partoffset	= (stack-8)
50driveno		= (stack-14)
51heads		= (stack-16)
52sectors		= (stack-18)
53ebios_flag	= (stack-20)
54secpercyl	= (stack-24)
55
56BIOS_kbdflags	= 0x417
57BIOS_page	= 0x462
58
59	/* gas/ld has issues with doing this as absolute addresses... */
60	.section ".bootsec", "a", @nobits
61	.globl	bootsec
62bootsec:
63	.space	512
64
65	.text
66	.globl	_start
67_start:
68	.byte	0x33, 0xed	/* xorw	%bp, %bp */
69	nop
70	nop
71	nop
72	nop
73	nop
74	nop
75	nop
76	nop
77	nop
78	nop
79	nop
80	nop
81	nop
82	nop
83	nop
84	nop
85	nop
86	nop
87	nop
88	nop
89	nop
90	nop
91	nop
92	nop
93	nop
94	nop
95	nop
96	nop
97	nop
98	nop
99	.byte	0x33, 0xed	/* xorw	%bp, %bp */
100	cli
101	movw	%bp, %ss
102	movw	$stack, %sp
103	sti
104	cld
105
106	/* Check to see if we have a partition table entry */
107	xorl	%ebx, %ebx
108	xorl	%ecx, %ecx
109#ifdef PARTITION_SUPPORT
110	andw	%si, %si		/* %si == 0 -> no partition data */
111	jz	1f
112	testb	$0x7f, (%si)		/* Invalid active flag field? */
113	jnz	1f
114	cmpb	%cl, 4(%si)		/* Partition type zero == invalid? */
115	je	1f
116	cmpl	$0x58504721, %eax	/* !GPT signature in EAX? */
117	jne	2f
118	cmpb	$0xed, 4(%si)		/* EFI partition type? */
119	jne	2f
120
121	/* We have GPT partition information */
122	movl	(32+20)(%si), %ecx
123	movl	(36+20)(%si), %ebx
124	jmp	1f
125
126	/* We have non-GPT partition information */
1272:
128	movl	8(%si), %ecx
129#endif
1301:
131	/* We have no partition information */
132	pushl	%ebx			/*  -4: partoffset_hi */
133	pushl	%ecx			/*  -8: partoffset_lo */
134	pushw	%es			/* -10: es:di -> $PnP header */
135	pushw	%di			/* -12: es:di -> $PnP header */
136
137	movw	%bp, %ds
138	movw	%bp, %es
139
140	ADJUST_DRIVE
141	pushw	%dx			/* -14: dl -> drive number */
142
143	/* Copy down to 0:0x600 */
144	movw	$0x7c00, %si
145	movw	$_start, %di
146	movw	$(512/2), %cx
147	rep; movsw
148
149	ljmpw	$0, $next
150next:
151
152	/* Check to see if we have EBIOS */
153	pushw	%dx		/* drive number */
154	movb	$0x41, %ah	/* %al == 0 already */
155	movw	$0x55aa, %bx
156	xorw	%cx, %cx
157	xorb	%dh, %dh
158	stc
159	int	$0x13
160	jc	1f
161	cmpw	$0xaa55, %bx
162	jne	1f
163	andw	$1,%cx		/* Bit 0 = fixed disk subset */
164	jz	1f
165
166	/* We have EBIOS; patch in the following code at
167	   read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
168	movl	$0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
169		(read_sector_cbios)
170	jmp	1f
1711:
172	popw	%dx
173	pushw	%cx		/* EBIOS flag */
174
175	/* Get (C)HS geometry */
176	movb	$0x08, %ah
177	int	$0x13
178	andw	$0x3f, %cx	/* Sector count */
179	popw	%bx		/* EBIOS flag */
180	pushw	%cx		/* -16: Save sectors on the stack */
181	movzbw	%dh, %ax	/* dh = max head */
182	incw	%ax		/* From 0-based max to count */
183	pushw	%ax		/* -18: Save heads on the stack */
184	mulw	%cx		/* Heads*sectors -> sectors per cylinder */
185
186	pushw	%bx		/* -20: EBIOS flag */
187
188	/* Save sectors/cylinder on the stack */
189	pushw	%dx		/* -22: High word */
190	pushw	%ax		/* -24: Low word */
191
192	/*
193	 * Load sectors.  We do this one at a time mostly to avoid
194	 * pitfalls and to share code with the stock MBR code.
195	 */
196	movw	$0x7c00, %bx
197	movw	$4, %cx		/* Sector count */
198	movl	(lba_offset), %eax
199
2002:
201	call	read_sector
202	jc	disk_error
203	incl	%eax
204	addb	$(512 >> 8), %bh
205	loopw	2b
206
207	/*
208	 * Okay, that actually worked... update the stack pointer
209	 * and jump into isolinux.bin...
210	 */
211	cmpl	$HYBRID_MAGIC,(isolinux_hybrid_signature)
212	jne	bad_signature
213
214	cli
215	movw	$ebios_flag, %sp
216
217	/*
218	 * Use a ljmpw here to work around a bug in some unknown version
219	 * of gas or ld when it comes to jumping to an absolute symbol...
220	 *
221	 * Look more closely into it if we ever are short on space.
222	 */
223	ljmpw	$0, $isolinux_start_hybrid
224
225bad_signature:
226	call	error
227	.ascii	"isolinux.bin missing or corrupt.\r\n"
228
229/*
230 * read_sector: read a single sector pointed to by %eax to %es:%bx.
231 * CF is set on error.  All registers saved.
232 */
233read_sector:
234	pushal
235	xorl	%edx, %edx
236	addl	(partoffset), %eax
237	adcl	(partoffset+4), %edx
238	pushl	%edx	/* MSW of LBA */
239	pushl	%eax	/* LSW of LBA */
240	pushw	%es	/* Buffer segment */
241	pushw	%bx	/* Buffer offset */
242	pushw	$1	/* Sector count */
243	pushw	$16	/* Size of packet */
244	movw	%sp, %si
245
246	/* This chunk is skipped if we have ebios */
247	/* Do not clobber %eax before this chunk! */
248	/* This also relies on %bx and %edx as set up above. */
249read_sector_cbios:
250	divl	(secpercyl)
251	shlb	$6, %ah
252	movb	%ah, %cl
253	movb	%al, %ch
254	xchgw	%dx, %ax
255	divb	(sectors)
256	movb	%al, %dh
257	orb	%ah, %cl
258	incw	%cx	/* Sectors are 1-based */
259	movw	$0x0201, %ax
260
261read_common:
262	movb	(driveno), %dl
263	int	$0x13
264	leaw	16(%si), %sp	/* Drop DAPA */
265	popal
266	ret
267
268disk_error:
269	call	error
270	.ascii	"Operating system load error.\r\n"
271
272/*
273 * Print error messages.  This is invoked with "call", with the
274 * error message at the return address.
275 */
276error:
277	popw	%si
2782:
279	lodsb
280	movb	$0x0e, %ah
281	movb	(BIOS_page), %bh
282	movb	$0x07, %bl
283	int	$0x10		/* May destroy %bp */
284	cmpb	$10, %al	/* Newline? */
285	jne	2b
286
287	int	$0x18		/* Boot failure */
288die:
289	hlt
290	jmp	die
291
292	/* Address of pointer to isolinux.bin */
293lba_offset = _start+432
294