aboutsummaryrefslogtreecommitdiff
path: root/arch/um/os-Linux
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/os-Linux')
-rw-r--r--arch/um/os-Linux/Makefile8
-rw-r--r--arch/um/os-Linux/aio.c467
-rw-r--r--arch/um/os-Linux/helper.c4
-rw-r--r--arch/um/os-Linux/main.c14
-rw-r--r--arch/um/os-Linux/process.c31
-rw-r--r--arch/um/os-Linux/signal.c246
-rw-r--r--arch/um/os-Linux/skas/Makefile10
-rw-r--r--arch/um/os-Linux/skas/mem.c283
-rw-r--r--arch/um/os-Linux/skas/process.c566
-rw-r--r--arch/um/os-Linux/skas/trap.c73
-rw-r--r--arch/um/os-Linux/start_up.c2
-rw-r--r--arch/um/os-Linux/time.c131
-rw-r--r--arch/um/os-Linux/trap.c41
-rw-r--r--arch/um/os-Linux/tt.c64
-rw-r--r--arch/um/os-Linux/uaccess.c4
-rw-r--r--arch/um/os-Linux/umid.c335
-rw-r--r--arch/um/os-Linux/util.c117
17 files changed, 2089 insertions, 307 deletions
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index b83ac8e21c3..08a4e628b24 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -4,11 +4,13 @@
#
obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \
- start_up.o time.o tt.o tty.o uaccess.o user_syms.o drivers/ \
- sys-$(SUBARCH)/
+ start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \
+ util.o drivers/ sys-$(SUBARCH)/
+
+obj-$(CONFIG_MODE_SKAS) += skas/
USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \
- start_up.o time.o tt.o tty.o uaccess.o
+ start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o
elf_aux.o: $(ARCH_DIR)/kernel-offsets.h
CFLAGS_elf_aux.o += -I$(objtree)/arch/um
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
index ffa759addd3..f897140cc4a 100644
--- a/arch/um/os-Linux/aio.c
+++ b/arch/um/os-Linux/aio.c
@@ -16,12 +16,12 @@
#include "mode.h"
struct aio_thread_req {
- enum aio_type type;
- int io_fd;
- unsigned long long offset;
- char *buf;
- int len;
- struct aio_context *aio;
+ enum aio_type type;
+ int io_fd;
+ unsigned long long offset;
+ char *buf;
+ int len;
+ struct aio_context *aio;
};
static int aio_req_fd_r = -1;
@@ -38,18 +38,18 @@ static int aio_req_fd_w = -1;
static long io_setup(int n, aio_context_t *ctxp)
{
- return syscall(__NR_io_setup, n, ctxp);
+ return syscall(__NR_io_setup, n, ctxp);
}
static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
{
- return syscall(__NR_io_submit, ctx, nr, iocbpp);
+ return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
- struct io_event *events, struct timespec *timeout)
+ struct io_event *events, struct timespec *timeout)
{
- return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout);
+ return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout);
}
#endif
@@ -66,243 +66,245 @@ static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
*/
static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf,
- int len, unsigned long long offset, struct aio_context *aio)
+ int len, unsigned long long offset, struct aio_context *aio)
{
- struct iocb iocb, *iocbp = &iocb;
- char c;
- int err;
-
- iocb = ((struct iocb) { .aio_data = (unsigned long) aio,
- .aio_reqprio = 0,
- .aio_fildes = fd,
- .aio_buf = (unsigned long) buf,
- .aio_nbytes = len,
- .aio_offset = offset,
- .aio_reserved1 = 0,
- .aio_reserved2 = 0,
- .aio_reserved3 = 0 });
-
- switch(type){
- case AIO_READ:
- iocb.aio_lio_opcode = IOCB_CMD_PREAD;
- err = io_submit(ctx, 1, &iocbp);
- break;
- case AIO_WRITE:
- iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
- err = io_submit(ctx, 1, &iocbp);
- break;
- case AIO_MMAP:
- iocb.aio_lio_opcode = IOCB_CMD_PREAD;
- iocb.aio_buf = (unsigned long) &c;
- iocb.aio_nbytes = sizeof(c);
- err = io_submit(ctx, 1, &iocbp);
- break;
- default:
- printk("Bogus op in do_aio - %d\n", type);
- err = -EINVAL;
- break;
- }
-
- if(err > 0)
- err = 0;
+ struct iocb iocb, *iocbp = &iocb;
+ char c;
+ int err;
+
+ iocb = ((struct iocb) { .aio_data = (unsigned long) aio,
+ .aio_reqprio = 0,
+ .aio_fildes = fd,
+ .aio_buf = (unsigned long) buf,
+ .aio_nbytes = len,
+ .aio_offset = offset,
+ .aio_reserved1 = 0,
+ .aio_reserved2 = 0,
+ .aio_reserved3 = 0 });
+
+ switch(type){
+ case AIO_READ:
+ iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+ err = io_submit(ctx, 1, &iocbp);
+ break;
+ case AIO_WRITE:
+ iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
+ err = io_submit(ctx, 1, &iocbp);
+ break;
+ case AIO_MMAP:
+ iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+ iocb.aio_buf = (unsigned long) &c;
+ iocb.aio_nbytes = sizeof(c);
+ err = io_submit(ctx, 1, &iocbp);
+ break;
+ default:
+ printk("Bogus op in do_aio - %d\n", type);
+ err = -EINVAL;
+ break;
+ }
+
+ if(err > 0)
+ err = 0;
else
err = -errno;
- return err;
+ return err;
}
static aio_context_t ctx = 0;
static int aio_thread(void *arg)
{
- struct aio_thread_reply reply;
- struct io_event event;
- int err, n, reply_fd;
-
- signal(SIGWINCH, SIG_IGN);
-
- while(1){
- n = io_getevents(ctx, 1, 1, &event, NULL);
- if(n < 0){
- if(errno == EINTR)
- continue;
- printk("aio_thread - io_getevents failed, "
- "errno = %d\n", errno);
- }
- else {
- reply = ((struct aio_thread_reply)
- { .data = (void *) (long) event.data,
- .err = event.res });
+ struct aio_thread_reply reply;
+ struct io_event event;
+ int err, n, reply_fd;
+
+ signal(SIGWINCH, SIG_IGN);
+
+ while(1){
+ n = io_getevents(ctx, 1, 1, &event, NULL);
+ if(n < 0){
+ if(errno == EINTR)
+ continue;
+ printk("aio_thread - io_getevents failed, "
+ "errno = %d\n", errno);
+ }
+ else {
+ reply = ((struct aio_thread_reply)
+ { .data = (void *) (long) event.data,
+ .err = event.res });
reply_fd = ((struct aio_context *) reply.data)->reply_fd;
err = os_write_file(reply_fd, &reply, sizeof(reply));
- if(err != sizeof(reply))
+ if(err != sizeof(reply))
printk("aio_thread - write failed, fd = %d, "
- "err = %d\n", aio_req_fd_r, -err);
- }
- }
- return 0;
+ "err = %d\n", aio_req_fd_r, -err);
+ }
+ }
+ return 0;
}
#endif
static int do_not_aio(struct aio_thread_req *req)
{
- char c;
- int err;
-
- switch(req->type){
- case AIO_READ:
- err = os_seek_file(req->io_fd, req->offset);
- if(err)
- goto out;
-
- err = os_read_file(req->io_fd, req->buf, req->len);
- break;
- case AIO_WRITE:
- err = os_seek_file(req->io_fd, req->offset);
- if(err)
- goto out;
-
- err = os_write_file(req->io_fd, req->buf, req->len);
- break;
- case AIO_MMAP:
- err = os_seek_file(req->io_fd, req->offset);
- if(err)
- goto out;
-
- err = os_read_file(req->io_fd, &c, sizeof(c));
- break;
- default:
- printk("do_not_aio - bad request type : %d\n", req->type);
- err = -EINVAL;
- break;
- }
-
- out:
- return err;
+ char c;
+ int err;
+
+ switch(req->type){
+ case AIO_READ:
+ err = os_seek_file(req->io_fd, req->offset);
+ if(err)
+ goto out;
+
+ err = os_read_file(req->io_fd, req->buf, req->len);
+ break;
+ case AIO_WRITE:
+ err = os_seek_file(req->io_fd, req->offset);
+ if(err)
+ goto out;
+
+ err = os_write_file(req->io_fd, req->buf, req->len);
+ break;
+ case AIO_MMAP:
+ err = os_seek_file(req->io_fd, req->offset);
+ if(err)
+ goto out;
+
+ err = os_read_file(req->io_fd, &c, sizeof(c));
+ break;
+ default:
+ printk("do_not_aio - bad request type : %d\n", req->type);
+ err = -EINVAL;
+ break;
+ }
+
+out:
+ return err;
}
static int not_aio_thread(void *arg)
{
- struct aio_thread_req req;
- struct aio_thread_reply reply;
- int err;
-
- signal(SIGWINCH, SIG_IGN);
- while(1){
- err = os_read_file(aio_req_fd_r, &req, sizeof(req));
- if(err != sizeof(req)){
- if(err < 0)
- printk("not_aio_thread - read failed, "
- "fd = %d, err = %d\n", aio_req_fd_r,
- -err);
- else {
- printk("not_aio_thread - short read, fd = %d, "
- "length = %d\n", aio_req_fd_r, err);
- }
- continue;
- }
- err = do_not_aio(&req);
- reply = ((struct aio_thread_reply) { .data = req.aio,
- .err = err });
- err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply));
- if(err != sizeof(reply))
- printk("not_aio_thread - write failed, fd = %d, "
- "err = %d\n", aio_req_fd_r, -err);
- }
+ struct aio_thread_req req;
+ struct aio_thread_reply reply;
+ int err;
+
+ signal(SIGWINCH, SIG_IGN);
+ while(1){
+ err = os_read_file(aio_req_fd_r, &req, sizeof(req));
+ if(err != sizeof(req)){
+ if(err < 0)
+ printk("not_aio_thread - read failed, "
+ "fd = %d, err = %d\n", aio_req_fd_r,
+ -err);
+ else {
+ printk("not_aio_thread - short read, fd = %d, "
+ "length = %d\n", aio_req_fd_r, err);
+ }
+ continue;
+ }
+ err = do_not_aio(&req);
+ reply = ((struct aio_thread_reply) { .data = req.aio,
+ .err = err });
+ err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply));
+ if(err != sizeof(reply))
+ printk("not_aio_thread - write failed, fd = %d, "
+ "err = %d\n", aio_req_fd_r, -err);
+ }
+
+ return 0;
}
static int aio_pid = -1;
static int init_aio_24(void)
{
- unsigned long stack;
- int fds[2], err;
-
- err = os_pipe(fds, 1, 1);
- if(err)
- goto out;
-
- aio_req_fd_w = fds[0];
- aio_req_fd_r = fds[1];
- err = run_helper_thread(not_aio_thread, NULL,
- CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
- if(err < 0)
- goto out_close_pipe;
-
- aio_pid = err;
- goto out;
-
- out_close_pipe:
- os_close_file(fds[0]);
- os_close_file(fds[1]);
- aio_req_fd_w = -1;
- aio_req_fd_r = -1;
- out:
+ unsigned long stack;
+ int fds[2], err;
+
+ err = os_pipe(fds, 1, 1);
+ if(err)
+ goto out;
+
+ aio_req_fd_w = fds[0];
+ aio_req_fd_r = fds[1];
+ err = run_helper_thread(not_aio_thread, NULL,
+ CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+ if(err < 0)
+ goto out_close_pipe;
+
+ aio_pid = err;
+ goto out;
+
+out_close_pipe:
+ os_close_file(fds[0]);
+ os_close_file(fds[1]);
+ aio_req_fd_w = -1;
+ aio_req_fd_r = -1;
+out:
#ifndef HAVE_AIO_ABI
printk("/usr/include/linux/aio_abi.h not present during build\n");
#endif
printk("2.6 host AIO support not used - falling back to I/O "
"thread\n");
- return 0;
+ return 0;
}
#ifdef HAVE_AIO_ABI
#define DEFAULT_24_AIO 0
static int init_aio_26(void)
{
- unsigned long stack;
- int err;
+ unsigned long stack;
+ int err;
- if(io_setup(256, &ctx)){
+ if(io_setup(256, &ctx)){
err = -errno;
- printk("aio_thread failed to initialize context, err = %d\n",
- errno);
- return err;
- }
+ printk("aio_thread failed to initialize context, err = %d\n",
+ errno);
+ return err;
+ }
- err = run_helper_thread(aio_thread, NULL,
- CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
- if(err < 0)
- return err;
+ err = run_helper_thread(aio_thread, NULL,
+ CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+ if(err < 0)
+ return err;
- aio_pid = err;
+ aio_pid = err;
printk("Using 2.6 host AIO\n");
- return 0;
+ return 0;
}
static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len,
unsigned long long offset, struct aio_context *aio)
{
- struct aio_thread_reply reply;
- int err;
-
- err = do_aio(ctx, type, io_fd, buf, len, offset, aio);
- if(err){
- reply = ((struct aio_thread_reply) { .data = aio,
- .err = err });
- err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
- if(err != sizeof(reply))
- printk("submit_aio_26 - write failed, "
- "fd = %d, err = %d\n", aio->reply_fd, -err);
- else err = 0;
- }
-
- return err;
+ struct aio_thread_reply reply;
+ int err;
+
+ err = do_aio(ctx, type, io_fd, buf, len, offset, aio);
+ if(err){
+ reply = ((struct aio_thread_reply) { .data = aio,
+ .err = err });
+ err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
+ if(err != sizeof(reply))
+ printk("submit_aio_26 - write failed, "
+ "fd = %d, err = %d\n", aio->reply_fd, -err);
+ else err = 0;
+ }
+
+ return err;
}
#else
#define DEFAULT_24_AIO 1
static int init_aio_26(void)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len,
unsigned long long offset, struct aio_context *aio)
{
- return -ENOSYS;
+ return -ENOSYS;
}
#endif
@@ -310,8 +312,8 @@ static int aio_24 = DEFAULT_24_AIO;
static int __init set_aio_24(char *name, int *add)
{
- aio_24 = 1;
- return 0;
+ aio_24 = 1;
+ return 0;
}
__uml_setup("aio=2.4", set_aio_24,
@@ -328,28 +330,27 @@ __uml_setup("aio=2.4", set_aio_24,
static int init_aio(void)
{
- int err;
-
- CHOOSE_MODE(({
- if(!aio_24){
- printk("Disabling 2.6 AIO in tt mode\n");
- aio_24 = 1;
- } }), (void) 0);
-
- if(!aio_24){
- err = init_aio_26();
- if(err && (errno == ENOSYS)){
- printk("2.6 AIO not supported on the host - "
- "reverting to 2.4 AIO\n");
- aio_24 = 1;
- }
- else return err;
- }
-
- if(aio_24)
- return init_aio_24();
-
- return 0;
+ int err;
+
+ CHOOSE_MODE(({ if(!aio_24){
+ printk("Disabling 2.6 AIO in tt mode\n");
+ aio_24 = 1;
+ } }), (void) 0);
+
+ if(!aio_24){
+ err = init_aio_26();
+ if(err && (errno == ENOSYS)){
+ printk("2.6 AIO not supported on the host - "
+ "reverting to 2.4 AIO\n");
+ aio_24 = 1;
+ }
+ else return err;
+ }
+
+ if(aio_24)
+ return init_aio_24();
+
+ return 0;
}
/* The reason for the __initcall/__uml_exitcall asymmetry is that init_aio
@@ -362,8 +363,8 @@ __initcall(init_aio);
static void exit_aio(void)
{
- if(aio_pid != -1)
- os_kill_process(aio_pid, 1);
+ if(aio_pid != -1)
+ os_kill_process(aio_pid, 1);
}
__uml_exitcall(exit_aio);
@@ -371,30 +372,30 @@ __uml_exitcall(exit_aio);
static int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len,
unsigned long long offset, struct aio_context *aio)
{
- struct aio_thread_req req = { .type = type,
- .io_fd = io_fd,
- .offset = offset,
- .buf = buf,
- .len = len,
- .aio = aio,
- };
- int err;
-
- err = os_write_file(aio_req_fd_w, &req, sizeof(req));
- if(err == sizeof(req))
- err = 0;
-
- return err;
+ struct aio_thread_req req = { .type = type,
+ .io_fd = io_fd,
+ .offset = offset,
+ .buf = buf,
+ .len = len,
+ .aio = aio,
+ };
+ int err;
+
+ err = os_write_file(aio_req_fd_w, &req, sizeof(req));
+ if(err == sizeof(req))
+ err = 0;
+
+ return err;
}
int submit_aio(enum aio_type type, int io_fd, char *buf, int len,
- unsigned long long offset, int reply_fd,
- struct aio_context *aio)
+ unsigned long long offset, int reply_fd,
+ struct aio_context *aio)
{
- aio->reply_fd = reply_fd;
- if(aio_24)
- return submit_aio_24(type, io_fd, buf, len, offset, aio);
- else {
- return submit_aio_26(type, io_fd, buf, len, offset, aio);
- }
+ aio->reply_fd = reply_fd;
+ if(aio_24)
+ return submit_aio_24(type, io_fd, buf, len, offset, aio);
+ else {
+ return submit_aio_26(type, io_fd, buf, len, offset, aio);
+ }
}
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index 36cc8475bcd..6490a4ff40a 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -60,7 +60,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
if((stack_out != NULL) && (*stack_out != 0))
stack = *stack_out;
- else stack = alloc_stack(0, um_in_interrupt());
+ else stack = alloc_stack(0, __cant_sleep());
if(stack == 0)
return(-ENOMEM);
@@ -124,7 +124,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
unsigned long stack, sp;
int pid, status, err;
- stack = alloc_stack(stack_order, um_in_interrupt());
+ stack = alloc_stack(stack_order, __cant_sleep());
if(stack == 0) return(-ENOMEM);
sp = stack + (page_size() << stack_order) - sizeof(void *);
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index 23da27d2256..2878e89a674 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -16,8 +16,6 @@
#include "user_util.h"
#include "kern_util.h"
#include "mem_user.h"
-#include "signal_user.h"
-#include "time_user.h"
#include "irq_user.h"
#include "user.h"
#include "init.h"
@@ -83,20 +81,8 @@ extern void scan_elf_aux( char **envp);
int main(int argc, char **argv, char **envp)
{
char **new_argv;
- sigset_t mask;
int ret, i, err;
- /* Enable all signals except SIGIO - in some environments, we can
- * enter with some signals blocked
- */
-
- sigemptyset(&mask);
- sigaddset(&mask, SIGIO);
- if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
- perror("sigprocmask");
- exit(1);
- }
-
#ifdef UML_CONFIG_CMDLINE_ON_HOST
/* Allocate memory for thread command lines */
if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index d9c52387c4a..7f5e2dac2a3 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -15,10 +15,10 @@
#include "os.h"
#include "user.h"
#include "user_util.h"
-#include "signal_user.h"
#include "process.h"
#include "irq_user.h"
#include "kern_util.h"
+#include "longjmp.h"
#define ARBITRARY_ADDR -1
#define FAILURE_PID -1
@@ -206,24 +206,13 @@ void init_new_thread_signals(int altstack)
int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
{
- sigjmp_buf buf;
- int n;
-
- *jmp_ptr = &buf;
- n = sigsetjmp(buf, 1);
- if(n != 0)
- return(n);
- (*fn)(arg);
- return(0);
+ sigjmp_buf buf;
+ int n, enable;
+
+ *jmp_ptr = &buf;
+ n = UML_SIGSETJMP(&buf, enable);
+ if(n != 0)
+ return(n);
+ (*fn)(arg);
+ return(0);
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index c7bfd5ee392..f11b3124a0c 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -4,27 +4,74 @@
*/
#include <signal.h>
-#include "time_user.h"
-#include "mode.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/mman.h>
+#include "user_util.h"
+#include "user.h"
+#include "signal_kern.h"
+#include "sysdep/sigcontext.h"
#include "sysdep/signal.h"
+#include "sigcontext.h"
+#include "mode.h"
+#include "os.h"
+
+/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled
+ * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to
+ * be able to profile all of UML, not just the non-critical sections. If
+ * profiling is not thread-safe, then that is not my problem. We can disable
+ * profiling when SMP is enabled in that case.
+ */
+#define SIGIO_BIT 0
+#define SIGIO_MASK (1 << SIGIO_BIT)
+
+#define SIGVTALRM_BIT 1
+#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
+
+#define SIGALRM_BIT 2
+#define SIGALRM_MASK (1 << SIGALRM_BIT)
+
+static int signals_enabled = 1;
+static int pending = 0;
void sig_handler(ARCH_SIGHDLR_PARAM)
{
struct sigcontext *sc;
+ int enabled;
+
+ /* Must be the first thing that this handler does - x86_64 stores
+ * the sigcontext in %rdx, and we need to save it before it has a
+ * chance to get trashed.
+ */
ARCH_GET_SIGCONTEXT(sc, sig);
+
+ enabled = signals_enabled;
+ if(!enabled && (sig == SIGIO)){
+ pending |= SIGIO_MASK;
+ return;
+ }
+
+ block_signals();
+
CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
sig, sc);
+
+ set_signals(enabled);
}
extern int timer_irq_inited;
-void alarm_handler(ARCH_SIGHDLR_PARAM)
+static void real_alarm_handler(int sig, struct sigcontext *sc)
{
- struct sigcontext *sc;
-
- ARCH_GET_SIGCONTEXT(sc, sig);
- if(!timer_irq_inited) return;
+ if(!timer_irq_inited){
+ signals_enabled = 1;
+ return;
+ }
if(sig == SIGALRM)
switch_timers(0);
@@ -34,15 +81,180 @@ void alarm_handler(ARCH_SIGHDLR_PARAM)
if(sig == SIGALRM)
switch_timers(1);
+
}
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+void alarm_handler(ARCH_SIGHDLR_PARAM)
+{
+ struct sigcontext *sc;
+ int enabled;
+
+ ARCH_GET_SIGCONTEXT(sc, sig);
+
+ enabled = signals_enabled;
+ if(!signals_enabled){
+ if(sig == SIGVTALRM)
+ pending |= SIGVTALRM_MASK;
+ else pending |= SIGALRM_MASK;
+
+ return;
+ }
+
+ block_signals();
+
+ real_alarm_handler(sig, sc);
+ set_signals(enabled);
+}
+
+extern void do_boot_timer_handler(struct sigcontext * sc);
+
+void boot_timer_handler(ARCH_SIGHDLR_PARAM)
+{
+ struct sigcontext *sc;
+ int enabled;
+
+ ARCH_GET_SIGCONTEXT(sc, sig);
+
+ enabled = signals_enabled;
+ if(!enabled){
+ if(sig == SIGVTALRM)
+ pending |= SIGVTALRM_MASK;
+ else pending |= SIGALRM_MASK;
+ return;
+ }
+
+ block_signals();
+
+ do_boot_timer_handler(sc);
+ set_signals(enabled);
+}
+
+void set_sigstack(void *sig_stack, int size)
+{
+ stack_t stack = ((stack_t) { .ss_flags = 0,
+ .ss_sp = (__ptr_t) sig_stack,
+ .ss_size = size - sizeof(void *) });
+
+ if(sigaltstack(&stack, NULL) != 0)
+ panic("enabling signal stack failed, errno = %d\n", errno);
+}
+
+void remove_sigstack(void)
+{
+ stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
+ .ss_sp = NULL,
+ .ss_size = 0 });
+
+ if(sigaltstack(&stack, NULL) != 0)
+ panic("disabling signal stack failed, errno = %d\n", errno);
+}
+
+void set_handler(int sig, void (*handler)(int), int flags, ...)
+{
+ struct sigaction action;
+ va_list ap;
+ sigset_t sig_mask;
+ int mask;
+
+ va_start(ap, flags);
+ action.sa_handler = handler;
+ sigemptyset(&action.sa_mask);
+ while((mask = va_arg(ap, int)) != -1){
+ sigaddset(&action.sa_mask, mask);
+ }
+ va_end(ap);
+ action.sa_flags = flags;
+ action.sa_restorer = NULL;
+ if(sigaction(sig, &action, NULL) < 0)
+ panic("sigaction failed - errno = %d\n", errno);
+
+ sigemptyset(&sig_mask);
+ sigaddset(&sig_mask, sig);
+ if(sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0)
+ panic("sigprocmask failed - errno = %d\n", errno);
+}
+
+int change_sig(int signal, int on)
+{
+ sigset_t sigset, old;
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, signal);
+ sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
+ return(!sigismember(&old, signal));
+}
+
+void block_signals(void)
+{
+ signals_enabled = 0;
+}
+
+void unblock_signals(void)
+{
+ int save_pending;
+
+ if(signals_enabled == 1)
+ return;
+
+ /* We loop because the IRQ handler returns with interrupts off. So,
+ * interrupts may have arrived and we need to re-enable them and
+ * recheck pending.
+ */
+ while(1){
+ /* Save and reset save_pending after enabling signals. This
+ * way, pending won't be changed while we're reading it.
+ */
+ signals_enabled = 1;
+
+ save_pending = pending;
+ if(save_pending == 0)
+ return;
+
+ pending = 0;
+
+ /* We have pending interrupts, so disable signals, as the
+ * handlers expect them off when they are called. They will
+ * be enabled again above.
+ */
+
+ signals_enabled = 0;
+
+ /* Deal with SIGIO first because the alarm handler might
+ * schedule, leaving the pending SIGIO stranded until we come
+ * back here.
+ */
+ if(save_pending & SIGIO_MASK)
+ CHOOSE_MODE_PROC(sig_handler_common_tt,
+ sig_handler_common_skas, SIGIO, NULL);
+
+ if(save_pending & SIGALRM_MASK)
+ real_alarm_handler(SIGALRM, NULL);
+
+ if(save_pending & SIGVTALRM_MASK)
+ real_alarm_handler(SIGVTALRM, NULL);
+ }
+}
+
+int get_signals(void)
+{
+ return signals_enabled;
+}
+
+int set_signals(int enable)
+{
+ int ret;
+ if(signals_enabled == enable)
+ return enable;
+
+ ret = signals_enabled;
+ if(enable)
+ unblock_signals();
+ else block_signals();
+
+ return ret;
+}
+
+void os_usr1_signal(int on)
+{
+ change_sig(SIGUSR1, on);
+}
diff --git a/arch/um/os-Linux/skas/Makefile b/arch/um/os-Linux/skas/Makefile
new file mode 100644
index 00000000000..5fd8d4dad66
--- /dev/null
+++ b/arch/um/os-Linux/skas/Makefile
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
+# Licensed under the GPL
+#
+
+obj-y := mem.o process.o trap.o
+
+USER_OBJS := mem.o process.o trap.o
+
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
new file mode 100644
index 00000000000..9890e9090f5
--- /dev/null
+++ b/arch/um/os-Linux/skas/mem.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include "mem_user.h"
+#include "mem.h"
+#include "skas.h"
+#include "user.h"
+#include "os.h"
+#include "proc_mm.h"
+#include "ptrace_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "registers.h"
+#include "uml-config.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/stub.h"
+
+extern unsigned long batch_syscall_stub, __syscall_stub_start;
+
+extern void wait_stub_done(int pid, int sig, char * fname);
+
+static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
+ unsigned long *stack)
+{
+ if(stack == NULL) {
+ stack = (unsigned long *) mm_idp->stack + 2;
+ *stack = 0;
+ }
+ return stack;
+}
+
+extern int proc_mm;
+
+int single_count = 0;
+int multi_count = 0;
+int multi_op_count = 0;
+
+static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
+{
+ unsigned long regs[MAX_REG_NR];
+ int n;
+ long ret, offset;
+ unsigned long * data;
+ unsigned long * syscall;
+ int pid = mm_idp->u.pid;
+
+ if(proc_mm)
+#warning Need to look up userspace_pid by cpu
+ pid = userspace_pid[0];
+
+ multi_count++;
+
+ get_safe_registers(regs);
+ regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ ((unsigned long) &batch_syscall_stub -
+ (unsigned long) &__syscall_stub_start);
+
+ n = ptrace_setregs(pid, regs);
+ if(n < 0)
+ panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
+ n);
+
+ wait_stub_done(pid, 0, "do_syscall_stub");
+
+ /* When the stub stops, we find the following values on the
+ * beginning of the stack:
<