PearPC: Mac-In-Boxby Howard Wen
PearPC is a program that runs Mac OS X on a Linux or Windows PC. Technically, this is actually a side benefit, since PearPC's primary purpose is to emulate the PowerPC processor on the x86. As is the case with emulators of advanced processors, especially in the early state that PearPC is currently in, performance is sluggish compared to an actual PowerPC. But there's no denying that it's pretty neat to see the familiar Mac OS X desktop running within a window on a non-Macintosh system.
The PearPC project had its origins in early 2002 when Sebastian Biallas of Aachen, Germany, ported a PowerPC disassembler to HT (a multiarchitecture disassembler, code analyzer, and hex editor). Based on this work, he wrote a program "just for fun" that could boot a complete Linux system from hard disk. He next became interested in figuring out how to use this new program to boot Darwin. "In fact, this wasn't that hard [to do]. I only needed to make a few corrections of previously unnoticed bugs here and there," says the 23-year-old Biallas, a computer science student. "Most of the time was spent searching for bugs, instead of writing new code. Darwin was bootable/installable around December 2003."
In its early state, PearPC functioned very slowly; for every PowerPC instruction, the emulator had to execute, on average, 500 host instructions. To remedy this Biallas developed a just-in-time compiler (JITC) for x86 hosts that could generate equivalent x86 code for every PowerPC instruction. Because this specific code can be cached, the result is faster performance. After this feature was implemented, PearPC Version 0.1 was released in May 2004. Daniel Foesch, a 25-year-old from Albuquerque, New Mexico, has since contributed AltiVec support for the emulator to further hone its compatibility.
PearPC Brings Apple to Linux
The extent of PearPC's emulation of the PowerPC processor is demonstrated in its ability to run OS X, as shown in Figure 1 (click the image to expand it).
Interview with the Developers
Biallas and Foesch spoke with Mac DevCenter about the development of PearPC and the technology behind it.
Howard Wen: What is the current status of PearPC?
Daniel Foesch: With AltiVec, the generic core is correct and working. The JITC is working most of the time but is most likely not correct.
HW: Was PearPC inspired by any other program?
Sebastian Biallas: Not really. But it contains code and ideas from other open source programs. For example, I reused a lot of code I wrote for HT in PearPC, and I looked at other emulators, namely Bochs, to learn about IDE emulation.
HW: What language was used to write PearPC? Any reason why this was chosen?
Biallas: We use C, C++, and x86 assembler (and some shell scripts for configuration). But the C++ code is mainly enhanced C and not "real" C++.
C/C++ was chosen mainly for portability and speed, but other languages like Pascal would be equally useful. For the just-in-time compiler, I need languages where I can execute arbitrary memory; this couldn't be done in script languages or Java.
HW: Does PearPC use code or libraries that the PearPC team did not originally develop? Why were these chosen?
Foesch: Basically, it uses the C library, POSIX OS stuff, Windows OS stuff, BeOS OS stuff, and then there's also SDL stuff and X11 stuff. These were primarily picked because they are the most baseline libraries available and would provide the most amount of portability to the project.
Biallas: As I mentioned, we use some code from HT. This is mainly a set of classes for easy string handling, file I/O, and an abstraction of the OS API (for thread handling, large file support, etc.). I also included the x86 and PowerPC disassembler from HT, but this is only used for debugging purposes at the moment.
Additionally, we use HFS/HFS+ libraries for booting from the disk images.
Last but not least, we use the video driver of MOL, which is mainly used for switching video modes when running Mac OS X as [a] guest OS.
HW: Was any new technology specifically developed for PearPC?
Foesch: The whole project is full of little libraries that provide functionality to various things. The biggest one I can think of would be the JITC framework in the CPU core. It's quite a beast, but it's fun to see that it works.
Seriously, the more I learn about the core, the more I'm amazed that it works, rather than the other way around. Sebastian and Stefan have done an amazing job so far.
HW: What are the major technical limitations of PearPC, thus far?
Biallas: The most visible is the emulation speed. We still need to put a lot of effort into it to make it faster. Some things [are] still very limited, like the sound emulation.
What would be really cool [is] a better video driver that could delegate all video operations directly to the host OS, instead of emulating a slow frame buffer. Unfortunately, this is almost impossible [to do], because we don't have access to the necessary documentation.
Foesch: In the AltiVec core, I'm running into a lot of problems with the limitations of SSE technology. There are a great number of instructions in AltiVec, such as vperm and lvsl, that could be performed really quickly with SSE implementations, but SSE just does not allow for variable operations of its shuffling and Shift Left Double. It also just doesn't really have the granularity on the same scale as AltiVec.
I got in a fight with some guy on OSNews. For him, as a hardcore number cruncher, since AltiVec doesn't support double floating points, he said it was useless. To me, as a general programmer, since the PowerPC already has a very good double-precision FPU core, it's far better to be using that than wasting vector space to perform a dual-parallel operation on a vector. And SSE having the total lack of granularity and flexibility that AltiVec has totally turns me off to the SSE architecture. But then I've been a little disenchanted with the whole x86 architecture already.
HW: What have been the biggest technical challenges you have faced in developing PearPC?
Foesch: Getting SSE to work right. I write an implementation for just two functions anywhere in SSE, and it breaks something. It's very frustrating. Usually it's not a problem in any of my implementation; it's a problem somewhere else, like some function not flushing the vector registers before it hits an exception, or something like that. Unfortunately, the result is that I end up with code that works... some of the time. Finding those bugs is the hardest thing in programming.
Biallas: I can't remember anything that was really technically challenging. But I was confronted with a lot of things that were challenging in another sense: During development I had to find some bugs that were really hard to track down. I remember an IDE problem that I couldn't find for three weeks. It's really hard not to give up because of such problems.
HW: What are some of the major issues when it comes to emulating the PowerPC processor?
Biallas: It isn't that complicated to emulate a PowerPC processor. In fact, I'd bet it's much more complicated to emulate an x86 processor.
The problems begin when you try to archive fast emulation of a PowerPC (of course, this also applies to other processors). PearPC currently tries to archive this by generating one or more x86 instructions for every PowerPC instruction. So, once PowerPC code is executed more than one time, the equivalent x86 code is ready and can be executed.
Since the x86 platform had less visible registers than the PowerPC's, the mapping between x86 and PowerPC registers is somehow arranged dynamically to optimize the code. One thing I really have to add here is that modern x86 processors don't have less general-purpose registers than PowerPCs. This is often confused since only eight x86 registers are visible for the programmer. But, internally, they have 100+ registers which are dynamically assigned to the eight visible registers. This is transparent for the programmer. [This is] not directly related to PearPC, but I think it is a good place to debunk this myth.
Foesch: For the AltiVec core, it's the fact that AltiVec and SSE don't match up very well. Just about all of the raw arithmetic and logic instructions are functionally equivalent, but all of the support functions are horribly mismatched. SSE took the CISC approach, and AltiVec took the RISC approach. So I end up having to emulate a lot of things that shouldn't have to be done.
As for the core in general, it's a problem of register space. We have seven 32-bit registers to do all our work with on the x86. Those have to map thirty-two 32-bit GPRs and even more special-purpose registers. Occasionally, I need a few to do my AltiVec emulation. And with the HWMMU [Hardware MMU] branch, that's going to be cut down to about six registers most of the time, too.
HW: Could the code for PearPC be reused for other purposes? For example, could it be used as a means to port Mac OS X code?
Foesch: The PearPC CPU core could probably be drag-and-dropped into another project, but it would be a hard-going thing to do. But as a means to port OS X code? No. There's nothing in PearPC that is OS X-specific, so it wouldn't help porting.
Biallas: One could take the CPU emulation core of PearPC and put it into the x86-Darwin kernel to make x86-Darwin run PowerPC executables. The SoftPear project is trying to achieve this, not with PearPC's code but with a different CPU emulation. This might get into license problems, though.
HW: What features are you adding to the next version of PearPC?
Foesch: Working on jitc AltiVec, and HWMMU is what we're shooting for as the biggest two things to come in. Both of these would help performance a lot.
Biallas: I am working on an optimized MMU (memory management unit) that makes use of the host processor's MMU. The Windows native CD-ROM patch should be merged soon, which enables the use of a "real" CD-ROM drive for the Windows version (no need for CD images). We're also working on a sound card emulation.
HW: What would you like others to pay notice to the most about PearPC?
Foesch: Just the coolness of PearPC. Being able to run OS X on a normal x86 computer at decent speeds is incredible. This is really the first viable option for that.
Biallas: Developers might be interested in the PearPC license: PearPC is free software released under the GPL. And I'm especially proud of PearPC's platform independence; all OS API calls are (more or less) cleanly separated so that it can be easily ported to new platforms.
HW: Got any advice for those who are interested in developing their own emulator?
Biallas: They should have good documentation. I don't think PearPC would have been possible without good documentation about PowerPC processors and Apple computers.
Foesch: Get the original documentation straight from the company that makes the material. Collect as much information as you can about the pieces you'll have to emulate, and then seek to emulate them as exactly as possible.
Also, once you've got your core all up and coded, the hardest time debugging you'll have in your life is debugging your core. A CPU core is by far the most difficult thing to debug in the world. Learn how to "white-box test" your code. Most of the time, the only way you'll find bugs is to slowly read through all your code and think about if it's working right.
HW: If somebody wants to contribute to your project, what skills from them could you use now?
Foesch: The ability to dive into the code without much help. I've always felt that the greatest skill anyone can have is the ability to read code, like it's a book or story: Sit down, read a couple pages, and get a clue as to what the code is doing.
I've been on the project for a short time, but just because of my ability to read code, I've become pretty influential. I'm actually now at a point where I understand how the code works and the general framework of how things are done. If you really want to be able to contribute to an open source project, it can't be overestimated how important the ability to read code is.
If you can just look at a short snippet of code, and realize the logic flow, and how everything is supposed to fit together, you're already most of the way through solving whatever problem.
Return to the Mac DevCenter.