checkpoint. booting second processor. stack is messed up, but thanks to cliff

and plan 9 code, at least boots and gets into C code.
This commit is contained in:
kaashoek 2006-06-22 01:28:57 +00:00
parent 7baa34a421
commit 21a88fd487
13 changed files with 499 additions and 145 deletions

View file

@ -1,5 +1,5 @@
OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o trap.o vectors.o \ 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 CC = i386-jos-elf-gcc
LD = i386-jos-elf-ld LD = i386-jos-elf-ld
@ -20,8 +20,12 @@ bootblock : bootasm.S bootmain.c
$(OBJCOPY) -S -O binary bootblock.o bootblock $(OBJCOPY) -S -O binary bootblock.o bootblock
./sign.pl bootblock ./sign.pl bootblock
kernel : $(OBJS) kernel : $(OBJS) bootother.S
$(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) $(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 $(OBJDUMP) -S kernel > kernel.asm
vectors.S : vectors.pl vectors.S : vectors.pl

View file

@ -1,17 +1,4 @@
#define SEG_NULL \ #include "asm.h"
.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
.set PROT_MODE_CSEG,0x8 # code segment selector .set PROT_MODE_CSEG,0x8 # code segment selector
.set PROT_MODE_DSEG,0x10 # data segment selector .set PROT_MODE_DSEG,0x10 # data segment selector

77
bootother.S Normal file
View file

@ -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

11
defs.h
View file

@ -22,6 +22,7 @@ void tinit(void);
void * memcpy(void *dst, void *src, unsigned n); void * memcpy(void *dst, void *src, unsigned n);
void * memset(void *dst, int c, unsigned n); void * memset(void *dst, int c, unsigned n);
int memcmp(const void *v1, const void *v2, unsigned n); int memcmp(const void *v1, const void *v2, unsigned n);
void *memmove(void *dst, const void *src, unsigned n);
// syscall.c // syscall.c
void syscall(void); void syscall(void);
@ -31,5 +32,13 @@ void irq_setmask_8259A(uint16_t mask);
void pic_init(void); void pic_init(void);
// mp.c // 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);

9
main.c
View file

@ -8,6 +8,7 @@
#include "syscall.h" #include "syscall.h"
extern char edata[], end[]; extern char edata[], end[];
extern int acpu;
char buf[512]; char buf[512];
@ -17,12 +18,18 @@ main()
struct proc *p; struct proc *p;
int i; int i;
if (acpu) {
cprintf("an application processor\n");
release_spinlock(&kernel_lock);
while (1) ;
}
acpu = 1;
// clear BSS // clear BSS
memset(edata, 0, end - edata); memset(edata, 0, end - edata);
cprintf("\nxV6\n\n"); cprintf("\nxV6\n\n");
mpinit(); // multiprocessor mp_init(); // multiprocessor
kinit(); // physical memory allocator kinit(); // physical memory allocator
tinit(); // traps and interrupts tinit(); // traps and interrupts
pic_init(); pic_init();

284
mp.c
View file

@ -2,11 +2,201 @@
#include "mp.h" #include "mp.h"
#include "defs.h" #include "defs.h"
#include "memlayout.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 int ncpu;
static struct cpu *bcpu;
static struct _MP_* 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)
;
/*
* 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) mp_scan(uint8_t *addr, int len)
{ {
uint8_t *e, *p, sum; uint8_t *e, *p, sum;
@ -14,24 +204,24 @@ mp_scan(uint8_t *addr, int len)
cprintf("scanning: 0x%x\n", (uint32_t)addr); cprintf("scanning: 0x%x\n", (uint32_t)addr);
e = addr+len; 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)) if(memcmp(p, "_MP_", 4))
continue; continue;
sum = 0; sum = 0;
for(i = 0; i < sizeof(struct _MP_); i++) for(i = 0; i < sizeof(struct MP); i++)
sum += p[i]; sum += p[i];
if(sum == 0) if(sum == 0)
return (struct _MP_ *)p; return (struct MP *)p;
} }
return 0; return 0;
} }
static struct _MP_* static struct MP*
mp_search(void) mp_search(void)
{ {
uint8_t *bda; uint8_t *bda;
uint32_t p; uint32_t p;
struct _MP_ *mp; struct MP *mp;
/* /*
* Search for the MP Floating Pointer Structure, which according to the * Search for the MP Floating Pointer Structure, which according to the
@ -56,7 +246,7 @@ mp_search(void)
static int static int
mp_detect(void) mp_detect(void)
{ {
struct PCMP *pcmp; struct MPCTB *pcmp;
uint8_t *p, sum; uint8_t *p, sum;
uint32_t length; uint32_t length;
@ -67,10 +257,10 @@ mp_detect(void)
* if correct, check the version. * if correct, check the version.
* To do: check extended table checksum. * To do: check extended table checksum.
*/ */
if((_mp_ = mp_search()) == 0 || _mp_->physaddr == 0) if((mp = mp_search()) == 0 || mp->physaddr == 0)
return 1; return 1;
pcmp = KADDR(_mp_->physaddr); pcmp = KADDR(mp->physaddr);
if(memcmp(pcmp, "PCMP", 4)) if(memcmp(pcmp, "PCMP", 4))
return 2; return 2;
@ -82,48 +272,65 @@ mp_detect(void)
if(sum || (pcmp->version != 1 && pcmp->version != 4)) if(sum || (pcmp->version != 1 && pcmp->version != 4))
return 3; return 3;
cprintf("MP spec rev #: %x\n", _mp_->specrev); cprintf("MP spec rev #: %x\n", mp->specrev);
return 0; return 0;
} }
int
mp_isbcpu()
{
if (bcpu == 0) return 1;
else return 0;
}
void void
mpinit() mp_init()
{ {
int r; int r;
uint8_t *p, *e; uint8_t *p, *e;
struct PCMP *pcmp; struct MPCTB *mpctb;
struct MPPE *proc;
struct cpu *c;
ncpu = 0; ncpu = 0;
if ((r = mp_detect()) != 0) return; 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 * Run through the table saving information needed for starting
* application processors and initialising any I/O APICs. The table * application processors and initialising any I/O APICs. The table
* is guaranteed to be in order such that only one pass is necessary. * is guaranteed to be in order such that only one pass is necessary.
*/ */
pcmp = KADDR(_mp_->physaddr); mpctb = KADDR(mp->physaddr);
p = ((uint8_t*)pcmp)+sizeof(struct PCMP); lapicaddr = KADDR(mpctb->lapicaddr);
e = ((uint8_t*)pcmp)+pcmp->length; cprintf("apicaddr: %x\n", lapicaddr);
p = ((uint8_t*)mpctb)+sizeof(struct MPCTB);
e = ((uint8_t*)mpctb)+mpctb->length;
while(p < e) { while(p < e) {
switch(*p){ switch(*p){
case PcmpPROCESSOR: case MPPROCESSOR:
cprintf("a processor\n"); 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++; ncpu++;
p += sizeof(struct PCMPprocessor); p += sizeof(struct MPPE);
continue; continue;
case PcmpBUS: case MPBUS:
cprintf("a bus\n"); p += sizeof(struct MPBE);
p += sizeof(struct PCMPbus);
continue; continue;
case PcmpIOAPIC: case MPIOAPIC:
cprintf("an IO APIC\n"); cprintf("an I/O APIC\n");
p += sizeof(struct PCMPioapic); p += sizeof(struct MPIOAPIC);
continue; continue;
case PcmpIOINTR: case MPIOINTR:
cprintf("an IO interrupt assignment\n"); p += sizeof(struct MPIE);
p += sizeof(struct PCMPintr);
continue; continue;
default: default:
cprintf("mpinit: unknown PCMP type 0x%x (e-p 0x%x)\n", *p, e-p); cprintf("mpinit: unknown PCMP type 0x%x (e-p 0x%x)\n", *p, e-p);
@ -135,5 +342,22 @@ mpinit()
} }
} }
cprintf("ncpu: %d\n", ncpu); lapic_init(cpu-bcpu);
cprintf("ncpu: %d boot %d\n", ncpu, cpu-bcpu);
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);
}
} }

138
mp.h
View file

@ -1,7 +1,10 @@
/* /*
* MultiProcessor Specification Version 1.[14]. * MultiProcessor Specification Version 1.[14].
*
* Credit: Plan 9 sources
*/ */
struct _MP_ { /* floating pointer */
struct MP { /* floating pointer */
uint8_t signature[4]; /* "_MP_" */ uint8_t signature[4]; /* "_MP_" */
physaddr_t physaddr; /* physical address of MP configuration table */ physaddr_t physaddr; /* physical address of MP configuration table */
uint8_t length; /* 1 */ uint8_t length; /* 1 */
@ -12,7 +15,7 @@ struct _MP_ { /* floating pointer */
uint8_t reserved[3]; uint8_t reserved[3];
}; };
struct PCMP { /* configuration table header */ struct MPCTB { /* configuration table header */
uint8_t signature[4]; /* "PCMP" */ uint8_t signature[4]; /* "PCMP" */
uint16_t length; /* total table length */ uint16_t length; /* total table length */
uint8_t version; /* [14] */ uint8_t version; /* [14] */
@ -21,15 +24,15 @@ struct PCMP { /* configuration table header */
uintptr_t oemtable; /* OEM table pointer */ uintptr_t oemtable; /* OEM table pointer */
uint16_t oemlength; /* OEM table length */ uint16_t oemlength; /* OEM table length */
uint16_t entry; /* entry count */ 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 */ uint16_t xlength; /* extended table length */
uint8_t xchecksum; /* extended table checksum */ uint8_t xchecksum; /* extended table checksum */
uint8_t reserved; uint8_t reserved;
}; };
struct PCMPprocessor { /* processor table entry */ struct MPPE { /* processor table entry */
uint8_t type; /* entry type (0) */ 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 version; /* local APIC verison */
uint8_t flags; /* CPU flags */ uint8_t flags; /* CPU flags */
uint8_t signature[4]; /* CPU signature */ uint8_t signature[4]; /* CPU signature */
@ -37,13 +40,13 @@ struct PCMPprocessor { /* processor table entry */
uint8_t reserved[8]; uint8_t reserved[8];
}; };
struct PCMPbus { /* bus table entry */ struct MPBE { /* bus table entry */
uint8_t type; /* entry type (1) */ uint8_t type; /* entry type (1) */
uint8_t busno; /* bus id */ uint8_t busno; /* bus id */
char string[6]; /* bus type string */ 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 type; /* entry type (2) */
uint8_t apicno; /* I/O APIC id */ uint8_t apicno; /* I/O APIC id */
uint8_t version; /* I/O APIC version */ 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 */ 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 type; /* entry type ([34]) */
uint8_t intr; /* interrupt type */ uint8_t intr; /* interrupt type */
uint16_t flags; /* interrupt flag */ uint16_t flags; /* interrupt flag */
@ -61,71 +64,34 @@ struct PCMPintr { /* interrupt table entry */
uint8_t intin; /* destination APIC [L]INTIN# */ uint8_t intin; /* destination APIC [L]INTIN# */
}; };
struct PCMPsasm { /* system address space mapping entry */ enum { /* table entry types */
uint8_t type; /* entry type (128) */ MPPROCESSOR = 0x00, /* one entry per processor */
uint8_t length; /* of this entry (20) */ MPBUS = 0x01, /* one entry per bus */
uint8_t busno; /* bus id */ MPIOAPIC = 0x02, /* one entry per I/O APIC */
uint8_t addrtype; MPIOINTR = 0x03, /* one entry per bus interrupt source */
uintptr_t addrbase[2]; MPLINTR = 0x04, /* one entry per system interrupt source */
uint32_t addrlength[2];
};
struct PCMPhierarchy { /* bus hierarchy descriptor entry */ MPSASM = 0x80,
uint8_t type; /* entry type (129) */ MPHIERARCHY = 0x81,
uint8_t length; /* of this entry (8) */ MPCBASM = 0x82,
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 */ /* PCMPprocessor and PCMPioapic flags */
uint8_t type; /* entry type (130) */ MPEN = 0x01, /* enabled */
uint8_t length; /* of this entry (8) */ MPBP = 0x02, /* bootstrap processor */
uint8_t busno; /* bus id */
uint8_t modifier; /* address modifier */
uint32_t range; /* predefined range list */
};
enum { /* table entry types */ /* PCMPiointr and PCMPlintr flags */
PcmpPROCESSOR = 0x00, /* one entry per processor */ MPPOMASK = 0x03, /* polarity conforms to specifications of bus */
PcmpBUS = 0x01, /* one entry per bus */ MPHIGH = 0x01, /* active high */
PcmpIOAPIC = 0x02, /* one entry per I/O APIC */ MPLOW = 0x03, /* active low */
PcmpIOINTR = 0x03, /* one entry per bus interrupt source */ MPELMASK = 0x0C, /* trigger mode of APIC input signals */
PcmpLINTR = 0x04, /* one entry per system interrupt source */ MPEDGE = 0x04, /* edge-triggered */
MPLEVEL = 0x0C, /* level-triggered */
PcmpSASM = 0x80, /* PCMPiointr and PCMPlintr interrupt type */
PcmpHIERARCHY = 0x81, MPINT = 0x00, /* vectored interrupt from APIC Rdt */
PcmpCBASM = 0x82, MPNMI = 0x01, /* non-maskable interrupt */
MPSMI = 0x02, /* system management interrupt */
/* PCMPprocessor and PCMPioapic flags */ MPExtINT = 0x03, /* vectored interrupt from external PIC */
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 */
}; };
/* /*
@ -136,23 +102,23 @@ enum { /* table entry types */
* Local APIC Timer Vector Table. * Local APIC Timer Vector Table.
*/ */
enum { enum {
ApicFIXED = 0x00000000, /* [10:8] Delivery Mode */ APIC_FIXED = 0x00000000, /* [10:8] Delivery Mode */
ApicLOWEST = 0x00000100, /* Lowest priority */ APIC_LOWEST = 0x00000100, /* Lowest priority */
ApicSMI = 0x00000200, /* System Management Interrupt */ APIC_SMI = 0x00000200, /* System Management Interrupt */
ApicRR = 0x00000300, /* Remote Read */ APIC_RR = 0x00000300, /* Remote Read */
ApicNMI = 0x00000400, APIC_NMI = 0x00000400,
ApicINIT = 0x00000500, /* INIT/RESET */ APIC_INIT = 0x00000500, /* INIT/RESET */
ApicSTARTUP = 0x00000600, /* Startup IPI */ APIC_STARTUP = 0x00000600, /* Startup IPI */
ApicExtINT = 0x00000700, APIC_ExtINT = 0x00000700,
ApicPHYSICAL = 0x00000000, /* [11] Destination Mode (RW) */ APIC_PHYSICAL = 0x00000000, /* [11] Destination Mode (RW) */
ApicLOGICAL = 0x00000800, APIC_LOGICAL = 0x00000800,
ApicDELIVS = 0x00001000, /* [12] Delivery Status (RO) */ APIC_DELIVS = 0x00001000, /* [12] Delivery Status (RO) */
ApicHIGH = 0x00000000, /* [13] Interrupt Input Pin Polarity (RW) */ APIC_HIGH = 0x00000000, /* [13] Interrupt Input Pin Polarity (RW) */
ApicLOW = 0x00002000, APIC_LOW = 0x00002000,
ApicRemoteIRR = 0x00004000, /* [14] Remote IRR (RO) */ APIC_RemoteIRR = 0x00004000, /* [14] Remote IRR (RO) */
ApicEDGE = 0x00000000, /* [15] Trigger Mode (RW) */ APIC_EDGE = 0x00000000, /* [15] Trigger Mode (RW) */
ApicLEVEL = 0x00008000, APIC_LEVEL = 0x00008000,
ApicIMASK = 0x00010000, /* [16] Interrupt Mask */ APIC_IMASK = 0x00010000, /* [16] Interrupt Mask */
}; };

View file

@ -1,3 +1,4 @@
#define NPROC 64 #define NPROC 64
#define PAGE 4096 #define PAGE 4096
#define KSTACKSIZE PAGE #define KSTACKSIZE PAGE
#define NCPU 8

View file

@ -4,15 +4,6 @@
#include "x86.h" #include "x86.h"
#include "defs.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. // Current IRQ mask.
// Initial IRQ mask has interrupt 2 enabled (for slave 8259A). // Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
uint16_t irq_mask_8259A = 0xFFFF & ~(1<<IRQ_SLAVE); uint16_t irq_mask_8259A = 0xFFFF & ~(1<<IRQ_SLAVE);

39
spinlock.c Normal file
View file

@ -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;
}

View file

@ -38,3 +38,23 @@ memcmp(const void *v1, const void *v2, unsigned n)
return 0; 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;
}

View file

@ -27,3 +27,8 @@ trapret:
popl %ds popl %ds
addl $0x8, %esp /* trapno and errcode */ addl $0x8, %esp /* trapno and errcode */
iret iret
.globl acpu
acpu:
.long 0

24
x86.h
View file

@ -261,6 +261,17 @@ cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *e
*edxp = edx; *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 static __inline uint64_t
read_tsc(void) read_tsc(void)
{ {
@ -299,3 +310,16 @@ struct Trapframe {
uint16_t tf_ss; uint16_t tf_ss;
uint16_t tf_padding4; 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