9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* [9fans] for your viewing pleasure: pbslba with comments
@ 2006-11-20 19:55 ron minnich
  0 siblings, 0 replies; only message in thread
From: ron minnich @ 2006-11-20 19:55 UTC (permalink / raw)
  To: Fans of the OS Plan 9 from Bell Labs

[-- Attachment #1: Type: text/plain, Size: 379 bytes --]

I thought some folks out there might enjoy this, I am just messing
around with pbs a bit, and wanted to make sure I understood it.
Corrections weclome.  I hope this 13K value-add to your inbox is
acceptable :-)

I just figure this early ugly stuff is something we need to really know about.

Sorry if this annoys anyone, but I hope some of you enjoy it.

thanks

ron

[-- Attachment #2.1: Type: text/plain, Size: 351 bytes --]

from postmaster@ethel:
The following attachment had content that we can't
prove to be harmless.  To avoid possible automatic
execution, we changed the content headers.
The original header was:

	Content-Type: application/octet-stream; name=newpbslba.s
	Content-Transfer-Encoding: base64
	Content-Disposition: attachment; filename="newpbslba.s"

[-- Attachment #2.2: newpbslba.s.suspect --]
[-- Type: application/octet-stream, Size: 13378 bytes --]

/*
 * FAT Partition Boot Sector. Loaded at 0x7C00:
 *	8a newpbslba.s; 8l -o newpbslba -l -H3 -T0x7C00 newpbslba.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 _volid field in the FAT header containing
 * the LBA of the root directory.
 */
#include "x16.h"
#include "mem.h"

#define LOADSEG		(0x10000/16)	/* where to load code (64KB) */
#define LOADOFF		0
#define DIROFF		0x0200		/* where to read the root directory */

/*
 * FAT directory entry.
 */
#define Dname		0x00
#define Dext		0x08
#define Dattr		0x0B
#define Dtime		0x16
#define Ddate		0x18
#define Dstart		0x1A
#define Dlengthlo	0x1C
#define Dlengthhi	0x1E

#define Dirsz		0x20

/*
 * Data is kept on the stack, indexed by rBP. Note that DAP is 16 bytes. 
 */
#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 */

#ifdef COMMENT 
IBM/MS INT 13 Extensions - EXTENDED READ

AH = 42h
DL = drive number
DS:SI -> disk address packet (see #00272)

Return:
CF clear if successful AH = 00h 
CF set on error AH = error code (see #00234) disk address packet's block count field set to number of blocks successfully transferred

See Also: AH=02h - AH=41h"INT 13 Ext" - AH=43h"INT 13 Ext"

Format of disk address packet: 
Offset Size Description (Table 00272) 
00h BYTE size of packet (10h or 18h) 
01h BYTE reserved (0) 
02h WORD number of blocks to transfer (max 007Fh for Phoenix EDD) 
04h DWORD -> transfer buffer 
08h QWORD starting absolute block number (for non-LBA devices, compute as (Cylinder*NumHeads + SelectedHead) * SectorPerTrack + SelectedSector - 1 
10h QWORD (EDD-3.0, optional) 64-bit flat address of transfer buffer; used if DWORD at 04h is FFFFh:FFFFh 
#endif

TEXT _magic(SB), $0
	BYTE $0xEB; BYTE $0x3C;		/* jmp .+ 0x3C  (_start0x3E) */
	BYTE $0x90			/* nop */
TEXT _version(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _sectsize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _clustsize(SB), $0
	BYTE $0x00
TEXT _nresrv(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _nfats(SB), $0
	BYTE $0x00
TEXT _rootsize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _volsize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _mediadesc(SB), $0
	BYTE $0x00
TEXT _fatsize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _trksize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _nheads(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _nhiddenlo(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _nhiddenhi(SB), $0
	BYTE $0x00; BYTE $0x00;
TEXT _bigvolsize(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
TEXT _driveno(SB), $0
	BYTE $0x00
TEXT _reserved0(SB), $0
	BYTE $0x00
TEXT _bootsig(SB), $0
	BYTE $0x00
TEXT _volid(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
TEXT _label(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _type(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;

_start0x3E:
	/* disable interrupts */
	CLI
	/* nice to have 0 in r0 */
	CLR(rAX)
	/* stack will be in low memory.  (first 64k) */
	MTSR(rAX, rSS)			/* 0000 -> rSS */
	/* data will be in low memory (first 64k) */
	MTSR(rAX, rDS)			/* 0000 -> rDS, source segment */
	/* extra will be in low memory (first 64k)  */
	MTSR(rAX, rES)
	/* sp lives at top of seg 0, and the stack starts at of this segment. Note that _magic starts at 7c00 */
	LWI(_magic-Xtotal(SB), rSP)
	MW(rSP, rBP)			/* set the indexed-data pointer */

	/* boot drive is passed in rDL from MBR */
	SBPB(rDL, Xdrive)		/* save the boot drive */

	/* I wonder why this happens? Matters not. Goal is to get CS (code seg) to be 0 */
	/* booting from a CD starts us at 7C0:0.  Move to 0:7C00 */
	/* push CS, which we want to be zero, and rAX is 0 */
	PUSHR(rAX)
	/* compute  offset, which is _nxt, load into rAX */
	LWI(_nxt(SB), rAX)
	/* push offset */
	PUSHR(rAX)
	/* this ret will load cs:ip which we just pushed. */
	BYTE $0xCB	/* FAR RET */

TEXT _nxt(SB), $0
	/* wonder why we enable interrupts? For errors ? */
	STI
	/* print out the cute message using BIOS interrupt */
	LWI(confidence(SB), rSI)	/* for that warm, fuzzy feeling */
	CALL16(BIOSputs(SB))

#ifdef COMMENT
see http://www.ctyme.com/intr/rb-0706.htm. read extensions. 
#endif
	LBI(0x41, rAH)			/* check extensions present */
	LWI(0x55AA, rBX)
	LXB(Xdrive, xBP, rDL)		/* drive */
	BIOSCALL(0x13)			/* CF set on failure */
	/* carry set means we're screwed, bios int failed for some reason */
	JCS _jmp01
	/* aa55 means installed; if not installed, we're screwed */
	CMPI(0xAA55, rBX)
	JNE _jmp01
	/* if bit 0 not set, there are no extend disk access instructions, we're screwed */
	ANDI(0x0001, rCX)
	JEQ _jmp01

	/* if we are here: the int 13 worked, the extensions are installed, and extended disk access is installed */

					/* rCX contains 0x0001 thanks to AND above*/
	
	/* this is just setting up stuff used later, is not related to the dreset below */
	/* Form up the invariant parts of Xdap -- data packet -- to be used for the I/O*/
	/* set the ATA packet size -- NOT the I/O size, the PACKET size 0x10 or 0x18 */
	SBPWI(0x0010, Xdap+0)		/* reserved + packet size */
	/* we always transfer one block */
	SBPWI(rCX, Xdap+2)		/* reserved + # of blocks to transfer */

	/* clear rCX cheaply */
	DEC(rCX)
	/* zero out more of the data packet -- this is high-order 32 bits of address */
	SBPW(rCX, Xdap+12)
	SBPW(rCX, Xdap+14)

	CALL16(dreset(SB))

_jmp00:
	/* this was, we assume, set in mbr ... or by format */
	LW(_volid(SB), rAX)		/* Xrootlo */
	LW(_volid+2(SB), rDX)		/* Xroothi */

	LWI(_magic+DIROFF(SB), rBX)
	CALL16(BIOSread(SB))		/* read the root directory */

	/* note the assumption here, dir is one 512-byte block, so you only get 16 entries to search for */
	LWI((512/Dirsz), rBX)

	LWI(_magic+DIROFF(SB), rDI)	/* compare first directory entry */

_cmp00:
	PUSHR(rDI)			/* save for later if it matches */
	LWI(bootfile(SB), rSI)		/* e.g. '9load' */
	LWI(Dattr, rCX)			/* this is 0x'B', or .. 8.3 */
	/* strncmp */
	REP
	CMPSB
	/* pop the DI, you trashed it in the CMPSB */
	POPR(rDI)
	/* match */
	JEQ _jmp02

	/* no match; anything left? */
	DEC(rBX)
	JEQ _jmp01

	/* search next ... increment di */
	ADDI(Dirsz, rDI)
	JMP _cmp00
_jmp01:
	CALL16(buggery(SB))

_jmp02:
	CLR(rBX)			/* a handy value */
	LW(_rootsize(SB), rAX)		/* calculate and save Xrootsz */
	/* ax = rootsize (I assume in entries ) */
	LWI(Dirsz, rCX)
	/* cx  = dirsz (a constant) */
	MUL(rCX)
	/* rootbytes = dirsz * rootsize (result in rdx:rax (rax low)*/
	LW(_sectsize(SB), rCX)
	/* cx = sectsize, from MBR */
	PUSHR(rCX)	
	DEC(rCX)
	/* cx--;*/
	ADD(rCX, rAX)
	/* rootbytes += sectsize - 1 (from cx) */
	/* propagate high bit to get 32-bit add */
	ADC(rBX, rDX)
	/* (second half) rootbytes += sectsize (note bx is 0 so we just add C bit */
	POPR(rCX)			/* _sectsize(SB) */
	/* restore the sectsize */
	DIV(rCX)
	/* divide */
	/* so what is this? Basically, it's a way of finding first cluster after directory */
	/* firstclust = ((rootsize * direntsize) + (clustsize - 1))/clustsize ==> clustno in rdx:rax */
	/* it is also the rootsz in clusters */
	/* and then save rax, I guess we don't save rdx */
	/* it is 0 at this point anyway */
	PUSHR(rAX)			/* Xrootsz */

	/*
	 * rDI points to the matching directory entry.
	 */
	/* so we index into the FAT entry pointed to by DI, and get starting cluster */
	/* and, for reasons unknown to us, it is decremented */
	LXW(Dstart, xDI, rAX)		/* starting cluster address */
	DEC(rAX)			/* that's just the way it is */
	DEC(rAX)

#ifdef COMMENT
http://www.ctyme.com/intr/rb-0607.htm
AH = 02h
AL = number of sectors to read (must be nonzero)
CH = low eight bits of cylinder number
CL = sector number 1-63 (bits 0-5) , high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer
#endif
	/* set clustersize in rCL */
	LB(_clustsize(SB), rCL)
	CLRB(rCH)
	/* rCX now has the clustersize */
	/* rAX has the cluster # */
	MUL(rCX)
	/* rDX:rAX now has sector, we get this from multiplying the cluster size * cluster #*/
	/* root is the sector of the root */
	/* we offset the computed sector by the start of the root */
	LW(_volid(SB), rCX)		/* Xrootlo */
	ADD(rCX, rAX)
	LW(_volid+2(SB), rCX)		/* Xroothi */
	ADC(rCX, rDX)
	/* then we offset by the size of the root */
	POPR(rCX)			/* Xrootsz */
	ADD(rCX, rAX)
	ADC(rBX, rDX)

	/* save our computed sector # */
	PUSHR(rAX)			/* calculate how many sectors to read */
	PUSHR(rDX)
	/* get our length to read */
	LXW(Dlengthlo, xDI, rAX)
	LXW(Dlengthhi, xDI, rDX)
	/* sectsize is sector size in bytes */
	LW(_sectsize(SB), rCX)
	PUSHR(rCX)
	/* sectsize -- */
	DEC(rCX)
	ADD(rCX, rAX)
	ADC(rBX, rDX)
	/* length + sectsize  -1 */
	POPR(rCX)			/* _sectsize(SB) */
	/* (length + sectsize --) / sectsize */
	DIV(rCX)
	/* result in rDX:RAX, rDX is zero, store in rCX */
	MW(rAX, rCX)
	/* restore computed sector */
	POPR(rDX)
	POPR(rAX)

	/* set us up to read the data in at LOADSEG:LOADOFF */
	LWI(LOADSEG, rBX)		/* address to load into (seg+offset) */
	MTSR(rBX, rES)			/*  seg */
	LWI(LOADOFF, rBX)		/*  offset */

	/* pull it in, one clustersize  thing at a time */
_readboot:
	CALL16(BIOSread(SB))		/* read the sector(s) */
	/* success if we have returned */
	/* load sectsize into rDI */
	LW(_sectsize(SB), rDI)		/* bump addresses/counts */
	/* we bump the offset, if it wraps to the next segment we have to accomodate that */
	/* carry clear means it did not wrap */
	/* so bump the offset */
	ADD(rDI, rBX)
	/* if we don't wrap off the end of the segment, just need to grow secno */
	JCC _incsecno

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

_incsecno:
	/* we're here because we DID not wrap */
	/* this is a 32-bit add, note we clear RDI to make it go */
	CLR(rDI)
	INC(rAX)
	ADC(rDI, rDX)
	/* LOOP lops until cx is zero IIRC */
	LOOP _readboot

	/* so we're here; bootstrap read in OK */
	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 */

	/* set up the packet. This is using the indexed BP register for loads etc. */
	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

/*
 * 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

/* "Bad format or I/O error\r\nPress almost any key to reboot..." */
TEXT error(SB), $0
	BYTE $'B'; BYTE $'a'; BYTE $'d'; BYTE $' ';
	BYTE $'f'; BYTE $'o'; BYTE $'r'; BYTE $'m';
	BYTE $'a'; BYTE $'t'; BYTE $' '; BYTE $'o';
	BYTE $'r'; BYTE $' ';
/* "I/O error\r\nPress almost any key to reboot..." */
TEXT ioerror(SB), $0
	BYTE $'I'; BYTE $'/'; BYTE $'O'; BYTE $' ';
	BYTE $'e'; BYTE $'r'; BYTE $'r'; BYTE $'o';
	BYTE $'r'; BYTE $'\r';BYTE $'\n';
	BYTE $'P'; BYTE $'r'; BYTE $'e'; BYTE $'s';
	BYTE $'s'; BYTE $' '; BYTE $'a'; BYTE $' ';
	BYTE $'k'; BYTE $'e'; BYTE $'y';
	BYTE $' '; BYTE $'t'; BYTE $'o'; BYTE $' ';
	BYTE $'r'; BYTE $'e'; BYTE $'b'; BYTE $'o';
	BYTE $'o'; BYTE $'t';
	BYTE $'.'; BYTE $'.'; BYTE $'.';
	BYTE $'\z';

#ifdef USEBCOM
/* "B       COM" */
TEXT bootfile(SB), $0
	BYTE $'B'; BYTE $' '; BYTE $' '; BYTE $' ';
	BYTE $' '; BYTE $' '; BYTE $' '; BYTE $' ';
	BYTE $'C'; BYTE $'O'; BYTE $'M';
	BYTE $'\z';
#else
/* "9LOAD      " */
TEXT bootfile(SB), $0
	BYTE $'9'; BYTE $'L'; BYTE $'O'; BYTE $'A';
	BYTE $'D'; BYTE $' '; BYTE $' '; BYTE $' ';
	BYTE $' '; BYTE $' '; BYTE $' ';
	BYTE $'\z';
#endif /* USEBCOM */

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2006-11-20 19:55 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-11-20 19:55 [9fans] for your viewing pleasure: pbslba with comments ron minnich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).