bootsect.S 9.08 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2
!
! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
3 4
! 0x7F00 is 0x7F000 bytes = 508kB, more than enough for current
! versions of linux which compress the kernel
Linus Torvalds's avatar
Linus Torvalds committed
5
!
Linus Torvalds's avatar
Linus Torvalds committed
6 7
#include <linux/config.h>
SYSSIZE = DEF_SYSSIZE
Linus Torvalds's avatar
Linus Torvalds committed
8
!
9
!	bootsect.s		Copyright (C) 1991, 1992 Linus Torvalds
Linus Torvalds's avatar
Linus Torvalds committed
10
!	modified by Drew Eckhardt
11
!	modified by Bruce Evans (bde)
Linus Torvalds's avatar
Linus Torvalds committed
12 13
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
14 15 16 17
! itself out of the way to address 0x90000, and jumps there.
!
! bde - should not jump blindly, there may be systems with only 512K low
! memory.  Use int 0x12 to get the top of memory, etc.
Linus Torvalds's avatar
Linus Torvalds committed
18 19 20 21
!
! It then loads 'setup' directly after itself (0x90200), and the system
! at 0x10000, using BIOS interrupts. 
!
22 23
! NOTE! currently system is at most (8*65536-4096) bytes long. This should 
! be no problem, even in the future. I want to keep it simple. This 508 kB
Linus Torvalds's avatar
Linus Torvalds committed
24
! kernel size should be enough, especially as this doesn't contain the
25 26
! buffer cache as in minix (and especially now that the kernel is 
! compressed :-)
Linus Torvalds's avatar
Linus Torvalds committed
27
!
Linus Torvalds's avatar
Linus Torvalds committed
28
! The loader has been made as simple as possible, and continuous
Linus Torvalds's avatar
Linus Torvalds committed
29
! read errors will result in a unbreakable loop. Reboot by hand. It
30
! loads pretty fast by getting whole tracks at a time whenever possible.
31 32 33

.text

34 35 36 37 38
SETUPSECS = 4				! nr of setup-sectors
BOOTSEG   = 0x07C0			! original address of boot-sector
INITSEG   = DEF_INITSEG			! we move boot here - out of the way
SETUPSEG  = DEF_SETUPSEG		! setup starts here
SYSSEG    = DEF_SYSSEG			! system loaded at 0x10000 (65536).
39

Linus Torvalds's avatar
Linus Torvalds committed
40 41 42
! ROOT_DEV & SWAP_DEV are now written by "build".
ROOT_DEV = 0
SWAP_DEV = 0
43 44 45 46 47 48
#ifndef SVGA_MODE
#define SVGA_MODE ASK_VGA
#endif
#ifndef RAMDISK
#define RAMDISK 0
#endif 
49 50 51
#ifndef CONFIG_ROOT_RDONLY
#define CONFIG_ROOT_RDONLY 0
#endif
52

53 54 55 56 57 58
! ld86 requires an entry symbol. This may as well be the usual one.
.globl	_main
_main:
#if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */
	int	3
#endif
59 60 61 62 63 64 65
	mov	ax,#BOOTSEG
	mov	ds,ax
	mov	ax,#INITSEG
	mov	es,ax
	mov	cx,#256
	sub	si,si
	sub	di,di
66
	cld
67
	rep
68
	movsw
69
	jmpi	go,INITSEG
Linus Torvalds's avatar
Linus Torvalds committed
70 71

go:	mov	ax,cs		
Linus Torvalds's avatar
Linus Torvalds committed
72
	mov	di,#0x4000-12	! 0x4000 is arbitrary value >= length of
73 74 75 76 77 78 79 80
				! bootsect + length of setup + room for stack
				! 12 is disk parm size

! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde).  We
! wouldn't have to worry about this if we checked the top of memory.  Also
! my BIOS can be configured to put the wini drive tables in high memory
! instead of in the vector table.  The old stack might have clobbered the
! drive table.
Linus Torvalds's avatar
Linus Torvalds committed
81

82 83
	mov	ds,ax
	mov	es,ax
84
	mov	ss,ax		! put stack at INITSEG:0x4000-12.
Linus Torvalds's avatar
Linus Torvalds committed
85
	mov	sp,di
Linus Torvalds's avatar
Linus Torvalds committed
86 87 88 89 90 91 92 93 94
/*
 *	Many BIOS's default disk parameter tables will not 
 *	recognize multi-sector reads beyond the maximum sector number
 *	specified in the default diskette parameter tables - this may
 *	mean 7 sectors in some cases.
 *
 *	Since single sector reads are slow and out of the question,
 *	we must take care of this by creating new parameter tables
 *	(for the first disk) in RAM.  We will set the maximum sector
Linus Torvalds's avatar
Linus Torvalds committed
95
 *	count to 36 - the most we will encounter on an ED 2.88.  
Linus Torvalds's avatar
Linus Torvalds committed
96 97 98 99
 *
 *	High doesn't hurt.  Low does.
 *
 *	Segments are as follows: ds=es=ss=cs - INITSEG,
Linus Torvalds's avatar
Linus Torvalds committed
100
 *		fs = 0, gs is unused.
Linus Torvalds's avatar
Linus Torvalds committed
101 102 103 104 105
 */

	push	#0
	pop	fs
	mov	bx,#0x78		! fs:bx is parameter table address
Linus Torvalds's avatar
Linus Torvalds committed
106
	push	ds
Linus Torvalds's avatar
Linus Torvalds committed
107
	seg fs
Linus Torvalds's avatar
Linus Torvalds committed
108
	lds	si,(bx)			! ds:si is source
Linus Torvalds's avatar
Linus Torvalds committed
109 110 111

	mov	cx,#6			! copy 12 bytes
	cld
Linus Torvalds's avatar
Linus Torvalds committed
112
	push	di
Linus Torvalds's avatar
Linus Torvalds committed
113 114

	rep
115
	movsw
Linus Torvalds's avatar
Linus Torvalds committed
116

Linus Torvalds's avatar
Linus Torvalds committed
117 118 119 120
	pop	di
	pop	ds

	movb	4(di),*36		! patch sector count
Linus Torvalds's avatar
Linus Torvalds committed
121 122 123 124 125 126 127 128 129

	seg fs
	mov	(bx),di
	seg fs
	mov	2(bx),es

	xor	ah,ah			! reset FDC 
	xor	dl,dl
	int 	0x13	
130

Linus Torvalds's avatar
Linus Torvalds committed
131 132
! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.
133 134

load_setup:
Linus Torvalds's avatar
Linus Torvalds committed
135
	xor	dx, dx			! drive 0, head 0
Linus Torvalds's avatar
Linus Torvalds committed
136 137
	mov	cx,#0x0002		! sector 2, track 0
	mov	bx,#0x0200		! address = 512, in INITSEG
138 139
	mov	ax,#0x0200+SETUPSECS	! service 2, nr of sectors
					! (assume all on head 0, track 0)
Linus Torvalds's avatar
Linus Torvalds committed
140 141
	int	0x13			! read it
	jnc	ok_load_setup		! ok - continue
Linus Torvalds's avatar
Linus Torvalds committed
142 143 144 145 146 147 148 149 150

	push	ax			! dump error code
	call	print_nl
	mov	bp, sp
	call	print_hex
	pop	ax	
	
	xor	dl, dl			! reset FDC
	xor	ah, ah
151
	int	0x13
152
	jmp	load_setup
153 154 155

ok_load_setup:

Linus Torvalds's avatar
Linus Torvalds committed
156
! Get disk drive parameters, specifically nr of sectors/track
157

158 159 160 161 162 163
#if 0

! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
! disks.  It doesn't work for one of my BIOS's (1987 Award).  It was
! fatal not to check the error code.

Linus Torvalds's avatar
Linus Torvalds committed
164 165
	xor	dl,dl
	mov	ah,#0x08		! AH=8 is get drive parameters
166
	int	0x13
Linus Torvalds's avatar
Linus Torvalds committed
167
	xor	ch,ch
168 169 170
#else

! It seems that there is no BIOS call to get the number of sectors.  Guess
Linus Torvalds's avatar
Linus Torvalds committed
171 172 173 174
! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
! 15 if sector 15 can be read.  Otherwise guess 9.

	mov	si,#disksizes		! table of sizes to try
175

Linus Torvalds's avatar
Linus Torvalds committed
176 177 178 179 180 181 182 183
probe_loop:
	lodsb
	cbw				! extend to word
	seg cs
	mov	sectors, ax
	cmp	si,#disksizes+4
	jae	got_sectors		! if all else fails, try 9
	xchg	ax, cx			! cx = track and sector
184 185 186 187
	xor	dx, dx			! drive 0, head 0
	mov	bx,#0x0200+SETUPSECS*0x200  ! address after setup (es = cs)
	mov	ax,#0x0201		! service 2, 1 sector
	int	0x13
Linus Torvalds's avatar
Linus Torvalds committed
188
	jc	probe_loop		! try next value
189 190 191 192

#endif

got_sectors:
Linus Torvalds's avatar
Linus Torvalds committed
193 194 195

! Restore es

196 197 198
	mov	ax,#INITSEG
	mov	es,ax

Linus Torvalds's avatar
Linus Torvalds committed
199
! Print some inane message
200

Linus Torvalds's avatar
Linus Torvalds committed
201
	mov	ah,#0x03		! read cursor pos
202 203 204
	xor	bh,bh
	int	0x10
	
Linus Torvalds's avatar
Linus Torvalds committed
205
	mov	cx,#9
Linus Torvalds's avatar
Linus Torvalds committed
206
	mov	bx,#0x0007		! page 0, attribute 7 (normal)
207
	mov	bp,#msg1
Linus Torvalds's avatar
Linus Torvalds committed
208
	mov	ax,#0x1301		! write string, move cursor
209 210
	int	0x10

Linus Torvalds's avatar
Linus Torvalds committed
211 212
! ok, we've written the message, now
! we want to load the system (at 0x10000)
213 214

	mov	ax,#SYSSEG
Linus Torvalds's avatar
Linus Torvalds committed
215
	mov	es,ax		! segment of 0x010000
216 217
	call	read_it
	call	kill_motor
Linus Torvalds's avatar
Linus Torvalds committed
218
	call	print_nl
219

Linus Torvalds's avatar
Linus Torvalds committed
220 221
! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
Linus Torvalds's avatar
Linus Torvalds committed
222 223
! Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8),
! depending on the number of sectors we pretend to know we have.
224 225 226

	seg cs
	mov	ax,root_dev
Linus Torvalds's avatar
Linus Torvalds committed
227
	or	ax,ax
228 229 230
	jne	root_defined
	seg cs
	mov	bx,sectors
Linus Torvalds's avatar
Linus Torvalds committed
231
	mov	ax,#0x0208		! /dev/ps0 - 1.2Mb
232 233
	cmp	bx,#15
	je	root_defined
Linus Torvalds's avatar
Linus Torvalds committed
234
	mov	al,#0x1c		! /dev/PS0 - 1.44Mb
235 236
	cmp	bx,#18
	je	root_defined
Linus Torvalds's avatar
Linus Torvalds committed
237 238 239 240
	mov	al,#0x20		! /dev/fd0H2880 - 2.88Mb
	cmp	bx,#36
	je	root_defined
	mov	al,#0			! /dev/fd0 - autodetect
241 242 243 244
root_defined:
	seg cs
	mov	root_dev,ax

Linus Torvalds's avatar
Linus Torvalds committed
245
! after that (everything loaded), we jump to
Linus Torvalds's avatar
Linus Torvalds committed
246 247
! the setup-routine loaded directly after
! the bootblock:
248 249 250

	jmpi	0,SETUPSEG

Linus Torvalds's avatar
Linus Torvalds committed
251 252 253 254 255 256
! This routine loads the system at address 0x10000, making sure
! no 64kB boundaries are crossed. We try to load it as fast as
! possible, loading whole tracks whenever we can.
!
! in:	es - starting address segment (normally 0x1000)
!
257
sread:	.word 1+SETUPSECS	! sectors read of current track
Linus Torvalds's avatar
Linus Torvalds committed
258 259
head:	.word 0			! current head
track:	.word 0			! current track
260 261 262 263

read_it:
	mov ax,es
	test ax,#0x0fff
Linus Torvalds's avatar
Linus Torvalds committed
264 265
die:	jne die			! es must be at 64kB boundary
	xor bx,bx		! bx is starting address within segment
266 267
rp_read:
	mov ax,es
268 269 270
	sub ax,#SYSSEG
	cmp ax,syssize		! have we loaded all yet?
	jbe ok1_read
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
	ret
ok1_read:
	seg cs
	mov ax,sectors
	sub ax,sread
	mov cx,ax
	shl cx,#9
	add cx,bx
	jnc ok2_read
	je ok2_read
	xor ax,ax
	sub ax,bx
	shr ax,#9
ok2_read:
	call read_track
	mov cx,ax
	add ax,sread
	seg cs
	cmp ax,sectors
	jne ok3_read
	mov ax,#1
	sub ax,head
	jne ok4_read
	inc track
ok4_read:
	mov head,ax
	xor ax,ax
ok3_read:
	mov sread,ax
	shl cx,#9
	add bx,cx
	jnc rp_read
	mov ax,es
Linus Torvalds's avatar
Linus Torvalds committed
304
	add ah,#0x10
305 306 307 308 309
	mov es,ax
	xor bx,bx
	jmp rp_read

read_track:
Linus Torvalds's avatar
Linus Torvalds committed
310 311 312 313 314 315 316
	pusha
	pusha	
	mov	ax, #0xe2e 	! loading... message 2e = .
	mov	bx, #7
 	int	0x10
	popa		

317 318 319 320 321 322 323 324
	mov	dx,track
	mov	cx,sread
	inc	cx
	mov	ch,dl
	mov	dx,head
	mov	dh,dl
	and	dx,#0x0100
	mov	ah,#2
Linus Torvalds's avatar
Linus Torvalds committed
325 326 327 328 329 330
	
	push	dx				! save for error dump
	push	cx
	push	bx
	push	ax

331 332 333
	int	0x13
	jc	bad_rt
	add	sp, #8
Linus Torvalds's avatar
Linus Torvalds committed
334
	popa
335
	ret
Linus Torvalds's avatar
Linus Torvalds committed
336 337 338 339 340 341 342

bad_rt:	push	ax				! save error code
	call	print_all			! ah = error, al = read
	
	
	xor ah,ah
	xor dl,dl
343
	int 0x13
Linus Torvalds's avatar
Linus Torvalds committed
344 345 346 347
	

	add	sp, #10
	popa	
348 349
	jmp read_track

Linus Torvalds's avatar
Linus Torvalds committed
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
/*
 *	print_all is for debugging purposes.  
 *	It will print out all of the registers.  The assumption is that this is
 *	called from a routine, with a stack frame like
 *	dx 
 *	cx
 *	bx
 *	ax
 *	error
 *	ret <- sp
 *
*/
 
print_all:
	mov	cx, #5		! error code + 4 registers
	mov	bp, sp	

print_loop:
	push	cx		! save count left
	call	print_nl	! nl for readability
370

Linus Torvalds's avatar
Linus Torvalds committed
371
	cmp	cl, #5
Linus Torvalds's avatar
Linus Torvalds committed
372 373
	jae	no_reg		! see if register name is needed
	
374
	mov	ax, #0xe05 + 'A - 1
Linus Torvalds's avatar
Linus Torvalds committed
375 376 377
	sub	al, cl
	int	0x10

378
	mov	al, #'X
Linus Torvalds's avatar
Linus Torvalds committed
379 380
	int	0x10

381
	mov	al, #':
Linus Torvalds's avatar
Linus Torvalds committed
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
	int	0x10

no_reg:
	add	bp, #2		! next register
	call	print_hex	! print it
	pop	cx
	loop	print_loop
	ret

print_nl:
	mov	ax, #0xe0d	! CR
	int	0x10
	mov	al, #0xa	! LF
	int 	0x10
	ret

/*
 *	print_hex is for debugging purposes, and prints the word
Linus Torvalds's avatar
Linus Torvalds committed
400
 *	pointed to by ss:bp in hexadecimal.
Linus Torvalds's avatar
Linus Torvalds committed
401 402 403 404 405 406 407
*/

print_hex:
	mov	cx, #4		! 4 hex digits
	mov	dx, (bp)	! load word into dx
print_digit:
	rol	dx, #4		! rotate so that lowest 4 bits are used
Linus Torvalds's avatar
Linus Torvalds committed
408 409 410 411 412 413
	mov	ax, #0xe0f	! ah = request, al = mask for nybble
	and	al, dl
	add	al, #0x90	! convert al to ascii hex (four instructions)
	daa
	adc	al, #0x40
	daa
Linus Torvalds's avatar
Linus Torvalds committed
414 415 416 417 418
	int	0x10
	loop	print_digit
	ret


419 420 421 422 423 424 425 426
/*
 * This procedure turns off the floppy drive motor, so
 * that we enter the kernel in a known state, and
 * don't have to worry about it later.
 */
kill_motor:
	push dx
	mov dx,#0x3f2
Linus Torvalds's avatar
Linus Torvalds committed
427
	xor al, al
428 429 430 431 432 433 434
	outb
	pop dx
	ret

sectors:
	.word 0

Linus Torvalds's avatar
Linus Torvalds committed
435 436 437
disksizes:
	.byte 36,18,15,9

438 439
msg1:
	.byte 13,10
Linus Torvalds's avatar
Linus Torvalds committed
440
	.ascii "Loading"
441

442 443 444
.org 498
root_flags:
	.word CONFIG_ROOT_RDONLY
445 446
syssize:
	.word SYSSIZE
Linus Torvalds's avatar
Linus Torvalds committed
447 448
swap_dev:
	.word SWAP_DEV
449 450 451 452
ram_size:
	.word RAMDISK
vid_mode:
	.word SVGA_MODE
453 454 455 456
root_dev:
	.word ROOT_DEV
boot_flag:
	.word 0xAA55