SMP - Kernel is loaded above 1M by default

- the 16-bit trampoline must be within the first megabyte of physical
  memory thus the smp trampoline is copied explicitly below 1M
This commit is contained in:
Tomas Hruby 2010-09-15 14:10:00 +00:00
parent 62c666566e
commit a42ab504a0
3 changed files with 60 additions and 6 deletions

View File

@ -31,6 +31,7 @@ _PROTOTYPE(void trampoline, (void));
*/
extern volatile u32_t __ap_id;
extern volatile struct segdesc_s __ap_gdt, __ap_idt;
extern void * __trampoline_end;
extern u32_t busclock[CONFIG_MAX_CPUS];
extern int panicking;
@ -47,6 +48,49 @@ SPINLOCK_DEFINE(dispq_lock)
FORWARD _PROTOTYPE(void smp_init_vars, (void));
FORWARD _PROTOTYPE(void smp_reinit_vars, (void));
/*
* copies the 16-bit AP trampoline code to the first 1M of memory
*/
PRIVATE phys_bytes copy_trampoline(void)
{
char * s, *end;
phys_bytes tramp_base;
unsigned tramp_size;
tramp_size = (unsigned) &__trampoline_end - (unsigned)&trampoline;
s = env_get("memory");
if (!s)
return 0;
while (*s != 0) {
phys_bytes base = 0xfffffff;
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. */
size = strtoul(s, &end, 0x10); /* get number */
if (end != s && *end == ',')
s = ++end; /* skip ',' */
tramp_base = (base + 0xfff) & ~(0xfff);
/* the address must be less than 1M */
if (tramp_base >= (1 << 20))
continue;
if (size - (tramp_base - base) < tramp_size)
continue;
break;
}
phys_copy(vir2phys(trampoline), tramp_base, tramp_size);
return tramp_base;
}
PRIVATE void smp_start_aps(void)
{
/*
@ -54,7 +98,7 @@ PRIVATE void smp_start_aps(void)
*/
unsigned cpu;
u32_t biosresetvector;
phys_bytes trampoline_base = vir2phys(trampoline);
phys_bytes trampoline_base, __ap_id_phys;
/* TODO hack around the alignment problem */
@ -64,13 +108,20 @@ PRIVATE void smp_start_aps(void)
outb(RTC_INDEX, 0xF);
outb(RTC_IO, 0xA);
/* setup the warm reset vector */
phys_copy(vir2phys(&trampoline_base), 0x467, sizeof(u32_t));
/* prepare gdt and idt for the new cpus */
__ap_gdt = gdt[GDT_INDEX];
__ap_idt = gdt[IDT_INDEX];
if (!(trampoline_base = copy_trampoline())) {
printf("Copying trampoline code failed, cannot boot SMP\n");
ncpus = 1;
}
__ap_id_phys = trampoline_base +
(phys_bytes) &__ap_id - (phys_bytes)&trampoline;
/* setup the warm reset vector */
phys_copy(vir2phys(&trampoline_base), 0x467, sizeof(u32_t));
/* okay, we're ready to go. boot all of the ap's now. we loop through
* using the processor's apic id values.
*/
@ -86,6 +137,8 @@ PRIVATE void smp_start_aps(void)
}
__ap_id = cpu;
phys_copy(vir2phys(__ap_id), __ap_id_phys, sizeof(__ap_id));
mfence();
if (apic_send_init_ipi(cpu, trampoline_base) ||
apic_send_startup_ipi(cpu, trampoline_base)) {
printf("WARNING cannot boot cpu %d\n", cpu);
@ -222,7 +275,7 @@ PUBLIC void smp_init (void)
/* set smp idt entries. */
apic_idt_init(0); /* Not a reset ! */
idt_reload();
BOOT_VERBOSE(printf("SMP initialized\n"));
switch_k_stack((char *)get_k_stack_top(bsp_cpu_id) -

View File

@ -29,3 +29,4 @@ LABEL(__ap_gdt)
.space 8
LABEL(__ap_idt)
.space 8
LABEL(__trampoline_end)

View File

@ -123,7 +123,7 @@ PUBLIC void cstart(
* get_value *
*===========================================================================*/
PRIVATE char *get_value(
PUBLIC char *get_value(
const char *params, /* boot monitor parameters */
const char *name /* key to look up */
)