summaryrefslogtreecommitdiff
path: root/bootblocks/mbr.s
blob: a5a392348fcf94cb6cf3955ca3c23733b47b6bb2 (plain)
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
!
! This is a 'Master Boot Record' following the MSDOS 'standards'.
! This BB successfully boots MSDOS or Linux.
!
! In addition it has the facility to load and execute a small program
! before the boot blocks are checked.
!
! Or
!
! Space for 12 extra partitions in the 'DiskManager' form that Linux 
! _does_ understand.
!
! NB: This needs as86 0.15.2 or later

! Lowest available is $0500, MSDOS appears to use $0600 ... I wonder why?
ORGADDR=$0500
preboot=0	! Include the pre-boot loader.
mbrkey=0	! Option to choose the boot record base on keystroke
message=1	! Display boot message
use512=0	! Put the end marker at byte 510..512

diskman=0	! Disk manager partitions, allows 16 partitions but
		! don't overwrite this with a LILO BB.

linear=0	! Use the linear addresses not the CHS ones

partition_start=ORGADDR+0x1BE
partition_size=0x10
partition_end=ORGADDR+0x1FE

 if diskman
  ! Partition table start ...
  table_start=ORGADDR+0xFC
  low_partition=table_start+2
 else
  table_start=partition_start
 endif

org ORGADDR
  cli			! Assume _nothing_!
  cld
  mov	bx,#$7C00	! Pointer to start of BB.
  xor	ax,ax		! Segs all to zero
  mov	ds,ax
  mov	es,ax
  mov	ss,ax
  mov	sp,bx		! SP Just below BB
  mov	cx,#$100	! Move 256 words
  mov	si,bx		! From default BB
  mov	di,#ORGADDR	! To the correct address.
  rep
   movsw
  jmpi	cont,#0		! Set CS:IP correct.
cont:
  sti			! Let the interrupts back in.

! Next check for a pre-boot load or a keypress
 if message
  call disp_message
 endif
 if preboot
  call preboot_code
 endif
 if mbrkey
  call 	key_wait
 endif

! Now check the partition table, must use SI as pointer cause that's what the
! partition boot blocks expect.

  mov	si,#partition_start
check_active:
  cmp	byte [si],#$80			! Flag for activated partition
  jz	found_active
 if mbrkey=0
bad_boot:
 endif
  add	si,#partition_size
  cmp	si,#partition_end
  jnz	check_active

  ! Check for Disk manager partitions in the order that Linux numbers them.
 if diskman
  cmp	word ptr diskman_magic,#$55AA
  jnz	no_diskman
  mov	si,#partition_start
check_next:
  sub	si,#partition_size
  cmp	byte [si],#$80			! Flag for activated partition
  jz	found_active
  cmp	si,#low_partition
  jnz	check_next

no_diskman:
 endif

  mov	si,#no_bootpart		! Message & boot
  jmp	no_boot

found_active:
 if linear
  call linearise
 else
  mov	di,#6		! Max retries, int list says 3 ... double it
  mov	dx,[si]		! dh = Drive head, dl = $80 ie HD drive 0
  mov	cx,[si+2]	! cx = Sector & head encoded for int $13
  ! bx is correct at $7C00
 endif
retry:
  movb	[$7DFE],#0	! Clear magic for dosemu
  mov	ax,#$0201	! Read 1 sector
  int   $13		! Disk read.
  jnc	sector_loaded

! Error, reset and retry
  xor	ax,ax
  int	$13		! Disk reset

  dec	di
  jnz	retry		! Try again

  mov	si,#disk_read_error
  jmp	no_boot		! Sorry it ain't gonna work.

sector_loaded:
  mov	di,#$7DFE	! End of sector loaded
  cmp	[di],#$AA55	! Check for magic
  jnz	bad_boot	! No? Try next partition.

  mov	bp,si		! LILO says some BBs use bp rather than si
  jmpi	#$7C00,#0	! Go!

! Fatal errors ...........
 if mbrkey
bad_boot:
  mov	si,#no_bootpart
no_boot:		! SI now has pointer to error message
  call	puts
  mov	si,#crlf
  call	puts
tick:
  call	key_pause
  j	tick

 else

no_boot:		! SI now has pointer to error message
  lodsb
  cmp	al,#0
  jz	EOS
  mov	bx,#7
  mov	ah,#$E		! Can't use $13 cause that's AT+ only!
  int	$10
  jmp	no_boot
EOS:
  cmp	si,#press_end	! After msg output 'press key' message
  jz	keyboot
  mov	si,#press_key
  jmp	no_boot

keyboot:		! Wait for a key then reboot
  xor	ax,ax
  int	$16
  jmpi	$0,$FFFF	! Reboot.

press_key:
  .asciz	"\r\nPress return:"
press_end:
 endif

no_bootpart:
  .asciz	"No active partition"
disk_read_error:
  .asciz	"Disk read error"

!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
! Instead of loading using the CHS data in the ptbl use the linear addr
!
 if linear
linearise:
  mov	di,#6		! Max retries, int list says 3 ... double it
  mov	dx,[si]		! dh = Drive head, dl = $80 ie HD drive 0
  mov	cx,[si+2]	! cx = Sector & head encoded for int $13
  ! bx is correct at $7C00

  fail! Todo ...
  ret
 endif

!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
! Choose the partition based on a pressed key ...

 if mbrkey
key_pause:
  mov	si,#Pause
  call	puts
  j	wait_key

key_wait:
  mov	si,#Prompt
  call	puts

wait_key:
  mov	di,#19			! Wait for 18-19 ticks

next_loop:
  mov	ah,#1
  int	$16
  jnz   Got_key
  mov	ah,#0
  int	$1A			! Get current tick
  cmp	dx,si			! If changed DEC our counter.
  jz	next_loop
  mov	si,dx
  dec	di
  jnz	next_loop

  mov	si,#Unprompt		! Nothing has happened, return.
  call	puts

bad_key:
  ret

Got_key:
  mov	ah,#0			! Clean the kbd buffer.
  int	$16

  cmp	al,#$20
  jz	key_pause		! Recursion !?

  mov	Showkey,al
  mov	si,#Showkey
  call	puts
  mov	al,Showkey

  ! ... Now we use our key ...
  ! 0 		=> Floppy
  ! 1 .. 4	=> Hard disk partition.

  mov	di,#-1
  cmp	al,#$20
  jz	next_loop

  and	ax,#0xF

  jnz	not_floppy
  mov	si,#floppy_part
  br	found_active

not_floppy:
  dec	ax
  test	ax,#0xC
  jnz	bad_key

  mov	cl,#4
  shl	ax,cl
  add	ax,#partition_start
  mov	si,ax

! Set active flag for disk interrupt.
  or	byte [si],#$80

  br	found_active

puts:
  lodsb
  cmp	al,#0
  jz	EOS
  push	bx
  mov	bx,#7
  mov	ah,#$E			! Can't use $13 cause that's AT+ only!
  int	$10
  pop	bx
  jmp	puts
EOS:
  ret

Prompt:
  .asciz	"\rMBR 0-4: "
Unprompt:
  .asciz	"\r        \r"
Pause:
  .asciz	"\rMBR 0-4> "
Showkey:
  .ascii	" "
crlf:
  .asciz	"\r\n"
floppy_part:
  .word	0,1

 endif

!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
!
 if message
disp_message:
  mov	si,#Banner

 if mbrkey
  br	puts
 else

puts:
  lodsb
  cmp	al,#0
  jz	.EOS
  push	bx
  mov	bx,#7
  mov	ah,#$E			! Can't use $13 cause that's AT+ only!
  int	$10
  pop	bx
  jmp	puts
.EOS:
  ret
 endif
export Banner
Banner:
  .asciz	""
 endif
!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
! This is the pre-boot loader it uses CHS but that's ok for track 0
!
 if preboot
public preboot_code
preboot_code:
  push	bx
  mov	si,#pre_boot_table
  lodsw
  mov	di,ax		! First word is execute address
more_boot:
  lodsw
  test	ah,ah
  jz	load_done
  mov	bx,ax		! word 1 address
  lodsw
  mov	cx,ax		! word 2 CX, cylinder/sector
  lodsw
  mov	dx,ax		! word 3 DX, drive, head
  lodsw			! word 4 AX, $02, sector count
  int	$13
  jnc	more_boot	! This doesn't retry, with a HD it shouldn't be bad.

  mov	si,#disk_read_error
  br	no_boot		! Sorry it ain't gonna work.
load_done:
  call	di
exec_done:
  pop	bx

return:
  ret

export pre_boot_table
pre_boot_table:
  ! Example: Do nothing.
  .word return,0

  ! Labels
  ! .word <execute address>
  ! Then repeat ..
  ! .word <BX>, <CX>, <DX>, <AX>
  ! Or.
  ! .word <Load Address>
  ! .byte <sector> + (<cyl> & $300)>>2), <cyl> & $FF, <Drive>, <Head>, <cnt>, 2
  ! Finally
  ! .word 0

  ! Example: Load rest of H0,C0 into mem at $7C00 (8k).
  ! .word $7C00
  ! .word $7C00,$0002,$8000,$0210
  ! .word $0000
 endif

!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
! Now make sure this isn't too big!
  if *>table_start
   fail! Partition table overlaps
  endif

!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
! The diskman magic number and empty DM partitions.
 if diskman
  org ORGADDR+0xFC
public diskman_magic
diskman_magic:
  .word 0xAA55
  .blkb 12*partition_size-1
  .byte 0
 endif

!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
! And finally a copyright message if there's room.
 if *<ORGADDR+0x180
  org ORGADDR+0x180
.asciz "ELKS MBR       "
.asciz "Robert de Bath,"
.asciz "Copyright      "
.asciz "1996-2002.  "
  org partition_start-1
  .byte 0xFF
 endif

 if use512
  org ORGADDR+0x1FE
  .word 0xAA55
 endif

!THE END