Developers/Technical Information

From OnMac.net Wiki
Jump to: navigation, search
Error creating thumbnail: Unable to save thumbnail to destination
Back to Developers

This page contains in-depth information about the solution.

Background

This section describes the sequence of events that lead to a successful Windows setup boot.

These are the files that get loaded while Windows is booting setup from a CDROM:

  • Boot sector

This portion is filesystem specific. For a CDROM, the boot sector understands ISO-9660. It locates the file I386/BOOTLDR.BIN, loads it and then transfers control to it.

  • BOOTLDR.BIN

A real mode program, BOOTLDR.BIN contains an embedded PE executable (setupldr.exe) which it extracts and relocates to its default address. It then transitions into protected mode and transfers control to the relocated image.

  • setupldr.exe / osloader.exe

Several things happen during this phase. First NTDETECT.COM, a real mode program, is executed. The CPU is temporarily switched back into real mode for this task. During this time, hardware is detected and stored in a configuration tree. The screen displays the "Setup is detecting your hardware" message. Once NTDETECT.COM returns, the NT kernel, the default HAL and all the boot drivers defined in TXTSETUP.SIF are loaded. Although running in protected mode, this code still relies entirely on the BIOS to perform any I/O. This is done by calling entry points defined in BOOTLDR.BIN, which transition into real mode after copying stack parameters, perform a specific task and then jump back into protected mode. During this time, the machine is still operating in "text mode" with the drivers loaded displayed at the bottom row of the screen. Eventually the "Setup is starting Windows" message is displayed, at which time, the next phase is entered.

  • ntoskrnl.exe, hal.exe, boot drivers (*.sys files)

Windows finally starts. Memory managment (paging) is setup. The idle thread is started. The IO subsystem is initialized in two phases. Boot drivers loaded by setupldr are given a chance to initialize and create any devices they manage (for legacy devices) or listen to managed devices (for plug and play devices). Kd debugging is now possible and encouraged.

MBR Mirroring

Video

Windows comprises a disparate set of modules which interact in a specific way to cause the setup to always run in text mode. This is the case even when some components (setupdd.sys - the text setup main driver) are written to support graphics modes.

The first thing Windows does is detect the Video hardware. This is done as part of SETUPLDR's hardware detecting phase. Unfortunately this seems to be hardcoded as follows:

void DetectVideo(DEVICE* pDevice) {
  ...
  pDevice->VideoId = strdup("VGA");
  ...
}

Later, while loading boot drivers, SETUPLDR maps the video id using the TXTSETUP.SIF entry [Display.Load].

Xom could be improved if instead of patching vga.sys, it used xomdd.sys instead by setting:

[Display.Load]
vga=xomdd.sys

However, at the time of this writing, vga maps to vga.sys, which later gets patched in memory by the time-based patching engine built into xom.efi.

Once Windows starts and during I/O initialization, the video driver is initialized and given a chance to create its device \Device\Video0.

Finally, setupdd.sys is given control. This device driver is the main driver of the text mode setup. It opens the video device \Device\Video0, enumerates all available modes using the following algorithm to choose the correct one:

TextMode = NULL;
ChosenMode = NULL;
foreach VideoMode {
  if (VideoMode.isText) {
    TextMode = VideoMode;
  }
  if (VideoMode.isGraphic && VideoMode.XRes >= 640 && VideoMode.YRes >= 480) {
    ChosenMode = VideoMode;
    break;
  }
}
if (TextMode != NULL)
  ChosenMode = TextMode;

So, in a few words, if there's a text mode available, it takes it. Otherwises, it chooses the first Graphics mode >= (640,480).

Unfortunately, vga.sys comes preloaded with the eight VGA video modes. One of them being the 80x25 text mode available in all VGA cards. This being the case, setup chooses to use it, after configuring it with a smaller font so that more rows are available.

xomdd.sys circuments this issue by removing the preloaded video modes. Additionally, it queries the available modes via the VESA BIOS SVGA GetModeInfo call. This in turn is implemented in xom.efi to return only one mode, which is a linear RGBA mode which matches the EFI graphics mode.

Under this circumstances, setupdd.sys has no choice but choose this only available mode. To whoever wrote setupdd.sys' credit, it was written to support all imaginable modes, be it an arbitrary sized text mode or graphics mode. The graphic mode being either palette-indexed or direct color, as well as plane-based or linear frame buffer-based. A shame that all of this goes to waste on any x86 install thanks to the thick-headedness of vga.sys.

More information about video from: http://daemons.net/~clay/index.php/2006/03/15/dual-booting-windows-xp-and-mac-os-x-on-intel-macs/#comment-138

Yes, getting VGA to work was a pain in the butt. It consisted of mainly three steps:

  1. Disable IGD (internal graphics device) from decoding legacy VGA IO ports (PCI configuration on i945)
  2. Enable legacy VGA forwarding on the PCIX bus (PCI conf i945 too)
  3. Configure M56 to enable framebuffer at 0xB8000 (done through legacy VGA ports)

Here’s the code that does that:

UINT8 cr[] = { 0×5f, 0×4f, 0×50, 0×82, 0×55, 0×81, 0xbf, 0×1f, 0, 0xc7, 6, 7, 0, 
0, 0, 0, 0×9c, 0×8e, 0×8f, 0×28, 0×1f, 0×96, 0xb9, 0xa3, 0xff };
UINT8 sr[] = { 0, 1, 3, 0, 2 };
UINT8 gr[] = { 0, 0, 0, 0, 0, 0×10, 0xe, 0, 0xff };
UINT8 ar[] = { 0, 1, 2, 3, 4, 5, 6, 7, 0×10, 0×11, 0×12, 0×13, 0×14, 0×15, 0×16,
0×17, 8, 0, 0xf, 0, 0 };
poke8(0xE0000052, 0); // disable IGD from reading VGA addresses
poke8(0xE0000054, 0×83); // disable IGD altogether
poke8(0xE000803E, 0xC); // enable VGA 16-bit decode for PCIX devices (M56)
out8(0×3c2, 0×63); // enable frame buffer access
ioFeed(0×3b4, 0×3b5, cr, sizeof(cr));
ioFeed(0×3c4, 0×3c5, sr, sizeof(sr));
ioFeed(0×3ce, 0×3cf, gr, sizeof(gr));
ioFeed(0×3c0, 0×3c0, ar, sizeof(ar));

Anyway, I will release the source code soon… I’m sure we can join all that we learned to make this rock solid…