Plan 9 from Bell Labs’s /usr/web/sources/plan9/sys/src/boot/pc/pbsraw.s

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 *  Partition Boot Sector. Loaded at 0x7C00:
 *	8a pbsraw.s; 8l -o pbsraw -l -H3 -T0x7C00 pbsraw.8
 * Will load the target at LOADSEG*16+LOADOFF, so the target
 * should be probably be loaded with LOADOFF added to the
 * -Taddress.
 * If LOADSEG is a multiple of 64KB and LOADOFF is 0 then
 * targets larger than 64KB can be loaded.
 *
 * This code is uses Enhanced BIOS Services for Disc Drives and
 * can be used with discs up to 137GB in capacity.
 *
 * It relies on the _startlba,  _filesz and _sectsz containing the start lba of
 * the loader and filesz to contain the size of the file and the sector size.
 * The sector size can be probably detected by the bios.
 */
#include "x16.h"

#define LOADSEG		(0x10000/16)	/* where to load code (64KB) */
#define LOADOFF		0

/*
 * Data is kept on the stack, indexed by rBP.
 */
#define Xdap		0x00		/* disc address packet */
#define Xrootsz		0x10		/* file data area */
#define Xdrive		0x12		/* boot drive, passed by BIOS or MBR */
#define Xtotal		0x14		/* sum of allocated data above */

TEXT _magic(SB), $0
	BYTE $0xEB; BYTE $0x3C;		/* jmp .+ 0x3C  (_start0x3E) */
	BYTE $0x90			/* nop */
TEXT _startlba(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _filesz(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _sectsz(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _pad(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00

_start0x3E:
	CLI
	CLR(rAX)
	MTSR(rAX, rSS)			/* 0000 -> rSS */
	MTSR(rAX, rDS)			/* 0000 -> rDS, source segment */
	MTSR(rAX, rES)
	LWI(_magic-Xtotal(SB), rSP)
	MW(rSP, rBP)			/* set the indexed-data pointer */

	SBPB(rDL, Xdrive)		/* save the boot drive */

	/* booting from a CD starts us at 7C0:0.  Move to 0:7C00 */
	PUSHR(rAX)
	LWI(_nxt(SB), rAX)
	PUSHR(rAX)
	BYTE $0xCB			/* FAR RET */

TEXT _nxt(SB), $0
	STI

	LWI(confidence(SB), rSI)	/* for that warm, fuzzy feeling */
	CALL16(BIOSputs(SB))

	LBI(0x41, rAH)			/* check extensions present */
	LWI(0x55AA, rBX)
	LXB(Xdrive, xBP, rDL)		/* drive */
	BIOSCALL(0x13)			/* CF set on failure */
	JCS _jmp00
	CMPI(0xAA55, rBX)
	JNE _jmp00
	ANDI(0x0001, rCX)
	JNE _jmp01

_jmp00:
	CALL16(buggery(SB))

_jmp01:
	SBPWI(0x0010, Xdap+0)		/* reserved + packet size */
	SBPW(rCX, Xdap+2)		/* reserved + # of blocks to transfer */

	DEC(rCX)
	SBPW(rCX, Xdap+12)
	SBPW(rCX, Xdap+14)

	CALL16(dreset(SB))

_jmp02:
	CLR(rBX)			/* a handy value */

	LW(_startlba(SB), rAX)
	LW(_startlba+2(SB), rDX)
	CALL16(printDXAX(SB))
	PUSHR(rAX)
	PUSHR(rDX)
	LW(_filesz(SB), rAX)
	LW(_filesz+2(SB), rDX)
	CALL16(printDXAX(SB))

	MW(rAX, rCX)
	POPR(rDX)
	POPR(rAX)

	LWI(LOADSEG, rBX)		/* address to load into (seg+offset) */
	MTSR(rBX, rES)			/*  seg */
	LWI(LOADOFF, rBX)		/*  offset */

_readboot:
	CALL16(BIOSread(SB))		/* read the sector */

	LW(_sectsz(SB), rDI)		/* bump addresses/counts */
	ADD(rDI, rBX)
	JCC _incsecno

	MFSR(rES, rDI)			/* next 64KB segment */
	ADDI(0x1000, rDI)
	MTSR(rDI, rES)

_incsecno:
	CLR(rDI)
	INC(rAX)
	ADC(rDI, rDX)
	LOOP _readboot

	LWI(LOADSEG, rDI)		/* set rDS for loaded code */
	MTSR(rDI, rDS)
	FARJUMP16(LOADSEG, LOADOFF)	/* no deposit, no return */

TEXT buggery(SB), $0
	LWI(error(SB), rSI)
	CALL16(BIOSputs(SB))

_wait:
	CLR(rAX)			/* wait for almost any key */
	BIOSCALL(0x16)

_reset:
	CLR(rBX)			/* set ES segment for BIOS area */
	MTSR(rBX, rES)

	LWI(0x0472, rBX)		/* warm-start code address */
	LWI(0x1234, rAX)		/* warm-start code */
	POKEW				/* MOVW	AX, ES:[BX] */

	FARJUMP16(0xFFFF, 0x0000)	/* reset */

/*
 * Read a sector from a disc. On entry:
 *   rDX:rAX	sector number
 *   rES:rBX	buffer address
 */
TEXT BIOSread(SB), $0
	LWI(5, rDI)			/* retry count (ATAPI ZIPs suck) */
_retry:
	PUSHA				/* may be trashed by BIOSCALL */

	SBPW(rBX, Xdap+4)		/* transfer buffer :offset */
	MFSR(rES, rDI)			/* transfer buffer seg: */
	SBPW(rDI, Xdap+6)
	SBPW(rAX, Xdap+8)		/* LBA (64-bits) */
	SBPW(rDX, Xdap+10)

	MW(rBP, rSI)			/* disk address packet */
	LBI(0x42, rAH)			/* extended read */
	LBPB(Xdrive, rDL)		/* form drive */
	BIOSCALL(0x13)			/* CF set on failure */
	JCC _BIOSreadret

	POPA
	DEC(rDI)			/* too many retries? */
	JEQ _ioerror

	CALL16(dreset(SB))
	JMP _retry

_ioerror:
	LWI(ioerror(SB), rSI)
	CALL16(BIOSputs(SB))
	JMP _wait

_BIOSreadret:
	POPA
	RET

TEXT dreset(SB), $0
	PUSHA
	CLR(rAX)			/* rAH == 0 == reset disc system */
	LBPB(Xdrive, rDL)
	BIOSCALL(0x13)
	ORB(rAH, rAH)			/* status (0 == success) */
	POPA
	JNE _ioerror
	RET

TEXT printsharp(SB), $0
	LWI(sharp(SB), rSI)
_doprint:
	CALL16(BIOSputs(SB))
	RET

TEXT printspace(SB), $0
	LWI(space(SB), rSI)
	JMP _doprint

TEXT printnl(SB), $0
	LWI(nl(SB), rSI)
	JMP _doprint

/*
 * Output a string to the display.
 * String argument is in rSI.
 */
TEXT BIOSputs(SB), $0
	PUSHA
	CLR(rBX)
_BIOSputs:
	LODSB
	ORB(rAL, rAL)
	JEQ _BIOSputsret

	LBI(0x0E, rAH)
	BIOSCALL(0x10)
	JMP _BIOSputs

_BIOSputsret:
	POPA
	RET

/*
 * Output a register to the display.
 */
TEXT printAX(SB), $0
	PUSHR(rAX)
	PUSHR(rBX)
	PUSHR(rCX)
	PUSHR(rDI)

	LWI(4, rCX)
	LWI(numbuf+4(SB), rSI)

_nextchar:
	DEC(rSI)
	MW(rAX, rBX)
	ANDI(0x000F, rBX)
	ADDI(0x30, rBX)	/* 0x30 = '0' */
	CMPI(0x39, rBX)	/* 0x39 = '9' */
	JLE _dowrite
	ADDI(0x07, rBX)	/* 0x07 = 'A'-(1+'9')*/

_dowrite:
	SXB(rBL, 0, xSI)
	SHRI(4, rAX)

	DEC(rCX)
	JNE _nextchar

	LWI(numbuf(SB), rSI)
	CALL16(BIOSputs(SB))

	POPR(rDI)
	POPR(rCX)
	POPR(rBX)
	POPR(rAX)

	CALL16(printspace(SB))
	RET

TEXT printDXAX(SB), $0
	PUSHR(rAX)
	MW(rDX, rAX)
	CALL16(printAX(SB))
	POPR(rAX)
	CALL16(printAX(SB))
	RET

TEXT printBX(SB), $0
	PUSHR(rAX)
	MW(rBX, rAX)
	CALL16(printAX(SB))
	POPR(rAX)
	RET

TEXT error(SB), $0
	BYTE $'E';

TEXT ioerror(SB), $0
	BYTE $'I';

TEXT nl(SB), $0
	BYTE $'\r';
	BYTE $'\n';
	BYTE $'\z';

TEXT numbuf(SB), $0
	BYTE $'X'; BYTE $'X'; BYTE $'X'; BYTE $'X';
	BYTE $'\z';

TEXT space(SB), $0
	BYTE $' ';
	BYTE $'\z';

TEXT sharp(SB), $0
	BYTE $'#'; BYTE $'\z';

/* "PBSR..." */
TEXT confidence(SB), $0
	BYTE $'P'; BYTE $'B'; BYTE $'S'; BYTE $'R';
	BYTE $'.'; BYTE $'.'; BYTE $'.';
	BYTE $'\z';

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.