summaryrefslogtreecommitdiff
path: root/lapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'lapic.c')
-rw-r--r--lapic.c71
1 files changed, 68 insertions, 3 deletions
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;
+}