diff options
| author | kaashoek <kaashoek> | 2006-06-22 01:28:57 +0000 | 
|---|---|---|
| committer | kaashoek <kaashoek> | 2006-06-22 01:28:57 +0000 | 
| commit | 21a88fd487177841c882d9017bd9f4476801c6f6 (patch) | |
| tree | bfa061e00662efde2186d6c0498fc78f889356ce | |
| parent | 7baa34a421e4c970ee90c2537ceacd7230f2474e (diff) | |
| download | xv6-labs-21a88fd487177841c882d9017bd9f4476801c6f6.tar.gz xv6-labs-21a88fd487177841c882d9017bd9f4476801c6f6.tar.bz2 xv6-labs-21a88fd487177841c882d9017bd9f4476801c6f6.zip  | |
checkpoint. booting second processor.  stack is messed up, but thanks to cliff
and plan 9 code, at least boots and gets into C code.
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | bootasm.S | 15 | ||||
| -rw-r--r-- | bootother.S | 77 | ||||
| -rw-r--r-- | defs.h | 11 | ||||
| -rw-r--r-- | main.c | 11 | ||||
| -rw-r--r-- | mp.c | 284 | ||||
| -rw-r--r-- | mp.h | 150 | ||||
| -rw-r--r-- | param.h | 1 | ||||
| -rw-r--r-- | picirq.c | 9 | ||||
| -rw-r--r-- | spinlock.c | 39 | ||||
| -rw-r--r-- | string.c | 20 | ||||
| -rw-r--r-- | trapasm.S | 5 | ||||
| -rw-r--r-- | x86.h | 24 | 
13 files changed, 505 insertions, 151 deletions
@@ -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 mp.o +       syscall.o ide.o picirq.o mp.o spinlock.o  CC = i386-jos-elf-gcc  LD = i386-jos-elf-ld @@ -20,8 +20,12 @@ bootblock : bootasm.S bootmain.c  	$(OBJCOPY) -S -O binary bootblock.o bootblock  	./sign.pl bootblock -kernel : $(OBJS) -	$(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) +kernel : $(OBJS) bootother.S +	$(CC) -nostdinc -I. -c bootother.S +	$(LD) -N -e start -Ttext 0x7000 -o bootother.out bootother.o +	$(OBJCOPY) -S -O binary bootother.out bootother +	$(OBJDUMP) -S bootother.o > bootother.asm +	$(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) -b binary bootother  	$(OBJDUMP) -S kernel > kernel.asm  vectors.S : vectors.pl @@ -1,17 +1,4 @@ -#define SEG_NULL						\ -	.word 0, 0;						\ -	.byte 0, 0, 0, 0 -#define SEG(type,base,lim)					\ -	.word (((lim) >> 12) & 0xffff), ((base) & 0xffff);	\ -	.byte (((base) >> 16) & 0xff), (0x90 | (type)),		\ -		(0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) - -#define STA_X		0x8	    // Executable segment -#define STA_E		0x4	    // Expand down (non-executable segments) -#define STA_C		0x4	    // Conforming code segment (executable only) -#define STA_W		0x2	    // Writeable (non-executable segments) -#define STA_R		0x2	    // Readable (executable segments) -#define STA_A		0x1	    // Accessed +#include "asm.h"  .set PROT_MODE_CSEG,0x8		# code segment selector  .set PROT_MODE_DSEG,0x10        # data segment selector diff --git a/bootother.S b/bootother.S new file mode 100644 index 0000000..cba4a5f --- /dev/null +++ b/bootother.S @@ -0,0 +1,77 @@ +#include "asm.h" +	 +/* + * Start an Application Processor. This must be placed on a 4KB boundary + * somewhere in the 1st MB of conventional memory (APBOOTSTRAP). However, + * due to some shortcuts below it's restricted further to within the 1st + * 64KB. The AP starts in real-mode, with + *   CS selector set to the startup memory address/16; + *   CS base set to startup memory address; + *   CS limit set to 64KB; + *   CPL and IP set to 0. + *	 + * Credit: Cliff Frey + */ + +.set PROT_MODE_CSEG,0x8		# code segment selector +.set PROT_MODE_DSEG,0x10        # data segment selector +.set CR0_PE_ON,0x1		# protected mode enable flag + +.globl start +start:		.code16				# This runs in real mode +		cli				# Disable interrupts +		cld				# String operations increment + +		# Set up the important data segment registers (DS, ES, SS). +		xorw	%ax,%ax			# Segment number zero +		movw	%ax,%ds			# -> Data Segment +		movw	%ax,%es			# -> Extra Segment +		movw	%ax,%ss			# -> Stack Segment + +		# Set up the stack pointer, growing downward from 0x7000. +		movw	$start,%sp         	# Stack Pointer +	 +#### Switch from real to protected mode	 +####     The descriptors in our GDT allow all physical memory to be accessed. +####     Furthermore, the descriptors have base addresses of 0, so that the +####     segment translation is a NOP, ie. virtual addresses are identical to +####     their physical addresses.  With this setup, immediately after +####	 enabling protected mode it will still appear to this code +####	 that it is running directly on physical memory with no translation. +####	 This initial NOP-translation setup is required by the processor +####	 to ensure that the transition to protected mode occurs smoothly. +	 +		lgdt	gdtdesc			# load GDT -- mandatory in protected mode +		movl	%cr0, %eax		# turn on protected mode +		orl	$CR0_PE_ON, %eax	#  +		movl	%eax, %cr0		#  +	        ### CPU magic: jump to relocation, flush prefetch queue, and reload %cs +		### Has the effect of just jmp to the next instruction, but simultaneous +		### loads CS with $PROT_MODE_CSEG. +		ljmp	$PROT_MODE_CSEG, $protcseg +	 +#### we are in 32-bit protected mode (hence the .code32) +.code32 +protcseg:	 +		# Set up the protected-mode data segment registers +		movw	$PROT_MODE_DSEG, %ax	# Our data segment selector +		movw	%ax, %ds		# -> DS: Data Segment +		movw	%ax, %es		# -> ES: Extra Segment +		movw	%ax, %fs		# -> FS +		movw	%ax, %gs		# -> GS +		movw	%ax, %ss		# -> SS: Stack Segment + +	# XXX hack +		movl	0x10018, %eax		# elfhdr->entry (left over in scratch space) +		# subl	$KERNBASE, %eax +		jmp	*%eax                   # this jumps to _start in kern/entry.S +	 +.p2align 2					# force 4 byte alignment +gdt: +	SEG_NULL				# null seg +	SEG(STA_X|STA_R, 0x0, 0xffffffff)	# code seg +	SEG(STA_W, 0x0, 0xffffffff)	        # data seg +	 +gdtdesc: +	.word	0x17			# sizeof(gdt) - 1 +	.long	gdt			# address gdt @@ -22,6 +22,7 @@ void tinit(void);  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); +void *memmove(void *dst, const void *src, unsigned n);  // syscall.c  void syscall(void); @@ -31,5 +32,13 @@ void irq_setmask_8259A(uint16_t mask);  void pic_init(void);  // mp.c -void mpinit(void); +void mp_init(void); +int lapic_cpu_number(void); +int mp_isbcpu(void); + +// spinlock.c +extern uint32_t kernel_lock; +void acquire_spinlock(uint32_t* lock); +void release_spinlock(uint32_t* lock); +void release_grant_spinlock(uint32_t* lock, int cpu); @@ -8,6 +8,7 @@  #include "syscall.h"  extern char edata[], end[]; +extern int acpu;  char buf[512]; @@ -16,13 +17,19 @@ main()  {    struct proc *p;    int i; -   + +  if (acpu) { +    cprintf("an application processor\n"); +    release_spinlock(&kernel_lock); +    while (1) ; +  } +  acpu = 1;    // clear BSS    memset(edata, 0, end - edata);    cprintf("\nxV6\n\n"); -  mpinit(); // multiprocessor +  mp_init(); // multiprocessor    kinit(); // physical memory allocator    tinit(); // traps and interrupts    pic_init(); @@ -2,11 +2,201 @@  #include "mp.h"  #include "defs.h"  #include "memlayout.h" +#include "param.h" +#include "x86.h" +#include "mmu.h" -static struct _MP_* _mp_;  /* The MP floating point structure */ +/*  + * Credit: Plan 9 sources, Intel MP spec, and Cliff Frey + */ + +enum {					/* Local APIC registers */ +  LAPIC_ID  = 0x0020,	/* ID */ +  LAPIC_VER = 0x0030,	/* Version */ +  LAPIC_TPR = 0x0080,	/* Task Priority */ +  LAPIC_APR = 0x0090,	/* Arbitration Priority */ +  LAPIC_PPR = 0x00A0,	/* Processor Priority */ +  LAPIC_EOI = 0x00B0,	/* EOI */ +  LAPIC_LDR = 0x00D0,	/* Logical Destination */ +  LAPIC_DFR = 0x00E0,	/* Destination Format */ +  LAPIC_SVR = 0x00F0,	/* Spurious Interrupt Vector */ +  LAPIC_ISR = 0x0100,	/* Interrupt Status (8 registers) */ +  LAPIC_TMR = 0x0180,	/* Trigger Mode (8 registers) */ +  LAPIC_IRR = 0x0200,	/* Interrupt Request (8 registers) */ +  LAPIC_ESR = 0x0280,	/* Error Status */ +  LAPIC_ICRLO = 0x0300,	/* Interrupt Command */ +  LAPIC_ICRHI = 0x0310,	/* Interrupt Command [63:32] */ +  LAPIC_TIMER = 0x0320,	/* Local Vector Table 0 (TIMER) */ +  LAPIC_PCINT = 0x0340,	/* Performance Counter LVT */ +  LAPIC_LINT0 = 0x0350,	/* Local Vector Table 1 (LINT0) */ +  LAPIC_LINT1 = 0x0360,	/* Local Vector Table 2 (LINT1) */ +  LAPIC_ERROR = 0x0370,	/* Local Vector Table 3 (ERROR) */ +  LAPIC_TICR = 0x0380,	/* Timer Initial Count */ +  LAPIC_TCCR = 0x0390,	/* Timer Current Count */ +  LAPIC_TDCR = 0x03E0,	/* Timer Divide Configuration */ +}; + +enum {					/* LAPIC_SVR */ +  LAPIC_ENABLE	= 0x00000100,	/* Unit Enable */ +  LAPIC_FOCUS	= 0x00000200,	/* Focus Processor Checking Disable */ +}; + +enum {					/* LAPIC_ICRLO */ +					/* [14] IPI Trigger Mode Level (RW) */ +  LAPIC_DEASSERT = 0x00000000,	/* Deassert level-sensitive interrupt */ +  LAPIC_ASSERT	= 0x00004000,	/* Assert level-sensitive interrupt */ + +  /* [17:16] Remote Read Status */ +  LAPIC_INVALID	= 0x00000000,	/* Invalid */ +  LAPIC_WAIT	= 0x00010000,	/* In-Progress */ +  LAPIC_VALID	= 0x00020000,	/* Valid */ + +  /* [19:18] Destination Shorthand */ +  LAPIC_FIELD	= 0x00000000,	/* No shorthand */ +  LAPIC_SELF	= 0x00040000,	/* Self is single destination */ +  LAPIC_ALLINC	= 0x00080000,	/* All including self */ +  LAPIC_ALLEXC	= 0x000C0000,	/* All Excluding self */ +}; + +enum {					/* LAPIC_ESR */ +  LAPIC_SENDCS	= 0x00000001,	/* Send CS Error */ +  LAPIC_RCVCS	= 0x00000002,	/* Receive CS Error */ +  LAPIC_SENDACCEPT = 0x00000004,	/* Send Accept Error */ +  LAPIC_RCVACCEPT = 0x00000008,	/* Receive Accept Error */ +  LAPIC_SENDVECTOR = 0x00000020,	/* Send Illegal Vector */ +  LAPIC_RCVVECTOR = 0x00000040,	/* Receive Illegal Vector */ +  LAPIC_REGISTER = 0x00000080,	/* Illegal Register Address */ +}; + +enum {					/* LAPIC_TIMER */ +					/* [17] Timer Mode (RW) */ +  LAPIC_ONESHOT	= 0x00000000,	/* One-shot */ +  LAPIC_PERIODIC = 0x00020000,	/* Periodic */ + +  /* [19:18] Timer Base (RW) */ +  LAPIC_CLKIN	= 0x00000000,	/* use CLKIN as input */ +  LAPIC_TMBASE	= 0x00040000,	/* use TMBASE */ +  LAPIC_DIVIDER	= 0x00080000,	/* use output of the divider */ +}; + +enum {					/* LAPIC_TDCR */ +  LAPIC_X2 = 0x00000000,	/* divide by 2 */ +  LAPIC_X4 = 0x00000001,	/* divide by 4 */ +  LAPIC_X8 = 0x00000002,	/* divide by 8 */ +  LAPIC_X16 = 0x00000003,	/* divide by 16 */ +  LAPIC_X32 = 0x00000008,	/* divide by 32 */ +  LAPIC_X64 = 0x00000009,	/* divide by 64 */ +  LAPIC_X128 = 0x0000000A,	/* divide by 128 */ +  LAPIC_X1 = 0x0000000B,	/* divide by 1 */ +}; + +#define APBOOTCODE 0x7000 // XXX hack + +static struct MP* mp;  /* The MP floating point structure */ +static uint32_t *lapicaddr; +static struct cpu { +  uint8_t apicid;       /* Local APIC ID */ +  int lintr[2];		/* Local APIC */ +} cpu[NCPU];  static int ncpu; +static struct cpu *bcpu; + +static int +lapic_read(int r) +{ +  return *(lapicaddr+(r/sizeof(*lapicaddr))); +} + +static void +lapic_write(int r, int data) +{ +  *(lapicaddr+(r/sizeof(*lapicaddr))) = data; +} + +static void +lapic_init(int c) +{ +  uint32_t r, lvt; + +  cprintf("lapic_init %d\n", c); +  lapic_write(LAPIC_DFR, 0xFFFFFFFF); +  r = (lapic_read(LAPIC_ID)>>24) & 0xFF; +  lapic_write(LAPIC_LDR, (1<<r)<<24); +  lapic_write(LAPIC_TPR, 0xFF); +  lapic_write(LAPIC_SVR, LAPIC_ENABLE|(IRQ_OFFSET+IRQ_SPURIOUS)); + +  /* +   * Set the local interrupts. It's likely these should just be +   * masked off for SMP mode as some Pentium Pros have problems if +   * LINT[01] are set to ExtINT. +   * Acknowledge any outstanding interrupts. +   */ +  lapic_write(LAPIC_LINT0, cpu[c].lintr[0]); +  lapic_write(LAPIC_LINT1, cpu[c].lintr[1]); +  lapic_write(LAPIC_EOI, 0); + +  lvt = (lapic_read(LAPIC_VER)>>16) & 0xFF; +  if(lvt >= 4) +    lapic_write(LAPIC_PCINT, APIC_IMASK); +  lapic_write(LAPIC_ERROR, IRQ_OFFSET+IRQ_ERROR); +  lapic_write(LAPIC_ESR, 0); +  lapic_read(LAPIC_ESR); + +  /* +   * Issue an INIT Level De-Assert to synchronise arbitration ID's. +   */ +  lapic_write(LAPIC_ICRHI, 0); +  lapic_write(LAPIC_ICRLO, LAPIC_ALLINC|APIC_LEVEL|LAPIC_DEASSERT|APIC_INIT); +  while(lapic_read(LAPIC_ICRLO) & APIC_DELIVS) +    ; -static struct _MP_* +  /* +   * Do not allow acceptance of interrupts until all initialisation +   * for this processor is done. For the bootstrap processor this can be +   * early duing initialisation. For the application processors this should +   * be after the bootstrap processor has lowered priority and is accepting +   * interrupts. +   */ +  lapic_write(LAPIC_TPR, 0); +  cprintf("Done init of an apic\n"); +} + +static void +lapic_online(void)  +{ +  lapic_write(LAPIC_TPR, 0); +} + +int +lapic_cpu_number(void) +{ +  return (lapic_read(LAPIC_ID)>>24) & 0xFF; +} + +static void +lapic_startap(struct cpu *c, int v) +{ +  int crhi, i; +  volatile int j = 0; + +  crhi = c->apicid<<24; +  lapic_write(LAPIC_ICRHI, crhi); +  lapic_write(LAPIC_ICRLO, LAPIC_FIELD|APIC_LEVEL|LAPIC_ASSERT|APIC_INIT); + +  while (j++ < 10000) {;} +  lapic_write(LAPIC_ICRLO, LAPIC_FIELD|APIC_LEVEL|LAPIC_DEASSERT|APIC_INIT); + +  while (j++ < 1000000) {;} + +  // in p9 code, this was i < 2, which is what the spec says on page B-3 +  for(i = 0; i < 1; i++){ +    lapic_write(LAPIC_ICRHI, crhi); +    lapic_write(LAPIC_ICRLO, LAPIC_FIELD|APIC_EDGE|APIC_STARTUP|(v/PGSIZE)); +    while (j++ < 100000) {;} +  } +} + +static struct MP*  mp_scan(uint8_t *addr, int len)  {    uint8_t *e, *p, sum; @@ -14,24 +204,24 @@ mp_scan(uint8_t *addr, int len)    cprintf("scanning: 0x%x\n", (uint32_t)addr);    e = addr+len; -  for(p = addr; p < e; p += sizeof(struct _MP_)){ +  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++) +    for(i = 0; i < sizeof(struct MP); i++)        sum += p[i];      if(sum == 0) -      return (struct _MP_ *)p; +      return (struct MP *)p;    }    return 0;  } -static struct _MP_* +static struct MP*  mp_search(void)  {    uint8_t *bda;    uint32_t p; -  struct _MP_ *mp; +  struct MP *mp;    /*     * Search for the MP Floating Pointer Structure, which according to the @@ -56,7 +246,7 @@ mp_search(void)  static int   mp_detect(void)  { -  struct PCMP *pcmp; +  struct MPCTB *pcmp;    uint8_t *p, sum;    uint32_t length; @@ -67,10 +257,10 @@ mp_detect(void)     * if correct, check the version.     * To do: check extended table checksum.     */ -  if((_mp_ = mp_search()) == 0 || _mp_->physaddr == 0) +  if((mp = mp_search()) == 0 || mp->physaddr == 0)      return 1; -  pcmp = KADDR(_mp_->physaddr); +  pcmp = KADDR(mp->physaddr);    if(memcmp(pcmp, "PCMP", 4))      return 2; @@ -82,48 +272,65 @@ mp_detect(void)    if(sum || (pcmp->version != 1 && pcmp->version != 4))      return 3; -  cprintf("MP spec rev #: %x\n", _mp_->specrev); +  cprintf("MP spec rev #: %x\n", mp->specrev);    return 0;  } +int +mp_isbcpu() +{ +  if (bcpu == 0) return 1; +  else return 0; +} +  void -mpinit() +mp_init()  {     int r;    uint8_t *p, *e; -  struct PCMP *pcmp; +  struct MPCTB *mpctb; +  struct MPPE *proc; +  struct cpu *c;    ncpu = 0;    if ((r = mp_detect()) != 0) return; -  cprintf ("This computer is multiprocessor!\n"); + +  cprintf ("This computer is a 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; +  mpctb = KADDR(mp->physaddr); +  lapicaddr = KADDR(mpctb->lapicaddr); +  cprintf("apicaddr: %x\n", lapicaddr); +  p = ((uint8_t*)mpctb)+sizeof(struct MPCTB); +  e = ((uint8_t*)mpctb)+mpctb->length;    while(p < e) {      switch(*p){ -    case PcmpPROCESSOR: -      cprintf("a processor\n"); +    case MPPROCESSOR: +      proc = (struct MPPE *) p; +      cpu[ncpu].apicid = proc->apicid; +      cpu[ncpu].lintr[0] = APIC_IMASK; +      cpu[ncpu].lintr[1] = APIC_IMASK; +      cprintf("a processor %x\n", cpu[ncpu].apicid); +      if (proc->flags & MPBP) { +	bcpu = &cpu[ncpu]; +      }        ncpu++; -      p += sizeof(struct PCMPprocessor); +      p += sizeof(struct MPPE);        continue; -    case PcmpBUS: -      cprintf("a bus\n"); -      p += sizeof(struct PCMPbus); +    case MPBUS: +      p += sizeof(struct MPBE);        continue; -    case PcmpIOAPIC: -      cprintf("an IO APIC\n"); -      p += sizeof(struct PCMPioapic); +    case MPIOAPIC: +      cprintf("an I/O APIC\n"); +      p += sizeof(struct MPIOAPIC);        continue; -    case PcmpIOINTR: -      cprintf("an IO interrupt assignment\n"); -      p += sizeof(struct PCMPintr); +    case MPIOINTR: +      p += sizeof(struct MPIE);        continue;      default:        cprintf("mpinit: unknown PCMP type 0x%x (e-p 0x%x)\n", *p, e-p); @@ -134,6 +341,23 @@ mpinit()        break;      }    } +   +  lapic_init(cpu-bcpu); +  cprintf("ncpu: %d boot %d\n", ncpu, cpu-bcpu); -  cprintf("ncpu: %d\n", ncpu); +  lapic_online(); + +  extern uint8_t _binary_bootother_start[], _binary_bootother_size[]; +  memmove(KADDR(APBOOTCODE),_binary_bootother_start,  +	  (uint32_t) _binary_bootother_size); + +  acquire_spinlock(&kernel_lock); +  for (c = cpu; c < &cpu[ncpu]; c++) { +    if (c == bcpu) continue; +    cprintf ("starting processor %d\n", c - cpu); +    release_grant_spinlock(&kernel_lock, c - cpu); +    lapic_startap(c, (uint32_t) KADDR(APBOOTCODE)); +    acquire_spinlock(&kernel_lock); +    cprintf ("done starting processor %d\n", c - cpu); +  }  } @@ -1,7 +1,10 @@  /*   * MultiProcessor Specification Version 1.[14]. + * + * Credit: Plan 9 sources   */ -struct _MP_ {			/* floating pointer */ + +struct MP {			/* floating pointer */    uint8_t signature[4];		/* "_MP_" */    physaddr_t physaddr;	        /* physical address of MP configuration table */    uint8_t length;		/* 1 */ @@ -12,7 +15,7 @@ struct _MP_ {			/* floating pointer */    uint8_t reserved[3];  }; -struct PCMP {			/* configuration table header */ +struct MPCTB {			/* configuration table header */    uint8_t signature[4];		/* "PCMP" */    uint16_t length;		/* total table length */    uint8_t version;		/* [14] */ @@ -21,15 +24,15 @@ struct PCMP {			/* configuration table header */    uintptr_t oemtable;		/* OEM table pointer */    uint16_t oemlength;		/* OEM table length */    uint16_t entry;		/* entry count */ -  uintptr_t lapicbase;		/* address of local APIC */ +  uintptr_t lapicaddr;		/* address of local APIC */    uint16_t xlength;		/* extended table length */    uint8_t xchecksum;		/* extended table checksum */    uint8_t reserved;  }; -struct PCMPprocessor {		/* processor table entry */ +struct MPPE {		/* processor table entry */    uint8_t type;			/* entry type (0) */ -  uint8_t apicno;		/* local APIC id */ +  uint8_t apicid;		/* local APIC id */    uint8_t version;		/* local APIC verison */    uint8_t flags;		/* CPU flags */    uint8_t signature[4];		/* CPU signature */ @@ -37,13 +40,13 @@ struct PCMPprocessor {		/* processor table entry */    uint8_t reserved[8];  }; -struct PCMPbus {		/* bus table entry */ +struct MPBE {		/* 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 */ +struct MPIOAPIC {	/* 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 */ @@ -51,7 +54,7 @@ struct PCMPioapic {		/* I/O APIC table entry */    uintptr_t addr;		/* I/O APIC address */  }; -struct PCMPintr {		/* interrupt table entry */ +struct MPIE {		/* interrupt table entry */    uint8_t type;			/* entry type ([34]) */    uint8_t intr;			/* interrupt type */    uint16_t flags;		/* interrupt flag */ @@ -61,71 +64,34 @@ struct PCMPintr {		/* interrupt table entry */    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 */ +enum {			/* table entry types */ +  MPPROCESSOR	= 0x00,		/* one entry per processor */ +  MPBUS = 0x01,		        /* one entry per bus */ +  MPIOAPIC = 0x02,		/* one entry per I/O APIC */ +  MPIOINTR = 0x03,		/* one entry per bus interrupt source */ +  MPLINTR = 0x04,		/* one entry per system interrupt source */ + +  MPSASM = 0x80, +  MPHIERARCHY	= 0x81, +  MPCBASM = 0x82, + +                        /* PCMPprocessor and PCMPioapic flags */ +  MPEN = 0x01,		        /* enabled */ +  MPBP = 0x02,		        /* bootstrap processor */ + +			/* PCMPiointr and PCMPlintr flags */ +  MPPOMASK = 0x03,		/* polarity conforms to specifications of bus */ +  MPHIGH = 0x01,		/* active high */ +  MPLOW = 0x03,		/* active low */ +  MPELMASK = 0x0C,		/* trigger mode of APIC input signals */ +  MPEDGE = 0x04,		/* edge-triggered */ +  MPLEVEL = 0x0C,		/* level-triggered */ + +                        /* PCMPiointr and PCMPlintr interrupt type */ +  MPINT = 0x00,		        /* vectored interrupt from APIC Rdt */ +  MPNMI = 0x01,		        /* non-maskable interrupt */ +  MPSMI = 0x02,		        /* system management interrupt */ +  MPExtINT = 0x03,		/* vectored interrupt from external PIC */  };  /* @@ -136,23 +102,23 @@ enum {				/* table entry types */   *	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 */ +  APIC_FIXED = 0x00000000,	/* [10:8] Delivery Mode */ +  APIC_LOWEST = 0x00000100,	/* Lowest priority */ +  APIC_SMI = 0x00000200,	        /* System Management Interrupt */ +  APIC_RR = 0x00000300,	        /* Remote Read */ +  APIC_NMI = 0x00000400, +  APIC_INIT = 0x00000500,	/* INIT/RESET */ +  APIC_STARTUP = 0x00000600,	/* Startup IPI */ +  APIC_ExtINT = 0x00000700, + +  APIC_PHYSICAL = 0x00000000,	/* [11] Destination Mode (RW) */ +  APIC_LOGICAL = 0x00000800, + +  APIC_DELIVS = 0x00001000,	/* [12] Delivery Status (RO) */ +  APIC_HIGH = 0x00000000,	/* [13] Interrupt Input Pin Polarity (RW) */ +  APIC_LOW = 0x00002000, +  APIC_RemoteIRR	= 0x00004000,	/* [14] Remote IRR (RO) */ +  APIC_EDGE = 0x00000000,	/* [15] Trigger Mode (RW) */ +  APIC_LEVEL = 0x00008000, +  APIC_IMASK = 0x00010000,	/* [16] Interrupt Mask */  }; @@ -1,3 +1,4 @@  #define NPROC 64  #define PAGE 4096  #define KSTACKSIZE PAGE +#define NCPU 8 @@ -4,15 +4,6 @@  #include "x86.h"  #include "defs.h" -#define MAX_IRQS	16	// Number of IRQs - -// I/O Addresses of the two 8259A programmable interrupt controllers -#define IO_PIC1		0x20	// Master (IRQs 0-7) -#define IO_PIC2		0xA0	// Slave (IRQs 8-15) - -#define IRQ_SLAVE	2	// IRQ at which slave connects to master -#define IRQ_OFFSET	32	// IRQ 0 corresponds to int IRQ_OFFSET -  // Current IRQ mask.  // Initial IRQ mask has interrupt 2 enabled (for slave 8259A).  uint16_t irq_mask_8259A = 0xFFFF & ~(1<<IRQ_SLAVE); diff --git a/spinlock.c b/spinlock.c new file mode 100644 index 0000000..fa04a27 --- /dev/null +++ b/spinlock.c @@ -0,0 +1,39 @@ +#include "types.h" +#include "defs.h" +#include "x86.h" + +#define LOCK_FREE -1 + +uint32_t kernel_lock = LOCK_FREE; + +// lock = LOCK_FREE if free, else = cpu_id of owner CPU +void  +acquire_spinlock(uint32_t* lock) +{ +  int cpu_id = lapic_cpu_number(); +  cprintf ("acquire: %d\n", cpu_id); + +  if (*lock == cpu_id) +    return; +  while ( cmpxchg(LOCK_FREE, cpu_id, lock) != cpu_id ) { ; } +} + +void +release_spinlock(uint32_t* lock) +{ +  int cpu_id = lapic_cpu_number(); +  cprintf ("release: %d\n", cpu_id); +  if (*lock != cpu_id) +    panic("release_spinlock: releasing a lock that i don't own\n"); +  *lock = LOCK_FREE; +} + +void +release_grant_spinlock(uint32_t* lock, int c) +{ +  int cpu_id = lapic_cpu_number(); +  cprintf ("release_grant: %d -> %d\n", cpu_id, c); +  if (*lock != cpu_id) +    panic("release_spinlock: releasing a lock that i don't own\n"); +  *lock = c; +} @@ -38,3 +38,23 @@ memcmp(const void *v1, const void *v2, unsigned n)    return 0;  } + +void * +memmove(void *dst, const void *src, unsigned n) +{ +  const char *s; +  char *d; +	 +  s = src; +  d = dst; +  if (s < d && s + n > d) { +    s += n; +    d += n; +    while (n-- > 0) +      *--d = *--s; +  } else +    while (n-- > 0) +      *d++ = *s++; + +  return dst; +} @@ -27,3 +27,8 @@ trapret:          popl %ds          addl $0x8, %esp /* trapno and errcode */          iret + +		 +.globl 	acpu +acpu: +	.long 0 @@ -261,6 +261,17 @@ cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *e  		*edxp = edx;  } +static __inline uint32_t +cmpxchg(uint32_t oldval, uint32_t newval, volatile uint32_t* lock_addr) +{ +  uint32_t result; +  __asm__ __volatile__( +		       "lock; cmpxchgl %2, %0" +		       :"+m" (*lock_addr), "=a" (result) : "r"(newval), "1"(oldval) : "cc" +		       ); +  return result; +} +  static __inline uint64_t  read_tsc(void)  { @@ -299,3 +310,16 @@ struct Trapframe {      uint16_t tf_ss;      uint16_t tf_padding4;  }; + + +#define MAX_IRQS	16	// Number of IRQs + +// I/O Addresses of the two 8259A programmable interrupt controllers +#define IO_PIC1		0x20	// Master (IRQs 0-7) +#define IO_PIC2	        0xA0	// Slave (IRQs 8-15) + +#define IRQ_SLAVE       2	// IRQ at which slave connects to master +#define IRQ_OFFSET      32	// IRQ 0 corresponds to int IRQ_OFFSET + +#define IRQ_ERROR       19 +#define IRQ_SPURIOUS    31  | 
