Solaris on EFI (iMac)

First, I'd like to point out that Solaris already runs on iMac with BootCamp (see blog by Jan Setje-Eilers). What I'm talking about is getting Solaris booted from EFI without legacy BIOS emulation. To start with, we need Intel's EFI toolkit. With instructions from web search, it was straightforward to get an EFI shell and run sample applications.

Gnuefi and Elilo The next step was to run my own EFI application that can bootstrap Solaris. To do that, I needed to compile my own EFI executable and I didn't want to setup a Windows environment. Naturally, I picked the gnuefi. At first, I downloaded gnu-efi-3.0a, but it didn't compile on my Linux environment. After some web surfing, I found some related postings. Eventually, I moved to gnu-efi-3.0c, which worked fine.

Now I was ready to tackle Solaris specific issues. The first choice I needed to make was whether to have EFI load Solaris directly or via an intermediate efi program. After some experiments, it became clear to me that the EFI execution format should be kept out of Solaris, to make OS more independent of firmware and to avoid legal issues related to using gnuefi to compile Solaris binaries. So I decided to use elilo to load the Solaris multiboot and ramdisk. The code changes are pretty straightforward. I added a "multiboot" loader to elilo, making sure it's run before "plain" elf loader. On the Solaris side, I modified multiboot to disable BIOS calls, console I/O (yikes!), and modified the kernel to use pci probe mechanism 1.

Console I/O? So far so good. But what about console I/O?! Solaris only supports vga/keyboard and isa serial ports as console devices. The iMac has neither (truly legacy free). The first step was to cheat a little bit. I modified elilo not to call ExitBootServices() so I could get some early output in Solaris multiboot program using EFI SimpleText service. It took me a while to figure out that SimpleText stops working if IDT is reloaded or paging is enabled. After pulling all the tricks I could think of, I still wasn't able to get the Solaris banner out on the screen, pretty discouraging for a couple of week's work.

Now I turned my attention of UGA, the EFI's replacement for VGA. The EFI toolkit document refers to a Microsoft webpage describing how to use UGA inside an OS kernel, but the webpage is nowhere to be found. Then I found a Linux paper by Matthew Tolentino describing a UGA implementation in Linux kernel. It was exactly what I was looking for, but the amount of work of daunting. I sent email to the author to see if the code was, by any chance, released (preferrably under a BSD-like license), but it was not to be.

So I can't use the screen and I don't have a serial port. What else? It happened that we have a contact at Apple who informed us that the ICH7 chipset supports a USB debug controller port. This sounded promising, but I wasn't able to find any debug device I can buy. However, this gave me an idea. I could get a USB to serial cable and redirect the Solaris console to the USB serial device. Although the device doesn't work early in boot, I can still boot the system up if the kernel "just worked".

I bought a USB serial cable from Walmart. The cable is made by IOGear based on Prolific PL2303 chipset. There happens to be a Solaris driver for it (usbsprl). I modified the Solaris consconfig_dacf module to work with USB serial device and tried it on a PC that already runs Solaris, the device worked fine. I was very happy and proceeded to set up the software and hardware on the iMac. After elilo printed the expected text on screen, I sat there, waiting anxious waiting for output on the other end of the serial line... nothing happened. The machine seems to have hung.

Desperation I wasn't ready give up, not yet anyway. Since the machine appeared to be hung, I tried some "blind" debugging. To do so, I inserted a call to reset() in the kernel startup code to see if the reset actually happens. By changing the location of the reset() call, I might be able to find out when things went wrong. I was pleasantly surprised to find that the kernel was running fine, but the usb controller failed to attach, hence no console output. My suspicion naturally fell on interrupt controller programming and ACPI processing.

Checking the ACPI info, I noticed that iMac's ACPI memory region is at 8F000 which the ACPICA (Solaris uses intel's ACPICA) expects it to be between E0000 and FFFFF. Naturally, I modified ACPICA to scan 8EFFF, but it didn't work. After consulting is ACPI experts (Dana Myers and David Chieu), I decide to make a last ditch effort to override the ACPI table. Jan has a second iMac running BootCamp (legacy BIOS emulation). I captured the ACPI tables from BootCamp and added them to the Solaris image (see blog by David Chieu ) and tried booting again, it still didn't work.

At this point, I was ready to give up. Hopefully, the next ia32 platform with EFI will have VGA or serial port. There was one last gleamer of hope, that is to workaround the interrupt issue by running USB controller in polled mode. I went to our USB expert, Artem Kachitchkin, who patiently offered some suggestions. I modified uhci and ehci not to add interrupt handlers. Instead, launch a kernel thread to call interrupt handlers every millisec. With this change, I was finally able to get console output on the iMac!

EFI, UGA, and USB debug device It has been quite an experience to get Solaris up on EFI and much work still lies ahead. Overall, I like the overall EFI capability. The EFI shell appears more capable than the OpenBoot Firmware on sparc. The UGA stuff is questionable at best; being part of the BootService (instead of RunTime service), it's pretty much useless for OS booting. The USB debug controller sounds like a good idea, if debug hardware becomes available. I hope other ia32 platforms with EFI firmware can keep some legacy stuff around so that individual OS developers can work on them.

Post a Comment:
Comments are closed for this entry.



« January 2017