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

View file

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

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 * 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);

9
main.c
View file

@ -8,6 +8,7 @@
#include "syscall.h"
extern char edata[], end[];
extern int acpu;
char buf[512];
@ -17,12 +18,18 @@ 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();

284
mp.c
View file

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

130
mp.h
View file

@ -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 */
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 */
PcmpSASM = 0x80,
PcmpHIERARCHY = 0x81,
PcmpCBASM = 0x82,
MPSASM = 0x80,
MPHIERARCHY = 0x81,
MPCBASM = 0x82,
/* PCMPprocessor and PCMPioapic flags */
PcmpEN = 0x01, /* enabled */
PcmpBP = 0x02, /* bootstrap processor */
MPEN = 0x01, /* enabled */
MPBP = 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 */
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 */
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 */
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,
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,
ApicPHYSICAL = 0x00000000, /* [11] Destination Mode (RW) */
ApicLOGICAL = 0x00000800,
APIC_PHYSICAL = 0x00000000, /* [11] Destination Mode (RW) */
APIC_LOGICAL = 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_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 */
};

View file

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

View file

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

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;
}
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
addl $0x8, %esp /* trapno and errcode */
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;
}
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