<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>~clay &#187; mac</title>
	<atom:link href="http://daemons.net/~clay/tag/mac/feed/" rel="self" type="application/rss+xml" />
	<link>http://daemons.net/~clay</link>
	<description>merely my musings</description>
	<lastBuildDate>Mon, 10 May 2010 17:48:58 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Dual-booting Windows XP and Mac OS X on Intel Macs</title>
		<link>http://daemons.net/~clay/2006/03/15/dual-booting-windows-xp-and-mac-os-x-on-intel-macs/</link>
		<comments>http://daemons.net/~clay/2006/03/15/dual-booting-windows-xp-and-mac-os-x-on-intel-macs/#comments</comments>
		<pubDate>Wed, 15 Mar 2006 20:39:29 +0000</pubDate>
		<dc:creator>clay</dc:creator>
				<category><![CDATA[Geek]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://daemons.net/~clay/?p=50</guid>
		<description><![CDATA[I had hoped to use this blog entry to post step-by-step instructions for installing Windows XP on shiny new MacIntels, but alas, it appears that someone has beaten me to it. The winners, narf2006 and blanka, have been working on the problem for quite a while and have been posting pictures of their progress over [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/cwaidoh/4345926802/"><img alt="OSXP" src="http://farm3.static.flickr.com/2732/4345926802_8435b94027_m.jpg" title="OSXP" class="alignleft" width="240" height="180" /></a>I had hoped to use this blog entry to post step-by-step instructions for installing Windows XP on shiny new MacIntels, but alas, it appears that someone <a href="http://windowsxp.onmac.net/">has beaten me to it</a>. The winners, narf2006 and blanka, have been working on the problem for quite a while and have been posting <a href="http://www.flickr.com/photos/32436196@N00/110977744/in/photostream/">pictures of their progress</a> over the past few weeks. Today they uploaded a <a href="http://youtube.com/watch?v=nzH6OFpXgzI">video </a>showing a fresh install of XP on an iMac and they submitted their solution to sud0n1m for testing. Assuming the testing goes well, they will be declared the winners and will share the $13k prize.</p>
<p>While I&#8217;m disappointed not to have won, I&#8217;m encouraged to see that our approaches were remarkably similar. We both wrote custom EFI CSM drivers to emulate the BIOS functions Windows requires to boot. I&#8217;m very curious how they managed to get VGA working, and I won&#8217;t be surprised if it doesn&#8217;t work in either the Mini or the Macbook Pro, as it looks like they did all their development on an iMac.</p>
<p>If nothing else, this was a tremendous learning experience for me, and the timing couldn&#8217;t have been better. I have recently become interested in Intel assembly and protected mode programming, topics I considered too challenging years ago when I was doing DOS programming, but concepts that make much more sense to me now. I had randomly dusted off some old assembly language references from my bookshelf and read some chapters on protected mode programming a few weeks prior to beginning work on this project, so I was able to grasp what needed to be done to provide a working solution almost immediately.</p>
<p>With the deadline fast approaching and narf&#8217;s Flickr images haunting me, I coded quickly and didn&#8217;t spend much time making the code pretty or maintainable, but I&#8217;m still fairly proud of the code I wrote. It&#8217;s fairly succinct, but does quite a bit. Anyone who&#8217;s interested can <a href="http://github.com/claymation/osxp/tree/master">peruse the code here</a>.</p>
<p>The main function is in OSXP.c, which contains code for reading the GPT partition table that Mac OS X uses, writing a MBR partition table that Windows would use, and loading a bootloader from an El Torito bootable CD-ROM.</p>
<p>Code to switch from protected mode to real mode (called a <a href="http://en.wikipedia.org/wiki/Thunk">thunk</a>) is in thunk.c and asmthunk.s. It&#8217;s not very general, but it&#8217;s the first protected mode assembly code I&#8217;ve ever written, and, surprisingly enough, it works.</p>
<p>Code to setup a real-mode interrupt vector table and the real-mode interrupt service routine is in rmisr.s. For the most part, this duplicates the thunk code, but in reverse order: it switches from real mode to protected mode and then back again. This reverse thunk is necessary to emulate BIOS functions using the native EFI functions (read disk sector, print character, etc).</p>
<p>The protected-mode interrupt service routine, which does the actual BIOS emulation, is in pmisr.c. It reads and writes a saved register context on the stack that the real-mode code inherits upon return from the interrupt service routine.</p>
<p>Just writing those thunk and interrupt service routines is probably about 50% of a complete solution, and I&#8217;m very happy with how they came out. The first time I thunked into the MBR code, it worked better than I expected, and actually identified the active partition, loaded the boot sector from it, and jumped to it. Booting into the CD bootloader worked also, though it hung right after probing memory.</p>
<p>I&#8217;m pretty amazed that my code works, but to toot my own horn a little more, I&#8217;m pretty happy with some of the debug techniques I came up with along the way. Running EFI applications in the pre-boot environment leaves a lot to be desired. You can&#8217;t exactly fire up gdb and throw a bunch of watchpoints on your code to find out what&#8217;s going wrong (though I did toy with the idea of compiling GDB for EFI). And even if I had a debugger at my disposal, it&#8217;s hard to debug a protected mode/real mode transition.</p>
<p><a href="http://www.flickr.com/photos/extraspecial/107310593/in/set-72057594074203534/"><img alt="Take a picture now!" src="http://farm1.static.flickr.com/40/107310593_31eff49e81.jpg" title="Take a picture now!" class="alignleft" width="406" height="500" /></a>At first, my debugging consisted of writing copious amounts of debug output to the console and waiting for my tester, Chris, to run the code and <a href="http://www.flickr.com/photos/extraspecial/107310668/in/set-72057594074203534/">take a picture of the result</a>. At that time I didn&#8217;t have an Intel Mac to play with, so needless to say, progress was slow. We did get fairly far with this method, though. I wrote all of the partition table (GPT and MBR) code without ever having seen my code run with my own eyes. <a href="http://www.flickr.com/photos/extraspecial/sets/72057594074203534/">Chris&#8217; pictures</a> showed me what I needed to know, then I&#8217;d make a change, recompile, and Chris would download the new file and reboot. Again and again. Thanks, Chris.</p>
<p>I was unsure of how to access the CD-ROM under EFI, because it didn&#8217;t show up when I listed all the block I/O devices in Chris&#8217; Macbook Pro. Ryan was nice enough to lend me his shiny new Mac Mini, and I was pleased to find that the CD-ROM device showed up once there was a disk in the drive. I was even more pleased to see that my El Torito code worked almost flawlessly from the beginning.</p>
<p>Then came the hard part, thunking into real mode. I wrote code and pored over it for hours making sure it looked right, but when I ran it, the computer spontaneously rebooted. Unsure of which instruction(s) were causing the reboots, I added an infinite loop to a section of the code, recompiled, and ran it. The machine hung. That validated that all of the code above the loop was not causing the reboot (at least not directly), so I moved the loop down a few instructions and tried again. Using this technique I was eventually able to find all of the bugs in my code, which were all stupid syntax problems and not logic problems (there&#8217;s a big difference between $0&#215;10 and 0&#215;10 in AT&amp;T assembly).</p>
<p>Once the thunk and interrupt handler code was working, I started looking into why NTLDR was hanging after probing memory. NTLDR is 233kb and its disassembly is 97k lines long. I knew roughly where the hang occurred, based on the output I had from the last BIOS interrupt it invoked, but I wanted to narrow it down to a specific routine.</p>
<p>It occured to me that I could just write my own debugger of sorts. By handling interrupt 3, my code would get control anytime the NTLDR code stumbled onto an INT3 instruction. So, using the disassembly listing as a guide, I made a  list of instructions that I thought might be interesting stopping points, and wrote a routine to replace those instructions with 0xCC (the INT3 opcode). Then I wrote an INT3 handler that replaced the original instruction and decremented the return address by one so the original code would be run upon return from the interrupt service routine. And, to my surprise, it worked!</p>
<p>Earlier today I extended this a bit by automatically enabling trap mode in the INT3 handler so I could repatch the breakpoint instruction with 0xCC right after executing the original code. This change allowed a breakpoint to show up each time through a loop or each time a particular function was called. Then I went a step farther and added a breakpoint option that would leave trap mode enabled, so I could get a trace of every instruction executed between two points in the code. This would prove useful for figuring out which branches the program took as it made various tests and decisions.</p>
<p>The one thing that continues to elude me is how to enable VGA text mode. The standard graphics and text framebuffers (0xA0000 and 0xB8000) aren&#8217;t even mapped in memory, and reading from the VGA registers appears to return garbage. I suspect if I knew more about PCI programming, I&#8217;d be able to map the framebuffer memory and configure the I/O ports, but I&#8217;m at a loss for how to do that. In the interim, I&#8217;ve been patching NTLDR at load time so that it writes to my own text framebuffer, which I then scan on every interrupt in order to paint a portion of the emulated textmode screen. This is slow and hackish, and I know it&#8217;s possible to enable true VGA mode (narf and blanka did), but I don&#8217;t know where to begin.</p>
<p>All in all I&#8217;m pretty happy with the code I wrote, even though I didn&#8217;t win the contest. I&#8217;m looking forward to the next big challenge and an opportunity to use some of the techniques I learned on this project.</p>
]]></content:encoded>
			<wfw:commentRss>http://daemons.net/~clay/2006/03/15/dual-booting-windows-xp-and-mac-os-x-on-intel-macs/feed/</wfw:commentRss>
		<slash:comments>51</slash:comments>
		</item>
	</channel>
</rss>
