wok-stable diff gpxe/stuff/prefix.u @ rev 955

Add gPXE
author Pascal Bellard <pascal.bellard@slitaz.org>
date Fri Jun 27 20:38:59 2008 +0000 (2008-06-27)
parents
children 0ebb1ed44fed
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gpxe/stuff/prefix.u	Fri Jun 27 20:38:59 2008 +0000
     1.3 @@ -0,0 +1,393 @@
     1.4 +--- gpxe-0.9.3/src/arch/i386/prefix/lkrnprefix.S
     1.5 ++++ gpxe-0.9.3/src/arch/i386/prefix/lkrnprefix.S
     1.6 +@@ -50,40 +50,343 @@
     1.7 + 	.arch i386
     1.8 + 	.org	0
     1.9 + 	.section ".prefix", "ax", @progbits
    1.10 +-/* 
    1.11 +-	This is a minimal boot sector.	If anyone tries to execute it (e.g., if
    1.12 +-	a .lilo file is dd'ed to a floppy), print an error message. 
    1.13 +-*/
    1.14 + 
    1.15 +-bootsector: 
    1.16 +-	jmp	$BOOTSEG, $1f	/* reload cs:ip to match relocation addr */
    1.17 +-1:
    1.18 +-	movw	$0x2000, %di		/*  0x2000 is arbitrary value >= length
    1.19 +-					    of bootsect + room for stack */
    1.20 ++	call	here
    1.21 ++here:
    1.22 ++	pop	%ax
    1.23 ++	cmpw	$0x103, %ax		/* COM entry point is cs:0x100 */
    1.24 ++	jne	bootsector
    1.25 ++
    1.26 ++/* We need a real mode stack that won't be stomped on by Etherboot
    1.27 ++   which starts at 0x20000. Choose something that's sufficiently high,
    1.28 ++   but not in DOC territory. Note that we couldn't do this in a real
    1.29 ++   .com program since stack variables are in the same segment as the
    1.30 ++   code and data, but this isn't really a .com program, it just looks
    1.31 ++   like one to make DOS load it into memory. It still has the 64kB
    1.32 ++   limitation of .com files though. */
    1.33 ++#define STACK_SEG	0x7000
    1.34 ++#define STACK_SIZE	0x4000
    1.35 ++	/* Set up temporary stack */ 
    1.36 ++	movw	$STACK_SEG, %ax
    1.37 ++	movw	%ax, %ss
    1.38 ++	movw	$STACK_SIZE, %sp
    1.39 ++
    1.40 ++	/* Calculate segment address of image start */
    1.41 ++	pushw	%cs
    1.42 ++	popw	%ax
    1.43 ++	addw	$(0x100/16), %ax
    1.44 ++	jmp	go_setup_code
    1.45 ++
    1.46 ++bootsector:
    1.47 ++	jmp	$BOOTSEG, $go		/* reload cs:ip to match relocation addr */
    1.48 ++go: 
    1.49 ++	movw	$0x2000-12, %di		/* 0x2000 is arbitrary value >= length */
    1.50 ++					/* of bootsect + room for stack + 12 for */
    1.51 ++					/* saved disk parm block */
    1.52 + 
    1.53 + 	movw	$BOOTSEG, %ax
    1.54 + 	movw	%ax,%ds
    1.55 + 	movw	%ax,%es
    1.56 +-
    1.57 +-	cli
    1.58 +-	movw	%ax, %ss		/* put stack at BOOTSEG:0x2000. */
    1.59 ++	movw	%ax,%ss			/* put stack at initial position */
    1.60 + 	movw	%di,%sp
    1.61 +-	sti
    1.62 + 
    1.63 +-	movw	$why_end-why, %cx
    1.64 +-	movw	$why, %si
    1.65 ++/* Many BIOS's default disk parameter tables will not recognize multi-sector
    1.66 ++ * reads beyond the maximum sector number specified in the default diskette
    1.67 ++ * parameter tables - this may mean 7 sectors in some cases.
    1.68 ++ *
    1.69 ++ * Since single sector reads are slow and out of the question, we must take care
    1.70 ++ * of this by creating new parameter tables (for the first disk) in RAM.  We
    1.71 ++ * will set the maximum sector count to 36 - the most we will encounter on an
    1.72 ++ * ED 2.88.  High doesn't hurt.	Low does.
    1.73 ++ *
    1.74 ++ * Segments are as follows: ds=es=ss=cs - BOOTSEG
    1.75 ++ */
    1.76 + 
    1.77 +-	movw	$0x0007, %bx		/* page 0, attribute 7 (normal) */
    1.78 +-	movb	$0x0e, %ah		/* write char, tty mode */
    1.79 +-prloop: 
    1.80 ++	xorw	%cx,%cx
    1.81 ++	movw	%cx,%es			/* access segment 0 */
    1.82 ++	movw	$0x78, %bx		/* 0:bx is parameter table address */
    1.83 ++	pushw	%ds			/* save ds */
    1.84 ++/* 0:bx is parameter table address */
    1.85 ++	ldsw	%es:(%bx),%si		/* loads ds and si */
    1.86 ++
    1.87 ++	movw	%ax,%es			/* ax is BOOTSECT (loaded above) */
    1.88 ++	movb	$6, %cl			/* copy 12 bytes */
    1.89 ++	cld
    1.90 ++	pushw	%di			/* keep a copy for later */
    1.91 ++	rep
    1.92 ++	movsw				/* ds:si is source, es:di is dest */
    1.93 ++	popw	%di
    1.94 ++
    1.95 ++	movb	$36,%es:4(%di)
    1.96 ++
    1.97 ++	movw	%cx,%ds			/* access segment 0 */
    1.98 ++	xchgw	%di,(%bx)
    1.99 ++	movw	%es,%si
   1.100 ++	xchgw	%si,2(%bx)
   1.101 ++	popw	%ds			/* restore ds */
   1.102 ++	movw	%di, dpoff		/* save old parameters */
   1.103 ++	movw	%si, dpseg		/* to restore just before finishing */
   1.104 ++	pushw	%ds
   1.105 ++	popw	%es			/* reload es */
   1.106 ++
   1.107 ++/* Note that es is already set up.  Also cx is 0 from rep movsw above. */
   1.108 ++
   1.109 ++	xorb	%ah,%ah			/* reset FDC */
   1.110 ++	xorb	%dl,%dl
   1.111 ++	int	$0x13
   1.112 ++
   1.113 ++/* Get disk drive parameters, specifically number of sectors/track.
   1.114 ++ *
   1.115 ++ * It seems that there is no BIOS call to get the number of sectors.  Guess
   1.116 ++ * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
   1.117 ++ * 15 if sector 15 can be read.	Otherwise guess 9.
   1.118 ++ */
   1.119 ++
   1.120 ++	movw	$disksizes, %si		/* table of sizes to try */
   1.121 ++
   1.122 ++probe_loop: 
   1.123 + 	lodsb
   1.124 ++	orb	%al, %al
   1.125 ++	je	got_sectors		/* if all else fails, try 9 */
   1.126 ++	cbtw				/* extend to word */
   1.127 ++	movw	%ax, sectors
   1.128 ++	xchgw	%cx,%ax			/* cx = track and sector */
   1.129 ++	xorw	%dx,%dx			/* drive 0, head 0 */
   1.130 ++	movw	$0x0200, %bx		/* address after boot sector */
   1.131 ++					/*   (512 bytes from origin, es = cs) */
   1.132 ++	movw	$0x0201, %ax		/* service 2, 1 sector */
   1.133 ++	int	$0x13
   1.134 ++	jc	probe_loop		/* try next value */
   1.135 ++
   1.136 ++got_sectors: 
   1.137 ++	movw	$msg1end-msg1, %cx
   1.138 ++	movw	$msg1, %si
   1.139 ++	call	print_str
   1.140 ++
   1.141 ++/* ok, we've written the Loading... message, now we want to load the system */
   1.142 ++
   1.143 ++	pushw	%es			/* = ds */
   1.144 ++	movw	$SYSSEG, %ax
   1.145 ++	movw	%ax,%es			/* segment of SYSSEG<<4 */
   1.146 ++	pushw	%es
   1.147 ++	call	read_it
   1.148 ++
   1.149 ++/* This turns off the floppy drive motor, so that we enter the kernel in a
   1.150 ++ * known state, and don't have to worry about it later.
   1.151 ++ */
   1.152 ++	movw	$0x3f2, %dx
   1.153 ++	xorb	%al,%al
   1.154 ++	outb	%al,%dx
   1.155 ++
   1.156 ++	call	print_nl
   1.157 ++	pop	%es			/* = SYSSEG */
   1.158 ++	pop	%es			/* balance push/pop es */
   1.159 ++sigok: 
   1.160 ++
   1.161 ++/* Restore original disk parameters */
   1.162 ++	movw	$0x78, %bx
   1.163 ++	movw	dpoff, %di
   1.164 ++	movw	dpseg, %si
   1.165 ++	xorw	%ax,%ax
   1.166 ++	movw	%ax,%ds
   1.167 ++	movw	%di,(%bx)
   1.168 ++	movw	%si,2(%bx)
   1.169 ++
   1.170 ++/* after that (everything loaded), we call to the .ROM file loaded. */
   1.171 ++
   1.172 ++	movw	$SYSSEG, %ax
   1.173 ++	jmp	go_setup_code
   1.174 ++
   1.175 ++/* This routine loads the system at address SYSSEG<<4, making sure no 64kB
   1.176 ++ * boundaries are crossed. We try to load it as fast as possible, loading whole
   1.177 ++ * tracks whenever we can.
   1.178 ++ *
   1.179 ++ * in:	es - starting address segment (normally SYSSEG)
   1.180 ++ */
   1.181 ++read_it: 
   1.182 ++	movw	$0,sread		/* read whole image incl boot sector */
   1.183 ++	movw	%es,%ax
   1.184 ++	testw	$0x0fff, %ax
   1.185 ++die:	jne	die			/* es must be at 64kB boundary */
   1.186 ++	xorw	%bx,%bx			/* bx is starting address within segment */
   1.187 ++rp_read: 
   1.188 ++	movw	%es,%ax
   1.189 ++	movw	%bx,%dx
   1.190 ++	movb	$4, %cl
   1.191 ++	shrw	%cl,%dx			/* bx is always divisible by 16 */
   1.192 ++	addw	%dx,%ax
   1.193 ++.equ	SYSSIZE, _load_size_pgh - 32
   1.194 ++	cmpw	$SYSSEG+SYSSIZE, %ax	/* have we loaded all yet? */
   1.195 ++	jb	ok1_read
   1.196 ++	ret
   1.197 ++ok1_read: 
   1.198 ++	movw	sectors, %ax
   1.199 ++	subw	sread, %ax
   1.200 ++	movw	%ax,%cx
   1.201 ++	shlw	$9, %cx			/* 80186 opcode */
   1.202 ++	addw	%bx,%cx
   1.203 ++	jnc	ok2_read
   1.204 ++	je	ok2_read
   1.205 ++	xorw	%ax,%ax
   1.206 ++	subw	%bx,%ax
   1.207 ++	shrw	$9, %ax			/* 80186 opcode */
   1.208 ++ok2_read: 
   1.209 ++	call	read_track
   1.210 ++	movw	%ax,%cx
   1.211 ++	addw	sread, %ax
   1.212 ++	cmpw	sectors, %ax
   1.213 ++	jne	ok3_read
   1.214 ++	movw	$1, %ax
   1.215 ++	subw	head, %ax
   1.216 ++	jne	ok4_read
   1.217 ++	incw	track
   1.218 ++ok4_read: 
   1.219 ++	movw	%ax, head
   1.220 ++	xorw	%ax,%ax
   1.221 ++ok3_read: 
   1.222 ++	movw	%ax, sread
   1.223 ++	shlw	$9, %cx			/* 80186 opcode */
   1.224 ++	addw	%cx,%bx
   1.225 ++	jnc	rp_read
   1.226 ++	movw	%es,%ax
   1.227 ++	addb	$0x10, %ah
   1.228 ++	movw	%ax,%es
   1.229 ++	xorw	%bx,%bx
   1.230 ++	jmp	rp_read
   1.231 ++
   1.232 ++read_track: 
   1.233 ++	pusha				/* 80186 opcode */
   1.234 ++	pushw	%ax
   1.235 ++	pushw	%bx
   1.236 ++	pushw	%bp			/* just in case the BIOS is buggy */
   1.237 ++	movb	$0x2e, %al		/* 0x2e = . */
   1.238 ++	call	print_char
   1.239 ++	popw	%bp
   1.240 ++	popw	%bx
   1.241 ++	popw	%ax
   1.242 ++
   1.243 ++	movw	sread, %cx
   1.244 ++	incw	%cx
   1.245 ++	movb	track, %ch
   1.246 ++	movw	$0x0100, %dx
   1.247 ++	andb	head, %dh
   1.248 ++	movb	$2, %ah
   1.249 ++
   1.250 ++	pushw	%dx			/* save for error dump */
   1.251 ++	pushw	%cx
   1.252 ++	pushw	%bx
   1.253 ++	pushw	%ax
   1.254 ++
   1.255 ++	int	$0x13
   1.256 ++	jc	bad_rt
   1.257 ++	addw	$8, %sp
   1.258 ++	popa				/* 80186 opcode */
   1.259 ++	ret
   1.260 ++
   1.261 ++bad_rt: pushw	%ax			/* save error code */
   1.262 ++	call	print_all		/* ah = error, al = read */
   1.263 ++
   1.264 ++	xorb	%ah,%ah
   1.265 ++	xorb	%dl,%dl
   1.266 ++	int	$0x13
   1.267 ++
   1.268 ++	addw	$10, %sp
   1.269 ++	popa				/* 80186 opcode */
   1.270 ++	jmp	read_track
   1.271 ++
   1.272 ++/* print_all is for debugging purposes.	It will print out all of the registers.
   1.273 ++ * The assumption is that this is called from a routine, with a stack frame like
   1.274 ++ *	dx
   1.275 ++ *	cx
   1.276 ++ *	bx
   1.277 ++ *	ax
   1.278 ++ *	error
   1.279 ++ *	ret <- sp
   1.280 ++ */
   1.281 ++
   1.282 ++print_all: 
   1.283 ++	call	print_nl		/* nl for readability */
   1.284 ++					/* print_nl update ah and bx */
   1.285 ++	movw	$5, %cx			/* error code + 4 registers */
   1.286 ++	movw	%sp,%bp
   1.287 ++
   1.288 ++print_loop: 
   1.289 ++	pushw	%cx			/* save count left */
   1.290 ++
   1.291 ++	cmpb	$5, %cl
   1.292 ++	jae	no_reg			/* see if register name is needed */
   1.293 ++
   1.294 ++	movb	$0x5+0x41-1, %al
   1.295 ++	subb	%cl,%al
   1.296 ++	int	$0x10
   1.297 ++
   1.298 ++	movb	$0x58, %al		/* 'X' */
   1.299 + 	int	$0x10
   1.300 ++
   1.301 ++	movb	$0x3A, %al		/* ':' */
   1.302 ++	int	$0x10
   1.303 ++
   1.304 ++no_reg: 
   1.305 ++	addw	$2, %bp			/* next register */
   1.306 ++	call	print_hex		/* print it */
   1.307 ++	movb	$0x20, %al		/* print a space */
   1.308 ++	int	$0x10
   1.309 ++	popw	%cx
   1.310 ++	loop	print_loop
   1.311 ++					/* nl for readability */
   1.312 ++print_nl: 
   1.313 ++	movb	$0xd, %al		/* CR */
   1.314 ++	call	print_char
   1.315 ++	movb	$0xa, %al		/* LF */
   1.316 ++	jmp	print_char
   1.317 ++
   1.318 ++
   1.319 ++print_str: 
   1.320 ++prloop: 
   1.321 ++	lodsb
   1.322 ++	call	print_char
   1.323 + 	loop	prloop
   1.324 +-freeze: jmp	freeze
   1.325 ++	ret
   1.326 ++
   1.327 ++/* print_hex prints the word pointed to by ss:bp in hexadecimal. */
   1.328 ++
   1.329 ++print_hex: 
   1.330 ++	movw	(%bp),%dx		/* load word into dx */
   1.331 ++	movb	$4, %cl
   1.332 ++	call	print_2digits
   1.333 ++print_2digits: 
   1.334 ++	call	print_digit
   1.335 ++/* fall through */
   1.336 ++print_digit: 
   1.337 ++	rol	%cl,%dx			/* rotate to use lowest 4 bits */
   1.338 ++	movb	$0x0f, %al		/* mask for nybble */
   1.339 ++	andb	%dl,%al
   1.340 ++	addb	$0x90, %al		/* convert al to ascii hex */
   1.341 ++	daa				/* (four instructions) */
   1.342 ++	adcb	$0x40, %al
   1.343 ++	daa
   1.344 ++print_char:
   1.345 ++	movb	$0x0e, %ah		/* write char, tty mode */
   1.346 ++	movw	$0x0007, %bx		/* page 0, attribute 7 (normal) */
   1.347 ++	int	$0x10
   1.348 ++	ret
   1.349 ++
   1.350 ++sread:	.word 0				/* sectors read of current track */
   1.351 ++head:	.word 0				/* current head */
   1.352 ++track:	.word 0				/* current track */
   1.353 ++
   1.354 ++sectors: 
   1.355 ++	.word 0
   1.356 + 
   1.357 +-why:	.ascii	"This image cannot be loaded from a floppy disk.\r\n"
   1.358 +-why_end: 
   1.359 ++dpseg:	.word 0
   1.360 ++dpoff:	.word 0
   1.361 + 
   1.362 ++disksizes: 
   1.363 ++	.byte 36,18,15,9,0
   1.364 ++
   1.365 ++msg1: 
   1.366 ++	.ascii "Loading ROM image"
   1.367 ++msg1end: 
   1.368 + 
   1.369 + 	.org	497
   1.370 + setup_sects: 
   1.371 +@@ -123,14 +426,23 @@
   1.372 + 	executing the Etherboot image that's loaded at SYSSEG:0 and
   1.373 + 	whose entry point is SYSSEG:0.
   1.374 + */
   1.375 +-setup_code:
   1.376 ++setup_code: 
   1.377 ++	movw	$(SYSSEG-(PREFIXSIZE/16)), %ax
   1.378 + 	/* Etherboot expects to be contiguous in memory once loaded.
   1.379 + 	 * LILO doesn't do this, but since we don't need any
   1.380 + 	 * information that's left in the prefix, it doesn't matter:
   1.381 + 	 * we just have to ensure that %cs:0000 is where the start of
   1.382 + 	 * the Etherboot image *would* be.
   1.383 + 	 */
   1.384 +-	ljmp	$(SYSSEG-(PREFIXSIZE/16)), $run_etherboot
   1.385 ++go_setup_code: 
   1.386 ++	xorw	%cx, %cx
   1.387 ++	pushw	%cx
   1.388 ++	pushw	%cx		/* No parameters to preserve for exit path */
   1.389 ++	pushw	%cx		/* Use prefix exit path mechanism */
   1.390 ++	pushw	%ax
   1.391 ++	pushw	$run_etherboot
   1.392 ++	/* Calculated lcall to _start with %cs:0000 = image start */
   1.393 ++	lret
   1.394 + 
   1.395 + 
   1.396 + 	.org	PREFIXSIZE