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.
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
$(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 $<"
$(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 $@"
#include "types.h" // u8
#include "farptr.h" // SET_SEG
+#include "config.h" // CONFIG_*
+
+#define PACKED __attribute__((packed))
/****************************************************************
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
u32 user_wait_timeout;
// 40:A0
u8 rtc_wait_flag;
-} __attribute__((packed));
+} PACKED;
// BDA floppy_recalibration_status bitdefs
#define FRS_TIMEOUT (1<<7)
} while (0)
+/****************************************************************
+ * 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)
****************************************************************/
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
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)
#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
+#ifndef __CONFIG_H
+#define __CONFIG_H
// Configuration definitions.
#define CONFIG_FLOPPY_SUPPORT 1
#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
--- /dev/null
+// GCC does something odd when one uses -combine with just one .c
+// file. So this dummy file makes gcc happy.
#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()
{
}
static void
-cdemu_init()
+ata_init()
{
- // XXX
- //ebda->cdemu.active = 0;
+ // 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
-ata_init()
+ata_detect()
{
// XXX
}
static void
-ata_detect()
+fill_hdinfo(struct fdpt_s *info, u8 typecmos, u8 basecmos)
{
- // XXX
+ 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);
}
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()
{
ata_init();
ata_detect();
}
- cdemu_init();
callrom(0xf000, OFFSET_begin_boot);
}
* POST handler
****************************************************************/
+ // 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 _start
-_start:
.globl post16
post16:
// init the stack pointer
- xorw %ax, %ax
- movw %ax, %ss
- movl $ CONFIG_STACK_OFFSET , %esp
+ RESET_STACK
// Set entry point of rombios32 code - the actual address
// is altered later in the build process.
.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
// XXX - Fixed Disk Parameter Table
.org 0xe6f2
- // XXX - should reset ss and sp
jmp entry_19
.org 0xe6f5
#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)
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)
{
handle_ret(regs, 0);
}
-// 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)
+handle_1553(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);
}
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);
}
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;
// 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);
+}
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
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)