*/
#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include "os.h"
#include "proc_mm.h"
#include "skas_ptrace.h"
+#include "chan_user.h"
+#include "signal_user.h"
+
+int is_skas_winch(int pid, int fd, void *data)
+{
+ if(pid != getpid())
+ return(0);
+
+ register_winch_irq(-1, fd, -1, data);
+ return(1);
+}
+
+/* These are set once at boot time and not changed thereafter */
unsigned long exec_regs[FRAME_SIZE];
unsigned long exec_fp_regs[HOST_FP_SIZE];
segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
}
-static void handle_trap(int pid, union uml_pt_regs *regs)
+/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
+static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu)
{
int err, syscall_nr, status;
syscall_nr = PT_SYSCALL_NR(regs->skas.regs);
+ UPT_SYSCALL_NR(regs) = syscall_nr;
if(syscall_nr < 1){
relay_signal(SIGTRAP, regs);
return;
}
- UPT_SYSCALL_NR(regs) = syscall_nr;
- err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
- if(err < 0)
- panic("handle_trap - nullifying syscall failed errno = %d\n",
- errno);
+ if (!local_using_sysemu)
+ {
+ err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
+ if(err < 0)
+ panic("handle_trap - nullifying syscall failed errno = %d\n",
+ errno);
- err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
- if(err < 0)
- panic("handle_trap - continuing to end of syscall failed, "
- "errno = %d\n", errno);
+ err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
+ if(err < 0)
+ panic("handle_trap - continuing to end of syscall failed, "
+ "errno = %d\n", errno);
- err = waitpid(pid, &status, WUNTRACED);
- if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
- panic("handle_trap - failed to wait at end of syscall, "
- "errno = %d, status = %d\n", errno, status);
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
+ if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
+ panic("handle_trap - failed to wait at end of syscall, "
+ "errno = %d, status = %d\n", errno, status);
+ }
handle_syscall(regs);
}
-int userspace_pid;
-
static int userspace_tramp(void *arg)
{
init_new_thread_signals(0);
return(0);
}
-void start_userspace(void)
+/* Each element set once, and only accessed by a single processor anyway */
+#define NR_CPUS 1
+int userspace_pid[NR_CPUS];
+
+void start_userspace(int cpu)
{
void *stack;
unsigned long sp;
panic("start_userspace : clone failed, errno = %d", errno);
do {
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("start_userspace : wait failed, errno = %d",
errno);
if(munmap(stack, PAGE_SIZE) < 0)
panic("start_userspace : munmap failed, errno = %d\n", errno);
- userspace_pid = pid;
+ userspace_pid[cpu] = pid;
}
void userspace(union uml_pt_regs *regs)
{
- int err, status, op;
+ int err, status, op, pid = userspace_pid[0];
+ int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
restore_registers(regs);
- err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0);
+ local_using_sysemu = get_using_sysemu();
+
+ if (local_using_sysemu)
+ err = ptrace(PTRACE_SYSEMU, pid, 0, 0);
+ else
+ err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
if(err)
- panic("userspace - PTRACE_SYSCALL failed, errno = %d\n",
- errno);
+ panic("userspace - PTRACE_%s failed, errno = %d\n",
+ local_using_sysemu ? "SYSEMU" : "SYSCALL", errno);
while(1){
- err = waitpid(userspace_pid, &status, WUNTRACED);
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
if(err < 0)
panic("userspace - waitpid failed, errno = %d\n",
errno);
if(WIFSTOPPED(status)){
switch(WSTOPSIG(status)){
case SIGSEGV:
- handle_segv(userspace_pid);
+ handle_segv(pid);
break;
case SIGTRAP:
- handle_trap(userspace_pid, regs);
+ handle_trap(pid, regs, local_using_sysemu);
break;
case SIGIO:
case SIGVTALRM:
case SIGILL:
case SIGBUS:
case SIGFPE:
+ case SIGWINCH:
user_signal(WSTOPSIG(status), regs);
break;
default:
restore_registers(regs);
- op = singlestepping_skas() ? PTRACE_SINGLESTEP :
- PTRACE_SYSCALL;
- err = ptrace(op, userspace_pid, 0, 0);
+ /*Now we ended the syscall, so re-read local_using_sysemu.*/
+ local_using_sysemu = get_using_sysemu();
+
+ if (local_using_sysemu)
+ op = singlestepping_skas() ? PTRACE_SINGLESTEP :
+ PTRACE_SYSEMU;
+ else
+ op = singlestepping_skas() ? PTRACE_SINGLESTEP :
+ PTRACE_SYSCALL;
+
+ err = ptrace(op, pid, 0, 0);
if(err)
- panic("userspace - PTRACE_SYSCALL failed, "
- "errno = %d\n", errno);
+ panic("userspace - PTRACE_%s failed, "
+ "errno = %d\n",
+ local_using_sysemu ? "SYSEMU" : "SYSCALL", errno);
}
}
void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
void (*handler)(int))
{
- jmp_buf switch_buf, fork_buf;
+ unsigned long flags;
+ sigjmp_buf switch_buf, fork_buf;
*switch_buf_ptr = &switch_buf;
*fork_buf_ptr = &fork_buf;
- if(setjmp(fork_buf) == 0)
+ /* Somewhat subtle - siglongjmp restores the signal mask before doing
+ * the longjmp. This means that when jumping from one stack to another
+ * when the target stack has interrupts enabled, an interrupt may occur
+ * on the source stack. This is bad when starting up a process because
+ * it's not supposed to get timer ticks until it has been scheduled.
+ * So, we disable interrupts around the sigsetjmp to ensure that
+ * they can't happen until we get back here where they are safe.
+ */
+ flags = get_signals();
+ block_signals();
+ if(sigsetjmp(fork_buf, 1) == 0)
new_thread_proc(stack, handler);
+ set_signals(flags);
remove_sigstack();
}
void thread_wait(void *sw, void *fb)
{
- jmp_buf buf, **switch_buf = sw, *fork_buf;
+ sigjmp_buf buf, **switch_buf = sw, *fork_buf;
*switch_buf = &buf;
fork_buf = fb;
- if(setjmp(buf) == 0)
- longjmp(*fork_buf, 1);
+ if(sigsetjmp(buf, 1) == 0)
+ siglongjmp(*fork_buf, 1);
}
-static int move_registers(int int_op, int fp_op, union uml_pt_regs *regs,
- unsigned long *fp_regs)
+static int move_registers(int pid, int int_op, int fp_op,
+ union uml_pt_regs *regs, unsigned long *fp_regs)
{
- if(ptrace(int_op, userspace_pid, 0, regs->skas.regs) < 0)
+ if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
return(-errno);
- if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0)
+ if(ptrace(fp_op, pid, 0, fp_regs) < 0)
return(-errno);
return(0);
}
fp_regs = regs->skas.fp;
}
- err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs);
+ err = move_registers(userspace_pid[0], PTRACE_GETREGS, fp_op, regs,
+ fp_regs);
if(err)
panic("save_registers - saving registers failed, errno = %d\n",
- err);
+ -err);
}
void restore_registers(union uml_pt_regs *regs)
fp_regs = regs->skas.fp;
}
- err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs);
+ err = move_registers(userspace_pid[0], PTRACE_SETREGS, fp_op, regs,
+ fp_regs);
if(err)
panic("restore_registers - saving registers failed, "
- "errno = %d\n", err);
+ "errno = %d\n", -err);
}
void switch_threads(void *me, void *next)
{
- jmp_buf my_buf, **me_ptr = me, *next_buf = next;
+ sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
*me_ptr = &my_buf;
- if(setjmp(my_buf) == 0)
- longjmp(*next_buf, 1);
+ if(sigsetjmp(my_buf, 1) == 0)
+ siglongjmp(*next_buf, 1);
}
-static jmp_buf initial_jmpbuf;
+static sigjmp_buf initial_jmpbuf;
/* XXX Make these percpu */
static void (*cb_proc)(void *arg);
static void *cb_arg;
-static jmp_buf *cb_back;
+static sigjmp_buf *cb_back;
int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
{
- jmp_buf **switch_buf = switch_buf_ptr;
+ sigjmp_buf **switch_buf = switch_buf_ptr;
int n;
*fork_buf_ptr = &initial_jmpbuf;
- n = setjmp(initial_jmpbuf);
+ n = sigsetjmp(initial_jmpbuf, 1);
if(n == 0)
new_thread_proc((void *) stack, new_thread_handler);
else if(n == 1)
remove_sigstack();
else if(n == 2){
(*cb_proc)(cb_arg);
- longjmp(*cb_back, 1);
+ siglongjmp(*cb_back, 1);
}
else if(n == 3){
kmalloc_ok = 0;
kmalloc_ok = 0;
return(1);
}
- longjmp(**switch_buf, 1);
+ siglongjmp(**switch_buf, 1);
}
void remove_sigstack(void)
void initial_thread_cb_skas(void (*proc)(void *), void *arg)
{
- jmp_buf here;
+ sigjmp_buf here;
cb_proc = proc;
cb_arg = arg;
cb_back = &here;
block_signals();
- if(setjmp(here) == 0)
- longjmp(initial_jmpbuf, 2);
+ if(sigsetjmp(here, 1) == 0)
+ siglongjmp(initial_jmpbuf, 2);
unblock_signals();
cb_proc = NULL;
void halt_skas(void)
{
block_signals();
- longjmp(initial_jmpbuf, 3);
+ siglongjmp(initial_jmpbuf, 3);
}
void reboot_skas(void)
{
block_signals();
- longjmp(initial_jmpbuf, 4);
-}
-
-int new_mm(int from)
-{
- struct proc_mm_op copy;
- int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0);
-
- if(fd < 0)
- return(-errno);
-
- if(from != -1){
- copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
- .u =
- { .copy_segments = from } } );
- n = os_write_file(fd, ©, sizeof(copy));
- if(n != sizeof(copy))
- printk("new_mm : /proc/mm copy_segments failed, "
- "errno = %d\n", errno);
- }
- return(fd);
+ siglongjmp(initial_jmpbuf, 4);
}
void switch_mm_skas(int mm_fd)
{
int err;
- err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd);
+#warning need cpu pid in switch_mm_skas
+ err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
if(err)
panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
errno);
void kill_off_processes_skas(void)
{
- os_kill_process(userspace_pid, 1);
+#warning need to loop over userspace_pids in kill_off_processes_skas
+ os_kill_process(userspace_pid[0], 1);
}
void init_registers(int pid)