// // 第一部分:MBR的总体流程 // XP.MBR.1主要流程 AX = 0 SS, ES, DS = AX = 0 SP = 0x7C00 memcpy(0x61B, 0x7C1B, 0x1E5) // offset:0x1B + size:0x1E5 = 0x200 PUSH AX = 0 PUSH DI = 0x61B RETF // 长跳到0x61B处继续执行,即offset:0x1B处代码 其中,STI置中断允许位,CLD清方向标志位 XP.MBR.2主要流程 MOV BP, 0x7BE // 0x7BE - 0x600 = 0x1BE即DPT MOV CL, 0x4 // 4个DPT while(CX) { if([BP + 0] < CH) // 0x80是单字节负数 { SI = BP + 10 // 下一个DPT表项 --CX if(CX == 0) // 最后一个分区是启动分区 { JMP 0x14F } while([SI + 0] == CH) // 剩下的分区都必须是不可启动分区 { SI = SI + 10 --CX if(CX == 0) { JMP 0x14F } } // else { JMP 0x13A // break,跳转到XP.MBR.3 } } if([BP + 0] != CH) { JMP 0x13A // break,跳转到XP.MBR.3 } // DPT为空 BP += 0x10 // 下一个DPT表项 --CX } INT 18 // 尝试以其他方式启动,即启动顺序 XP.MBR.3、4主要流程 0x13A: MOV AL, [0x7B5] // 0x7B5 - 0x600 = 0x1B5里的数据,即AL = 0x2C SI = 0x72C // 0x72C - 0x600 = 0x12C,刚好是"Invalid partition table\0" 调用INT 10中断逐个打印字符 并进入死循环,即不响应了 0x14F: CALL 019B // 跳转到XP.MBR.5,尝试读取启动分区的第一个扇区 JNB 0181 // 成功读取,跳转到XP.MBR.4,校验MBR标识 INC BYTE PTR [BP + 10] // 启动分区后面的分区 CMP BYTE PTR [BP + 04], 0B // 分区文件系统,Win95 FAT32 JZ 016B // 尝试Win95 FAT32 CMP BYTE PTR [BP + 04], 0C // 分区文件系统,Win95 FAT32 LBA JZ 0142 // 前面的死循环 MOV BX, 0007 MOV AH, 0E INT 10 JMP 0141 // 前面的打印字符串,死循环 MOV [BP + 10], CL CALL 019B JNB 0181 // 成功读取,跳转到XP.MBR.4,校验MBR标识 0x157: INC BYTE PTR [BP + 10] // 启动分区后面的分区 CMP BYTE PTR [BP + 04], 0B // 分区文件系统,Win95 FAT32 JZ 016B // 尝试Win95 FAT32 (LBA) CMP BYTE PTR [BP + 04], 0C // 分区文件系统,Win95 FAT32 LBA JZ 016B // 尝试Win95 FAT32 (LBA) MOV AL, [07B6] // 0x1B6,"Error loading operating system\0" JNZ 013D // 前面的打印字符串,死循环 0x16B: // 尝试Win95 FAT32 (LBA) ADD BYTE PTR [BP + 02], 06 ADD WORD PTR [BP + 08], 06 ADC WORD PTR [BP + 0A], 00 CALL 019B JNB 0181 // 成功读取,跳转到XP.MBR.4,校验MBR标识 MOV AL, [07B6] // 0x1B6,"Error loading operating system\0" JNZ 013D // 前面的打印字符串,死循环 0x181: CMP WORD PTR [7DFE], AA55 JZ 0194 // 执行OS Loader CMP BYTE PTR [BP + 10], 00 JZ 0157 // 如果后面还有非启动分区的话 MOV AL, [07B7] // 没有非启动分区了,0x1B7,"Missing operating system\0" JNZ 013D // 前面的打印字符串,死循环 0x194: MOV DI, SP PUSH DS PUSH DI MOV SI, BP RETF // // 第二部分:读取启动分区中的第一个扇区 // XP.MBR.5、6、7主要流程 0x19B: DI = 0x5 DL = [BP + 0] // [BP + 0]小于0才会到此,即DL = 0x80 or 0x81 or ...,INT 13中断中DL = 0x80时为第一个硬盘,依此类推 AH = 0x8 INT 13 // 获取硬盘参数 JB 01CA // 没有发生错误则转移,跳转到XP.MBR.7 // 下面是对获取硬盘参数错误时的修正 MOV AL, CL AND AL, 3F CBW // 此时AX中是扇区号 MOV BL, DH MOV BH, AH INC BX // 此时BX中是磁头号+1,即FE+1=FF MUL BX // AX * BX MOV DX, CX XCHG DL, DH MOV CL, 06 SHR DH, CL INC DX // 此时DX中是柱面号+1 MUL DX // AX * DX CMP [BP + 0A], DX JA 01E6 // >时跳转到XP.MBR.8 JB 01CA // <转移到正常情况 CMP [BP + 08], DX JNB 01E6 // 前面=,这里>=跳转到XP.MBR.8 // 转移到正常情况 0x1CA: // 读取启动分区中的第一个扇区 MOV AX, 0201 MOV BX, 7C00 MOV CX, [BP + 02] // 设置好柱面+扇区 MOV DX, [BP + 00] // 设置好设备+磁头 INT 13 // 从硬盘指定偏移读取1个扇区,即分区第一个扇区 JNB 022B // 无错误则转移,跳转到XP.MBR.10 DEC DI JZ 022B // 此处受DI影响,DI为0时则转移,跳转到XP.MBR.10 XOR AH, AH MOV DL, [BP + 00] INT 13 // 检查硬盘状态 JMP 1CA // 循环读硬盘,尝试DI次,DI = 0x5 XP.MBR.8、9主要流程 0x1E6: // 对获取硬盘参数错误修正失败时 MOV DL, [BP + 00] DB 60 MOV BX, 55AA MOV AH, 41 INT 13 // 检查硬盘扩展标志位0x55AA JB 0229 // 没有硬盘扩展标志位则转移,跳转到XP.MBR.10 CMP BX, AA55 JNZ 0229 // 没有硬盘扩展标志位则转移,跳转到XP.MBR.10 DB 61 0x1FF: // 此处与XP.MBR.7中的0x1CA类似 DB 60 DB 6A ADD [BP + SI + 00], CH PUSH [BP + 0A] PUSH [BP + 08] DB 6A ADD [BP + SI + 00], CH JL 027A ADD [BP + SI + 10], BP MOV AH, 42 MOV SI, SP INT 13 DB 61 DB 61 JNB 022B // 跳转到XP.MBR.10 DEC DI JZ 022B // 跳转到XP.MBR.10 XOR AH, AH MOV DL, [BP + 00] INT 13 // 检查硬盘状态 JMP 01FF // 循环读硬盘,尝试DI次,DI = 0x5 XP.MBR.10主要流程 // 发生错误时置进位标志位 0x229: DB 61 STC // 置进位标志位 0x22B: RET