; SMBNEW.ASM
; modified version of
; smbmbr.asm  Small Multi-Boot Master-Boot-Record
; see  http://www.execpc.com/~geezer/johnfine/
; New  provisional personal version on 3/3/2002
; I have only changed some lines in the original John S. Fine's version 
;
; Modifications to the version 3.0 ( ** indicate the main modifications) :
;  Can boot on a partition above the 8 Go limit (use int 13h extended 42 read)
;  Is compatible with Windows XP (disk signature in the MBR)
;
;  Only four choices:
;   Type 1 to boot on the first partition, 
;   Type 2 to boot on the second partition, 
;   Type 3 to boot on the third partition 
;   Type 4 to boot on the fourth partition
;   If no entry : boot on the last partition used
;
; Cannot boot on extended partition
; The boot disk must be chosen in the bios
; Before to boot on a floppy (or CD ROM), boot before on the disk partition which must be active
;  (even if not yet bootable : it is only to activate this partition in the MBR)
; At boot are displayed:
;	-the last partition used (To boot on another partition enter the partition number)
;	-"SMBMBR" (If you have several disks it is recommended to replace "SMBMBR" 
;		by the name of the disk.  This can be done directly in the file smbnew.bin 
;		without compiling and linking)
;	-a beep is emitted to ask for a key
;	-the partition effectively booted  (or error messages)
; Error messages:
;  "1 2 3 or 4 only " : you have entered a key which is not 1 2 3 or 4 try again
;  "no partition " the key is accepted but no partition exists on the disk for this key, try again
;  "disk error" : cannot read or write the disk
;  other messages are from the bios or from the booted partition.
; 
; smbnew.bin compiled with nasm16 version 0.98 and linked with JLOC version 0.6
;  Georges Jullien    ___gljullien@numericable.fr___
;_____________________________________________________________________________
; Original comments for the version 3.0 by John S. Fine : 
;_________quote begin___________
; smbmbr.asm  Small Multi-Boot Master-Boot-Record
; Version 3.0, Dec 17, 1997
; Sample code
; by John S. Fine  johnfine@erols.com
; I do not place any restrictions on your use of this source code
; I do not provide any warranty of the correctness of this source code
;
;  See detailed documentation in smbmbr.txt
;  See memory layout in smbmbr.lnk
;
;  To build:
;
;  NASM -f obj smbmbr.asm
;  JLOC smbmbr.lnk smbmbr.bin smbmbr.map
;
;  (I used NASM version 0.97 and JLOC version 0.3 in testing)
;___________quote end______________________________________


struc	PT_ENT		;Partition table entry
BootFlag	resb	1
BeginHead       resb	1
BeginSector     resb	1
BeginCyl        resb	1
SystemID        resb	1
EndHead         resb	1
EndSector       resb	1
EndCyl          resb	1
RelSectorLow    resw	1
RelSectorHigh   resw	1
NumSectorsLow   resw	1
NumSectorsHigh  resw	1
	endstruc

	struc	CHOICE		;Choice table entry
drive		resb	1
letter		resb	1
	endstruc

	extern	reloc_start	;.LNK file defines relocation address (0:7A00)

tick	equ	0x46C		;Location where the BIOS keeps the tick count

SEGMENT START USE16			;At 0:7C00

start:
	xor	cx, cx			;Set segment registers to zero
	mov	es, cx
	mov	ds, cx
	mov	ss, cx
	mov	sp, reloc_start		;Top of stack
	mov	di, sp			;  is bottom of relocation point
	mov	si, start
	cld
	mov	ch, 1			;cx = 256
	rep movsw			;Copy self to 0:7A00
	jmp	continue		;near JMP to copy of self

SEGMENT MAIN USE16			;At 0:7A00 + START.length
continue:
	sti
	mov	si, message		;Main message
	mov	ax, 0x0E0D		;Start with CR				**
	mov	bx, 7			;Normal display attribute
	int	10h			;Display one character			**
	mov	al, [last_boot]		;display last boot 			**
	int	10h			;Display one character
again:	mov	ax, 0x0E0D		;Start with CR
disp:	int	10h			;Display one character
	lodsb				;Get next char of message
	test	al, al			;Null terminated
	jnz	disp
	mov	bx, 182*5/10		;Allow up to five seconds
	add	bx, [tick]		; beyond current tick count
keywait:
	mov	ah, 1			;Test for keystroke
	int	16h
	jnz	getkey			;Got one
	cmp	bx, [tick]		;Check current tick count
	jns	keywait			;Keep waiting

	mov	al, [last_boot]		;Timeout:  Get default
	jmp short gotkey
getkey:	mov	ah, 0			;Read the key
	int	16h
gotkey:	cmp	al, 'a'			;Convert to upper case
	jb	.10
	sub	al, 'a'-'A'
.10:	
	mov	ah, 0x0E		;					**
	mov	bx, 7			;					**
	int	10h			;display the key			**
	mov	di, PartitionTable-0x0A	;Start of partition table-(dummy length=10)   **
	mov	si, di			; is also end of choice table
.20:	sub	si, byte CHOICE_size	;Loop through choice table
	cmp	[si+letter], al		;Found it?
	je	found			;Yes
	cmp byte [si+letter], 0		;Done whole table?
	jne	.20			;No
erreur:	mov	si, wrong		;Error message
	jmp short again			;Try again
nopar:	mov	si,nopart		;no partition for the key		**
	jmp short again			;					**
found:
	mov	dl, [si+drive]		;Get drive or partition Number
	mov	ch, 0			;Cylinder 0
	mov	dh, 0			;Head 0
	cmp	dl, 0xFC		;Is it a partition code?
	jb	erreur			;no 1 no 2 no 3 no 4 			**
	mov	cl, al			;Save choice 				**
	mov	ax, PT_ENT_size		;Compute location of partition entry
	mul	dx
	add	ax, PartitionTable - (0xFC * PT_ENT_size)
	mov	di,ax			;					**
	cmp byte [di+0x04],0		;is there a partition?			**
	je	nopar			;partition does not exist		**
	mov	[last_boot], cl		;Save choice as new default
	mov	cl, 1			;Sector 1 				**
	mov	di, PartitionTable	;Start of partition table
	mov	[di], ch		;Mark all four partitions nonactive
	mov	[di+PT_ENT_size], ch
	mov	[di+2*PT_ENT_size], ch
	mov	[di+3*PT_ENT_size], ch
	mov	[N_parti_loc], ax	;save boot partition location 		**
	xchg	ax, di			;DI = selected entry
	mov	dl, 0x80		;hard-drive-0 / head 0
	mov	dh, 0
	mov	[di], dl		;Mark it active
	mov	bx, reloc_start		;0:7A00
	mov	ch, 0
	mov	cl, 1			;Sector 1 / Cylinder 0  	**
	mov	ax, 0x301		;Command to write one sector
	int	13h			;Rewrite boot block
	jc	fail			;Failed
	mov	ax, [N_parti_loc]	;				**
	xchg	ax, di			;				**
	mov	cx, [di+RelSectorHigh]	;Sector				**
	mov	ax, [di+RelSectorLow]	;Sector 			**
	mov	dx, [di+BootFlag]	;Drive / Head 			**
go:	mov	si, 3			;Three tries  			
try:	mov	bx, start		;Read it into 0:7C00 		
	push	si			;				**
	xor	si,si			;				**
	push	si			;0				**
	push	si			;0				**
	push	cx			;sector high			**
	push	ax			;sector low			**
	push	es			;segment memory block		**  
	push	bx    			;offset  memory block    7C00	**
	mov	si,1			; transfert one sector		**
	push	si			;				**
	mov	si,0x10			;				**
	push	si			;				**
	mov	si,sp			;				**
	pusha				;				**
	mov	ax, 0x4200		;Command to read one sector (extended) **
	int	13h			;				**
	popa				;				**
	lea	sp,[si+0x10]		;16 octets to compensate 8 push	**
	pop	si			;				**
	jnc	ok			;Success
	dec	si			;retry count
	jnz	try
fail:	mov	si, failed		;Error message
	jmp 	again			;
ok:	mov	bx, 182*1/10		;Allow up to 1 seconds		**
	add	bx, [tick]		; beyond current tick count
waitkey:
	cmp	bx, [tick]		;time left to press  key 	**
	jns	waitkey			;during system boot (F8..)		**
	jmp	start			;Start partition boot block

last_boot	db	'1'		;Default for next boot	
N_parti_loc	dw	0x7BBE		;Default for partition table location		**
failed		db	10,'Disk error',13	
wrong		db	10,'1 2 3 or 4 only ',13,10,0
nopart		db	10,'no partition ',13,10,0	;				**

SEGMENT FINAL USE16			;.LNK file aligns this to end of sector

;Choice table is accessed backwards from the (start of the partition table-10)		** 
; (to leave place for XP disk signature)						**
;You should edit the choice table to represent the choices that make
;sense on your system.  The first byte of each choice represents the			**
;action:
; 0xFC - 0xFF  ->  First through fourth entry in partition table.
;           0  ->  A:
;           1  ->  B:
;        0x81  ->  Hard drive 1
;
;Note that fdisk generally doesn't number partitions according to their
;position in the partition table, so you need to find out some other
;way.
;
;The second byte in each choice entry is the key used to select it.
;_____________________________________________________________________________
message	db	10,7,'SMBMBR  ',10,13,0	;7 = beep replace "SMBMBR  " by your disk name	**
	db	'A'			;not used 					**
	db	0			;not used					**
	db	0,0			;not used					**
	db	0			;Flag (backwards) end of table
	db	0xFC, '1'		;boot on first partition
	db	0xFD, '2'		;	second
	db	0xFE, '3'		;	third
	db	0xFF, '4'		;	fourth
	db	0,0,0,0,0		; dummy zone for XP length=10  (copy only   	**
	db	0,0,0,0,0		;    0 to 1B3 on MBR to avoid   XP disk 	**
					;    signature and partitions)
					;  : partcopy xxx.bin 0 1b4 -h0
PartitionTable  resb 4*PT_ENT_size
	dw	0AA55h
