; microsoft.windows.98se.mbr.asm.txt ; Windows 98se ; MBR ( Master Boot Record ) by Daniel B. Sedory ; http://thestarman.pcministry.com 7C00 33C0 XOR AX,AX ; Zero out both the Accumulator and 7C02 8ED0 MOV SS,AX ; the Stack Segment register. 7C04 BC007C MOV SP,7C00 ; Set Stack Pointer to 0000:7C00 7C07 FB STI ; Enable Interrupts 7C08 50 PUSH AX ; (AX=0) 7C09 07 POP ES ; Zero-out Extra Segment 7C0A 50 PUSH AX ; (AX=0) 7C0B 1F POP DS ; Zero-out Data Segment 7C0C FC CLD ; Clear Direction Flag 7C0D BE1B7C MOV SI,7C1B ; Source Index: Copy from here... 7C10 BF1B06 MOV DI,061B ; Destination Index: Copy to here: ; Code will begin at: 0000:061B 7C13 50 PUSH AX ; Set up Segment(AX) and Offset(DI) 7C14 57 PUSH DI ; for jump to 0000:061B. 7C15 B9E501 MOV CX,01E5 ; Set up Counter (CX) to copy ; (1E5h) 485 bytes of code. 7C18 F3 REP ; REPeat the following MOVSB ; instruction for 'CX' times. 7C19 A4 MOVSB ; Copy one byte at a time. 7C1A CB RETF ; Use RETF to do Jump to where we ; copied the code: 0000:061B. ; Since the preceding routine copies the remainder of the code to 0000:061B ; through 0000:07FF and continues its execution there, the following ; addresses have been changed to reflect the code's actual location in ; memory at the time of execution. ; This next section of code tries to find an ACTIVE (i.e., bootable) entry in ; the Partition Table. The first byte of an entry indicates if it's bootable ; (normally an 80h, but in this case, anything from 81h through FFh as well!) ; or not (a 00h); any other values (from 01h through 7Fh) in these locations ; means the Table is invalid! If none of the four entries in the Table is ; active, then the INT 18h instruction will be executed; for which most BIOS ; today (see note at 062B below) will display "PRESS A KEY TO REBOOT". 061B BEBE07 MOV SI,07BE ; Location of first entry in the partition table (see Sample Table here). 061E B104 MOV CL,04 ; Maximum of 4 entries. 0620 382C CMP [SI],CH ; We know (from Counter decrement above) that CH=0, so CoMPare 1st byte of entry [SI] to zero. Only if the high bit is set (80h thru FFh), will it be 'less than': 0622 7C09 JL 062D ; Found a possible boot entry, but let's check it out more at 062D, or... continue searching table. 0624 7515 JNZ 063B ; If not a zero byte (01h to 7Fh), then print out error message... -> "Invalid partition table" 0626 83C610 ADD SI,+10 ; Checking the next entry... (10h = 16 bytes per entry) 0629 E2F5 LOOP 0620 ; Go back & check next Entry... unless CL=0 (tried all four). 062B CD18 INT 18 ; Checked all 4; NONE of them were bootable, so start ROM-BASIC (only available on some IBM machines!) Many BIOS simply display "PRESS A KEY TO REBOOT" when Int 18h is run. ; An Active partition was found, but we must check all other entries ; for being non-bootable (first byte = 00h), or there's an error! ; (Obviously, only one entry at a time can be marked as 'Active'!) ; Before doing so, we load the Head and Drive data into DX for use by ; the DOS Interrupt 13 commands later.... 062D 8B14 MOV DX,[SI] ; This causes the Drive # (Yes, the Active BootFlag bytes in ; Partition Tables are Drive Numbers) to be placed into -> DL and its ; Head # -> DH. For the Standard MBR, DL will always be 80h (see offset ; 0622 there with an 80h 'hardcoded' into the instruction) making only ; the first drive bootable! [So, that part of the Standard MBR code was ; often changed by MBR replacements! If you have an OS that can boot up ; from another drive, this new Win95B-ME MBR makes it easier to do so.] 062F 8BEE MOV BP,SI ; Save offset of this entry... 0631 83C610 ADD SI,+10 ; see if any more are left. 0634 49 DEC CX ; If CX=0, then we're done here, 0635 7416 JZ 064D ; so Jump to ID-type checking! 0637 382C CMP [SI],CH ; CoMPare entry's first byte [SI] 0639 74F6 JZ 0631 ; to Zero (CH=0). If it's not zero, we fall into the error routine immediately following... ; If there was an error, then this next routine displays the message that ; SI points to. After printing the ASCII-Z string (null terminated), the ; program 'hangs' by going into an infinite loop of executions between ; 063E and 0642 as soon as it hits the Zero-byte at the end of the error ; message. ; This is an interesting way to form an endless loop: Since the LODSB ; instruction increments SI whenever it's executed, the decrement of SI ; at 063E forces the CPU to load the same byte at 0726 (a 00h) into the ; AL register over and over again! 063B BE1007 MOV SI,0710 ; To make SI point to: (070F or "Invalid partition table") after the decrement of SI. |063E 4E DEC SI ; Used only to 'hang' machine! |063F AC LODSB ; Load byte at SI into AL and increment SI register. |0640 3C00 CMP AL,00 ; Is it the string terminator? |0642 74FA JZ 063E ; If so, 'lock-up' machine! 0644 BB0700 MOV BX,0007 ; Use normal White on Black text 0647 B40E MOV AH,0E ; and Function 0Eh of INT 10 to 0649 CD10 INT 10 ; display the character in AL on the video screen. 064B EBF2 JMP 063F ; Get next string character... ; At this point, the BP Register contains the offset to the Active entry ; (see 062F) and AX should still be zero. The first instruction in the code ; below seems rather strange; especially if we are booting the first entry, ; since this overwrites data in the third entry! This is just in Memory ; though; the only entry that matters at this time is the one we are going ; to boot from. But why use an offset of +25 Hex (or 37 bytes) when each ; entry is only 16 bytes long? For example, if booting from the first entry ; which makes BP=07BE, this first instruction will affect the two bytes at ; offsets 07E3h and 07E4h. Let's try to figure out why this was done: 064D 894625 MOV [BP+25],AX ; Zero-out the two bytes at offsets BP plus 37 (25 hex) and 38. 0650 96 XCHG SI,AX ; The contents of SI should be 07FE at this point (from checking the last entry in the Table), so this makes AX -> 07FE and SI -> zero. But after the next 2 instructions the 07FE is gone! So this is just a quick way to zero-out SI! 0651 8A4604 MOV AL,[BP+04] ; This is the Partition Type ID for the bootable entry! 0654 B406 MOV AH,06 ; 06h = FAT16 (>32MB) Partition. 0656 3C0E CMP AL,0E ; 0Eh = FAT16 LBA-mapped Partition. 0658 7411 JZ 066B ; If Partition Type is 0E hex, Jump to 066B with AX=060E. 065A B40B MOV AH,0B ; 0Bh = FAT32 Partition. 065C 3C0C CMP AL,0C ; 0Ch = FAT32 LBA-mapped Partition; uses Extended INT 13 code to begin past cylinder 1024. 065E 7405 JZ 0665 ; If Partition Type is 0C hex, Jump to 0665 with AX=0B0C. 0660 3AC4 CMP AL,AH ; AH should still be 0Bh. 0662 752B JNZ 068F ; For ID Types other than 06,0B, 0C or 0E, jump to 068F with AX=0Bxx where xx = ID Type. 0664 40 INC AX ; Partition Type is 0B hex, but we make it a 0C hex in AL (this changes the Zero Flag to a Non-zero which forces a jump to 068F below!) 0665 C6462506 MOV BYTE PTR [BP+25],06 ; Make the byte at BP plus 37 a 06 and.. 0669 7524 JNZ 068F ; Jump to 068F with AX=0B0C only if we have an ID Type = 0Bh. Otherwise (e.g.,type=0Ch)... 066B BBAA55 MOV BX,55AA ;| 066E 50 PUSH AX ;| Check for INT 13 066F B441 MOV AH,41 ;| Extended Functions 0671 CD13 INT 13 ;| Any of three tests below will cause the check to fail. 0673 58 POP AX 0674 7216 JB 068C ; Extensions are not present! 0676 81FB55AA CMP BX,AA55 067A 7510 JNZ 068C ; Extensions are not present! 067C F6C101 TEST CL,01 067F 740B JZ 068C ; Extensions are not present! 0681 8AE0 MOV AH,AL 0683 885624 MOV [BP+24],DL 0686 C706A106EB1E MOV WORD PTR [06A1],1EEB ; This is an unusual use of code in a commercial OS! This instruction actually modifies the code at offset 06A1 from what you see below to a: JMP 06C1 which aborts the Standard INT13 call. 068C 886604 MOV [BP+04],AH 068F BF0A00 MOV DI,000A 0692 B80102 MOV AX,0201 ; Function 02 of INT 13: 0695 8BDC MOV BX,SP 0697 33C9 XOR CX,CX 0699 83FF05 CMP DI,+05 069C 7F03 JG 06A1 069E 8B4E25 MOV CX,[BP+25] 06A1 034E02 ADD CX,[BP+02] ; Can also be: JMP 06C1 (if the test for Extended INT 13 above is positive!) 06A4 CD13 INT 13 06A6 7229 JB 06D1 06A8 BE4607 MOV SI,0746 ; -> "Missing operating system" 06AB 813EFE7D55AA CMP WORD PTR [7DFE],AA55 ; Checking the last two bytes of newly loaded sector for "Magic Number" (AA55h). 06B1 745A JZ 070D ; See Note at 070Dh for this seemingly odd usage. 06B3 83EF05 SUB DI,+05 06B6 7FDA JG 0692 06B8 85F6 TEST SI,SI 06BA 7583 JNZ 063F 06BC BE2707 MOV SI,0727 ; --> "Error loading operating system" 06BF EB8A JMP 064B ; The code at 064B was conveniently used in order to jump all the way back to 063F without having to use a three-byte NEAR jump! See Using SHORT Jumps for more info. 06C1 98 CBW ; Convert Byte to Word. 06C2 91 XCHG CX,AX 06C3 52 PUSH DX 06C4 99 CWD ; Convert Word to DoubleWord. 06C5 034608 ADD AX,[BP+08] 06C8 13560A ADC DX,[BP+0A] 06CB E81200 CALL 06E0 06CE 5A POP DX 06CF EBD5 JMP 06A6 06D1 4F DEC DI 06D2 74E4 JZ 06B8 06D4 33C0 XOR AX,AX ;| INT 13 Function 0 06D6 CD13 INT 13 ;| "RESET DISK SYSTEM" 06D8 EBB8 JMP 0692 06DA 0000 ; Location in Memory of what we're 06DC 00000000 ; calling the "Mystery Bytes" ; SUBROUTINE: 06E0 56 PUSH SI 06E1 33F6 XOR SI,SI 06E3 56 PUSH SI 06E4 56 PUSH SI 06E5 52 PUSH DX 06E6 50 PUSH AX 06E7 06 PUSH ES 06E8 53 PUSH BX 06E9 51 PUSH CX 06EA BE1000 MOV SI,0010 06ED 56 PUSH SI 06EE 8BF4 MOV SI,SP 06F0 50 PUSH AX 06F1 52 PUSH DX 06F2 B80042 MOV AX,4200 ;| ( An INT 13 Extension ) 06F5 8A5624 MOV DL,[BP+24] ;| 06F8 CD13 INT 13 ;| Extended READ Function 06FA 5A POP DX 06FB 58 POP AX 06FC 8D6410 LEA SP,[SI+10] 06FF 720A JB 070B 0701 40 INC AX 0702 7501 JNZ 0705 0704 42 INC DX 0705 80C702 ADD BH,02 0708 E2F7 LOOP 0701 070A F8 CLC 070B 5E POP SI 070C C3 RET 070D EB74 JMP 0783 ; At first glance, this may appear to be a wasteful use of bytes,but it's necessary because the point of the code here is to get program execution to jump from 06B1 to 0783 using only fast 2-byte jumps which are limited to +127 bytes forward. See Using SHORT Jumps for more info. Apparently, moving the Error Messages you see below wasn't an option. ;Location of Error Messages in Memory ;070F 49 I ;0710 6E 76 61 6C 69 64 20 70 61 72 74 69 74 69 6F 6E nvalid partition ;0720 20 74 61 62 6C 65 00 45 72 72 6F 72 20 6C 6F 61 table.Error loa ;0730 64 69 6E 67 20 6F 70 65 72 61 74 69 6E 67 20 73 ding operating s ;0740 79 73 74 65 6D 00 4D 69 73 73 69 6E 67 20 6F 70 ystem.Missing op ;0750 65 72 61 74 69 6E 67 20 73 79 73 74 65 6D 00 00 erating system.. ;0760 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ;0770 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ;0780 00 00 00 ... ;(Note: The unused bytes above allow for longer error messages in other languages.) ;Location of the Lonely Code Bytes in Memory 0783 8BFC MOV DI,SP ; Set up Offset (DI) with 7C00. 0785 1E PUSH DS ; (which is 0000 at this time) 0786 57 PUSH DI 0787 8BF5 MOV SI,BP 0789 CB RETF ; Use RETF to do a Jump to the OS Boot Sector code at 0000:7C00 continuing the boot-up process! ;Unused and S/N Area ; A B C D E F ; 078A 00 00 00 00 00 00 ...... ; 0790 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ; 07A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ; 07B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .............. ; 0 1 2 3 4 5 6 7 8 9 A B C D ;(The bytes in offset 7B8h through 7BBh, may contain an NT Drive Serial Number if the computer was ever booted up under Windows NT/2000/XP.)