From 7baa34a421e4c970ee90c2537ceacd7230f2474e Mon Sep 17 00:00:00 2001 From: kaashoek Date: Wed, 21 Jun 2006 01:53:07 +0000 Subject: [PATCH] start on MP; detect MP configuration --- Makefile | 2 +- defs.h | 5 ++ main.c | 3 +- memlayout.h | 3 + mp.c | 139 +++++++++++++++++++++++++++++++++++++++++++++ mp.h | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++ string.c | 15 +++++ 7 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 memlayout.h create mode 100644 mp.c create mode 100644 mp.h diff --git a/Makefile b/Makefile index 81241f4..936bc40 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o trap.o vectors.o \ - syscall.o ide.o picirq.o + syscall.o ide.o picirq.o mp.o CC = i386-jos-elf-gcc LD = i386-jos-elf-ld diff --git a/defs.h b/defs.h index 199ea87..4e1e8a5 100644 --- a/defs.h +++ b/defs.h @@ -21,6 +21,7 @@ void tinit(void); // string.c void * memcpy(void *dst, void *src, unsigned n); void * memset(void *dst, int c, unsigned n); +int memcmp(const void *v1, const void *v2, unsigned n); // syscall.c void syscall(void); @@ -28,3 +29,7 @@ void syscall(void); // picirq.c void irq_setmask_8259A(uint16_t mask); void pic_init(void); + +// mp.c +void mpinit(void); + diff --git a/main.c b/main.c index 2f3b00e..07b3862 100644 --- a/main.c +++ b/main.c @@ -22,6 +22,7 @@ main() cprintf("\nxV6\n\n"); + mpinit(); // multiprocessor kinit(); // physical memory allocator tinit(); // traps and interrupts pic_init(); @@ -47,7 +48,7 @@ main() write_eflags(read_eflags() | FL_IF); irq_setmask_8259A(0); -#if 1 +#if 0 ide_read(0, buf, 1); cprintf("sec0.0 %x\n", buf[0] & 0xff); #endif diff --git a/memlayout.h b/memlayout.h new file mode 100644 index 0000000..a33f347 --- /dev/null +++ b/memlayout.h @@ -0,0 +1,3 @@ +#define EXTPHYSMEM 0x100000 + +#define KADDR(a) ((void *) a) diff --git a/mp.c b/mp.c new file mode 100644 index 0000000..9d47e50 --- /dev/null +++ b/mp.c @@ -0,0 +1,139 @@ +#include "types.h" +#include "mp.h" +#include "defs.h" +#include "memlayout.h" + +static struct _MP_* _mp_; /* The MP floating point structure */ +static int ncpu; + +static struct _MP_* +mp_scan(uint8_t *addr, int len) +{ + uint8_t *e, *p, sum; + int i; + + cprintf("scanning: 0x%x\n", (uint32_t)addr); + e = addr+len; + for(p = addr; p < e; p += sizeof(struct _MP_)){ + if(memcmp(p, "_MP_", 4)) + continue; + sum = 0; + for(i = 0; i < sizeof(struct _MP_); i++) + sum += p[i]; + if(sum == 0) + return (struct _MP_ *)p; + } + return 0; +} + +static struct _MP_* +mp_search(void) +{ + uint8_t *bda; + uint32_t p; + struct _MP_ *mp; + + /* + * Search for the MP Floating Pointer Structure, which according to the + * spec is in one of the following three locations: + * 1) in the first KB of the EBDA; + * 2) in the last KB of system base memory; + * 3) in the BIOS ROM between 0xE0000 and 0xFFFFF. + */ + bda = KADDR(0x400); + if((p = (bda[0x0F]<<8)|bda[0x0E])){ + if((mp = mp_scan(KADDR(p), 1024))) + return mp; + } + else{ + p = ((bda[0x14]<<8)|bda[0x13])*1024; + if((mp = mp_scan(KADDR(p-1024), 1024))) + return mp; + } + return mp_scan(KADDR(0xF0000), 0x10000); +} + +static int +mp_detect(void) +{ + struct PCMP *pcmp; + uint8_t *p, sum; + uint32_t length; + + /* + * Search for an MP configuration table. For now, + * don't accept the default configurations (physaddr == 0). + * Check for correct signature, calculate the checksum and, + * if correct, check the version. + * To do: check extended table checksum. + */ + if((_mp_ = mp_search()) == 0 || _mp_->physaddr == 0) + return 1; + + pcmp = KADDR(_mp_->physaddr); + if(memcmp(pcmp, "PCMP", 4)) + return 2; + + length = pcmp->length; + sum = 0; + for(p = (uint8_t*)pcmp; length; length--) + sum += *p++; + + if(sum || (pcmp->version != 1 && pcmp->version != 4)) + return 3; + + cprintf("MP spec rev #: %x\n", _mp_->specrev); + return 0; +} + +void +mpinit() +{ + int r; + uint8_t *p, *e; + struct PCMP *pcmp; + + ncpu = 0; + if ((r = mp_detect()) != 0) return; + cprintf ("This computer is multiprocessor!\n"); + + /* + * Run through the table saving information needed for starting + * application processors and initialising any I/O APICs. The table + * is guaranteed to be in order such that only one pass is necessary. + */ + pcmp = KADDR(_mp_->physaddr); + p = ((uint8_t*)pcmp)+sizeof(struct PCMP); + e = ((uint8_t*)pcmp)+pcmp->length; + + while(p < e) { + switch(*p){ + case PcmpPROCESSOR: + cprintf("a processor\n"); + ncpu++; + p += sizeof(struct PCMPprocessor); + continue; + case PcmpBUS: + cprintf("a bus\n"); + p += sizeof(struct PCMPbus); + continue; + case PcmpIOAPIC: + cprintf("an IO APIC\n"); + p += sizeof(struct PCMPioapic); + continue; + case PcmpIOINTR: + cprintf("an IO interrupt assignment\n"); + p += sizeof(struct PCMPintr); + continue; + default: + cprintf("mpinit: unknown PCMP type 0x%x (e-p 0x%x)\n", *p, e-p); + while(p < e){ + cprintf("%uX ", *p); + p++; + } + break; + } + } + + cprintf("ncpu: %d\n", ncpu); +} diff --git a/mp.h b/mp.h new file mode 100644 index 0000000..df46574 --- /dev/null +++ b/mp.h @@ -0,0 +1,158 @@ +/* + * MultiProcessor Specification Version 1.[14]. + */ +struct _MP_ { /* floating pointer */ + uint8_t signature[4]; /* "_MP_" */ + physaddr_t physaddr; /* physical address of MP configuration table */ + uint8_t length; /* 1 */ + uint8_t specrev; /* [14] */ + uint8_t checksum; /* all bytes must add up to 0 */ + uint8_t type; /* MP system configuration type */ + uint8_t imcrp; + uint8_t reserved[3]; +}; + +struct PCMP { /* configuration table header */ + uint8_t signature[4]; /* "PCMP" */ + uint16_t length; /* total table length */ + uint8_t version; /* [14] */ + uint8_t checksum; /* all bytes must add up to 0 */ + uint8_t product[20]; /* product id */ + uintptr_t oemtable; /* OEM table pointer */ + uint16_t oemlength; /* OEM table length */ + uint16_t entry; /* entry count */ + uintptr_t lapicbase; /* address of local APIC */ + uint16_t xlength; /* extended table length */ + uint8_t xchecksum; /* extended table checksum */ + uint8_t reserved; +}; + +struct PCMPprocessor { /* processor table entry */ + uint8_t type; /* entry type (0) */ + uint8_t apicno; /* local APIC id */ + uint8_t version; /* local APIC verison */ + uint8_t flags; /* CPU flags */ + uint8_t signature[4]; /* CPU signature */ + uint32_t feature; /* feature flags from CPUID instruction */ + uint8_t reserved[8]; +}; + +struct PCMPbus { /* bus table entry */ + uint8_t type; /* entry type (1) */ + uint8_t busno; /* bus id */ + char string[6]; /* bus type string */ +}; + +struct PCMPioapic { /* I/O APIC table entry */ + uint8_t type; /* entry type (2) */ + uint8_t apicno; /* I/O APIC id */ + uint8_t version; /* I/O APIC version */ + uint8_t flags; /* I/O APIC flags */ + uintptr_t addr; /* I/O APIC address */ +}; + +struct PCMPintr { /* interrupt table entry */ + uint8_t type; /* entry type ([34]) */ + uint8_t intr; /* interrupt type */ + uint16_t flags; /* interrupt flag */ + uint8_t busno; /* source bus id */ + uint8_t irq; /* source bus irq */ + uint8_t apicno; /* destination APIC id */ + uint8_t intin; /* destination APIC [L]INTIN# */ +}; + +struct PCMPsasm { /* system address space mapping entry */ + uint8_t type; /* entry type (128) */ + uint8_t length; /* of this entry (20) */ + uint8_t busno; /* bus id */ + uint8_t addrtype; + uintptr_t addrbase[2]; + uint32_t addrlength[2]; +}; + +struct PCMPhierarchy { /* bus hierarchy descriptor entry */ + uint8_t type; /* entry type (129) */ + uint8_t length; /* of this entry (8) */ + uint8_t busno; /* bus id */ + uint8_t info; /* bus info */ + uint8_t parent; /* parent bus */ + uint8_t reserved[3]; +}; + +struct PCMPcbasm { /* compatibility bus address space modifier entry */ + uint8_t type; /* entry type (130) */ + uint8_t length; /* of this entry (8) */ + uint8_t busno; /* bus id */ + uint8_t modifier; /* address modifier */ + uint32_t range; /* predefined range list */ +}; + +enum { /* table entry types */ + PcmpPROCESSOR = 0x00, /* one entry per processor */ + PcmpBUS = 0x01, /* one entry per bus */ + PcmpIOAPIC = 0x02, /* one entry per I/O APIC */ + PcmpIOINTR = 0x03, /* one entry per bus interrupt source */ + PcmpLINTR = 0x04, /* one entry per system interrupt source */ + + PcmpSASM = 0x80, + PcmpHIERARCHY = 0x81, + PcmpCBASM = 0x82, + + /* PCMPprocessor and PCMPioapic flags */ + PcmpEN = 0x01, /* enabled */ + PcmpBP = 0x02, /* bootstrap processor */ + + /* PCMPiointr and PCMPlintr flags */ + PcmpPOMASK = 0x03, /* polarity conforms to specifications of bus */ + PcmpHIGH = 0x01, /* active high */ + PcmpLOW = 0x03, /* active low */ + PcmpELMASK = 0x0C, /* trigger mode of APIC input signals */ + PcmpEDGE = 0x04, /* edge-triggered */ + PcmpLEVEL = 0x0C, /* level-triggered */ + + /* PCMPiointr and PCMPlintr interrupt type */ + PcmpINT = 0x00, /* vectored interrupt from APIC Rdt */ + PcmpNMI = 0x01, /* non-maskable interrupt */ + PcmpSMI = 0x02, /* system management interrupt */ + PcmpExtINT = 0x03, /* vectored interrupt from external PIC */ + + /* PCMPsasm addrtype */ + PcmpIOADDR = 0x00, /* I/O address */ + PcmpMADDR = 0x01, /* memory address */ + PcmpPADDR = 0x02, /* prefetch address */ + + /* PCMPhierarchy info */ + PcmpSD = 0x01, /* subtractive decode bus */ + + /* PCMPcbasm modifier */ + PcmpPR = 0x01, /* predefined range list */ +}; + +/* + * Common bits for + * I/O APIC Redirection Table Entry; + * Local APIC Local Interrupt Vector Table; + * Local APIC Inter-Processor Interrupt; + * Local APIC Timer Vector Table. + */ +enum { + ApicFIXED = 0x00000000, /* [10:8] Delivery Mode */ + ApicLOWEST = 0x00000100, /* Lowest priority */ + ApicSMI = 0x00000200, /* System Management Interrupt */ + ApicRR = 0x00000300, /* Remote Read */ + ApicNMI = 0x00000400, + ApicINIT = 0x00000500, /* INIT/RESET */ + ApicSTARTUP = 0x00000600, /* Startup IPI */ + ApicExtINT = 0x00000700, + + ApicPHYSICAL = 0x00000000, /* [11] Destination Mode (RW) */ + ApicLOGICAL = 0x00000800, + + ApicDELIVS = 0x00001000, /* [12] Delivery Status (RO) */ + ApicHIGH = 0x00000000, /* [13] Interrupt Input Pin Polarity (RW) */ + ApicLOW = 0x00002000, + ApicRemoteIRR = 0x00004000, /* [14] Remote IRR (RO) */ + ApicEDGE = 0x00000000, /* [15] Trigger Mode (RW) */ + ApicLEVEL = 0x00008000, + ApicIMASK = 0x00010000, /* [16] Interrupt Mask */ +}; diff --git a/string.c b/string.c index f27b025..40019d5 100644 --- a/string.c +++ b/string.c @@ -23,3 +23,18 @@ memset(void *dst, int c, unsigned n) return dst; } + +int +memcmp(const void *v1, const void *v2, unsigned n) +{ + const uint8_t *s1 = (const uint8_t *) v1; + const uint8_t *s2 = (const uint8_t *) v2; + + while (n-- > 0) { + if (*s1 != *s2) + return (int) *s1 - (int) *s2; + s1++, s2++; + } + + return 0; +}