Xv6 with picoc & Linkage editor
v1.0
The project delineate mutual cohesion between c library, linkage editor ( linker), interpreter and operating system by porting the same on xv6 kernel
|
00001 // The local APIC manages internal (non-I/O) interrupts. 00002 // See Chapter 8 & Appendix C of Intel processor manual volume 3. 00003 00004 #include "types.h" 00005 #include "defs.h" 00006 #include "memlayout.h" 00007 #include "traps.h" 00008 #include "mmu.h" 00009 #include "x86.h" 00010 00011 // Local APIC registers, divided by 4 for use as uint[] indices. 00012 #define ID (0x0020/4) // ID 00013 #define VER (0x0030/4) // Version 00014 #define TPR (0x0080/4) // Task Priority 00015 #define EOI (0x00B0/4) // EOI 00016 #define SVR (0x00F0/4) // Spurious Interrupt Vector 00017 #define ENABLE 0x00000100 // Unit Enable 00018 #define ESR (0x0280/4) // Error Status 00019 #define ICRLO (0x0300/4) // Interrupt Command 00020 #define INIT 0x00000500 // INIT/RESET 00021 #define STARTUP 0x00000600 // Startup IPI 00022 #define DELIVS 0x00001000 // Delivery status 00023 #define ASSERT 0x00004000 // Assert interrupt (vs deassert) 00024 #define DEASSERT 0x00000000 00025 #define LEVEL 0x00008000 // Level triggered 00026 #define BCAST 0x00080000 // Send to all APICs, including self. 00027 #define BUSY 0x00001000 00028 #define FIXED 0x00000000 00029 #define ICRHI (0x0310/4) // Interrupt Command [63:32] 00030 #define TIMER (0x0320/4) // Local Vector Table 0 (TIMER) 00031 #define X1 0x0000000B // divide counts by 1 00032 #define PERIODIC 0x00020000 // Periodic 00033 #define PCINT (0x0340/4) // Performance Counter LVT 00034 #define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0) 00035 #define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1) 00036 #define ERROR (0x0370/4) // Local Vector Table 3 (ERROR) 00037 #define MASKED 0x00010000 // Interrupt masked 00038 #define TICR (0x0380/4) // Timer Initial Count 00039 #define TCCR (0x0390/4) // Timer Current Count 00040 #define TDCR (0x03E0/4) // Timer Divide Configuration 00041 00042 volatile uint *lapic; // Initialized in mp.c 00043 00044 static void 00045 lapicw(int index, int value) 00046 { 00047 lapic[index] = value; 00048 lapic[ID]; // wait for write to finish, by reading 00049 } 00050 //PAGEBREAK! 00051 00052 void 00053 lapicinit(int c) 00054 { 00055 if(!lapic) 00056 return; 00057 00058 // Enable local APIC; set spurious interrupt vector. 00059 lapicw(SVR, ENABLE | (T_IRQ0 + IRQ_SPURIOUS)); 00060 00061 // The timer repeatedly counts down at bus frequency 00062 // from lapic[TICR] and then issues an interrupt. 00063 // If xv6 cared more about precise timekeeping, 00064 // TICR would be calibrated using an external time source. 00065 lapicw(TDCR, X1); 00066 lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER)); 00067 lapicw(TICR, 10000000); 00068 00069 // Disable logical interrupt lines. 00070 lapicw(LINT0, MASKED); 00071 lapicw(LINT1, MASKED); 00072 00073 // Disable performance counter overflow interrupts 00074 // on machines that provide that interrupt entry. 00075 if(((lapic[VER]>>16) & 0xFF) >= 4) 00076 lapicw(PCINT, MASKED); 00077 00078 // Map error interrupt to IRQ_ERROR. 00079 lapicw(ERROR, T_IRQ0 + IRQ_ERROR); 00080 00081 // Clear error status register (requires back-to-back writes). 00082 lapicw(ESR, 0); 00083 lapicw(ESR, 0); 00084 00085 // Ack any outstanding interrupts. 00086 lapicw(EOI, 0); 00087 00088 // Send an Init Level De-Assert to synchronise arbitration ID's. 00089 lapicw(ICRHI, 0); 00090 lapicw(ICRLO, BCAST | INIT | LEVEL); 00091 while(lapic[ICRLO] & DELIVS) 00092 ; 00093 00094 // Enable interrupts on the APIC (but not on the processor). 00095 lapicw(TPR, 0); 00096 } 00097 00098 int 00099 cpunum(void) 00100 { 00101 // Cannot call cpu when interrupts are enabled: 00102 // result not guaranteed to last long enough to be used! 00103 // Would prefer to panic but even printing is chancy here: 00104 // almost everything, including cprintf and panic, calls cpu, 00105 // often indirectly through acquire and release. 00106 if(readeflags()&FL_IF){ 00107 static int n; 00108 if(n++ == 0) 00109 cprintf("cpu called from %x with interrupts enabled\n", 00110 __builtin_return_address(0)); 00111 } 00112 00113 if(lapic) 00114 return lapic[ID]>>24; 00115 return 0; 00116 } 00117 00118 // Acknowledge interrupt. 00119 void 00120 lapiceoi(void) 00121 { 00122 if(lapic) 00123 lapicw(EOI, 0); 00124 } 00125 00126 // Spin for a given number of microseconds. 00127 // On real hardware would want to tune this dynamically. 00128 void 00129 microdelay(int us) 00130 { 00131 } 00132 00133 #define IO_RTC 0x70 00134 00135 // Start additional processor running entry code at addr. 00136 // See Appendix B of MultiProcessor Specification. 00137 void 00138 lapicstartap(uchar apicid, uint addr) 00139 { 00140 int i; 00141 ushort *wrv; 00142 00143 // "The BSP must initialize CMOS shutdown code to 0AH 00144 // and the warm reset vector (DWORD based at 40:67) to point at 00145 // the AP startup code prior to the [universal startup algorithm]." 00146 outb(IO_RTC, 0xF); // offset 0xF is shutdown code 00147 outb(IO_RTC+1, 0x0A); 00148 wrv = (ushort*)P2V((0x40<<4 | 0x67)); // Warm reset vector 00149 wrv[0] = 0; 00150 wrv[1] = addr >> 4; 00151 00152 // "Universal startup algorithm." 00153 // Send INIT (level-triggered) interrupt to reset other CPU. 00154 lapicw(ICRHI, apicid<<24); 00155 lapicw(ICRLO, INIT | LEVEL | ASSERT); 00156 microdelay(200); 00157 lapicw(ICRLO, INIT | LEVEL); 00158 microdelay(100); // should be 10ms, but too slow in Bochs! 00159 00160 // Send startup IPI (twice!) to enter code. 00161 // Regular hardware is supposed to only accept a STARTUP 00162 // when it is in the halted state due to an INIT. So the second 00163 // should be ignored, but it is part of the official Intel algorithm. 00164 // Bochs complains about the second one. Too bad for Bochs. 00165 for(i = 0; i < 2; i++){ 00166 lapicw(ICRHI, apicid<<24); 00167 lapicw(ICRLO, STARTUP | (addr>>12)); 00168 microdelay(200); 00169 } 00170 } 00171 00172