File: mbr.S

package info (click to toggle)
lilo 1%3A23.2-4
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 3,368 kB
  • sloc: ansic: 13,187; asm: 10,441; perl: 1,095; sh: 989; makefile: 582
file content (498 lines) | stat: -rw-r--r-- 9,646 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
;  mbr.S -- Master Boot Record to boot first partition marked active
;
; Copyright 2002-2004 John Coffman.
; All rights reserved.
;
; Licensed under the terms contained in the file 'COPYING' in the 
; source directory.
;

/* set to 1 for debugging output */
#define DEBUG 0

#define SEARCH 1		/* turn on search for device code */
#define CYL1023 0		/* 1==compare to 1023 / 0==fn8 cyl #    */
#define PASS_PARAMS 1		/* 1==pass lilo parameters */
#define BYPASS18 0		/* bypass int 18h exit */

#ifdef MBX
# define EXT_PART 1		/* search extended partitions, too */
/*# define VIDEO_ENABLE		/ we just have no space for this */
# define VIDEO_ENABLE		/* we now do have space for this */
#else
# define EXT_PART 0		/* search primary partition only */
# define VIDEO_ENABLE
#endif

DELAY	= 12			/* tenths of a second */

#if DEBUG
STEP	= 1			/* delay is in seconds if DEBUG */
# ifdef VIDEO_ENABLE
/*#  undef VIDEO_ENABLE*/
# endif
#else
STEP	= 10			/* delay is in deciseconds if not DEBUG */
#endif

#define LILO_ASM
#include "lilo.h"


	.text

	.globl	_main

	.org	PARTS_LOAD

zero:
_main:	cli			! NT 4 blows up if this is missing
	jmp	start

#if EXT_PART
stage:	.byte	STAGE_MBR2	! search extended partitions, too
#else
stage:	.byte	STAGE_MBR	! search primary parition only
#endif

	.org	PARTS_LOAD+6
sig:	.ascii	"LILO"		! signature
vers:	.word	VERSION

! the disk I/O packet	DS:SI uses it
packet:	.word	16		! size of packet
	.word	1		! count of sectors to transfer
addr:	.word	BOOTSEG*16	! address offset to transfer to
	.word	0		! address segment to transfer to
daddr:	.long	0		! low order disk address
	.long	0		! high order disk address
! end of packet


	
#if DEBUG
#if !SEARCH
dout:	push	ax		! save low half
	shr	eax,#16
	call	wout		! put out high word
	pop	ax
wout:	push	ax
	xchg	ah,al		! put out AH first
	call	bout
	pop	ax		! restore AL
#endif
bout:	push	ax		! convert & output hex byte in AL
	shr	al,#4		! high nibble
	call	nout
	pop	ax		! low nibble
nout:	and	al,#0x0F	! write the nibble in low half of AL
	daa			! convert to upper case hex character
	add	al,#0xF0	! **
	adc	al,#0x40	! **
cout:	push	bx		! write character to the console
	mov	ah,#0x0E	! video BIOS function 14
	mov	bh,#0
	int	0x10		! video interrupt
	pop	bx
	ret
#endif

say:	pop	si		! get CS:SI pointer to character string
say1:	lodsb			! but DS==CS, so this works
	or	al,al		! NUL terminated?
	jz	say9
#if DEBUG
	call	cout
#else
	mov	ah,#0x0E	! in-line character write routine
	mov	bx,#07		! write to page 0
	int	0x10		! video interrupt
#endif
	jmp	say1
say9:
#if DEBUG
	jmp	si		! return from "say:"
#endif
stop:
#if DEBUG
	hlt			! wait for interrupt
	jmp	stop		! loop back after interrupt
#else
#if BYPASS18
	xor	eax,eax		! EXPERIMENTAL code
	mov	[daddr],eax	! zero the disk address
	inc	dx		! try the next device code
	call	disk_read	! read sector 0
	jmpi	(addr)
#else
	mov	cx,#DELAY*16/STEP  ! delay DELAY/10 seconds, DX doesn't matter

	mov	ah,#0x86
	int	0x15		! delay call

	int	0x18		! exit to BIOS

#endif	/* BYPASS18 */
#endif	/* DEBUG */

start:
	xor	ax,ax			! all addressing from 0000:0000
	mov	ss,ax			! set up the stack
	mov	sp,#BOOTSEG*16		! #0x7C00
	sti				! enable interrupts
#if PASS_PARAMS
	mov	cx,sp
	push	es
	push	bx
	push	si
	push	dx
	mov	si,cx
#else
	mov	si,sp			! from here 0000:7C000
#endif
	cld				! clear direction flag (UP)
	mov	ds,ax			! DS=0
	mov	es,ax			! ES=0
	mov	di,#PARTS_LOAD		! move to here 0000:0600
	mov	cx,#SECTOR_SIZE/2	! one sector worth
	rep
	  movsw				! move words
	jmpi	go,0			! intersegment jump 0:go
go:
#ifdef VIDEO_ENABLE
	pusha			! certain video cards trash DX
#if 0
	mov	al,[0x449]		! get video mode
	cbw
#else
	mov	ax,#0x1200	! enable video (VGA)
	mov	bl,#0x36	! (probably a nop on EGA or MDA)
#endif
	int	0x10		! 

	popa			! DX must be protected from rogue video cards
#endif

#if SEARCH
	mov	edi,[serial_no]		! serial number to look for
	or	edi,edi
	jz	use_boot

	mov	ah,#8		! get number of hard drives
	mov	dl,#0x80
	int	0x13
	movzx	cx,dl

	xchg	ax,dx		! save device code in AX
	mov	dx,#0x80	! device 80

vagain:
	call	disk_read	

	cmp	edi,[BOOTSEG*16+PART_TABLE_OFFSET-6]
	je	vol_found
	inc	dx		! try next device
	loop	vagain

	xchg	ax,dx		! try what we were passed

vol_found:
use_boot:

#endif

#if DEBUG
	call	say			! debugging dump of DL
	.ascii	"DL="
	.byte	0
	mov	ax,dx
	call	bout			! write the byte in AL
#if !SEARCH
	mov	al,#0x20
	call	cout
	mov	eax,[serial_no]		! serial number to look for
	call	dout
#endif
	call	say
	.byte	13,10,0
#endif	
	mov	si,#p_table		! scan the partition table 
#if EXT_PART
	xor	edi,edi			! BASE = 0
#endif
	mov	cx,#4			! 4 entries
find_active:
#if EXT_PART
	call	is_ext			! test for extended
#endif
	test	byte ptr (si),#0x80	! test hi-bit
	mov	bp,si			! save possible ptr
	js	one_found		! found Active if sign bit set
	add	si,#16			! move to next entry
	loop	find_active		! & loop back

#if EXT_PART
/* no primary partition was marked active */
	xchg	edi,ebp			! EBP = base, EDI = second
	xor	edi,edi

/* extended partitions exist, search them */
ext_search:
	add	edi,ebp			! second += base
	mov	[daddr],edi
	call	disk_read
	mov	si,#BOOTSEG*16+PART_TABLE_OFFSET	! pt[0]
	test	byte ptr (si),#0x80	! test hi-bit
	js	boot_si			! one to boot if set
	add	si,#16			! pt[1]
	call	is_ext			! will set EDI
	jz	ext_search
#endif

	call	say			! comment & quit
#if DEBUG
	.ascii	"nPa"
#else
	.ascii	"No partition active"
#endif
	.byte	13,10,0
#if DEBUG
stop1:	br	stop
#endif


#if !EXT_PART
find_more:				! check for more that one partition
#if EXT_PART
	call	is_ext			! continue check for extended part.
#endif
	test	byte ptr (si),#0x80	! with active bit set
	jns	one_found
	call	say			! oops, a second partition is active
#if DEBUG
	.ascii	"iPT"
#else
	.ascii	"Invalid PT"
#endif
	.byte	13,10,0			! comment & quit
#if DEBUG
	jmp	stop1
#endif

one_found:				! one partition is active
	add	si,#16			! go on & test others
	loop	find_more		! continue the loop

; BP points at the only active partition

	mov	si,bp		; now SI points at active partition
#else
one_found:
#endif	/* !EXT_PART */

boot_si:
	mov	eax,(si+8)	; get partition start
#if EXT_PART
	add	[daddr],eax	; set disk address
#else
	mov	[daddr],eax	; set disk address
#endif
	call	disk_read	; read sector

boot_it:
;;;	seg	es			! DS==ES, so don't need prefix
	cmp	word ptr [BOOTSEG*16+BOOT_SIG_OFFSET],#0xAA55	! look for boot signature
	jne	no_boot			! not bootable if no sig.

#ifdef LCF_COHERENT
	mov	(si),dl		; move into partition table
#endif
	xor	ax,ax		; signal no disk error
#if DEBUG
	pusha
	call	say
	.ascii	"B:"
	.byte	13,10,0

	mov	cx,#DELAY*16/STEP/2  ! delay DELAY/10 seconds, DX doesn't matter

	mov	ah,#0x86
	int	0x15		! delay call
	popa
#endif
#if PASS_PARAMS
	pop	ax		! check for possible params
	cmp	al,#0xFE	!
	jne	no_params
	mov	ah,dl
	pop	si
	pop	bx
	pop	es
	xchg	ax,dx
no_params:
#endif
	jmpi	(addr)


no_boot: call	say
#if DEBUG
	.ascii	"nBs"
#else
#if EXT_PART
;;;	.ascii	"No 0xAA55 in partition"
	.ascii	"No boot sig. in partition"
#else
	.ascii	"No boot signature in partition"
#endif
#endif
	.byte	13,10,0
#if DEBUG
	jmp	stop1
#endif

! packet read routine
disk_read:
	pusha
	mov	bp,#12		! retry count

disk_retry:
	mov	si,#packet
	mov	bx,#0x55AA	;magic number
	mov	ah,#0x41
	int	0x13
	jc	disk_convert
	cmp	bx,#0xAA55	;changed?
	jne	disk_convert
	test	cl,#EDD_PACKET	;EDD packet calls supported
	jz	disk_convert

	mov	ah,#0x42
	jmp	disk_int13


disk_convert:
	push	dx
	mov	ah,#8		! get geometry
	int	0x13
	jc	disk_error12

#if !CYL1023
	push	cx
	shr	cl,#6		;;;;
	xchg	cl,ch	   ;CX is max cylinder number
	mov	di,cx	   ;DI saves it
	pop	cx
#endif
	shr	dx,#8
	xchg	ax,dx		;AX <- DX
	inc	ax		;AX is number of heads (256 allowed)

	and	cx,#0x003f	;CX is number of sectors
	mul	cx		; kills DX also
	xchg	ax,bx	   	;save in BX

	mov	ax,[daddr]	;low part of address
	mov	dx,[daddr+2]	;hi part of address
	
	cmp	dx,bx
	jae	disk_error2	;prevent division error
	div	bx		;AX is cyl, DX is head/sect
#if CYL1023
	cmp	ax,#1023
#else
	cmp	ax,di
#endif
	ja	disk_error2	;cyl is too big

	shl	ah,#6		; save hi 2 bits
	xchg	al,ah
	xchg	ax,dx
	div	cl		;AH = sec-1, AL = head
	or	dl,ah	   ;form Cyl/Sec
	mov	cx,dx
	inc	cx		; sector is 1 based

	pop	dx		! restore device code
	mov	dh,al		! set head#
	mov	ax,#0x201	;read, count of 1

disk_int13:
	les	bx,[addr-packet](si)	! for both reads
	int	0x13
	jc	disk_error1
disk_ret:
	popa
	ret


disk_error2:
	mov	ah,#0x40	; signal seek error
disk_error12:
	pop	dx
disk_error1:
	dec	bp
	jz	disk_error0

;;	mov	ah,#0x0D	! reset fixed disk controller
	xor	ah,ah
	int	0x13
	jmp	disk_retry

disk_error0:
disk_error:
#if DEBUG
	xchg	al,ah		; error code to AL
	call	bout
	call	say
	.ascii	"=dRe"
#else
	call	say		; something is wrong with the disk read
	.ascii	"Disk read error"
#endif
	.byte	13,10,0
#if DEBUG
	br	stop
#endif



#if EXT_PART
/* return ZF=1 if SI -> extended partition and set EDI */
is_ext:
	mov	al,(si+4)		; get partition type
	cmp	al,#PART_DOS_EXTD
	jz	is_extd
	cmp	al,#PART_WIN_EXTD_LBA
	jz	is_extd
	cmp	al,#PART_LINUX_EXTD
	jnz	is_extr
is_extd:
	mov	edi,(si+8)		; get start to edi
is_extr:
	ret
#endif

theend1:	/* better be at or below 07B6 */

	.org	PARTS_LOAD+MAX_BOOT_SIZE
	.word	0
serial_no:	.blkb	4	! volume serial number
	.blkb	2

!!!	.org	0x1be		! spot for the partition table
p_table:
	.blkb	16		! the partition table is filled in
	.blkb	16		! when this Master Boot Record is installed
	.blkb	16		! just leave space
	.blkb	16		! here
#if defined MBX
	.org	*-2
	.long	MBX		! boot block signature check
#elif defined MBR
	.org	*-2
	.long	MBR		! boot block signature check
#else
	.word	0xAA55		! boot block signature goes here
#endif

theend:	! must be 0000:0800