summaryrefslogtreecommitdiff
path: root/lapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'lapic.c')
-rw-r--r--lapic.c229
1 files changed, 0 insertions, 229 deletions
diff --git a/lapic.c b/lapic.c
deleted file mode 100644
index b22bbd7..0000000
--- a/lapic.c
+++ /dev/null
@@ -1,229 +0,0 @@
-// The local APIC manages internal (non-I/O) interrupts.
-// See Chapter 8 & Appendix C of Intel processor manual volume 3.
-
-#include "param.h"
-#include "types.h"
-#include "defs.h"
-#include "date.h"
-#include "memlayout.h"
-#include "traps.h"
-#include "mmu.h"
-#include "x86.h"
-
-// Local APIC registers, divided by 4 for use as uint[] indices.
-#define ID (0x0020/4) // ID
-#define VER (0x0030/4) // Version
-#define TPR (0x0080/4) // Task Priority
-#define EOI (0x00B0/4) // EOI
-#define SVR (0x00F0/4) // Spurious Interrupt Vector
- #define ENABLE 0x00000100 // Unit Enable
-#define ESR (0x0280/4) // Error Status
-#define ICRLO (0x0300/4) // Interrupt Command
- #define INIT 0x00000500 // INIT/RESET
- #define STARTUP 0x00000600 // Startup IPI
- #define DELIVS 0x00001000 // Delivery status
- #define ASSERT 0x00004000 // Assert interrupt (vs deassert)
- #define DEASSERT 0x00000000
- #define LEVEL 0x00008000 // Level triggered
- #define BCAST 0x00080000 // Send to all APICs, including self.
- #define BUSY 0x00001000
- #define FIXED 0x00000000
-#define ICRHI (0x0310/4) // Interrupt Command [63:32]
-#define TIMER (0x0320/4) // Local Vector Table 0 (TIMER)
- #define X1 0x0000000B // divide counts by 1
- #define PERIODIC 0x00020000 // Periodic
-#define PCINT (0x0340/4) // Performance Counter LVT
-#define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0)
-#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1)
-#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR)
- #define MASKED 0x00010000 // Interrupt masked
-#define TICR (0x0380/4) // Timer Initial Count
-#define TCCR (0x0390/4) // Timer Current Count
-#define TDCR (0x03E0/4) // Timer Divide Configuration
-
-volatile uint *lapic; // Initialized in mp.c
-
-//PAGEBREAK!
-static void
-lapicw(int index, int value)
-{
- lapic[index] = value;
- lapic[ID]; // wait for write to finish, by reading
-}
-
-void
-lapicinit(void)
-{
- if(!lapic)
- return;
-
- // Enable local APIC; set spurious interrupt vector.
- lapicw(SVR, ENABLE | (T_IRQ0 + IRQ_SPURIOUS));
-
- // The timer repeatedly counts down at bus frequency
- // from lapic[TICR] and then issues an interrupt.
- // If xv6 cared more about precise timekeeping,
- // TICR would be calibrated using an external time source.
- lapicw(TDCR, X1);
- lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER));
- lapicw(TICR, 10000000);
-
- // Disable logical interrupt lines.
- lapicw(LINT0, MASKED);
- lapicw(LINT1, MASKED);
-
- // Disable performance counter overflow interrupts
- // on machines that provide that interrupt entry.
- if(((lapic[VER]>>16) & 0xFF) >= 4)
- lapicw(PCINT, MASKED);
-
- // Map error interrupt to IRQ_ERROR.
- lapicw(ERROR, T_IRQ0 + IRQ_ERROR);
-
- // Clear error status register (requires back-to-back writes).
- lapicw(ESR, 0);
- lapicw(ESR, 0);
-
- // Ack any outstanding interrupts.
- lapicw(EOI, 0);
-
- // Send an Init Level De-Assert to synchronise arbitration ID's.
- lapicw(ICRHI, 0);
- lapicw(ICRLO, BCAST | INIT | LEVEL);
- while(lapic[ICRLO] & DELIVS)
- ;
-
- // Enable interrupts on the APIC (but not on the processor).
- lapicw(TPR, 0);
-}
-
-int
-lapicid(void)
-{
- if (!lapic)
- return 0;
- return lapic[ID] >> 24;
-}
-
-// Acknowledge interrupt.
-void
-lapiceoi(void)
-{
- if(lapic)
- lapicw(EOI, 0);
-}
-
-// Spin for a given number of microseconds.
-// On real hardware would want to tune this dynamically.
-void
-microdelay(int us)
-{
-}
-
-#define CMOS_PORT 0x70
-#define CMOS_RETURN 0x71
-
-// Start additional processor running entry code at addr.
-// See Appendix B of MultiProcessor Specification.
-void
-lapicstartap(uchar apicid, uint addr)
-{
- int i;
- ushort *wrv;
-
- // "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(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;
-
- // "Universal startup algorithm."
- // Send INIT (level-triggered) interrupt to reset other CPU.
- lapicw(ICRHI, apicid<<24);
- lapicw(ICRLO, INIT | LEVEL | ASSERT);
- microdelay(200);
- lapicw(ICRLO, INIT | LEVEL);
- microdelay(100); // should be 10ms, but too slow in Bochs!
-
- // Send startup IPI (twice!) to enter code.
- // Regular hardware is supposed to only accept a STARTUP
- // when it is in the halted state due to an INIT. So the second
- // should be ignored, but it is part of the official Intel algorithm.
- // Bochs complains about the second one. Too bad for Bochs.
- for(i = 0; i < 2; i++){
- lapicw(ICRHI, apicid<<24);
- lapicw(ICRLO, STARTUP | (addr>>12));
- microdelay(200);
- }
-}
-
-#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;
-}