segmentless smp fixes

adjust the smp booting procedure for segmentless operation. changes are
mostly due to gdt/idt being dependent on paging, because of the high
location, and paging being on much sooner because of that too.

also smaller fixes: redefine DESC_SIZE, fix kernel makefile variable name
(crosscompiling), some null pointer checks that trap now because of a
sparser pagetable, acpi sanity checking
This commit is contained in:
Ben Gras 2012-07-13 00:54:27 +02:00
parent 50e2064049
commit 1d48c0148e
16 changed files with 259 additions and 145 deletions

View file

@ -16,6 +16,14 @@ struct segdesc_s { /* segment descriptor for protected mode */
u8_t base_high; u8_t base_high;
} __attribute__((packed)); } __attribute__((packed));
struct gatedesc_s {
u16_t offset_low;
u16_t selector;
u8_t pad; /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */
u8_t p_dpl_type; /* |P|DL|0|TYPE| */
u16_t offset_high;
} __attribute__((packed));
struct desctableptr_s { struct desctableptr_s {
u16_t limit; u16_t limit;
u32_t base; u32_t base;

View file

@ -8,7 +8,7 @@ PROG= kernel
SRCS+= clock.c cpulocals.c interrupt.c main.c proc.c system.c \ SRCS+= clock.c cpulocals.c interrupt.c main.c proc.c system.c \
table.c utility.c table.c utility.c
LINKERSCRIPT=${.CURDIR}/arch/${ARCH}/kernel.lds LINKERSCRIPT=${.CURDIR}/arch/${MACHINE_ARCH}/kernel.lds
DPADD+= ${LIBTIMERS} ${LIBSYS} ${LIBEXEC} $(LINKERSCRIPT) DPADD+= ${LIBTIMERS} ${LIBSYS} ${LIBEXEC} $(LINKERSCRIPT)
LDADD+= -ltimers -lsys -lexec LDADD+= -ltimers -lsys -lexec

View file

@ -39,6 +39,24 @@ static int acpi_check_signature(const char * orig, const char * match)
return strncmp(orig, match, ACPI_SDT_SIGNATURE_LEN); return strncmp(orig, match, ACPI_SDT_SIGNATURE_LEN);
} }
static u32_t acpi_phys2vir(u32_t p)
{
if(!vm_running) {
printf("acpi: returning 0x%lx as vir addr\n", p);
return p;
}
panic("acpi: can't get virtual address of arbitrary physical address");
}
static int acpi_phys_copy(phys_bytes phys, void *target, size_t len)
{
if(!vm_running) {
memcpy(target, (void *) phys, len);
return 0;
}
panic("can't acpi_phys_copy with vm");
}
static int acpi_read_sdt_at(phys_bytes addr, static int acpi_read_sdt_at(phys_bytes addr,
struct acpi_sdt_header * tb, struct acpi_sdt_header * tb,
size_t size, size_t size,
@ -172,7 +190,7 @@ static int get_acpi_rsdp(void)
/* /*
* Read 40:0Eh - to find the starting address of the EBDA. * Read 40:0Eh - to find the starting address of the EBDA.
*/ */
phys_copy (0x40E, vir2phys(&ebda), sizeof(ebda)); acpi_phys_copy (0x40E, &ebda, sizeof(ebda));
if (ebda) { if (ebda) {
ebda <<= 4; ebda <<= 4;
if(platform_tbl_ptr(ebda, ebda + 0x400, 16, &acpi_rsdp, if(platform_tbl_ptr(ebda, ebda + 0x400, 16, &acpi_rsdp,
@ -192,16 +210,10 @@ static int get_acpi_rsdp(void)
return 0; return 0;
} }
static int acpi_read_kernel(phys_bytes addr, void * buff, size_t size)
{
phys_copy(addr, vir2phys(buff), size);
return 0;
}
void acpi_init(void) void acpi_init(void)
{ {
int s, i; int s, i;
read_func = acpi_read_kernel; read_func = acpi_phys_copy;
if (!get_acpi_rsdp()) { if (!get_acpi_rsdp()) {
printf("WARNING : Cannot configure ACPI\n"); printf("WARNING : Cannot configure ACPI\n");
@ -238,7 +250,7 @@ struct acpi_madt_ioapic * acpi_get_ioapic_next(void)
if (idx == 0) { if (idx == 0) {
madt_hdr = (struct acpi_madt_hdr *) madt_hdr = (struct acpi_madt_hdr *)
phys2vir(acpi_get_table_base("APIC")); acpi_phys2vir(acpi_get_table_base("APIC"));
if (madt_hdr == NULL) if (madt_hdr == NULL)
return NULL; return NULL;
} }
@ -260,7 +272,7 @@ struct acpi_madt_lapic * acpi_get_lapic_next(void)
if (idx == 0) { if (idx == 0) {
madt_hdr = (struct acpi_madt_hdr *) madt_hdr = (struct acpi_madt_hdr *)
phys2vir(acpi_get_table_base("APIC")); acpi_phys2vir(acpi_get_table_base("APIC"));
if (madt_hdr == NULL) if (madt_hdr == NULL)
return NULL; return NULL;
} }

View file

@ -365,6 +365,11 @@ void ioapic_disable_all(void)
static void ioapic_disable_irq(unsigned irq) static void ioapic_disable_irq(unsigned irq)
{ {
if(!(io_apic_irq[irq].ioa)) {
printf("ioapic_disable_irq: no ioa set for irq %d!\n", irq);
return;
}
assert(io_apic_irq[irq].ioa); assert(io_apic_irq[irq].ioa);
ioapic_disable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin); ioapic_disable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
@ -373,6 +378,11 @@ static void ioapic_disable_irq(unsigned irq)
static void ioapic_enable_irq(unsigned irq) static void ioapic_enable_irq(unsigned irq)
{ {
if(!(io_apic_irq[irq].ioa)) {
printf("ioapic_enable_irq: no ioa set for irq %d!\n", irq);
return;
}
assert(io_apic_irq[irq].ioa); assert(io_apic_irq[irq].ioa);
ioapic_enable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin); ioapic_enable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
@ -915,16 +925,17 @@ static int acpi_get_ioapics(struct io_apic * ioa, unsigned * nioa, unsigned max)
if (acpi_ioa == NULL) if (acpi_ioa == NULL)
break; break;
assert(acpi_ioa->address);
ioa[n].id = acpi_ioa->id; ioa[n].id = acpi_ioa->id;
ioa[n].addr = acpi_ioa->address; ioa[n].addr = acpi_ioa->address;
ioa[n].paddr = (phys_bytes) acpi_ioa->address; ioa[n].paddr = (phys_bytes) acpi_ioa->address;
ioa[n].gsi_base = acpi_ioa->global_int_base; ioa[n].gsi_base = acpi_ioa->global_int_base;
ioa[n].pins = ((ioapic_read(ioa[n].addr, ioa[n].pins = ((ioapic_read(ioa[n].addr,
IOAPIC_VERSION) & 0xff0000) >> 16)+1; IOAPIC_VERSION) & 0xff0000) >> 16)+1;
printf("IO APIC %d addr 0x%lx paddr 0x%lx pins %d\n", printf("IO APIC idx %d id %d addr 0x%lx paddr 0x%lx pins %d\n",
acpi_ioa->id, ioa[n].addr, ioa[n].paddr, n, acpi_ioa->id, ioa[n].addr, ioa[n].paddr,
ioa[n].pins); ioa[n].pins);
n++; n++;
} }

View file

@ -206,6 +206,7 @@ void context_stop(struct proc * p)
u64_t * __tsc_ctr_switch = get_cpulocal_var_ptr(tsc_ctr_switch); u64_t * __tsc_ctr_switch = get_cpulocal_var_ptr(tsc_ctr_switch);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
unsigned cpu = cpuid; unsigned cpu = cpuid;
int must_bkl_unlock = 0;
/* /*
* This function is called only if we switch from kernel to user or idle * This function is called only if we switch from kernel to user or idle
@ -222,7 +223,7 @@ void context_stop(struct proc * p)
tmp = sub64(tsc, *__tsc_ctr_switch); tmp = sub64(tsc, *__tsc_ctr_switch);
kernel_ticks[cpu] = add64(kernel_ticks[cpu], tmp); kernel_ticks[cpu] = add64(kernel_ticks[cpu], tmp);
p->p_cycles = add64(p->p_cycles, tmp); p->p_cycles = add64(p->p_cycles, tmp);
BKL_UNLOCK(); must_bkl_unlock = 1;
} else { } else {
u64_t bkl_tsc; u64_t bkl_tsc;
atomic_t succ; atomic_t succ;
@ -295,6 +296,12 @@ void context_stop(struct proc * p)
} }
*__tsc_ctr_switch = tsc; *__tsc_ctr_switch = tsc;
#ifdef CONFIG_SMP
if(must_bkl_unlock) {
BKL_UNLOCK();
}
#endif
} }
void context_stop_idle(void) void context_stop_idle(void)

View file

@ -11,7 +11,10 @@
#include "arch_proto.h" #include "arch_proto.h"
#include "kernel/glo.h" #include "kernel/glo.h"
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <machine/archtypes.h>
#include <archconst.h>
#include <machine/cmos.h> #include <machine/cmos.h>
#include <machine/bios.h> #include <machine/bios.h>
#include <minix/portio.h> #include <minix/portio.h>
@ -31,8 +34,9 @@ void trampoline(void);
* They have to be in location which is reachable using absolute addressing in * They have to be in location which is reachable using absolute addressing in
* 16-bit mode * 16-bit mode
*/ */
extern volatile u32_t __ap_id; extern volatile u32_t __ap_id, __ap_pt;
extern volatile struct desctableptr_s __ap_gdt, __ap_idt; extern volatile struct desctableptr_s __ap_gdt, __ap_idt;
extern u32_t __ap_gdt_tab, __ap_idt_tab;
extern void * __trampoline_end; extern void * __trampoline_end;
extern u32_t busclock[CONFIG_MAX_CPUS]; extern u32_t busclock[CONFIG_MAX_CPUS];
@ -50,81 +54,84 @@ SPINLOCK_DEFINE(dispq_lock)
static void smp_reinit_vars(void); static void smp_reinit_vars(void);
/* These are initialized in protect.c */
extern struct segdesc_s gdt[GDT_SIZE];
extern struct gatedesc_s idt[IDT_SIZE];
extern struct tss_s tss[CONFIG_MAX_CPUS];
extern int prot_init_done; /* Indicates they are ready */
static phys_bytes trampoline_base;
static u32_t ap_lin_addr(void *vaddr)
{
assert(trampoline_base);
return (u32_t) vaddr - (u32_t) &trampoline + trampoline_base;
}
/* /*
* copies the 16-bit AP trampoline code to the first 1M of memory * copies the 16-bit AP trampoline code to the first 1M of memory
*/ */
static phys_bytes copy_trampoline(void) void copy_trampoline(void)
{ {
char * s, *end; char * s, *end;
phys_bytes tramp_base = 0; unsigned tramp_size, tramp_start = (unsigned)&trampoline;;
unsigned tramp_size;
tramp_size = (unsigned) &__trampoline_end - (unsigned)&trampoline; /* The trampoline code/data is made to be page-aligned. */
s = env_get("memory"); assert(!(tramp_start % I386_PAGE_SIZE));
if (!s)
return 0;
while (*s != 0) { tramp_size = (unsigned) &__trampoline_end - tramp_start;
phys_bytes base = 0xfffffff; trampoline_base = alloc_lowest(&kinfo, tramp_size);
unsigned size;
/* Read fresh base and expect colon as next char. */
base = strtoul(s, &end, 0x10); /* get number */
if (end != s && *end == ':')
s = ++end; /* skip ':' */
else
*s=0;
/* Read fresh size and expect comma or assume end. */ /* The memory allocator finds the lowest available memory..
size = strtoul(s, &end, 0x10); /* get number */ * Verify it's low enough
if (end != s && *end == ',') */
s = ++end; /* skip ',' */ assert(trampoline_base + tramp_size < (1 << 20));
tramp_base = (base + 0xfff) & ~(0xfff); /* prepare gdt and idt for the new cpus; make copies
/* the address must be less than 1M */ * of both the tables and the descriptors of them
if (tramp_base >= (1 << 20)) * in their boot addressing environment.
continue; */
if (size - (tramp_base - base) < tramp_size) assert(prot_init_done);
continue; memcpy(&__ap_gdt_tab, gdt, sizeof(gdt));
break; memcpy(&__ap_idt_tab, gdt, sizeof(idt));
} __ap_gdt.base = ap_lin_addr(&__ap_gdt_tab);
__ap_gdt.limit = sizeof(gdt)-1;
__ap_idt.base = ap_lin_addr(&__ap_idt_tab);
__ap_idt.limit = sizeof(idt)-1;
phys_copy(vir2phys(trampoline), tramp_base, tramp_size); phys_copy(trampoline, trampoline_base, tramp_size);
return tramp_base;
} }
extern struct desctableptr_s gdt_desc, idt_desc; extern int booting_cpu; /* tell protect.c what to do */
static void smp_start_aps(void) static void smp_start_aps(void)
{ {
/*
* Find an address and align it to a 4k boundary.
*/
unsigned cpu; unsigned cpu;
u32_t biosresetvector; u32_t biosresetvector, *newptpos;
phys_bytes trampoline_base, __ap_id_phys; phys_bytes __ap_id_phys;
struct proc *bootstrap_pt = get_cpulocal_var(ptproc);
/* TODO hack around the alignment problem */ /* TODO hack around the alignment problem */
phys_copy (0x467, vir2phys(&biosresetvector), sizeof(u32_t)); phys_copy (0x467, &biosresetvector, sizeof(u32_t));
/* set the bios shutdown code to 0xA */ /* set the bios shutdown code to 0xA */
outb(RTC_INDEX, 0xF); outb(RTC_INDEX, 0xF);
outb(RTC_IO, 0xA); outb(RTC_IO, 0xA);
/* prepare gdt and idt for the new cpus */ assert(bootstrap_pt);
__ap_gdt = gdt_desc; assert(bootstrap_pt->p_seg.p_cr3);
__ap_idt = idt_desc; __ap_pt = bootstrap_pt->p_seg.p_cr3;
assert(__ap_pt);
if (!(trampoline_base = copy_trampoline())) { copy_trampoline();
printf("Copying trampoline code failed, cannot boot SMP\n");
ncpus = 1; /* New locations for cpu id, pagetable root */
}
__ap_id_phys = trampoline_base + __ap_id_phys = trampoline_base +
(phys_bytes) &__ap_id - (phys_bytes)&trampoline; (phys_bytes) &__ap_id - (phys_bytes)&trampoline;
/* setup the warm reset vector */ /* setup the warm reset vector */
phys_copy(vir2phys(&trampoline_base), 0x467, sizeof(u32_t)); phys_copy(&trampoline_base, 0x467, sizeof(u32_t));
/* okay, we're ready to go. boot all of the ap's now. we loop through /* okay, we're ready to go. boot all of the ap's now. we loop through
* using the processor's apic id values. * using the processor's apic id values.
@ -137,9 +144,8 @@ static void smp_start_aps(void)
continue; continue;
} }
__ap_id = cpu; __ap_id = booting_cpu = cpu;
phys_copy(vir2phys((void *) &__ap_id), phys_copy((void *) &__ap_id, __ap_id_phys, sizeof(__ap_id));
__ap_id_phys, sizeof(__ap_id));
mfence(); mfence();
if (apic_send_init_ipi(cpu, trampoline_base) || if (apic_send_init_ipi(cpu, trampoline_base) ||
apic_send_startup_ipi(cpu, trampoline_base)) { apic_send_startup_ipi(cpu, trampoline_base)) {
@ -161,7 +167,7 @@ static void smp_start_aps(void)
} }
} }
phys_copy(vir2phys(&biosresetvector),(phys_bytes)0x467,sizeof(u32_t)); phys_copy(&biosresetvector,(phys_bytes)0x467,sizeof(u32_t));
outb(RTC_INDEX, 0xF); outb(RTC_INDEX, 0xF);
outb(RTC_IO, 0); outb(RTC_IO, 0);
@ -219,9 +225,6 @@ static void ap_finish_booting(void)
/* inform the world of our presence. */ /* inform the world of our presence. */
ap_cpu_ready = cpu; ap_cpu_ready = cpu;
while(!bootstrap_pagetable_done)
arch_pause();
/* /*
* Finish processor initialisation. CPUs must be excluded from running. * Finish processor initialisation. CPUs must be excluded from running.
* lapic timer calibration locks and unlocks the BKL because of the * lapic timer calibration locks and unlocks the BKL because of the
@ -231,14 +234,7 @@ static void ap_finish_booting(void)
spinlock_lock(&boot_lock); spinlock_lock(&boot_lock);
BKL_LOCK(); BKL_LOCK();
/* printf("CPU %d is up\n", cpu);
* we must load some page tables befre we turn paging on. As VM is
* always present we use those
*/
pg_load(); /* load bootstrap pagetable built by BSP */
vm_enable_paging();
printf("CPU %d paging is on\n", cpu);
cpu_identify(); cpu_identify();

View file

@ -161,12 +161,13 @@ u32_t read_ds(void);
u32_t read_ss(void); u32_t read_ss(void);
void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len); void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len);
phys_bytes alloc_lowest(kinfo_t *cbi, phys_bytes len);
void vm_enable_paging(void); void vm_enable_paging(void);
void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end); void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end);
phys_bytes pg_roundup(phys_bytes b); phys_bytes pg_roundup(phys_bytes b);
void pg_info(reg_t *, u32_t **); void pg_info(reg_t *, u32_t **);
void pg_clear(void); void pg_clear(void);
void pg_identity(void); void pg_identity(kinfo_t *);
phys_bytes pg_load(void); phys_bytes pg_load(void);
void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end, kinfo_t *cbi); void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end, kinfo_t *cbi);
int pg_mapkernel(void); int pg_mapkernel(void);

View file

@ -28,6 +28,8 @@
#define LDT_SELECTOR SEG_SELECTOR(LDT_INDEX) #define LDT_SELECTOR SEG_SELECTOR(LDT_INDEX)
#define TSS_SELECTOR(cpu) SEG_SELECTOR(TSS_INDEX(cpu)) #define TSS_SELECTOR(cpu) SEG_SELECTOR(TSS_INDEX(cpu))
#define DESC_SIZE 8
/* Privileges. */ /* Privileges. */
#define INTR_PRIVILEGE 0 /* kernel and interrupt handlers */ #define INTR_PRIVILEGE 0 /* kernel and interrupt handlers */
#define USER_PRIVILEGE 3 /* servers and user processes */ #define USER_PRIVILEGE 3 /* servers and user processes */

View file

@ -164,11 +164,11 @@ static int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr,
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
unsigned cpu = cpuid; unsigned cpu = cpuid;
if (GET_BIT(srcproc->p_stale_tlb, cpu)) { if (srcproc && GET_BIT(srcproc->p_stale_tlb, cpu)) {
changed = 1; changed = 1;
UNSET_BIT(srcproc->p_stale_tlb, cpu); UNSET_BIT(srcproc->p_stale_tlb, cpu);
} }
if (GET_BIT(dstproc->p_stale_tlb, cpu)) { if (dstproc && GET_BIT(dstproc->p_stale_tlb, cpu)) {
changed = 1; changed = 1;
UNSET_BIT(dstproc->p_stale_tlb, cpu); UNSET_BIT(dstproc->p_stale_tlb, cpu);
} }
@ -815,10 +815,13 @@ int arch_phys_map(const int index,
*flags = VMMF_UNCACHED; *flags = VMMF_UNCACHED;
return OK; return OK;
} }
else if (ioapic_enabled && index <= ioapic_last_index) { else if (ioapic_enabled && index >= ioapic_first_index && index <= ioapic_last_index) {
*addr = io_apic[index - 1].paddr; int ioapic_idx = index - ioapic_first_index;
*addr = io_apic[ioapic_idx].paddr;
assert(*addr);
*len = 4 << 10 /* 4kB */; *len = 4 << 10 /* 4kB */;
*flags = VMMF_UNCACHED; *flags = VMMF_UNCACHED;
printf("ioapic map: addr 0x%lx\n", *addr);
return OK; return OK;
} }
#endif #endif

View file

@ -479,27 +479,22 @@ ENTRY(startup_ap_32)
/* /*
* we are in protected mode now, %cs is correct and we need to set the * we are in protected mode now, %cs is correct and we need to set the
* data descriptors before we can touch anything * data descriptors before we can touch anything
*
* first load the regular, highly mapped idt, gdt
*/ */
movw $KERN_DS_SELECTOR, %ax
mov %ax, %ds
mov %ax, %ss
mov %ax, %es
movw $0, %ax
mov %ax, %fs
mov %ax, %gs
/* load TSS for this cpu which was prepared by BSP */
movl _C_LABEL(__ap_id), %ecx
shl $3, %cx
mov $TSS_SELECTOR(0), %eax
add %cx, %ax
ltr %ax
/* /*
* use the boot stack for now. The running CPUs are already using their * use the boot stack for now. The running CPUs are already using their
* own stack, the rest is still waiting to be booted * own stack, the rest is still waiting to be booted
*/ */
movw $KERN_DS_SELECTOR, %ax
mov %ax, %ds
mov %ax, %ss
mov $_C_LABEL(k_boot_stktop) - 4, %esp mov $_C_LABEL(k_boot_stktop) - 4, %esp
/* load the highly mapped idt, gdt, per-cpu tss */
call _C_LABEL(prot_load_selectors)
jmp _C_LABEL(smp_ap_boot) jmp _C_LABEL(smp_ap_boot)
hlt hlt
#endif #endif

View file

@ -22,6 +22,17 @@ static phys_bytes kern_kernlen = (phys_bytes) &_kern_size;
/* page directory we can use to map things */ /* page directory we can use to map things */
static u32_t pagedir[1024] __aligned(4096); static u32_t pagedir[1024] __aligned(4096);
void print_memmap(kinfo_t *cbi)
{
int m;
assert(cbi->mmap_size < MAXMEMMAP);
for(m = 0; m < cbi->mmap_size; m++) {
phys_bytes addr = cbi->memmap[m].addr, endit = cbi->memmap[m].addr + cbi->memmap[m].len;
printf("%08lx-%08lx ",addr, endit);
}
printf("\nsize %08lx\n", cbi->mmap_size);
}
void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end) void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end)
{ {
int m; int m;
@ -32,6 +43,8 @@ void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end)
if((o=end % I386_PAGE_SIZE)) if((o=end % I386_PAGE_SIZE))
end += I386_PAGE_SIZE - o; end += I386_PAGE_SIZE - o;
assert(kernel_may_alloc);
for(m = 0; m < cbi->mmap_size; m++) { for(m = 0; m < cbi->mmap_size; m++) {
phys_bytes substart = start, subend = end; phys_bytes substart = start, subend = end;
phys_bytes memaddr = cbi->memmap[m].addr, phys_bytes memaddr = cbi->memmap[m].addr,
@ -53,10 +66,29 @@ void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end)
} }
} }
phys_bytes alloc_lowest(kinfo_t *cbi, phys_bytes len)
{
/* Allocate the lowest physical page we have. */
int m;
#define EMPTY 0xffffffff
phys_bytes lowest = EMPTY;
assert(len > 0);
len = roundup(len, I386_PAGE_SIZE);
assert(kernel_may_alloc);
for(m = 0; m < cbi->mmap_size; m++) {
if(cbi->memmap[m].len < len) continue;
if(cbi->memmap[m].addr < lowest) lowest = cbi->memmap[m].addr;
}
assert(lowest != EMPTY);
cut_memmap(cbi, lowest, len);
return lowest;
}
void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len) void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len)
{ {
int m; int m;
phys_bytes highmark;
#define LIMIT 0xFFFFF000 #define LIMIT 0xFFFFF000
/* Truncate available memory at 4GB as the rest of minix /* Truncate available memory at 4GB as the rest of minix
* currently can't deal with any bigger. * currently can't deal with any bigger.
@ -69,20 +101,25 @@ void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len)
if(len == 0) return; if(len == 0) return;
addr = roundup(addr, I386_PAGE_SIZE); addr = roundup(addr, I386_PAGE_SIZE);
len = rounddown(len, I386_PAGE_SIZE); len = rounddown(len, I386_PAGE_SIZE);
assert(kernel_may_alloc);
for(m = 0; m < MAXMEMMAP; m++) { for(m = 0; m < MAXMEMMAP; m++) {
phys_bytes highmark;
if(cbi->memmap[m].len) continue; if(cbi->memmap[m].len) continue;
cbi->memmap[m].addr = addr; cbi->memmap[m].addr = addr;
cbi->memmap[m].len = len; cbi->memmap[m].len = len;
cbi->memmap[m].type = MULTIBOOT_MEMORY_AVAILABLE; cbi->memmap[m].type = MULTIBOOT_MEMORY_AVAILABLE;
if(m >= cbi->mmap_size) if(m >= cbi->mmap_size)
cbi->mmap_size = m+1; cbi->mmap_size = m+1;
highmark = addr + len;
if(highmark > cbi->mem_high_phys) {
cbi->mem_high_phys = highmark;
}
return; return;
} }
highmark = addr + len;
if(highmark > cbi->mem_high_phys)
cbi->mem_high_phys = highmark;
panic("no available memmap slot"); panic("no available memmap slot");
} }
@ -105,6 +142,9 @@ phys_bytes pg_alloc_page(kinfo_t *cbi)
{ {
int m; int m;
multiboot_memory_map_t *mmap; multiboot_memory_map_t *mmap;
assert(kernel_may_alloc);
for(m = cbi->mmap_size-1; m >= 0; m--) { for(m = cbi->mmap_size-1; m >= 0; m--) {
mmap = &cbi->memmap[m]; mmap = &cbi->memmap[m];
if(!mmap->len) continue; if(!mmap->len) continue;
@ -120,16 +160,26 @@ phys_bytes pg_alloc_page(kinfo_t *cbi)
panic("can't find free memory"); panic("can't find free memory");
} }
void pg_identity(void) void pg_identity(kinfo_t *cbi)
{ {
int i; int i;
phys_bytes phys; phys_bytes phys;
/* We map memory that does not correspond to physical memory
* as non-cacheable. Make sure we know what it is.
*/
assert(cbi->mem_high_phys);
/* Set up an identity mapping page directory */ /* Set up an identity mapping page directory */
for(i = 0; i < I386_VM_DIR_ENTRIES; i++) { for(i = 0; i < I386_VM_DIR_ENTRIES; i++) {
u32_t flags = I386_VM_PRESENT | I386_VM_BIGPAGE |
I386_VM_USER | I386_VM_WRITE;
if((cbi->mem_high_phys & I386_VM_ADDR_MASK_4MB)
<= (phys & I386_VM_ADDR_MASK_4MB)) {
flags |= I386_VM_PWT | I386_VM_PCD;
}
phys = i * I386_BIG_PAGE_SIZE; phys = i * I386_BIG_PAGE_SIZE;
pagedir[i] = phys | I386_VM_PRESENT | I386_VM_BIGPAGE | pagedir[i] = phys | flags;
I386_VM_USER | I386_VM_WRITE;
} }
} }
@ -216,6 +266,8 @@ void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end,
static u32_t *pt = NULL; static u32_t *pt = NULL;
int pde, pte; int pde, pte;
assert(kernel_may_alloc);
if(phys == PG_ALLOCATEME) { if(phys == PG_ALLOCATEME) {
assert(!(vaddr % I386_PAGE_SIZE)); assert(!(vaddr % I386_PAGE_SIZE));
} else { } else {

View file

@ -37,6 +37,9 @@ char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
/* String length used for mb_itoa */ /* String length used for mb_itoa */
#define ITOA_BUFFER_SIZE 20 #define ITOA_BUFFER_SIZE 20
/* Kernel may use memory */
int kernel_may_alloc = 1;
static int mb_set_param(char *bigbuf, char *name, char *value, kinfo_t *cbi) static int mb_set_param(char *bigbuf, char *name, char *value, kinfo_t *cbi)
{ {
char *p = bigbuf; char *p = bigbuf;
@ -96,16 +99,6 @@ int overlaps(multiboot_module_t *mod, int n, int cmp_mod)
return 0; return 0;
} }
void print_memmap(kinfo_t *cbi)
{
int m;
assert(cbi->mmap_size < MAXMEMMAP);
for(m = 0; m < cbi->mmap_size; m++) {
printf("%08lx-%08lx ",cbi->memmap[m].addr, cbi->memmap[m].addr + cbi->memmap[m].len);
}
printf("\nsize %08lx\n", cbi->mmap_size);
}
void get_parameters(u32_t ebx, kinfo_t *cbi) void get_parameters(u32_t ebx, kinfo_t *cbi)
{ {
multiboot_memory_map_t *mmap; multiboot_memory_map_t *mmap;
@ -225,9 +218,6 @@ kinfo_t *pre_init(u32_t magic, u32_t ebx)
* Here we find out whether we should do serial output. * Here we find out whether we should do serial output.
*/ */
get_parameters(ebx, &kinfo); get_parameters(ebx, &kinfo);
/* Say hello. */
printf("MINIX loading\n");
assert(magic == MULTIBOOT_BOOTLOADER_MAGIC); assert(magic == MULTIBOOT_BOOTLOADER_MAGIC);
@ -236,7 +226,7 @@ kinfo_t *pre_init(u32_t magic, u32_t ebx)
* this code stays where it should be. * this code stays where it should be.
*/ */
pg_clear(); pg_clear();
pg_identity(); pg_identity(&kinfo);
kinfo.freepde_start = pg_mapkernel(); kinfo.freepde_start = pg_mapkernel();
pg_load(); pg_load();
vm_enable_paging(); vm_enable_paging();

View file

@ -21,19 +21,13 @@
/* This is OK initially, when the 1:1 mapping is still there. */ /* This is OK initially, when the 1:1 mapping is still there. */
char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER; char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
struct gatedesc_s {
u16_t offset_low;
u16_t selector;
u8_t pad; /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */
u8_t p_dpl_type; /* |P|DL|0|TYPE| */
u16_t offset_high;
} __attribute__((packed));
/* Storage for gdt, idt and tss. */ /* Storage for gdt, idt and tss. */
static struct segdesc_s gdt[GDT_SIZE] __aligned(DESC_SIZE); struct segdesc_s gdt[GDT_SIZE] __aligned(DESC_SIZE);
struct gatedesc_s idt[IDT_SIZE] __aligned(DESC_SIZE); struct gatedesc_s idt[IDT_SIZE] __aligned(DESC_SIZE);
struct tss_s tss[CONFIG_MAX_CPUS]; struct tss_s tss[CONFIG_MAX_CPUS];
int prot_init_done = 0;
phys_bytes vir2phys(void *vir) phys_bytes vir2phys(void *vir)
{ {
extern char _kern_vir_base, _kern_phys_base; /* in kernel.lds */ extern char _kern_vir_base, _kern_phys_base; /* in kernel.lds */
@ -263,12 +257,33 @@ multiboot_module_t *bootmod(int pnr)
panic("boot module %d not found", pnr); panic("boot module %d not found", pnr);
} }
int booting_cpu = 0;
void prot_load_selectors(void)
{
/* this function is called by both prot_init by the BSP and
* the early AP booting code in mpx.S by secondary CPU's.
* everything is set up the same except for the TSS that is per-CPU.
*/
x86_lgdt(&gdt_desc); /* Load gdt */
idt_init();
idt_reload();
x86_lldt(LDT_SELECTOR); /* Load bogus ldt */
x86_ltr(TSS_SELECTOR(booting_cpu));
x86_load_kerncs();
x86_load_ds(KERN_DS_SELECTOR);
x86_load_es(KERN_DS_SELECTOR);
x86_load_fs(KERN_DS_SELECTOR);
x86_load_gs(KERN_DS_SELECTOR);
x86_load_ss(KERN_DS_SELECTOR);
}
/*===========================================================================* /*===========================================================================*
* prot_init * * prot_init *
*===========================================================================*/ *===========================================================================*/
void prot_init() void prot_init()
{ {
int sel_tss;
extern char k_boot_stktop; extern char k_boot_stktop;
memset(gdt, 0, sizeof(gdt)); memset(gdt, 0, sizeof(gdt));
@ -279,7 +294,7 @@ void prot_init()
gdt_desc.limit = sizeof(gdt)-1; gdt_desc.limit = sizeof(gdt)-1;
idt_desc.base = (u32_t) idt; idt_desc.base = (u32_t) idt;
idt_desc.limit = sizeof(idt)-1; idt_desc.limit = sizeof(idt)-1;
sel_tss = tss_init(0, &k_boot_stktop); tss_init(0, &k_boot_stktop);
/* Build GDT */ /* Build GDT */
init_param_dataseg(&gdt[LDT_INDEX], init_param_dataseg(&gdt[LDT_INDEX],
@ -290,22 +305,11 @@ void prot_init()
init_codeseg(USER_CS_INDEX, USER_PRIVILEGE); init_codeseg(USER_CS_INDEX, USER_PRIVILEGE);
init_dataseg(USER_DS_INDEX, USER_PRIVILEGE); init_dataseg(USER_DS_INDEX, USER_PRIVILEGE);
x86_lgdt(&gdt_desc); /* Load gdt */
idt_init();
idt_reload();
x86_lldt(LDT_SELECTOR); /* Load bogus ldt */
x86_ltr(sel_tss); /* Load global TSS */
/* Currently the multiboot segments are loaded; which is fine, but /* Currently the multiboot segments are loaded; which is fine, but
* let's replace them with the ones from our own GDT so we test * let's replace them with the ones from our own GDT so we test
* right away whether they work as expected. * right away whether they work as expected.
*/ */
x86_load_kerncs(); prot_load_selectors();
x86_load_ds(KERN_DS_SELECTOR);
x86_load_es(KERN_DS_SELECTOR);
x86_load_fs(KERN_DS_SELECTOR);
x86_load_gs(KERN_DS_SELECTOR);
x86_load_ss(KERN_DS_SELECTOR);
/* Set up a new post-relocate bootstrap pagetable so that /* Set up a new post-relocate bootstrap pagetable so that
* we can map in VM, and we no longer rely on pre-relocated * we can map in VM, and we no longer rely on pre-relocated
@ -313,10 +317,11 @@ void prot_init()
*/ */
pg_clear(); pg_clear();
pg_identity(); /* Still need 1:1 for lapic and video mem and such. */ pg_identity(&kinfo); /* Still need 1:1 for lapic and video mem and such. */
pg_mapkernel(); pg_mapkernel();
pg_load(); pg_load();
bootstrap_pagetable_done = 1; /* secondary CPU's can use it too */
prot_init_done = 1;
} }
void arch_post_init(void) void arch_post_init(void)

View file

@ -1,4 +1,5 @@
#include <machine/asm.h> #include <machine/asm.h>
#include <machine/vm.h>
#include "archconst.h" #include "archconst.h"
.balign 4096 .balign 4096
@ -6,7 +7,7 @@
.code16 .code16
ENTRY(trampoline) ENTRY(trampoline)
cli cli
/* %cs has some value and we must use the same for data */ /* %cs has some value and we must use the same for data */
mov %cs, %ax mov %cs, %ax
mov %ax, %ds mov %ax, %ds
@ -20,13 +21,38 @@ ENTRY(trampoline)
orb $1, %al orb $1, %al
mov %eax, %cr0 mov %eax, %cr0
/* set page table feature flags: cr4.PSE on, cr4.PGE off */
movl %cr4, %eax
orl $I386_CR4_PSE, %eax /* Turn on PSE */
andl $~I386_CR4_PGE, %eax /* Turn off PGE */
movl %eax, %cr4
/* load boot cr3 and turn PG on so CPU can see all of memory */
movl _C_LABEL(__ap_pt) - _C_LABEL(trampoline), %eax
movl %eax, %cr3
movl %cr0, %ecx
orl $I386_CR0_PG, %ecx
movl %ecx, %cr0
/* turn on cr4.PGE after cr0.PG is on */
movl %cr4, %eax
orl $I386_CR4_PGE, %eax
movl %eax, %cr4
/* jump into regular highly mapped kernel */
ljmpl $KERN_CS_SELECTOR, $_C_LABEL(startup_ap_32) ljmpl $KERN_CS_SELECTOR, $_C_LABEL(startup_ap_32)
.balign 4 .balign 4
LABEL(__ap_id) LABEL(__ap_id)
.space 4 .space 4
LABEL(__ap_pt)
.space 4
LABEL(__ap_gdt) LABEL(__ap_gdt)
.space 8 .space 8
LABEL(__ap_idt) LABEL(__ap_idt)
.space 8 .space 8
LABEL(__ap_gdt_tab)
.space GDT_SIZE*DESC_SIZE
LABEL(__ap_idt_tab)
.space IDT_SIZE*DESC_SIZE
LABEL(__trampoline_end) LABEL(__trampoline_end)

View file

@ -59,11 +59,11 @@ EXTERN u64_t cpu_hz[CONFIG_MAX_CPUS];
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
EXTERN int config_no_smp; /* optionaly turn off SMP */ EXTERN int config_no_smp; /* optionaly turn off SMP */
#endif #endif
EXTERN int bootstrap_pagetable_done;
/* VM */ /* VM */
EXTERN int vm_running; EXTERN int vm_running;
EXTERN int catch_pagefaults; EXTERN int catch_pagefaults;
EXTERN int kernel_may_alloc;
/* Variables that are initialized elsewhere are just extern here. */ /* Variables that are initialized elsewhere are just extern here. */
extern struct boot_image image[NR_BOOT_PROCS]; /* system image processes */ extern struct boot_image image[NR_BOOT_PROCS]; /* system image processes */

View file

@ -107,6 +107,9 @@ void bsp_finish_booting(void)
machine.bsp_id = 0; machine.bsp_id = 0;
#endif #endif
/* Kernel may no longer use bits of memory as VM will be running soon */
kernel_may_alloc = 0;
switch_to_user(); switch_to_user();
NOT_REACHABLE; NOT_REACHABLE;
} }
@ -128,6 +131,9 @@ void kmain(kinfo_t *local_cbi)
/* We can talk now */ /* We can talk now */
printf("MINIX booting\n"); printf("MINIX booting\n");
/* Kernel may use bits of main memory before VM is started */
kernel_may_alloc = 1;
assert(sizeof(kinfo.boot_procs) == sizeof(image)); assert(sizeof(kinfo.boot_procs) == sizeof(image));
memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs)); memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));