diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/biosvar.h | 184 | ||||
-rw-r--r-- | src/boot.c | 118 | ||||
-rw-r--r-- | src/cbt.c | 8 | ||||
-rw-r--r-- | src/clock.c | 54 | ||||
-rw-r--r-- | src/cmos.h | 51 | ||||
-rw-r--r-- | src/config.h | 8 | ||||
-rw-r--r-- | src/disk.c | 67 | ||||
-rw-r--r-- | src/disk.h | 33 | ||||
-rw-r--r-- | src/farptr.h | 57 | ||||
-rw-r--r-- | src/floppy.c | 757 | ||||
-rw-r--r-- | src/font.c | 139 | ||||
-rw-r--r-- | src/ioport.h | 56 | ||||
-rw-r--r-- | src/kbd.c | 35 | ||||
-rw-r--r-- | src/output.c | 161 | ||||
-rw-r--r-- | src/post.c | 312 | ||||
-rw-r--r-- | src/rombios32.lds.S | 31 | ||||
-rw-r--r-- | src/romlayout.S | 304 | ||||
-rw-r--r-- | src/serial.c | 23 | ||||
-rw-r--r-- | src/system.c | 529 | ||||
-rw-r--r-- | src/types.h | 21 | ||||
-rw-r--r-- | src/util.h | 55 |
21 files changed, 3003 insertions, 0 deletions
diff --git a/src/biosvar.h b/src/biosvar.h new file mode 100644 index 0000000..8b15f5b --- /dev/null +++ b/src/biosvar.h @@ -0,0 +1,184 @@ +// Variable layouts of bios. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "types.h" // u8 +#include "farptr.h" // SET_SEG + + +/**************************************************************** + * Bios Data Area (BDA) + ****************************************************************/ + +struct ivec { + u16 offset; + u16 seg; +}; + +struct bios_data_area_s { + // 00:00 + struct ivec ivecs[256]; + // 30:00 +// u8 stack[256]; + // 40:00 + u16 port_com1, port_com2, port_com3, port_com4; + u16 port_lpt1, port_lpt2, port_lpt3; + u16 ebda_seg; + // 40:10 + u16 equipment_list_flags; + u8 pad1; + u16 mem_size_kb; + u8 pad2; + u8 ps2_ctrl_flag; + u16 kbd_flag; + u8 alt_keypad; + u16 kbd_buf_head; + u16 kbd_buf_tail; + // 40:1e + u8 kbd_buf[32]; + u8 floppy_recalibration_status; + u8 floppy_motor_status; + // 40:40 + u8 floppy_motor_counter; + u8 floppy_last_status; + u8 floppy_return_status[7]; + u8 other1[0x7]; + // 40:50 + u8 other2[0x1c]; + // 40:6c + u32 timer_counter; + // 40:70 + u8 timer_rollover; + u8 other4[0x0f]; + // 40:80 + u16 kbd_buf_start_offset; + u16 kbd_buf_end_offset; + u8 other5[7]; + u8 floppy_last_data_rate; + u8 other6[3]; + u8 floppy_harddisk_info; + // 40:90 + u8 floppy_media_state[4]; + u8 floppy_track0; + u8 floppy_track1; + u8 kbd_mode; + u8 kbd_led; + u32 ptr_user_wait_complete_flag; + u32 user_wait_timeout; + // 40:A0 + u8 rtc_wait_flag; +} __attribute__((packed)); + +// BDA floppy_recalibration_status bitdefs +#define FRS_TIMEOUT (1<<7) + +// BDA rtc_wait_flag bitdefs +#define RWS_WAIT_PENDING (1<<0) +#define RWS_WAIT_ELAPSED (1<<7) + +// BDA floppy_media_state bitdefs +#define FMS_DRIVE_STATE_MASK (0x07) +#define FMS_MEDIA_DRIVE_ESTABLISHED (1<<4) +#define FMS_DOUBLE_STEPPING (1<<5) +#define FMS_DATA_RATE_MASK (0xc0) + +// Accessor functions +#define GET_BDA(var) ({ \ + SET_SEG(ES, 0x0000); \ + GET_VAR(ES, ((struct bios_data_area_s *)0)->var); }) +#define SET_BDA(var, val) do { \ + SET_SEG(ES, 0x0000); \ + SET_VAR(ES, ((struct bios_data_area_s *)0)->var, val); \ + } while (0) +#define CLEARBITS_BDA(var, val) do { \ + typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \ + SET_BDA(var, (__val & ~(val))); \ + } while (0) +#define SETBITS_BDA(var, val) do { \ + typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \ + SET_BDA(var, (__val | (val))); \ + } while (0) + + +/**************************************************************** + * Extended Bios Data Area (EBDA) + ****************************************************************/ + +struct extended_bios_data_area_s { + u8 size; + u8 other1[0x3c]; + + // FDPT - Can be splitted in data members if needed + u8 fdpt0[0x10]; + u8 fdpt1[0x10]; + + u8 other2[0xC4]; + + // ATA Driver data + //ata_t ata; + +#if BX_ELTORITO_BOOT + // El Torito Emulation data + cdemu_t cdemu; +#endif // BX_ELTORITO_BOOT +}; + + +/**************************************************************** + * Extended Bios Data Area (EBDA) + ****************************************************************/ + +#define UREG(ER, R, RH, RL) union { u32 ER; struct { u16 R; u16 R ## _hi; }; struct { u8 RL; u8 RH; u8 R ## _hilo; u8 R ## _hihi; }; } + +struct bregs { + u16 ds; + u16 es; + UREG(edi, di, di_hi, di_lo); + UREG(esi, si, si_hi, si_lo); + UREG(ebp, bp, bp_hi, bp_lo); + UREG(esp, sp, sp_hi, sp_lo); + UREG(ebx, bx, bh, bl); + UREG(edx, dx, dh, dl); + UREG(ecx, cx, ch, cl); + UREG(eax, ax, ah, al); + u16 ip; + u16 cs; + u16 flags; +} __attribute__((packed)); + +// bregs flags bitdefs +#define F_CF (1<<9) + +static inline void +set_cf(struct bregs *regs, int cond) +{ + if (cond) + regs->flags |= F_CF; + else + regs->flags &= ~F_CF; +} + + +/**************************************************************** + * Bios Config Table + ****************************************************************/ + +struct bios_config_table_s { + // XXX + u8 x; +}; + +extern struct bios_config_table_s BIOS_CONFIG_TABLE; + + +/**************************************************************** + * Memory layout info + ****************************************************************/ + +#define SEG_BIOS 0xf000 + +#define EBDA_SEG 0x9FC0 +#define EBDA_SIZE 1 // In KiB +#define BASE_MEM_IN_K (640 - EBDA_SIZE) diff --git a/src/boot.c b/src/boot.c new file mode 100644 index 0000000..828be14 --- /dev/null +++ b/src/boot.c @@ -0,0 +1,118 @@ +// 16bit code to load disk image and start system boot. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "types.h" // VISIBLE +#include "util.h" // irq_enable +#include "biosvar.h" // struct bregs +#include "farptr.h" // SET_SEG + +static inline void +__call_irq(u8 nr) +{ + asm volatile("int %0" : : "N" (nr)); +} + +static inline u32 +call_irq(u8 nr, struct bregs *callregs) +{ + u32 flags; + asm volatile( + // Save current registers + "pushal\n" + // Pull in calling registers. + "movl 0x04(%%eax), %%edi\n" + "movl 0x08(%%eax), %%esi\n" + "movl 0x0c(%%eax), %%ebp\n" + "movl 0x14(%%eax), %%ebx\n" + "movl 0x18(%%eax), %%edx\n" + "movl 0x1c(%%eax), %%ecx\n" + "movl 0x20(%%eax), %%eax\n" + // Invoke interrupt + "int %1\n" + // Restore registers + "popal\n" + // Exract flags + "pushfw\n" + "popl %%eax\n" + : "=a" (flags): "N" (nr), "a" (callregs), "m" (*callregs)); + return flags; +} + +static void +print_boot_failure() +{ + bprintf(0, "Boot failed\n"); +} + +static void +try_boot() +{ + // XXX - assume floppy + u16 bootseg = 0x07c0; + u8 bootdrv = 0; + + // Read sector + struct bregs cr; + memset(&cr, 0, sizeof(cr)); + cr.dl = bootdrv; + SET_SEG(ES, bootseg); + cr.bx = 0; + cr.ah = 2; + cr.al = 1; + cr.ch = 0; + cr.cl = 1; + cr.dh = 0; + u32 status = call_irq(0x13, &cr); + + if (status & F_CF) { + print_boot_failure(); + return; + } + + u16 bootip = (bootseg & 0x0fff) << 4; + bootseg &= 0xf000; + + u32 segoff = (bootseg << 16) | bootip; + asm volatile ( + "pushf\n" + "pushl %0\n" + "movb %b1, %%dl\n" + // Set the magic number in ax and the boot drive in dl. + "movw $0xaa55, %%ax\n" + // Zero some of the other registers. + "xorw %%bx, %%bx\n" + "movw %%bx, %%ds\n" + "movw %%bx, %%es\n" + "movw %%bx, %%bp\n" + // Go! + "iretw\n" + : : "r" (segoff), "ri" (bootdrv)); +} + +// Boot Failure recovery: try the next device. +void VISIBLE +handle_18(struct bregs *regs) +{ + debug_enter(regs); + try_boot(); +} + +// INT 19h Boot Load Service Entry Point +void VISIBLE +handle_19(struct bregs *regs) +{ + debug_enter(regs); + try_boot(); +} + +// Callback from 32bit entry - start boot process +void VISIBLE +begin_boot() +{ + irq_enable(); + __call_irq(0x19); +} diff --git a/src/cbt.c b/src/cbt.c new file mode 100644 index 0000000..015f16f --- /dev/null +++ b/src/cbt.c @@ -0,0 +1,8 @@ +#include "biosvar.h" // CONFIG_BIOS_TABLE + +// bios variables + +struct bios_config_table_s BIOS_CONFIG_TABLE = { + // XXX + 18, +}; diff --git a/src/clock.c b/src/clock.c new file mode 100644 index 0000000..5ca2b5c --- /dev/null +++ b/src/clock.c @@ -0,0 +1,54 @@ +// 16bit code to handle system clocks. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "biosvar.h" // struct bregs +#include "util.h" // debug_enter +#include "disk.h" // floppy_tick + +// INT 1Ah Time-of-day Service Entry Point +void VISIBLE +handle_1a(struct bregs *regs) +{ + debug_enter(regs); + set_cf(regs, 1); +} + +// User Timer Tick +void VISIBLE +handle_1c(struct bregs *regs) +{ + debug_enter(regs); +} + +// INT 08h System Timer ISR Entry Point +void VISIBLE +handle_08(struct bregs *regs) +{ +// debug_enter(regs); + + floppy_tick(); + + u32 counter = GET_BDA(timer_counter); + counter++; + // compare to one days worth of timer ticks at 18.2 hz + if (counter >= 0x001800B0) { + // there has been a midnight rollover at this point + counter = 0; + SET_BDA(timer_rollover, GET_BDA(timer_rollover) + 1); + } + + SET_BDA(timer_counter, counter); + // XXX - int #0x1c + eoi_master_pic(); +} + +// int70h: IRQ8 - CMOS RTC +void VISIBLE +handle_70(struct bregs *regs) +{ + debug_enter(regs); +} diff --git a/src/cmos.h b/src/cmos.h new file mode 100644 index 0000000..33cde16 --- /dev/null +++ b/src/cmos.h @@ -0,0 +1,51 @@ +// Definitions for X86 CMOS non-volatile memory access. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. +#ifndef __CMOS_H +#define __CMOS_H + +#include "ioport.h" // inb, outb + +#define CMOS_RTC_SECONDS 0x00 +#define CMOS_RTC_SECONDS_ALARM 0x01 +#define CMOS_RTC_MINUTES 0x02 +#define CMOS_RTC_MINUTES_ALARM 0x03 +#define CMOS_RTC_HOURS 0x04 +#define CMOS_RTC_HOURS_ALARM 0x05 +#define CMOS_STATUS_B 0x0b +#define CMOS_RESET_CODE 0x0f +#define CMOS_FLOPPY_DRIVE_TYPE 0x10 +#define CMOS_EQUIPMENT_INFO 0x14 +#define CMOS_EXTMEM_LOW 0x30 +#define CMOS_EXTMEM_HIGH 0x31 +#define CMOS_EXTMEM2_LOW 0x34 +#define CMOS_EXTMEM2_HIGH 0x35 + +// CMOS_STATUS_B bitdefs +#define CSB_EN_ALARM_IRQ (1<<5) + +// CMOS_FLOPPY_DRIVE_TYPE bitdefs +#define CFD_NO_DRIVE 0 +#define CFD_360KB 1 +#define CFD_12MB 2 +#define CFD_720KB 3 +#define CFD_144MB 4 +#define CFD_288MB 5 + +static inline u8 +inb_cmos(u8 reg) +{ + outb(reg, PORT_CMOS_INDEX); + return inb(PORT_CMOS_DATA); +} + +static inline void +outb_cmos(u8 val, u8 reg) +{ + outb(reg, PORT_CMOS_INDEX); + outb(val, PORT_CMOS_DATA); +} + +#endif // cmos.h diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..53996b4 --- /dev/null +++ b/src/config.h @@ -0,0 +1,8 @@ +// Configuration definitions. + +#define CONFIG_FLOPPY_SUPPORT 1 +#define CONFIG_PS2_MOUSE 0 +#define CONFIG_ATA 0 +#define CONFIG_STACK16_SEGMENT 0x00 +#define CONFIG_STACK16_OFFSET 0xfffe +#define CONFIG_STACK32_OFFSET 0x80000 diff --git a/src/disk.c b/src/disk.c new file mode 100644 index 0000000..8901b7d --- /dev/null +++ b/src/disk.c @@ -0,0 +1,67 @@ +// 16bit code to access hard drives. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "disk.h" // floppy_13 +#include "biosvar.h" // struct bregs +#include "util.h" // debug_enter + +static void +disk_13(struct bregs *regs, u8 drive) +{ + set_cf(regs, 1); +} + +static void +handle_legacy_disk(struct bregs *regs, u8 drive) +{ + if (drive < 0x80) { + floppy_13(regs, drive); + return; + } +#if BX_USE_ATADRV + if (drive >= 0xE0) { + int13_cdrom(regs); // xxx + return; + } +#endif + + disk_13(regs, drive); +} + +void VISIBLE +handle_40(struct bregs *regs) +{ + debug_enter(regs); + handle_legacy_disk(regs, regs->dl); + debug_exit(regs); +} + +// INT 13h Fixed Disk Services Entry Point +void VISIBLE +handle_13(struct bregs *regs) +{ + debug_enter(regs); + u8 drive = regs->dl; +#if BX_ELTORITO_BOOT + if (regs->ah >= 0x4a || regs->ah <= 0x4d) { + int13_eltorito(regs); + } else if (cdemu_isactive() && cdrom_emulated_drive()) { + int13_cdemu(regs); + } else +#endif + handle_legacy_disk(regs, drive); + debug_exit(regs); +} + +// record completion in BIOS task complete flag +void VISIBLE +handle_76(struct bregs *regs) +{ + debug_enter(regs); + SET_BDA(floppy_harddisk_info, 0xff); + eoi_both_pics(); +} diff --git a/src/disk.h b/src/disk.h new file mode 100644 index 0000000..d7b3547 --- /dev/null +++ b/src/disk.h @@ -0,0 +1,33 @@ +// Definitions for X86 bios disks. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "ioport.h" // outb + +#define DISK_RET_SUCCESS 0x00 +#define DISK_RET_EPARAM 0x01 +#define DISK_RET_ECHANGED 0x06 +#define DISK_RET_EBOUNDARY 0x09 +#define DISK_RET_ECONTROLLER 0x20 +#define DISK_RET_ETIMEOUT 0x80 +#define DISK_RET_EMEDIA 0xC0 + +static inline void +eoi_master_pic() +{ + outb(PIC1_IRQ5, PORT_PIC1); +} + +static inline void +eoi_both_pics() +{ + outb(PIC2_IRQ13, PORT_PIC2); + eoi_master_pic(); +} + +// floppy.c +struct bregs; +void floppy_13(struct bregs *regs, u8 drive); +void floppy_tick(); diff --git a/src/farptr.h b/src/farptr.h new file mode 100644 index 0000000..1c3044b --- /dev/null +++ b/src/farptr.h @@ -0,0 +1,57 @@ +// Code to access multiple segments within gcc. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#define READ8_SEG(SEG, var) ({ \ + u8 __value; \ + __asm__ __volatile__("movb %%" #SEG ":%1, %b0" \ + : "=Qi"(__value) : "m"(var)); \ + __value; }) +#define READ16_SEG(SEG, var) ({ \ + u16 __value; \ + __asm__ __volatile__("movw %%" #SEG ":%1, %w0" \ + : "=ri"(__value) : "m"(var)); \ + __value; }) +#define READ32_SEG(SEG, var) ({ \ + u32 __value; \ + __asm__ __volatile__("movl %%" #SEG ":%1, %0" \ + : "=ri"(__value) : "m"(var)); \ + __value; }) +#define WRITE8_SEG(SEG, var, value) \ + __asm__ __volatile__("movb %b0, %%" #SEG ":%1" \ + : : "Q"(value), "m"(var)) +#define WRITE16_SEG(SEG, var, value) \ + __asm__ __volatile__("movw %w0, %%" #SEG ":%1" \ + : : "r"(value), "m"(var)) +#define WRITE32_SEG(SEG, var, value) \ + __asm__ __volatile__("movl %0, %%" #SEG ":%1" \ + : : "r"(value), "m"(var)) + +#define GET_VAR(seg, var) ({ \ + typeof(var) __val; \ + if (__builtin_types_compatible_p(typeof(__val), u8)) \ + __val = READ8_SEG(seg, var); \ + else if (__builtin_types_compatible_p(typeof(__val), u16)) \ + __val = READ16_SEG(seg, var); \ + else if (__builtin_types_compatible_p(typeof(__val), u32)) \ + __val = READ32_SEG(seg, var); \ + __val; }) + +#define SET_VAR(seg, var, val) do { \ + if (__builtin_types_compatible_p(typeof(var), u8)) \ + WRITE8_SEG(seg, var, (val)); \ + else if (__builtin_types_compatible_p(typeof(var), u16)) \ + WRITE16_SEG(seg, var, (val)); \ + else if (__builtin_types_compatible_p(typeof(var), u32)) \ + WRITE32_SEG(seg, var, (val)); \ + } while (0) + +#define SET_SEG(SEG, value) \ + __asm__ __volatile__("movw %w0, %%" #SEG : : "r"(value)) +#define GET_SEG(SEG) ({ \ + u16 __seg; \ + __asm__ __volatile__("movw %%" #SEG ", %w0" : "=r"(__seg)); \ + __seg;}) + diff --git a/src/floppy.c b/src/floppy.c new file mode 100644 index 0000000..5e70df2 --- /dev/null +++ b/src/floppy.c @@ -0,0 +1,757 @@ +// 16bit code to access floppy drives. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "types.h" // u8 +#include "disk.h" // DISK_RET_SUCCESS +#include "config.h" // CONFIG_FLOPPY_SUPPORT +#include "biosvar.h" // struct bregs +#include "util.h" // irq_disable +#include "cmos.h" // inb_cmos + +#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */ + +////.org 0xefc7 +// Since no provisions are made for multiple drive types, most +// values in this table are ignored. I set parameters for 1.44M +// floppy here +char diskette_param_table[11] = { + 0xAF, + 0x02, // head load time 0000001, DMA used + 0x25, + 0x02, + 18, + 0x1B, + 0xFF, + 0x6C, + 0xF6, + 0x0F, + 0x08, +}; + +// New diskette parameter table adding 3 parameters from IBM +// Since no provisions are made for multiple drive types, most +// values in this table are ignored. I set parameters for 1.44M +// floppy here +char diskette_param_table2[14] VISIBLE = { + 0xAF, + 0x02, // head load time 0000001, DMA used + 0x25, + 0x02, + 18, + 0x1B, + 0xFF, + 0x6C, + 0xF6, + 0x0F, + 0x08, + 79, // maximum track + 0, // data transfer rate + 4, // drive type in cmos +}; + +// Oddities: +// Return codes vary greatly - AL not cleared consistenlty, BDA return +// status not set consistently, sometimes panics. +// Extra outb(0x000a, 0x02) in read? +// Does not disable interrupts on failure paths. +// numfloppies used before set in int_1308 +// int_1305 verifies track but doesn't use it? + +static inline void +set_diskette_current_cyl(u8 drive, u8 cyl) +{ + if (drive) + SET_BDA(floppy_track1, cyl); + else + SET_BDA(floppy_track0, cyl); +} + +static u16 +get_drive_type(u8 drive) +{ + // check CMOS to see if drive exists + u8 drive_type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE); + if (drive == 0) + drive_type >>= 4; + else + drive_type &= 0x0f; + return drive_type; +} + +static u16 +floppy_media_known(u8 drive) +{ + if (!(GET_BDA(floppy_recalibration_status) & (1<<drive))) + return 0; + u8 v = GET_BDA(floppy_media_state[drive]); + if (!(v & FMS_MEDIA_DRIVE_ESTABLISHED)) + return 0; + return 1; +} + +static void +floppy_reset_controller() +{ + // Reset controller + u8 val8 = inb(PORT_FD_DOR); + outb(val8 & ~0x04, PORT_FD_DOR); + outb(val8 | 0x04, PORT_FD_DOR); + + // Wait for controller to come out of reset + while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80) + ; +} + +static void +floppy_prepare_controller(u8 drive) +{ + CLEARBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT); + + // turn on motor of selected drive, DMA & int enabled, normal operation + u8 prev_reset = inb(PORT_FD_DOR) & 0x04; + u8 dor = 0x10; + if (drive) + dor = 0x20; + dor |= 0x0c; + dor |= drive; + outb(dor, PORT_FD_DOR); + + // reset the disk motor timeout value of INT 08 + SET_BDA(floppy_motor_counter, BX_FLOPPY_ON_CNT); + + // wait for drive readiness + while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80) + ; + + if (prev_reset == 0) { + irq_enable(); + u8 v; + do { + v = GET_BDA(floppy_recalibration_status); + } while ((v & FRS_TIMEOUT) == 0); + irq_disable(); + + v &= ~FRS_TIMEOUT; + SET_BDA(floppy_recalibration_status, v); + } +} + +static u8 +floppy_pio(u8 *cmd, u8 cmdlen) +{ + floppy_prepare_controller(cmd[1] & 1); + + // send command to controller + u8 i; + for (i=0; i<cmdlen; i++) + outb(cmd[i], PORT_FD_DATA); + + irq_enable(); + u8 v; + do { + if (!GET_BDA(floppy_motor_counter)) { + irq_disable(); + floppy_reset_controller(); + return DISK_RET_ETIMEOUT; + } + v = GET_BDA(floppy_recalibration_status); + } while (!(v & FRS_TIMEOUT)); + irq_disable(); + + v &= ~FRS_TIMEOUT; + SET_BDA(floppy_recalibration_status, v); + + if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) + BX_PANIC("int13_diskette: ctrl not ready\n"); + + return 0; +} + +static u8 +floppy_cmd(struct bregs *regs, u16 count, u8 *cmd, u8 cmdlen) +{ + // es:bx = pointer to where to place information from diskette + // port 04: DMA-1 base and current address, channel 2 + // port 05: DMA-1 base and current count, channel 2 + u16 page = regs->es >> 12; // upper 4 bits + u16 base_es = regs->es << 4; // lower 16bits contributed by ES + u16 base_address = base_es + regs->bx; // lower 16 bits of address + // contributed by ES:BX + if (base_address < base_es) + // in case of carry, adjust page by 1 + page++; + + // check for 64K boundary overrun + u16 last_addr = base_address + count; + if (last_addr < base_address) + return DISK_RET_EBOUNDARY; + + u8 mode_register = 0x4a; // single mode, increment, autoinit disable, + if (cmd[0] == 0xe6) + // read + mode_register = 0x46; + + DEBUGF("floppy dma c2"); + outb(0x06, PORT_DMA1_MASK_REG); + outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop + outb(base_address, PORT_DMA_ADDR_2); + outb(base_address>>8, PORT_DMA_ADDR_2); + outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop + outb(count, PORT_DMA_CNT_2); + outb(count>>8, PORT_DMA_CNT_2); + + // port 0b: DMA-1 Mode Register + // transfer type=write, channel 2 + outb(mode_register, PORT_DMA1_MODE_REG); + + // port 81: DMA-1 Page Register, channel 2 + outb(page, PORT_DMA_PAGE_2); + + outb(0x02, PORT_DMA1_MASK_REG); // unmask channel 2 + + u8 ret = floppy_pio(cmd, cmdlen); + if (ret) + return ret; + + // read 7 return status bytes from controller + u8 i; + for (i=0; i<7; i++) { + u8 v = inb(PORT_FD_DATA); + cmd[i] = v; + SET_BDA(floppy_return_status[i], v); + } + + return 0; +} + +static void +floppy_drive_recal(u8 drive) +{ + // send Recalibrate command (2 bytes) to controller + u8 data[12]; + data[0] = 0x07; // 07: Recalibrate + data[1] = drive; // 0=drive0, 1=drive1 + floppy_pio(data, 2); + + SETBITS_BDA(floppy_recalibration_status, 1<<drive); + set_diskette_current_cyl(drive, 0); +} + +static u16 +floppy_media_sense(u8 drive) +{ + u16 rv; + u8 config_data, media_state; + + floppy_drive_recal(drive); + + // for now cheat and get drive type from CMOS, + // assume media is same as drive type + + // ** config_data ** + // Bitfields for diskette media control: + // Bit(s) Description (Table M0028) + // 7-6 last data rate set by controller + // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps + // 5-4 last diskette drive step rate selected + // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah + // 3-2 {data rate at start of operation} + // 1-0 reserved + + // ** media_state ** + // Bitfields for diskette drive media state: + // Bit(s) Description (Table M0030) + // 7-6 data rate + // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps + // 5 double stepping required (e.g. 360kB in 1.2MB) + // 4 media type established + // 3 drive capable of supporting 4MB media + // 2-0 on exit from BIOS, contains + // 000 trying 360kB in 360kB + // 001 trying 360kB in 1.2MB + // 010 trying 1.2MB in 1.2MB + // 011 360kB in 360kB established + // 100 360kB in 1.2MB established + // 101 1.2MB in 1.2MB established + // 110 reserved + // 111 all other formats/drives + + switch (get_drive_type(drive)) { + case 1: + // 360K 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x25; // 0010 0101 + rv = 1; + break; + case 2: + // 1.2 MB 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5) + rv = 1; + break; + case 3: + // 720K 3.5" drive + config_data = 0x00; // 0000 0000 ??? + media_state = 0x17; // 0001 0111 + rv = 1; + break; + case 4: + // 1.44 MB 3.5" drive + config_data = 0x00; // 0000 0000 + media_state = 0x17; // 0001 0111 + rv = 1; + break; + case 5: + // 2.88 MB 3.5" drive + config_data = 0xCC; // 1100 1100 + media_state = 0xD7; // 1101 0111 + rv = 1; + break; + // + // Extended floppy size uses special cmos setting + case 6: + // 160k 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x27; // 0010 0111 + rv = 1; + break; + case 7: + // 180k 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x27; // 0010 0111 + rv = 1; + break; + case 8: + // 320k 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x27; // 0010 0111 + rv = 1; + break; + default: + // not recognized + config_data = 0x00; // 0000 0000 + media_state = 0x00; // 0000 0000 + rv = 0; + } + + SET_BDA(floppy_last_data_rate, config_data); + SET_BDA(floppy_media_state[drive], media_state); + return rv; +} + +static inline void +floppy_ret(struct bregs *regs, u8 code) +{ + regs->ah = code; + SET_BDA(floppy_last_status, code); + set_cf(regs, code); +} + +static inline void +floppy_fail(struct bregs *regs, u8 code) +{ + regs->al = 0; // no sectors read + floppy_ret(regs, code); +} + +static u16 +check_drive(struct bregs *regs, u8 drive) +{ + // see if drive exists + if (drive > 1 || !get_drive_type(drive)) { + floppy_fail(regs, DISK_RET_ETIMEOUT); + return 1; + } + + // see if media in drive, and type is known + if (floppy_media_known(drive) == 0 && floppy_media_sense(drive) == 0) { + floppy_fail(regs, DISK_RET_EMEDIA); + return 1; + } + return 0; +} + +// diskette controller reset +static void +floppy_1300(struct bregs *regs, u8 drive) +{ + if (drive > 1) { + floppy_ret(regs, DISK_RET_EPARAM); + return; + } + if (!get_drive_type(drive)) { + floppy_ret(regs, DISK_RET_ETIMEOUT); + return; + } + set_diskette_current_cyl(drive, 0); // current cylinder + floppy_ret(regs, DISK_RET_SUCCESS); +} + +// Read Diskette Status +static void +floppy_1301(struct bregs *regs, u8 drive) +{ + u8 v = GET_BDA(floppy_last_status); + regs->ah = v; + set_cf(regs, v); +} + +// Read Diskette Sectors +static void +floppy_1302(struct bregs *regs, u8 drive) +{ + if (check_drive(regs, drive)) + return; + + u8 num_sectors = regs->al; + u8 track = regs->ch; + u8 sector = regs->cl; + u8 head = regs->dh; + + if (head > 1 || sector == 0 || num_sectors == 0 + || track > 79 || num_sectors > 72) { + BX_INFO("int13_diskette: read/write/verify: parameter out of range\n"); + floppy_fail(regs, DISK_RET_EPARAM); + return; + } + + // send read-normal-data command (9 bytes) to controller + u8 data[12]; + data[0] = 0xe6; // e6: read normal data + data[1] = (head << 2) | drive; // HD DR1 DR2 + data[2] = track; + data[3] = head; + data[4] = sector; + data[5] = 2; // 512 byte sector size + data[6] = sector + num_sectors - 1; // last sector to read on track + data[7] = 0; // Gap length + data[8] = 0xff; // Gap length + + u16 ret = floppy_cmd(regs, (num_sectors * 512) - 1, data, 9); + if (ret) { + floppy_fail(regs, ret); + return; + } + + if (data[0] & 0xc0) { + floppy_fail(regs, DISK_RET_ECONTROLLER); + return; + } + + // ??? should track be new val from return_status[3] ? + set_diskette_current_cyl(drive, track); + // AL = number of sectors read (same value as passed) + floppy_ret(regs, DISK_RET_SUCCESS); +} + +// Write Diskette Sectors +static void +floppy_1303(struct bregs *regs, u8 drive) +{ + if (check_drive(regs, drive)) + return; + + u8 num_sectors = regs->al; + u8 track = regs->ch; + u8 sector = regs->cl; + u8 head = regs->dh; + + if (head > 1 || sector == 0 || num_sectors == 0 + || track > 79 || num_sectors > 72) { + BX_INFO("int13_diskette: read/write/verify: parameter out of range\n"); + floppy_fail(regs, DISK_RET_EPARAM); + return; + } + + // send write-normal-data command (9 bytes) to controller + u8 data[12]; + data[0] = 0xc5; // c5: write normal data + data[1] = (head << 2) | drive; // HD DR1 DR2 + data[2] = track; + data[3] = head; + data[4] = sector; + data[5] = 2; // 512 byte sector size + data[6] = sector + num_sectors - 1; // last sector to write on track + data[7] = 0; // Gap length + data[8] = 0xff; // Gap length + + u8 ret = floppy_cmd(regs, (num_sectors * 512) - 1, data, 9); + if (ret) { + floppy_fail(regs, ret); + return; + } + + if (data[0] & 0xc0) { + if (data[1] & 0x02) { + regs->ax = 0x0300; + set_cf(regs, 1); + return; + } + BX_PANIC("int13_diskette_function: read error\n"); + } + + // ??? should track be new val from return_status[3] ? + set_diskette_current_cyl(drive, track); + // AL = number of sectors read (same value as passed) + floppy_ret(regs, DISK_RET_SUCCESS); +} + +// Verify Diskette Sectors +static void +floppy_1304(struct bregs *regs, u8 drive) +{ + if (check_drive(regs, drive)) + return; + + u8 num_sectors = regs->al; + u8 track = regs->ch; + u8 sector = regs->cl; + u8 head = regs->dh; + + if (head > 1 || sector == 0 || num_sectors == 0 + || track > 79 || num_sectors > 72) { + BX_INFO("int13_diskette: read/write/verify: parameter out of range\n"); + floppy_fail(regs, DISK_RET_EPARAM); + return; + } + + // ??? should track be new val from return_status[3] ? + set_diskette_current_cyl(drive, track); + // AL = number of sectors verified (same value as passed) + floppy_ret(regs, DISK_RET_SUCCESS); +} + +// format diskette track +static void +floppy_1305(struct bregs *regs, u8 drive) +{ + DEBUGF("floppy f05\n"); + + if (check_drive(regs, drive)) + return; + + u8 num_sectors = regs->al; + u8 head = regs->dh; + + if (head > 1 || num_sectors == 0 || num_sectors > 18) { + BX_INFO("int13_diskette: read/write/verify: parameter out of range\n"); + floppy_fail(regs, DISK_RET_EPARAM); + return; + } + + // send format-track command (6 bytes) to controller + u8 data[12]; + data[0] = 0x4d; // 4d: format track + data[1] = (head << 2) | drive; // HD DR1 DR2 + data[2] = 2; // 512 byte sector size + data[3] = num_sectors; // number of sectors per track + data[4] = 0; // Gap length + data[5] = 0xf6; // Fill byte + + u8 ret = floppy_cmd(regs, (num_sectors * 4) - 1, data, 6); + if (ret) { + floppy_fail(regs, ret); + return; + } + + if (data[0] & 0xc0) { + if (data[1] & 0x02) { + regs->ax = 0x0300; + set_cf(regs, 1); + return; + } + BX_PANIC("int13_diskette_function: read error\n"); + } + + set_diskette_current_cyl(drive, 0); + floppy_ret(regs, 0); +} + +// read diskette drive parameters +static void +floppy_1308(struct bregs *regs, u8 drive) +{ + DEBUGF("floppy f08\n"); + + u8 drive_type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE); + u8 num_floppies = 0; + if (drive_type & 0xf0) + num_floppies++; + if (drive_type & 0x0f) + num_floppies++; + + if (drive > 1) { + regs->ax = 0; + regs->bx = 0; + regs->cx = 0; + regs->dx = 0; + regs->es = 0; + regs->di = 0; + regs->dl = num_floppies; + set_cf(regs, 0); + return; + } + + if (drive == 0) + drive_type >>= 4; + else + drive_type &= 0x0f; + + regs->bh = 0; + regs->bl = drive_type; + regs->ah = 0; + regs->al = 0; + regs->dl = num_floppies; + + switch (drive_type) { + case 0: // none + regs->cx = 0; + regs->dh = 0; // max head # + break; + + case 1: // 360KB, 5.25" + regs->cx = 0x2709; // 40 tracks, 9 sectors + regs->dh = 1; // max head # + break; + + case 2: // 1.2MB, 5.25" + regs->cx = 0x4f0f; // 80 tracks, 15 sectors + regs->dh = 1; // max head # + break; + + case 3: // 720KB, 3.5" + regs->cx = 0x4f09; // 80 tracks, 9 sectors + regs->dh = 1; // max head # + break; + + case 4: // 1.44MB, 3.5" + regs->cx = 0x4f12; // 80 tracks, 18 sectors + regs->dh = 1; // max head # + break; + + case 5: // 2.88MB, 3.5" + regs->cx = 0x4f24; // 80 tracks, 36 sectors + regs->dh = 1; // max head # + break; + + case 6: // 160k, 5.25" + regs->cx = 0x2708; // 40 tracks, 8 sectors + regs->dh = 0; // max head # + break; + + case 7: // 180k, 5.25" + regs->cx = 0x2709; // 40 tracks, 9 sectors + regs->dh = 0; // max head # + break; + + case 8: // 320k, 5.25" + regs->cx = 0x2708; // 40 tracks, 8 sectors + regs->dh = 1; // max head # + break; + + default: // ? + BX_PANIC("floppy: int13: bad floppy type\n"); + } + + /* set es & di to point to 11 byte diskette param table in ROM */ + regs->es = SEG_BIOS; + regs->di = (u16)diskette_param_table2; + /* disk status not changed upon success */ +} + +// read diskette drive type +static void +floppy_1315(struct bregs *regs, u8 drive) +{ + DEBUGF("floppy f15\n"); + if (drive > 1) { + regs->ah = 0; // only 2 drives supported + // set_diskette_ret_status here ??? + set_cf(regs, 1); + return; + } + u8 drive_type = get_drive_type(drive); + + regs->ah = (drive_type != 0); + set_cf(regs, 0); +} + +// get diskette change line status +static void +floppy_1316(struct bregs *regs, u8 drive) +{ + DEBUGF("floppy f16\n"); + if (drive > 1) { + floppy_ret(regs, DISK_RET_EPARAM); + return; + } + floppy_ret(regs, DISK_RET_ECHANGED); +} + +static void +floppy_13XX(struct bregs *regs, u8 drive) +{ + BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH()); + floppy_ret(regs, DISK_RET_EPARAM); +} + +void +floppy_13(struct bregs *regs, u8 drive) +{ + if (CONFIG_FLOPPY_SUPPORT) { + switch (regs->ah) { + case 0x00: floppy_1300(regs, drive); break; + case 0x01: floppy_1301(regs, drive); break; + case 0x02: floppy_1302(regs, drive); break; + case 0x03: floppy_1303(regs, drive); break; + case 0x04: floppy_1304(regs, drive); break; + case 0x05: floppy_1305(regs, drive); break; + case 0x08: floppy_1308(regs, drive); break; + case 0x15: floppy_1315(regs, drive); break; + case 0x16: floppy_1316(regs, drive); break; + default: floppy_13XX(regs, drive); break; + } + } else { + switch (regs->ah) { + case 0x01: floppy_1301(regs, drive); break; + default: floppy_13XX(regs, drive); break; + } + } +} + +// INT 0Eh Diskette Hardware ISR Entry Point +void VISIBLE +handle_0e(struct bregs *regs) +{ + debug_enter(regs); + if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) { + outb(0x08, PORT_FD_DATA); // sense interrupt status + while ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) + ; + do { + inb(PORT_FD_DATA); + } while ((inb(PORT_FD_STATUS) & 0xc0) == 0xc0); + } + eoi_master_pic(); + // diskette interrupt has occurred + SETBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT); +} + +// Called from int08 handler. +void +floppy_tick() +{ + // time to turn off drive(s)? + u8 fcount = GET_BDA(floppy_motor_counter); + if (fcount) { + fcount--; + SET_BDA(floppy_motor_counter, fcount); + if (fcount == 0) + // turn motor(s) off + outb(inb(PORT_FD_DOR) & 0xcf, PORT_FD_DOR); + } +} diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..01c73ed --- /dev/null +++ b/src/font.c @@ -0,0 +1,139 @@ +#include "types.h" // u8 + +// Character Font for 320x200 & 640x200 Graphics (lower 128 characters) + +/* + * This font comes from the fntcol16.zip package (c) by Joseph Gil + * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip + * This font is public domain + */ +const u8 vgafont8[128*8] __attribute__((aligned (1))) = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, + 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, + 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c, + 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, + 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, + 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, + 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, + 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, + 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0, + 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, + 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99, + 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, + 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, + 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, + 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, + 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, + 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, + 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, + 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, + 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, + 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, + 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, + 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, + 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, + 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, + 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, + 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00, + 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, + 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00, + 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, + 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, + 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, + 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00, + 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, + 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, + 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, + 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, + 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, + 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, + 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, + 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00, + 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, + 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00, + 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, + 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, + 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00, + 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, + 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, + 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, + 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, + 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00, + 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, + 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00, + 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, + 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, + 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, +}; diff --git a/src/ioport.h b/src/ioport.h new file mode 100644 index 0000000..344803e --- /dev/null +++ b/src/ioport.h @@ -0,0 +1,56 @@ +// Definitions for X86 IO port access. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. +#ifndef __IOPORT_H +#define __IOPORT_H + +#include "types.h" // u8 + +#define PORT_DMA_ADDR_2 0x0004 +#define PORT_DMA_CNT_2 0x0005 +#define PORT_DMA1_MASK_REG 0x000a +#define PORT_DMA1_MODE_REG 0x000b +#define PORT_DMA1_CLEAR_FF_REG 0x000c +#define PORT_DMA1_MASTER_CLEAR 0x000d +#define PORT_PIC1 0x0020 +#define PORT_PIC1_DATA 0x0021 +#define PORT_PIT_COUNTER0 0x0040 +#define PORT_PIT_COUNTER1 0x0041 +#define PORT_PIT_COUNTER2 0x0042 +#define PORT_PIT_MODE 0x0043 +#define PORT_KBD_CTRLB 0x0061 +#define PORT_CMOS_INDEX 0x0070 +#define PORT_CMOS_DATA 0x0071 +#define PORT_DMA_PAGE_2 0x0081 +#define PORT_A20 0x0092 +#define PORT_PIC2 0x00a0 +#define PORT_PIC2_DATA 0x00a1 +#define PORT_DMA2_MASK_REG 0x00d4 +#define PORT_DMA2_MODE_REG 0x00d6 +#define PORT_DMA2_MASTER_CLEAR 0x00da +#define PORT_FD_DOR 0x03f2 +#define PORT_FD_STATUS 0x03f4 +#define PORT_FD_DATA 0x03f5 + +// PORT_PIC1 bitdefs +#define PIC1_IRQ5 (1<<5) +// PORT_PIC2 bitdefs +#define PIC2_IRQ8 (1<<0) +#define PIC2_IRQ13 (1<<5) + +// PORT_KBD_CTRLB bitdefs +#define KBD_REFRESH (1<<4) + + +static inline void outb(u8 value, u16 port) { + __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port)); +} +static inline u8 inb(u16 port) { + u8 value; + __asm__ __volatile__("inb %w1, %b0" : "=a"(value) : "Nd"(port)); + return value; +} + +#endif // ioport.h diff --git a/src/kbd.c b/src/kbd.c new file mode 100644 index 0000000..bcc1a59 --- /dev/null +++ b/src/kbd.c @@ -0,0 +1,35 @@ +// 16bit code to handle keyboard requests. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "biosvar.h" // struct bregs +#include "util.h" // debug_enter + +void +handle_15c2(struct bregs *regs) +{ +} + +// INT 16h Keyboard Service Entry Point +void VISIBLE +handle_16(struct bregs *regs) +{ + //debug_enter(regs); +} + +// INT09h : Keyboard Hardware Service Entry Point +void VISIBLE +handle_09(struct bregs *regs) +{ + debug_enter(regs); +} + +// INT74h : PS/2 mouse hardware interrupt +void VISIBLE +handle_74(struct bregs *regs) +{ + debug_enter(regs); +} diff --git a/src/output.c b/src/output.c new file mode 100644 index 0000000..9670163 --- /dev/null +++ b/src/output.c @@ -0,0 +1,161 @@ +// Raw screen writing code. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include <stdarg.h> // va_list + +#include "farptr.h" // GET_VAR +#include "util.h" // bprintf +#include "biosvar.h" // struct bregs + +static void +screenc(char c) +{ + // XXX +} + +// XXX +#define PORT_DEBUG 0x403 + +// Write a charcter to the framebuffer. +static void +putc(u16 action, char c) +{ + screenc(c); + outb(c, PORT_DEBUG); +} + +// Write a string to the framebuffer. +static void +puts(u16 action, const char *s) +{ + for (; *s; s++) + putc(action, *s); +} + +// Write a string to the framebuffer. +static void +puts_cs(u16 action, const char *s) +{ + for (;; s++) { + char c = GET_VAR(CS, (u8)*s); + if (!c) + break; + putc(action, c); + } +} + +// Write an unsigned integer to the screen. +static void +putuint(u16 action, u32 val) +{ + char buf[12]; + char *d = &buf[sizeof(buf) - 1]; + *d-- = '\0'; + for (;;) { + *d = val % 10; + val /= 10; + if (!val) + break; + d--; + } + puts(action, d); +} + +// Write a single digit hex character to the screen. +static inline void +putsinglehex(u16 action, u32 val) +{ + if (val <= 9) + val = '0' + val; + else + val = 'a' + val - 10; + putc(action, val); +} + +// Write an integer in hexadecimal to the screen. +static void +puthex(u16 action, u32 val) +{ + putsinglehex(action, (val >> 28) & 0xf); + putsinglehex(action, (val >> 24) & 0xf); + putsinglehex(action, (val >> 20) & 0xf); + putsinglehex(action, (val >> 16) & 0xf); + putsinglehex(action, (val >> 12) & 0xf); + putsinglehex(action, (val >> 8) & 0xf); + putsinglehex(action, (val >> 4) & 0xf); + putsinglehex(action, (val >> 0) & 0xf); +} + +void +bprintf(u16 action, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + const char *s = fmt; + for (;; s++) { + char c = GET_VAR(CS, (u8)*s); + if (!c) + break; + if (c != '%') { + putc(action, c); + continue; + } + const char *n = s+1; + c = GET_VAR(CS, (u8)*n); + s32 val; + const char *sarg; + switch (c) { + case '%': + putc(action, '%'); + break; + case 'd': + val = va_arg(args, s32); + if (val < 0) { + putc(action, '-'); + val = -val; + } + putuint(action, val); + break; + case 'u': + val = va_arg(args, s32); + putuint(action, val); + break; + case 'x': + val = va_arg(args, s32); + puthex(action, val); + break; + case 's': + sarg = va_arg(args, const char *); + puts_cs(action, sarg); + break; + default: + putc(action, *s); + n = s; + } + s = n; + } + va_end(args); +} + +// Function called on handler startup. +void +__debug_enter(const char *fname, struct bregs *regs) +{ + bprintf(0, "enter %s: a=%x b=%x c=%x d=%x si=%x di=%x\n" + , fname, regs->eax, regs->ebx, regs->ecx, regs->edx + , regs->esi, regs->edi); + bprintf(0, "&=%x ds=%x es=%x bp=%x sp=%x ip=%x cs=%x f=%x\n" + , (u32)regs, regs->ds, regs->es, regs->ebp, regs->esp + , regs->ip, regs->cs, regs->flags); +} + +void +__debug_exit(const char *fname, struct bregs *regs) +{ + bprintf(0, "exit %s: a=%x b=%x c=%x d=%x s=%x i=%x\n" + , fname, regs->eax, regs->ebx, regs->ecx, regs->edx + , regs->esi, regs->edi); +} diff --git a/src/post.c b/src/post.c new file mode 100644 index 0000000..8d35f97 --- /dev/null +++ b/src/post.c @@ -0,0 +1,312 @@ +// 32bit code to Power On Self Test (POST) a machine. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "ioport.h" // PORT_* +#include "../out/rom16.offset.auto.h" // OFFSET_* +#include "config.h" // CONFIG_* +#include "cmos.h" // CMOS_* +#include "util.h" // memset +#include "biosvar.h" // struct bios_data_area_s + +#define bda ((struct bios_data_area_s *)0) +#define ebda ((struct extended_bios_data_area_s *)(EBDA_SEG<<4)) + +static void +init_bda() +{ + memset(bda, 0, sizeof(*bda)); + + int i; + for (i=0; i<256; i++) { + bda->ivecs[i].seg = 0xf000; + bda->ivecs[i].offset = OFFSET_dummy_iret_handler; + } + + bda->mem_size_kb = BASE_MEM_IN_K; +} + +static void +init_handlers() +{ + // set vector 0x79 to zero + // this is used by 'gardian angel' protection system + bda->ivecs[0x79].seg = 0; + bda->ivecs[0x79].offset = 0; + + bda->ivecs[0x40].offset = OFFSET_entry_40; + bda->ivecs[0x0e].offset = OFFSET_entry_0e; + bda->ivecs[0x13].offset = OFFSET_entry_13; + bda->ivecs[0x76].offset = OFFSET_entry_76; + bda->ivecs[0x17].offset = OFFSET_entry_17; + bda->ivecs[0x18].offset = OFFSET_entry_18; + bda->ivecs[0x19].offset = OFFSET_entry_19; + bda->ivecs[0x1c].offset = OFFSET_entry_1c; + bda->ivecs[0x12].offset = OFFSET_entry_12; + bda->ivecs[0x11].offset = OFFSET_entry_11; + bda->ivecs[0x15].offset = OFFSET_entry_15; + bda->ivecs[0x08].offset = OFFSET_entry_08; + bda->ivecs[0x09].offset = OFFSET_entry_09; + bda->ivecs[0x16].offset = OFFSET_entry_16; + bda->ivecs[0x14].offset = OFFSET_entry_14; + bda->ivecs[0x1a].offset = OFFSET_entry_1a; + bda->ivecs[0x70].offset = OFFSET_entry_70; + bda->ivecs[0x74].offset = OFFSET_entry_74; + bda->ivecs[0x75].offset = OFFSET_entry_75; + bda->ivecs[0x10].offset = OFFSET_entry_10; +} + +static void +init_ebda() +{ + ebda->size = EBDA_SIZE; + bda->ebda_seg = EBDA_SEG; + bda->ivecs[0x41].seg = EBDA_SEG; + bda->ivecs[0x41].offset = 0x3d; // XXX + bda->ivecs[0x46].seg = EBDA_SEG; + bda->ivecs[0x46].offset = 0x4d; // XXX +} + +static void +pit_setup() +{ + // timer0: binary count, 16bit count, mode 2 + outb(0x34, PORT_PIT_MODE); + // maximum count of 0000H = 18.2Hz + outb(0x0, PORT_PIT_COUNTER0); + outb(0x0, PORT_PIT_COUNTER0); +} + +static void +kbd_init() +{ +} + +static void +kbd_setup() +{ + bda->kbd_mode = 0x10; + bda->kbd_buf_head = bda->kbd_buf_tail = offsetof(struct bios_data_area_s, kbd_buf); + bda->kbd_buf_start_offset = offsetof(struct bios_data_area_s, kbd_buf); + bda->kbd_buf_end_offset = offsetof(struct bios_data_area_s, kbd_buf[sizeof(bda->kbd_buf)]); + kbd_init(); + + // XXX + u16 eqb = bda->equipment_list_flags; + eqb = (eqb & 0xff00) | inb_cmos(CMOS_EQUIPMENT_INFO); + bda->equipment_list_flags = eqb; +} + +static void +lpt_setup() +{ + // XXX +} + +static void +serial_setup() +{ + // XXX +} + +static u32 +bcd2bin(u8 val) +{ + return (val & 0xf) + ((val >> 4) * 10); +} + +static void +timer_setup() +{ + u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS)); + u32 ticks = (seconds * 18206507) / 1000000; + u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES)); + ticks += (minutes * 10923904) / 10000; + u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS)); + ticks += (hours * 65543427) / 1000; + bda->timer_counter = ticks; + bda->timer_rollover = 0; +} + +static void +pic_setup() +{ + outb(0x11, PORT_PIC1); + outb(0x11, PORT_PIC2_DATA); + outb(0x08, PORT_PIC1_DATA); + outb(0x70, PORT_PIC2_DATA); + outb(0x04, PORT_PIC1_DATA); + outb(0x02, PORT_PIC2_DATA); + outb(0x01, PORT_PIC1_DATA); + outb(0x01, PORT_PIC2_DATA); + outb(0xb8, PORT_PIC1_DATA); + if (CONFIG_PS2_MOUSE) + outb(0x8f, PORT_PIC2_DATA); + else + outb(0x9f, PORT_PIC2_DATA); +} + +static void +floppy_drive_post() +{ + u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE); + u8 out = 0; + if (type & 0xf0) + out |= 0x07; + if (type & 0x0f) + out |= 0x70; + bda->floppy_harddisk_info = out; + outb(0x02, PORT_DMA1_MASK_REG); + + bda->ivecs[0x1E].offset = OFFSET_diskette_param_table2; +} + +static void +cdemu_init() +{ + //ebda->cdemu.active = 0; +} + +static void +ata_init() +{ +} + +static void +ata_detect() +{ +} + +static void +hard_drive_post() +{ +} + +static void +init_boot_vectors() +{ +} + +static void __attribute__((noinline)) +call16(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)); +} + +static int +checksum(u8 *p, u32 len) +{ + u32 i; + u8 sum = 0; + for (i=0; i<len; i++) + sum += p[i]; + return sum; +} + +#define PTR_TO_SEG(p) ((((u32)(p)) >> 4) & 0xf000) +#define PTR_TO_OFFSET(p) (((u32)(p)) & 0xffff) + +static void +rom_scan() +{ + u8 *p = (u8*)0xc0000; + for (; p <= (u8*)0xe0000; p += 2048) { + u8 *rom = p; + if (*(u16*)rom != 0xaa55) + continue; + u32 len = rom[2] * 512; + if (checksum(rom, len) != 0) + continue; + p = (u8*)(((u32)p + len) / 2048 * 2048); + call16(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 + // all the bootable devices, but we can get away with one pass. + if (rom[0x1a] != '$' || rom[0x1b] != 'P' + || rom[0x1c] != 'n' || rom[0x1d] != 'P') + continue; + // 0x1A is also the offset into the expansion header of... + // the Bootstrap Entry Vector, or zero if there is none. + u16 entry = *(u16*)&rom[0x1a+0x1a]; + if (!entry) + continue; + // Found a device that thinks it can boot the system. Record + // its BEV and product name string. + + // XXX + } +} + +static void +status_restart(u8 status) +{ +#if 0 + if (status == 0x05) + eoi_jmp_post(); +#endif + + BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status); +} + +static void +post() +{ + // first reset the DMA controllers + outb(0, PORT_DMA1_MASTER_CLEAR); + outb(0, PORT_DMA2_MASTER_CLEAR); + + // then initialize the DMA controllers + outb(0xc0, PORT_DMA2_MODE_REG); + outb(0x00, PORT_DMA2_MASK_REG); + + // Get and then clear CMOS shutdown status. + u8 status = inb_cmos(CMOS_RESET_CODE); + outb_cmos(0, CMOS_RESET_CODE); + + if (status != 0x00 && status != 0x09 && status < 0x0d) + status_restart(status); + + BX_INFO("Start bios"); + + init_bda(); + init_handlers(); + init_ebda(); + + pit_setup(); + kbd_setup(); + lpt_setup(); + serial_setup(); + timer_setup(); + pic_setup(); + //pci_setup(); + init_boot_vectors(); + rom_scan(); + + printf("BIOS - begin\n\n"); + + floppy_drive_post(); + hard_drive_post(); + if (CONFIG_ATA) { + ata_init(); + ata_detect(); + } + cdemu_init(); + call16(0xf000, OFFSET_begin_boot); +} + +void VISIBLE +_start() +{ + post(); +} diff --git a/src/rombios32.lds.S b/src/rombios32.lds.S new file mode 100644 index 0000000..dae62d8 --- /dev/null +++ b/src/rombios32.lds.S @@ -0,0 +1,31 @@ +// Linker definitions for 32bit code +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "config.h" +#include "../out/rom16.offset.auto.h" + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start); +SECTIONS +{ + . = (OFFSET_bios16c_end | 0xf0000); + . = ALIGN(16); + _text32_start = . ; + .text : { *(.text) } + .rodata : { *(.rodata) } + . = ALIGN(16); + .data : { *(.data) } + __bss_start = . ; + .bss : { *(.bss) *(COMMON) } + _end = . ; + /DISCARD/ : { *(.stab) + *(.stabstr) + *(.comment) + *(.note) + } +} diff --git a/src/romlayout.S b/src/romlayout.S new file mode 100644 index 0000000..c9cc6ef --- /dev/null +++ b/src/romlayout.S @@ -0,0 +1,304 @@ +// Rom layout and bios assembler to C interface. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "config.h" + + .code16gcc + .text + .globl bios16c_start, bios16c_end +bios16c_start: +.include "out/blob.proc.16.s" + .text +bios16c_end: + + + .org 0xe05b + .globl _start +_start: + .globl post16 +post16: + + // Entry point of rombios32 code - the actual instruction is + // altered later in the build process. + .globl set_entry32 +set_entry32: + mov $0xf0000000, %ebx + + // init the stack pointer + movl $ CONFIG_STACK32_OFFSET , %esp + +transition32: + // Disable irqs + cli + + // enable a20 + inb $0x92, %al + orb $0x02, %al + outb %al, $0x92 + + // Set segment descriptors + lidt %cs:pmode_IDT_info + lgdt %cs:rombios32_gdt_48 + + // set PE bit in CR0 + movl %cr0, %eax + orb $0x01, %al + movl %eax, %cr0 + + // start protected mode code + .word 0xea66, 1f, 0x000f, 0x0010 // ljmpl $0x10, $(post32 | 0xf0000) + + .code32 +1: + // init data segments + movl $0x18, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + xorl %eax, %eax + movw %ax, %fs + movw %ax, %gs + + cld + + jmp *%ebx + + .code16gcc + +// We need a copy of this string, but we are not actually a PnP BIOS, +// so make sure it is *not* aligned, so OSes will not see it if they +// scan. + .align 2 + .byte 0 +pnp_string: + .ascii "$PnP" + +// Return from 32bit code to 16bit code - must pass in destination +// code segment,offset (%ebx) and the return stack position (%esp). + + .globl call16 +call16: + // restore data segment limits to 0xffff + movw $0x28, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + + // reset PE bit in CR0 + movl %cr0, %eax + andb $0xfe, %al + movl %eax, %cr0 + + // far jump to flush CPU queue after transition to real mode + ljmpw $0xf000, $1f +1: + // restore IDT to normal real-mode defaults + lidt %cs:rmode_IDT_info + + // Setup segment registers + xorw %ax, %ax + movw %ax, %ds + movw %ax, %fs + movw %ax, %gs + movw $0xf000, %ax + movw %ax, %es + lea pnp_string, %di + movw $ CONFIG_STACK16_SEGMENT , %ax + movw %ax, %ss + movl %esp, %eax + movl $ CONFIG_STACK16_OFFSET , %esp + + // Save info + pushl %eax + pushl %ebx + movl %esp, %ebp + + lcallw %ss:*(%bp) + + // Restore stack and jump back to 32bit mode. + popl %eax + popl %esp + + // Resume point of rombios32 code - the actual instruction is + // altered later in the build process. + .globl set_resume32 +set_resume32: + mov $0xf0000000, %ebx + + jmp transition32 + + +// Protected mode IDT descriptor +// +// I just make the limit 0, so the machine will shutdown +// if an exception occurs during protected mode memory +// transfers. +// +// Set base to f0000 to correspond to beginning of BIOS, +// in case I actually define an IDT later +// Set limit to 0 +pmode_IDT_info: + .word 0x0000 // limit 15:00 + .word 0x0000 // base 15:00 + .byte 0x0f // base 23:16 + +// Real mode IDT descriptor +// +// Set to typical real-mode values. +// base = 000000 +// limit = 03ff +rmode_IDT_info: + .word 0x03ff // limit 15:00 + .word 0x0000 // base 15:00 + .byte 0x00 // base 23:16 + +rombios32_gdt_48: + .word 0x30 + .word rombios32_gdt + .word 0x000f + +rombios32_gdt: + .word 0, 0, 0, 0 + .word 0, 0, 0, 0 + .word 0xffff, 0, 0x9b00, 0x00cf // 32 bit flat code segment (0x10) + .word 0xffff, 0, 0x9300, 0x00cf // 32 bit flat data segment (0x18) + .word 0xffff, 0, 0x9b0f, 0x0000 // 16 bit code segment base=0xf0000 limit=0xffff + .word 0xffff, 0, 0x9300, 0x0000 // 16 bit data segment base=0x0 limit=0xffff + + + .macro ENTRY cfunc + pushal + pushw %es + pushw %ds + movw %ss, %ax + movw %ax, %ds + mov %esp, %eax + call \cfunc + popw %ds + popw %es + popal + .endm + + .macro IRQ_ENTRY num + .globl entry_\num + entry_\num : + ENTRY handle_\num + iretw + .endm + + + .org 0xe2c3 + IRQ_ENTRY nmi + + IRQ_ENTRY 13 + IRQ_ENTRY 19 + IRQ_ENTRY 12 + IRQ_ENTRY 11 + IRQ_ENTRY 76 + IRQ_ENTRY 18 + IRQ_ENTRY 1c + IRQ_ENTRY 70 + IRQ_ENTRY 74 + IRQ_ENTRY 75 + + .org 0xe3fe + jmp entry_13 + + .org 0xe401 + // XXX - Fixed Disk Parameter Table + + .org 0xe6f2 + jmp entry_19 + + .org 0xe6f5 +.include "out/cbt.proc.16.s" + .text + + .org 0xe729 + // XXX - Baud Rate Generator Table + + .org 0xe739 + IRQ_ENTRY 14 + + .org 0xe82e + IRQ_ENTRY 16 + + .org 0xe987 + IRQ_ENTRY 09 + + .org 0xec59 + IRQ_ENTRY 40 + + .org 0xef57 + IRQ_ENTRY 0e + + .org 0xefc7 + // XXX - Diskette Controller Parameter Table + + .org 0xefd2 + IRQ_ENTRY 17 + + .org 0xf045 + // XXX int 10 + iretw + + .org 0xf065 + IRQ_ENTRY 10 + + .org 0xf0a4 + // XXX int 1D + iretw + + .org 0xf841 + jmp entry_12 + + .org 0xf84d + jmp entry_11 + + .org 0xf859 + IRQ_ENTRY 15 + + .org 0xfa6e +.include "out/font.proc.16.s" + .text + + .org 0xfe6e + IRQ_ENTRY 1a + + .org 0xfea5 + IRQ_ENTRY 08 + + .org 0xfef3 + // XXX - Initial Interrupt Vector Offsets Loaded by POST + + .org 0xff00 + // XXX - BIOS_COPYRIGHT_STRING + .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team." + + .org 0xff53 + .globl dummy_iret_handler +dummy_iret_handler: + iretw + + .org 0xff54 + IRQ_ENTRY 05 + + .org 0xfff0 // Power-up Entry Point + ljmpw $0xf000, $post16 + + .org 0xfff5 + // BIOS build date + .ascii "06/23/99" + + .org 0xfffe + // model byte 0xFC = AT + .byte 0xfc + .byte 0x00 + + .end diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 0000000..5541089 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,23 @@ +// 16bit code to handle serial and printer services. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "biosvar.h" // struct bregs +#include "util.h" // debug_enter + +// INT 14h Serial Communications Service Entry Point +void VISIBLE +handle_14(struct bregs *regs) +{ + debug_enter(regs); +} + +// INT17h : Printer Service Entry Point +void VISIBLE +handle_17(struct bregs *regs) +{ + debug_enter(regs); +} diff --git a/src/system.c b/src/system.c new file mode 100644 index 0000000..3967fc4 --- /dev/null +++ b/src/system.c @@ -0,0 +1,529 @@ +// 16bit system callbacks +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "util.h" // irq_restore +#include "biosvar.h" // CONFIG_BIOS_TABLE +#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) +{ + // get current setting first + u8 newval, oldval = inb(PORT_A20); + if (cond) + newval = oldval | 0x02; + else + newval = oldval & ~0x02; + outb(newval, PORT_A20); + + 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) +{ + set_a20(0); + handle_ret(regs, 0); +} + +static void +handle_152401(struct bregs *regs) +{ + set_a20(1); + handle_ret(regs, 0); +} + +static void +handle_152402(struct bregs *regs) +{ + regs->al = !!(inb(PORT_A20) & 0x20); + handle_ret(regs, 0); +} + +static void +handle_152403(struct bregs *regs) +{ + regs->bx = 3; + handle_ret(regs, 0); +} + +static void +handle_1524XX(struct bregs *regs) +{ + handle_ret(regs, RET_EUNSUPPORTED); +} + +// removable media eject +static void +handle_1552(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) +{ + 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); +} + +// Sleep for n microseconds. currently using the +// refresh request port 0x61 bit4, toggling every 15usec +static void +usleep(u32 count) +{ + count = count / 15; + u8 kbd = inb(PORT_KBD_CTRLB); + while (count) + if ((inb(PORT_KBD_CTRLB) ^ kbd) & KBD_REFRESH) + count--; +} + +// Wait for CX:DX microseconds. currently using the +// refresh request port 0x61 bit4, toggling every 15usec +static void +handle_1586(struct bregs *regs) +{ + irq_enable(); + usleep((regs->cx << 16) | regs->dx); + irq_disable(); +} + +static void +handle_1587(struct bregs *regs) +{ + // +++ should probably have descriptor checks + // +++ should have exception handlers + + // turn off interrupts + unsigned long flags = irq_save(); + + u8 prev_a20_enable = set_a20(1); // enable A20 line + + // 128K max of transfer on 386+ ??? + // source == destination ??? + + // ES:SI points to descriptor table + // offset use initially comments + // ============================================== + // 00..07 Unused zeros Null descriptor + // 08..0f GDT zeros filled in by BIOS + // 10..17 source ssssssss source of data + // 18..1f dest dddddddd destination of data + // 20..27 CS zeros filled in by BIOS + // 28..2f SS zeros filled in by BIOS + + //es:si + //eeee0 + //0ssss + //----- + +// check for access rights of source & dest here + + // Initialize GDT descriptor + u16 si = regs->si; + u16 base15_00 = (regs->es << 4) + si; + u16 base23_16 = regs->es >> 12; + if (base15_00 < (regs->es<<4)) + base23_16++; + SET_VAR(ES, *(u16*)(si+0x08+0), 47); // limit 15:00 = 6 * 8bytes/descriptor + SET_VAR(ES, *(u16*)(si+0x08+2), base15_00);// base 15:00 + SET_VAR(ES, *(u8 *)(si+0x08+4), base23_16);// base 23:16 + SET_VAR(ES, *(u8 *)(si+0x08+5), 0x93); // access + SET_VAR(ES, *(u16*)(si+0x08+6), 0x0000); // base 31:24/reserved/limit 19:16 + + // Initialize CS descriptor + SET_VAR(ES, *(u16*)(si+0x20+0), 0xffff);// limit 15:00 = normal 64K limit + SET_VAR(ES, *(u16*)(si+0x20+2), 0x0000);// base 15:00 + SET_VAR(ES, *(u8 *)(si+0x20+4), 0x000f);// base 23:16 + SET_VAR(ES, *(u8 *)(si+0x20+5), 0x9b); // access + SET_VAR(ES, *(u16*)(si+0x20+6), 0x0000);// base 31:24/reserved/limit 19:16 + + // Initialize SS descriptor + u16 ss = GET_SEG(SS); + base15_00 = ss << 4; + base23_16 = ss >> 12; + SET_VAR(ES, *(u16*)(si+0x28+0), 0xffff); // limit 15:00 = normal 64K limit + SET_VAR(ES, *(u16*)(si+0x28+2), base15_00);// base 15:00 + SET_VAR(ES, *(u8 *)(si+0x28+4), base23_16);// base 23:16 + SET_VAR(ES, *(u8 *)(si+0x28+5), 0x93); // access + SET_VAR(ES, *(u16*)(si+0x28+6), 0x0000); // base 31:24/reserved/limit 19:16 + + asm volatile( + // Save registers + "pushw %%ds\n" + "pushw %%es\n" + "pushal\n" + + // Load new descriptor tables + "lgdt %%es:(%1)\n" + "lidt %%cs:pmode_IDT_info\n" + + // set PE bit in CR0 + "movl %%cr0, %%eax\n" + "orb $0x01, %%al\n" + "movl %%eax, %%cr0\n" + + // far jump to flush CPU queue after transition to protected mode + "ljmpw $0xf000, $1f\n" + "1:\n" + + // GDT points to valid descriptor table, now load DS, ES + "movw $0x10, %%ax\n" // 010 000 = 2nd descriptor in table, TI=GDT, RPL=00 + "movw %%ax, %%ds\n" + "movw $0x18, %%ax\n" // 011 000 = 3rd descriptor in table, TI=GDT, RPL=00 + "movw %%ax, %%es\n" + + // move CX words from DS:SI to ES:DI + "xorw %%si, %%si\n" + "xorw %%di, %%di\n" + "cld\n" + "rep movsw\n" + + // reset PG bit in CR0 ??? + "movl %%cr0, %%eax\n" + "andb $0xfe, %%al\n" + "movl %%eax, %%cr0\n" + + // far jump to flush CPU queue after transition to real mode + "ljmpw $0xf000, $2f\n" + "2:\n" + + // restore IDT to normal real-mode defaults + "lidt %%cs:rmode_IDT_info\n" + + // restore regisers + "popal\n" + "popw %%es\n" + "popw %%ds\n" : : "c" (regs->cx), "r" (si + 8)); + + set_a20(prev_a20_enable); + + irq_restore(flags); + + handle_ret(regs, 0); +} + +// Get the amount of extended memory (above 1M) +static void +handle_1588(struct bregs *regs) +{ + regs->al = inb_cmos(CMOS_EXTMEM_LOW); + regs->ah = inb_cmos(CMOS_EXTMEM_HIGH); + // According to Ralf Brown's interrupt the limit should be 15M, + // but real machines mostly return max. 63M. + if (regs->ax > 0xffc0) + regs->ax = 0xffc0; + set_cf(regs, 0); +} + +// Device busy interrupt. Called by Int 16h when no key available +static void +handle_1590(struct bregs *regs) +{ +} + +// Interrupt complete. Called by Int 16h when key becomes available +static void +handle_1591(struct bregs *regs) +{ +} + +static void +handle_15c0(struct bregs *regs) +{ + regs->es = SEG_BIOS; + regs->bx = (u16)&BIOS_CONFIG_TABLE; +} + +static void +handle_15c1(struct bregs *regs) +{ + regs->es = GET_BDA(ebda_seg); + set_cf(regs, 0); +} + +static void +handle_15e801(struct bregs *regs) +{ + // my real system sets ax and bx to 0 + // this is confirmed by Ralph Brown list + // but syslinux v1.48 is known to behave + // strangely if ax is set to 0 + // regs.u.r16.ax = 0; + // regs.u.r16.bx = 0; + + // Get the amount of extended memory (above 1M) + regs->cl = inb_cmos(CMOS_EXTMEM_LOW); + regs->ch = inb_cmos(CMOS_EXTMEM_HIGH); + + // limit to 15M + if (regs->cx > 0x3c00) + regs->cx = 0x3c00; + + // Get the amount of extended memory above 16M in 64k blocs + regs->dl = inb_cmos(CMOS_EXTMEM2_LOW); + regs->dh = inb_cmos(CMOS_EXTMEM2_HIGH); + + // Set configured memory equal to extended memory + regs->ax = regs->cx; + regs->bx = regs->dx; + + set_cf(regs, 0); +} + +#define ACPI_DATA_SIZE 0x00010000L + +static void +set_e820_range(u16 DI, u32 start, u32 end, u16 type) +{ + SET_VAR(ES, *(u16*)(DI+0), start); + SET_VAR(ES, *(u16*)(DI+2), start >> 16); + SET_VAR(ES, *(u16*)(DI+4), 0x00); + SET_VAR(ES, *(u16*)(DI+6), 0x00); + + end -= start; + SET_VAR(ES, *(u16*)(DI+8), end); + SET_VAR(ES, *(u16*)(DI+10), end >> 16); + SET_VAR(ES, *(u16*)(DI+12), 0x0000); + SET_VAR(ES, *(u16*)(DI+14), 0x0000); + + SET_VAR(ES, *(u16*)(DI+16), type); + SET_VAR(ES, *(u16*)(DI+18), 0x0); +} + +// XXX - should create e820 memory map in post and just copy it here. +static void +handle_15e820(struct bregs *regs) +{ + if (regs->edx != 0x534D4150) { + handle_ret(regs, RET_EUNSUPPORTED); + return; + } + + u32 extended_memory_size = inb_cmos(CMOS_EXTMEM2_HIGH); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(CMOS_EXTMEM2_LOW); + extended_memory_size *= 64; + // greater than EFF00000??? + if (extended_memory_size > 0x3bc000) + // everything after this is reserved memory until we get to 0x100000000 + extended_memory_size = 0x3bc000; + extended_memory_size *= 1024; + extended_memory_size += (16L * 1024 * 1024); + + if (extended_memory_size <= (16L * 1024 * 1024)) { + extended_memory_size = inb_cmos(CMOS_EXTMEM_HIGH); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(CMOS_EXTMEM_LOW); + extended_memory_size *= 1024; + } + + switch (regs->bx) { + case 0: + set_e820_range(regs->di, 0x0000000L, 0x0009fc00L, 1); + regs->ebx = 1; + regs->eax = 0x534D4150; + regs->ecx = 0x14; + set_cf(regs, 0); + break; + case 1: + set_e820_range(regs->di, 0x0009fc00L, 0x000a0000L, 2); + regs->ebx = 2; + regs->eax = 0x534D4150; + regs->ecx = 0x14; + set_cf(regs, 0); + break; + case 2: + set_e820_range(regs->di, 0x000e8000L, 0x00100000L, 2); + regs->ebx = 3; + regs->eax = 0x534D4150; + regs->ecx = 0x14; + set_cf(regs, 0); + break; + case 3: + set_e820_range(regs->di, 0x00100000L, + extended_memory_size - ACPI_DATA_SIZE, 1); + regs->ebx = 4; + regs->eax = 0x534D4150; + regs->ecx = 0x14; + set_cf(regs, 0); + break; + case 4: + set_e820_range(regs->di, + extended_memory_size - ACPI_DATA_SIZE, + extended_memory_size, 3); // ACPI RAM + regs->ebx = 5; + regs->eax = 0x534D4150; + regs->ecx = 0x14; + set_cf(regs, 0); + break; + case 5: + /* 256KB BIOS area at the end of 4 GB */ + set_e820_range(regs->di, 0xfffc0000L, 0x00000000L, 2); + regs->ebx = 0; + regs->eax = 0x534D4150; + regs->ecx = 0x14; + set_cf(regs, 0); + break; + default: /* AX=E820, DX=534D4150, BX unrecognized */ + 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); +} + +// INT 15h System Services Entry Point +void VISIBLE +handle_15(struct bregs *regs) +{ + debug_enter(regs); + switch (regs->ah) { + case 0x24: + switch (regs->al) { + case 0x00: handle_152400(regs); break; + case 0x01: handle_152401(regs); break; + case 0x02: handle_152402(regs); break; + case 0x03: handle_152403(regs); break; + default: handle_1524XX(regs); break; + } + 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 0x86: handle_1586(regs); break; + case 0x87: handle_1587(regs); break; + case 0x88: handle_1588(regs); break; + case 0x90: handle_1590(regs); break; + case 0x91: handle_1591(regs); break; + case 0xc0: handle_15c0(regs); break; + case 0xc1: handle_15c1(regs); break; + case 0xc2: handle_15c2(regs); break; + case 0xe8: + switch (regs->al) { + case 0x01: handle_15e801(regs); break; + case 0x20: handle_15e820(regs); break; + default: handle_15e8XX(regs); break; + } + break; + default: handle_15XX(regs); break; + } + debug_exit(regs); +} + +// INT 12h Memory Size Service Entry Point +void VISIBLE +handle_12(struct bregs *regs) +{ + debug_enter(regs); + regs->ax = GET_BDA(mem_size_kb); + debug_exit(regs); +} + +// INT 11h Equipment List Service Entry Point +void VISIBLE +handle_11(struct bregs *regs) +{ + debug_enter(regs); + regs->ax = GET_BDA(equipment_list_flags); + debug_exit(regs); +} + +// INT 05h Print Screen Service Entry Point +void VISIBLE +handle_05(struct bregs *regs) +{ + debug_enter(regs); +} + +// INT 10h Video Support Service Entry Point +void VISIBLE +handle_10(struct bregs *regs) +{ + debug_enter(regs); + // dont do anything, since the VGA BIOS handles int10h requests +} + +void VISIBLE +handle_nmi(struct bregs *regs) +{ + debug_enter(regs); + // XXX +} + +// INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION +void VISIBLE +handle_75(struct bregs *regs) +{ + debug_enter(regs); +} diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..ea245bf --- /dev/null +++ b/src/types.h @@ -0,0 +1,21 @@ +// Basic type definitions for X86 cpus. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. +#ifndef __TYPES_H +#define __TYPES_H + +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned int u32; +typedef signed int s32; +typedef u32 size_t; + +#define VISIBLE __attribute__((externally_visible)) + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif // types.h diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..0870ad5 --- /dev/null +++ b/src/util.h @@ -0,0 +1,55 @@ +// Basic x86 asm functions and function defs. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "ioport.h" // outb + +static inline void irq_disable(void) { + asm volatile("cli": : :"memory"); +} + +static inline void irq_enable(void) { + asm volatile("sti": : :"memory"); +} + +static inline unsigned long irq_save(void) +{ + unsigned long flags; + asm volatile("pushfl ; popl %0" : "=g" (flags)); + irq_disable(); + return flags; +} + +static inline void irq_restore(unsigned long flags) +{ + asm volatile("pushl %0 ; popfl" : : "g" (flags) : "memory", "cc"); +} + +#define DEBUGF(fmt, args...) +#define BX_PANIC(fmt, args...) +#define BX_INFO(fmt, args...) + +static inline void +memset(void *s, int c, size_t n) +{ + while (n) + ((char *)s)[n--] = c; +} + +// output.c +void bprintf(u16 action, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); +struct bregs; +void __debug_enter(const char *fname, struct bregs *regs); +void __debug_exit(const char *fname, struct bregs *regs); +#define debug_enter(regs) \ + __debug_enter(__func__, regs) +#define debug_exit(regs) \ + __debug_exit(__func__, regs) +#define printf(fmt, args...) \ + bprintf(0, fmt , ##args ) + +// kbd.c +void handle_15c2(struct bregs *regs); |