Wednesday, May 11, 2011

Chimera v1.1.0 Source Pedigree and Enhancements

Most of you know about Chimera based on the announcement we made on the tonymacx86 Blog. A few of you are interested in what I did and what is different in Chimera compared to the Chameleon trunk. Without getting too deep into the code, I will attempt to explain in general terms these differences. I will be explaining the changes based on v1.1.0 r753 as this was the first source version released.

I wanted to start with the trunk version as I know that code is clean and stable. The first few things I did was fix a few spelling errors in TODO and i386/doc/README. No big deal, but I think something that was overdue. Next, I went through all of the source files. I cleaned up the comments for readability to make sure they all lined up properly. Here are the list of files that I did this to:

i386/boot2/boot.h
i386/libsa/memory.h
i386/libsaio/bootstruct.h
i386/libsaio/cpu.h
i386/libsaio/fdisk.h
i386/libsaio/memvendors.h
i386/libsaio/nvidia.c
i386/libsaio/smbio_patcher.c
i386/libsaio/smbio_patcher.h
i386/libsaio/spd.c

Again, not a big deal, but to make it easier for me to read the code.

So now it was time to start merging features. I decided to start with Kabyl's ATI support. For this I had to update doc/BootHelp.txt to include his 2 new boot keys. I also added the two actual boot keys to i386/boot2/boot.h. Then in i386/libsaio/, I replaced the trunk ati.c with Kabyl's. Added his ati_reg.h and removed ati.h. Then I added Kabyl's changes to pci.cpci.h and pci_setup.c.

Next was merging valv's NVIDIA changes. For that I added 2 new NVIDIA keys to i386/boot2/boot.h. Then in i386/libsaio/nvidia.c I used a combination of trunk, valv and new device ID's I could find to support as many cards as possible in NVKnownChipsets. I then used valv's #define NVIDIA_ROM_SIZE 0x20000 and  static uint8_t default_dcfg_0[]static uint8_t default_dcfg_1[], and static uint8_t default_NVPM[]. I also used his improved video RAM detect code, workaround code for gt 430 & 9600M GT and support for user supplied @0,display-cfg and @1,display-cfg keys.

The final changes were in adding Sandy Bridge support. For this I used some of valv's code but added a bunch of my own. From valv I used his setup features which required using his CPU Features in platform.h. Where I also took his #define bit definitions. Then in cpu.h I used his additional MSR defines and static inline __attribute__((always_inline)) void wrmsr(unsigned val, msr_t msr), typedef struct msr_struct and static inline __attribute__((always_inline)) msr_t rdmsr(unsigned val). And finally some of his CPU debug messages and formatting at the end of cpu.c.

So as documented above, I've reused a bunch of code from Kabyl and valv. Now let's discuss the changes I did. The first thing is in platform.h where I added #define CPU_MODEL_DUNNINGTON 0x1D and #define CPU_MODEL_SANDY_BRIDGE 0x2A. Then in cpu.c I changed all p->CPU.Model from using hex values to defined values from platform.h. I did this to make troubleshooting easier- as I don't know all of the CPUs model codes by heart. I then removed p->CPU.Model == 0x1f as I can find no reference anywhere of this CPU model. I then went and redid  if ((p->CPU.Vendor == 0x756E6547 /* Intel */) && ((p->CPU.Family == 0x06) || (p->CPU.Family == 0x0f))) to add Sandy Bridge support.

When testing the code I found that cpu.c was reporting 8 cores and 16 threads for Core i and Sandy Bridge CPUs. It took a bit of digging but I found that in the original code the value for them was being extracted from a Machine Specific Register (MSR) that was returning the Maximum # of addressable IDs for logical processors in this physical package and Maximum # of addressable IDs for processors cores in this physical package. So I did a bunch of testing and research and found that there is an undocumented MSR, MSR_CORE_THREAD_COUNT that will return the correct values. I used that in Chimera v1.0.0 r750 but we soon learned that that isn't a valid MSR on Penryn or earlier CPU models.  So in v1.1.0 I added the following code to set the number of cores and threads correctly:

if ((p->CPU.Vendor == 0x756E6547 /* Intel */) &&
    (p->CPU.Family == 0x06) && (p->CPU.Model >= 0x1a)){
msr = rdmsr64(MSR_CORE_THREAD_COUNT);            // Undocumented MSR
p->CPU.NoCores = bitfield((uint32_t)msr, 31, 16);     // Get actual values
p->CPU.NoThreads = bitfield((uint32_t)msr, 150);   // Get actual values
} else {  // Use previous method for Cores and Threads
p->CPU.NoThreads = bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16);
p->CPU.NoCores = bitfield(p->CPU.CPUID[CPUID_4][0], 31, 26) + 1;
}

I also changed the Mobile CPU test from using a hex value to the MSR name MSR_IA32_Platform_ID.

Next up was  i386/libsaio/acpi_patcher.c. Here I removed the case 0x0D: statement as this CPU model family Dothan, pre-dates the Core family. I also added a case CPU_MODEL_SANDY_BRIDGE: and added comments for what each CPU model covers. So for example:

 case CPU_MODEL_FIELDS:// Intel Core i5, i7, Xeon X34xx LGA1156 (45nm).

In  i386/libsaio/spd.c I changed smbus_controllers[] to report "5 Series" instead of "P55" and added {0x8086, 0x1C22, "6 Series",read_smb_intel }.

The final source file to modify was i386/libsaio/smbios_patcher.c. Here I also added better CPU comments like in acpi_patcher.c. I also changed all reference of "Apple Computer, Inc." to "Apple Inc.",  fixed MacPro3,1 "SMboardproduct" and MacPro4,1 "SMboardproduct" to use the correct board numbers and finally reorganized the system order to MacBook, MacBook Pro, mini, iMac8,1, iMac11,1 MacPro3,1 and MacPro4,1. The I removed all instances of case 0x19: // Intel Core i5 650 @3.20 Ghz as I couldn't find any references to this CPU model and the description didn't match the model value. I also removed  case 0x0D:  and added case CPU_MODEL_SANDY_BRIDGE:. Other changes were adding DBG("FSBFrequency %d\n", Platform.CPU.FSBFrequency); and changing DBG("qpimult %x\n", qpimult); to display in hex instead of decimal. The final changes were hard coding the Processor Interconnect speed for Sandy Bridge CPUs to 4.8 GT/s instead of the incorrect calculated value. Finally I redid sm_get_cputype to correctly handle all possible CPU types, including Xeons.

In addition, I took from tonymacx86.com forum user AndyStubbs his code additions to support the AMD Radeon HD 6000 cards and his fix to i386/libsaio/smbios_patcher.c for DMI table overflow on Sandy Bridge systems. Thanks Andy.

Going forward the plan is to keep Chimera updated with trunk revisions in addition to adding new features and bug fixes.

I will post further code changes when I release new versions. So stay tuned for updates.

Further Reading:
Chimera Source
Chimera: Unified Chameleon Bootloader
Chimera Now An Official Chameleon Branch
Chimera 1.1 Update
Chimera 1.3 Update
Chimera at tonymacx86 Wiki

5 comments:

Anonymous said...

I just decided to build a osx86 mac because my friend did it and sent me to tonymacx86 for instructions. I just read this post, which deeply impressed upon me your dedication to the project. I sent a small contribution... Thank you!

Anonymous said...

Hi Macman,
Thanks for the explanation of your work. I, reading your comments you are refering to Sandy bridge cpu model as 0x2A . However in your codeley a itle bit further you are testing for cpu model 0x1A as Sandy bridge CPU model?
Which one is correct I looked at your code you are using 0x1A but I think it should be 0x2A as you mention in your comments above.

Can you also please publish the boot options that you support.

Thanks again and good luck with your work.

Anonymous said...

Which one is the right one in text description or in your code? In your text you are talking about 0x2A as cpu type, in your code I also checked it on your trunk you have 0x1A instead? I think your code should be corrected to 0x2A? am I mis reading or this is a bug?
f ((p->CPU.Vendor == 0x756E6547 /* Intel */) &&
(p->CPU.Family == 0x06) && (p->CPU.Model >= 0x1a)){

MacManx86 said...

You are miss reading it, the line of code you quoted reads: If the cpu vendor is Intel and then if the CPU family is 0x06 and the model is GREATER THAN or equal to 0x1a. It's very easy to miss the greater than symbol.

Fandy Alonso said...

It has taken me ages to discover your site. Finally. This is just the information I was looking for.

Post a Comment