几年前写的小玩意儿: 黑苹果引导工具tboot

    若干年前,tpu听说苹果的MacOSX也推出PC版本了,十分兴奋,赶紧下载ISO想试试看。我记得下载的版本是10.4.6吧。然后准备安装。由于硬盘前面都满了,于是找了个扩展分区安装。安装后傻眼了......不启动啊。然后才开始上网看各种文档,这才知道,MacOSX只能安装在主分区。

    tpu不甘心啊,找来各种资料研究。darwin本身是开放源代码的,关于引导的文件,都可以找得到。比如chain0, boot0 boot1 boot2等。有了这些原始的资料帮助,再加上tpu很久之前就研究过MBR这些东西,于是就拼凑出了tboot这个东西(tpu's bootloader)。

    tboot的原理很简单,在boot0的代码基础上,完善了扩展分区的搜索代码。这样不论系统装在哪个分区上,都可以找得到。找到之后,再加载该分区前面的boot1部分。boot1再解析分区结构,继续加载boot2。boot2完成整个OSX的加载。

    boot2运行后,如果你的硬盘有多个分区,会显示一个分区列表,让你选择从哪一个分区启动。默认的选项是第一个分区。但一般OSX所在的分区不是第一个,这样每次启动你必须再手动选择一次,很是麻烦。于是tpu对boot2打了个补丁,让它把OSX所在的分区作为默认分区。这样就方便许多了。

    虽然tpu为引导OSX费了这么大的劲,但OSX只在我硬盘上存在几周就消失了。用起来实在是不习惯啊。不过副产品tboot一直有很多网友在用,它确实解决了一些实际的问题,tpu觉得所作的努力还是值得的。听说现在引导工具已经是百花齐放了,比tboot各种先进。不知道tboot是否还能继续引导最新的OSX...

; tboot.s
;
; Load HFS volume on any partition(main or ext)
; writen by tpu, base on boot0 source from Darwin
;

; Set to 1 to enable obscure debug messages.
DEBUG                EQU  0

; Various constants.
kBoot0Segment        EQU  0x0000
kBoot0Stack          EQU  0xFFF0        ; boot0 stack pointer
kBoot0LoadAddr       EQU  0x7C00        ; boot0 load address
kBoot0RelocAddr      EQU  0xE000        ; boot0 relocated address

kBoot2Sectors        EQU  126           ; sectors to load for boot2
kBoot2Address        EQU  0x0000        ; boot2 load address
kBoot2Segment        EQU  0x2000        ; boot2 load segment

kMBRBuffer           EQU  0x1000        ; MBR buffer address
kExtBuffer           EQU  0x1200        ; MBR buffer address

kPartTableOffset     EQU  0x1be
kMBRPartTable        EQU  kMBRBuffer + kPartTableOffset
kExtPartTable        EQU  kExtBuffer + kPartTableOffset

kSectorBytes         EQU  512           ; sector size in bytes
kBootSignature       EQU  0xAA55        ; boot sector signature

kPartCount           EQU  4             ; number of paritions per table

kPartTypeBoot        EQU  0xab          ; boot2 partition type
kPartTypeUFS         EQU  0xa8          ; UFS partition type
kPartTypeHFS         EQU  0xaf          ; HFS partition type

kPartTypeExtDOS      EQU  0x05          ; DOS extended partition type
kPartTypeExtWin      EQU  0x0f          ; Windows extended partition type
kPartTypeExtLinux    EQU  0x85          ; Linux extended partition type
kPartActive	         EQU  0x80
kDriveNumber         EQU  0x80

; Format of fdisk partition entry.
; The symbol 'part_size' is automatically defined as an `EQU'
; giving the size of the structure.
           struc part
.bootid:   resb 1      ; bootable or not 
.head:     resb 1      ; starting head, sector, cylinder
.sect:     resb 1      ;
.cyl:      resb 1      ;
.type:     resb 1      ; partition type
.endhead   resb 1      ; ending head, sector, cylinder
.endsect:  resb 1      ;
.endcyl:   resb 1      ;
.lba:      resd 1      ; starting lba
.sectors   resd 1      ; size in sectors
           endstruc

; Macros.
%macro DebugCharMacro 1
	mov   al, %1
	call  _putc
%endmacro

%if DEBUG
%define putc(x)		DebugCharMacro x
%else
%define putc(x)
%endif

%macro puts 1
	mov   si, %1
	call  put_string
%endmacro
;--------------------------------------------------------------------------
; Start of text segment.

	SEGMENT .text

	ORG     0xe000                  ; must match kBoot0RelocAddr

;--------------------------------------------------------------------------
; Boot code is loaded at 0:7C00h.
start:
	; Set up the stack to grow down from kBoot0Segment:kBoot0Stack.
	; Interrupts should be off while the stack is being manipulated.
	cli                             ; interrupts off
	xor     ax, ax                  ; zero ax
	mov     ss, ax                  ; ss <- 0
	mov     sp, kBoot0Stack         ; sp <- top of stack
	sti                             ; reenable interrupts

	mov     es, ax                  ; es <- 0
	mov     ds, ax                  ; ds <- 0

	; Relocate boot0 code.
	mov     si, kBoot0LoadAddr      ; si <- source
	mov     di, kBoot0RelocAddr     ; di <- destination
	cld                             ; auto-increment SI and/or DI registers
	mov     cx, kSectorBytes/2      ; copy 256 words
	repnz   movsw                   ; repeat string move (word) operation

	; Code relocated, jump to start_reloc in relocated location.
	jmp     0:start_reloc

;--------------------------------------------------------------------------
; Start execution from the relocated location.
;
start_reloc:

.loop_next_drive:

	; Clear drive flags.
	xor     eax, eax
	mov     [first_part], eax        ; clear EBIOS LBA offset
	mov     [this_part], eax

%if DEBUG
	putc('D')
	mov     al, dl
	call    putb
	putc(' ')
%endif
	; Read MBR sector to memory.
	mov     al, 1                   ; load one sector
	mov     bx, kMBRBuffer          ; MBR load address
	xor     ecx, ecx
	call    load
	jc      .next_drive

	mov     di, kMBRBuffer
	mov     si, kMBRBuffer+kPartTableOffset
	cmp     WORD [si + part_size * kPartCount], kBootSignature
	jne     .next_drive             ; Signature error

	; Look for the HFS partition in the MBR partition table
	call    find_boot               ; will not return on success

.next_drive:
	inc     dl                      ; next drive number
	test    dl, 0x4                 ; went through all 4 drives?
	jz      .loop_next_drive        ; not yet, loop again

	puts    part_error_str
.hang:
	hlt
	jmp     SHORT .hang

;--------------------------------------------------------------------------
; Find the HFS partition and load the booter from the partition.
;--------------------------------------------------------------------------
find_boot:
	mov     cx, 4                   ; number of partition entries per table

.loop_part:
	push    cx
	push    si

%if DEBUG
	mov     al, [si + part.type]
	call    putb
	putc(' ')
	mov     eax, [si + part.lba]
	call    putd
	putc(10)
	putc(13)
%endif

	mov     eax, [si + part.lba]
	mov     bl, [si + part.type]    ; print partition type

	cmp     bl, kPartTypeExtLinux   ; Extended Linux
	je		.ext_check
	cmp     bl, kPartTypeExtDOS     ; Extended DOS
	je		.ext_check
	cmp     bl, kPartTypeExtWin     ; Extended Windows(95)
	jne		.nonext

.ext_check:
	cmp     di, kMBRBuffer
	jnz     .ext_not_mbr

	mov     [first_part], eax
	xor     eax, eax
.ext_not_mbr:
	mov     [this_part], eax

	; Read extended partition table
	mov     ecx, eax
	mov     al, 1                   ; load one sector
	mov     bx, kExtBuffer          ; extended load address
	call    load
	jc      .next_part

	mov     si, kExtBuffer+kPartTableOffset
	cmp     WORD [si + part_size * kPartCount], kBootSignature
	jne     .next_part              ; Signature error

	push    di
	mov     di, kExtBuffer
	call    find_boot
	pop		di

	cmp     di, kMBRBuffer
	jnz     .next_part
	xor     eax, eax
	mov     [this_part], eax
	mov     [first_part], eax

.next_part:
	pop     si
	pop     cx
	add     si, part_size           ; advance SI to next partition entry
	loop    .loop_part              ; loop through all partition entries

.exit_find
	ret

.nonext:
	cmp     bl, 0
	je      .next_part

	cmp     bl, kPartTypeHFS
	je     .found_part
	cmp     bl, kPartTypeUFS
	je     .found_part
	cmp     bl, kPartTypeBoot
	jne     .next_part

.found_part:
	add     eax, [this_part]
	mov     ecx, eax
	add     eax, [first_part]
	mov     [si+part.lba], eax

	; Found boot partition, read boot sector to memory.
	mov     bx, kBoot0LoadAddr
	mov     al, 1
	call    load
	jc      .next_part               ; load error, keep looking?

	putc("F")

	cmp     WORD [bx + 510], kBootSignature
	jnz     .next_part

	; patch boot1h
	mov     eax, [0x7cbb]
	cmp     eax, 0x20000200
	jnz     .no_patch

	mov     eax, 0x00007d40
	mov     [0x7cbb], eax

	push    si
	mov     si, patch_code_start
	mov     di, 0x7d40
	mov     cx, (patch_code_end-patch_code_start)
	cld
	repnz
	movsb
	pop     si

.no_patch:
	; Jump to partition booter. The drive number is already in register DL.
	; SI is pointing to the modified partition entry.
	jmp     kBoot0Segment:kBoot0LoadAddr


;--------------------------------------------------------------------------
; load - Read sectors from a partition using LBA addressing.
;--------------------------------------------------------------------------
load:
	pushad                          ; save all registers
	mov     bp, sp                  ; save current SP

	;push    DWORD 0               ; offset 12, upper 32-bit LBA
	push    ds                      ; For sake of saving memory,
	push    ds                      ; push DS register, which is 0.

	add     ecx, [first_part]        ; offset 8, lower 32-bit LBA
	push    ecx
	push    es                      ; offset 6, memory segment
	push    bx                      ; offset 4, memory offset
	xor     ah, ah                  ; offset 3, must be 0
	push    ax                      ; offset 2, number of sectors
	push    WORD 16                 ; offset 0-1, packet size

%if DEBUG
	putc('L')
	mov     eax, ecx
	call    putd
	putc(10)
	putc(13)
%endif

	mov     si, sp
	mov     ah, 0x42
	int     0x13

	mov     sp, bp                  ; restore SP
	popad
	ret

;--------------------------------------------------------------------------
; Write a string to the console.
;
; Arguments:
;   DS:SI   pointer to a NULL terminated string.
;
; Clobber list:
;   AX, BX, SI
;
put_string
	mov     bx, 1                   ; BH=0, BL=1 (blue)
	cld                             ; increment SI after each lodsb call
.loop
	lodsb                           ; load a byte from DS:SI into AL
	cmp     al, 0                   ; Is it a NULL?
	je      .exit                   ; yes, all done
	mov     ah, 0xE                 ; INT10 Func 0xE
	int     0x10                    ; display byte in tty mode
	jmp     short .loop
.exit
	ret


%if DEBUG


; Show a DWORD value.
putd
	ror eax, 16
	call putw
	ror eax, 16
; Show a WORD value.
putw
	ror ax, 8
	call putb
	ror ax, 8
; Show a BYTE value.
putb
	ror al, 4
	call put_nibble
	ror al, 4
; Show 4 bit value.
put_nibble
	push eax
	and al, 0x0f
	add al, 0x30
	cmp al, 0x39
	jna .pascii
	add al, 0x07
.pascii
	call _putc
	pop eax
	ret

; Show a ASCII character to the console.
_putc
	pusha
	mov bx, 1
	mov ah, 0x0e
	int 0x10
	popa
	ret

%endif ;DEBUG


patch_code_start:
	; patch boot2: SelectBootVolume
	mov     di, 0x39ac
	mov     eax, [es:di]
	cmp     eax, 0x01a8da45
	jne     .no_patch

	mov     al, 2
	mov     [es:di+3], al

.no_patch:
	; Jump to boot2. The drive number is already in register DL.
	jmp     kBoot2Segment:kBoot2Address + kSectorBytes
patch_code_end:


; NULL terminated strings.
part_error_str:   db  'No HFS partition found', 10, 13, 0

;--------------------------------------------------------------------------
; Pad the rest of the 512 byte sized booter with zeroes. The last
; two bytes is the mandatory boot sector signature.

pad_boot
	times 510-($-$$) db 0
	dw    kBootSignature

	ABSOLUTE 0xE400

; In memory variables.
first_part      resd   1   ; starting LBA of the intial extended partition.
this_part       resd   1   ; starting LBA of the current extended partition. 
part_base       resd   1
        
END


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值