Version 0.1.2
diff --git a/src/post.c b/src/post.c
index a6dd424..3049001 100644
--- a/src/post.c
+++ b/src/post.c
@@ -14,6 +14,7 @@
 
 #define bda ((struct bios_data_area_s *)0)
 #define ebda ((struct extended_bios_data_area_s *)(EBDA_SEG<<4))
+#define ipl ((struct ipl_s *)(IPL_SEG<<4))
 
 static void
 init_bda()
@@ -62,12 +63,13 @@
 static void
 init_ebda()
 {
+    memset(ebda, 0, sizeof(*ebda));
     ebda->size = EBDA_SIZE;
     bda->ebda_seg = EBDA_SEG;
     bda->ivecs[0x41].seg = EBDA_SEG;
-    bda->ivecs[0x41].offset = 0x3d; // XXX
+    bda->ivecs[0x41].offset = offsetof(struct extended_bios_data_area_s, fdpt0);
     bda->ivecs[0x46].seg = EBDA_SEG;
-    bda->ivecs[0x46].offset = 0x4d; // XXX
+    bda->ivecs[0x41].offset = offsetof(struct extended_bios_data_area_s, fdpt1);
 }
 
 static void
@@ -222,22 +224,64 @@
            - 0x400);
     keyboard_init();
 
-    // XXX
+    // mov CMOS Equipment Byte to BDA Equipment Word
     u16 eqb = bda->equipment_list_flags;
-    eqb = (eqb & 0xff00) | inb_cmos(CMOS_EQUIPMENT_INFO);
-    bda->equipment_list_flags = eqb;
+    bda->equipment_list_flags = (eqb & 0xff00) | inb_cmos(CMOS_EQUIPMENT_INFO);
+}
+
+static u16
+detect_parport(u16 port, u8 timeout, u8 count)
+{
+    // clear input mode
+    outb(inb(port+2) & 0xdf, port+2);
+
+    outb(0xaa, port);
+    if (inb(port) != 0xaa)
+        // Not present
+        return 0;
+    bda->port_lpt[count] = port;
+    bda->lpt_timeout[count] = timeout;
+    return 1;
 }
 
 static void
 lpt_setup()
 {
-    // XXX
+    u16 count = 0;
+    count += detect_parport(0x378, 0x14, count);
+    count += detect_parport(0x278, 0x14, count);
+
+    // Equipment word bits 14..15 determing # parallel ports
+    u16 eqb = bda->equipment_list_flags;
+    bda->equipment_list_flags = (eqb & 0x3fff) | (count << 14);
+}
+
+static u16
+detect_serial(u16 port, u8 timeout, u8 count)
+{
+    outb(0x02, port+1);
+    if (inb(port+1) != 0x02)
+        return 0;
+    if (inb(port+2) != 0x02)
+        return 0;
+    outb(0x00, port+1);
+    bda->port_com[count] = port;
+    bda->com_timeout[count] = timeout;
+    return 1;
 }
 
 static void
 serial_setup()
 {
-    // XXX
+    u16 count = 0;
+    count += detect_serial(0x3f8, 0x0a, count);
+    count += detect_serial(0x2f8, 0x0a, count);
+    count += detect_serial(0x3e8, 0x0a, count);
+    count += detect_serial(0x2e8, 0x0a, count);
+
+    // Equipment word bits 9..11 determing # serial ports
+    u16 eqb = bda->equipment_list_flags;
+    bda->equipment_list_flags = (eqb & 0xf1ff) | (count << 9);
 }
 
 static u32
@@ -295,40 +339,64 @@
 static void
 cdemu_init()
 {
+    // XXX
     //ebda->cdemu.active = 0;
 }
 
 static void
 ata_init()
 {
+    // XXX
 }
 
 static void
 ata_detect()
 {
+    // XXX
 }
 
 static void
 hard_drive_post()
 {
+    // XXX
 }
 
+
 static void
 init_boot_vectors()
 {
+    // Clear out the IPL table.
+    memset(ipl, 0, sizeof(*ipl));
+
+    // Floppy drive
+    struct ipl_entry_s *ip = &ipl->table[0];
+    ip->type = IPL_TYPE_FLOPPY;
+    ip++;
+
+    // First HDD
+    ip->type = IPL_TYPE_HARDDISK;
+    ip++;
+
+    // CDROM
+    if (CONFIG_ELTORITO_BOOT) {
+        ip->type = IPL_TYPE_CDROM;
+        ip++;
+    }
+
+    ipl->count = ip - ipl->table;
+    ipl->sequence = 0xffff;
 }
 
-static void __attribute__((noinline))
-call16(u16 seg, u16 offset)
+static void
+callrom(u16 seg, u16 offset)
 {
-    u32 segoff = (seg << 16) | offset;
-    asm volatile(
-        "pushal\n"  // Save registers
-        "ljmp $0x20, %0\n" // Jump to 16bit transition code
-        ".globl call16_resume\n"
-        "call16_resume:\n"  // point of return
-        "popal\n"   // restore registers
-        : : "Z" (OFFSET_call16), "b" (segoff));
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.es = 0xf000;
+    br.di = OFFSET_pnp_string;
+    br.cs = seg;
+    br.ip = offset;
+    call16(&br);
 }
 
 static int
@@ -341,9 +409,6 @@
     return sum;
 }
 
-#define PTR_TO_SEG(p) ((((u32)(p)) >> 4) & 0xf000)
-#define PTR_TO_OFFSET(p) (((u32)(p)) & 0xffff)
-
 static void
 rom_scan()
 {
@@ -356,7 +421,7 @@
         if (checksum(rom, len) != 0)
             continue;
         p = (u8*)(((u32)p + len) / 2048 * 2048);
-        call16(PTR_TO_SEG(rom), PTR_TO_OFFSET(rom + 3));
+        callrom(PTR_TO_SEG(rom), PTR_TO_OFFSET(rom + 3));
 
         // Look at the ROM's PnP Expansion header.  Properly, we're supposed
         // to init all the ROMs and then go back and build an IPL table of
@@ -372,13 +437,25 @@
         // Found a device that thinks it can boot the system.  Record
         // its BEV and product name string.
 
-        // XXX
+        if (ipl->count >= ARRAY_SIZE(ipl->table))
+            continue;
+
+        struct ipl_entry_s *ip = &ipl->table[ipl->count];
+        ip->type = IPL_TYPE_BEV;
+        ip->vector = (PTR_TO_SEG(rom) << 16) | entry;
+
+        u16 desc = *(u16*)&rom[0x1a+0x10];
+        if (desc)
+            ip->description = (PTR_TO_SEG(rom) << 16) | desc;
+
+        ipl->count++;
     }
 }
 
 static void
 status_restart(u8 status)
 {
+    // XXX
 #if 0
     if (status == 0x05)
         eoi_jmp_post();
@@ -417,6 +494,7 @@
     serial_setup();
     timer_setup();
     pic_setup();
+    // XXX - need to do pci stuff
     //pci_setup();
     init_boot_vectors();
     rom_scan();
@@ -430,7 +508,7 @@
         ata_detect();
     }
     cdemu_init();
-    call16(0xf000, OFFSET_begin_boot);
+    callrom(0xf000, OFFSET_begin_boot);
 }
 
 void VISIBLE