mirror of https://github.com/dzavalishin/oskit/
201 lines
5.5 KiB
C
201 lines
5.5 KiB
C
|
/*
|
||
|
* Copyright (c) 1996, 1998, 1999 University of Utah and the Flux Group.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This file is part of the Flux OSKit. The OSKit is free software, also known
|
||
|
* as "open source;" you can redistribute it and/or modify it under the terms
|
||
|
* of the GNU General Public License (GPL), version 2, as published by the Free
|
||
|
* Software Foundation (FSF). To explore alternate licensing terms, contact
|
||
|
* the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
|
||
|
*
|
||
|
* The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
|
||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||
|
* FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
|
||
|
* received a copy of the GPL along with the OSKit; see the file COPYING. If
|
||
|
* not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Machine dependent thread initialization.
|
||
|
*/
|
||
|
#include <threads/pthread_internal.h>
|
||
|
#include <oskit/c/sys/mman.h>
|
||
|
#include <oskit/machine/trap.h>
|
||
|
#include <oskit/machine/base_trap.h>
|
||
|
#include <oskit/machine/proc_reg.h>
|
||
|
|
||
|
/*
|
||
|
* Pointer to fpustate for the thread that last used the FP unit. This
|
||
|
* points into a PCB structure, and starts out pointing at the main
|
||
|
* thread. At each context switch the TS flag is set. An attempt to
|
||
|
* use the FPU will cause an NM exception. The current state of the
|
||
|
* FPU will be saved into *cur_fpustate, cur_fpustate reset to point
|
||
|
* at the current thread PCB, and an FP reload done. The TS flag is
|
||
|
* cleared so that the FP operation can continue.
|
||
|
*/
|
||
|
pthread_thread_t *owner_fpu;
|
||
|
extern pthread_thread_t threads_mainthread;
|
||
|
extern int pthread_fpu_trap_handler(struct trap_state *ts);
|
||
|
extern int oskit_usermode_simulation;
|
||
|
extern void thread_switch_usermode(), thread_switch_realmode();
|
||
|
void (*thread_switch)(pthread_thread_t *pnext,
|
||
|
pthread_lock_t *l, pthread_thread_t *cur) = 0;
|
||
|
void (*oskit_vm_switch)(pthread_t);
|
||
|
|
||
|
/*
|
||
|
* Machine dependent pthread system initialization.
|
||
|
*/
|
||
|
void
|
||
|
thread_machdep_init()
|
||
|
{
|
||
|
if (! oskit_usermode_simulation) {
|
||
|
#ifndef SMP
|
||
|
/*
|
||
|
* Override NM trap handler.
|
||
|
*/
|
||
|
base_trap_handlers[T_NO_FPU] = pthread_fpu_trap_handler;
|
||
|
|
||
|
owner_fpu = &threads_mainthread;
|
||
|
#endif
|
||
|
thread_switch = thread_switch_realmode;
|
||
|
}
|
||
|
else {
|
||
|
thread_switch = thread_switch_usermode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Set up an initial stack that looks like:
|
||
|
*
|
||
|
* ------------
|
||
|
* | Pthread |
|
||
|
* ------------
|
||
|
* | Panic RA |
|
||
|
* ------------
|
||
|
* | Starter |
|
||
|
* ------------ <--- SP
|
||
|
*
|
||
|
* The starter routine takes the new pthread as its argument. It does
|
||
|
* some intitialization stuff, and then applies the user specified start
|
||
|
* function(argument). Set up a panic just in case something goes wrong
|
||
|
* and the threads unwinds too far.
|
||
|
*/
|
||
|
extern void pthread_start_thread(void);
|
||
|
extern void thread_fpuinit(oskit_u32_t *, oskit_u32_t *);
|
||
|
|
||
|
void
|
||
|
thread_setup(pthread_thread_t *pthread)
|
||
|
{
|
||
|
pcb_t *ppcb = pthread->ppcb;
|
||
|
oskit_u32_t *pframe;
|
||
|
void thread_bottom_exit();
|
||
|
oskit_u32_t fstate[32];
|
||
|
|
||
|
#ifdef STACKGUARD
|
||
|
if (pthread->guardsize)
|
||
|
pthread_mprotect((oskit_addr_t) pthread->pstk,
|
||
|
pthread->guardsize, PROT_READ);
|
||
|
#endif
|
||
|
/*
|
||
|
* The initial frame starts at the other end of the stack
|
||
|
* memory.
|
||
|
*/
|
||
|
pframe = (oskit_u32_t *) (((oskit_u32_t) pthread->pstk) +
|
||
|
pthread->ssize);
|
||
|
pframe -= 3;
|
||
|
pframe[0] = (oskit_u32_t) pthread_start_thread;
|
||
|
pframe[1] = (oskit_u32_t) thread_bottom_exit;
|
||
|
pframe[2] = (oskit_u32_t) pthread;
|
||
|
|
||
|
/*
|
||
|
* Setting the EIP would seem redundant, but the context switch
|
||
|
* code is going to use it instead of the location on the stack.
|
||
|
*/
|
||
|
ppcb->esp = (oskit_u32_t) pframe;
|
||
|
ppcb->eip = (oskit_u32_t) pthread_start_thread;
|
||
|
|
||
|
/*
|
||
|
* Set up the current floating point state. Done in asm code.
|
||
|
*/
|
||
|
thread_fpuinit(fstate, pthread->pcb.fstate);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Machine dependent thread destroy.
|
||
|
*/
|
||
|
void
|
||
|
thread_destroy(pthread_thread_t *pthread)
|
||
|
{
|
||
|
#ifdef STACKGUARD
|
||
|
if (pthread->guardsize)
|
||
|
pthread_mprotect((oskit_addr_t) pthread->pstk,
|
||
|
pthread->guardsize, PROT_READ|PROT_WRITE);
|
||
|
#endif
|
||
|
if (owner_fpu == pthread)
|
||
|
owner_fpu = &threads_mainthread;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
thread_bottom_exit()
|
||
|
{
|
||
|
panic("thread_bottom_exit:");
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Dump a stack backtrace for a switched out thread.
|
||
|
*/
|
||
|
int
|
||
|
threads_stack_back_trace(int tid, int max_st_levels)
|
||
|
{
|
||
|
unsigned int *fp, i;
|
||
|
pthread_thread_t *pthread;
|
||
|
|
||
|
if ((pthread = tidtothread((pthread_t) tid)) == NULL_THREADPTR)
|
||
|
return EINVAL;
|
||
|
|
||
|
if (pthread == CURPTHREAD())
|
||
|
return EINVAL;
|
||
|
|
||
|
fp = (unsigned int *) pthread->pcb.ebp;
|
||
|
|
||
|
printf("Backtrace tid:%d P:%08x: eip:0x%08x fp:0x%08x\n\t", tid,
|
||
|
(int) pthread, (int) pthread->pcb.eip, (int) fp);
|
||
|
|
||
|
/* Switch the vmspace */
|
||
|
if (oskit_vm_switch) {
|
||
|
(*oskit_vm_switch)((pthread_t)tid);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < max_st_levels && fp != NULL; i++) {
|
||
|
if (!(*(fp + 1) && *fp))
|
||
|
break;
|
||
|
|
||
|
printf(" %08x", *(fp + 1));
|
||
|
|
||
|
fp = (int *)(*fp);
|
||
|
}
|
||
|
printf("\n");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Get machine-specific thread state and stash into the given pointer.
|
||
|
* This is used by pthread_getstate.
|
||
|
*/
|
||
|
void
|
||
|
thread_getstate(pthread_thread_t *pthread, pthread_state_t *pstate)
|
||
|
{
|
||
|
pstate->stacksize = pthread->ssize - pthread->guardsize;
|
||
|
pstate->stackbase = (ssize_t)pthread->pstk + pthread->guardsize;
|
||
|
|
||
|
if (pthread == CURPTHREAD()) {
|
||
|
pstate->stackptr = (oskit_u32_t) get_esp();
|
||
|
pstate->frameptr = (oskit_u32_t) get_ebp();
|
||
|
}
|
||
|
else {
|
||
|
pstate->stackptr = (oskit_u32_t) pthread->pcb.esp;
|
||
|
pstate->frameptr = (oskit_u32_t) pthread->pcb.ebp;
|
||
|
}
|
||
|
}
|