diff --git a/defs.h b/defs.h index 560b19a..43431e3 100644 --- a/defs.h +++ b/defs.h @@ -4,6 +4,7 @@ struct file; struct inode; struct pipe; struct proc; +struct rtcdate; struct spinlock; struct stat; struct superblock; @@ -71,6 +72,7 @@ void kinit2(void*, void*); void kbdintr(void); // lapic.c +void cmostime(struct rtcdate *r); int cpunum(void); extern volatile uint* lapic; void lapiceoi(void); diff --git a/lapic.c b/lapic.c index 94b484f..4da4214 100644 --- a/lapic.c +++ b/lapic.c @@ -3,6 +3,7 @@ #include "types.h" #include "defs.h" +#include "date.h" #include "memlayout.h" #include "traps.h" #include "mmu.h" @@ -130,7 +131,8 @@ microdelay(int us) { } -#define IO_RTC 0x70 +#define CMOS_PORT 0x70 +#define CMOS_RETURN 0x71 // Start additional processor running entry code at addr. // See Appendix B of MultiProcessor Specification. @@ -143,8 +145,8 @@ lapicstartap(uchar apicid, uint addr) // "The BSP must initialize CMOS shutdown code to 0AH // and the warm reset vector (DWORD based at 40:67) to point at // the AP startup code prior to the [universal startup algorithm]." - outb(IO_RTC, 0xF); // offset 0xF is shutdown code - outb(IO_RTC+1, 0x0A); + outb(CMOS_PORT, 0xF); // offset 0xF is shutdown code + outb(CMOS_PORT+1, 0x0A); wrv = (ushort*)P2V((0x40<<4 | 0x67)); // Warm reset vector wrv[0] = 0; wrv[1] = addr >> 4; @@ -169,4 +171,67 @@ lapicstartap(uchar apicid, uint addr) } } +#define CMOS_STATA 0x0a +#define CMOS_STATB 0x0b +#define CMOS_UIP (1 << 7) // RTC update in progress +#define SECS 0x00 +#define MINS 0x02 +#define HOURS 0x04 +#define DAY 0x07 +#define MONTH 0x08 +#define YEAR 0x09 + +static uint cmos_read(uint reg) +{ + outb(CMOS_PORT, reg); + microdelay(200); + + return inb(CMOS_RETURN); +} + +static void fill_rtcdate(struct rtcdate *r) +{ + r->second = cmos_read(SECS); + r->minute = cmos_read(MINS); + r->hour = cmos_read(HOURS); + r->day = cmos_read(DAY); + r->month = cmos_read(MONTH); + r->year = cmos_read(YEAR); +} + +// qemu seems to use 24-hour GWT and the values are BCD encoded +void cmostime(struct rtcdate *r) +{ + struct rtcdate t1, t2; + int sb, bcd; + + sb = cmos_read(CMOS_STATB); + + bcd = (sb & (1 << 2)) == 0; + + // make sure CMOS doesn't modify time while we read it + for (;;) { + fill_rtcdate(&t1); + if (cmos_read(CMOS_STATA) & CMOS_UIP) + continue; + fill_rtcdate(&t2); + if (memcmp(&t1, &t2, sizeof(t1)) == 0) + break; + } + + // convert + if (bcd) { +#define CONV(x) (t1.x = ((t1.x >> 4) * 10) + (t1.x & 0xf)) + CONV(second); + CONV(minute); + CONV(hour ); + CONV(day ); + CONV(month ); + CONV(year ); +#undef CONV + } + + *r = t1; + r->year += 2000; +} diff --git a/sysproc.c b/sysproc.c index c66339e..027a5e5 100644 --- a/sysproc.c +++ b/sysproc.c @@ -1,6 +1,7 @@ #include "types.h" #include "x86.h" #include "defs.h" +#include "date.h" #include "param.h" #include "memlayout.h" #include "mmu.h" diff --git a/user.h b/user.h index 9e26cf1..f45b8d5 100644 --- a/user.h +++ b/user.h @@ -1,4 +1,5 @@ struct stat; +struct rtcdate; // system calls int fork(void);