Oberon/A2/BootManager.Asm

; Bluebottle Boot Manager &#59; &#59;&#32;Written by A.L. Fischer using Network Assembler syntax for use with &#59;&#32;the Bluebottle assembler PCAAMD64.Mod &#59;&#9;PCAAMD64.Assemble BootManager.Asm &#126; &#59;&#32;This Boot Manager uses the int 13h extensions for &#59;&#32;accessing blocks in LBA mode in order to break the 8.4GB barrier, &#59;&#32;if that access method is supported by the BIOS and the hard drive, &#59;&#32;and uses the C-H-S disk access mode otherwise. &#59;&#32;In Oberon, what is otherwise named "sector" is called "block", &#59;&#32;in relation with LBA &#61; Logical Block Address &#59;&#32;The 1st block of a volume is named MBR and that of a partition PBR. &#59;&#32;Reference&#58; BIOS Enhanced Disk Drive Specification &#59;&#32;&#32;&#32;&#32;&#32;&#32;Version 3.0 - Rev 0.9b - June 24, 1999. Phoenix Technologies Ltd. &#59;&#32;&#32;&#32;&#32;&#32;&#32;http&#58;//www.t13.org/project/d1386r0.pdf &#59;&#32;http&#58;//web.inter.nl.net/hcc/J.Steunebrink/bioslim.htm &#59;&#32;2007-04-13 afi Started &#59;&#9;Adaptation from original BootManager.Asm &#59;&#32;2007-06-24 afi completed first version &#59;&#32;2007-11-12 afi converted text from Turbo to Network Assembler &#59;&#32;The date of the current version is located at bmdate and displayed &#59;&#32;in the title line of the boot menu at startup. &#59;&#32; &#59;&#32;Infrastructure and implementation procedure&#58; &#59; &#59;&#32;1 - edit this text &#59;&#32;2 - assemble by executing&#58; PCAAMD64.Assemble BootManager.Asm &#126; &#59;&#9;to obtain BootManager.Bin &#59;&#32;3 - Split BootManager.Bin into BootManagerMBR.Bin and BootManagerTail.Bin &#59;&#32; &#59;&#32;(0) central combined CHS / LBA support. &#59;&#32;&#32;&#32;&#32;&#32;&#32;&#32;All of it must be located in block with LBA&#61;0 (MBR) &#59;&#32;(1) added for warning when a partition has no valid PBR &#59;&#32;(2) added for using 1 or 2 digits depending on the # of partitions &#59;&#9;Up to 12 partitions per volume can be handled &#59;&#32;(3) added for inspecting the graphic controller capabilities &#59;&#9;incorporated to (15) - previously done with enter &#39;v&#39; &#59;&#9;procedure inspectvbe &#59;&#9;VESA BIOS Extensions 2.0 (VBE) &#59;&#9;http&#58;www.geocities.com/SiliconValley/Park/8933.vesa.html &#59;&#32;(4) added for collecting disk drive information - proc driveinfo &#59;&#32;(5) added for displaying VBE information or not - now part of (15) &#59;&#32;(6) added for providing a better disk error diagnostic &#59;&#9;as soon as the complete BootManager is loaded &#59;&#32;(7) added for scanning PCI bus &#59;&#32;(8) added for presenting a survey of installed drives &#59;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Nowadays justified by the appearance of external mobile drives &#59;&#32;&#32;&#32;&#32;&#32;&#32;&#32;with USB or Firewire interface resulting in an ever changing &#59;&#32;&#32;&#32;&#32;&#32;&#32;&#32;drive configuration &#59;&#32;(9) was diskette support, now removed &#59;&#32;(10) added for indicating which volume is currently explored (underline) &#59;&#32;(11) void &#59;&#32;(12) was diskette support, now removed &#59;&#32;(13) show drive interface&#58; IDE, FDD, CD-ROM, USB when available &#59;&#32;(14) skip non-accessible (USB) drives &#59;&#32;(15) display PC hardware information - enter &#39;h&#39; - inspectvbe/inspectpci &#59;&#32;(16) GUI text restructured - not marked in code &#59;&#32;(17) diskette support entirely removed. Presence of FDD now ignored. &#59;&#9;In 2007, PCs are very seldomly equipped with a diskette drive. &#59;&#9;All PCs, without exception support external USB devices having &#59;&#9;many thousand times superior storage capacity. &#59;&#9;If no FDD is installed, it should be disabled in the BIOS setup. &#59;&#32;(18) toggle between 25 (default) and 50 lines on screen - enter &#39;l&#39; &#59;&#32;(20) announce OS start &#59;&#32;(21) display CPU information with cpuid &#59;&#32;(22) switch/swap the current MBR and that of another volume - enter &#39;s&#39; &#59;&#32;(23) add some persistance to the message line &#59;&#32;(24) display partition sizes &#59;&#32;(25) toggle store/do NOT store selected volume and partition - enter &#39;b&#39; &#59;&#32;&#32;Refer to Dual/Multi Booting With Vista - www.multibooters.co.uk/mbr.html &#59;&#32; CPU P4 &#9;bits 16 &#59;&#32;define filler character filler&#58; equ &#39;U&#39;	; Unused byte &#59;&#32;BIOS reads the first physical block (MBR) of the boot device and places &#59;&#32;it into memory at location biosloc&#58; equ 7c00h &#59;&#32;The initial part of the contained program (up to entry01) has the &#59;&#32;duty of freeing the area at biosloc by relocating it to memory &#59;&#32;at location 0000&#58;0600 (newloc below). &#59;&#32;The rest of the program will read and place the PBR &#59;&#32;at the same location biosloc as if it had been read by the BIOS. newloc&#58; equ 0600h	; address of the area in which &#59;&#9;the MBR will be relocated MBRreloc&#58; equ 0200h	; (22) address of the area in &#59;&#9;which the MBR is temporarily saved for a possible swapping CR&#58;	equ 13	; Carriage Return 0ch LF&#58;	equ 10	; Line Feed 0ah blocksize&#58;	equ 512	; bytes per block signID&#58;	equ 0aa55h	; signature bmLBA&#58;	equ 1	; LBA of stage 2 &#59;&#32;Changing bmLBA might be required to locate the bulk of the &#59;&#32;IPL bootmanager elsewhere than immediatly after the MBR &#59;&#32;as is suggested here with the value 1. &#59;&#32;The boot manager is split into two parts&#58; &#59;&#9;- the MBR of the volume&#58; stage1 contained in block LBA&#61;0 &#59;&#9;- the rest, comprising bmsize blocks, in a free area of the volume bmsize&#58;	equ 12	; stage2 size in blocks &#59;&#32;the block with LBA&#61; 12 is used to memorize the last user selection &#59;&#32;defaultd and defaultp lbalen&#58;	equ 21	; length of an lbalist entry partlen&#58;	equ 16	; length of a partition entry &#59;&#32;offset (in blocks) of the first partition with respect to the volume beginning &#59;partoffset&#58;	equ 2048	; on a HD formatted with Vista &#59;partoffset&#58;	equ 63	; on a HD or USB memory stick &#59;partoffset&#58;	equ 32	; on a CD-ROM maxretry&#58;	equ 5	; max. number of read/write retries &#59;&#32; &#59;&#32;LBA 0 - MBR - Master Boot Record  &#9;org 0 &#59;&#32;WARNING&#58; Do not alter dl until call inspectdisk is over entry&#58;	cli	; disable interrupts &#59;&#32;NOTE&#58; No justification yet for the presence of this "cli" but &#59;&#32;in LILO one can read "NT 4 blows up if this is missing". &#9;xor ax, ax	; clear &#9;mov ss, ax	; set stack segment to 0000 &#9;mov sp, biosloc	; set stack pointer &#9;sti	; enable interrupts &#9;push ax	; &#9;pop es	; es now 0000 &#9;push ax	; &#9;pop ds	; ds now 0000 &#9;cld	; clear direction flag &#9;mov si, biosloc + entry01	; set si &#9;mov di, newloc + entry01	; relocation address &#9;push ax	; 0000 &#9;push di	; newloc + offset entry01 &#9;mov cx, blocksize - (entry01-entry)	; set count &#9;rep movsb	; move MBR from 0000&#58;7c00 to 0000&#58;0600 &#9;retf	; jump to 0000&#58;newloc + entry01 entry01&#58;	call savembr &#9;mov &#91;newloc + currdrive&#93;, dl	; note from which drive it all started &#9;call inspectdisk &#59;&#32;read rest of boot manager - bmsize blocks in one operation &#9;mov bp, newloc + baseadd	; lba &#61; 1 for accessing the 2nd block &#9;call readblock	; read all blocks in one go &#9;mov si, biosloc	; set si &#9;mov di, newloc + blocksize	; relocation address &#9;mov cx, bmsize*blocksize	; set count for bmsize blocks &#9;rep movsb	; move from 0000&#58;7c00 to 0000&#58;0800 &#59;&#32;The area extending from entry to this point may be used to store data &#59;&#32;as soon as execution passed this point. &#59;&#32;Imperative condition&#58; it must be at least 3*16 bytes long to contain &#59;&#32;3 partition table entries of an extended partition - see at isext label &#59;&#32; &#59;&#32;At this point, the entire boot manager is loaded into memory (bmloaded). &#59;&#32;An eventual disk operation error can be diagnosed correctly and &#59;&#32;reported on the display console. &#9;mov &#91;newloc + bmloaded&#93;, 1	; (6) set indicator to TRUE &#59;&#32;Collect the information on the installed drives (drive numbers ordered &#59;&#32;by index) for deciding what to tell the user about the environment &#59;&#32;Takes place only once at the very beginning &#9;call cpuinfo &#9;call driveinfo	; (4) &#9;jmp word newmbr &#59;&#32;Jump to the main processing located at the end of this block.  &#59;&#32;All the procedures which appear below and up to the label newmbr &#59;&#32;must imperatively be located within the block with LBA&#61;0 because &#59;&#32;they are all needed for getting the remaining blocks LBA&#61;1 to bmsize &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; read a block with the specified LBA number (0) &#59;&#32;NOTE&#58; (0) starts at label readblock. What comes before is used later &#59;&#32;use the LBA directly or convert that value to CHS &#59;&#32;in &#58; bp &#61; point to lba in table entry &#59;&#32;out &#58; dl &#61; drive number ; bx &#61; data buffer address readplus&#58; &#59;&#32;has the function of tracing the partition types detected - optional &#9;call info	; info about the current entry, set bp &#59;&#32;Up to maxretry attempts, with at each failed attempt a disk reset. &#59;&#32;The registers are conditioned first to launch an extended read and &#59;&#32;if LBA mode is not supported, a standard read in prepared. &#59;&#32;A discriminator is also placed immediately before the int 13h instruction &#59;&#32;to trim the operation code in ah, al. readblock&#58;	mov di, maxretry	; number of tries readtry&#58; &#59;&#32;set up dap for an extended read/write 13h disk operation &#59;&#32;the Device Address Packet (dap) is constructed on the fly by pushing &#59;&#32;the parts on the stack. &#59;&#32;the structure of the dap is&#58; &#59;dap	db 10h	; dap size (fixed) &#59;&#9;db 0	; reserved (fixed) &#59;num	dw bmsize	; number of blocks to transfer (fixed) &#59;boff	dw biosloc	; address of transfer buffer - offset &#59;bseg	dw 0	; address of transfer buffer - segment &#59;sec0	dd ? ; starting absolute block address &#59;sec1	dd 0	; remaining 32 bits of address &#59;&#32;it is easiest to set up the dap first because the values to assign are &#59;&#32;available straight away. &#59;&#32;a volatile dap has the disadvantage that it must be rebuilt for a read retry &#9;mov ax, word &#91;bp&#93;	; dx&#58;ax &#61; lba number of block to read &#9;mov dx, word &#91;bp+2&#93; &#59;&#32;now leave dx&#58;ax untouched until the next test of the lba indicator ! &#59;&#32;NOTE&#58;	pushd 0 is an "Illegal instruction" for tasm in 16-bit mode &#9;push byte 0	; remaining 16 bits &#9;push byte 0	; remaining 16 bits &#59;&#32;NOTE&#58;	push dword &#91;bp&#93;	; starting absolute block address &#59;&#32;replaced by the next 2 lines because ax and dx are set already &#9;push dx &#9;push ax &#9;push es	; address of transfer buffer - segment &#9;push biosloc	; address of transfer buffer - offset &#9;push byte bmsize	; read bmsize blocks (fixed) &#9;push byte 10h	; 00h reserved - DAP is 16 bytes long (fixed) &#9;mov si, sp	; give access to the dap ds&#58;si &#61; dap &#59;&#32;test if the drive supports extended int 13h extensions, i.e. LBA mode &#59;&#32;and trim to standard read if lba is not supported &#9;cmp &#91;newloc + lbaindic&#93;, 0	; test the lba indicator &#9;jne short uselba &#59;&#32;convert lba (dx&#58;ax &#61; lba number of block to read) to CHS values &#59;&#32;see http&#58;//homepage2.nifty.com/cars/misc/chs2lba.html &#9;mov bx, word &#91;newloc + blocks&#93;	; blocks per track (spt) &#9;div bx	; remainder in dx (lba MOD spt) &#9;inc dx	; correct block number &#9;mov cx, dx	; move it in cx &#9;xor dx, dx	; clear &#59;&#32;dx&#58;ax &#61; quotient of lba DIV spt &#9;mov bx, word &#91;newloc + heads&#93;	; number of heads &#9;div bx	; remainder in dx &#59;&#32;at this point, the register values are&#58; &#59;&#32;&#32;&#32;ax &#61; cylinder number &#59;&#32;&#32;&#32;dx &#61; head number &#59;&#32;&#32;&#32;cx &#61; block number &#59;&#32;place the obtained values in the registers for the upcoming standard read &#9;mov ch, al	; lsb of cylinder number &#9;shl ah, 6	; 2 msb of cylinder number &#9;or cl, ah	; merge to form cylinder number &#9;mov dh, dl	; head number &#9;mov bx, biosloc	; data buffer offset &#9;mov ax, 0200h + bmsize	; function 02h, read bmsize blocks &#9;jmp short chsmode uselba&#58;	mov ah, 42h	; ready for extended read chsmode&#58;	mov dl, &#91;newloc + currdrive&#93;	; current drive number &#9;int 13h	; call BIOS &#9;mov &#91;newloc + errcode&#93;, ah	; (6) stow the error code away &#9;lea sp, &#91;si + 10h&#93;	; load original offset value in sp &#9;jnc short int13ok	; carry flag not set&#58; success, proceed &#59;&#32;failure is signalled by carry and ah value &#60;&#62; &#58;, perform a disk reset &#9;xor ax, ax	; reset disk system &#9;int 13h	; call BIOS &#9;dec di	; does not clear carry &#9;jnz readtry	; retry counter &#62; 0, retry &#9;cmp &#91;newloc + bmloaded&#93;, 0	; (6) &#9;jne near readerr	; (6) display errormsg with error code &#9;mov si, newloc + errormsg &#9;call writestring	; issue msg - call WILAstring not &#9;&#9;&#59;&#32;allowed yet (not yet in memory) &#59;&#32;when the attempt to read the rest of the boot manager fails, nothing else &#59;&#32;can be attempted except bringing the machine to a grinding halt !!! hang&#58;	jmp short hang	; halt the system !!! endless loop int13ok&#58;	mov di, biosloc + sign	; point to the signature &#59;&#32;For each block read note the signature &#9;mov ax, word &#91;di&#93;	; (1) get it &#9;mov &#91;newloc + mbrsign&#93;, ax	; (1) make a note &#59;&#32;Later on if the block is a PBR its validity will be assessed. good&#58;	ret &#59;&#32;messages errormsg&#58;	db 10,&#39;Disk error &#39;	; must remain in the 1st block errorgui&#58;	db &#39;??&#39;,CR,LF,0	; (6) errcode translated for GUI currdrive&#58;	db 0h	; current drive # as returned by BIOS in dl lbaindic&#58;	db 0	; lba indicator&#58; 0 &#61; lba not supported mbrsign&#58;	dw 0	; (1) mbr signature (55AA) &#9;&#9;&#59;&#32;saved for TUI &#59;&#32;3 fields storing data obtained by int 13h, funct 08h (get drive parameters) &#59;&#32;heads and blocks are used to convert an LBA value to CHS cyls&#58;	dw 0	; number of cylinders heads&#58;	dw 0	; maximum head number blocks&#58;	dw 0	; maximum block number chainadd&#58;	dd 0	; lba of chained extended flag&#58;	db 1fh	; flag/mask for testing bits in the BIOS &#59;&#9;&#9;&#59;&#32;shift status byte at address 0040h&#58;0017h mbrinproc&#58;	db 0	; bit 0 &#61; 1 new mbr being processed, &#9;&#9;&#59;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;force interaction &#9;&#9;&#59;&#32;bit 7 &#61; 1 write LBA 12 lock &#9;&#9;&#59;&#32;after having swapped mbr digindic&#58;	db 2	; (2) no. of digits indic. (1 &#61; one, 2 &#61; two) bmloaded&#58;	db 0	; (6) bit 0 &#61; 1 bootmanager loaded errcode&#58;	db 0	; (6) disk operation error code &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; write one character at the current cursor location and &#59;&#32;advance the cursor (display operating in text mode) &#59;&#32;on entry&#58; al &#61; character &#59;&#32;mod&#58; none writechar&#58; &#9;push ax &#59;&#9;push bx &#59;&#32;NOTE&#58; commented because invalid in text mode. Found everywhere though. &#59;&#32;Setting the attribute in text mode is done as shown in proc setred &#59;&#9;mov bx, 7	; screen attributes&#58; white text on black bg &#9;mov ah, 0eh	; &#9;int 10h	; display character on the screen &#59;&#9;pop bx &#9;pop ax &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; write a zero-terminated string &#59;&#32;must be located in the MBR to be able to report a disk error (message &#59;&#32;labelled "errormsg") while reading the rest of the boot manager (LBA&#61;1 ...) &#59;&#32;in &#58; si &#61; pointer to zero terminated string &#59;&#32;mod&#58; al,si writestring&#58; nxtchar&#58;	lodsb	; get char of message &#9;cmp al, 0	; is end of message ? &#9;jz short finish	; yes &#9;call writechar	; display this character &#9;jmp nxtchar	; proceed to next character finish&#58;	ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; inspect the properties of the disk/diskette drives &#59;&#32;with the purpose of finding out if LBA is supported and of determining &#59;&#32;the disk geometry for converting an LBA value to a C-H-S equivalent. &#59;&#32;in &#58; dl &#61; drive number (00h is diskette; 80h, 81h, ... is internal or &#59;&#32;external drives, incl. USB flash memory and others) &#59;&#32;On the first call, the drive number is supplied in dl by BIOS inspectdisk&#58; &#59;&#32;find out if the drive supports extended int 13h extensions &#9;mov &#91;newloc + lbaindic&#93;, 0	; clear lba indicator &#9;cmp dl, 80h	; is it a hard disk ? &#9;jb short params	; no, lba not applicable to diskette &#9;mov bx, 55aah	; condition next BIOS call &#9;mov ah, 41h	; check extension present &#9;int 13h	; call BIOS &#9;jc short params	; carry, LBA not supported &#9;cmp bx, signID	; confirm lba extensions present &#9;jne short params	; no &#9;test cx, 01h	; fixed disk access subset - is LBA ready ? &#9;jz short params	; no &#9;mov &#91;newloc + lbaindic&#93;, cl	; save lba level indicator &#9;ret	; omit what follows &#59;&#32;get number of heads and blocks in view of a needed conversion &#59;&#32;from LBA to CHS in the procedure readblock &#59;&#32;the number of cylinders is evaluated for presenting on the display &#59;&#32;dl has still the correct value params&#58;	push es	; save to protect its value &#9;mov ah, 08h	; get disk drive parameters &#9;int 13h	; call BIOS &#9;xor ax, ax	; clear 16 bits &#9;mov al, dh	; max. # of heads (0-based) &#9;inc ax	; effective # of heads &#9;mov&#91;newloc + heads&#93;, ax	; save it &#9;mov al, cl	; number of blocks per track (0 .. 63) &#9;and ax, 3fh	; mask cylinder bits &#9;mov &#91;newloc + blocks&#93;, ax	; save number of blocks &#9;xchg ch, cl	; 8 MLB of number of cylinders &#9;shr ch, 6	; 2 MSB of do. &#9;inc cx &#9;mov &#91;newloc + cyls&#93;, cx	; save number of cylinders &#9;pop es	; restore es &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; save the MBR just read in a save area (22) savembr&#58; &#9;mov si, biosloc	; &#9;mov di, MBRreloc	; &#9;mov cx, blocksize	; (22) set count &#9;rep movsb	; (22) save MBR &#9;ret &#59;&#32;code stretch used for testing and now commented out&#58; tracesec&#58; <span style="font-weight: normal" > <span style="font-weight: normal; color: #FF0000" >&#59;&#32;test code&#58; display the beginning of the block just read &#59;&#9;mov cx <span style="font-weight: normal" >, <span style="font-weight: normal; color: #FF0000" >40	; &#59;&#9;mov si <span style="font-weight: normal" >, <span style="font-weight: normal; color: #FF0000" >biosloc &#59;disnxt&#58;	lodsb	; get char of message &#59;&#9;mov bh <span style="font-weight: normal" >, <span style="font-weight: normal; color: #FF0000" >al &#59;&#9;call char2hex	; display this character &#59;&#9;loop disnxt	; proceed to next character &#59;&#9;ret <span style="font-weight: normal" > &#59;&#32;The code between the labels newmbr<span style="font-weight: normal" > and bmdate<span style="font-weight: normal" > may be moved &#59;&#32;to a block with LBA &#62; 0 when more space is needed for essential &#59;&#32;processing which must take place in the MBR (LBA &#61; 0). &#59;&#32;Process the partition table entries of a new MBR <span style="font-weight: normal" >newmbr&#58; &#9;call inspectmbr &#9;mov &#91;newloc + digindic&#93;, 2	; assume 2 &#9;mov si, newloc + lbaval	; point to lba in first table entry &#59;&#32;process the four partition table entries of the MBR now relocated next2&#58;	mov ebx, &#91;si&#93;	; note base lba of partition &#9;cmp ebx, byte 0	; is this entry empty ? &#9;je near donext	; yes, skip entry &#9;cmp &#91;newloc + lbaindic&#93;, 0 &#9;jne short lbaready	; ignore limit &#9;cmp ebx, 16450560	; 1024 * 255 * 63 &#9;&#9;&#59;&#32;max. lba value accessible with c-h-s addressing &#9;ja near donext	; cannot access &#62; 8.4GB, skip entry lbaready&#58;	mov &#91;newloc + baseadd&#93;, ebx	; save lba of extended partition &#9;mov &#91;newloc + chainadd&#93;, ebx	; save lba of chained extended &#9;call addlba	; collect in list &#9;push si &#9;call readplus	; read the corresponding block &#9;&#9;&#59;&#32;either of primary or extended partition &#9;cmp &#91;bp-4&#93;, 05h	; is it for a DOS extended partition ? &#9;je short isext	; yes, &#9;cmp byte &#91;bp-4&#93;, 0fh	; is it for a WIN extended partition LBA ? &#9;jne near notext	; no, skip &#59;&#32;process 2 first table entries of an extended partition &#59;&#32;1 - save these 2 entries in the 32 bytes at the beginning of newloc &#59;&#32;2 - the first one points to a logical drive &#59;&#32;3 - the second one, can be empty or point to the next extended partition isext&#58;	add word &#91;newloc + lbaslot&#93;, byte lbalen	; next lba entry address &#9;jmp short nxtsect	; continue in next block &#59;&#32;Free space &#9;db &#39;UUUUUUUUUUUUUUUUU&#39;	;17 bytes &#59;&#32;By design, the remaining data in block must imperatively be located here. &#59;&#32;NOTE&#58; fillto was a macro used to force locating some values at the &#59;&#32;specified offset. The macro disppaeared but the offsets are imperative. &#59;&#9;fillto 1a3h	; imperative location !!! &#9;db &#39;*&#39;	; Visible reference point bmdate&#58;	db &#39;13.03.2008 - &#39; &#59;&#32;By design, the remaining data in block must imperatively be located here. &#59;&#9;fillto 1b0h	; imperative location !!! bbmid&#58;	db &#39;BBM &#39;	; (12) unique &#39;BBM &#39; identifier baseadd&#58;	db bmLBA,0,0,0	; lba of block where the bulk <span style="font-weight: normal" >&#59;&#9;Field also stores the lba of an extended partition during the processing. <span style="font-weight: normal; color: #00009A" >&#59;&#32;Windows 2000, XP and Vista disk signature! &#59;&#32;When a drive has either of these OSes installed, the four bytes at offset &#59;&#32;1b8h through 1bbh will/might be overwritten with that disk signature. One &#59;&#32;observes a high tendency for the 1st and 3rd and for the 2nd and 4th bytes &#59;&#32;to be the same, as in the examples&#58; 96 e9 96 e9 or a8 e1 a8 e1 &#32;&#59;&#9;fillto 1b8h	; imperative location !!! dsignat&#58;	db 66h,0dh,67h,0dh,0,0	; Vista disk signature &#59;&#32;These four bytes at 1b8h MUST BE TAKEN OVER from the Windows Vista install. &#59;&#32;See&#58; http&#58;//www.multibooters.co.uk/mbr.html &#59;&#9;Dual/Multi Booting With Vista <span style="font-weight: normal" > &#59;&#32;The partition table in the MBR has four 16-byte entries. &#59;&#32;The data in this area originates from&#58; &#59;&#9;either the MBR of the boot volume &#59;&#9;or the MBR of the volume accessed by selecting another volume &#59;&#9;in the list - when entering &#39;n&#39; or &#39;p&#39;. Processing starts at label extract&#58; &#59;&#32;When only the boot manager resides on a volume (thus not partitioned) &#59;&#32;this area should contain all 0&#39;s as defined below. &#59;&#9;fillto 1beh	; imperative location !!! partab&#58;	dd 0 partyp&#58;	dd 0	; lbaval&#58;	dd 0	; 1st lba of partition <span style="font-weight: normal" >&#9;dd 0	; partition size in blocks &#9;dd 0,0,0,0	; &#9;dd 0,0,0,0	; &#9;dd 0,0,0,0	; sign&#58;	dw signID	; MBR signature &#59;&#32; &#59;&#32;LBA 1 - contains the boot manager continuation i.e. stage2 <span style="font-weight: normal" > nxtsect&#58; isext2&#58;	mov si, biosloc + partab	; point to first entry in new block &#9;mov di, newloc	; point to free space in relocated MBR &#9;mov cx, 3 * partlen	; was mov cx,32 &#9;rep movsb	; move 2 ext. part. entries to save area &#9;mov si, newloc + 8	; point to first entry lba in extended &#9;mov ebx, &#91;newloc + chainadd&#93;	; retrieve base lba of partition &#9;add &#91;si&#93;, ebx	; add relative lba &#9;mov ebx, &#91;si&#93;	; absolute lba &#9;call addlba	; collect in list &#9;call readplus	; read block corresponding to entry 1 &#9;call lbatxte	; collect the OS name in the table &#9;mov si, newloc + 24	; point to 2nd entry lba in extended &#9;cmp dword &#91;si&#93;, byte 0	; is the chain finished ? &#9;jz short donexte	; yes &#59;&#32;At this point the information about the partitions is in the lbalist table &#9;mov ebx, &#91;newloc + baseadd&#93;	; retrieve base LBA of extended &#9;add &#91;si&#93;, ebx	; add relative LBA &#9;mov ebx, &#91;si&#93;	; absolute LBA of this chained extended &#9;mov &#91;newloc + chainadd&#93;, ebx	; lba of chained extended &#9;call readplus	; read block corresponding to entry 2 &#9;jmp isext2 notext&#58;	call lbatxt	; collect the OS name in the table donexte&#58;	pop si donext&#58;	add si, byte partlen	; point to next table entry lba &#59;&#32;there are 4 partition table entries terminated with 0aa55h. &#9;cmp word &#91;si - 8&#93;, signID	; signature in there is end of table ? &#9;jne word next2	; no, process next entry &#9;cmp &#91;newloc + flag&#93;, 0	; any bit set in flag (mask)? &#9;je short direct	; no, boot directly &#9;push ds &#9;xor ax, ax &#9;mov ds, ax &#9;mov al, &#91;417h&#93;	; shift status byte in BIOS low address 0040h&#58;0017h &#9;&#9;&#9;&#9;&#59;&#32;7	Insert locked &#9;&#9;&#9;&#9;&#59;&#32;6	Caps Lock locked &#9;&#9;&#9;&#9;&#59;&#32;5	Num Lock locked &#9;&#9;&#9;&#9;&#59;&#32;4	Scroll Lock locked &#9;&#9;&#9;&#9;&#59;&#32;3	Alt key is pressed &#9;&#9;&#9;&#9;&#59;&#32;2	Ctrl key is pressed &#9;&#9;&#9;&#9;&#59;&#32;1	Left Shift is pressed &#9;&#9;&#9;&#9;&#59;&#32;0	Right Shift is pressed &#59;&#32;NOTE&#58; the same information can be collected with int 16h, function ah &#61; 02h &#59;&#32;Same technique for halting the boot process as in the OBL boot loader. &#9;pop ds &#9;test al, &#91;newloc + flag&#93;	; flag mask tests if any bit is set &#9;jnz short interact	; stop boot process for user interaction &#59;&#32;if no flag instructs to cause an interaction, force it if mbrinproc &#61; 1 &#59;&#32;i.e. &#39;p&#39; or &#39;n&#39; input caused to extract info from another mbr &#9;test &#91;newloc + mbrinproc&#93;, 1	; is flag &#61; 1 ? &#9;jnz short interact	; yes, force interaction &#59;&#32;boot the partition directly, thus without user intervention/interaction &#9;cmp &#91;newloc + defaultd&#93;, 0	; is default &#60;&#62; 0 ? e.g. 80h ? &#9;je short interact	; no, force interaction &#59;&#32;access the correct hard disk &#9;mov cl, &#91;newloc + curindex&#93;	; index of drive currently analyzed &#9;call getdrvno	; set dl &#61; drive number with that index &#9;cmp dl, &#91;newloc + defaultd&#93;	; is current hd also the default ? &#9;je short locatep	; yes, locate the partition to boot &#9;inc cl	; next drive index &#9;jmp word extract2	; extract the info from the partition table &#59;&#32;without halting the boot process for a user interaction &#59;&#32;access the correct partition locatep&#58;	mov al, dl	; &#9;call announce	; (20) optional, may be commented out &#9;mov bx, newloc + lbadesc &#9;mov ax, &#91;newloc + defaultp&#93; direct&#58; nxtos&#58;	cmp ax, word &#91;bx&#93; &#9;je near startdirec	; digit pair found, now start os &#9;add bx, byte lbalen	; point to next entry &#9;jmp nxtos interact&#58;	call clearscr &#59;&#32;stow the MBR date in the prompt line &#9;mov cx, 10	; pdate is 10 bytes long &#9;mov si, newloc + bmdate &#9;mov di, newloc + pdate &#9;rep movsb &#9;call setblue23 &#9;call WILAstring	; issue top prompt text line &#9;dw newloc + prompt &#9;call WILAstring &#9;dw newloc + drivelisth &#9;call underline	; (10) indicate selected vol. &#59;&#32;info displayed differs depending on the drive mode, i.e. LBA or CHS &#9;mov cl, &#91;newloc + currdrive&#93;	; current drive number &#9;mov al, cl &#9;call hex	; convert to 2 hex characters &#9;mov &#91;newloc + driveno&#93;, ax	; stow away in text &#9;call WILAstring &#9;dw newloc + twolinef &#9;cmp &#91;newloc + lbaindic&#93;, 0 &#9;jne short notchs &#9;call WILAstring &#9;dw newloc + modechs &#9;mov ax, &#91;newloc + cyls&#93;	; number of cylinders &#9;call int2charv &#9;mov ax, &#91;newloc + heads&#93;	; number of heads &#9;call int2charv &#9;mov ax, &#91;newloc + blocks&#93;	; blocks per track &#9;mov &#91;newloc + intval + 4&#93;, 0 &#9;call int2charv &#9;mov &#91;newloc + intval + 4&#93;, &#39;x&#39; &#9;call WILAstring &#9;dw newloc + fddtail &#9;jmp word invitlin notchs&#58;	mov si, newloc + modelba &#9;mov ah, &#91;newloc + lbaindic&#93; &#9;or ah, 30h	; convert to decimal character &#9;mov &#91;si + 4&#93;, ah	; store in text &#9;call writestring &#59;&#32;Display which kind of MBR is present on this volume <span style="font-weight: normal" >&#9;mov si, newloc + BBMBR &#9;test &#91;newloc + uvstate&#93;, 80h	; &#39;Foreign&#39; &#9;jz short setbbm	; &#9;test &#91;newloc + uvstate&#93;, 40h	; &#39;GRUB&#39; &#9;jnz short setgrub	; &#9;test &#91;newloc + uvstate&#93;, 20h	; &#39;LILO&#39; &#9;jnz short setlilo	; &#9;test &#91;newloc + uvstate&#93;, 10h	; &#39;GAG&#39; &#9;jnz short setgag	; &#9;jmp short setforeign setgag&#58;	add si, MBRtxtlen	; position on &#39;GAG&#39; setlilo&#58;	add si, MBRtxtlen	; position on &#39;LILO&#39; setgrub&#58;	add si, MBRtxtlen	; position on &#39;GRUB&#39; setforeign&#58;	add si, MBRtxtlen	; position on &#39;Foreign&#39; &#9;call writestring &#9;jmp short settail setbbm&#58;	call writestring settail&#58;	call WILAstring &#9;dw newloc + BBMtail &#59;&#32;Display a list of OSs to choose from &#59;&#32;The information is extracted from the table lbadesc creating &#59;&#32;one line of text in lbaline per primary or logical partition &#59;&#32;The extended partition is not published. <span style="font-weight: normal" >nombr&#58;	mov bx, newloc + lbadesc &#59;&#32;transfer the text in the entry to a line for display nxtline&#58;	cmp byte &#91;bx + 4&#93;, &#39;x&#39; &#9;jne short nxtline2 &#9;mov ax, &#91;bx&#93; &#9;mov &#91;newloc + locked&#93;, ax nxtline2&#58;	mov si, bx &#9;mov di, newloc + lbaline &#9;mov cx, 12	; text length, incl. line number &#9;rep movsb	; transfer text &#9;mov al, byte &#91;bx + 12&#93;	; get partition type &#9;call hex	; convert to 2 hex characters &#9;mov &#91;newloc + lbalinep&#93;, ax	; stow away in text &#9;call showsize	; (24) &#9;call hilite &#9;mov si, newloc + lbaline	; 1 line partition info &#59;&#32;if the number of partitions is less than 10 use one digit &#9;mov ax, word &#91;newloc + lbaslot&#93;	; (2) &#9;sub ax, newloc + lbalist	; (2) &#9;cmp ax, 10*lbalen	; (2) &#9;jae short twodigit	; (2) &#9;mov byte &#91;newloc + digindic&#93;, 1	; (2) note only 1 digit &#9;inc si	; (2) start in the 2nd position twodigit&#58;	call writestring &#9;add bx, byte lbalen &#9;cmp bx, word &#91;newloc + lbaslot&#93; &#9;jb nxtline &#59;&#32;Construct the user prompt line&#58; the information displayed will vary &#59;&#32;depending on the number of disk drives detected <span style="font-weight: normal" >invitlin&#58;	call WILAstring &#9;dw newloc + selectinit	; prompt initial &#9;call defaultsel &#9;call WILAstring	; finalize user prompting &#9;dw newloc + selectfin	; prompt final &#9;cmp &#91;newloc + maxdrive&#93;, 1	; only 1 disk drive ? &#9;je short finalize	; &#59;&#32;Prompt user to select the next or previous drive. &#59;&#32;In response, the partitions on the selected drive are enumerated. &#9;mov cl, &#91;newloc + curindex&#93; &#9;cmp cl, 1	; is first drive ? &#9;ja short notfirst	; go wait for new input &#9;mov si, newloc + selectn	; prompt user to select next &#9;jmp short writeit	; notfirst&#58;	cmp cl, &#91;newloc + maxdrive&#93;	; is last drive ? &#9;jb short notlast	; &#9;mov si, newloc + selectp	; prompt user to select &#9;jmp short writeit	; notlast&#58;	mov si, newloc + select	; prompt user to select writeit&#58;	call writestring &#9;call WILAstring	; finalize user prompting &#9;dw newloc + selectdrv	; prompt final finalize&#58; input&#58;	and byte &#91;newloc + mbrinproc&#93;, 0ffh - 1	; reset &#9;call readchar	; wait for single character input &#59;&#32;User response discriminator for the following cases &#59;&#32;&#39;s&#39; &#124; &#39;l&#39; &#124; &#39;b&#39; &#124; &#39;h&#39;&#39; &#124; &#39;n&#39; &#124; &#39;p&#39; &#124; 1-decimal digit &#124; 2-decimal digit <span style="font-weight: normal" >&#9;mov cl, &#91;newloc + curindex&#93;	; index of current drive &#59;&#32;CASE &#39;s&#39; <span style="font-weight: normal" >&#9;cmp al, &#39;s&#39;	; (22) &#9;je near swapMBR	; (22) &#59;&#32;CASE &#39;l&#39; <span style="font-weight: normal" >&#9;cmp al, &#39;l&#39;	; (18) &#9;jne short notl	; (18) &#9;test &#91;newloc + uvstate&#93;, 04h	; (18) &#9;jnz short set25	; (18) &#9;or &#91;newloc + uvstate&#93;, 04h	; (18) done &#9;jmp short now50	; (18) &#59;&#32;fill rest of block, and check if size ok &#9;times 2*blocksize - ($-$$) -2 db filler &#9;dw signID	; imperative signature to verify &#59;&#32;BootManager is designed to read volume MBRs and PBRs. &#59;&#32;It must verify that the blocks read have a valid signature. &#59;&#32;The second BootManager block at LBA &#61; 1 is subjected to the same &#59;&#32;validation to make sure that the continuation was correctly loaded. &#59;&#32; &#59;&#32;LBA 2 - contains the boot manager continuation <span style="font-weight: normal" > set25&#58;	and &#91;newloc + uvstate&#93;, 0ffh - 04h	; (18) now50&#58;	call clearscr	; (18) &#9;test &#91;newloc + uvstate&#93;, 2	; (18) &#9;jnz short inspecti	; (18) &#9;jmp word extract	; (18) &#59;&#32;CASE &#39;b&#39; <span style="font-weight: normal" >notl&#58; &#9;cmp al, &#39;b&#39;	; (25) &#9;jne short notb	; (25) &#9;test &#91;newloc + memoriz&#93;, 01h	; (25) &#9;jnz short resetb	; (25) &#9;or &#91;newloc + memoriz&#93;, 01h	; (25) set indicator &#9;jmp word interact	; (25) resetb&#58;	and &#91;newloc + memoriz&#93;, 0ffh - 01h	; (25) clear indicator &#9;jmp word interact	; (25) &#59;&#32;CASE &#39;h&#39; <span style="font-weight: normal" >notb&#58; &#9;cmp al, &#39;h&#39;	; (15) request to display HW info ? &#9;jne short noth	; (15) no &#9;call clearscr	; (15) inspecti&#58;	call inspectvbe	; (3) &#9;call inspectpci	; (15) &#9;call WILAstring	; issue top prompt text line &#9;dw newloc + invitretn &#9;call readchar &#9;mov cl, &#91;newloc + curindex&#93;	; index of current drive &#9;jmp short extract	; (5) &#59;&#32;CASE &#39;n&#39; <span style="font-weight: normal" >noth&#58;	cmp al, &#39;n&#39;	; request to explore next drive ? &#9;jne short notn	; no notv2&#58;	inc cl	; index of next drive to access &#9;cmp cl, &#91;newloc + maxdrive&#93;	; is above last drive ? &#9;ja word input	; yes, go wait for new input &#9;call isaccess	; (14) is that drive marked &#39;not accessible&#39; ? &#9;je notv2	; (14) ignore it and proceed to next &#9;jmp short extract	; &#59;&#32;CASE &#39;p&#39; <span style="font-weight: normal" >notn&#58;	cmp al, &#39;p&#39;	; request to explore previous drive ? &#9;jne notp	; no notn2&#58;	dec cl	; index of previous drive to access &#9;cmp cl, 1	; is below first drive ? &#9;jb word input	; yes, go wait for new input &#9;call isaccess	; (14) is that drive marked &#39;not accessible&#39; ? &#9;je notn2	; (14) ignore it and proceed to next <span style="font-weight: normal" >&#59;&#32;extract the MBR of another volume and process it as if it had been &#59;&#32;loaded by the BIOS, that is, originated from the boot volume. extract&#58;	or byte &#91;newloc + mbrinproc&#93;, 1 extract2&#58;	mov &#91;newloc + curindex&#93;, cl; note index of volume to process &#9;call getdrvno &#9;mov &#91;newloc + currdrive&#93;, dl		; note the volume to inspect next &#59;&#32;restore the default text in the lbadesc table &#9;call restorelba &#9;call inspectdisk &#9;mov bp, newloc + baseadd	; point to pseudo table entry &#9;mov dword &#91;bp&#93;, 0	; MBR on any volume has LBA&#61;0 &#9;call readblock	; read MBR into area at biosloc &#9;call savembr	; what kind of data in MBR &#59;&#32;move the 4 partition table entries to newloc thus replacing the current ones &#9;mov si, biosloc + partab	; si points to partab &#9;mov di, newloc + partab	; relocation address &#9;mov cx, 64	; set count &#9;rep movsb	; move partition table data &#9;jmp word newmbr	; go process another MBR &#59;&#32;CASE &#39;digit&#39; <span style="font-weight: normal" >&#59;&#32;find the LBA corresponding to the chosen partition number and save in bx notp&#58; &#59;&#9;call writechar	; TRACE - echo user input &#9;cmp byte &#91;newloc + digindic&#93;, 2	; (2) &#9;je short firstdig	; (2) is first digit &#9;mov dl, &#39;0&#39;	; (2) force &#39;0&#39; as 1st digit &#59;&#32;whereas the user will operate with 1 or 2 digits, the internal processing &#59;&#32;is always dealing with 2 digits &#9;jmp short isalone	; (2) this digit is alone &#59;&#32;find the first digit in the lbadesc table firstdig&#58;		; (2) &#9;mov bx, newloc + lbadesc dig1try&#58;	cmp al, &#91;bx&#93; &#9;je short digit2	; digit found, now find digit pair &#9;add bx, byte lbalen	; point to next entry &#9;cmp bx, word &#91;newloc + lbaslot&#93; &#9;jb dig1try invresp&#58;	call WILAstring &#9;dw newloc + invalid &#9;jmp word input	; go wait for new input &#59;&#32;expect 2nd digit digit2&#58;	mov dl, al	; save first digit &#9;call readchar	; wait for single character input &#9;call writechar	; echo user input &#59;&#32;find the 2-digit value in the lbadesc table isalone&#58;		; (2) &#9;xchg ah, al &#9;mov al, dl &#9;mov bx, newloc + lbadesc dig2try&#58;	cmp ax, word &#91;bx&#93; &#9;jne short nentry	; digit pair not found, next &#9;cmp dword &#91;bx + 3&#93;, &#39;no P&#39;	; &#39;no PBR&#39; &#9;je invresp &#9;cmp dword &#91;bx + 3&#93;, &#39;&#124;no &#39;	; &#39;&#124;no PBR&#39; &#9;je invresp &#9;jmp short startos	; digit pair found, now start os nentry&#58;	add bx, byte lbalen	; point to next entry &#9;cmp bx, word &#91;newloc + lbaslot&#93; &#9;jb dig2try dig2ext&#58;	jmp invresp	; invalid response &#59;&#32;END CASE<span style="font-weight: normal" > &#59;&#32;Start the operating system chosen by its menu number, &#59;&#32;read the partition boot block, place it at the exact location where &#59;&#32;the BIOS would have placed it and jump to it &#59;&#32;i.e. chain load to the Partition Boot Record of the selected partition <span style="font-weight: normal" >&#59;&#32;At this point, bx points to the lbadesc entry corresponding to the partition startos&#58;	cmp word &#91;newloc + locked&#93;, ax	; is it the locked Extended ? &#9;je dig2ext	; yes, it may not be selected &#59;&#32;Note which drive and which partition are now selected. &#59;&#32;They become the defaults for the next BootManager start. &#9;mov word &#91;newloc + defaultp&#93;, ax	; note partition number &#9;mov dl, &#91;newloc + currdrive&#93;	; get current drive number &#9;mov &#91;newloc + defaultd&#93;, dl	; note drive number &#9;test &#91;newloc + memoriz&#93;, 01h	; (25) &#9;jnz short leavesel	; (25) &#9;mov &#91;newloc + defaultd&#93;, 0	; (25) force de-selection &#9;mov word &#91;newloc + defaultp&#93;, &#39;??&#39;	; (25) force de-selection &#59;&#32;Save to drive configuration for the next system restart. leavesel&#58;	mov cx, 8*prevdlen	; (8) &#9;mov si, newloc + drivelist	; (8) source &#9;mov di, newloc + prevdlist	; (8) relocation address &#9;rep movsb	; (8) move &#9;push bx &#9;call writeblock	; record these values &#9;pop bx &#59;&#32;determine which partition table entry corresponds to this LBA and load &#59;&#32;its address in si - Needed by the interface to Damn Small Linux - DSL startdirec&#58;	call setsiDSL &#9;mov ebx, &#91;bx-4&#93;	; point to corresponding lba &#9;mov &#91;newloc + baseadd&#93;, ebx &#9;mov bp, newloc + baseadd	; &#9;call readblock	; read partition boot block <span style="font-weight: normal; color: #FF0000" >&#59;&#32;test code&#58; display the first 32 bytes of the block just read, stop and &#59;&#32;wait for a keyboard input &#59;&#9;mov cx, 32	; 32 bytes &#59;&#9;mov si, biosloc	; &#59;nxtlba&#58;	lodsb	; get char of message &#59;&#9;cmp cx, 0	; is last entry ? &#59;&#9;jz short read	; yes &#59;&#9;mov bh, al &#59;&#9;call ptyp	; display this character &#59;&#9;dec cx &#59;&#9;jmp nxtlba	; proceed to next character &#59;read&#58;	call readchar	; wait for single character input <span style="font-weight: normal" > &#59;&#32;Drive mapping just before transferring control to the PBR loaded at biosloc <span style="font-weight: normal" >&#59;&#32;In the case of Bluebottle, Native Oberon and DOS, the drive &#59;&#32;number (80h, 81h ...) is stored in the boot block of the OS partition. &#59;&#32;In order to boot from a drive which is not the first as it was at &#59;&#32;installation time, one needs to insert the correct number before &#59;&#32;the boot block is exploited. &#59;&#32;In pratice, it suffices to modify it on the fly in memory at biosloc. &#59;&#32;Drive mapping for other OSs will eventually be implemented later. &#9;mov dl, &#91;newloc + currdrive&#93;	; get drive number &#59;&#32;and place it in DL as specified in the work assumptions - cfr. BootMan.Text &#9;cmp word &#91;biosloc + 3&#93;, &#39;OB&#39;	; for &#39;OBERON&#39;, map drive ? &#59;&#32;&#39;OBERON&#39; is found in Oberon partitions of types&#58; 4ch &#61; 76, 4fh and 50h &#9;je short mapdrive	; do map &#9;cmp word &#91;biosloc + 6&#93;, &#39;LI&#39;	; &#39;SYSLINUX&#39; of DSL " &#9;jne short mapdrive	; if DSL do not map, leave PBR as is &#59;&#32;Such is the case for DSL on a USB flash memory stick &#9;mov si, &#91;newloc + DSLsiVal&#93; &#9;jmp short nomap <span style="font-weight: normal; color: #FF0000" > &#59;&#32;Add whichever OS needs a drive number in its PBR here! <span style="font-weight: normal" >mapdrive&#58;	mov byte &#91;biosloc + 24h&#93;, dl	; correct drive number on the fly nomap&#58;	xor dh, dh	; zero dh; dl must be passed over &#9;jmp 0&#58;biosloc 	; jump to PBR &#59;&#32;On entry to the PBR&#58; &#59;&#9;es &#61; 0 &#59;&#9;dl &#61; is the BIOS drive number accessed &#59;&#32;This code is now definitively left !!<span style="font-weight: normal" > &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; place the OS name (primary partition) in the next entry <span style="font-weight: normal" >&#59;&#32;si &#58; MUST be left untouched! - pointer to lba in partition table entry lbatxt&#58; &#9;mov di, word &#91;newloc + lbaslot&#93; &#9;add di, byte 7	; position of text inside slot osname&#58;	push si &#59;&#32;Now that a PBR is being processed, verify that the signature is valid. &#9;cmp word &#91;newloc + mbrsign&#93;, signID	; (1) is signature present ? &#9;je short signgood &#9;mov si, newloc + notPBR	; bad signID means not a PBR &#9;jmp short movename signgood&#58;	mov si, biosloc + 3	; OS name in PBR &#59;&#32;The PBR has a valid signID but when the OS name contains all 0h &#59;&#32;it is the sign of a Linux partition (Ubuntu, Mandriva, DSL, ....) &#9;cmp word &#91;si&#93;,0 &#9;jne short testLILO &#9;mov si, newloc + linuxtxt	; substitute this to the 0s &#9;jmp short movename testLILO&#58;	cmp dword &#91;si + 3&#93;,&#39;LILO&#39; &#9;jne short testOBER &#9;mov si, newloc + LILOMBR	; same shifted left &#9;jmp short movename testOBER&#58;	cmp word &#91;si&#93;,&#39;OB&#39; &#9;jne short movename &#9;mov word &#91;si + 6&#93;,&#39; &#39; &#59;&#32;move whichever name applies to this partition to output area movename&#58;	mov cx, 8 &#9;rep movsb &#9;pop si &#9;add word &#91;newloc + lbaslot&#93;, byte lbalen	; next lba entry address &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; write the block with LBA &#61; bmLBA+bmsize-1 to the volume <span style="font-weight: normal" >&#59;&#32;thus recording the number of&#58; &#59;&#32;- the selected boot disk (field defaultd) and of &#59;&#32;- the selected partition (fields defaultp) &#59;&#32;which become default values &#59;&#32;No write operation is performed when booting from a FD because&#58; &#59;&#32;1 - a FDD is considered as a rescue disk, not resident &#59;&#32;2 - a CD-ROM emulates a FDD and cannot be written on writeblock&#58; <span style="font-weight: normal; color: #FF0000" >&#59;&#32;simple tracing sequence &#59;&#9;mov cx, 32	; &#59;&#9;mov si, newloc + blocksize &#59;nxtlba&#58;	lodsb	; get char &#59;&#9;cmp cx, 0	; is last char ? &#59;&#9;jz short read	; yes &#59;&#9;call char2hex	; display this character &#59;&#9;dec cx &#59;&#9;jmp nxtlba	; proceed to next character &#59;read&#58; <span style="font-weight: normal" > &#9;test byte &#91;newloc + mbrinproc&#93;, 80h	; write lock on ? &#9;jnz short donotwrt	; yes, do not write &#9;inc byte &#91;newloc + reason&#93;	; discrimator of situation &#9;cmp byte &#91;newloc + drivenbrs + 1&#93;, 80h	; is it a hard disk ? &#59;&#32;if the boot disk drive (first in the list) was a USB-FDD or CD-ROM, then &#9;jb short donotwrt	; DO NOT register the selection &#9;inc byte &#91;newloc + reason&#93;	; discrimator of situation &#9;test &#91;newloc + uvstate&#93;, 80h	; is it a foreign MBR ? &#9;jnz short donotwrt	; DO NOT register the selection &#9;mov di, maxretry	; number of tries tryw&#58;	mov ax, 4300h	; ready for extended read &#9;mov si, newloc + dapw	; dap - Device Address Packet (see below) &#59;&#32;test if the drive supports extended int 13h extensions, i.e. LBA mode &#59;&#32;and trim to standard write if lba not supported &#9;cmp &#91;newloc + lbaindic&#93;, 0	; test the lba indicator &#9;jne short uselbaw &#9;mov ax, 0301h	; standard write 03h, 1 block &#59;&#32;place the values in the registers &#9;mov cx, bmLBA + bmsize - 1	; write block corresponding to LBA 12 &#9;mov dh, 0	; head 0 &#9;mov bx, newloc + bmsize * blocksize	; data buffer offset &#9;jmp short uselbaw &#59;&#9;times 3*blocksize - ($-$$) db filler &#59;&#32; &#59;&#32;LBA 3 <span style="font-weight: normal" > uselbaw&#58;	mov dl, 80h	; boot drive number &#9;int 13h	; call BIOS &#9;jnc short int13okw	; carry flag not set&#58; ok, proceed &#59;&#32;on failure, perform a disk reset &#59;&#32;by experience this event was never observed but who knows !!! it &#59;&#32;will never happen? &#9;mov &#91;newloc + errcode&#93;, ah	; (6) stow the error code away &#9;xor ax, ax	; reset disk &#9;int 13h	; call BIOS &#9;dec di	; does not clear carry &#9;jnz tryw	; retry counter &#62; 0, retry &#9;jmp word showerr	; (6) display errormsg with code &#59;&#32;better than the next brutal instruction &#59;&#32;hangw&#58;	jmp hangw	; halt the system !!! endless loop int13okw&#58;	call WILAstring &#9;dw newloc + recording &#9;jmp short persist donotwrt&#58;	call WILAstring &#9;dw newloc + ignoring persist&#58;	call persistance	; (23) add msg persistance &#9;ret	; &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; insert size (MB/GB) in text string <span style="font-weight: normal" >&#59;&#32;in &#58; bx &#61; pointer to lbadesc for this partition line &#59;&#32;&#32;&#32;&#32;&#32;&#32;&#32;must be left unaltered showsize&#58; &#9;mov dword &#91;newloc + limit&#93;, 999999 &#9;mov eax, dword &#91;bx + 13&#93;	; (24) get partition size in blocks &#59;&#32;show volume size showsizev&#58;	mov cx,6	; (24) max. number of digits to produce &#9;mov si,newloc + sizeunit	; (24) start at least significant digit &#9;shr eax,11	; (24) partition size in MB &#9;mov word &#91;newloc + sizeMG&#93;, &#39;MB&#39;	; (24) Megabytes &#9;cmp eax, dword &#91;newloc + limit&#93;	; (24) display max. 6 digits &#9;jbe short sizeM	; (24) &#9;shr eax, 10	; (24) DIV 1024 &#62; size in GB &#9;mov word &#91;newloc + sizeMG&#93;, &#39;GB&#39;	; (24) Gigabytes sizeM&#58;	push bx	; (24) &#9;call convert	; (24) &#9;pop bx	; (24) &#9;ret	; (24) limit&#58;	dd 0 &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; place the OS name (logical drive) in the next entry <span style="font-weight: normal" >&#59;&#32;in &#58; PBR located at biosloc lbatxte&#58; &#9;mov di, word &#91;newloc + lbaslot&#93; &#9;mov byte &#91;di + 7&#93;, &#39;&#124;&#39; &#9;add di, byte 8	; position of text inside slot &#9;jmp word osname	; treat as primary partition name &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; collect the information on the number of installed (4) &#59;&#32;drives in a group - either hard disk or floppy disk or both &#59;&#32;Executed only once when the MBR from the boot volume is extracted <span style="font-weight: normal" >driveinfo&#58; &#9;cmp &#91;newloc + maxdrive&#93;,0	; max. drive number determined ? &#9;jne short done	; yes, skip &#9;mov word &#91;newloc + driveslot&#93;,newloc + drivelist &#9;&#9;&#59;&#32;set the table beginning address &#9;mov dl,&#91;newloc + currdrive&#93;	; get current drive &#9;mov al,dl &#9;call hex	; convert to 2 hex characters &#9;mov &#91;newloc + driveinctrl&#93;,ax	; stow away in drivelisth &#9;push es	; save to protect its value &#9;call groupinfo &#9;xor &#91;newloc + currdrive&#93;,80h	; flip msb to access other group &#9;call groupinfo &#9;xor &#91;newloc + currdrive&#93;,80h	; restore original value &#9;pop es	; restore es done&#58;	ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; collect the information on the number of installed (4) &#59;&#32;drives in a group - floppy disk or hard disk <span style="font-weight: normal" >&#59;&#32;mod&#58; ax, cx, dx, di groupinfo&#58; &#9;mov dl,&#91;newloc + currdrive&#93;	; get current drive &#9;and dl,80h	; (22) start with first in group &#9;mov &#91;newloc + grouplead&#93;,dl	; (22) save group leader &#59;&#32;obtain the number of drives in this goup (returned in dl) &#9;mov ah,08h	; get disk drive parameters &#9;int 13h	; call BIOS <span style="font-weight: normal; color: #FF0000" >&#59;&#32;(9) dl now contains the number of drives around that drive, but even when &#59;&#32;no diskette drive is installed or when it is disabled, BIOS returns dl &#61; 1. &#59;&#32;In that case of non-existent diskette drive, CF &#61; 0 means successful, but &#59;&#32;bx &#61; 0 is used to decide that no diskette drive is present. &#59;&#32;However, booting from CD-ROM also arrives here with dl &#61; 1 and bx &#61; 0. &#59;&#32;Must thus test if CD-ROM or not -&#62; using value in ax as discriminator. &#59;&#32;When booting from USB_FDD, the BIOS volume id is 00h or 80h depending &#59;&#32;on the BIOS. &#9;cmp <span style="font-weight: normal" >&#91; <span style="font-weight: normal; color: #FF0000" >newloc + <span style="font-weight: normal" > <span style="font-weight: normal; color: #FF0000" >currdrive&#93;,80h	; (9) &#9;jae short hddgrp	; (9) no problem with hdd &#9;cmp <span style="font-weight: normal" >&#91; <span style="font-weight: normal; color: #FF0000" >newloc + <span style="font-weight: normal" > <span style="font-weight: normal; color: #FF0000" >maxdrive&#93;,0	; (9) first group detected is fdd &#59;&#32;which means that the boot volume is a CD-ROM or a USB-FDD. &#9;jne short exitgrp	; (9) no, forget about fdds &#9;mov <span style="font-weight: normal" >word &#91; <span style="font-weight: normal; color: #FF0000" >newloc + <span style="font-weight: normal" > <span style="font-weight: normal; color: #FF0000" >fddtype&#93;,ax	; note that &#9;mov dl,1	; (9) consider only one device &#59;&#32;and ignore the remaining fdds if any exists. <span style="font-weight: normal" > <span style="font-weight: normal; color: #FF0000" >hddgrp&#58; <span style="font-weight: normal" >	add &#91;newloc + maxdrive&#93;,dl &#9;xor cx,cx &#9;mov cl,dl	; set repeat counter, dl now free &#9;xor ax,ax	; clear &#9;mov al,&#91;newloc + grouplead&#93;	; (22) group leader dgroup&#58; &#9;inc word &#91;newloc + drivtaddr&#93; &#9;mov di,&#91;newloc + drivtaddr&#93; &#9;mov byte &#91;di&#93;,al	; save drive number in table &#9;push cx	; save repeat counter &#59;&#32;brief report of the drive number and parameters. One report per drive is &#59;&#32;in the drivelist at the address found in driveslot. &#9;push ax	; save drive number &#9;push di &#9;mov di,&#91;newloc + driveslot&#93; &#9;mov byte &#91;di&#93;,26	; single character &#39;right arrow&#39; &#9;call hex &#9;mov byte &#91;di + 1&#93;,al	; most sign. in drive number &#9;xchg ah,al	; &#9;mov byte &#91;di + 2&#93;,al	; least sign. in drive number &#9;pop di &#9;call driveparam	; (8) &#9;pop ax	; restore drive number &#9;inc al	; next drive &#9;pop cx	; restore repeat counter &#9;add word &#91;newloc + driveslot&#93;,byte 10 &#9;loop dgroup exitgrp&#58;	ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; collect the information on the installed drives (8) <span style="font-weight: normal" >&#59;&#32;interprete the data in the return buffer and its extensions, if any driveparam&#58; &#9;mov dl,byte &#91;di&#93;	; get current drive number &#9;cmp dl,80h	; is it among the hdds ? &#9;jb isfdd	; no, is floppy drive or cd-rom &#59;&#32;collect more information concerning hdds &#9;mov si,newloc + dpbuffer	; extra-muros buffer &#9;mov word &#91;si&#93;,74	; data size to receive &#9;&#9;&#59;&#32;see remark under dpbuffer &#9;mov ah,48h	; get drive parameters &#9;int 13h	; call BIOS &#9;jc short int13err	; carry denotes error <span style="font-weight: normal; color: #FF0000" >&#59;&#32;volume geometry information - not used &#59;&#9;mov al,&#91;newloc + <span style="font-weight: normal" > <span style="font-weight: normal; color: #FF0000" >infflags&#93; &#59;&#9;call char2hex &#59;&#9;mov ax,&#91;si + 4&#93; <span style="font-weight: normal" >	; cylinders <span style="font-weight: normal; color: #FF0000" > &#59;&#9;call int2char4 &#59;&#9;mov ax,&#91;si + 8&#93; <span style="font-weight: normal" >	; heads <span style="font-weight: normal; color: #FF0000" > &#59;&#9;call int2char4 &#59;&#9;mov ax,&#91;si + 12&#93; <span style="font-weight: normal" >	; blocks per track <span style="font-weight: normal; color: #FF0000" > &#59;&#9;call int2char4 &#59;&#9;mov ax,&#91;si + 24&#93; <span style="font-weight: normal" >	; bytes per block <span style="font-weight: normal; color: #FF0000" > &#59;&#9;call int2char4 <span style="font-weight: normal" > &#59;&#32;TRACE&#58; Take a view of the first dpbuffer encountered and halt! &#59;&#32;Modern PCs do not return device path information, &#59;&#32;only PCI interface path <span style="font-weight: normal; color: #FF0000" >&#59;&#9;mov cx,72	; &#59;&#9;mov si,newloc + <span style="font-weight: normal" > <span style="font-weight: normal; color: #FF0000" >dpbuffer	; extra-muros buffer &#59;disnxt&#58;	lodsb	; get char of buffer &#59;&#9;mov bh,al &#59;&#9;call char2hex	; display in 2 hex &#59;&#9;loop disnxt	; proceed to next character &#59;hardstop&#58;	jmp short hardstop <span style="font-weight: normal" > &#9;mov di,&#91;newloc + driveslot&#93; &#9;add di,byte 4 &#59;&#32;display the volume size in the matching entry on the next line &#9;mov dword &#91;newloc + limit&#93;,999 &#9;mov eax,dword &#91;si + 16&#93;	; (8) volume size in blocks &#9;call showsizev	; (8) &#59;&#32;transfer the volume size to the next driveslot &#9;mov cx,5	; extract only 5 bytes &#9;mov si,newloc + sizethous	; first digit to extract &#9;rep movsb	; move cx bytes &#9;call interfinfo	; (13) collect volume interface information &#9;ret	; &#59;&#32;This error occurs when&#58; &#59;&#32;1 - BIOS was set up to boot from a USB drive (it chooses the first one) &#59;&#32;2 - then attempt to obtain the drive parameters of another USB drive. &#59;&#32;That drive is not accessible in that set-up. int13err&#58;	mov di,&#91;newloc + driveslot&#93; &#9;add di,byte 4 &#9;mov dword &#91;di&#93;,&#39;n.a.&#39;	; mark as &#39;not accessible&#39; &#9;ret	; exit isfdd&#58; &#59;&#32;discriminate FDD and CD-ROM by the value returned earlier in ax &#59;&#32;this bit of code appears superfluous&#58; same value returned for real fdd &#59;&#32;or fdd emulating cd-rom &#9;mov di,&#91;newloc + driveslot&#93;	; (13) &#59;&#9;cmp word &#91;newloc + fddtype&#93;,0030h	; (13) CD-ROM emulating FDD ? &#59;&#9;jne short notcd	; (13) no, booting from FDD &#59;&#9;mov dword &#91;di + 81&#93;,&#39;CD-R&#39;	; (13) 80 char. line + 1 &#59;&#9;mov word &#91;di + 85&#93;,&#39;OM&#39;	; (13) 80 char. line + 5 &#59;&#9;ret	; (13) notcd&#58;	mov dword &#91;di + 83&#93;,&#39;FDD &#39;	; (13) 80 char. line + 3 &#9;ret	; (13) &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; underline the drive info line (10) <span style="font-weight: normal" >underline&#58; &#59;&#32;adjust the curindex as is required after swapping MBR &#9;mov si,newloc + drivenbrs + 1	; &#9;mov al,1 &#9;mov cl,&#91;newloc + currdrive&#93;	; get current drive trynextd&#58;	cmp byte &#91;si&#93;,cl &#9;je short valindex	; valid index obtained &#9;inc si &#9;inc al &#9;jmp trynextd valindex&#58;	mov &#91;newloc + curindex&#93;,al	; correct curindex &#9;mov di,newloc + drivelistul	; destination address &#9;mov al,&#91;newloc + curindex&#93;	; current drive index addspace&#58;	mov cx,10 &#9;dec al &#9;jz short markit &#9;mov si,newloc + spaces	; move 10 spaces &#9;rep movsb &#9;jmp short addspace markit&#58;	mov si,newloc + marks	; move 10 marks &#9;rep movsb &#9;mov byte &#91;di&#93;,0	; add a 0-terminator &#9;call WILAstring	; write complete underlining string &#9;dw newloc + drivelistul &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; is current drive accessible ? (14) <span style="font-weight: normal" >&#59;&#32;in&#58; cl - drive index (origin is 1) &#59;&#32;out&#58; carry is 1 if drive marked as non-accessible isaccess&#58; &#9;mov al,cl	; (14) index of drive to scrutinize &#9;cbw	; (14) convert byte to word &#9;mov dx,10	; (14) drivelist entry length &#9;mul dx	; (14) ax now contains destination location &#9;mov di,ax	; (14) total displacement &#9;add di, newloc + drivelist - 6	; (14) 10 - 4 &#61; 6 &#9;cmp dword &#91;di&#93;,&#39;n.a.&#39;	; (14) 10 - 4 &#61; 6 &#9;ret	; (14) &#59;&#32;&#61;&#61;&#61;&#61;&#61; edit the disk operation error code as errorgui in the errormsg &#59;&#32;Extension of the readblock/writeblock procedure (6) <span style="font-weight: normal" > showerr&#58;	mov al,&#91;newloc + errcode&#93; &#9;call hex	; convert to 2 hex characters &#9;mov word &#91;newloc + errorgui&#93;,ax	; stow away in text &#9;call WILAstring &#9;dw newloc + errormsg &#9;jmp word invitlin &#59;&#32;&#61;&#61;&#61;&#61;&#61; edit the disk operation error code as errorgui in the errormsg &#59;&#32;Extension of the readblock procedure (6) <span style="font-weight: normal" > readerr&#58;	mov al,&#91;newloc + errcode&#93; &#9;call hex	; convert to 2 hex characters &#9;mov word &#91;newloc + errorgui&#93;,ax	; stow away in text &#9;call WILAstring &#9;dw newloc + errormsg &#9;cmp dl,80h	; is it a hard disk ? &#9;jae word input	;no, &#9;call WILAstring &#9;dw newloc + fdderror errinfo&#58;	call persistance	; (23) add msg persistance &#9;jmp word interact driveslot&#58;	dw newloc + drivelist	; address of next available slot fddtype&#58;	dw 0	; type of fdd detected &#9;times 4*blocksize - ($-$$) db filler &#59;&#32; &#59;&#32;LBA 4 - data areas <span style="font-weight: normal" > modelba&#58;	db &#39;LBA ?) - MBR&#58; &#39;,0 modechs&#58;	db &#39;CHS &#39;,0 &#59;&#32;One line of text per partition &#59;&#32;number / partition type / partition size lbaline&#58;	db &#39;ij -          &#39; lbalinep&#58;	db &#39;XY  &#39;	; partition type in hex &#9;db &#39;thu&#39; &#59;&#32;the following 5 bytes are for displaying volume size sizethous&#58;	db &#39;th&#39;	; thousand/hundred/ sizeunit&#58;	db &#39;u&#39;	; unit digit is inserted first sizeMG&#58;	db &#39;mb&#39;	; MB or GB crlf&#58;	db CR,LF,0 dfttext&#58;	db &#39;Extended &#39;,0	; default text locked&#58;	dw 0	; OS number which may not be selected &#9;&#9;&#59;&#32;that is, the extended partition &#59;&#32;area in which partition data for up to 12 partitions is collected&#58; &#59;&#32;each partition is completely identified by a quadruple&#58; &#59;&#9;lbalist / lbadesc / lbapartno / lbasize in no. of blocks &#59;&#32;each entry has lbalen bytes lbaslot&#58;	dw newloc + lbalist	; address of next available slot lbalist&#58;	dd 0	; lba of first partition block lbadesc&#58;	db &#39;01 Extended &#39;	; partition description lbapartno&#58;	db 0	; partition type extracted from partition table lbasize&#58;	dd 0	; (24) partition size in no. of blocks &#9;dd 0 &#9;db &#39;02 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;03 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;04 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;05 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;06 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;07 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;08 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;09 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;10 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;11 Extended &#39; &#9;db 0 &#9;dd 0 &#9;dd 0 &#9;db &#39;12 Extended &#39; &#9;db 0 &#9;dd 0 &#59;&#32;three lines of up to 8 volumes detected to display in one go &#59;&#32;Each volume is allocated a 10-byte slot with the structure&#58; &#59;&#32;&#9;1 character "right arrow" &#59;&#32;&#9;2 characters drive number 00h, 01h, 80h, 81h, ... &#59;&#32;&#9;1 space &#59;&#32;&#9;the drive size in MB or GB, or &#39;fdd&#39; for a floppy diskette &#59;&#9;or a CD-ROM emulating a floppy &#59;&#32;&#9;2 spaces drivelisth&#58;	db &#39;BIOS detected volumes / &#39; driveinctrl&#58;	db &#39; &#39;	; drive in control by MBR &#9;db &#39; is boot volume in control&#39;,CR,LF	; drive list header drivelist&#58;	db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#59;&#9;db CR,LF	; automatic cr+lf because full line volinterf&#58;	db &#39;         &#39;	; volume interface&#58; ATAPI, ATA, USB &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#59;&#9;db CR,LF	; automatic cr+lf because full line &#9;db 0 &#59;&#9;times 5*blocksize - ($-$$) db filler &#59;&#32; &#59;&#32;LBA 5 <span style="font-weight: normal" >maxdrive&#58;	db 0	; max. number of hard disk detected &#59;&#32;0 denotes that the max. drive number is not yet determined drivtaddr&#58;	dw newloc + drivenbrs	; address in table for groupinfo drivenbrs&#58;	db -1,-2,-2,-2,-2,-2,-2,-2,-2 &#59;&#9;table of (max. 8) disk drive numbers &#9;&#9;&#59;&#32;position with index 0 is empty curindex&#58;	db 1	; index of drive currently accessed &#91;1 .. 8&#93; &#9;&#9;&#59;&#32;for underline &#59;&#32;dap for an extended write 13h disk operation defined in proc writeblock &#59;&#32;the structure of the dap is&#58; dapw&#58;	db 10h	; dap size (fixed) &#9;db 0	; reserved (fixed) &#9;dw 1	; number of blocks to transfer (fixed) boffw&#58;	dw newloc + bmsize * blocksize	; address of transfer buffer - offset &#9;dw 0	; address of transfer buffer - segment &#9;dd bmLBA + bmsize - 1	; starting absolute block address LBA &#9;dd 0	; remaining 32 bits of address &#59;&#32;work areas and prompt lines spaces&#58;	db &#39;         &#39; selectn&#58;	db &#39; N(ext)&#39;,0 select&#58;	db &#39; N(ext) or&#39; selectp&#58;	db &#39; P(revious)&#39;,0 selectdrv&#58;	db &#39; volume&#39; marks&#58;	db &#39; &#39;,30,30,30,30,30,30,CR,LF,0	; (10) marks selectfin&#58;	db &#39; L (toggle) 25/50 lines&#39;,CR,LF &#9;db &#39; H to display PC HW info&#39;,CR,LF &#9;db &#39; S MBR on selected volume is to take control as boot volume&#39;,CR,LF,0 invalid&#58;	db &#39; invalid input, retry&#39;,CR,LF,0 &#59;&#32;(25) text to appear in green or red preselr&#58;	db &#39; B (toggle) @ next boot, show this menu&#39;,CR,LF,0 preselg&#58;	db &#39; B (toggle) @ next boot, start selected OS &#91;currently v. &#39; dftdtext&#58;	db &#39;, p. &#39; dftptext&#58;	db &#39; &#93;&#39;,CR,LF,0 fdderror&#58;	db &#39;Either no floppy drive is present&#58; disable it &#39; &#9;db &#39;in the BIOS setup,&#39;,CR,LF &#9;db &#39;       or no diskette is present&#58; insert one&#39;,CR,LF,0 &#59;&#9;times 6*blocksize - ($-$$) db filler &#59;&#32; &#59;&#32;LBA 6 <span style="font-weight: normal" > twolinef&#58;	db CR,LF,&#39;Volume &#39; driveno&#58;	db &#39;  &#39;	; displayable digit mode&#58;	db &#39;(Mode &#39;,0 grouplead&#58;	db 0	; (22) is 80h OR 00h wrongdid&#58;	db &#39;Must access 80h&#39;,CR,LF,0 BBMtail&#58;	db &#39; - Vol. signature @ 1B8h&#58; &#39; signb1&#58;	db &#39;   &#39; signb2&#58;	db &#39;   &#39; signb3&#58;	db &#39;   &#39; signb4&#58;	db &#39;  &#39;,CR,LF,LF,0 fddtail&#58;	db &#39;) Not partitioned.&#39;,CR,LF,0 &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; inspect the data in the MBR just read <span style="font-weight: normal" >&#59;&#32;does not alter registers inspectmbr&#58; &#59;&#32; determine the kind of boot manager it corresponds to&#58; &#59;&#9;Bluebottle, GRUB, LILO or Foreign &#59;&#32;A Windows MBR has no fixed identifying strign, hence Foreign &#59;&#32;Save that information in uvstate for later use.<span style="font-weight: normal" > &#9;and &#91;newloc + uvstate&#93;,0ffh - 0f0h	; clear bits 7,6,5,4 &#9;cmp dword &#91;MBRreloc + 17h&#93;,&#39;GAG &#39;	; position of GAG &#9;jne short notGAG &#9;or &#91;newloc + uvstate&#93;,90h	; set bit 4 &#61; GAG &#9;jmp short MBRok notGAG&#58;	cmp dword &#91;MBRreloc + bbmid&#93;,&#39;BBM &#39; &#9;je short MBRok &#9;or &#91;newloc + uvstate&#93;,80h	; set bit 7 &#61; foreign &#9;cmp dword &#91;MBRreloc + 017fh&#93;,&#39;GRUB&#39;	; position of GRUB &#9;jne short notGRUB &#9;or &#91;newloc + uvstate&#93;,40h	; set bit 6 &#61; GRUB &#9;jmp short MBRok &#9; notGRUB&#58;	cmp dword &#91;MBRreloc + 06h&#93;,&#39;LILO&#39;	; position of LILO &#9;jne short MBRok &#9;or &#91;newloc + uvstate&#93;,20h	; set bit 5 &#61; LILO MBRok&#58; &#59;&#32;reveal the disk signature in the MBR<span style="font-weight: normal" >&#58; stow info in signb1 to 4 &#9;pusha &#9;mov al,&#91;MBRreloc + dsignat&#93; &#9;call hex &#9;mov word &#91;newloc + signb1&#93;,ax &#9;mov al,&#91;MBRreloc + dsignat + 1&#93; &#9;call hex &#9;mov word &#91;newloc + signb2&#93;,ax &#9;mov al,&#91;MBRreloc + dsignat + 2&#93; &#9;call hex &#9;mov word &#91;newloc + signb3&#93;,ax &#9;mov al,&#91;MBRreloc + dsignat + 3&#93; &#9;call hex &#9;mov word &#91;newloc + signb4&#93;,ax &#9;popa &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; set the cursor to the u.l. corner and fill the screen &#59;&#32;with blanks on 25 or 50 lines according to bit 2 in uvstate &#59;&#32;References&#58; <span style="font-weight: normal" >&#59;&#32;http&#58;//home.earthlink.net/&#126;danrollins/techhelp/0117.HTM and 0124.HTM clearscr&#58; &#9;push cx &#59;&#32;set cursor at row 0, column 0 (upper left screen corner) &#9;mov ah,2 &#9;mov bh,0 &#9;xor dx,dx &#9;int 10h	; call BIOS - display characters &#59;&#32;fill the entire screen with blanks &#9;mov cx,4000	; repeat write char. 80 x 50 times &#9;test &#91;newloc + uvstate&#93;,04h	; &#9;jz short go50 &#9;mov ax,03h	; set text mode 80 x 25 lines <span style="font-weight: normal; color: #FF0000" > <span style="font-weight: normal" >&#9;xor bx,bx <span style="font-weight: normal; color: #FF0000" > <span style="font-weight: normal" >&#9;int 10h	; call BIOS &#9;mov cx,2000	; repeat write char. 80 x 25 times &#9;jmp short blkscr go50&#58;	mov ax,1112h	; set text mode 80 x 50 lines &#9;xor bx,bx <span style="font-weight: normal; color: #FF0000" > <span style="font-weight: normal" >&#9;int 10h	; call BIOS blkscr&#58;	mov ax,0920h	; write blank (20h) and attribute &#9;mov bx,0fh	; bright white &#9;int 10h	; call BIOS &#9;pop cx &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; inform of default boot pre-selection (16) &#59;&#32;memorizing the operating system started last <span style="font-weight: normal" >defaultsel&#58; &#9;cmp byte &#91;newloc + drivenbrs + 1&#93;,80h	; is it a hard disk ? &#59;&#32;if the boot disk drive (first in the list) was a FD, then nothing memorized &#9;jb short nopresel	; no preselection &#9;mov al,&#91;newloc + defaultd&#93; &#9;call hex	; convert to 2 hex characters &#9;mov &#91;newloc + dftdtext&#93;,ax	; stow away in text &#9;mov ax,&#91;newloc + defaultp&#93; &#9;mov &#91;newloc + dftptext&#93;,ax	; stow away in text &#9;mov cx,68	; (25) presel text length &#9;test &#91;newloc + memoriz&#93;, 01h	; (25) &#9;jnz short greepresel	; (25) &#9;call setred	; (25) &#9;call WILAstring	; (25) &#9;dw newloc + preselr	; (25) &#9;jmp short nopresel	; (25) greepresel&#58;	call setgreen	; (25) &#9;call WILAstring	; (25) &#9;dw newloc + preselg	; (25) nopresel&#58;	ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; set si for DSL (tested with DSL on 62MB USB-HDD) &#59;&#32;Find the address of the partition table entry containing the LBA value &#59;&#32;found in the lbalist <span style="font-weight: normal" >&#59;&#32;In bx&#58; pointer to LBA value where the OS starts setsiDSL&#58; &#9;mov ax,newloc + partab	; point to first entry &#59;&#9;mov ebx,&#91;bx-4&#93;	; point to lba in front of lbadesc &#59;&#9;cmp ebx,&#91;ax + 8&#93;	; lba found in partition table entry &#59;&#9;jne short setsiEND &#9;mov &#91;newloc + DSLsiVal&#93;,ax <span style="font-weight: normal" >setsiEND&#58;	ret DSLsiVal&#58;	dw 0	; si value for interface to DSL &#59;&#32;&#61;&#61;&#61;&#61;&#61; Transfer control from the current Boot Manager to a MBR in &#59;&#32;another volume (retrieve the saved MBR and relocate it in biosloc &#59;&#32;and behave as BIOS would)<span style="font-weight: normal" > swapMBR&#58;	mov si,MBRreloc	; (22) copy the memorized MBR &#9;mov di,biosloc	; (22) to the area where BIOS &#9;&#9;&#59;&#32;(22) would have loaded it normally &#9;mov cx,blocksize	; (22) set count &#9;rep movsb	; (22) copy MBR &#59;&#32;Attempt to pass control to MBR on volume 8xh after booting from 80h. &#59;&#32;Does not work, except with a Bluebottle MBR. &#59;&#32;Otherwise only successful when passing control to a foreign MBR on 80h. &#59;&#32;Was tested with GRUB and Ubuntu installed on a HDD, enumerated as 81h, while &#59;&#32;booting from USB-HDD thus enumerated as 80h. &#9;cmp dword &#91;biosloc + bbmid&#93;,&#39;BBM &#39;	; (22) is this a Bluebottle MBR? &#9;je short bluembr	; (22) this works always &#59;&#32;Pass control to a foreign MBR which must this time be on volume 80h &#9;cmp &#91;newloc + currdrive&#93;,80h	; (22) &#9;je short bluembr	; (22) this works &#59;&#32;boot volume does not have drive id as expected by MBR of installed OS &#9;call WILAstring &#9;dw newloc + wrongdid	; wrong drive id &#9;jmp word errinfo bluembr&#58;	call WILAstring	; (22) &#9;dw newloc + swap	; (22) &#9;call persistance	; (23) add msg persistance &#9;or byte &#91;biosloc + mbrinproc&#93;,80h	; &#59;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NOTE! &#62; biosloc	lock writing defaultd and defaultp &#9;mov dl,&#91;newloc + currdrive&#93;	; (22) get current drive number &#9;jmp 0&#58;biosloc	; (22) activate new MBR swap&#58;	db &#39;Switch MBR in 4"...&#39;,0	; (22) timed message recording&#58;	db CR,LF,&#39;Recording user selection&#39;,CR,LF,0	; (22) timed message ignoring&#58;	db CR,LF,&#39;Selection not recorded &#39; reason&#58;	db &#39;A&#39;,CR,LF,0	; (22) timed message MBRtxtlen&#58;	equ 11 BBMBR&#58;	db &#39;Bluebottle&#39;,0 FORMBR&#58;	db &#39;Foreign  &#39;,0 GRUBMBR&#58;	db &#39;GRUB      &#39;,0 LILOMBR&#58;	db &#39;LILO      &#39;,0 GAGMBR&#58;	db &#39;GAG       &#39;,0 &#59;&#32; &#59;&#32;LBA 7 <span style="font-weight: normal" > linuxtxt&#58;	db &#39;Linux   &#39;	; PBR with 8 x 0h at offset 3 notPBR&#58;	db &#39;no PBR  &#39;	; PBR with invalid signature vbeinfo&#58;	db CR,LF,LF,&#39;VESA modes&#58; WidthxHeightxDepth&#39;,CR,LF,0	; (3) dimen&#58;	db &#39; MB&#39; hyphen&#58;	db &#39; - &#39;,0 &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; inspect the graphic controller capabilities (3) <span style="font-weight: normal" >inspectvbe&#58; &#9;call WILAstring &#9;dw newloc + vendebx &#9;call WILAstring &#9;dw newloc + newline &#59;&#32;vesatab at es&#58;di - 1KB scratch segment for receiving the VBE &#59;&#9;controller information block located at the end of this program &#9;mov di,newloc + vesatab &#9;mov ax,4f00h	; return VBE controller information &#9;mov dword &#91;di&#93;,&#39;VBE2&#39;	; "VBE2" signature &#9;int 10h	; call BIOS &#9;cmp ax,004fh &#9;jne near endmode &#59;&#32;process the data returned in the buffer &#9;mov cl,&#91;di+4&#93;	; save value before overwriting it &#9;mov byte &#91;di+4&#93;,0	; now zero-terminated string at di &#9;mov si,di	; &#9;call writestring &#9;mov al,&#91;di+5&#93;	; first digit of version number &#9;or al,30h	; convert to decimal character &#9;call writechar &#9;mov al,&#39;.&#39;	; decimal point &#9;call writechar &#9;mov al,cl	; bring back 2nd digit &#9;or al,30h	; convert to decimal character &#9;call writechar &#9;mov al,&#39; &#39;	; space &#9;call writechar &#9;mov ax,&#91;di + 12h&#93;	; &#9;shr ax,4 &#9;call int2char4	; &#9;call WILAstring &#9;dw newloc + dimen &#59;&#32;trace VBE controller information (19 bytes of code) &#59;&#9;mov cx,0 &#59;&#9;push di &#59;nextsi&#58;	mov al,&#91;di&#93; &#59;&#9;inc di &#59;&#9;push cx &#59;&#9;call char2hex &#59;&#9;pop cx &#59;&#9;inc cx &#59;&#9;cmp cx,34h &#59;&#9;jb nextsi &#59;&#9;pop di &#59;&#32;As from VESA 2.0, additional information is returned. Some of it &#59;&#32;is displayed now &#9;mov al,&#91;di+5&#93;	; first digit of version number &#9;cmp al,2	; is it 2 ? &#9;jb short vesa1	; no, skip what appeared later &#9;push ds	; save before accessing the other ds &#9;mov si,&#91;di + 16h&#93;	; of vendor string &#9;mov ds,&#91;di + 18h&#93;	; ds of vendor string &#9;call writestring &#9;pop ds	; restore &#9;call WILAstring &#9;dw newloc + hyphen &#9;push ds	; save before accessing the other ds &#9;mov si,&#91;di + 1ah&#93;	; of product &#9;mov ds,&#91;di + 1ch&#93;	; ds of product &#9;call writestring &#9;pop ds	; restore &#9;call WILAstring &#9;dw newloc + crlf vesa1&#58;	push ds	; save before accessing the other ds &#9;mov si,&#91;di + 6h&#93;	; of OEM string &#9;mov ds,&#91;di + 8h&#93;	; ds of OEM &#9;call writestring &#9;pop ds	; restore &#9;call WILAstring &#9;dw newloc + vbeinfo &#59;&#32;extract all modes from the mode list and display their characteristics &#59;&#32;coloring is used to identify the modes suitable for Bluebottle. hasmodes&#58; &#9;push ds &#9;mov si,&#91;di + 0eh&#93;	; offset of mode list &#9;mov ds,&#91;di + 10h&#93;	; ds of mode list nxtmode&#58; &#9;mov al,&#91;si&#93;	; get first byte &#9;cmp al,0ffh	; is it an end of list marker ? &#9;je near endmode	; yes &#59;&#32;inspect mode and inform only about VBE mode for which LFB is available &#59;&#32;A color code is used to differentiate the modes of the graphic card&#58; &#59;&#9;green&#58; mode supported by BB &#59;&#9;white&#58; mode not supported &#59;&#9;yellow&#58; 15-bit depth mode not supported, but potentially suitable &#59;&#9;Requires a module modification. &#9;mov ax,4f01h	; return VBE mode information &#9;mov cx,&#91;si&#93;	; for this mode &#9;mov di,newloc + vesatab + blocksize	; another block for storing data &#9;int 10h	; call BIOS &#9;cmp ax,004fh	; is mode supported ? &#9;jne short skipmode	; no &#9;test byte &#91;es&#58;di&#93;,80h	; is video mode attribute LFB available &#9;jz short white	; not good for Bluebottle &#59;&#9;test byte &#91;es&#58;di&#93;,10h	; is video mode attribute graphic mode &#59;&#9;jz short white	; not good for bluebottle &#9;cmp byte &#91;es&#58;di + 19h&#93;,15	; 15 bits per pixel ? not yet supported &#9;jne short green	; yes, good for Bluebottle &#59;&#9;or byte &#91;newloc + lfbyes&#93;,80h	; at least one mode supports LFB &#9;call setyellow4	; not good for bluebottle &#59;&#32;NOTE&#58; currently, 15-bit modes are not supported but it would be rather easy &#59;&#32;to include them (as green) by modifying Displays.Mod &#9;jmp short white green&#58;	call setgreen4	; good for Bluebottle &#59;&#32;display the mode (1 blank and 3 hexadecimal characters) white&#58;	mov al,&#91;si + 1&#93; &#9;call hex &#9;xchg ah,al	; &#9;call writechar &#9;mov al,&#91;si&#93; &#9;call hex &#9;call writechar &#9;xchg ah,al	; &#9;call writechar &#9;mov al,&#39; &#39;	; terminate with a blank &#9;call writechar &#59;&#32;restore the program code data segment from the stack via ax &#9;pop ax &#9;push ds	; save the current ds containing &#9;&#9;&#59;&#32;the VBE mode information &#9;mov ds,ax &#9;mov ax,&#91;es&#58;di + 12h&#93;	; horizontal resolution in pixels &#9;call int2char4 &#9;mov ax,&#91;es&#58;di + 14h&#93;	; vertical resolution in pixels &#9;call int2char4 &#9;mov al,&#91;es&#58;di + 19h&#93;	; bits per pixel &#9;aam 0ah &#9;or ax,&#39;00&#39;	; make it zero ASCII-based &#9;xchg al,ah &#9;cmp al,&#39;0&#39;	; is first digit &#39;0&#39; ? &#9;jne short leaveit	; no &#9;mov al,&#39; &#39;	; suppress leading &#39;0&#39; leaveit&#58;	mov &#91;newloc + here&#93;,ax	; stow away in buffer &#9;push si &#9;call WILAstring	; display it &#9;dw newloc + here &#9;pop si &#59;&#32;restore the VBE mode info data segment from the stack via ax &#9;pop ax &#9;push ds	; save the program code data segment &#9;mov ds,ax skipmode&#58;	add si,byte 2	; position to next mode &#9;jmp word nxtmode	; repeat for next mode here&#58;	db 0,0,&#39;   &#39;,0 endmode&#58;	pop ds &#9;call WILAstring &#9;dw newloc + initinfo &#9;call readchar	; halt display output &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; convert 1 byte to two hexadecimal characters <span style="font-weight: normal" >&#59;&#32;in &#58; al &#61; byte to convert &#59;&#32;out&#58; al &#61; most significant ; ah &#61; least significant hex&#58; &#9;aam 10h	; ah &#58;&#61; al DIV 10h &#9;&#9;&#59;&#32;al &#58;&#61; al MOD 10h &#9;or ax,word &#39;00&#39;	; make it zero ASCII-based &#9;xchg ah,al	; exchange in view of output order &#9;cmp al,&#39;9&#39; &#9;jna short hexl	; &#60;&#61; 9 is alright &#9;add al,7	; &#62; 9 modified to &#39;A&#39; .. &#39;F&#39; hexl&#58;	cmp ah,&#39;9&#39; &#9;jna short hexh	; &#60;&#61; 9 is alright &#9;add ah,7	; &#62; 9 modified to &#39;A&#39; .. &#39;F&#39; hexh&#58;	ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; convert an integer to decimal 4-character string &#59;&#32;with 0-terminator, with suppression of leading zeros <span style="font-weight: normal" >&#59;&#32;in&#58; ax &#61; 16-bit value &#59;&#32;out&#58;    si pointer to most significant character of zero-delimited string int2char&#58; &#9;push ax	; correction&#58; extend ax to eax &#9;xor eax,eax &#9;pop ax &#9;mov cx,4	; max. number of digits to produce &#9;mov si,newloc + intval + 3 &#9;call convert &#9;ret intval&#58;	db 0,0,0,0,&#39;x&#39;,0	; 4 receiving pos, a &#39;x&#39; and a delimiter &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; convert a long integer to decimal character string &#59;&#32;with 0-terminator, with suppression of leading zeroes <span style="font-weight: normal" >&#59;&#32;in&#58; eax &#61; 32-bit value &#59;&#32;&#32;&#32;&#32;&#32;&#32;cx &#61; max. number of digits to produce &#59;&#32;&#32;&#32;&#32;&#32;&#32;si &#61; pointer to unit digit in result string &#59;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#9;further digits are added from right to left &#59;&#32;out&#58;    si pointer to most significant character of zero-delimited string convert&#58; &#9;mov ebx,10	; conversion base 10 convertdig&#58;	xor edx,edx	; extend eax to 64-bit edx&#58;eax &#9;div ebx	; eax &#60;- edx&#58;eax div ebx, edx &#60;- remainder &#9;or dl,&#39;0&#39;	; make it &#39;0&#39;+ ASCII-based &#9;mov &#91;si&#93;,dl	; stow away in buffer &#9;dec si	; place right to left in buffer &#9;loop convertdig	; loop on count in cx &#59;&#32;replace leading &#39;0&#39; by &#39; &#39; &#9;inc si convert0&#58;	cmp &#91;si&#93;,&#39;0&#39;	; is this digit &#39;0&#39; ? &#9;jne short convertexit	; no, keep it &#9;mov &#91;si&#93;,&#39; &#39;	; put a &#39; &#39; in there &#9;inc si	; address next digit &#9;jmp convert0	; repeat that convertexit&#58;	ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; convert an integer to a variable length string of decimal &#59;&#32;characters terminated with 0, suppressing the leading zeroes, &#59;&#32;and display it <span style="font-weight: normal" >&#59;&#32;in&#58; ax &#61; 16-bit value int2charv&#58; &#9;push si &#9;call int2char &#9;call writestring	; display it &#9;pop si &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; convert an integer to a string of 4 decimal characters &#59;&#32;terminated with &#39;x&#39; and 0, suppressing the leading zeroes, &#59;&#32;and display it <span style="font-weight: normal" >&#59;&#32;in&#58; ax &#61; 16-bit value int2char4&#58; &#9;push si &#9;call int2char &#9;call WILAstring	; display it &#9;dw newloc + intval	; position at the beginning &#9;pop si &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; convert a binary integer to a 4-hexadecimal ascii string &#59;&#32;not used here, but good to keep <span style="font-weight: normal" >&#59;&#32;in&#58; ax &#61; 16-bit value &#59;&#32;&#32;&#32;&#32;&#32;&#32;di &#61; pointer destination - 1st byte int2hex4&#58; &#9;pusha &#9;mov bx,10h	; conversion base is hex (15) &#9;mov cx,4	; number of characters &#9;add di,byte 3 int2hex4n&#58;	xor dx,dx	; extend ax to 32-bit dx&#58;ax &#9;div bx	; ax &#60;- dx&#58;ax div bx, dx &#60;- remainder &#9;cmp dl,10	; is dl &#60; 10 ? &#9;jb short int2hex4d	; yes, is to become a digit &#9;add dl,&#39;A&#39; - 10	; form a letter A .. F &#9;jmp short int2hex4l	; skip, it is a letter int2hex4d&#58;	or dl,&#39;0&#39;	; form a digit int2hex4l&#58;	mov &#91;di&#93;,dl	; stow away in buffer &#9;dec di	; place right to left in buffer &#9;loop int2hex4n	; loop on count in cx &#9;popa &#9;ret &#9;times 8*blocksize - ($-$$) db filler &#59;&#32; &#59;&#32;LBA 8 <span style="font-weight: normal" > &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; wait until an ASCII character is received from the keyboard <span style="font-weight: normal" >&#59;&#32;out &#58; al &#61; character readchar&#58; el0&#58;	mov ah,0	; wait for a keyboard event &#9;int 16h	; call BIOS &#9;cmp al,0	; is a scan code in ah ? &#9;je el0	; yes, ignore &#9;ret lfbyes&#58;	db 0	; at least one mode support LFB (T/F) uvstate&#58;	db 4	; 04h - bit 2 &#61; 25/50 lines &#9;&#9;&#59;&#32;10h - bit 4 on &#61; GAG &#9;&#9;&#59;&#32;20h - bit 5 on &#61; LILO &#9;&#9;&#59;&#32;40h - bit 6 on &#61; GRUB &#9;&#9;&#59;&#32;80h - bit 7 off &#61; BBM in MBR / on &#61; foreign memoriz&#58;	db 0	; (25) initinfo&#58;	db CR,LF,&#39;Set Init&#61; to a green mode val&#39; &#9;db &#39;ue and Boot&#61;DisplayLinear&#39;,CR,LF,LF invitretn&#58;	db &#39;Press any key to continue&#39;,CR,LF,0 &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; info about the partition type of the current entry <span style="font-weight: normal" >&#59;&#32;in &#58; si &#61; pointer to lba in entry info&#58; &#9;mov bp,si	; save entry pointer used in readblock <span style="font-weight: normal; color: #FF0000" >&#9;ret	; shortcut the remaining code &#59;&#32;trace code snippet, now deactivated (16 bytes) <span style="font-weight: normal" >&#9;mov dh,&#91;si-4&#93;	; partition type ptyp&#58;	mov al,dh &#59;&#32;in &#58; al &#61; byte to display as 2 hexadecimal digits char2hex&#58;	call hex &#9;call writechar &#9;xchg ah,al	; &#9;call writechar &#9;mov al,&#39; &#39; &#9;call writechar &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; add an lba value and partition type to the lbalist <span style="font-weight: normal" >&#59;&#32;the address of the next free slot is available in lbaslot &#59;&#32;in &#58; si&#58; partition table entry address &#59;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ebx&#58; LBA value addlba&#58; &#59;&#9;call readchar	; used to pause between detected partitions &#59;&#32;NOTE&#58; can be used to trace the progress through the partition table entries. &#9;mov cl,&#91;si - 4&#93;	; get partition type &#9;mov edx,&#91;si + 4&#93;	; (24) get partition size in blocks &#9;push si	; save partition table entry address &#9;mov si,word &#91;newloc + lbaslot&#93;	; next free slot address &#9;mov &#91;si&#93;,ebx	; save LBA in lbalist &#9;mov byte &#91;si + 16&#93;,cl	; save partition type &#9;mov dword &#91;si + 17&#93;,edx	; (24) save partition size &#9;pop si &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; restore the default text in the lbadesc table <span style="font-weight: normal" >restorelba&#58; &#9;mov bx,newloc + lbadesc nxtdft&#58;	mov si,newloc + dfttext	; &#9;mov di,bx	; &#9;add di,byte 3 &#9;mov cx,10	; dfttext length &#9;rep movsb	; restore text &#9;add bx, byte lbalen &#9;cmp bx,word &#91;newloc + lbaslot&#93; &#9;jb nxtdft &#59;&#32;finally, reset the lbaslot content to the first slot address &#9;mov word &#91;newloc + lbaslot&#93;,newloc + lbalist &#9;mov word &#91;newloc + locked&#93;,0	; none is locked &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; set the color attribute of 11 characters &#59;&#32;light red is used to warn when a partition is not bootable as is the case &#59;&#32;for an extende one or when the PBR has no signature signID <span style="font-weight: normal" >&#59;&#32;in &#58; pointer to string to display hilite&#58; &#9;cmp dword &#91;bx + 3&#93;,&#39;no P&#39;	; &#39;no PBR&#39; &#9;je short setred11 &#9;cmp dword &#91;bx + 3&#93;,&#39;&#124;no &#39;	; &#39;&#124;no PBR&#39; &#9;je short setred11 &#9;cmp dword &#91;bx + 3&#93;,&#39;Exte&#39;	; &#39;Extended&#39; &#9;jne short hiliteno setred11&#58;	mov cx,11	; string length setred&#58;	push bx	; user defined string length &#9;mov bx,0ch	; light red setattrib&#58;	mov ax,0920h	; write blank and attribute &#9;int 10h	; call BIOS - display characters &#9;pop bx hiliteno&#58;	ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; set the color attribute of 1 character <span style="font-weight: normal" >&#59;&#32;mod &#58; ax, cx setwhite&#58;	mov cx,1	; write 1 character &#9;push bx	; user defined string length &#9;mov bx,07h	; white &#9;jmp short setattrib &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; set the color attribute of 12 characters <span style="font-weight: normal" >&#59;&#32;mod &#58; ax, cx setblue23&#58;	mov cx,23 &#9;push bx	; user defined string length &#9;mov bx,1fh	; light blue &#9;jmp short setattrib &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; set the color attribute of 4 characters <span style="font-weight: normal" >&#59;&#32;mod &#58; ax, cx setgreen4&#58;	mov cx,4 setgreen&#58;	push bx	; user defined string length &#9;mov bx,0ah	; light green &#9;jmp short setattrib &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; set the color attribute of 4 characters <span style="font-weight: normal" >&#59;&#32;mod &#58; ax, cx setyellow4&#58;	mov cx,4 &#9;push bx	; user defined string length &#9;mov bx,0eh	; light yellow &#9;jmp short setattrib &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; inspect the PCI Bus (7) &#59;&#32;References&#58; &#59;&#32;PCI Bus Specifications - Intel<span style="font-weight: normal" > inspectpci&#58; &#59;&#32;PCI1 - Determine if a PCI BIOS is present &#9;mov ax,0b101h	; pci function id / pci bios present &#9;int 1ah	; call BIOS &#9;jc short nopci	; cf &#61; 1 means &#39;no BIOS present&#39; &#9;cmp edx,&#39;PCI &#39;	; edx &#60;&#62; &#39;PCI &#39; means &#39;no BIOS present&#39; &#9;jne short nopci	; &#9;or ah,ah &#9;jnz short nopci	; ah &#60;&#62; 0 means &#39;no BIOS present&#39; &#9;and al,3h	; extract hardware mechanism bits 0,1 &#9;or &#91;newloc + hwmech&#93;,al	; transform to decimal character &#9;mov al,bh	; &#9;or &#91;newloc + pciversion&#93;,al	; transform to decimal character &#9;mov al,bl	; &#9;shr al,4 &#9;or &#91;newloc + pciversion + 2&#93;,al	; transform to decimal character &#9;mov al,bl	; &#9;and al,0fh &#9;or &#91;newloc + pciversion + 3&#93;,al	; transform to decimal character &#9;mov &#91;newloc + lastbus&#93;,cl	; save number of last PCI bus &#9;call WILAstring &#9;dw newloc + equtitle &#59;&#32;PCI2 - Explore bus by bus until last bus in the system &#9;xor bx,bx	; 0 in bh &#38; bl nextbus&#58;	push bx &#9;call scanbus	; (15) &#9;pop bx &#9;inc bh &#9;cmp bh,&#91;newloc + lastbus&#93; &#9;jbe nextbus nopci&#58;	ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; scan the PCI bus (15) <span style="font-weight: normal" >&#59;&#32;Inspired from Bluebottle PCITools.Mod - ReadConfigDword &#59;&#32;bh &#61; bus number - range 0 .. 0ffh &#59;&#32;bl &#61; devfn - range 0 .. 0feh &#59;&#32;dh &#61; ismulti - dl &#61; devfn MOD 8 scanbus&#58; &#9;xor bl,bl	; 0 in devfn &#9;xor dx,dx	; clear nxtdevfn&#58;	cmp bl,0feh	; FOR devfn &#58;&#61; 0 TO 0feh DO &#9;jbe short trydevfn &#9;ret trydevfn&#58;	mov dl,bl &#9;and dl,7	; devfn MOD 8 &#9;cmp dl,0	; IF devfn MOD 8 &#61; 0 THEN &#9;je short okdevfn &#9;test dh,80h	; (dh) ODD(hdrtype DIV 80h) &#9;jz near gonext okdevfn&#58;	mov di,0eh	; hdrtype offset in al &#9;call readpcib &#9;cmp dl,0	; IF devfn MOD 8 &#61; 0 THEN &#9;jne short skiptest &#9;mov dh,al	; hdrtype in dh (prepare multi) skiptest&#58;	mov di,0	; vendor offset &#9;call readpciw	; load vendor in ax &#9;cmp ax,0ffffh	; IF vendor &#61; 0ffffh THEN skip &#9;je near gonext &#59;&#32;!!! from here on, bl, bh and dh must be left untouched until gonext&#58; is &#59;&#32;reached and execution returns to trydevfn&#58; and to line (dh) above &#59;&#32;dl is computed at each round &#9;mov &#91;newloc + venid&#93;,ax	; save vendor &#59;&#32;fill area with blanks - reset in preparation of collecting new infos &#9;mov si,newloc + devbus	; fill with blanks &#9;mov cx,devend - devbus	; # of blanks insertb&#58;	mov byte &#91;si&#93;,&#39; &#39; &#9;inc si &#9;loop insertb &#9;mov di,newloc + manid	; insert vendor in hex there &#9;call int2hex4 &#9;mov al,bh	; bus &#9;or al,&#39;0&#39;	; convert to decimal character &#9;mov byte &#91;newloc + devbus&#93;,al	; stow away in text &#9;mov al,bl	; device &#38; function &#9;shr al,3	; device &#9;call hex	; convert to 2 hex characters &#9;mov &#91;newloc + devno&#93;,ax	; stow away in text &#9;mov al,bl &#9;and al,7	; extract function (3 LSB) &#9;or al,&#39;0&#39;	; convert to decimal character &#9;mov &#91;newloc + devfunno&#93;,al	; stow away in text &#59;&#32;get the device but do not search it. It cannot be found anyway. &#9;mov di,2	; offset to device &#9;call readpciw	; load device in ax &#9;mov di,newloc + devid	; insert device in hex there &#9;call int2hex4 &#9;mov ax,&#91;newloc + venid&#93;	; retrieve vendor &#59;&#32;get the device class and subclass &#9;mov di,0ah	; offset to class &#9;call readpciw	; load class and subclass in ax &#9;call movedescr &#59;&#32;discriminate the device classes &#59;&#32;CASE &#39;0ch&#39; <span style="font-weight: normal" >&#59;&#32;discriminate the various serial bus types 00, 03, 05 serialbus&#58;	cmp ah,0ch	; is serial bus controller ? &#9;jne short notserb	; &#9;push ax &#9;mov si,newloc + serialdesc &#9;call movesubd &#9;pop ax notsmbus&#58;	cmp al,03h	; is USB controller ? &#9;je short moreusb &#9;jmp word classdone moreusb&#58;	push dx &#59;&#32;get USB Specification release &#9;mov di,60h	; offset to read USB Spec. release &#9;call readpcib	; read byte &#9;call hex &#9;mov &#91;newloc + devrel&#93;,al	; stow away in text &#9;mov byte &#91;newloc + devdot&#93;,&#39;.&#39;	; stow away in text &#9;mov &#91;newloc + devrelsub&#93;,ah	; stow away in text &#59;&#32;get the device Programming Interface &#9;mov di,09h	; offset to PI &#9;call readpcib	; load PI in ax &#59;&#32;process the base address &#9;mov di,20h	; offset to base address &#9;call readpciw	; read word in ax &#9;and ax,0fffeh	; clear bit 0 &#9;mov &#91;newloc + ioadd&#93;,ax	; save IOaddr for later &#9;mov dx,&#91;newloc + ioadd&#93;	; &#9;add dx,byte 10h	; USB port 1 register (base + 10h) &#9;mov di,newloc + devport1 &#9;call getport &#9;add dx,byte 02h	; USB port 2 register (base + 12h) &#9;mov di,newloc + devport2 &#9;call getport &#9;pop dx &#9;jmp classdone &#59;&#9;times 9*blocksize - ($-$$) db filler &#59;&#32; &#59;&#32;LBA 9 - PCI information collection (15) <span style="font-weight: normal" > &#59;&#32;CASE &#39;01h&#39; <span style="font-weight: normal" >&#9;cmp ah,01h	; is mass storage controller ? &#9;jne short serialbus &#9;mov si,newloc + massdesc &#9;call movesubd &#9;jmp word classdone &#59;&#32;CASE &#39;02h&#39; <span style="font-weight: normal" >notserb&#58;	cmp ah,02h	; is network controller ? &#9;jne short displayc &#9;mov si,newloc + netwdesc &#9;call movesubd &#9;jmp classdone &#59;&#32;CASE &#39;03h&#39; <span style="font-weight: normal" >displayc&#58;	cmp ah,03h	; is display controller ? &#9;jne short mmedia &#9;mov si,newloc + dispdesc &#9;call movesubd &#9;jmp short classdone &#59;&#32;CASE &#39;04h&#39; <span style="font-weight: normal" >mmedia&#58;	cmp ah,04h	; is multimedia ? &#9;jne short bridge &#9;mov si,newloc + mediadesc &#9;call movesubd &#9;jmp short classdone &#59;&#32;CASE &#39;06h&#39; <span style="font-weight: normal" >&#59;&#32;discriminate the various bridge bridge&#58;	cmp ah,06h	; is bridge ? &#9;jne short classdone &#9;cmp al,04h	; is PCI bridge ? &#9;jne short notPCIb &#9;mov byte &#91;newloc + ht&#93;,1 notPCIb&#58;	mov si,newloc + bridgdesc &#9;call movesubd &#59;&#32;ENDCASE<span style="font-weight: normal" > classdone&#58;	call WILAstring &#9;dw newloc + devdesc &#9;mov ah,dh	; hdrtype &#9;and ah,7fh	; hdrtype MOD 80h &#9;cmp byte &#91;newloc + ht&#93;,ah &#9;jne short gonext &#9;mov di,1ah	; offset to buses + 2 &#9;call readpcib	; read byte in ah &#9;cmp ah,0	; &#9;je short gonext	; yes &#9;mov di,18h	; offset to buses &#9;call readpciw	; read word in ax &#9;cmp ax,0 &#9;je short gonext &#9;pusha &#9;mov bh,ah &#9;call scanbus &#9;popa gonext&#58;	inc bl &#9;jmp word nxtdevfn &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; move class description to info line <span style="font-weight: normal" >movedescr&#58;	push ax &#9;mov si,newloc + classdesc movenextr&#58;	sub ah,1 &#9;cmp ah,0 &#9;je short moveendc &#9;add si,word classlen &#9;jmp short movenextr moveendc&#58;	mov di,newloc + devclass &#9;mov cx,word classlen &#9;rep movsb &#9;pop ax &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; move subclass description to info line <span style="font-weight: normal" >movesubd&#58;	cmp al,80h &#9;je short move80 movenexts&#58;	cmp al,0 &#9;je short moveends &#9;add si,word subclasslen &#9;sub al,1 &#9;jmp short movenexts move80&#58;	mov si,newloc + subcother &#9;jmp short movevalid moveends&#58;	cmp byte &#91;si&#93;,byte 0ffh &#9;jne short movevalid &#9;mov si,newloc + subcinval movevalid&#58;	mov di,newloc + devsubclass &#9;mov cx,word subclasslen &#9;rep movsb &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; read a word <span style="font-weight: normal" >&#59;&#32;in&#58; bh,bl &#59;&#32;&#32;&#32;&#32;&#32;&#32;di &#61; word offset &#59;&#32;out&#58; ax &#61; word read (transfered from cx) readpciw&#58; &#9;mov ax,0b109h	; read word readpci&#58;	int 1ah	; &#9;mov ax,cx &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; read a byte <span style="font-weight: normal" >&#59;&#32;in&#58; bh,bl &#59;&#32;&#32;&#32;&#32;&#32;&#32;di &#61; byte offset &#59;&#32;out&#58; al &#61; byte read (transfered from cx) readpcib&#58; &#9;mov ax,0b108h	; read byte &#9;jmp readpci &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; get information on attached device(s) <span style="font-weight: normal" >&#59;&#32;in&#58; dx &#61; IO base address &#59;&#32;out&#58; ax &#61; port status/control register contents getport&#58; &#9;in ax,dx &#9;and ax,0105h	; bit 8 &#61; 1 &#58; suspended, bit 2 &#61; 1 &#58; enabled &#9;cmp ax,0005h	; bit 0 &#61; 1 &#58; device present &#9;je short getportp	; device present &#9;mov byte &#91;di&#93;,&#39;_&#39; &#9;jmp short getporta	; device absent getportp&#58;	mov byte &#91;di&#93;,&#39;*&#39; getporta&#58;	ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; write a string specified by in-line address <span style="font-weight: normal" >&#59;&#9;call WILAstring &#59;&#9;dw newloc + fieldname &#59;&#32;Saves one byte per instruction pair (frequently used) &#59;<span style="font-weight: normal" >&#9;mov si,newloc + fieldname &#59;<span style="font-weight: normal" >&#9;call writestring <span style="font-weight: normal" >WILAstring&#58; &#9;push bp	; save bp (the caller might be using it) &#9;mov bp,sp	; bp now used to access the stack &#9;mov si,&#91;bp + 2&#93;	; get old IP (return address) &#9;mov si,&#91;si&#93;	; get word after call instruction &#9;call writestring &#9;add word &#91;bp + 2&#93;, byte 2	; return addres is 2 bytes further &#9;pop bp	; restore &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; extract the current drive number given its index <span style="font-weight: normal" >&#59;&#32;in &#58; cl &#61; drive index &#59;&#32;out &#58; dl &#61; drive number <span style="font-weight: normal" >getdrvno&#58; &#9;mov al,cl &#9;cbw &#9;add ax,newloc + drivenbrs	; &#9;mov si,ax &#9;mov dl,&#91;si&#93; &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; announce start of selected OS <span style="font-weight: normal" >announce&#58;		; (20) &#59;&#32;insert the volume number in a readable form in the msg text &#59;&#32;the partition number is already in the text in readable form &#9;pusha <span style="font-weight: normal; color: #AA0000" >&#9; <span style="font-weight: normal" >call hex &#9;mov &#91;newloc + drvcharh&#93;,al &#9;xchg ah,al	; &#9;mov &#91;newloc + drvcharl&#93;,al &#9;call WILAstring &#9;dw newloc + launchos &#9;popa &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; add some persistance to a text line (23) <span style="font-weight: normal" >&#59;&#32;let the message appear for a few seconds, approx. 4" persistance&#58; &#9;pusha &#9;xor ah,ah	; get tick count &#9;int 1ah	; call BIOS - timer service in dx &#9;mov bx,dx	; save RTC &#9;add bx,byte 70	; add 70 ticks x 55 ms &#61; 3850 ms waittim&#58;	xor ah,ah	; get tick count &#9;int 1ah	; call BIOS - timer service &#9;cmp dx,bx	; is tick count &#62;&#61; limit saved in cx &#9;jb waittim	; wait time not expired &#9;popa &#9;ret &#59;&#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; collect as much drive interface information as possible &#59;&#32;depending on how much data was returned by BIOS in dpbuffer <span style="font-weight: normal" >interfinfo&#58; &#9;mov si,newloc + dpbuffer	; extra-muros buffer &#9;cmp word &#91;si&#93;,byte 30	; (13) 30 or less bytes received ? &#9;jbe exitIF	; (13) yes, very little info available &#9;mov di,&#91;newloc + driveslot&#93;	; (13)  &#9;add di,word 84	; (13) destination is next line element &#9;cmp word &#91;newloc + interftype&#93;,&#39;AT&#39;	; (13) test ATA or ATAPI &#9;jne short notATA	; (13) &#9;mov dword &#91;di&#93;,&#39;IDE &#39; &#9;cmp word &#91;newloc + key&#93;,0beddh	; device path info available ? &#9;jne short exitIF	; no interface info &#9;cmp byte &#91;newloc + primary&#93;,0	; (13) &#9;je short isprim	; (13) &#9;mov byte &#91;di + 3&#93;,&#39;2&#39;	; (13) &#9;jmp short tstmaster	; (13) isprim&#58;	mov byte &#91;di + 3&#93;,&#39;0&#39;	; (13) tstmaster&#58;	cmp byte &#91;newloc + master&#93;,0	; (13) &#9;je short exitIF	; (13) &#9;add byte &#91;di + 3&#93;,01h	; (13) &#9;jmp short exitIF	; (13) notATA&#58;	cmp word &#91;newloc + interftype&#93;,&#39;US&#39;	; (13) test USB &#9;jne short exitIF	; (13) &#9;mov dword &#91;di&#93;,&#39;USB &#39;	; (13) exitIF&#58;	ret	; &#59; &#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; display CPU info extracted with CPUID (21) &#59;&#32;Should be applicable to CPUs of&#58; &#59;&#9;Intel Corp. - Vendor ID 8086h &#59;&#9;AMD - Vendor ID 1022h &#59;&#9;Via (formerly UDT/Centaur) - Vendor ID 1106h &#59;&#32;Could be applicable to Transmeta - not tested &#59;&#32;The CPUID instruction is not known by this assembler &#59;&#32;hence machine code is used instead &#59;&#32;Executed only once when the MBR of a volume is executed <span style="font-weight: normal" >CPUID&#58;	equ 0a20fh	; machine hard code cpuinfo&#58; &#59;&#32;References&#58; <span style="font-weight: normal" >&#59;&#32;Intel&#58; How to determine whether a processor supports &#59;&#9;hyper-threading &#59;&#32;Detecting Multi-Core Processors &#59;&#32;softwarecommunity.intel.com/Wiki/Processorfeaturedetection/63.htm &#59;&#32;6/17/2007 &#59;&#32;Advanced Micro Devices - CPUID Specification Rev. 2.18 Jan. 2006 &#59;&#32;CPUID - Determine if the CPUID instruction is supported &#59;&#32;by checking ability to set/clear ID flag (bit 21) in EFLAGS &#59;&#32;http&#58;//www.delphigl.com/forum/viewtopic.php?t&#61;4621 &#59;&#32;google&#58; test eflags &#9;pushfd	; EFLAGS on stack &#9;pop eax	; copy EFLAGS to eax &#9;mov ebx,eax	; save a copy &#9;xor eax, 00200000h	; flip ID bit 21 in EFLAGS &#9;push eax	; new value on stack &#9;popfd	; new value in EFLAGS &#9;pushfd	; EFLAGS on stack &#9;pop eax	; copy EFLAGS in eax &#9;cmp eax, ebx	; compare to see if toggled &#9;jnz short cpuidyes	; jmp if value changed &#59;&#32;CPUID not supported, one should check for Cyrix family but don&#39;t and &#59;&#32;assume "classic" Intel &#9;mov si,newloc + cpuidno &#9;mov di,newloc + vendebx &#9;mov cx,33 &#9;rep movsb &#9;ret &#59;&#32;CPUID - Get vendor string and stow in text cpuidyes&#58;	xor eax,eax	; clear &#9;dw CPUID	; machine code &#9;mov &#91;newloc + vendebx&#93;,ebx &#9;mov &#91;newloc + vendecx&#93;,ecx &#9;mov &#91;newloc + vendedx&#93;,edx &#59;&#32;CPUID - Determine family, model, stepping &#9;mov eax,1 &#9;dw CPUID	; machine code &#59;&#32;4 instructions suppressed - Stepping value not important &#59;&#9;mov ecx,eax	; save &#59;&#9;call hex &#59;&#9;mov &#91;newloc + cpus&#93;,ah	; stepping &#59;&#9;mov eax,ecx	; restore &#9;shr eax,4 &#9;call hex &#9;mov &#91;newloc + cpuf&#93;,al	; family &#9;mov &#91;newloc + cpum&#93;,ah	; model &#59;&#32;CPUID - Determine if deterministic cache parameters supported &#9;xor eax,eax	; clear &#9;dw CPUID	; machine code &#9;cmp ax,4	; supported ? &#9;jl short getHT	; not supported, assume single-core &#59;&#32;CPUID - Read deterministic cache parameters and validate &#9;mov eax,4 &#9;mov ecx,0 &#9;dw CPUID	; machine code &#9;push eax &#9;and al,1fh	; valid cache parameters read ? &#9;cmp al,00h	; eax&#91;4&#58;0&#93; &#61; 0 indicates invalid &#9;pop eax &#9;je short getBrand &#9;shr eax,14 &#59;&#9;add ax,31h	; add 1 and convert to printable digit &#59;&#9;mov &#91;newloc + logipack&#93;,al	; logical processors sharing a cache &#9;shr eax,12	; # of processor cores on this package/die &#9;add ax,31h	; add 1 and convert to printable digit &#9;mov &#91;newloc + phycores&#93;,al &#59;&#32;CPUID - Determine hyperthreading when not MCP - Multi-Core &#59;&#32;NOTE&#58; this only to assert that a physical package is capable of hardware HT. &#59;&#32;It does no imply that HT is enabled. getHT&#58;	mov eax,1 &#9;dw CPUID	; machine code &#9;shr ebx,16 &#59;&#32;If an IA-32 processor does not have HW HT support, &#59;&#32;the value in ebx&#91;23&#58;16&#93; is reserved &#59;&#32;bl &#61; max. number of logical processors in a physical package &#59;&#32;bh &#61; APIC ID &#9;test edx,010000000h	; hyper-threading bit 28 &#9;jz short getBrand &#9;mov byte &#91;newloc + HTind&#93;,&#39;Y&#39;	; replace &#39;N&#39; by &#39;Y&#39; &#9;or bl,30h	; convert to printable digit &#9;mov &#91;newloc + logiprocs&#93;,bl	; stow in text &#59;&#32;CODE LIMITATION&#58; max. 8 logical processors &#59;&#9;mov al,bh	; APIC ID &#59;&#9;call hex	; convert to 2 hex characters &#59;&#9;mov &#91;newloc + cpuapic&#93;, ax	; stow away in text &#59;&#32;CPUID - Obtain the Processor Brand string if supported getBrand&#58;	mov eax,80000002h &#9;dw CPUID	; machine code &#9;cmp eax,byte 0	; eax &#61; 0 &#58; no brand string &#9;jz short nobrand &#9;mov di,newloc + brand &#9;call mov16char &#9;mov eax,80000003h &#9;dw CPUID	; machine code &#9;call mov16char &#9;mov eax,80000004h &#9;dw CPUID	; machine code &#9;call mov16char &#59;&#32;CPUID - Determine width nobrand&#58;	mov eax,80000000h &#9;dw CPUID	; machine code &#9;and eax,byte 0fh	; &#9;cmp eax,byte 0	; &#9;je short not64 &#9;mov eax,80000001h &#9;dw CPUID	; machine code &#9;test edx,20000000h	; long mode 64-bit bit 29 &#9;jz short not64 &#9;mov word &#91;newloc + cpuwidth&#93;,&#39;64&#39; not64&#58;	ret &#59; &#32;&#61;&#61;&#61;&#61;&#61; procedure&#58; move 16 characters from 4 registers <span style="font-weight: normal" >mov16char&#58; &#9;mov &#91;di&#93;,eax &#9;mov &#91;di + 4&#93;,ebx &#9;mov &#91;di + 8&#93;,ecx &#9;mov &#91;di + 12&#93;,edx &#9;add di,16 &#9;ret &#59;&#32;TUI title line prompt&#58;	db &#39;Boot Manager &#39; pdate&#58;	db &#39;??/??/???? - &#39;,0	; transferred from LBA 0 &#59;&#32;Information repository for cpuid instructions &#59;&#32;LINE 1 &#59;&#32;NOTE the register order&#58; ebx, edx, ecx!!! vendebx&#58;	dd 0 vendedx&#58;	dd 0 vendecx&#58;	dd 0 brand&#58;	times 48 db &#39; &#39;	; 3 * 16 char fixed &#59;&#32;The brand string ends with 0h, thus a newline is needed &#59;&#32;LINE 2 newline&#58;	db CR,LF cpuwidth&#58;	db &#39;32&#39;	; 32 or 64 &#9;db &#39;-bit processor Family 0&#39; cpuf&#58;	db &#39;?&#39; &#9;db &#39;h Model 0&#39; cpum&#58;	db &#39;?&#39; &#59;&#9;db &#39;h Stepping 0&#39; &#59;cpus&#58;	db &#39;?&#39; &#9;db &#39;h Cores&#58; &#39; phycores&#58;	db &#39;1&#39;	; # of cores in a physical package &#9;db &#39; Logicals&#58; &#39; logiprocs&#58;	db &#39;1&#39; &#59;&#32;max. # of logical processors in a physical package &#61; HW capability of the &#59;&#32;processor as manufactured and does not necessarily equate to the # of &#59;&#32;logical processors enabled by the platform BIOS or operating system. &#59;&#9;db &#39; LPSh&#58; &#39; &#59;logipack&#58;	db &#39;1&#39;	; # of logical processors sharing a cache &#9;db &#39; HT&#58; &#39; HTind&#58;	db &#39;N&#39;	; hyper-threading capable &#39;Y&#39; / &#39;N&#39; &#59;&#9;db &#39; APIC &#39; &#59;cpuapic&#58;	db &#39;**&#39; &#9;db CR,LF,LF,0 cpuidno&#58;	db &#39;not supported, classic Intel/AMD&#39;,0	; to be moved to vendebx &#59;&#32;adapted from PCI SIG Class Code Table - www.pcisig.com classlen&#58;	equ 15	; 15-character entry classdesc&#58;	db &#39;Mass Stor. Ctrl&#39; &#9;db &#39;Network   Ctrl&#39; &#9;db &#39;Display   Ctrl&#39; &#9;db &#39;Multimed Device&#39; &#9;db &#39;Memory    Ctrl&#39; &#9;db &#39;Bridge  Device&#39; &#9;db &#39;Communic. Ctrl&#39; &#9;db &#39;Base peripheral&#39; &#9;db &#39;Input   Device&#39; &#9;db &#39;Docking Station&#39; &#9;db &#39;Processor     &#39; &#9;db &#39;Serial bus Ctrl&#39; subclasslen&#58;	equ 8	; 8-character entry massdesc&#58;	db &#39;SCSI   &#39; &#9;db &#39;IDE    &#39; &#9;db &#39;Floppy &#39; &#9;db 0ffh netwdesc&#58;	db &#39;Ethernet&#39; &#9;db 0ffh dispdesc&#58;	db &#39;VGA comp&#39; &#9;db &#39;XGA    &#39; &#9;db 0ffh mediadesc&#58;	db &#39;Video  &#39; &#9;db &#39;Audio  &#39; &#9;db &#39;Telephon&#39; &#9;db &#39;Audio  &#39; &#9;db 0ffh bridgdesc&#58;	db &#39;Host/PCI&#39; &#9;db &#39;PCI/ISA &#39; &#9;db &#39;PCI/EISA&#39; &#9;db &#39;PCI/MIC &#39; &#9;db &#39;PCI/PCI &#39; &#9;db &#39;PCI/PCMC&#39; &#9;db &#39;PCI/NuBu&#39; &#9;db &#39;PCI/Card&#39; &#9;db 0ffh serialdesc&#58;	db &#39;Firewire&#39; &#9;db &#39;ACCESS &#39; &#9;db &#39;SSArchit&#39; &#9;db &#39;USB    &#39; &#9;db &#39;???? &#39; &#9;db &#39;SMBus  &#39; &#9;db 0ffh subcinval&#58;	db &#39; unknown&#39; subcother&#58;	db &#39;  other&#39; &#59;&#32;References&#58; &#59;&#32;&#32;USB in DOS - "http&#58;//www.cybertrails.com/&#126;fys/usb.htm" &#59;&#32;&#32;UHCI Design Guide - Revision 1.1 - Intel &#59;&#32;&#32;&#32;"ftp&#58;//download.intel.com/design/usb/uhci11d.pdf" &#59;&#32;&#32;http&#58;//www.beyondlogic.org/usbnutshell/ <span style="font-weight: normal" > devindex&#58;	db 3fh,3fh venid&#58;	dw 0 ioadd&#58;	dw 0 ht&#58;	db 0 lastbus&#58;	db 0 &#59;&#32;PC equipment information title equtitle&#58;	db &#39;PC equipment - PCI version &#39; pciversion&#58;	db &#39;0.00&#39; &#9;db &#39; HW mechanism &#39; hwmech&#58;	db &#39;0&#39;,CR,LF,LF &#9;db &#39;Bus Dev Fun Ven. Dev. Class          Subclass Rel P1 P2&#39;,CR,LF,0 &#59;&#32;one line of device description (equivalent to PCITools.Scan) devdesc&#58;	db &#39; &#39; devbus&#58;	db &#39;?&#39; &#9;db &#39; &#39; devno&#58;	db &#39;??&#39; &#9;db &#39;  &#39; devfunno&#58;	db &#39;?&#39; &#9;db &#39; &#39; manid&#58;	db &#39;????&#39; &#9;db &#39; &#39; devid&#58;	db &#39;????&#39; &#9;db &#39; &#39; devclass&#58;	times classlen db &#39;?&#39; &#9;db &#39; &#39; devsubclass&#58;	times subclasslen db &#39;?&#39; &#9;db &#39; &#39; devrel&#58;	db &#39;?&#39; devdot&#58;	db &#39;.&#39; devrelsub&#58;	db &#39;?&#39; &#9;db &#39; &#39; devport1&#58;	db &#39;?&#39; &#9;db &#39; &#39; devport2&#58;	db &#39;?&#39; devend&#58;	db CR,LF,0 &#9;times 12*blocksize - ($-$$) db filler &#59;&#32; &#59;&#32;LBA 12 - Data areas holding information for the next system boot <span style="font-weight: normal" >&#59;&#32;CAUTION! This area might be occupied by a GRUB boot manager. &#59;&#32;Beware of a programming error in this Boot Manager when &#59;&#32;deciding to record this block by a call writeblock just &#59;&#32;before reading and transferring control to the PBR. &#59;&#32;defaultd &#38; defaultp contain the number of the drive and of the partitition &#59;&#32;selected last. &#59;&#32;When defaultd is zero (no default yet set), the user is prompted &#59;&#32;to enter values which will then become the defaults. &#59;&#32;Otherwise, prompting must be forced by the user. &#59;&#32;message issued when starting immediately the default OS designated &#59;&#32;by defaultd and defaultp launchos&#58;	db &#39;Starting OS on volume &#39; drvcharh&#58;	db &#39;?&#39; drvcharl&#58;	db &#39;?&#39; &#9;db &#39; partition &#39; &#59;&#32;Partition number to boot by default without user interaction&#58; &#59;&#32;"01", "02" ..., the same as used by Bluebottle for numbering partitions defaultp&#58;	db &#39;??&#39; &#9;db &#39; in 4"...&#39;,0	; 4" seconds delay &#59;&#32;Default volume number hosting the partition to boot&#58; &#59;&#32;80h, 81h ... for hard disks (internal or external) &#59;&#32;value 0 means that no default was set, the boot menu is displayed. defaultd&#58;	db 0 selectinit&#58;	db 10,&#39;Enter one of the following&#58;&#39;,CR,LF &#9;db &#39; the number of a partition hosting an OS to start (red &#61; no OS detected)&#39;,CR,LF &#9;db &#39;     Set ScrollLock to halt AOS start-up.&#39;,CR,LF,0 &#59;&#32;drive list save area - 8 x 10 bytes prevdlen&#58;	equ 10 prevdlist&#58;	db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;db &#39;         &#39; &#9;times 13*blocksize - ($-$$) db filler &#59;&#32; &#59;&#32;Extra-muros buffer (placed in memory after the previous block) &#59;&#32;to contain the drive parameters information (8) <span style="font-weight: normal" >&#59;&#32;Experience shows that at most 30 bytes (1eh) are returned by the BIOS call, &#59;&#32;instead of the documented 74 bytes, even when modern hardware is present &#9;&#9;&#59;&#32;(offset decimal) dpbuffer&#58;	dw 74	; (0) buffer length / size of returned data infflags&#58;	dw 0	; (2) information flags &#9;dd 0	; (4) number of physical cylinders &#9;dd 0	; (8) number of physical heads sectptr&#58;	dd 0	; (12) number of physical blocks per track sectnumb&#58;	dd 0,0	; (16) number of physical blocks quadword &#9;dw 0	; (24) number of bytes per block dpteoff&#58;	dw 0	; (26) pointer to DPTE seg&#58;offset dpteseg&#58;	dw 0 key&#58;	dw 0	; (30) key &#9;db 0,0,0,0	; (32) length of device path information bus&#58;	db 0,0,0,0	; (36) host bus type (ASCII) interftype&#58;	dd 0,0	; (40) interface type (ASCII&#58; ATA, ATAPI, SCSI ..) interfpath&#58;	dd 0,0	; (48) interface path &#9;&#9;&#59;&#32;(56) device path - 16 bytes master&#58;	db 0ffh	; 0 &#61; master, 1 &#61; slave primary&#58;	db 0ffh,0,0	; 0 &#61; primary, 1 &#61; secondary channel &#9;dd 0,0,0 &#9;db 0,0,0,0	; (72) &#9;dd 0,0,0,0	; (76) free space to adjust &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0 drivelistul&#58;	dd 0,0,0,0	; drivelist underline showing current drive &#9;dd 0,0,0,0	; 1 * 80-position screen line as sequence &#9;dd 0,0,0,0	; of spaces terminated with marks &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#9;dd 0,0,0,0 &#59;&#9;times 14*blocksize - ($-$$) db filler &#59;&#32; &#59;&#32;Extra-muros buffer (placed in memory after the previous block) &#59;&#32;to contain the VBE Controller Information (3) <span style="font-weight: normal" >&#59;&#32;obtained with a int 10h BIOS call, function 4f00h (see inspectvbe) &#59;&#32;512-byte information block vesatab&#58;	db &#39;VBE2&#39;	; 00 - VBE2.0 information request vbevers&#58;	dw 0	; 04 oemptr&#58;	dd 0	; 06 - pointer to OEM info capab&#58;	db 0,0,0,0	; 0a modeptr&#58;	dd 0	; 0e totalmem&#58;	dw 0	; 12 &#59;&#32;added for VBE 2.0 software&#58;	dw 0	; 14 - VBE implementation software rev. vendptr&#58;	dd 0	; 16 - pointer to OEM vendor name prodptr&#58;	dd 0	; 1a - pointer to OEM product name revision&#58;	dd 0	; 1e - pointer to OEM product revision &#59;&#32;The buffer at address newloc + vesatab + blocksize is used &#59;&#32;to store VBE mode information (3) &#59;&#32;and disk information