racerrehabman

Just some techie stuff

Archive for the ‘Computers’ Category

Yosemite/Haswell Kernel Patch for Early Reboot

with 46 comments

Just a quick update as I’m quite busy at the moment.

This is an update for Yosemite for an issue which was described for Mavericks in a previous post: https://racerrehabman.wordpress.com/2013/11/25/maverickshaswell-kernel-patch-for-early-reboot/

Since Yosemite has been released, we need a new patch for the OS X kernel to avoid early reboot on computers with locked CPU MSR 0xE2. The kernel has now moved to /System/Library/Kernels/kernel.

The code has changed slightly and now it is only necessary to change the data tables such that any table writing to register 0xE2 is changed to 0x00. I’ll explain more if I find time.

Here are the new patches required for 10.10.x:


perl -pi -e 's|\xe2\x00\x00\x00\x02\x00\x00\x00|\x00\x00\x00\x00\x00\x00\x00\x00|g' kernel
perl -pi -e 's|\xe2\x00\x00\x00\x4c\x00\x00\x00|\x00\x00\x00\x00\x00\x00\x00\x00|g' kernel
perl -pi -e 's|\xe2\x00\x00\x00\x90\x01\x00\x00|\x00\x00\x00\x00\x00\x00\x00\x00|g' kernel

Those using Clover do not need to patch the kernel manually as this same patch is provided with the KernelAndKextPatches/KernelPm option in config.plist.

Update 2015-01-26

As pointed out by Zenith432 (thanks!), the original published patch would write to MSR 0x0 after the 0xE2 values were zeroed. Although this did not appear to cause any problems and I already knew about it, it is probably a good idea to avoid it. The patches have been updated to account for this based on the information provided by Zenith432.

Advertisements

Written by racerrehabman

2014/10/18 at 17:38

Posted in Computers

Tagged with , , ,

Mavericks/Haswell Kernel Patch for Early Reboot

with 55 comments

One of the big changes for mach_kernel in OS X Mavericks is the relocation of CPU power management into the kernel (for Haswell only). What used to happen in AppleIntelCPUPowerManagement.kext, now happens in the kernel. Since this kernel writes to potentially locked MSRs, this can be a problem for computers where the BIOS cannot be patched, or simply where the owner of the computer does not want to patch the BIOS. But since Apple did not include the code to XCPM (XNU CPU Power Management) in the sources provided for the 10.9 kernel, if you build mach_kernel from sources, the XCPM code and thus the code writing to locked MSRs is not included. I wrote about this initially when I discovered it while trying to get Mavericks running on a Haswell-based HP laptop. See here: http://www.insanelymac.com/forum/topic/293503-haswell-early-reboot-mavericks-locked-msrs-and-hp-envy-15-j063cl-i7-4700mq/

As mentioned in that post, my reason for building the kernel myself was to explore the possibility of removing the code that manipulates these locked MSRs. Of course, I couldn’t find the code because Apple didn’t provide it. To my surprise, the kernel built without this code still worked and I was able to coble together a system which provided power management by using patched AppleIntelCPUPowerManagement.kext from 10.8.5 and this rebuilt from source mach_kernel. That success put the idea of finding a patch to the included kernel on hold. But my real goal was to eventually come up with a patch.

My prior attempts to do this had not worked. My attempt was to patch the kernel such that only writes to MSR 0xE2 were filtered out. But then Pike blogged about the possibility of eliminating all writes to MSRs (https://pikeralpha.wordpress.com/2013/11/23/experimental-bin-patch-for-maverick/), and even though he was targetting the wrong section of code (_wrmsr_carefully is not called, at least not by mach_kernel itself), and I was misunderstanding his post such that I thought he was targetting the correct section of code (see below), I tried the approach of filtering out all writes to locked MSRs. This worked (in fact I commented on his blog with a perl patch that does exactly that), so I wondered if the problem was that there were MSRs other than 0xE2 being written to that were also locked. This turned out not to be the case. The problem was my original patch was simply not done correctly. But the breakthrough was realizing that I was targetting the right section of code, and that my patch must be in error or incomplete.

This is the code in mach_kernel that poses the problem (otool -tV mach_kernel):

ffffff80002f9ba0 pushq %rbp
ffffff80002f9ba1 movq %rsp, %rbp
ffffff80002f9ba4 movl %edx, %r8d
ffffff80002f9ba7 testl %esi, %esi
ffffff80002f9ba9 je 0xffffff80002f9c17
ffffff80002f9bab addq $0x28, %rdi
ffffff80002f9baf nop
ffffff80002f9bb0 movl _xcpm_cpu_model(%rip), %eax
ffffff80002f9bb6 testl 0xffffffffffffffdc(%rdi), %eax
ffffff80002f9bb9 je 0xffffff80002f9c0f
ffffff80002f9bbb movl 0xffffffffffffffd8(%rdi), %ecx
ffffff80002f9bbe testl %r8d, %r8d
ffffff80002f9bc1 je 0xffffff80002f9bcb
ffffff80002f9bc3 cmpl %r8d, %ecx
ffffff80002f9bc6 movl %r8d, %ecx
ffffff80002f9bc9 jne 0xffffff80002f9c0f
ffffff80002f9bcb rdmsr
ffffff80002f9bcd movl %eax, %eax
ffffff80002f9bcf shlq $0x20, %rdx
ffffff80002f9bd3 orq %rax, %rdx
ffffff80002f9bd6 movq %rdx, 0xfffffffffffffff8(%rdi)
ffffff80002f9bda movq 0xffffffffffffffe8(%rdi), %rax
ffffff80002f9bde testq %rax, %rax
ffffff80002f9be1 je 0xffffff80002f9be9
ffffff80002f9be3 notq %rax
ffffff80002f9be6 andq %rax, %rdx
ffffff80002f9be9 orq 0xfffffffffffffff0(%rdi), %rdx
ffffff80002f9bed movq %rdx, %r9
ffffff80002f9bf0 shrq $0x20, %r9
ffffff80002f9bf4 movl %edx, %eax
ffffff80002f9bf6 movl 0xffffffffffffffd8(%rdi), %ecx
ffffff80002f9bf9 movq %r9, %rdx
ffffff80002f9bfc wrmsr
ffffff80002f9bfe movl 0xffffffffffffffd8(%rdi), %ecx
ffffff80002f9c01 rdmsr
ffffff80002f9c03 movl %eax, %eax
ffffff80002f9c05 shlq $0x20, %rdx
ffffff80002f9c09 orq %rax, %rdx
ffffff80002f9c0c movq %rdx, (%rdi)
ffffff80002f9c0f addq $0x30, %rdi
ffffff80002f9c13 decl %esi
ffffff80002f9c15 jne 0xffffff80002f9bb0
ffffff80002f9c17 popq %rbp
ffffff80002f9c18 ret
ffffff80002f9c19 nop
ffffff80002f9c1a nop
ffffff80002f9c1b nop
ffffff80002f9c1c nop
ffffff80002f9c1d nop
ffffff80002f9c1e nop
ffffff80002f9c1f nop

At 2f9bfc, you can see the wrmsr. This has the potential to write to any register as this function is walking through a table of entries, each 48 bytes in size, where the each entry contains the register to write to.

Note that there are seven nop codes following the function (padding), which gives us room to grow the function by 7-bytes to add additional code to filter out the writes that might be MSR 0xE2. My first attempt was to simply try a compare/conditional jump:

                 cmp 0xE2, %ecx
                 je skipwrmsr
ffffff80002f9bfc wrmsr
skipwrmsr:
ffffff80002f9bfe movl 0xffffffffffffffd8(%rdi), %ecx
ffffff80002f9c01 rdmsr
ffffff80002f9c03 movl %eax, %eax

The problem is fitting the two new instructions into only 7 bytes. I could not find a way (problem is a cmp byte-immed,%ecx is a sign extending compare).

Instead, I decided to simply check for zero in the table and then modify the table to zero out the entries with 0xE2:

                 testl %ecx, %ecx     ;85 c9
                 je skipwrmsr         ;74 07
ffffff80002f9bfc wrmsr
ffffff80002f9bfe movl 0xffffffffffffffd8(%rdi), %ecx
ffffff80002f9c01 rdmsr
skipwrmsr:
ffffff80002f9c03 movl %eax, %eax

Because we are inserting 4-bytes of extra code to implement this, a few other conditional jumps must be modified. It is useful to add some labels to the original code and add the opcodes as comments before attempting to build a perl script for the patch:

ffffff80002f9ba0 pushq %rbp                           ;55
ffffff80002f9ba1 movq %rsp, %rbp                      ;48 89 e5
ffffff80002f9ba4 movl %edx, %r8d                      ;41 89 d0
ffffff80002f9ba7 testl %esi, %esi                     ;85 f6
ffffff80002f9ba9 je 0xffffff80002f9c17 ;return1       ;74 6c
ffffff80002f9bab addq $0x28, %rdi                     ;48 83 c7 28
ffffff80002f9baf nop                                  ;90
loop1:
ffffff80002f9bb0 movl _xcpm_cpu_model(%rip), %eax     ;8b 05 5e 30 5e 00
ffffff80002f9bb6 testl 0xffffffffffffffdc(%rdi), %eax ;85 47 dc
ffffff80002f9bb9 je 0xffffff80002f9c0f ;continue1     ;74 54
ffffff80002f9bbb movl 0xffffffffffffffd8(%rdi), %ecx  ;8b 4f d8 45
ffffff80002f9bbe testl %r8d, %r8d                     ;85 c0
ffffff80002f9bc1 je 0xffffff80002f9bcb ;skip1         ;74 08
ffffff80002f9bc3 cmpl %r8d, %ecx                      ;44 39 c1
ffffff80002f9bc6 movl %r8d, %ecx                      ;44 89 c1
ffffff80002f9bc9 jne 0xffffff80002f9c0f ;continue1    ;75 44
skip1:
ffffff80002f9bcb rdmsr                                ;0f 32
ffffff80002f9bcd movl %eax, %eax                      ;89 c0
ffffff80002f9bcf shlq $0x20, %rdx                     ;48 c1 e2 20
ffffff80002f9bd3 orq %rax, %rdx                       ;48 09 c2
ffffff80002f9bd6 movq %rdx, 0xfffffffffffffff8(%rdi)  ;48 89 57 f8
ffffff80002f9bda movq 0xffffffffffffffe8(%rdi), %rax  ;48 8b 47 e8
ffffff80002f9bde testq %rax, %rax                     ;48 85 c0
ffffff80002f9be1 je 0xffffff80002f9be9 ;skip2         ;74 06
ffffff80002f9be3 notq %rax                            ;48 f7 d0
ffffff80002f9be6 andq %rax, %rdx                      ;48 21 c2
skip2:
ffffff80002f9be9 orq 0xfffffffffffffff0(%rdi), %rdx   ;48 0b 57 f0
ffffff80002f9bed movq %rdx, %r9                       ;49 89 d1
ffffff80002f9bf0 shrq $0x20, %r9                      ;49 c1 e9 20
ffffff80002f9bf4 movl %edx, %eax                      ;89 d0
ffffff80002f9bf6 movl 0xffffffffffffffd8(%rdi), %ecx  ;8b 4f d8
ffffff80002f9bf9 movq %r9, %rdx                       ;4c 89 ca
additional_code:
                 test %ecx,%ecx                       ;85 c9
                 je skip_rdmsr                        ;74 07
ffffff80002f9bfc wrmsr ;0f 30
ffffff80002f9bfe movl 0xffffffffffffffd8(%rdi), %ecx  ;8b 4f d8
ffffff80002f9c01 rdmsr                                ;0f 32
skip_rdmsr:
ffffff80002f9c03 movl %eax, %eax                      ;89 c0
ffffff80002f9c05 shlq $0x20, %rdx                     ;48 c1 e2 20
ffffff80002f9c09 orq %rax, %rdx                       ;48 09 c2
ffffff80002f9c0c movq %rdx, (%rdi)                    ;48 89 17
continue1:
ffffff80002f9c0f addq $0x30, %rdi                     ;48 83 c7 30
ffffff80002f9c13 decl %esi                            ;ff ce
ffffff80002f9c15 jne 0xffffff80002f9bb0 ;loop1        ;75 99
return1:
ffffff80002f9c17 popq %rbp                            ;5d
ffffff80002f9c18 ret                                  ;c3
ffffff80002f9c19 nop                                  ;90
ffffff80002f9c1a nop                                  ;90
ffffff80002f9c1b nop                                  ;90
ffffff80002f9c1c nop                                  ;90 ;; remove these 4 nops
ffffff80002f9c1d nop                                  ;90
ffffff80002f9c1e nop                                  ;90
ffffff80002f9c1f nop                                  ;90

As you can see, because the jump targets have moved, the conditional jumps at 2f9ba9, 2f9bb9, 2f9bc9, and 2f9c15 must be adjusted to accomodate the extra four bytes of code. My first attempt (prior to building the kernel from sources) only adjusted the last one (oops).

The final perl patch is as follows:

perl -pi -e 's|\x74\x6c(\x48\x83\xc7\x28\x90\x8b\x05\x5e\x30\x5e\x00\x85\x47\xdc)\x74\x54(\x8b\x4f\xd8\x45\x85\xc0\x74\x08\x44\x39\xc1\x44\x89\xc1)\x75\x44(\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x57\xf8\x48\x8b\x47\xe8\x48\x85\xc0\x74\x06\x48\xf7\xd0\x48\x21\xc2\x48\x0b\x57\xf0\x49\x89\xd1\x49\xc1\xe9\x20\x89\xd0\x8b\x4f\xd8\x4c\x89\xca)(\x0f\x30\x8b\x4f\xd8\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x17\x48\x83\xc7\x30\xff\xce)\x75\x99(\x5d\xc3\x90{3})\x90{4}|\x74\x70${1}\x74\x58${2}\x75\x48${3}\x85\xc9\x74\x07${4}\x75\x95${5}|g' mach_kernel

With that patch in place, the resulting patched function looks like:

ffffff80002f9ba0 pushq %rbp
ffffff80002f9ba1 movq %rsp, %rbp
ffffff80002f9ba4 movl %edx, %r8d
ffffff80002f9ba7 testl %esi, %esi
ffffff80002f9ba9 je 0xffffff80002f9c1b
ffffff80002f9bab addq $0x28, %rdi
ffffff80002f9baf nop
ffffff80002f9bb0 movl _xcpm_cpu_model(%rip), %eax
ffffff80002f9bb6 testl 0xffffffffffffffdc(%rdi), %eax
ffffff80002f9bb9 je 0xffffff80002f9c13
ffffff80002f9bbb movl 0xffffffffffffffd8(%rdi), %ecx
ffffff80002f9bbe testl %r8d, %r8d
ffffff80002f9bc1 je 0xffffff80002f9bcb
ffffff80002f9bc3 cmpl %r8d, %ecx
ffffff80002f9bc6 movl %r8d, %ecx
ffffff80002f9bc9 jne 0xffffff80002f9c13
ffffff80002f9bcb rdmsr
ffffff80002f9bcd movl %eax, %eax
ffffff80002f9bcf shlq $0x20, %rdx
ffffff80002f9bd3 orq %rax, %rdx
ffffff80002f9bd6 movq %rdx, 0xfffffffffffffff8(%rdi)
ffffff80002f9bda movq 0xffffffffffffffe8(%rdi), %rax
ffffff80002f9bde testq %rax, %rax
ffffff80002f9be1 je 0xffffff80002f9be9
ffffff80002f9be3 notq %rax
ffffff80002f9be6 andq %rax, %rdx
ffffff80002f9be9 orq 0xfffffffffffffff0(%rdi), %rdx
ffffff80002f9bed movq %rdx, %r9
ffffff80002f9bf0 shrq $0x20, %r9
ffffff80002f9bf4 movl %edx, %eax
ffffff80002f9bf6 movl 0xffffffffffffffd8(%rdi), %ecx
ffffff80002f9bf9 movq %r9, %rdx
ffffff80002f9bfc testl %ecx, %ecx
ffffff80002f9bfe je 0xffffff80002f9c07
ffffff80002f9c00 wrmsr
ffffff80002f9c02 movl 0xffffffffffffffd8(%rdi), %ecx
ffffff80002f9c05 rdmsr
ffffff80002f9c07 movl %eax, %eax
ffffff80002f9c09 shlq $0x20, %rdx
ffffff80002f9c0d orq %rax, %rdx
ffffff80002f9c10 movq %rdx, (%rdi)
ffffff80002f9c13 addq $0x30, %rdi
ffffff80002f9c17 decl %esi
ffffff80002f9c19 jne 0xffffff80002f9bb0
ffffff80002f9c1b popq %rbp
ffffff80002f9c1c ret
ffffff80002f9c1d nop
ffffff80002f9c1e nop
ffffff80002f9c1f nop

But that just allows us to replace the 0xE2 (or any MSR value) in the tables with zero such that it is never written to. But we need a patch to change the data tables.

One such table is here (xxd<mach_kernel):

062bc80: e200 0000 0200 0000 0000 0000 0000 0000 ................ ; _xcpm_core_scope_msrs (begin) esi=3
062bc90: 0004 0000 0000 0000 0700 001e 0000 0000 ................
062bca0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
062bcb0: e200 0000 0c00 0000 0000 0000 0000 0000 ................
062bcc0: 0004 0000 0000 0000 0500 001e 0000 0000 ................
062bcd0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
062bce0: e200 0000 1000 0000 0000 0000 0000 0000 ................
062bcf0: 0004 0000 0000 0000 0800 007e 0000 0000 ...........~....
062bd00: 0000 0000 0000 0000 0000 0000 0000 0000 ................ ; _xcpm_core_scope_msrs (end)

The patch for this table (three entries) is:

perl -pi -e 's|\xe2(\x00{3}\x02\x00{12}\x04\x00{6}\x07\x00{2}\x1e\x00{20})\xe2(\x00{3}\x0c\x00{12}\x04\x00{6}\x05\x00{2}\x1e\x00{20})\xe2(\x00{3}\x10\x00{12}\x04\x00{6}\x08\x00{2}\x7e\x00{20})|\x00${1}\x00${2}\x00${3}|g' mach_kernel

With these two patches in place, you can boot OS X with the (patched) mach_kernel even when register 0xE2 is locked.

Update #1

I managed to find a 5-byte opcode for (non-sign extend) cmpw $e2,%cx:

            cmpw    $00e2,%cx               ;66 81 f9 e2 00
            je  skip3                   ;74 02

Note that we are comparing cx here, not ecx, so we are comparing only the low-order 16-bits of ecx instead of the full 32-bits. But in all cases, the high-order 16-bits or ecx in this case are always zero (refer to the tables referenced by esi and passed to this function). Not surprising, since MSR register values are not that large.

The side benefit of this is no patching is necessary to the data tables that drive this function, and the rdmsr is allowed to execute.

As such, the following single perl patch can be used instead:

perl -pi -e 's|\x74\x6c(\x48\x83\xc7\x28\x90\x8b\x05\x5e\x30\x5e\x00\x85\x47\xdc)\x74\x54(\x8b\x4f\xd8\x45\x85\xc0\x74\x08\x44\x39\xc1\x44\x89\xc1)\x75\x44(\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x57\xf8\x48\x8b\x47\xe8\x48\x85\xc0\x74\x06\x48\xf7\xd0\x48\x21\xc2\x48\x0b\x57\xf0\x49\x89\xd1\x49\xc1\xe9\x20\x89\xd0\x8b\x4f\xd8\x4c\x89\xca)(\x0f\x30\x8b\x4f\xd8\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x17\x48\x83\xc7\x30\xff\xce)\x75\x99(\x5d\xc3)\x90{7}|\x74\x73${1}\x74\x5b${2}\x75\x4b${3}\x66\x81\xf9\xe2\x00\x74\x02${4}\x75\x92${5}|g' mach_kernel

Note: It uses all seven “spare” nop codes at the end of the function. But a closer look at this code reveals a poorly optimized function anyway. For example there are two instances of movl %eax,%eax:

ffffff80002f9bcd    movl    %eax, %eax              ;89 c0 (like a nop)
...
ffffff80002f9c03    movl    %eax, %eax              ;89 c0 (like a nop)

Note that even the simplest post-codegen optimizer should be able to remove such code.

And the reload of ecx after wrmsr is not necessary:

ffffff80002f9bfe    movl    0xffffffffffffffd8(%rdi), %ecx      ;8b 4f d8 (not necessary!)

So there is actually seven extra bytes for a total of 14 that could be used for extra code here.

Update #2

This patch is also applicable to the 10.8.5 kernel. I haven’t tested it, but the code is exactly the same (and at the same location) in the 10.8.5 kernel.

Note also that the Clover team has added this patch as an automatic on-the-fly patch. Just set “KernelPm” to true in the your config.plist (same section as “KernelLapic” would go).

Update #3

Scratch that on the 10.8.5 kernel. It is slightly different (I got my USB sticks confused!). I will provide an updated patch in a jiffy…

Update #4

Here is the 10.8.5 patch (not tested, but code review looks ok). I will test this later when I have a chance to install 10.8.5 on my laptop.

perl -pi -e 's|\x74\x69(\x48\x83\xc7\x28\x90\x8b\x05\xfe\xce\x5f\x00\x85\x47\xdc)\x74\x51(\x8b\x4f\xd8\x45\x85\xc0\x74\x05\x44\x39\xc1)\x75\x44(\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x57\xf8\x48\x8b\x47\xe8\x48\x85\xc0\x74\x06\x48\xf7\xd0\x48\x21\xc2\x48\x0b\x57\xf0\x49\x89\xd1\x49\xc1\xe9\x20\x89\xd0\x8b\x4f\xd8\x4c\x89\xca)(\x0f\x30\x8b\x4f\xd8\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x17\x48\x83\xc7\x30\xff\xce)\x75\x9c(\x5d\xc3)\x90{7}(\x90{3})|\x74\x70${1}\x74\x58${2}\x75\x4b${3}\x66\x81\xf9\xe2\x00\x74\x02${4}\x75\x95${5}${6}|g' mach_kernel

Update #5

You may have noticed that Apple has recently released 10.9.1. There are two versions of the 10.9.1 update, one for the new Haswell MacBookPro11,x (retina) laptops and another for the rest. The one for Haswell retina machines has a new mach_kernel, version 13.0.2. The code has changed only slightly but still requires a new patch.

The changed patch is as follows:
perl -pi -e 's|\x74\x6c(\x48\x83\xc7\x28\x90\x8b\x05\x46\x37\x5e\x00\x85\x47\xdc)\x74\x54(\x8b\x4f\xd8\x45\x85\xc0\x74\x08\x44\x39\xc1\x44\x89\xc1)\x75\x44(\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x57\xf8\x48\x8b\x47\xe8\x48\x85\xc0\x74\x06\x48\xf7\xd0\x48\x21\xc2\x48\x0b\x57\xf0\x49\x89\xd1\x49\xc1\xe9\x20\x89\xd0\x8b\x4f\xd8\x4c\x89\xca)(\x0f\x30\x8b\x4f\xd8\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x17\x48\x83\xc7\x30\xff\xce)\x75\x99(\x5d\xc3)\x90{7}|\x74\x73${1}\x74\x5b${2}\x75\x4b${3}\x66\x81\xf9\xe2\x00\x74\x02${4}\x75\x92${5}|g' mach_kernel

There are only two bytes different in the search pattern, but since these two bytes are likely to change in each release of the kernel, it probably makes sense to use a wildcard for them. Here is a modified patch that works on both current 10.9 kernels (13.0.0, 13.0.2… what happened to 13.0.1?):

perl -pi -e 's|\x74\x6c(\x48\x83\xc7\x28\x90\x8b\x05..\x5e\x00\x85\x47\xdc)\x74\x54(\x8b\x4f\xd8\x45\x85\xc0\x74\x08\x44\x39\xc1\x44\x89\xc1)\x75\x44(\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x57\xf8\x48\x8b\x47\xe8\x48\x85\xc0\x74\x06\x48\xf7\xd0\x48\x21\xc2\x48\x0b\x57\xf0\x49\x89\xd1\x49\xc1\xe9\x20\x89\xd0\x8b\x4f\xd8\x4c\x89\xca)(\x0f\x30\x8b\x4f\xd8\x0f\x32\x89\xc0\x48\xc1\xe2\x20\x48\x09\xc2\x48\x89\x17\x48\x83\xc7\x30\xff\xce)\x75\x99(\x5d\xc3)\x90{7}|\x74\x73${1}\x74\x5b${2}\x75\x4b${3}\x66\x81\xf9\xe2\x00\x74\x02${4}\x75\x92${5}|g' mach_kernel

Update #6

The same patch provided above works for the 10.9.2 mach_kernel (13.1.0).

Written by racerrehabman

2013/11/25 at 05:28

Posted in Computers

Tagged with , , ,

Guide to Installing Windows 7, Windows 8, Mac OS X Lion, and Ubuntu Multi-Boot

with 282 comments

This is one of my first blog posts.  I’m really not sure what I’ll be writing about on this blog, but most of the time it will involve technology and computers.

Lately, I’ve been experimenting with my Hackintosh computer (an HP ProBook 4350s notebook) thanks to tonymacx86.com and the great folks there.  One very popular question there is how to dual-boot Windows 7 and Mac OS X.  So I decided to write-up the technique I have used to setup my quad-boot system.

Getting Started

Things you need:
– Lion USB prepared with UniBeast (see tonymacx86.com)
– Win7 install media (preferably USB stick with Win7 SP1)
– Win8 install media (USB stick)
– Ubuntu 12.04LTS (USB stick) (see ubuntu.com)
– A blank HDD or SSD ready as install target

Section A (plan your partition scheme)

When setting up a multi-boot system involving Windows it is important to realize you will need to create what is known as a hybrid MBR/GPT partition scheme.  It is necessary to place all partitions intended to be accessed by Windows such that they are in sync’d MBR table.  This means they should be placed first.  For this guide, I will be setting up the following partitions on a 320GB hard drive:

EFI: 200MB, created by Mac OS X Disk Utility when partitioning
Win7: ~60GB, NTFS
Win8: ~60GB, NTFS
Transfer: ~60GB, exFAT (could use FAT32 as well)
Lion:~60GB, Mac OS X Extended (journaled)
Linux-Swap: 8GB (my computer has 8GB memory)
Linux: a bit less than 60GB (amount left), ext4

As a result, the Win7, Win8, and Transfer partitions are accessible to MBR based Windows.  Lion and Linux can access all of the partitions.  The Transfer partition can be used to move data between systems.

Section B (create initial partition scheme)

  1. Boot from the Lion USB key.
  2. Go into Disk Utility
  3. Select Partition tab
  4. Select to repartition as GPT the entire drive.  In my case, I use 5 partitions here (this will give you 5 equal sized partitions, if you want something different, you can do that).  Label, and set the file system type as follows:
    Win7, FAT32
    Win8, FAT32
    Transfer, exFAT
    Lion, Mac OS X Journaled
    Linux, FAT32
  5. Apply your changes, and Quit Disk Utility
  6. Shutdown your computer
  7. Remove Lion USB key.
  8. Insert the Ubuntu USB key, turn on computer and boot from Ubuntu USB
  9. Connect to wireless if necessary (if you don’t have the ethernet cable plugged in)
  10. Open the Ubuntu Software Center application
  11. Go to the Edit menu, and select “Software Sources…”
  12. Check the box for “universe”, then click Close
  13. Run Terminal (easiest way is Ctrl+Alt+T)
  14. Run the following commands:
    sudo apt-get update
    sudo apt-get install gptsync
  15. Copy gptsync to your Linux USB for later use (that way if you have to run it again, you don’t have to reinstall using apt-get above):
    sudo cp /sbin/gptsync /cdrom/gptsync
  16. Now run gparted (go to Ubuntu Home and type gparted, then click on it)
  17. gparted will scan your drives and display the first one
  18. If you have multiple drives in your system, make sure the target drive is displayed (for this guide I have one HDD known under Linux as /dev/sda)
  19. The last partition in the list should be the Linux/FAT32 partition… Delete that partition
  20. Create a new partition (select the unallocated space, then select Partition –> New from the menu)
  21. Make the size 8192 (smaller or larger depending on how much RAM you have)
  22. Set the file system type to ‘Linux-Swap’, and set the Label to ‘Linux-Swap’
  23. Now create another new partition, this time use all remaining space, and set the file system type to ‘ext4’ and Label to ‘Ubuntu’
  24. Select the Win7/FAT32 partition, and Format it as NTFS
  25. Select the Win8/FAT32 partition, and Format it as NTFS
  26. Apply the changes
  27. Select the first NTFS partition (the one that was Win7/FAT32) and label it Win7
  28. Select the second NTFS partition (the one that was Win8/FAT32) and label it Win8
  29. Apply the changes… You should now have a complete partition setup that matches our plan in Section A
  30. Now go back to the Terminal window that you launched earlier, and type the following:
    sudo /cdrom/gptsync /dev/sda
    (note: /dev/sda is the target drive)
  31. Shutdown the computer, and remove the Ubuntu USB key

Section C (Install Windows 7)

  1. Insert your Windows 7 USB key, and boot from it (alternatively, use your Win7 DVD)
  2. Choose your language, click Install Now, accept the license then choose ‘Custom’
  3. You should be able to select the Win7/NTFS partition and click Next.  If you can’t, format that partition (Drive Options within the Windows 7 installer).  If you still can’t install to that partition after formatting, close the Windows 7 Installer, and restart the computer, restarting the Windows 7 installer.
  4. Proceed to completely install Windows 7
  5. At the end of the Install sequence you now have Windows 7 installed with the Windows 7 boot loader
  6. Shutdown the computer, and remove the Windows 7 USB key

Section D (Install Windows 8)

  1. Insert your Windows 8 USB key, and boot from it
  2. Choose your language, then choose ‘Custom’
  3. You should be able to select the Win8/NTFS partition and click Next
  4. Proceed to completely install Windows 8
  5. At the end of the Install sequence you now have Windows 7 and Windows 8 installed using the Windows 8 boot loader (dual boot Win7/Win8 — this will cause trouble when we go to use the Chimera boot loader, but we’ll fix it later)
  6. Shutdown the computer, and remove the Win8 USB key

Section E (Install Lion)

  1. Insert your UniBeast prepared Lion install USB key, and boot from it.
  2. Choose your language
  3. If you proceed to the target selection page, you will probably notice that it won’t allow you to install to the Lion partition created earlier (I’m not sure why, but we fix that in the next step)
  4. Run ‘Disk Utility’ (again).
  5. Choose the ‘Lion’ partition on the left, then ‘Erase’ tab on the right.
  6. Erase (format) it as Mac OS X Extended (journaled)
  7. Quit Disk Utility
  8. You can now select ‘Lion’ as the target partition for Mac OS X install.
  9. Do that and run through the install like normal.
  10. After install, do any post-install stuff you need to do (in my case running HP ProBook Installer v4 to install, among other things, Chimera boot loader)
  11. Shutdown the computer, and remove the Lion USB key.
  12. You should be able to boot from the hard disk now and see the Chimera boot loader (or whatever boot loader you’re using)

Section F (Cleanup Windows BCD bootmgr)

First of all, if you are only installing one Windows operating system (just Windows 7 or just Windows 8), you can skip this section.  Otherwise, read on.

Now that you have Chimera installed, you can use it exclusively to boot between Windows 7 (although it is cumbersome), Windows 8, and Lion.  For now, if you attempt to boot the Win8 partition using Chimera, it will not work, but if you boot Win7 partition using Chimera, you will get the Windows 8 boot menu and you’ll be able to boot either Win7 or Win8 (Chimera is loading the Windows 8 boot loader).  The goal of this section is to fix that so, you can boot directly into the Win7 and Win8 partitions.

Basically what is going on here is that Windows 8 installed the Windows 8 boot loader into the Win7 partition and set up a dual boot between Win7/Win8.  There is no Windows boot loader on the Win8 partition.

Here’s how we fix this mess:

  1. Using Chimera, boot the Win7 partition
  2. You will now see the Windows 8 boot loader with selections for Windows 7 and Windows 8
  3. Choose to boot Windows 8 (Note: If you instead select Windows 7, the Windows 8 boot loader will reboot the computer, you will see the Chimera screen again, and should you select the Win7 partition from there, you will then boot directly to Windows 7)
  4. Once in Windows 8, go to the Desktop, then right click on the bottom-left corner of the screen, from the menu, choose “Command (Admin)”
  5. OK the UAC prompt
  6. You are now in the Windows 8 command line
  7. Some explanation might be handy here if your drive configuration is different than mine.  In my case there is only one HDD, so at this point in Windows 8, the C: drive is the Win8 partition and the D: drive is the Win7 partition.  We need to copy the necessary files for boot from the Win7 partition to the Win8 partition, as the Win8 partition doesn’t have a complete boot loader.  To do this we execute the following commands:
    robocopy d:\Boot c:\Boot /mir /xf bcd.*
    bcdedit /export c:\Boot\BCD
  8. Now we have a copy of the necessary boot files on both the Win7 and Win8 partitions, which will allow us to boot either one from Chimera.  Next we have to make it such that each boot menu contains only Windows 7 or Windows 8, and make it such that the boot menu does not appear.  To do so, you need to follow these instructions carefully.  First of all let’s fix up the Windows 8 boot menu.
  9. First you need to determine the identifier used for the Windows 7 entry in the boot loader.  Run the following:
    bcdedit /store c:\Boot\BCD
  10. This displays information about the BCD menu on the Win8 partition.  You want to look for the second “Windows Boot Loader” entry where it says “identifier”.  That is the entry you want to delete.
  11. In my case the identifier is {408f7757-c9e3-11e0-8a2d-b7f526558aef}, so the command required is:
    bcdedit /store c:\Boot\BCD /delete {408f7757-c9e3-11e0-8a2d-b7f526558aef} /cleanup
  12. We also need to fix up the {bootmgr} device entry:
    bcdedit /store c:\Boot\BCD /set {bootmgr} device partition=C:
  13. After that, you are done with the boot loader on the Win8 partition.  To check your results, type:
    bcdedit /store c:\Boot\BCD
  14. Now you have to fix up the Win7 boot entries, such that they do not include Windows 8. First determine which entry must be deleted:
    bcdedit /store d:\Boot\BCD
  15. It will probably look exactly like the one above before we changed it.  The Windows 8 identifier should be {default}, so to delete it, we use:
    bcdedit /store d:\Boot\BCD /delete {default} /cleanup
  16. Now we need to make it such that the menu doesn’t display in either case:
    bcdedit /store c:\Boot\BCD /set {bootmgr} displaybootmenu no
    bcdedit /store d:\Boot\BCD /set {bootmgr} displaybootmenu no
  17. At that point, we should be done.  You can display your work and double-check it with:
    bcdedit /store c:\Boot\BCD
    bcdedit /store d:\Boot\BCD
  18. Each boot menu should have only one boot menu entry, and they should be pointing to the appropriate partition… Win8 to C:, and Win7 to D:
  19. Restart the computer and try booting into each Win7 and Win8 partitions from Chimera.  It should work with no intervening Windows boot loader menu now.

Section G (Cleanup the Chimera menu)

When you boot your computer, you will notice that the Chimera boot loader picks up on the Transfer/exFAT partition and shows ‘GPT unknown’.  It would be nice to eliminate this from the menu.

  1. To do so, use Chimera to boot into Lion
  2. Once there, bring up a Terminal to determine which partition the exFAT partition is by typing: diskutil list
  3. Look under the IDENTIFIER column.  If you are following this guide exactly, the Transfer partition will be ‘disk0s4’
  4. Now use TextEdit to edit your /Extra/org.chameleon.Boot.plist
  5. Find or add the <Key>Hide Partition</key> section
  6. In the line below it, change or add the line to read:
    <string>hd(0,4)</string>
  7. That should hide the partition 4 on disk 0.
  8. Save the file.
  9. Restart to test, then Shutdown the computer.

Section H (Install Ubuntu)

  1. Turn on the computer and boot using the Ubuntu install USB
  2. Choose the first option, “Run Ubuntu” (do not choose the installer directly)
  3. After you arrive at the Ubuntu desktop, if you’re not connected to the internet, you may want to take this opportunity to do that (via the menu bar at the top of the screen)
  4. After that, choose the second icon down (run the Ubuntu installer)
  5. Answer the various questions about language, then Continue
  6. Eventually, you’ll come to a screen that asks about “Installation Type”. Choose “Something Else” from this screen. This gives you greater control over where Ubuntu installs.  Then click Continue.
  7. It will now scan disks.
  8. Look in the resulting list for the partition made earlier of ‘FAT32’ type, but intended to be the main Linux partition.  In my case, it is /dev/sda7.  Select it and click ‘Change’
  9. Change the ‘Use as’ to ‘Ext4 journaling file system’
  10. Change the ‘Mount point’ to ‘/’ (no quotes), click the checkbox to Format, then click OK.
  11. Find the swap partition created earlier. In my case it is /dev/sda6.  Select it and click ‘Change’.  Verify that it is using it as ‘swap area’ (should already be setup that way).  Click OK.
  12. IMPORTANT! You will want to pay special attention to the ‘Device for boot loader installation’.  Change it to the same ext4 partition we used in steps 8, 9 & 10. This will cause grub2 to be installed on the Ubuntu partition and won’t interfere with the Chimera boot loader already installed.  Again, in my case, it is /dev/sda7.
  13. You are now ready to install Ubuntu, so click ‘Install Now’, ignore the warning about the boot loader installation and Continue.
  14. While it is copying files, you can answer the other questions about Location, Keyboard layout, account, etc.
  15. Skip the part about importing accounts from Windows (ie. no checkbox)
  16. After Ubuntu installs is a good time to check to be sure the hybrid partition scheme is still intact, so don’t restart right when it asks you to.  Instead, bring up a terminal (Ctrl+Alt+T) and type:    sudo /cdrom/gptsync /dev/sda
    (of course, substituting /dev/sda with the real path of your HDD in case it is not /dev/sda)
    Answer Y, if it proposes changes.
  17. Now you are ready to restart and test.  You should now be able to boot Windows 7, Windows 8, Mac OS X Lion, and Ubuntu from the Chimera menu.  You will notice that you see the grub menu in the case of booting Linux, but we can fix that in the next section.

Section I (Cleanup/Disable GRUB2 menu)

  1. Boot into Ubuntu, then run Terminal (Ctrl+Alt+T)
  2. Type the following:
    gksu gedit /etc/default/grub
  3. In the editor, uncomment the GRUB_HIDDEN_TIMEOUT=0, and make GRUB_TIMEOUT=0, then save the file
  4. Back in the terminal, type:
    sudo update-grub
  5. Restart and test.  At this point, if you select Ubuntu from the Chimera boot loader, it should go directly there and you won’t see the GRUB2 menu (if you want it, supposedly you hold down shift while booting… side note: it didn’t work for me).

Section J (Install support for exFAT in Ubuntu)

In order to use the Transfer partition from Ubuntu, you need to install exFAT support as it doesn’t support it natively.  I used exFAT because it is a little more capable that FAT32 (particularly in support for files larger than 4GB)… if you decided to just use FAT32, you can skip this section.

  1. Boot into Ubuntu, then run Terminal (Ctrl+Alt+T)
  2. First we need to install exfat support using apt-get:
    sudo apt-add-repository ppa:relan/exfat
    sudo apt-get update
    sudo apt-get install fuse-exfat
  3. Now you can mount the Transfer (on /dev/sda4 in Linux) partition with:
    sudo mkdir /mnt/transfer
    sudo mount -t exfat /dev/sda4 /mnt/transfer
  4. And you can make it mount automatically, by editing fstab:
    gksu gedit /etc/fstab
  5. Once in the editor, add the following line to the bottom:
    /dev/sda4 /mnt/transfer exfat defaults 0 0
  6. Save, then to mount and check after that edit:
    sudo mount -a

Section K (Disable Fast Startup for Windows 8)

It appears that the new Hybrid Hibernate/Fast Startup feature new in Windows 8 does not work with this Chimera boot scheme.  I would suggest you disable it:

  1. Boot to Windows 8
  2. Go to the Windows 8 Desktop
  3. Right click at bottom left corner of screen, and choose Control Panel
  4. Search for ‘Power Options’
  5. Choose ‘Change what the power buttons do’
  6. Choose ‘Change settings currently unavailable’
  7. Scroll down to Shutdown settings
  8. Untick “Turn on fast startup (recommended)”
  9. Now shutdown from Windows 8 will now work correctly.

Conclusion

If you made it this far, you may be deciding to give it a try.  And if you do, please leave feedback as a comment. And if you find an error, let me know and I’ll try to fix it.  Good luck!

Written by racerrehabman

2012/07/06 at 20:38