pbsfun/000755 000765 000000 00000000000 10676462220 012773 5ustar00paureawheel000000 000000 pbsfun/mypbs/000755 000765 000000 00000000000 11536425746 014135 5ustar00paureawheel000000 000000 pbsfun/ronstuff/000755 000765 000000 00000000000 10676462220 014641 5ustar00paureawheel000000 000000 pbsfun/ronstuff/boot/000755 000765 000000 00000000000 10676462220 015604 5ustar00paureawheel000000 000000 pbsfun/ronstuff/boot/pbslba.s000644 000765 000000 00000017723 10676462217 017253 0ustar00paureawheel000000 000000 /* * FAT Partition Boot Sector. Loaded at 0x7C00: * 8a pbslba.s; 8l -o pbslba -l -H3 -T0x7C00 pbslba.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. */ #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 _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: 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 _jmp01 CMPI(0xAA55, rBX) JNE _jmp01 ANDI(0x0001, rCX) JEQ _jmp01 /* rCX contains 0x0001 */ SBPWI(0x0010, Xdap+0) /* reserved + packet size */ SBPWI(rCX, Xdap+2) /* reserved + # of blocks to transfer */ DEC(rCX) SBPW(rCX, Xdap+12) SBPW(rCX, Xdap+14) CALL16(dreset(SB)) _jmp00: LW(_volid(SB), rAX) /* Xrootlo */ LW(_volid+2(SB), rDX) /* Xroothi */ LWI(_magic+DIROFF(SB), rBX) CALL16(BIOSread(SB)) /* read the root directory */ 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) LWI(Dattr, rCX) REP CMPSB POPR(rDI) JEQ _jmp02 DEC(rBX) JEQ _jmp01 ADDI(Dirsz, rDI) JMP _cmp00 _jmp01: CALL16(buggery(SB)) _jmp02: CLR(rBX) /* a handy value */ LW(_rootsize(SB), rAX) /* calculate and save Xrootsz */ LWI(Dirsz, rCX) MUL(rCX) LW(_sectsize(SB), rCX) PUSHR(rCX) DEC(rCX) ADD(rCX, rAX) ADC(rBX, rDX) POPR(rCX) /* _sectsize(SB) */ DIV(rCX) PUSHR(rAX) /* Xrootsz */ /* * rDI points to the matching directory entry. */ LXW(Dstart, xDI, rAX) /* starting sector address */ DEC(rAX) /* that's just the way it is */ DEC(rAX) LB(_clustsize(SB), rCL) CLRB(rCH) MUL(rCX) LW(_volid(SB), rCX) /* Xrootlo */ ADD(rCX, rAX) LW(_volid+2(SB), rCX) /* Xroothi */ ADC(rCX, rDX) POPR(rCX) /* Xrootsz */ ADD(rCX, rAX) ADC(rBX, rDX) PUSHR(rAX) /* calculate how many sectors to read */ PUSHR(rDX) LXW(Dlengthlo, xDI, rAX) LXW(Dlengthhi, xDI, rDX) LW(_sectsize(SB), rCX) PUSHR(rCX) DEC(rCX) ADD(rCX, rAX) ADC(rBX, rDX) POPR(rCX) /* _sectsize(SB) */ DIV(rCX) 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(_sectsize(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 /* * 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'; pbsfun/ronstuff/boot/pc/000755 000765 000000 00000000000 11536426132 016204 5ustar00paureawheel000000 000000 pbsfun/ronstuff/boot/pc/mem.h000644 000765 000000 00000006453 10676462217 017153 0ustar00paureawheel000000 000000 /* * Memory and machine-specific definitions. Used in C and assembler. */ /* * Sizes */ #define BI2BY 8 /* bits per byte */ #define BI2WD 32 /* bits per word */ #define BY2WD 4 /* bytes per word */ #define BY2PG 4096 /* bytes per page */ #define WD2PG (BY2PG/BY2WD) /* words per page */ #define PGSHIFT 12 /* log(BY2PG) */ #define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) #define MAXMACH 1 /* max # cpus system can run */ /* * Time */ #define HZ (100) /* clock frequency */ #define MS2HZ (1000/HZ) /* millisec per clock tick */ #define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ #define TK2MS(x) ((x)*(1000/HZ)) #define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */ /* * Fundamental addresses */ #define IDTADDR 0x80000800 /* idt */ #define APBOOTSTRAP 0x80001000 /* AP bootstrap code */ #define CONFADDR 0x80001200 /* info passed from boot loader */ #define CPU0PDB 0x80002000 /* bootstrap processor PDB */ #define CPU0PTE 0x80003000 /* bootstrap processor PTE's for 0-4MB */ #define MACHADDR 0x80004000 /* as seen by current processor */ #define CPU0MACH 0x80005000 /* Mach for bootstrap processor */ #define MACHSIZE (BY2PG*8) /* stack size */ /* * Address spaces * * Kernel is at 2GB-4GB */ #define KZERO 0x80000000 /* base of kernel address space */ #define KTZERO KZERO /* first address in kernel text */ #define ROMBIOS (KZERO|0xF0000) /* * known 80386 segments (in GDT) and their selectors */ #define NULLSEG 0 /* null segment */ #define KDSEG 1 /* kernel data/stack */ #define KESEG 2 /* kernel executable */ #define UDSEG 3 /* user data/stack */ #define UESEG 4 /* user executable */ #define SYSGATE 5 /* system call gate */ #define TSSSEG 6 /* task segment */ #define SELGDT (0<<3) /* selector is in gdt */ #define SELLDT (1<<3) /* selector is in ldt */ #define SELECTOR(i, t, p) (((i)<<3) | (t) | (p)) #define NULLSEL SELECTOR(NULLSEG, SELGDT, 0) #define KESEL SELECTOR(KESEG, SELGDT, 0) #define KDSEL SELECTOR(KDSEG, SELGDT, 0) #define UESEL SELECTOR(UESEG, SELGDT, 3) #define UDSEL SELECTOR(UDSEG, SELGDT, 3) #define TSSSEL SELECTOR(TSSSEG, SELGDT, 0) /* * fields in segment descriptors */ #define SEGDATA (0x10<<8) /* data/stack segment */ #define SEGEXEC (0x18<<8) /* executable segment */ #define SEGTSS (0x9<<8) /* TSS segment */ #define SEGCG (0x0C<<8) /* call gate */ #define SEGIG (0x0E<<8) /* interrupt gate */ #define SEGTG (0x0F<<8) /* task gate */ #define SEGTYPE (0x1F<<8) #define SEGP (1<<15) /* segment present */ #define SEGPL(x) ((x)<<13) /* priority level */ #define SEGB (1<<22) /* granularity 1==4k (for expand-down) */ #define SEGG (1<<23) /* granularity 1==4k (for other) */ #define SEGE (1<<10) /* expand down */ #define SEGW (1<<9) /* writable (for data/stack) */ #define SEGR (1<<9) /* readable (for code) */ #define SEGD (1<<22) /* default 1==32bit (for code) */ /* * virtual MMU */ #define PTEMAPMEM (1024*1024) /* ??? */ #define SEGMAPSIZE 16 /* ??? */ #define PTEPERTAB (PTEMAPMEM/BY2PG) /* ??? */ #define PPN(x) ((x)&~(BY2PG-1)) /* * physical MMU */ #define PTEVALID (1<<0) #define PTEUNCACHED 0 /* everything is uncached */ #define PTEWRITE (1<<1) #define PTERONLY (0<<1) #define PTEKERNEL (0<<2) #define PTEUSER (1<<2) #define PTESIZE (1<<7) /* * flag register bits that we care about */ #define IFLAG 0x200 pbsfun/ronstuff/boot/pc/newpbslba.1.s000644 000765 000000 00000032610 10676462220 020510 0ustar00paureawheel000000 000000 /* * 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 0x18 /* file data area */ #define Xdrive 0x1a /* boot drive, passed by BIOS or MBR */ #define Xtotal 0x1c /* 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(0x0018, 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) /* set some -f stuff into the seg:off part of the packet */ DEC(rCX) SBPW(rCX, Xdap+4) SBPW(rCX, Xdap+6) /* note rCX is now -1 */ CALL16(dreset(SB)) _jmp00: #ifdef COMMENT /* 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 */ #endif #ifdef COMMENT /* 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 #endif JMP _jmp02 _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 */ #ifdef COMMENT /* 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) #endif /* OK, if we put a 0 here, that gets us to 9load wihout all the crap */ /* I have tested this by putting other numbers here, and it really breaks */ LWI(0, rAX) /* 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) #ifdef COMMENT /* get our length to read */ LXW(Dlengthlo, xDI, rAX) LXW(Dlengthhi, xDI, rDX) #endif /* hard-code length to 256KB for now */ LWI(0, rAX) LWI((262144>>16), 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) /* NOTE: 10 vs x10 */ SBPW(rBX,Xdap+0x10) SBPW(rDI, Xdap+0x12) /* ok, add the code to move the address to the extended packet. */ /* we are not using the packet yet. */ 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'; pbsfun/ronstuff/boot/pc/newpbslba.s000644 000765 000000 00000031173 10676462220 020354 0ustar00paureawheel000000 000000 /* * 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 */ #define DATAOFF 0x10000 /* where to read the data */ /* * 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 0x18 /* file data area */ #define Xdrive 0x1a /* boot drive, passed by BIOS or MBR */ #define Xtotal 0x1c /* 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(0x0018, 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) /* set some -f stuff into the seg:off part of the packet */ DEC(rCX) SBPW(rCX, Xdap+4) SBPW(rCX, Xdap+6) /* note rCX is now -1 */ CALL16(dreset(SB)) _jmp00: JMP _jmp02 _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 */ #ifdef COMMENT /* 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) #endif /* OK, if we put a 0 here, that gets us to 9load wihout all the crap */ /* I have tested this by putting other numbers here, and it really breaks */ LWI(0, rAX) /* 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) #ifdef COMMENT /* get our length to read */ LXW(Dlengthlo, xDI, rAX) LXW(Dlengthhi, xDI, rDX) #endif /* hard-code length to 256KB for now */ LWI(0, rAX) LWI((262144>>16), 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) /* NOTE: 10 vs x10 */ SBPW(rBX,Xdap+0x10) SBPW(rDI, Xdap+0x12) /* ok, add the code to move the address to the extended packet. */ /* we are not using the packet yet. */ 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 $'C'; BYTE $'S'; BYTE $'.'; BYTE $'.'; BYTE $'.'; BYTE $'\z'; pbsfun/ronstuff/boot/pc/pbslba.s000644 000765 000000 00000017723 10676462220 017647 0ustar00paureawheel000000 000000 /* * FAT Partition Boot Sector. Loaded at 0x7C00: * 8a pbslba.s; 8l -o pbslba -l -H3 -T0x7C00 pbslba.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. */ #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 _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: 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 _jmp01 CMPI(0xAA55, rBX) JNE _jmp01 ANDI(0x0001, rCX) JEQ _jmp01 /* rCX contains 0x0001 */ SBPWI(0x0010, Xdap+0) /* reserved + packet size */ SBPWI(rCX, Xdap+2) /* reserved + # of blocks to transfer */ DEC(rCX) SBPW(rCX, Xdap+12) SBPW(rCX, Xdap+14) CALL16(dreset(SB)) _jmp00: LW(_volid(SB), rAX) /* Xrootlo */ LW(_volid+2(SB), rDX) /* Xroothi */ LWI(_magic+DIROFF(SB), rBX) CALL16(BIOSread(SB)) /* read the root directory */ 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) LWI(Dattr, rCX) REP CMPSB POPR(rDI) JEQ _jmp02 DEC(rBX) JEQ _jmp01 ADDI(Dirsz, rDI) JMP _cmp00 _jmp01: CALL16(buggery(SB)) _jmp02: CLR(rBX) /* a handy value */ LW(_rootsize(SB), rAX) /* calculate and save Xrootsz */ LWI(Dirsz, rCX) MUL(rCX) LW(_sectsize(SB), rCX) PUSHR(rCX) DEC(rCX) ADD(rCX, rAX) ADC(rBX, rDX) POPR(rCX) /* _sectsize(SB) */ DIV(rCX) PUSHR(rAX) /* Xrootsz */ /* * rDI points to the matching directory entry. */ LXW(Dstart, xDI, rAX) /* starting sector address */ DEC(rAX) /* that's just the way it is */ DEC(rAX) LB(_clustsize(SB), rCL) CLRB(rCH) MUL(rCX) LW(_volid(SB), rCX) /* Xrootlo */ ADD(rCX, rAX) LW(_volid+2(SB), rCX) /* Xroothi */ ADC(rCX, rDX) POPR(rCX) /* Xrootsz */ ADD(rCX, rAX) ADC(rBX, rDX) PUSHR(rAX) /* calculate how many sectors to read */ PUSHR(rDX) LXW(Dlengthlo, xDI, rAX) LXW(Dlengthhi, xDI, rDX) LW(_sectsize(SB), rCX) PUSHR(rCX) DEC(rCX) ADD(rCX, rAX) ADC(rBX, rDX) POPR(rCX) /* _sectsize(SB) */ DIV(rCX) 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(_sectsize(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 /* * 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'; pbsfun/ronstuff/boot/pc/pbslba.s.hacked000644 000765 000000 00000027175 10676462220 021067 0ustar00paureawheel000000 000000 /* * FAT Partition Boot Sector. Loaded at 0x7C00: * 8a pbslba.s; 8l -o pbslba -l -H3 -T0x7C00 pbslba.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. */ #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 _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 */ 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 #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 */ JCS _jmp01 /* aa55 means installed; if not installed, we're screwed */ CMPI(0xAA55, rBX) JNE _jmp01 /* if 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 */ /* 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 -- at least I think that is what this is */ 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 probably address area */ SBPW(rCX, Xdap+12) SBPW(rCX, Xdap+14) CALL16(dreset(SB)) _jmp00: LW(_volid(SB), rAX) /* Xrootlo */ LW(_volid+2(SB), rDX) /* Xroothi */ /* actually we are going to read sector 2. That will in the long term be an a.out header */ ADDI(2, rAX) /* do this read, even though we don' t use it yet */ LWI(_magic+DIROFF(SB), rBX) CALL16(BIOSread(SB)) /* read the root directory */ /* Just set rDI to 3 */ LWI(3, xDI) JMP _jmp02 _jmp01: CALL16(buggery(SB)) _jmp02: CLR(rBX) /* a handy value */ #ifdef THIS_SUIT_IS_BLACK__________________NOT LW(_rootsize(SB), rAX) /* calculate and save Xrootsz */ /* ax = rootsize */ 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 */ 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 */ 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) #endif /* set the cluster # into rAX */ LWI(3, xDI) LWI(3, 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) /* we are going to be stupid for now. We will be smart later. */ /* just load 1st MB of stuff */ LWI(0, rAX) LWI(1048576, rDX) /* sectsize is sector size in bytes methinks */ 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) */ /* so data is read into rs:LOADOFF, and rBX is ... uh what? */ MTSR(rBX, rES) /* seg */ LWI(LOADOFF, rBX) /* offset */ /* pull it in, one 64kb thing at a time */ _readboot: CALL16(BIOSread(SB)) /* read the sector */ /* 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 sector # */ ADD(rDI, rBX) JCC _incsecno MFSR(rES, rDI) /* next 64KB segment */ ADDI(0x1000, rDI) MTSR(rDI, rES) _incsecno: /* we're here because we DID not wrap */ CLR(rDI) INC(rAX) ADC(rDI, rDX) /* LOOP lops until cx is zero IIRC */ LOOP _readboot /* so we're here; bootstrap read */ 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 /* * 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'; pbsfun/ronstuff/boot/pc/x16.h000644 000765 000000 00000012221 10676462220 016773 0ustar00paureawheel000000 000000 /* * Can't write 16-bit code for 8a without getting into * lots of bother, so define some simple commands and * output the code directly. * * N.B. CALL16(x) kills DI, so don't expect it to be * saved across calls. */ #define rAX 0 /* rX */ #define rCX 1 #define rDX 2 #define rBX 3 #define rSP 4 /* SP */ #define rBP 5 /* BP */ #define rSI 6 /* SI */ #define rDI 7 /* DI */ #define rAL 0 /* rL */ #define rCL 1 #define rDL 2 #define rBL 3 #define rAH 4 /* rH */ #define rCH 5 #define rDH 6 #define rBH 7 #define rES 0 /* rS */ #define rCS 1 #define rSS 2 #define rDS 3 #define rFS 4 #define rGS 5 #define xSI 4 /* rI (index) */ #define xDI 5 #define xBP 6 #define xBX 7 #define rCR0 0 /* rC */ #define rCR2 2 #define rCR3 3 #define rCR4 4 #define OP(o, m, ro, rm) BYTE $o; /* op + modr/m byte */ \ BYTE $(((m)<<6)|((ro)<<3)|(rm)) #define OPrm(o, r, m) OP(o, 0x00, r, 0x06); /* general r <-> m */ \ WORD $m; #define OPrr(o, r0, r1) OP(o, 0x03, r0, r1); /* general r -> r */ #define LW(m, rX) OPrm(0x8B, rX, m) /* m -> rX */ #define LXW(x, rI, r) OP(0x8B, 0x02, r, rI); /* x(rI) -> r */ \ WORD $x #define LBPW(x, r) OP(0x8B, 0x02, r, xBP); /* x(rBP) -> r */ \ WORD $x #define LB(m, rB) OPrm(0x8A, rB, m) /* m -> r[HL] */ #define LXB(x, rI, r) OP(0x8A, 0x01, r, rI); /* x(rI) -> r */ \ BYTE $x #define LBPB(x, r) OP(0x8A, 0x01, r, xBP); /* x(rBP) -> r */ \ BYTE $x #define SW(rX, m) OPrm(0x89, rX, m) /* rX -> m */ #define SXW(r, x, rI) OP(0x89, 0x02, r, rI); /* r -> x(rI) */ \ WORD $x #define SBPW(r, x) OP(0x89, 0x02, r, xBP); /* r -> x(rBP) */ \ WORD $(x) #define SBPWI(i, x) OP(0xC7, 0x01, 0, xBP); /* i -> x(rBP) */ \ BYTE $(x); WORD $(i) #define STB(rB, m) OPrm(0x88, rB, m) /* rB -> m */ #define SXB(r, x, rI) OP(0x88, 0x01, r, rI); /* rB -> x(rI) */ \ BYTE $x #define SBPB(r, x) OP(0x88, 0x01, r, xBP); /* r -> x(rBP) */ \ BYTE $x #define SBPBI(i, x) OP(0xC6, 0x01, 0, xBP); /* i -> x(rBP) */ \ BYTE $(x); BYTE $(i) #define LWI(i, rX) BYTE $(0xB8+rX); /* i -> rX */ \ WORD $i; #define LBI(i, rB) BYTE $(0xB0+rB); /* i -> r[HL] */ \ BYTE $i #define MW(r0, r1) OPrr(0x89, r0, r1) /* r0 -> r1 */ #define MFSR(rS, rX) OPrr(0x8C, rS, rX) /* rS -> rX */ #define MTSR(rX, rS) OPrr(0x8E, rS, rX) /* rX -> rS */ #define MFCR(rC, rX) BYTE $0x0F; /* rC -> rX */ \ OP(0x20, 0x03, rC, rX) #define MTCR(rX, rC) BYTE $0x0F; /* rX -> rC */ \ OP(0x22, 0x03, rC, rX) #define ADC(r0, r1) OPrr(0x11, r0, r1) /* r0 + r1 -> r1 */ #define ADD(r0, r1) OPrr(0x01, r0, r1) /* r0 + r1 -> r1 */ #define ADDI(i, r) OP(0x81, 0x03, 0x00, r);/* i+r -> r */ \ WORD $i; #define AND(r0, r1) OPrr(0x21, r0, r1) /* r0&r1 -> r1 */ #define ANDI(i, r) OP(0x81, 0x03, 0x04, r);/* i&r -> r */ \ WORD $i; #define CLR(r) OPrr(0x31, r, r) /* r^r -> r */ #define CLRB(r) OPrr(0x30, r, r) /* r^r -> r */ #define CMP(r0, r1) OPrr(0x39, r0, r1) /* r1-r0 -> flags */ #define CMPI(i, r) OP(0x81, 0x03, 0x07, r);/* r-i -> flags */ \ WORD $i; #define CMPBR(r0, r1) OPrr(0x38, r0, r1) /* r1-r0 -> flags */ #define DEC(r) BYTE $(0x48|r) /* r-1 -> r */ #define DIV(r) OPrr(0xF7, 0x06, r) /* rDX:rAX/r -> rAX, rDX:rAX%r -> rDX */ #define INC(r) BYTE $(0x40|r) /* r+1 -> r */ #define MUL(r) OPrr(0xF7, 0x04, r) /* r*rAX -> rDX:rAX */ #define IMUL(r0, r1) BYTE $0x0F; /* r0*r1 -> r1 */ \ OPrr(0xAF, r1, r0) /* (signed) */ #define OR(r0, r1) OPrr(0x09, r0, r1) /* r0|r1 -> r1 */ #define ORB(r0, r1) OPrr(0x08, r0, r1) /* r0|r1 -> r1 */ #define ORI(i, r) OP(0x81, 0x03, 0x01, r);/* i|r -> r */ \ WORD $i; #define ROLI(i, r) OPrr(0xC1, 0x00, r); /* r<<>>i -> r */ \ BYTE $i; #define SHLI(i, r) OPrr(0xC1, 0x04, r); /* r< r */ \ BYTE $i; #define SHLBI(i, r) OPrr(0xC0, 0x04, r); /* r< r */ \ BYTE $i; #define SHRI(i, r) OPrr(0xC1, 0x05, r); /* r>>i -> r */ \ BYTE $i; #define SHRBI(i, r) OPrr(0xC0, 0x05, r); /* r>>i -> r */ \ BYTE $i; #define SUB(r0, r1) OPrr(0x29, r0, r1) /* r1-r0 -> r1 */ #define SUBI(i, r) OP(0x81, 0x03, 0x05, r);/* r-i -> r */ \ WORD $i; #define STOSW STOSL #define CALL16(f) LWI(f, rDI); /* &f -> rDI */ \ BYTE $0xFF; /* (*rDI) */ \ BYTE $0xD7; #define FARJUMP16(s, o) BYTE $0xEA; /* jump to ptr16:16 */ \ WORD $o; WORD $s #define FARJUMP32(s, o) BYTE $0x66; /* jump to ptr32:16 */ \ BYTE $0xEA; LONG $o; WORD $s #define DELAY BYTE $0xEB; /* jmp .+2 */ \ BYTE $0x00 #define BIOSCALL(b) INT $b /* INT $b */ #define PEEKW BYTE $0x26; /* MOVW rES:[rBX], rAX */ \ BYTE $0x8B; BYTE $0x07 #define POKEW BYTE $0x26; /* MOVW rAX, rES:[rBX] */ \ BYTE $0x89; BYTE $0x07 #define OUTPORTB(p, d) LBI(d, rAL); /* d -> I/O port p */ \ BYTE $0xE6; \ BYTE $p; DELAY #define PUSHA BYTE $0x60 #define PUSHR(r) BYTE $(0x50|r) /* r -> (--rSP) */ #define PUSHS(rS) BYTE $(0x06|((rS)<<3)) /* rS -> (--rSP) */ #define PUSHI(i) BYTE $0x68; WORD $i; /* i -> --(rSP) */ #define POPA BYTE $0x61 #define POPR(r) BYTE $(0x58|r) /* (rSP++) -> r */ #define POPS(rS) BYTE $$(0x07|((rS)<<3)) /* (rSP++) -> r */ #define NOP BYTE $0x90 /* nop */ #define LGDT(gdtptr) BYTE $0x0F; /* LGDT */ \ BYTE $0x01; BYTE $0x16; \ WORD $gdtptr /* operand size switch. */ #define OPSIZE BYTE $0x66 pbsfun/mypbs/guide000644 000765 000000 00000002254 10676462217 015156 0ustar00paureawheel000000 000000 kill umsfs|rc usb/umsfs disk/format -b /386/pbslba -t hard -df -r 2 /n/ums/0/data /386/9load /386/9pcf /tmp/plan9.ini #mine is justpbs compiled to pbstrip disk/format -b /386/pbslba -t hard -df -r 2 /n/ums/0/data /usr/paurea/src/pc9load/9load /386/9pcf /tmp/plan9.ini disk/format -b /386/pbslba -df /n/ums/0/data /usr/paurea/src/pc9load/9load /386/9pcf.gz /tmp/plan9.ini ----------------------- term% kill umsfs|rc term% usb/umsfs maxlun 0 term% disk/mbr -m /386/mbr /n/ums/0/data term% disk/fdisk -p /n/ums/0/data part linux 251720 term% kill umsfs|rc term% kill umsfs|rc term% usb/umsfs maxlun 0 term% disk/fdisk -p part dos 62 251720 term% bind -b '#k' /dev echo clear>/dev/fs/ctl term% echo part 9fat /n/ums/0/data 62 251720 > /dev/fs/ctl term% cd /dev/fs term% ls 9fat ctl term% disk/format -b /386/pbslba -t hard -df -r 2 /dev/fs/9fat /usr/paurea/src/pc9load/9load /386/9pcf /tmp/plan9.ini format: too many files in root disk/format -b /386/pbslba -t hard -r 2 /dev/fs/9fat term% dossrv -f /n/ums/0/data:62 usbstorage dossrv: serving #s/usbstorage term% mount -c /srv/usbstorage /n/de term% cd /n/de term% cp /usr/paurea/src/pc9load/9load . term% cp /386/9pcf /tmp/plan9.ini . pbsfun/mypbs/justpbs.s000644 000765 000000 00000011071 10676462217 016011 0ustar00paureawheel000000 000000 orig = 0x7c00 magic: jmps begin nop //.space 0x3b total (30 two to the left) version: .space 8 sectsize: .space 2 clustsize: .space 1 nresrv: .space 2 nfats: .space 1 rootsize: .space 2 volsize: .space 2 mediadesc: .space 1 fatsize: .space 2 trksize: .space 2 nheads: .space 2 nhiddenlo: .space 2 nhiddenhi: .space 2 bigvolsize: .space 4 driveno: .space 1 reserved: .space 1 bootsig: .space 1 volid: .space 4 label: .space 11 type: .space 8 //FAT directory entry. //mov is botched. Dname = 0x00 Dnamesz = 0x0B Dext = 0x08 Dattr = 0x0B Dtime = 0x16 Ddate = 0x18 Dstart = 0x1A Dlengthlo = 0x1C Dlengthhi = 0x1E Dirsz=0x20 Diradjsz = 0x10 // 512/Dirsz //Data is kept on the stack, indexed by bp. Xdap = 0x00 // disc address packet Xrootsz = 0x10 // file data area Xdrive = 0x12 // boot drive, passed by BIOS or MBR Xtotal = 0x14 // sum of allocated data above LOADOFF = 0 LOADSEG = 0x1000 //where you used to load the code (64KB) DIROFF = 0x0200 away = 0x0000 begin: cli sub ax, ax mov ax, ss mov ax, ds mov ax, es mov $orig-Xtotal, sp //jump over the bios/mbr data mov sp, bp mov dl, Xdrive(bp) //save the drive //cd starts at 7C0, go to 0:7C00 push ax mov $nxt+orig, ax push ax lret nxt: sti mov $orig + hi, si //say hello call puts //--S call bigreal //change to bigreal mode... movb $0x41, ah //check extensions present mov $0x55aa, bx mov Xdrive(bp), dl int $0x13 //CF set on failure jcs jmp01 cmp $0xaa55, bx //check for buggy bios jne jmp01 and 0x0001, cx je ioerror /* rCX contains 0x0001 */ mov $0x0010, Xdap(bp) //reserved + packet size mov cx, Xdap+2(bp) //reserved + #blocks to transfer (1) dec cx mov cx, Xdap+12(bp) mov cx, Xdap+14(bp) call dreset jmp00: mov orig+volid, ax //Xrootlo mov orig+volid+2, dx //Xroothi mov $orig+DIROFF, bx call sectread // read the root directory mov $Diradjsz, bx //nentries mov $orig+DIROFF, di //name of the file cmp00: push di //save directory for later if it matches pusha mov di, si //print dirname (next is a pointer will start with zero :-)) call puts mov $'c', al call putc popa mov $orig+bootfile, si //'9load ' mov $Dnamesz, cx rep cmpsb pop di je jmp02 dec bx //nentries-- je jmp01 add $Dirsz, di jmp cmp00 jmp01: call ioerror jmp02: sub bx, bx // a handy value mov orig+rootsize, ax // calculate and save Xrootsz mov $Dirsz, cx mul cx mov orig+sectsize, cx push cx dec cx add cx, ax adc bx, dx pop cx // sectsize div cx push ax //Xrootsz //di points to the entry... mov Dstart(di), ax dec ax dec ax movb orig+clustsize, cl subb ch, ch mul cx mov orig+volid, cx add cx, ax mov orig+volid+2, cx adc cx, dx pop cx add cx, ax adc bx, dx push ax //calculate the number of sectors to read push dx mov Dlengthlo(di), ax mov Dlengthhi(di), dx mov orig+sectsize, cx push cx dec cx add cx, ax adc bx, dx pop cx div cx mov ax, cx pop dx pop ax mov $LOADSEG, bx mov bx, es mov $LOADOFF, bx readboot: call sectread mov orig+sectsize, di //bump addresses/counts add di, bx jncs incsecno mov es, di //inc sec count add $0x1000, di mov di, es incsecno: sub di, di inc ax adc di, dx loop readboot mov $LOADSEG, di mov di, ds ljmp 0x1000:LOADOFF //LOADSEG:LOADOFF ass!embler //----functions... dreset: pusha sub ax, ax //ah = 0, reset movb Xdrive(bp), dl int $0x13 orb ah, ah popa jne ioerror ret // // Read a sector from a disc. On entry: // rDX:rAX sector number // rES:rBX buffer address // sectread: mov 5, di //retry count retry: pusha //may be trashed by bios... uff mov bx, Xdap+4(bp) //buffer : offset mov es, di // buffer seg: mov di, Xdap+6(bp) mov ax, Xdap+8(bp) //LBA 64 bits mov dx, Xdap+10(bp) mov bp, si movb $0x42, ah movb Xdrive(bp), dl int $0x13 jncs biosrdret //CF set on failure popa dec di jes ioerror call dreset pusha may be trashed by bios... movb $'r', al call putc popa jmp retry ioerror: mov $orig+ioerr, si call puts wait: sub ax, ax int $0x16 reset: sub bx, bx mov bx, es mov 0x0472, bx //warm start code address mov 0x1234, ax //warm start code .byte 0x26, 0x89, 0x07 //mov ax, es:(bx) ljmp 0xffff:away //jump to reset biosrdret: movb $'*', al //print '*' call putc popa ret //--end debug puts: push cx //S mov $10, cx putsag: cld lodsb cmpb $0, al jes end dec cx jes end call putc jmp putsag end: pop cx //S ret putc: // write the char in al to video // write to video pusha movb $0xe, ah int $0x10 popa ret bootfile: <9LOAD \0> hi: ioerr: bye: finish: //to tell me if it ended... pbsfun/mypbs/mkfile000644 000765 000000 00000001154 10676462217 015326 0ustar00paureawheel000000 000000 objtype=386 /dev/null >[2=1] || exit 'program too big' cp /usr/paurea/src/pbsfun/mypbs/pbstrip /usr/paurea/src/pc9load/9pxeload pbsfun/mypbs/pbsabort.s000644 000765 000000 00000013064 10676462217 016137 0ustar00paureawheel000000 000000 orig = 0x7c00 magic: jmps begin nop //.space 0x3b total (30 two to the left) version: .space 8 sectsize: .space 2 clustsize: .space 1 nresrv: .space 2 nfats: .space 1 rootsize: .space 2 volsize: .space 2 mediadesc: .space 1 fatsize: .space 2 trksize: .space 2 nheads: .space 2 nhiddenlo: .space 2 nhiddenhi: .space 2 bigvolsize: .space 4 driveno: .space 1 reserved: .space 1 bootsig: .space 1 volid: .space 4 label: .space 11 type: .space 8 //FAT directory entry. //mov is botched. Dname = 0x00 Dnamesz = 0x0B Dext = 0x08 Dattr = 0x0B Dtime = 0x16 Ddate = 0x18 Dstart = 0x1A Dlengthlo = 0x1C Dlengthhi = 0x1E Dirsz=0x20 Diradjsz = 0x10 // 512/Dirsz //Data is kept on the stack, indexed by bp. Xdap = 0x00 // disc address packet Xrootsz = 0x10 // file data area Xdrive = 0x12 // boot drive, passed by BIOS or MBR Xtotal = 0x14 // sum of allocated data above LOADOFF = 0 LOADSEG = 0x1000 //where you used to load the code (64KB) DIROFF = 0x0200 away = 0x0000 begin: cli sub ax, ax mov ax, ss mov ax, ds mov ax, es mov ax, gs mov $orig-Xtotal, sp //jump over the bios/mbr data mov sp, bp mov dl, Xdrive(bp) //save the drive //cd starts at 7C0, go to 0:7C00 push ax mov $nxt+orig, ax push ax lret nxt: sti mov $orig + hi, si //say hello call puts //--S call bigreal //change to bigreal mode... movb $0x41, ah //check extensions present mov $0x55aa, bx mov Xdrive(bp), dl int $0x13 //CF set on failure jcs jmp01 cmp $0xaa55, bx //check for buggy bios jne jmp01 and 0x0001, cx je ioerror /* rCX contains 0x0001 */ mov $0x0010, Xdap(bp) //reserved + packet size mov cx, Xdap+2(bp) //reserved + #blocks to transfer (1) dec cx mov cx, Xdap+12(bp) mov cx, Xdap+14(bp) call dreset jmp00: mov orig+volid, ax //Xrootlo mov orig+volid+2, dx //Xroothi mov $orig+DIROFF, bx call sectread // read the root directory mov $Diradjsz, bx //nentries mov $orig+DIROFF, di //name of the file cmp00: push di //save directory for later if it matches //pusha //mov di, si //print dirname (next is a pointer will start with zero :-)) //call puts //mov $'c', al //call putc //popa mov $orig+bootfile, si //'9load ' mov $Dnamesz, cx rep cmpsb pop di je jmp02 dec bx //nentries-- je jmp01 add $Dirsz, di jmp cmp00 jmp01: call ioerror jmp02: sub bx, bx // a handy value mov orig+rootsize, ax // calculate and save Xrootsz mov $Dirsz, cx mul cx mov orig+sectsize, cx push cx dec cx add cx, ax adc bx, dx pop cx // sectsize div cx push ax //Xrootsz //di points to the entry... mov Dstart(di), ax dec ax dec ax movb orig+clustsize, cl subb ch, ch mul cx mov orig+volid, cx add cx, ax mov orig+volid+2, cx adc cx, dx pop cx add cx, ax adc bx, dx push ax //calculate the number of sectors to read push dx mov Dlengthlo(di), ax mov Dlengthhi(di), dx mov orig+sectsize, cx push cx dec cx add cx, ax adc bx, dx pop cx div cx mov ax, cx pop dx pop ax pusha jmp bigreal popa mov $LOADSEG, bx mov bx, gs mov $LOADOFF, bx readboot: call sectread mov orig+sectsize, di //bump addresses/counts add di, bx jncs incsecno mov gs, di //inc sec count add $0x1000, di mov di, gs incsecno: sub di, di inc ax adc di, dx loop readboot mov $LOADSEG, di mov di, ds ljmp 0x1000:LOADOFF //LOADSEG:LOADOFF ass!embler //----functions... bigreal: //call dumpsegs cli lgdt gdtaddr+orig //switch to protected .byte 0x0f, 0x20, 0xc0 //mov cr0, eax orb $1, al .byte 0x0f, 0x22, 0xc0 //mov eax, cr0 mov $next+orig, ax jmp ax next: movb $0x08, bl movb $0x00, bh mov bx, es andb $0xfe, al //back to real mode .byte 0x0f, 0x22, 0xc0 //mov eax, cr0 sti inb $0x92 //turn on A20 line, may not work on old orb $2, al outb $0x92 //call dumpsegs ret dreset: pusha sub ax, ax //ah = 0, reset movb Xdrive(bp), dl int $0x13 orb ah, ah popa jne ioerror ret moveblk: cld mov sp, bp sub ax, ax mov ax, ds opsz mov Xdap+4(bp), si //buffer offset taken from sectread opsz //mov [bp+06], edi mov 0x6(bp), di opsz //mov [bp+0a], ecx mov $0x1, cx rep .byte 0x67, 0x66, 0x26, 0xa5 //movsd ds:esi to es:edi ret // // Read a sector from a disc. On entry: // rDX:rAX sector number // rES:rBX buffer address // sectread: mov 5, di //retry count retry: pusha //may be trashed by bios... uff mov bx, Xdap+4(bp) //buffer : offset mov gs, di // buffer seg: mov di, Xdap+6(bp) mov ax, Xdap+8(bp) //LBA 64 bits mov dx, Xdap+10(bp) mov bp, si movb $0x42, ah movb Xdrive(bp), dl int $0x13 jncs biosrdret //CF set on failure popa dec di jes ioerror call dreset //pusha may be trashed by bios... //movb $'r', al //call putc //popa jmp retry ioerror: mov $orig+ioerr, si call puts wait: sub ax, ax int $0x16 reset: sub bx, bx mov bx, es mov 0x0472, bx //warm start code address mov 0x1234, ax //warm start code .byte 0x26, 0x89, 0x07 //mov ax, es:(bx) ljmp 0xffff:away //jump to reset biosrdret: //movb $'*', al //call putc //popa ret //--end debug puts: push cx //S mov $10, cx putsag: cld lodsb cmpb $0, al jes end dec cx jes end call putc jmp putsag end: pop cx //S ret putc: // write the char in al to video // write to video pusha movb $0xe, ah int $0x10 popa ret gdt_limit = gdt_end - gdt - 1 gdtentrysz = gdt_end - gdt gdtaddr: .word gdt_limit .word orig+gdt-gdt_entrysz, 0x0000 /* we know the offset */ gdt: //selgdt 0x8 /* unreal data segment at 000*/ .word 0xffff, 0x0000 .byte 0x00, 0x93, 0xcf, 0x00 gdt_end: bootfile: <9LOAD \0> hi: ioerr: bye: finish: //to tell me if it ended...pbsfun/mypbs/pbsx000644 000765 000000 00000000000 10676462217 015020 0ustar00paureawheel000000 000000 pbsfun/mypbs/pbsx.s000644 000765 000000 00000011071 10676462217 015273 0ustar00paureawheel000000 000000 orig = 0x7c00 magic: jmps begin nop //.space 0x3b total (30 two to the left) version: .space 8 sectsize: .space 2 clustsize: .space 1 nresrv: .space 2 nfats: .space 1 rootsize: .space 2 volsize: .space 2 mediadesc: .space 1 fatsize: .space 2 trksize: .space 2 nheads: .space 2 nhiddenlo: .space 2 nhiddenhi: .space 2 bigvolsize: .space 4 driveno: .space 1 reserved: .space 1 bootsig: .space 1 volid: .space 4 label: .space 11 type: .space 8 //FAT directory entry. //mov is botched. Dname = 0x00 Dnamesz = 0x0B Dext = 0x08 Dattr = 0x0B Dtime = 0x16 Ddate = 0x18 Dstart = 0x1A Dlengthlo = 0x1C Dlengthhi = 0x1E Dirsz=0x20 Diradjsz = 0x10 // 512/Dirsz //Data is kept on the stack, indexed by bp. Xdap = 0x00 // disc address packet Xrootsz = 0x10 // file data area Xdrive = 0x12 // boot drive, passed by BIOS or MBR Xtotal = 0x14 // sum of allocated data above LOADOFF = 0 LOADSEG = 0x1000 //where you used to load the code (64KB) DIROFF = 0x0200 away = 0x0000 begin: cli sub ax, ax mov ax, ss mov ax, ds mov ax, es mov $orig-Xtotal, sp //jump over the bios/mbr data mov sp, bp mov dl, Xdrive(bp) //save the drive //cd starts at 7C0, go to 0:7C00 push ax mov $nxt+orig, ax push ax lret nxt: sti mov $orig + hi, si //say hello call puts //--S call bigreal //change to bigreal mode... movb $0x41, ah //check extensions present mov $0x55aa, bx mov Xdrive(bp), dl int $0x13 //CF set on failure jcs jmp01 cmp $0xaa55, bx //check for buggy bios jne jmp01 and 0x0001, cx je ioerror /* rCX contains 0x0001 */ mov $0x0010, Xdap(bp) //reserved + packet size mov cx, Xdap+2(bp) //reserved + #blocks to transfer (1) dec cx mov cx, Xdap+12(bp) mov cx, Xdap+14(bp) call dreset jmp00: mov orig+volid, ax //Xrootlo mov orig+volid+2, dx //Xroothi mov $orig+DIROFF, bx call sectread // read the root directory mov $Diradjsz, bx //nentries mov $orig+DIROFF, di //name of the file cmp00: push di //save directory for later if it matches pusha mov di, si //print dirname (next is a pointer will start with zero :-)) call puts mov $'c', al call putc popa mov $orig+bootfile, si //'9load ' mov $Dnamesz, cx rep cmpsb pop di je jmp02 dec bx //nentries-- je jmp01 add $Dirsz, di jmp cmp00 jmp01: call ioerror jmp02: sub bx, bx // a handy value mov orig+rootsize, ax // calculate and save Xrootsz mov $Dirsz, cx mul cx mov orig+sectsize, cx push cx dec cx add cx, ax adc bx, dx pop cx // sectsize div cx push ax //Xrootsz //di points to the entry... mov Dstart(di), ax dec ax dec ax movb orig+clustsize, cl subb ch, ch mul cx mov orig+volid, cx add cx, ax mov orig+volid+2, cx adc cx, dx pop cx add cx, ax adc bx, dx push ax //calculate the number of sectors to read push dx mov Dlengthlo(di), ax mov Dlengthhi(di), dx mov orig+sectsize, cx push cx dec cx add cx, ax adc bx, dx pop cx div cx mov ax, cx pop dx pop ax mov $LOADSEG, bx mov bx, es mov $LOADOFF, bx readboot: call sectread mov orig+sectsize, di //bump addresses/counts add di, bx jncs incsecno mov es, di //inc sec count add $0x1000, di mov di, es incsecno: sub di, di inc ax adc di, dx loop readboot mov $LOADSEG, di mov di, ds ljmp 0x1000:LOADOFF //LOADSEG:LOADOFF ass!embler //----functions... dreset: pusha sub ax, ax //ah = 0, reset movb Xdrive(bp), dl int $0x13 orb ah, ah popa jne ioerror ret // // Read a sector from a disc. On entry: // rDX:rAX sector number // rES:rBX buffer address // sectread: mov 5, di //retry count retry: pusha //may be trashed by bios... uff mov bx, Xdap+4(bp) //buffer : offset mov es, di // buffer seg: mov di, Xdap+6(bp) mov ax, Xdap+8(bp) //LBA 64 bits mov dx, Xdap+10(bp) mov bp, si movb $0x42, ah movb Xdrive(bp), dl int $0x13 jncs biosrdret //CF set on failure popa dec di jes ioerror call dreset pusha may be trashed by bios... movb $'r', al call putc popa jmp retry ioerror: mov $orig+ioerr, si call puts wait: sub ax, ax int $0x16 reset: sub bx, bx mov bx, es mov 0x0472, bx //warm start code address mov 0x1234, ax //warm start code .byte 0x26, 0x89, 0x07 //mov ax, es:(bx) ljmp 0xffff:away //jump to reset biosrdret: movb $'*', al //print '*' call putc popa ret //--end debug puts: push cx //S mov $10, cx putsag: cld lodsb cmpb $0, al jes end dec cx jes end call putc jmp putsag end: pop cx //S ret putc: // write the char in al to video // write to video pusha movb $0xe, ah int $0x10 popa ret bootfile: <9LOAD \0> hi: ioerr: bye: finish: //to tell me if it ended... pbsfun/mypbs/pbsxdebug.s000644 000765 000000 00000013502 10676462217 016303 0ustar00paureawheel000000 000000 orig = 0x7c00 //FAT directory entry. //mov is botched. Dname = 0x00 Dext = 0x08 Dattr = 0x0B Dtime = 0x16 Ddate = 0x18 Dstart = 0x1A Dlengthlo = 0x1C Dlengthhi = 0x1E Dirsz=0x20 //Data is kept on the stack, indexed by rBP. Xdap=0x00 // disc address packet Xrootsz=0x10 // file data area Xdrive=0x12 // boot drive, passed by BIOS or MBR Xtotal=0x14 // sum of allocated data above start: jmps begin nop //.space 0x3b total (30 two to the left) version: .space 8 sectsize: .space 2 clustsize: .space 1 nresrv: .space 2 nfats: .space 1 rootsize: .space 2 volsize: .space 2 mediadesc: .space 1 fatsize: .space 2 trksize: .space 2 nheads: .space 2 nhiddenlo: .space 2 nhiddenhi: .space 2 bigvolsize: .space 4 driveno: .space 1 reserved: .space 1 bootsig: .space 1 volid: .space 4 label: .space 11 type: .space 8 begin: cli sub ax, ax mov ax, ss mov ax, bx mov ax, ds mov ax, es mov ax, fs mov $orig, sp sti cld mov $orig + hi, si //say hello call puts //move something to 0x10 call bigreal //call dumpstk //call dumpoff //call dumpsegs //mov $0x11a1, ax //push ax //mov $0x22b2, ax //push ax //mov $0x33c3, ax //push ax //mov $0x44d4, ax //push ax //mov $0x55e5, ax //push ax //mov $0x66e6, ax //push ax //call dumpstk //call peekstk call printsee mov $orig + cop, si call puts //sub di, di //mov $0xf000, ax //mov ax, es //movs; halt: mov $orig + bye, si call puts cli halt jmp halt //----debug enter: <\r\n\0> offmsg: off: mov $orig+offmsg, si call puts lea orig, bx call puthex4 mov $orig+enter, si call puts ret psrc: pdest: <--1234567890-12345678901234567890--\r\n\0> printsee: push $0x0 push $0x0002 push $0x00ff push $orig+pdest push $0x0 push $orig+psrc //call peekstk call moveblk add $0xc, sp //put the stack in place push $0x0 push $0x0002 push $0x0 push $orig+pdest push $0x00ff push $orig+pdest //call peekstk call moveblk add $0xc, sp //put the stack in place. mov $orig+pdest, si call puts ret nams: < sp cs ds ss es fs bp\r\n\0> dumpsegs: push ax push bx mov $orig+nams, si call puts movb $0x20, al call putc mov sp, bx call puthex4 movb $0x20, al call putc mov cs, bx call puthex4 movb $0x20, al call putc mov ds, bx call puthex4 movb $0x20, al call putc mov ss, bx call puthex4 movb $0x20, al call putc mov es, bx call puthex4 movb $0x20, al call putc mov fs, bx call puthex4 movb $0x20, al call putc mov bp, bx call puthex4 mov $orig+enter, si call puts pop bx pop ax ret peekstk: .byte 0x66, 0x8b, 0x76, 0x02 //mov [bp+2], esi .byte 0x66 shr $16, si mov si, bx call puthex4 mov sp, bp .byte 0x66, 0x8b, 0x76, 0x02 //mov [bp+2], esi mov si, bx call puthex4 mov $orig+enter, si call puts .byte 0x66, 0x8b, 0x7e, 0x06 //mov [bp+06], edi .byte 0x66 shr $16, di mov di, bx call puthex4 .byte 0x66, 0x8b, 0x7e, 0x06 //mov [bp+06], edi mov di, bx call puthex4 mov $orig+enter, si call puts .byte 0x66, 0x8b, 0x4e, 0x0a //mov [bp+0a], ecx .byte 0x66 shr $16, cx mov cx, bx call puthex4 .byte 0x66, 0x8b, 0x4e, 0x0a //mov [bp+0a], ecx mov cx, bx call puthex4 mov $orig+enter, si call puts ret dumpstk: pop ax pop bx pop cx pop dx push dx push cx push bx push ax push bx mov ax, bx call puthex4 mov $orig+enter, si call puts pop bx call puthex4 mov $orig+enter, si call puts mov cx, bx call puthex4 mov $orig+enter, si call puts mov dx, bx call puthex4 mov $orig+enter, si call puts ret puthex4: push al movb bh, al call puthex2 movb bl, al call puthex2 pop al ret / write al as two hex digits puthex2: pusha push ax mov $2, dx movb $0, ah movb $4, cl shr cl, ax 3: cmpb $10, al jls 1f subb $10, al / c - 10 + 'A' addb $0x41, al jmps 2f 1: orb $0x30, al 2: call putc dec dx jzs 1f pop ax push ax and $0xF, ax jmps 3b 1: pop ax popa ret //----functions... //THE function. it copies a N block from // ds:esi to es: edi with ecx as counter (in words of 4 bytes) // in our scheme ds is near (is an offset of $0) // es is the high (is a gdt selector from our entry // in bigreal fun) // before calling, you should: // push ecx high, // push ecx low // push edi high // push edi low // push esi high // push esi low // add $0xc, sp put the stack in place. moveblk: //push bp cld mov sp, bp sub ax, ax mov ax, ds .byte 0x66, 0x8b, 0x76, 0x02 //mov [bp+2], esi -> jump over pc. .byte 0x66, 0x8b, 0x7e, 0x06 //mov [bp+06], edi .byte 0x66, 0x8b, 0x4e, 0x0a //mov [bp+0a], ecx cld rep .byte 0x67, 0x66, 0x26, 0xa5 //movsd ds:esi to es:edi //pop bp ret bigreal: //call dumpsegs cli push bp lgdt gdtaddr+orig //switch to protected .byte 0x0f, 0x20, 0xc0 //mov cr0, eax orb $1, al .byte 0x0f, 0x22, 0xc0 //mov eax, cr0 mov $next+orig, ax jmp ax next: movb $0x10, bl movb $0x00, bh mov bx, es andb $0xfe, al //back to real mode .byte 0x0f, 0x22, 0xc0 //mov eax, cr0 sti inb $0x92 //turn on a20 line, may not work on old orb $2, al outb $0x92 sub ax, ax pop bp //call dumpsegs ret puts: lodsb cmpb $0, al jes end call putc jmp puts end: ret putc: // write the char in al to video / write to video movb $0xe, ah int $0x10 ret flop: mov $0x3f2, dx mov $0x10, ax outb cli halt hi: cop: bok: bye: gdt_limit = gdt_end - gdt - 1 gdtaddr: .word gdt_limit .word orig+gdt, 0x0000 /* we know the offset */ gdt: // selgdt 0 .word 0x0000, 0x0000 /* dummy */ .byte 0x00, 0x00, 0x00, 0x00 //selgdt 0x8 //selgdt 0x8 /* 16-bit 64k code segment at 000 */ .word 0xffff, 0x00f0 .byte 0x00, 0x9b, 0xcf, 0x00 //selgdt 0x10 /* unreal data segment at 000*/ .word 0xffff, 0x0000 .byte 0x00, 0x93, 0xcf, 0x00 gdt_end: finish: //to tell me if it ended... pbsfun/mypbs/scratch000644 000765 000000 00000005033 10676462217 015506 0ustar00paureawheel000000 000000 //debug puthex4: push al movb bh, al call puthex2 movb bl, al call puthex2 pop al ret / write al as two hex digits puthex2: pusha push ax mov $2, dx movb $0, ah movb $4, cl shr cl, ax 3: cmpb $10, al jls 1f subb $10, al / c - 10 + 'A' addb $0x41, al jmps 2f 1: orb $0x30, al 2: call putc dec dx jzs 1f pop ax push ax and $0xF, ax jmps 3b 1: pop ax popa ret //wrapper for the _moveblk function //receives an addr in ax moves to //the addr with (0xf000 | count):ax 512 bytes (512/4 = 0x80) //in dx is the count of blocks (for the high addr) //--S //--Smoveblk: //--S push bp //--S push $0x0 //--S push $0x0080 //--S or 0xf000, dx //--S push dx //dst //--S push ax //--S push $0x0 //src //--S push ax //--S //--S call _moveblk //--S add $0xc, sp //put the stack in place //--S pop bp //--Sret //THE function. it copies a N block from // ds:esi to es: edi with ecx as counter (in words of 4 bytes) // in our scheme ds is near (is an offset of $0) // es is the high (is a gdt selector from our entry // in bigreal fun) // before calling, you should: // push ecx high, // push ecx low // push edi high // push edi low // push esi high // push esi low // add $0xc, sp put the stack in place. //--S_moveblk: //--S cld //--S mov sp, bp //--S sub ax, ax //--S mov ax, ds //--S opsz //mov [bp+2], esi -> jump over pc. //--S mov 0x2(bp), si //--S opsz //mov [bp+06], edi //--S mov 0x6(bp), di //--S opsz //mov [bp+0a], ecx //--S mov 0xa(bp), cx //--S rep //--S .byte 0x67, 0x66, 0x26, 0xa5 //movsd ds:esi to es:edi //--Sret //--S //--Sbigreal: //--S //call dumpsegs //--S cli //--S lgdt gdtaddr+orig //--S //--S //switch to protected //--S .byte 0x0f, 0x20, 0xc0 //mov cr0, eax //--S orb $1, al //--S .byte 0x0f, 0x22, 0xc0 //mov eax, cr0 //--S //--S mov $next+orig, ax //--S jmp ax //--Snext: //--S movb $0x08, bl //--S movb $0x00, bh //--S mov bx, es //--S //--S andb $0xfe, al //back to real mode //--S .byte 0x0f, 0x22, 0xc0 //mov eax, cr0 //--S sti //--S //--S inb $0x92 //turn on A20 line, may not work on old //--S orb $2, al //--S outb $0x92 //--S //--S //call dumpsegs //--Sret //try negative values :-). //--Sgdt_limit = gdt_end - gdt - 1 //--S //--Sgdtaddr: //--S .word gdt_limit //--S .word orig+gdt, 0x0000 /* we know the offset */ //--S //--S//--Sgdt: //--S // selgdt 0 //--S .word 0x0000, 0x0000 /* dummy */ //--S .byte 0x00, 0x00, 0x00, 0x00 //--S //selgdt 0x8 //--S //--S //--S//selgdt 0x8 //--S/* unreal data segment at 000*/ //--S .word 0xffff, 0x0000 //--S .byte 0x00, 0x93, 0xcf, 0x00 //--Sgdt_end: