Skip to content

Commit

Permalink
Version 0.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinOConnor committed Feb 26, 2008
1 parent f076a3e commit 4b60c00
Show file tree
Hide file tree
Showing 15 changed files with 1,010 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -8,7 +8,7 @@
OUT=out/

# Source files
SRC16=floppy.c disk.c system.c clock.c serial.c kbd.c output.c boot.c
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)
Expand Down
17 changes: 8 additions & 9 deletions src/biosvar.h
Expand Up @@ -32,7 +32,8 @@ struct bios_data_area_s {
u16 mem_size_kb;
u8 pad2;
u8 ps2_ctrl_flag;
u16 kbd_flag;
u8 kbd_flag0;
u8 kbd_flag1;
u8 alt_keypad;
u16 kbd_buf_head;
u16 kbd_buf_tail;
Expand Down Expand Up @@ -85,13 +86,10 @@ struct bios_data_area_s {
#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 GET_BDA(var) \
GET_FARVAR(0x0000, ((struct bios_data_area_s *)0)->var)
#define SET_BDA(var, val) \
SET_FARVAR(0x0000, ((struct bios_data_area_s *)0)->var, (val))
#define CLEARBITS_BDA(var, val) do { \
typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
SET_BDA(var, (__val & ~(val))); \
Expand Down Expand Up @@ -149,7 +147,8 @@ struct bregs {
} __attribute__((packed));

// bregs flags bitdefs
#define F_CF (1<<9)
#define F_ZF (1<<6)
#define F_CF (1<<0)

static inline void
set_cf(struct bregs *regs, int cond)
Expand Down
233 changes: 231 additions & 2 deletions src/clock.c
Expand Up @@ -8,13 +8,242 @@
#include "biosvar.h" // struct bregs
#include "util.h" // debug_enter
#include "disk.h" // floppy_tick
#include "cmos.h" // inb_cmos

static void
init_rtc()
{
outb_cmos(0x26, CMOS_STATUS_A);
outb_cmos(0x02, CMOS_STATUS_B);
inb_cmos(CMOS_STATUS_C);
inb_cmos(CMOS_STATUS_D);
}

static u8
rtc_updating()
{
// This function checks to see if the update-in-progress bit
// is set in CMOS Status Register A. If not, it returns 0.
// If it is set, it tries to wait until there is a transition
// to 0, and will return 0 if such a transition occurs. A 1
// is returned only after timing out. The maximum period
// that this bit should be set is constrained to 244useconds.
// The count I use below guarantees coverage or more than
// this time, with any reasonable IPS setting.

u16 count = 25000;
while (--count != 0) {
if ( (inb_cmos(CMOS_STATUS_A) & 0x80) == 0 )
return 0;
}
return 1; // update-in-progress never transitioned to 0
}

// get current clock count
static void
handle_1a00(struct bregs *regs)
{
u32 ticks = GET_BDA(timer_counter);
regs->cx = ticks >> 16;
regs->dx = ticks;
regs->al = GET_BDA(timer_rollover);
SET_BDA(timer_rollover, 0); // reset flag
set_cf(regs, 0);
}

// Set Current Clock Count
static void
handle_1a01(struct bregs *regs)
{
u32 ticks = (regs->cx << 16) | regs->dx;
SET_BDA(timer_counter, ticks);
SET_BDA(timer_rollover, 0); // reset flag
regs->ah = 0;
set_cf(regs, 0);
}

// Read CMOS Time
static void
handle_1a02(struct bregs *regs)
{
if (rtc_updating()) {
set_cf(regs, 1);
return;
}

regs->dh = inb_cmos(CMOS_RTC_SECONDS);
regs->cl = inb_cmos(CMOS_RTC_MINUTES);
regs->ch = inb_cmos(CMOS_RTC_HOURS);
regs->dl = inb_cmos(CMOS_STATUS_B) & 0x01;
regs->ah = 0;
regs->al = regs->ch;
set_cf(regs, 0);
}

// Set CMOS Time
static void
handle_1a03(struct bregs *regs)
{
// Using a debugger, I notice the following masking/setting
// of bits in Status Register B, by setting Reg B to
// a few values and getting its value after INT 1A was called.
//
// try#1 try#2 try#3
// before 1111 1101 0111 1101 0000 0000
// after 0110 0010 0110 0010 0000 0010
//
// Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
// My assumption: RegB = ((RegB & 01100000b) | 00000010b)
if (rtc_updating()) {
init_rtc();
// fall through as if an update were not in progress
}
outb_cmos(regs->dh, CMOS_RTC_SECONDS);
outb_cmos(regs->cl, CMOS_RTC_MINUTES);
outb_cmos(regs->ch, CMOS_RTC_HOURS);
// Set Daylight Savings time enabled bit to requested value
u8 val8 = (inb_cmos(CMOS_STATUS_B) & 0x60) | 0x02 | (regs->dl & 0x01);
outb_cmos(val8, CMOS_STATUS_B);
regs->ah = 0;
regs->al = val8; // val last written to Reg B
set_cf(regs, 0);
}

// Read CMOS Date
static void
handle_1a04(struct bregs *regs)
{
regs->ah = 0;
if (rtc_updating()) {
set_cf(regs, 1);
return;
}
regs->cl = inb_cmos(CMOS_RTC_YEAR);
regs->dh = inb_cmos(CMOS_RTC_MONTH);
regs->dl = inb_cmos(CMOS_RTC_DAY_MONTH);
regs->ch = inb_cmos(CMOS_CENTURY);
regs->al = regs->ch;
set_cf(regs, 0);
}

// Set CMOS Date
static void
handle_1a05(struct bregs *regs)
{
// Using a debugger, I notice the following masking/setting
// of bits in Status Register B, by setting Reg B to
// a few values and getting its value after INT 1A was called.
//
// try#1 try#2 try#3 try#4
// before 1111 1101 0111 1101 0000 0010 0000 0000
// after 0110 1101 0111 1101 0000 0010 0000 0000
//
// Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
// My assumption: RegB = (RegB & 01111111b)
if (rtc_updating()) {
init_rtc();
set_cf(regs, 1);
return;
}
outb_cmos(regs->cl, CMOS_RTC_YEAR);
outb_cmos(regs->dh, CMOS_RTC_MONTH);
outb_cmos(regs->dl, CMOS_RTC_DAY_MONTH);
outb_cmos(regs->ch, CMOS_CENTURY);
u8 val8 = inb_cmos(CMOS_STATUS_B) & 0x7f; // clear halt-clock bit
outb_cmos(val8, CMOS_STATUS_B);
regs->ah = 0;
regs->al = val8; // AL = val last written to Reg B
set_cf(regs, 0);
}

// Set Alarm Time in CMOS
static void
handle_1a06(struct bregs *regs)
{
// Using a debugger, I notice the following masking/setting
// of bits in Status Register B, by setting Reg B to
// a few values and getting its value after INT 1A was called.
//
// try#1 try#2 try#3
// before 1101 1111 0101 1111 0000 0000
// after 0110 1111 0111 1111 0010 0000
//
// Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
// My assumption: RegB = ((RegB & 01111111b) | 00100000b)
u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B
regs->ax = 0;
if (val8 & 0x20) {
// Alarm interrupt enabled already
set_cf(regs, 1);
return;
}
if (rtc_updating()) {
init_rtc();
// fall through as if an update were not in progress
}
outb_cmos(regs->dh, CMOS_RTC_SECONDS_ALARM);
outb_cmos(regs->cl, CMOS_RTC_MINUTES_ALARM);
outb_cmos(regs->ch, CMOS_RTC_HOURS_ALARM);
outb(inb(PORT_PIC2_DATA) & ~PIC2_IRQ8, PORT_PIC2_DATA); // enable IRQ 8
// enable Status Reg B alarm bit, clear halt clock bit
outb_cmos((val8 & 0x7f) | 0x20, CMOS_STATUS_B);
set_cf(regs, 0);
}

// Turn off Alarm
static void
handle_1a07(struct bregs *regs)
{
// Using a debugger, I notice the following masking/setting
// of bits in Status Register B, by setting Reg B to
// a few values and getting its value after INT 1A was called.
//
// try#1 try#2 try#3 try#4
// before 1111 1101 0111 1101 0010 0000 0010 0010
// after 0100 0101 0101 0101 0000 0000 0000 0010
//
// Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
// My assumption: RegB = (RegB & 01010111b)
u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B
// clear clock-halt bit, disable alarm bit
outb_cmos(val8 & 0x57, CMOS_STATUS_B); // disable alarm bit
regs->ah = 0;
regs->al = val8; // val last written to Reg B
set_cf(regs, 0);
}

static void
handle_1ab1(struct bregs *regs)
{
// XXX - pcibios stuff
set_cf(regs, 1);
}

// Unsupported
static void
handle_1aXX(struct bregs *regs)
{
set_cf(regs, 1);
}

// INT 1Ah Time-of-day Service Entry Point
void VISIBLE
handle_1a(struct bregs *regs)
{
debug_enter(regs);
set_cf(regs, 1);
//debug_enter(regs);
switch (regs->ah) {
case 0x00: handle_1a00(regs); break;
case 0x01: handle_1a01(regs); break;
case 0x02: handle_1a02(regs); break;
case 0x03: handle_1a03(regs); break;
case 0x04: handle_1a04(regs); break;
case 0x05: handle_1a05(regs); break;
case 0x06: handle_1a06(regs); break;
case 0x07: handle_1a07(regs); break;
case 0xb1: handle_1ab1(regs); break;
default: handle_1aXX(regs); break;
}
debug_exit(regs);
}

// User Timer Tick
Expand Down
8 changes: 8 additions & 0 deletions src/cmos.h
Expand Up @@ -14,12 +14,20 @@
#define CMOS_RTC_MINUTES_ALARM 0x03
#define CMOS_RTC_HOURS 0x04
#define CMOS_RTC_HOURS_ALARM 0x05
#define CMOS_RTC_DAY_WEEK 0x06
#define CMOS_RTC_DAY_MONTH 0x07
#define CMOS_RTC_MONTH 0x08
#define CMOS_RTC_YEAR 0x09
#define CMOS_STATUS_A 0x0a
#define CMOS_STATUS_B 0x0b
#define CMOS_STATUS_C 0x0c
#define CMOS_STATUS_D 0x0d
#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_CENTURY 0x32
#define CMOS_EXTMEM2_LOW 0x34
#define CMOS_EXTMEM2_HIGH 0x35

Expand Down
2 changes: 1 addition & 1 deletion src/disk.c
Expand Up @@ -44,7 +44,7 @@ handle_40(struct bregs *regs)
void VISIBLE
handle_13(struct bregs *regs)
{
debug_enter(regs);
//debug_enter(regs);
u8 drive = regs->dl;
#if BX_ELTORITO_BOOT
if (regs->ah >= 0x4a || regs->ah <= 0x4d) {
Expand Down
13 changes: 0 additions & 13 deletions src/disk.h
Expand Up @@ -14,19 +14,6 @@
#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);
Expand Down
28 changes: 24 additions & 4 deletions src/farptr.h
Expand Up @@ -29,7 +29,7 @@
__asm__ __volatile__("movl %0, %%" #SEG ":%1" \
: : "r"(value), "m"(var))

#define GET_VAR(seg, var) ({ \
#define __GET_VAR(seg, var) ({ \
typeof(var) __val; \
if (__builtin_types_compatible_p(typeof(__val), u8)) \
__val = READ8_SEG(seg, var); \
Expand All @@ -39,7 +39,7 @@
__val = READ32_SEG(seg, var); \
__val; })

#define SET_VAR(seg, var, val) do { \
#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)) \
Expand All @@ -48,10 +48,30 @@
WRITE32_SEG(seg, var, (val)); \
} while (0)

#define SET_SEG(SEG, value) \
#define __SET_SEG(SEG, value) \
__asm__ __volatile__("movw %w0, %%" #SEG : : "r"(value))
#define GET_SEG(SEG) ({ \
#define __GET_SEG(SEG) ({ \
u16 __seg; \
__asm__ __volatile__("movw %%" #SEG ", %w0" : "=r"(__seg)); \
__seg;})

#ifdef MODE16
#define GET_VAR(seg, var) __GET_VAR(seg, var)
#define SET_VAR(seg, var, val) __SET_VAR(seg, var, val)
#define SET_SEG(SEG, value) __SET_SEG(SEG, value)
#define GET_SEG(SEG) __GET_SEG(SEG)
#else
// In 32-bit mode there is no need to mess with the segments.
#define GET_VAR(seg, var) (var)
#define SET_VAR(seg, var, val) (var) = (val)
#define SET_SEG(SEG, value) ((void)(value))
#define GET_SEG(SEG) 0
#endif

#define GET_FARVAR(seg, var) ({ \
SET_SEG(ES, (seg)); \
GET_VAR(ES, (var)); })
#define SET_FARVAR(seg, var, val) do { \
SET_SEG(ES, (seg)); \
SET_VAR(ES, (var), val); \
} while (0)

0 comments on commit 4b60c00

Please sign in to comment.