Misc updates.

Try to fix up make dependency tracking by including a "null.c" file.
Initialize hard disk tables during post.
Move RTC handlers from system.c to clock.c
Use a macro to init stacks in romlayout.S
Add C-Code stats to buildrom step.
diff --git a/Makefile b/Makefile
index f6019ac..e747126 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@
 SRC16=floppy.c disk.c system.c clock.c serial.c kbd.c mouse.c output.c boot.c
 SRC32=post.c output.c
 
-# Default compiler flags (note -march=armv4 is needed for 16 bit insns)
+# Default compiler flags
 CFLAGS = -Wall -g -Os -MD -m32 -march=i386 -mregparm=2 -ffreestanding
 CFLAGS16 = -Wall -Os -MD -m32 -DMODE16 -march=i386 -mregparm=2 -ffreestanding -fno-jump-tables
 
@@ -36,7 +36,7 @@
 
 $(OUT)%.16.s: %.c
 	@echo "  Generating assembler for $<"
-	$(Q)$(CC) $(CFLAGS16) -fwhole-program -S -combine -c $< -o $@
+	$(Q)$(CC) $(CFLAGS16) -fwhole-program -S -combine -c $< src/null.c -o $@
 
 $(OUT)%.lds: %.lds.S
 	@echo "  Precompiling $<"
@@ -60,7 +60,7 @@
 
 $(OUT)rom16.o: $(OUT)romlayout16.o
 	@echo "  Linking $@"
-	$(Q)ld -melf_i386 -Ttext 0 $< -o $@
+	$(Q)ld -melf_i386 -e post16 -Ttext 0 $< -o $@
 
 $(OUT)rom16.bin: $(OUT)rom16.o
 	@echo "  Extracting binary $@"
diff --git a/src/biosvar.h b/src/biosvar.h
index 037cdab..d4c04c7 100644
--- a/src/biosvar.h
+++ b/src/biosvar.h
@@ -8,6 +8,9 @@
 
 #include "types.h" // u8
 #include "farptr.h" // SET_SEG
+#include "config.h" // CONFIG_*
+
+#define PACKED __attribute__((packed))
 
 
 /****************************************************************
@@ -54,7 +57,10 @@
     u32 timer_counter;
     // 40:70
     u8 timer_rollover;
-    u8 other4[0x07];
+    u8 other4[0x04];
+    u8 disk_count;
+    u8 disk_control_byte;
+    u8 port_disk;
     u8 lpt_timeout[4];
     u8 com_timeout[4];
     // 40:80
@@ -74,7 +80,7 @@
     u32 user_wait_timeout;
     // 40:A0
     u8 rtc_wait_flag;
-} __attribute__((packed));
+} PACKED;
 
 // BDA floppy_recalibration_status bitdefs
 #define FRS_TIMEOUT (1<<7)
@@ -105,6 +111,107 @@
 
 
 /****************************************************************
+ * Hard drive info
+ ****************************************************************/
+
+struct fdpt_s {
+    u16 cylinders;
+    u8 heads;
+    u8 a0h_signature;
+    u8 phys_sectors;
+    u16 precompensation;
+    u8 reserved;
+    u8 drive_control_byte;
+    u16 phys_cylinders;
+    u8 phys_heads;
+    u16 landing_zone;
+    u8 sectors;
+    u8 checksum;
+} PACKED;
+
+struct chs_s {
+    u16 heads;      // # heads
+    u16 cylinders;  // # cylinders
+    u16 spt;        // # sectors / track
+};
+
+// DPTE definition
+struct dpte_s {
+    u16 iobase1;
+    u16 iobase2;
+    u8  prefix;
+    u8  unused;
+    u8  irq;
+    u8  blkcount;
+    u8  dma;
+    u8  pio;
+    u16 options;
+    u16 reserved;
+    u8  revision;
+    u8  checksum;
+};
+
+struct ata_channel_s {
+    u8  iface;        // ISA or PCI
+    u16 iobase1;      // IO Base 1
+    u16 iobase2;      // IO Base 2
+    u8  irq;          // IRQ
+} PACKED;
+
+struct ata_device_s {
+    u8  type;         // Detected type of ata (ata/atapi/none/unknown)
+    u8  device;       // Detected type of attached devices (hd/cd/none)
+    u8  removable;    // Removable device flag
+    u8  lock;         // Locks for removable devices
+    u8  mode;         // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
+    u16 blksize;      // block size
+
+    u8  translation;  // type of translation
+    struct chs_s  lchs;         // Logical CHS
+    struct chs_s  pchs;         // Physical CHS
+
+    u32 sectors;      // Total sectors count
+} PACKED;
+
+struct ata_s {
+    // ATA channels info
+    struct ata_channel_s channels[CONFIG_MAX_ATA_INTERFACES];
+
+    // ATA devices info
+    struct ata_device_s  devices[CONFIG_MAX_ATA_DEVICES];
+    //
+    // map between (bios hd id - 0x80) and ata channels
+    u8  hdcount, hdidmap[CONFIG_MAX_ATA_DEVICES];
+
+    // map between (bios cd id - 0xE0) and ata channels
+    u8  cdcount, cdidmap[CONFIG_MAX_ATA_DEVICES];
+
+    // Buffer for DPTE table
+    struct dpte_s dpte;
+
+    // Count of transferred sectors and bytes
+    u16 trsfsectors;
+    u32 trsfbytes;
+} PACKED;
+
+// ElTorito Device Emulation data
+struct cdemu_s {
+    u8  active;
+    u8  media;
+    u8  emulated_drive;
+    u8  controller_index;
+    u16 device_spec;
+    u32 ilba;
+    u16 buffer_segment;
+    u16 load_segment;
+    u16 sector_count;
+
+    // Virtual device
+    struct chs_s  vdevice;
+} PACKED;
+
+
+/****************************************************************
  * Extended Bios Data Area (EBDA)
  ****************************************************************/
 
@@ -112,19 +219,16 @@
     u8 size;
     u8 other1[0x3c];
 
-    // FDPT - Can be splitted in data members if needed
-    u8 fdpt0[0x10];
-    u8 fdpt1[0x10];
+    struct fdpt_s fdpt0;
+    struct fdpt_s fdpt1;
 
     u8 other2[0xC4];
 
     // ATA Driver data
-    //ata_t   ata;
+    struct ata_s   ata;
 
-#if BX_ELTORITO_BOOT
     // El Torito Emulation data
-    cdemu_t cdemu;
-#endif // BX_ELTORITO_BOOT
+    struct cdemu_s cdemu;
 };
 
 // Accessor functions
diff --git a/src/clock.c b/src/clock.c
index f89b391..6895876 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -280,6 +280,60 @@
     eoi_master_pic();
 }
 
+// Set Interval requested.
+static void
+handle_158300(struct bregs *regs)
+{
+    if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING) {
+        // Interval already set.
+        DEBUGF("int15: Func 83h, failed, already waiting.\n" );
+        handle_ret(regs, RET_EUNSUPPORTED);
+    }
+    // Interval not already set.
+    SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING);  // Set status byte.
+    u32 v = (regs->es << 16) | regs->bx;
+    SET_BDA(ptr_user_wait_complete_flag, v);
+    v = (regs->dx << 16) | regs->cx;
+    SET_BDA(user_wait_timeout, v);
+
+    // Unmask IRQ8 so INT70 will get through.
+    u8 irqDisable = inb(PORT_PIC2_DATA);
+    outb(irqDisable & ~PIC2_IRQ8, PORT_PIC2_DATA);
+    // Turn on the Periodic Interrupt timer
+    u8 bRegister = inb_cmos(CMOS_STATUS_B);
+    outb_cmos(CMOS_STATUS_B, bRegister | CSB_EN_ALARM_IRQ);
+
+    set_cf(regs, 0); // XXX - no set ah?
+}
+
+// Clear interval requested
+static void
+handle_158301(struct bregs *regs)
+{
+    SET_BDA(rtc_wait_flag, 0); // Clear status byte
+    // Turn off the Periodic Interrupt timer
+    u8 bRegister = inb_cmos(CMOS_STATUS_B);
+    outb_cmos(CMOS_STATUS_B, bRegister & ~CSB_EN_ALARM_IRQ);
+    set_cf(regs, 0); // XXX - no set ah?
+}
+
+static void
+handle_1583XX(struct bregs *regs)
+{
+    regs->al--;
+    handle_ret(regs, RET_EUNSUPPORTED);
+}
+
+void
+handle_1583(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x00: handle_158300(regs); break;
+    case 0x01: handle_158301(regs); break;
+    default:   handle_1583XX(regs); break;
+    }
+}
+
 // int70h: IRQ8 - CMOS RTC
 void VISIBLE
 handle_70(struct bregs *regs)
diff --git a/src/cmos.h b/src/cmos.h
index 60ebe80..4198e2a 100644
--- a/src/cmos.h
+++ b/src/cmos.h
@@ -24,7 +24,12 @@
 #define CMOS_STATUS_D            0x0d
 #define CMOS_RESET_CODE          0x0f
 #define CMOS_FLOPPY_DRIVE_TYPE   0x10
+#define CMOS_DISK_DATA           0x12
 #define CMOS_EQUIPMENT_INFO      0x14
+#define CMOS_DISK_DRIVE1_TYPE    0x19
+#define CMOS_DISK_DRIVE2_TYPE    0x1a
+#define CMOS_DISK_DRIVE1_CYL     0x1b
+#define CMOS_DISK_DRIVE2_CYL     0x24
 #define CMOS_BIOS_CONFIG         0x2d
 #define CMOS_EXTMEM_LOW          0x30
 #define CMOS_EXTMEM_HIGH         0x31
diff --git a/src/config.h b/src/config.h
index 161dfcc..5d91c60 100644
--- a/src/config.h
+++ b/src/config.h
@@ -1,3 +1,5 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
 // Configuration definitions.
 
 #define CONFIG_FLOPPY_SUPPORT 1
@@ -5,6 +7,10 @@
 #define CONFIG_ATA 0
 #define CONFIG_KBD_CALL_INT15_4F 1
 #define CONFIG_ELTORITO_BOOT 0
+#define CONFIG_MAX_ATA_INTERFACES 4
+#define CONFIG_MAX_ATA_DEVICES  (CONFIG_MAX_ATA_INTERFACES*2)
 
 #define CONFIG_STACK_SEGMENT 0x00
 #define CONFIG_STACK_OFFSET  0xfffe
+
+#endif // config.h
diff --git a/src/null.c b/src/null.c
new file mode 100644
index 0000000..be072ce
--- /dev/null
+++ b/src/null.c
@@ -0,0 +1,2 @@
+// GCC does something odd when one uses -combine with just one .c
+// file.  So this dummy file makes gcc happy.
diff --git a/src/post.c b/src/post.c
index 3049001..a154ac6 100644
--- a/src/post.c
+++ b/src/post.c
@@ -16,6 +16,16 @@
 #define ebda ((struct extended_bios_data_area_s *)(EBDA_SEG<<4))
 #define ipl ((struct ipl_s *)(IPL_SEG<<4))
 
+static int
+checksum(u8 *p, u32 len)
+{
+    u32 i;
+    u8 sum = 0;
+    for (i=0; i<len; i++)
+        sum += p[i];
+    return sum;
+}
+
 static void
 init_bda()
 {
@@ -337,16 +347,14 @@
 }
 
 static void
-cdemu_init()
-{
-    // XXX
-    //ebda->cdemu.active = 0;
-}
-
-static void
 ata_init()
 {
-    // XXX
+    // hdidmap  and cdidmap init.
+    u8 device;
+    for (device=0; device < CONFIG_MAX_ATA_DEVICES; device++) {
+        ebda->ata.hdidmap[device] = CONFIG_MAX_ATA_DEVICES;
+        ebda->ata.cdidmap[device] = CONFIG_MAX_ATA_DEVICES;
+    }
 }
 
 static void
@@ -356,9 +364,66 @@
 }
 
 static void
+fill_hdinfo(struct fdpt_s *info, u8 typecmos, u8 basecmos)
+{
+    u8 type = inb_cmos(typecmos);
+    if (type != 47)
+        // XXX - halt
+        return;
+
+    info->precompensation = (inb_cmos(basecmos+4) << 8) | inb_cmos(basecmos+3);
+    info->drive_control_byte = inb_cmos(basecmos+5);
+    info->landing_zone = (inb_cmos(basecmos+7) << 8) | inb_cmos(basecmos+6);
+    u16 cyl = (inb_cmos(basecmos+1) << 8) | inb_cmos(basecmos+0);
+    u8 heads = inb_cmos(basecmos+2);
+    u8 sectors = inb_cmos(basecmos+8);
+    if (cyl < 1024) {
+        // no logical CHS mapping used, just physical CHS
+        // use Standard Fixed Disk Parameter Table (FDPT)
+        info->cylinders = cyl;
+        info->heads = heads;
+        info->sectors = sectors;
+        return;
+    }
+
+    // complies with Phoenix style Translated Fixed Disk Parameter
+    // Table (FDPT)
+    info->phys_cylinders = cyl;
+    info->phys_heads = heads;
+    info->phys_sectors = sectors;
+    info->sectors = sectors;
+    info->a0h_signature = 0xa0;
+    if (cyl > 8192) {
+        cyl >>= 4;
+        heads <<= 4;
+    } else if (cyl > 4096) {
+        cyl >>= 3;
+        heads <<= 3;
+    } else if (cyl > 2048) {
+        cyl >>= 2;
+        heads <<= 2;
+    }
+    info->cylinders = cyl;
+    info->heads = heads;
+    info->checksum = ~checksum((u8*)info, sizeof(*info)-1) + 1;
+}
+
+static void
 hard_drive_post()
 {
-    // XXX
+    outb(0x0a, 0x03f6); // 0000 1010 = reserved, disable IRQ 14
+    bda->disk_count = 1;
+    bda->disk_control_byte = 0xc0;
+
+    // move disk geometry data from CMOS to EBDA disk parameter table(s)
+    u8 diskinfo = inb_cmos(CMOS_DISK_DATA);
+    if ((diskinfo & 0xf0) == 0xf0)
+        // Fill EBDA table for hard disk 0.
+        fill_hdinfo(&ebda->fdpt0, CMOS_DISK_DRIVE1_TYPE, CMOS_DISK_DRIVE1_CYL);
+    if ((diskinfo & 0x0f) == 0x0f)
+        // XXX - bochs halts on any other type
+        // Fill EBDA table for hard disk 1.
+        fill_hdinfo(&ebda->fdpt0, CMOS_DISK_DRIVE2_TYPE, CMOS_DISK_DRIVE2_CYL);
 }
 
 
@@ -399,16 +464,6 @@
     call16(&br);
 }
 
-static int
-checksum(u8 *p, u32 len)
-{
-    u32 i;
-    u8 sum = 0;
-    for (i=0; i<len; i++)
-        sum += p[i];
-    return sum;
-}
-
 static void
 rom_scan()
 {
@@ -507,7 +562,6 @@
         ata_init();
         ata_detect();
     }
-    cdemu_init();
     callrom(0xf000, OFFSET_begin_boot);
 }
 
diff --git a/src/romlayout.S b/src/romlayout.S
index 76de2eb..039a1d8 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -25,15 +25,19 @@
  * POST handler
  ****************************************************************/
 
-        .org 0xe05b
-        .globl _start
-_start:
-        .globl post16
-post16:
-        // init the stack pointer
+        // Macro to reset the 16bit stack
+        // Clobbers %ax
+        .macro RESET_STACK
         xorw %ax, %ax
         movw %ax, %ss
         movl $ CONFIG_STACK_OFFSET , %esp
+        .endm
+
+        .org 0xe05b
+        .globl post16
+post16:
+        // init the stack pointer
+        RESET_STACK
 
         // Set entry point of rombios32 code - the actual address
 	// is altered later in the build process.
@@ -280,18 +284,12 @@
 
         .globl entry_19
 entry_19:
-        // init the stack pointer
-        xorw %ax, %ax
-        movw %ax, %ss
-        movl $ CONFIG_STACK_OFFSET , %esp
+        RESET_STACK
         calll handle_19
 
         .globl entry_18
 entry_18:
-        // init the stack pointer
-        xorw %ax, %ax
-        movw %ax, %ss
-        movl $ CONFIG_STACK_OFFSET , %esp
+        RESET_STACK
         calll handle_18
 
         IRQ_TRAMPOLINE 02
@@ -310,7 +308,6 @@
         // XXX - Fixed Disk Parameter Table
 
         .org 0xe6f2
-        // XXX - should reset ss and sp
         jmp entry_19
 
         .org 0xe6f5
diff --git a/src/system.c b/src/system.c
index f54f930..ca8ff88 100644
--- a/src/system.c
+++ b/src/system.c
@@ -10,9 +10,6 @@
 #include "ioport.h" // inb
 #include "cmos.h" // inb_cmos
 
-#define RET_EUNSUPPORTED 0x86
-
-
 // Use PS2 System Control port A to set A20 enable
 static inline u8
 set_a20(u8 cond)
@@ -28,13 +25,6 @@
     return (newval & 0x02) != 0;
 }
 
-static inline void
-handle_ret(struct bregs *regs, u8 code)
-{
-    regs->ah = code;
-    set_cf(regs, code);
-}
-
 static void
 handle_152400(struct bregs *regs)
 {
@@ -76,47 +66,10 @@
     handle_ret(regs, 0);
 }
 
-// Set Interval requested.
 static void
-handle_158300(struct bregs *regs)
+handle_1553(struct bregs *regs)
 {
-    if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING) {
-        // Interval already set.
-        DEBUGF("int15: Func 83h, failed, already waiting.\n" );
-        handle_ret(regs, RET_EUNSUPPORTED);
-    }
-    // Interval not already set.
-    SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING);  // Set status byte.
-    u32 v = (regs->es << 16) | regs->bx;
-    SET_BDA(ptr_user_wait_complete_flag, v);
-    v = (regs->dx << 16) | regs->cx;
-    SET_BDA(user_wait_timeout, v);
-
-    // Unmask IRQ8 so INT70 will get through.
-    u8 irqDisable = inb(PORT_PIC2_DATA);
-    outb(irqDisable & ~PIC2_IRQ8, PORT_PIC2_DATA);
-    // Turn on the Periodic Interrupt timer
-    u8 bRegister = inb_cmos(CMOS_STATUS_B);
-    outb_cmos(CMOS_STATUS_B, bRegister | CSB_EN_ALARM_IRQ);
-
-    set_cf(regs, 0); // XXX - no set ah?
-}
-
-// Clear interval requested
-static void
-handle_158301(struct bregs *regs)
-{
-    SET_BDA(rtc_wait_flag, 0); // Clear status byte
-    // Turn off the Periodic Interrupt timer
-    u8 bRegister = inb_cmos(CMOS_STATUS_B);
-    outb_cmos(CMOS_STATUS_B, bRegister & ~CSB_EN_ALARM_IRQ);
-    set_cf(regs, 0); // XXX - no set ah?
-}
-
-static void
-handle_1583XX(struct bregs *regs)
-{
-    regs->al--;
+    // XXX - APM call
     handle_ret(regs, RET_EUNSUPPORTED);
 }
 
@@ -434,14 +387,12 @@
 static void
 handle_15e8XX(struct bregs *regs)
 {
-    regs->al--;
     handle_ret(regs, RET_EUNSUPPORTED);
 }
 
 static void
 handle_15XX(struct bregs *regs)
 {
-    regs->al--;
     handle_ret(regs, RET_EUNSUPPORTED);
 }
 
@@ -462,13 +413,8 @@
         break;
     case 0x4f: handle_154f(regs); break;
     case 0x52: handle_1552(regs); break;
-    case 0x83:
-        switch (regs->al) {
-        case 0x00: handle_158300(regs); break;
-        case 0x01: handle_158301(regs); break;
-        default:   handle_1583XX(regs); break;
-        }
-        break;
+    case 0x53: handle_1553(regs); break;
+    case 0x83: handle_1583(regs); break;
     case 0x86: handle_1586(regs); break;
     case 0x87: handle_1587(regs); break;
     case 0x88: handle_1588(regs); break;
diff --git a/src/util.h b/src/util.h
index d33f2ac..916f672 100644
--- a/src/util.h
+++ b/src/util.h
@@ -103,3 +103,15 @@
 
 // kbd.c
 void handle_15c2(struct bregs *regs);
+
+// clock.c
+void handle_1583(struct bregs *regs);
+
+// Frequent bios return helper
+#define RET_EUNSUPPORTED 0x86
+static inline void
+handle_ret(struct bregs *regs, u8 code)
+{
+    regs->ah = code;
+    set_cf(regs, code);
+}
diff --git a/tools/buildrom.py b/tools/buildrom.py
index c82bb2b..fd49076 100755
--- a/tools/buildrom.py
+++ b/tools/buildrom.py
@@ -57,6 +57,10 @@
     if size32 > freespace:
         print "32bit code too large (%d vs %d)" % (size32, freespace)
         sys.exit(1)
+    if data16[spos:spos+size32] != '\0'*size32:
+        print "Non zero data in 16bit freespace (%d to %d)" % (
+            spos, spos+size32)
+        sys.exit(1)
     outrom = data16[:spos] + data32 + data16[spos+size32:]
 
     # Fixup initial jump to 32 bit code
@@ -64,6 +68,11 @@
     start32 = int(o32['OFFSET__start'], 16)
     outrom = alteraddr(outrom, jmppos+2, start32)
 
+    print "Writing output rom %s" % OUT
+    print " 16bit C-code size: %d" % spos
+    print " 32bit C-code size: %d" % size32
+    print " Total C-code size: %d" % (spos+size32)
+
     # Write output rom
     f = open(OUT, 'wb')
     f.write(outrom)