Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3783 → Rev 3798

/branches/sparc/kernel/generic/src/main/main.c
275,7 → 275,7
if (!kinit_thread)
panic("Can't create kinit thread\n");
LOG_EXEC(thread_ready(kinit_thread));
 
/*
* This call to scheduler() will return to kinit,
* starting the thread of kernel threads.
/branches/sparc/kernel/generic/src/proc/scheduler.c
380,7 → 380,7
DEADLOCK_PROBE_INIT(p_joinwq);
 
ASSERT(CPU != NULL);
 
if (THREAD) {
/* must be run after the switch to scheduler stack */
after_thread_ran();
460,7 → 460,7
}
 
THREAD = find_best_thread();
 
spinlock_lock(&THREAD->lock);
priority = THREAD->priority;
spinlock_unlock(&THREAD->lock);
/branches/sparc/kernel/arch/sparc64/include/sun4v/regdef.h
37,7 → 37,17
#define KERN_sparc64_sun4v_REGDEF_H_
 
#define PSTATE_PRIV_BIT (1 << 2)
#define PSTATE_PEF_BIT (1 << 4)
 
#define TSTATE_PSTATE_SHIFT 8
#define TSTATE_PRIV_BIT (PSTATE_PRIV_BIT << TSTATE_PSTATE_SHIFT)
#define TSTATE_CWP_MASK 0x1f
 
#define WSTATE_NORMAL(n) (n)
#define WSTATE_OTHER(n) ((n) << 3)
 
#define TSTATE_PEF_BIT (PSTATE_PEF_BIT << TSTATE_PSTATE_SHIFT)
 
/*
 
#define PSTATE_IE_BIT (1 << 1)
/branches/sparc/kernel/arch/sparc64/include/cpu.h
42,9 → 42,14
#include <arch/register.h>
 
typedef struct {
#if defined (SUN4U)
uint32_t mid; /**< Processor ID as read from
UPA_CONFIG/FIREPLANE_CONFIG. */
ver_reg_t ver;
#elif defined (SUN4V)
uint64_t id; /**< virtual processor ID */
uint32_t mid; // TODO: left here only to keep the code compilable!!!
#endif
uint32_t clock_frequency; /**< Processor frequency in Hz. */
uint64_t next_tick_cmpr; /**< Next clock interrupt should be
generated when the TICK register
/branches/sparc/kernel/arch/sparc64/Makefile.inc
86,11 → 86,13
 
ifeq ($(MACHINE),us)
USARCH = sun4u
DEFS += -DSUN4U
DEFS += -DUS
endif
 
ifeq ($(MACHINE),us3)
USARCH = sun4u
DEFS += -DSUN4U
DEFS += -DUS3
endif
 
/branches/sparc/kernel/arch/sparc64/src/trap/sun4v/trap_table.S
446,35 → 446,85
.align TABLE_SIZE
 
 
#define NOT(x) ((x) == 0)
/*
* Spills the window at CWP + 2 to the kernel stack. This macro is to be
* used before doing SAVE when the spill trap is undesirable.
*/
.macro INLINE_SPILL
! CWP := CWP + 2
rdpr %cwp, %g3
add %g3, 2, %g3
and %g3, NWINDOWS - 1, %g3 ! modulo NWINDOWS
wrpr %g3, %cwp
! spill to kernel stack
stx %l0, [%sp + STACK_BIAS + L0_OFFSET]
stx %l1, [%sp + STACK_BIAS + L1_OFFSET]
stx %l2, [%sp + STACK_BIAS + L2_OFFSET]
stx %l3, [%sp + STACK_BIAS + L3_OFFSET]
stx %l4, [%sp + STACK_BIAS + L4_OFFSET]
stx %l5, [%sp + STACK_BIAS + L5_OFFSET]
stx %l6, [%sp + STACK_BIAS + L6_OFFSET]
stx %l7, [%sp + STACK_BIAS + L7_OFFSET]
stx %i0, [%sp + STACK_BIAS + I0_OFFSET]
stx %i1, [%sp + STACK_BIAS + I1_OFFSET]
stx %i2, [%sp + STACK_BIAS + I2_OFFSET]
stx %i3, [%sp + STACK_BIAS + I3_OFFSET]
stx %i4, [%sp + STACK_BIAS + I4_OFFSET]
stx %i5, [%sp + STACK_BIAS + I5_OFFSET]
stx %i6, [%sp + STACK_BIAS + I6_OFFSET]
stx %i7, [%sp + STACK_BIAS + I7_OFFSET]
 
/* Preemptible trap handler for TL=1.
*
* This trap handler makes arrangements to make calling of scheduler() from
* within a trap context possible. It is called from several other trap
* handlers.
*
* This function can be entered either with interrupt globals or alternate
* globals. Memory management trap handlers are obliged to switch to one of
* those global sets prior to calling this function. Register window management
* functions are not allowed to modify the alternate global registers.
*
* The kernel is designed to work on trap levels 0 - 4. For instance, the
* following can happen:
* TL0: kernel thread runs (CANSAVE=0, kernel stack not in DTLB)
* TL1: preemptible trap handler started after a tick interrupt
* TL2: preemptible trap handler did SAVE
* TL3: spill handler touched the kernel stack
* TL4: hardware or software failure
*
* Input registers:
* %g1 Address of function to call if this is not a syscall.
* %g2 First argument for the function.
* %g6 Pre-set as kernel stack base if trap from userspace.
* %g7 Pre-set as address of the userspace window buffer.
! CWP := CWP - 2
add %g3, NWINDOWS - 2, %g3
and %g3, NWINDOWS - 1, %g3 ! modulo NWINDOWS
wrpr %g3, %cwp
 
saved
.endm
 
/*
* Fill the window at CWP - 1 from the kernel stack. This macro is to be
* used before doing RESTORE when the fill trap is undesirable.
*/
.macro PREEMPTIBLE_HANDLER_TEMPLATE is_syscall
#if 0
.macro INLINE_FILL
! CWP := CWP - 1
rdpr %cwp, %g3
add %g3, NWINDOWS - 1, %g3
and %g3, NWINDOWS - 1, %g3
wrpr %g3, %cwp
 
! fill
ldx [%sp + STACK_BIAS + L0_OFFSET], %l0
ldx [%sp + STACK_BIAS + L1_OFFSET], %l1
ldx [%sp + STACK_BIAS + L2_OFFSET], %l2
ldx [%sp + STACK_BIAS + L3_OFFSET], %l3
ldx [%sp + STACK_BIAS + L4_OFFSET], %l4
ldx [%sp + STACK_BIAS + L5_OFFSET], %l5
ldx [%sp + STACK_BIAS + L6_OFFSET], %l6
ldx [%sp + STACK_BIAS + L7_OFFSET], %l7
ldx [%sp + STACK_BIAS + I0_OFFSET], %i0
ldx [%sp + STACK_BIAS + I1_OFFSET], %i1
ldx [%sp + STACK_BIAS + I2_OFFSET], %i2
ldx [%sp + STACK_BIAS + I3_OFFSET], %i3
ldx [%sp + STACK_BIAS + I4_OFFSET], %i4
ldx [%sp + STACK_BIAS + I5_OFFSET], %i5
ldx [%sp + STACK_BIAS + I6_OFFSET], %i6
ldx [%sp + STACK_BIAS + I7_OFFSET], %i7
 
! CWP := CWP + 1
add %g3, 1, %g3
and %g3, NWINDOWS - 1, %g3
wrpr %g3, %cwp
 
restored
.endm
 
/*
* Preemptible trap handler for handling traps from kernel.
*/
.macro PREEMPTIBLE_HANDLER_KERNEL
 
/*
* ASSERT(%tl == 1)
*/
485,95 → 535,27
0: ba 0b ! this is for debugging, if we ever get here
nop ! it will be easy to find
 
/* prevent unnecessary CLEANWIN exceptions */
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(0), %wstate
1:
.if NOT(\is_syscall)
rdpr %tstate, %g3
/*
* One of the ways this handler can be invoked is after a nested MMU trap from
* either spill_1_normal or fill_1_normal traps. Both of these traps manipulate
* the CWP register. We deal with the situation by simulating the MMU trap
* on TL=1 and restart the respective SAVE or RESTORE instruction once the MMU
* trap is resolved. However, because we are in the wrong window from the
* perspective of the MMU trap, we need to synchronize CWP with CWP from TL=0.
*/
and %g3, TSTATE_CWP_MASK, %g4
wrpr %g4, 0, %cwp ! resynchronize CWP
* Prevent SAVE instruction from causing a spill exception. If the
* CANSAVE register is zero, explicitly spill the current register
* window.
*/
 
andcc %g3, TSTATE_PRIV_BIT, %g0 ! if this trap came from the privileged mode...
bnz 0f ! ...skip setting of kernel stack and primary context
rdpr %cansave, %g3
brnz %g3, 2f
nop
.endif
/*
* Normal window spills will go to the userspace window buffer.
*/
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(2), %wstate
INLINE_SPILL
 
wrpr %g0, NWINDOWS - 1, %cleanwin ! prevent unnecessary clean_window exceptions
 
/*
* Switch to kernel stack. The old stack is
* automatically saved in the old window's %sp
* and the new window's %fp.
*/
save %g6, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp
 
.if \is_syscall
/*
* Copy arguments for the syscall to the new window.
*/
mov %i0, %o0
mov %i1, %o1
mov %i2, %o2
mov %i3, %o3
mov %i4, %o4
mov %i5, %o5
.endif
 
/*
* Mark the CANRESTORE windows as OTHER windows.
*/
rdpr %canrestore, %l0
wrpr %l0, %otherwin
wrpr %g0, %canrestore
 
/*
* Switch to primary context 0.
*/
mov VA_PRIMARY_CONTEXT_REG, %l0
stxa %g0, [%l0] ASI_DMMU
rd %pc, %l0
flush %l0
 
.if NOT(\is_syscall)
ba 1f
nop
0:
2:
/* ask for new register window */
save %sp, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp
 
/*
* At this moment, we are using the kernel stack
* and have successfully allocated a register window.
*/
1:
.endif
/*
* Other window spills will go to the userspace window buffer
* and normal spills will go to the kernel stack.
*/
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(0), %wstate
/*
* Copy arguments.
*/
/* copy higher level routine's address and its argument */
mov %g1, %l0
.if NOT(\is_syscall)
mov %g2, %o0
.else
! store the syscall number on the stack as 7th argument
stx %g2, [%sp + STACK_WINDOW_SAVE_AREA_SIZE + STACK_BIAS + STACK_ARG6]
.endif
 
/*
* Save TSTATE, TPC and TNPC aside.
581,7 → 563,6
rdpr %tstate, %g1
rdpr %tpc, %g2
rdpr %tnpc, %g3
rd %y, %g4
 
stx %g1, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TSTATE]
stx %g2, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TPC]
594,89 → 575,62
* versions of the SPARC architecture.
* Surprisingly, gcc makes use of this register without a notice.
*/
rd %y, %g4
stx %g4, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_Y]
 
/* switch to TL = 0, explicitly enable FPU */
wrpr %g0, 0, %tl
wrpr %g0, PSTATE_PRIV_BIT | PSTATE_PEF_BIT, %pstate
 
/* g1 -> l1, ..., g7 -> l7 */
SAVE_GLOBALS
.if NOT(\is_syscall)
/*
* Call the higher-level handler and pass istate as second parameter.
*/
 
/* call higher-level service routine, pass istate as its 2nd parameter */
call %l0
add %sp, PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC, %o1
.else
/*
* Call the higher-level syscall handler.
*/
call syscall_handler
nop
mov %o0, %i0 ! copy the value returned by the syscall
.endif
 
/* l1 -> g1, ..., l7 -> g7 */
RESTORE_GLOBALS
rdpr %pstate, %l1 ! we must preserve the PEF bit
wrpr %g0, PSTATE_AG_BIT | PSTATE_PRIV_BIT, %pstate
 
/* we must prserve the PEF bit */
rdpr %pstate, %l1
 
/* TL := 1, GL := 1 */
wrpr %g0, PSTATE_PRIV_BIT, %pstate
wrpr %g0, 1, %tl
/*
* Read TSTATE, TPC and TNPC from saved copy.
*/
wrpr %g0, 1, %gl
 
/* Read TSTATE, TPC and TNPC from saved copy. */
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TSTATE], %g1
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TPC], %g2
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC], %g3
 
/*
* Copy PSTATE.PEF to the in-register copy of TSTATE.
*/
/* Copy PSTATE.PEF to the in-register copy of TSTATE. */
and %l1, PSTATE_PEF_BIT, %l1
sllx %l1, TSTATE_PSTATE_SHIFT, %l1
sethi %hi(TSTATE_PEF_BIT), %g4
sethi %hi(TSTATE_PEF_BIT), %g4 ! reset the PEF bit to 0 ...
andn %g1, %g4, %g1
or %g1, %l1, %g1
or %g1, %l1, %g1 ! ... "or" it with saved PEF
 
/*
* Restore TSTATE, TPC and TNPC from saved copies.
*/
/* Restore TSTATE, TPC and TNPC from saved copies. */
wrpr %g1, 0, %tstate
wrpr %g2, 0, %tpc
wrpr %g3, 0, %tnpc
 
/*
* Restore Y.
*/
/* Restore Y. */
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_Y], %g4
wr %g4, %y
 
/*
* If OTHERWIN is zero, then all the userspace windows have been
* spilled to kernel memory (i.e. register window buffer). Moreover,
* if the scheduler was called in the meantime, all valid windows
* belonging to other threads were spilled by context_restore().
* If OTHERWIN is non-zero, then some userspace windows are still
* valid. Others might have been spilled. However, the CWP pointer
* needs no fixing because the scheduler had not been called.
*/
rdpr %otherwin, %l0
brnz %l0, 0f
nop
 
/*
* OTHERWIN == 0
*/
 
/*
* If TSTATE.CWP + 1 == CWP, then we still do not have to fix CWP.
*/
/* If TSTATE.CWP + 1 == CWP, then we do not have to fix CWP. */
and %g1, TSTATE_CWP_MASK, %l0
inc %l0
and %l0, NWINDOWS - 1, %l0 ! %l0 mod NWINDOWS
rdpr %cwp, %l1
cmp %l0, %l1
bz 0f ! CWP is ok
bz 4f ! CWP is ok
nop
 
3:
/*
* Fix CWP.
* In order to recapitulate, the input registers in the current
705,144 → 659,34
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I6], %i6
ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I7], %i7
 
4:
/*
* OTHERWIN != 0 or fall-through from the OTHERWIN == 0 case.
* The CWP has already been restored to the value it had after the SAVE
* at the beginning of this function.
* Prevent RESTORE instruction from causing a spill exception. If the
* CANRESTORE register is zero, explicitly spill the current register
* window.
*/
0:
.if NOT(\is_syscall)
rdpr %tstate, %g1
andcc %g1, TSTATE_PRIV_BIT, %g0 ! if we are not returning to userspace...,
bnz 1f ! ...skip restoring userspace windows
rdpr %canrestore, %g1
brnz %g1, 5f
nop
.endif
INLINE_FILL
 
/*
* Spills and fills will be processed by the {spill,fill}_1_normal
* handlers.
*/
wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(1), %wstate
 
/*
* Set primary context according to secondary context.
*/
wr %g0, ASI_DMMU, %asi
ldxa [VA_SECONDARY_CONTEXT_REG] %asi, %g1
stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi
rd %pc, %g1
flush %g1
rdpr %cwp, %g1
rdpr %otherwin, %g2
 
/*
* Skip all OTHERWIN windows and descend to the first window
* in the userspace window buffer.
*/
sub %g1, %g2, %g3
dec %g3
and %g3, NWINDOWS - 1, %g3
wrpr %g3, 0, %cwp
 
/*
* CWP is now in the window last saved in the userspace window buffer.
* Fill all windows stored in the buffer.
*/
clr %g4
0: andcc %g7, UWB_ALIGNMENT - 1, %g0 ! alignment check
bz 0f ! %g7 is UWB_ALIGNMENT-aligned, no more windows to refill
nop
 
add %g7, -STACK_WINDOW_SAVE_AREA_SIZE, %g7
ldx [%g7 + L0_OFFSET], %l0
ldx [%g7 + L1_OFFSET], %l1
ldx [%g7 + L2_OFFSET], %l2
ldx [%g7 + L3_OFFSET], %l3
ldx [%g7 + L4_OFFSET], %l4
ldx [%g7 + L5_OFFSET], %l5
ldx [%g7 + L6_OFFSET], %l6
ldx [%g7 + L7_OFFSET], %l7
ldx [%g7 + I0_OFFSET], %i0
ldx [%g7 + I1_OFFSET], %i1
ldx [%g7 + I2_OFFSET], %i2
ldx [%g7 + I3_OFFSET], %i3
ldx [%g7 + I4_OFFSET], %i4
ldx [%g7 + I5_OFFSET], %i5
ldx [%g7 + I6_OFFSET], %i6
ldx [%g7 + I7_OFFSET], %i7
 
dec %g3
and %g3, NWINDOWS - 1, %g3
wrpr %g3, 0, %cwp ! switch to the preceeding window
 
ba 0b
inc %g4
 
0:
/*
* Switch back to the proper current window and adjust
* OTHERWIN, CANRESTORE, CANSAVE and CLEANWIN.
*/
wrpr %g1, 0, %cwp
add %g4, %g2, %g2
cmp %g2, NWINDOWS - 2
bg 2f ! fix the CANRESTORE=NWINDOWS-1 anomaly
mov NWINDOWS - 2, %g1 ! use dealy slot for both cases
sub %g1, %g2, %g1
wrpr %g0, 0, %otherwin
wrpr %g1, 0, %cansave ! NWINDOWS - 2 - CANRESTORE
wrpr %g2, 0, %canrestore ! OTHERWIN + windows in the buffer
wrpr %g2, 0, %cleanwin ! avoid information leak
 
1:
5:
restore
 
.if \is_syscall
done
.else
retry
.endif
.endm
 
/*
* We got here in order to avoid inconsistency of the window state registers.
* If the:
*
* save %g6, -PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE, %sp
*
* instruction trapped and spilled a register window into the userspace
* window buffer, we have just restored NWINDOWS - 1 register windows.
* However, CANRESTORE can be only NWINDOW - 2 at most.
*
* The solution is to manually switch to (CWP - 1) mod NWINDOWS
* and set the window state registers so that:
*
* CANRESTORE = NWINDOWS - 2
* CLEANWIN = NWINDOWS - 2
* CANSAVE = 0
* OTHERWIN = 0
*
* The RESTORE instruction is therfore to be skipped.
*/
2:
wrpr %g0, 0, %otherwin
wrpr %g0, 0, %cansave
wrpr %g1, 0, %canrestore
wrpr %g1, 0, %cleanwin
 
rdpr %cwp, %g1
dec %g1
and %g1, NWINDOWS - 1, %g1
wrpr %g1, 0, %cwp ! CWP--
.if \is_syscall
done
.else
retry
.endif
#define NOT(x) ((x) == 0)
 
#endif
/* Preemptible trap handler for TL=1.
*
* This trap handler makes arrangements to make calling of scheduler() from
* within a trap context possible. It is called from several other trap
* handlers.
*/
.macro PREEMPTIBLE_HANDLER_TEMPLATE is_syscall
PREEMPTIBLE_HANDLER_KERNEL
.endm
 
.global preemptible_handler
/branches/sparc/kernel/arch/sparc64/src/cpu/sun4v/cpu.c
51,6 → 51,8
uint64_t myid;
__hypercall_fast_ret1(0, 0, 0, 0, 0, CPU_MYID, &myid);
 
CPU->arch.id = myid;
 
md_node_t node = md_get_root();
 
/* walk through MD, find the current CPU node & its clock-frequency */
91,9 → 93,8
*/
void cpu_print_report(cpu_t *m)
{
// TODO: modify cpu_t so that it contains a pointer to the MD of
// the represented CPU, from this function print the information found in the MD.
printf("Niagara, 5MHz\n");
printf("cpu%d: Niagara (%d MHz)\n", m->id,
m->arch.clock_frequency / 1000000);
}
 
/** @}