text:
Oberon/BootManager.Asm

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

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

title: Oberon/BootManager.Asm


text:
User talk:Choudharydeep420

Deep Choudhury Is The best web developer And village baghana kotkasim alwar. It address is the deep's address

title: User talk:Choudharydeep420