Update comments about _start, the kernel entry point, to reflect new

parameters needed for smp support.
If we are not the boot processor, jump to the smp startup code instead.
Implement a per-cpu panic stack, which is used for bootstrapping both
primary and secondary processors and during faults on the kernel stack.
Arrange the per-cpu page like the pcb, with the struct pcpu at the end
of the page and the panic stack before it.
Use the boot processor's panic stack for calling sparc64_init.
Split the code to set preloaded global registers and to map the kernel
tsb out into functions, which non-boot processors can call.
Allocate the kstack for thread0 dynamically in pmap_bootstrap, and give
it a guard page too.
This commit is contained in:
jake 2002-01-08 05:02:13 +00:00
parent 9424335541
commit 712c074db3
4 changed files with 321 additions and 101 deletions

View File

@ -28,8 +28,10 @@
#include <sys/syscall.h>
#include <machine/asi.h>
#include <machine/asmacros.h>
#include <machine/pstate.h>
#include <machine/upa.h>
#include "assym.s"
@ -39,30 +41,144 @@
.set kernbase,KERNBASE
/*
* void _start(caddr_t metadata, u_long o1, u_long o2, u_long o3,
* void _start(caddr_t metadata, u_int *state, u_int mid, u_int bootmid,
* u_long ofw_vec)
*
* XXX: in am smp system the other cpus are started in the loader, but since
* there's no way to look up a symbol there, we need to use the same entry
* point. So if the module id is not equal to bootcpu, jump to _mp_start.
*/
ENTRY(_start)
wrpr %g0, PSTATE_IE | PSTATE_PRIV | PSTATE_PEF, %pstate
mov %o0, %g1
mov %o4, %g2
/*
* Initialize misc state to known values. Interrupts disabled, normal
* globals, windows flushed (cr = 0, cs = nwindows - 1), no clean
* windows, pil 0, and floating point disabled.
*/
wrpr %g0, PSTATE_NORMAL, %pstate
flushw
wrpr %g0, 1, %cwp
wrpr %g0, 0, %cleanwin
wrpr %g0, 0, %pil
wr %g0, 0, %fprs
SET(kstack0 + KSTACK_PAGES * PAGE_SIZE - PCB_SIZEOF, %l0, %o0)
sub %o0, SPOFF + CCFSZ, %sp
#ifdef SMP
/*
* If we're not the boot processor, go do other stuff.
*/
cmp %o2, %o3
be %xcc, 1f
nop
call _mp_start
nop
sir
1:
#endif
mov %g1, %o0
/*
* Get onto our per-cpu panic stack, which precedes the struct pcpu in
* the per-cpu page.
*/
SET(pcpu0 + PAGE_SIZE - PC_SIZEOF, %l1, %l0)
sub %l0, SPOFF + CCFSZ, %sp
/*
* Enable interrupts.
*/
wrpr %g0, PSTATE_KERNEL, %pstate
/*
* Do initial bootstrap to setup pmap and thread0.
*/
call sparc64_init
mov %g2, %o1
nop
/*
* Get onto thread0's kstack.
*/
sub PCB_REG, SPOFF + CCFSZ, %sp
/*
* And away we go. This doesn't return.
*/
call mi_startup
nop
sir
! NOTREACHED
END(_start)
/*
* void cpu_setregs(struct pcpu *pc)
*/
ENTRY(cpu_setregs)
ldx [%o0 + PC_CURTHREAD], %o1
ldx [%o1 + TD_PCB], %o1
/*
* Disable interrupts, normal globals.
*/
wrpr %g0, PSTATE_NORMAL, %pstate
/*
* Normal %g6 points to the current thread's pcb, and %g7 points to
* the per-cpu data structure.
*/
mov %o1, PCB_REG
mov %o0, PCPU_REG
/*
* Alternate globals.
*/
wrpr %g0, PSTATE_ALT, %pstate
/*
* Alternate %g5 points to a per-cpu panic stack, %g6 points to the
* current thread's pcb, and %g7 points to the per-cpu data structure.
*/
mov %o0, ASP_REG
mov %o1, PCB_REG
mov %o0, PCPU_REG
/*
* Interrupt globals.
*/
wrpr %g0, PSTATE_INTR, %pstate
/*
* Interrupt %g7 points to the per-cpu data structure.
*/
mov %o0, PCPU_REG
/*
* MMU globals.
*/
wrpr %g0, PSTATE_MMU, %pstate
/*
* MMU %g7 points to the user tsb. Initialize it to something sane
* here to catch invalid use.
*/
mov %g0, TSB_REG
/*
* Normal globals again.
*/
wrpr %g0, PSTATE_NORMAL, %pstate
/*
* Force trap level 1 and take over the trap table.
*/
SET(tl0_base, %o2, %o1)
wrpr %g0, 1, %tl
wrpr %o1, 0, %tba
/*
* Re-enable interrupts.
*/
wrpr %g0, PSTATE_KERNEL, %pstate
retl
nop
END(cpu_setregs)
/*
* Signal trampoline, copied out to user stack. Must be 16 byte aligned or
* the argv and envp pointers can become misaligned.

View File

@ -28,8 +28,10 @@
#include <sys/syscall.h>
#include <machine/asi.h>
#include <machine/asmacros.h>
#include <machine/pstate.h>
#include <machine/upa.h>
#include "assym.s"
@ -39,30 +41,144 @@
.set kernbase,KERNBASE
/*
* void _start(caddr_t metadata, u_long o1, u_long o2, u_long o3,
* void _start(caddr_t metadata, u_int *state, u_int mid, u_int bootmid,
* u_long ofw_vec)
*
* XXX: in am smp system the other cpus are started in the loader, but since
* there's no way to look up a symbol there, we need to use the same entry
* point. So if the module id is not equal to bootcpu, jump to _mp_start.
*/
ENTRY(_start)
wrpr %g0, PSTATE_IE | PSTATE_PRIV | PSTATE_PEF, %pstate
mov %o0, %g1
mov %o4, %g2
/*
* Initialize misc state to known values. Interrupts disabled, normal
* globals, windows flushed (cr = 0, cs = nwindows - 1), no clean
* windows, pil 0, and floating point disabled.
*/
wrpr %g0, PSTATE_NORMAL, %pstate
flushw
wrpr %g0, 1, %cwp
wrpr %g0, 0, %cleanwin
wrpr %g0, 0, %pil
wr %g0, 0, %fprs
SET(kstack0 + KSTACK_PAGES * PAGE_SIZE - PCB_SIZEOF, %l0, %o0)
sub %o0, SPOFF + CCFSZ, %sp
#ifdef SMP
/*
* If we're not the boot processor, go do other stuff.
*/
cmp %o2, %o3
be %xcc, 1f
nop
call _mp_start
nop
sir
1:
#endif
mov %g1, %o0
/*
* Get onto our per-cpu panic stack, which precedes the struct pcpu in
* the per-cpu page.
*/
SET(pcpu0 + PAGE_SIZE - PC_SIZEOF, %l1, %l0)
sub %l0, SPOFF + CCFSZ, %sp
/*
* Enable interrupts.
*/
wrpr %g0, PSTATE_KERNEL, %pstate
/*
* Do initial bootstrap to setup pmap and thread0.
*/
call sparc64_init
mov %g2, %o1
nop
/*
* Get onto thread0's kstack.
*/
sub PCB_REG, SPOFF + CCFSZ, %sp
/*
* And away we go. This doesn't return.
*/
call mi_startup
nop
sir
! NOTREACHED
END(_start)
/*
* void cpu_setregs(struct pcpu *pc)
*/
ENTRY(cpu_setregs)
ldx [%o0 + PC_CURTHREAD], %o1
ldx [%o1 + TD_PCB], %o1
/*
* Disable interrupts, normal globals.
*/
wrpr %g0, PSTATE_NORMAL, %pstate
/*
* Normal %g6 points to the current thread's pcb, and %g7 points to
* the per-cpu data structure.
*/
mov %o1, PCB_REG
mov %o0, PCPU_REG
/*
* Alternate globals.
*/
wrpr %g0, PSTATE_ALT, %pstate
/*
* Alternate %g5 points to a per-cpu panic stack, %g6 points to the
* current thread's pcb, and %g7 points to the per-cpu data structure.
*/
mov %o0, ASP_REG
mov %o1, PCB_REG
mov %o0, PCPU_REG
/*
* Interrupt globals.
*/
wrpr %g0, PSTATE_INTR, %pstate
/*
* Interrupt %g7 points to the per-cpu data structure.
*/
mov %o0, PCPU_REG
/*
* MMU globals.
*/
wrpr %g0, PSTATE_MMU, %pstate
/*
* MMU %g7 points to the user tsb. Initialize it to something sane
* here to catch invalid use.
*/
mov %g0, TSB_REG
/*
* Normal globals again.
*/
wrpr %g0, PSTATE_NORMAL, %pstate
/*
* Force trap level 1 and take over the trap table.
*/
SET(tl0_base, %o2, %o1)
wrpr %g0, 1, %tl
wrpr %o1, 0, %tba
/*
* Re-enable interrupts.
*/
wrpr %g0, PSTATE_KERNEL, %pstate
retl
nop
END(cpu_setregs)
/*
* Signal trampoline, copied out to user stack. Must be 16 byte aligned or
* the argv and envp pointers can become misaligned.

View File

@ -106,33 +106,20 @@
typedef int ofw_vec_t(void *);
extern char tl0_base[];
extern char _end[];
int physmem;
int cold = 1;
long dumplo;
int Maxmem;
u_long debug_mask;
struct mtx Giant;
struct mtx sched_lock;
static struct pcpu __pcpu;
/*
* This needs not be aligned as the other user areas, provided that process 0
* does not have an fp state (which it doesn't normally).
* This constraint is only here for debugging.
*/
char kstack0[KSTACK_PAGES * PAGE_SIZE] __attribute__((aligned(64)));
static char uarea0[UAREA_PAGES * PAGE_SIZE] __attribute__((aligned(64)));
static struct trapframe frame0;
struct user *proc0uarea;
vm_offset_t proc0kstack;
char pcpu0[PAGE_SIZE];
char uarea0[UAREA_PAGES * PAGE_SIZE];
struct trapframe frame0;
char panic_stack[PANIC_STACK_PAGES * PAGE_SIZE];
vm_offset_t kstack0;
vm_offset_t kstack0_phys;
struct kva_md_info kmi;
@ -142,12 +129,15 @@ u_long ofw_tba;
static struct timecounter tick_tc;
static timecounter_get_t tick_get_timecount;
void sparc64_init(caddr_t mdp, ofw_vec_t *vec);
void sparc64_init(caddr_t mdp, u_int *state, u_int mid, u_int bootmid,
ofw_vec_t *vec);
void sparc64_shutdown_final(void *dummy, int howto);
static void cpu_startup(void *);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
CTASSERT(sizeof(struct pcpu) <= (PAGE_SIZE / 2));
static void
cpu_startup(void *arg)
{
@ -199,12 +189,13 @@ tick_get_timecount(struct timecounter *tc)
}
void
sparc64_init(caddr_t mdp, ofw_vec_t *vec)
sparc64_init(caddr_t mdp, u_int *state, u_int mid, u_int bootmid,
ofw_vec_t *vec)
{
struct pcpu *pc;
vm_offset_t end;
vm_offset_t off;
caddr_t kmdp;
u_long ps;
end = 0;
kmdp = NULL;
@ -276,20 +267,20 @@ sparc64_init(caddr_t mdp, ofw_vec_t *vec)
*/
tick_stop();
/* Initialize the interrupt tables. */
/*
* Initialize the interrupt tables.
*/
intr_init();
proc_linkup(&proc0);
/*
* Initialize proc0 stuff (p_contested needs to be done early).
*/
proc0uarea = (struct user *)uarea0;
proc0kstack = (vm_offset_t)kstack0;
proc_linkup(&proc0);
proc0.p_md.md_utrap = NULL;
proc0.p_uarea = proc0uarea;
proc0.p_uarea = (struct user *)uarea0;
proc0.p_stats = &proc0.p_uarea->u_stats;
thread0 = &proc0.p_thread;
thread0->td_kstack = proc0kstack;
thread0->td_kstack = kstack0;
thread0->td_pcb = (struct pcb *)
(thread0->td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
frame0.tf_tstate = TSTATE_IE | TSTATE_PEF;
@ -297,46 +288,20 @@ sparc64_init(caddr_t mdp, ofw_vec_t *vec)
LIST_INIT(&thread0->td_contested);
/*
* Force trap level 1 and take over the trap table.
* Prime our per-cpu data page for use. Note, we are using it for our
* stack, so don't pass the real size (PAGE_SIZE) to pcpu_init or
* it'll zero it out from under us.
*/
ps = rdpr(pstate);
wrpr(pstate, ps, PSTATE_IE);
wrpr(tl, 0, 1);
wrpr(tba, tl0_base, 0);
pc = (struct pcpu *)(pcpu0 + PAGE_SIZE) - 1;
pcpu_init(pc, 0, sizeof(struct pcpu));
pc->pc_curthread = thread0;
pc->pc_curpcb = thread0->td_pcb;
pc->pc_mid = mid;
/*
* Setup preloaded globals.
* Normal %g7 points to the per-cpu data structure.
* Initialize global registers.
*/
__asm __volatile("mov %0, %%g7" : : "r" (&__pcpu));
/*
* Alternate %g5 points to a per-cpu stack for saving alternate
* globals, %g6 points to the current thread's pcb, and %g7 points
* to the per-cpu data structure.
*/
wrpr(pstate, ps, PSTATE_AG | PSTATE_IE);
__asm __volatile("mov %0, %%g5" : : "r"
(&__pcpu.pc_alt_stack[ALT_STACK_SIZE - 1]));
__asm __volatile("mov %0, %%g6" : : "r" (thread0->td_pcb));
__asm __volatile("mov %0, %%g7" : : "r" (&__pcpu));
/*
* Interrupt %g6 points to a per-cpu interrupt queue, %g7 points to
* the interrupt vector table.
*/
wrpr(pstate, ps, PSTATE_IG | PSTATE_IE);
__asm __volatile("mov %0, %%g6" : : "r" (&__pcpu.pc_iq));
__asm __volatile("mov %0, %%g7" : : "r" (&intr_vectors));
/*
* MMU %g7 points to the user tsb. Initialize it to something sane
* here to catch invalid use.
*/
wrpr(pstate, ps, PSTATE_MG | PSTATE_IE);
__asm __volatile("mov %%g0, %%g7" : :);
wrpr(pstate, ps, 0);
cpu_setregs(pc);
/*
* Map and initialize the message buffer (after setting trap table).
@ -345,13 +310,6 @@ sparc64_init(caddr_t mdp, ofw_vec_t *vec)
pmap_kenter((vm_offset_t)msgbufp + off, msgbuf_phys + off);
msgbufinit(msgbufp, MSGBUF_SIZE);
/*
* Initialize curthread so that mutexes work.
*/
pcpu_init(pcpup, 0, sizeof(struct pcpu));
PCPU_SET(curthread, thread0);
PCPU_SET(curpcb, thread0->td_pcb);
/*
* Initialize mutexes.
*/

View File

@ -308,23 +308,23 @@ pmap_bootstrap(vm_offset_t ekva)
tsb_kernel_phys = pa;
tsb_kernel = (struct tte *)virtual_avail;
virtual_avail += KVA_PAGES * PAGE_SIZE_4M;
for (i = 0; i < KVA_PAGES; i++) {
va = (vm_offset_t)tsb_kernel + i * PAGE_SIZE_4M;
tte.tte_tag = TT_CTX(TLB_CTX_KERNEL) | TT_VA(va);
tte.tte_data = TD_V | TD_4M | TD_VA_LOW(va) | TD_PA(pa) |
TD_L | TD_CP | TD_CV | TD_P | TD_W;
tlb_store_slot(TLB_DTLB, va, TLB_CTX_KERNEL, tte,
TLB_SLOT_TSB_KERNEL_MIN + i);
}
pmap_map_tsb();
bzero(tsb_kernel, KVA_PAGES * PAGE_SIZE_4M);
/*
* Load the tsb registers.
* Allocate a kernel stack with guard page for thread0 and map it into
* the kernel tsb.
*/
stxa(AA_DMMU_TSB, ASI_DMMU, (vm_offset_t)tsb_kernel);
stxa(AA_IMMU_TSB, ASI_IMMU, (vm_offset_t)tsb_kernel);
membar(Sync);
flush(tsb_kernel);
pa = pmap_bootstrap_alloc(KSTACK_PAGES * PAGE_SIZE);
kstack0_phys = pa;
kstack0 = virtual_avail + (KSTACK_GUARD_PAGES * PAGE_SIZE);
virtual_avail += (KSTACK_PAGES + KSTACK_GUARD_PAGES) * PAGE_SIZE;
for (i = 0; i < KSTACK_PAGES; i++) {
pa = kstack0_phys + i * PAGE_SIZE;
va = kstack0 + i * PAGE_SIZE;
pmap_kenter(va, pa);
tlb_page_demap(TLB_DTLB, TLB_CTX_KERNEL, va);
}
/*
* Allocate the message buffer.
@ -399,6 +399,36 @@ pmap_bootstrap(vm_offset_t ekva)
pm->pm_active = ~0;
pm->pm_count = 1;
TAILQ_INIT(&pm->pm_pvlist);
}
void
pmap_map_tsb(void)
{
struct tte tte;
vm_offset_t va;
vm_offset_t pa;
int i;
/*
* Map the 4mb tsb pages.
*/
for (i = 0; i < KVA_PAGES; i++) {
va = (vm_offset_t)tsb_kernel + i * PAGE_SIZE_4M;
pa = tsb_kernel_phys + i * PAGE_SIZE_4M;
tte.tte_tag = TT_CTX(TLB_CTX_KERNEL) | TT_VA(va);
tte.tte_data = TD_V | TD_4M | TD_VA_LOW(va) | TD_PA(pa) |
TD_L | TD_CP | TD_CV | TD_P | TD_W;
tlb_store_slot(TLB_DTLB, va, TLB_CTX_KERNEL, tte,
TLB_SLOT_TSB_KERNEL_MIN + i);
}
/*
* Load the tsb registers.
*/
stxa(AA_DMMU_TSB, ASI_DMMU, (vm_offset_t)tsb_kernel);
stxa(AA_IMMU_TSB, ASI_IMMU, (vm_offset_t)tsb_kernel);
membar(Sync);
flush(tsb_kernel);
/*
* Set the secondary context to be the kernel context (needed for