Commit 39f82704 authored by Jeff Dike's avatar Jeff Dike

Merged the 2.5.52 Makefile changes.

parents 91ec8aa9 cf46dde7
......@@ -30,6 +30,13 @@ config RWSEM_GENERIC_SPINLOCK
bool
default y
config MODE_TT
bool
default y
config MODE_SKAS
bool
default y
menu "Code maturity level options"
......@@ -128,6 +135,7 @@ source "net/Kconfig"
source "fs/Kconfig"
source "lib/Kconfig"
menu "SCSI support"
......
#
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
ARCH_DIR = arch/um
OS := $(shell uname -s)
......@@ -11,37 +16,31 @@ include/linux/version.h: arch/$(ARCH)/Makefile
# EXTRAVERSION...
MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
MAKEBOOT = $(MAKE) -C $(ARCH_DIR)/boot
ifeq ($(CONFIG_DEBUGSYM),y)
DEBUG = -g
CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
endif
ifeq ($(CONFIG_GCOV),y)
CFLAGS += -fprofile-arcs -ftest-coverage
endif
ifeq ($(CONFIG_GPROF), y)
PROFILE += -pg -DPROFILING
LINK_PROFILE = $(PROFILE) -Wl,--wrap,__monstartup
endif
CFLAGS-$(CONFIG_DEBUGSYM) += -g
CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage
CFLAGS-$(CONFIG_GPROF) += $(PROFILE)
LINK-$(CONFIG_GPROF) += $(PROFILE) -Wl,--wrap,__monstartup
core-y += $(ARCH_DIR)/kernel/ \
$(ARCH_DIR)/drivers/ \
$(ARCH_DIR)/sys-$(SUBARCH)/
core-$(CONFIG_PT_PROXY) += $(ARCH_DIR)/ptproxy/
ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include
ARCH_INCLUDE = -I$(ARCH_DIR)/include
MODE_INCLUDE = -I$(ARCH_DIR)/kernel/tt/include \
-I$(ARCH_DIR)/kernel/skas/include
# -Derrno=kernel_errno - This turns all kernel references to errno into
# kernel_errno to separate them from the libc errno. This allows -fno-common
# in CFLAGS. Otherwise, it would cause ld to complain about the two different
# errnos.
CFLAGS += $(DEBUG) $(PROFILE) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
-D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) -Derrno=kernel_errno
CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
-D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \
$(MODE_INCLUDE)
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
......@@ -51,10 +50,16 @@ SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
include/asm-um/sigcontext.h include/asm-um/processor.h \
include/asm-um/ptrace.h include/asm-um/arch-signal.h
ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep arch/um/os \
$(SYMLINK_HEADERS)
ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
$(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
ifeq ($(CONFIG_MODE_SKAS), y)
GEN_HEADERS = $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
GEN_HEADERS = $(ARCH_DIR)/include/task.h
$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
endif
GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h
include $(ARCH_DIR)/Makefile-$(SUBARCH)
include $(ARCH_DIR)/Makefile-os-$(OS)
......@@ -62,9 +67,9 @@ include $(ARCH_DIR)/Makefile-os-$(OS)
$(ARCH_DIR)/vmlinux.lds.S :
touch $@
prepare: $(ARCH_SYMLINKS) $(GEN_HEADERS)
prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS)
LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o
LDFLAGS_vmlinux = -r
vmlinux: $(ARCH_DIR)/main.o
......@@ -74,18 +79,21 @@ $(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S scripts FORCE
AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \
-DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum
linux: arch/um/uml.lds.s vmlinux
$(CC) -Wl,-T,arch/um/uml.lds.s -o $@ $(LINK_PROFILE) \
$(LINK_WRAPS) -static vmlinux -L/usr/lib -lutil
linux: $(ARCH_DIR)/uml.lds.s vmlinux
$(CC) -Wl,-T,$(ARCH_DIR)/uml.lds.s -static $(LINK-y) $(LINK_WRAPS) \
-o linux $(ARCH_DIR)/main.o vmlinux -L/usr/lib -lutil
USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE)
USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
$(MODE_INCLUDE)
# To get a definition of F_SETSIG
USER_CFLAGS += -D_GNU_SOURCE
CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS)
$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c
$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
......@@ -106,7 +114,6 @@ archclean: sysclean
find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
-o -name '*.gcov' \) -type f -print | xargs rm -f
rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS)
@$(MAKEBOOT) clean
archdep:
for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done
......@@ -119,18 +126,28 @@ $(SYMLINK_HEADERS):
include/asm-um/arch:
cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
arch/um/include/sysdep:
cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep
$(ARCH_DIR)/include/sysdep:
cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep
arch/um/os:
$(ARCH_DIR)/os:
cd $(ARCH_DIR) && ln -sf os-$(OS) os
$(ARCH_DIR)/include/uml-config.h :
ln -sf $(TOPDIR)/include/linux/autoconf.h $@
$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
$< > $@
$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util FORCE ;
$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants
$< > $@
$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \
$(ARCH_DIR)/util FORCE ;
$(ARCH_DIR)/util: FORCE
@$(call descend,$@,)
$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h :
$(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h
export SUBARCH USER_CFLAGS OS
......@@ -21,13 +21,13 @@ prepare: $(SYS_HEADERS)
$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
$< > $@
$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
$< > $@
$(SYS_UTIL_DIR)/mk_sc: FORCE ;
@$(call descend,$(SYS_UTIL_DIR),$@)
$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) FORCE ;
$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ;
@$(call descend,$(SYS_UTIL_DIR),$@)
$(SYS_UTIL_DIR): include/asm FORCE
......
......@@ -24,7 +24,8 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts)
return(NULL);
}
static int not_configged_open(int input, int output, int primary, void *data)
static int not_configged_open(int input, int output, int primary, void *data,
char **dev_out)
{
printk(KERN_ERR "Using a channel type which is configured out of "
"UML\n");
......@@ -112,7 +113,8 @@ static int open_one_chan(struct chan *chan, int input, int output, int primary)
if(chan->opened) return(0);
if(chan->ops->open == NULL) fd = 0;
else fd = (*chan->ops->open)(input, output, primary, chan->data);
else fd = (*chan->ops->open)(input, output, primary, chan->data,
&chan->dev);
if(fd < 0) return(fd);
chan->fd = fd;
......@@ -258,6 +260,66 @@ void free_chan(struct list_head *chans)
}
}
static int one_chan_config_string(struct chan *chan, char *str, int size,
char **error_out)
{
int n = 0;
CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
if(chan->dev == NULL){
CONFIG_CHUNK(str, size, n, "", 1);
return(n);
}
CONFIG_CHUNK(str, size, n, ":", 0);
CONFIG_CHUNK(str, size, n, chan->dev, 0);
return(n);
}
static int chan_pair_config_string(struct chan *in, struct chan *out,
char *str, int size, char **error_out)
{
int n;
n = one_chan_config_string(in, str, size, error_out);
str += n;
size -= n;
if(in == out){
CONFIG_CHUNK(str, size, n, "", 1);
return(n);
}
CONFIG_CHUNK(str, size, n, ",", 1);
n = one_chan_config_string(out, str, size, error_out);
str += n;
size -= n;
CONFIG_CHUNK(str, size, n, "", 1);
return(n);
}
int chan_config_string(struct list_head *chans, char *str, int size,
char **error_out)
{
struct list_head *ele;
struct chan *chan, *in = NULL, *out = NULL;
list_for_each(ele, chans){
chan = list_entry(ele, struct chan, list);
if(!chan->primary)
continue;
if(chan->input)
in = chan;
if(chan->output)
out = chan;
}
return(chan_pair_config_string(in, out, str, size, error_out));
}
struct chan_type {
char *key;
struct chan_ops *ops;
......
......@@ -19,6 +19,8 @@
#include "user.h"
#include "helper.h"
#include "os.h"
#include "choose-mode.h"
#include "mode.h"
void generic_close(int fd, void *unused)
{
......@@ -144,32 +146,6 @@ static int winch_thread(void *arg)
}
}
static int tracer_winch[2];
static void tracer_winch_handler(int sig)
{
char c = 1;
if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c))
printk("tracer_winch_handler - write failed, errno = %d\n",
errno);
}
/* Called only by the tracing thread during initialization */
void setup_tracer_winch(void)
{
int err;
err = os_pipe(tracer_winch, 1, 1);
if(err){
printk("setup_tracer_winch : os_pipe failed, errno = %d\n",
-err);
return;
}
signal(SIGWINCH, tracer_winch_handler);
}
static int winch_tramp(int fd, void *device_data, int *fd_out)
{
struct winch_data data;
......@@ -212,9 +188,8 @@ void register_winch(int fd, void *device_data)
if(!isatty(fd)) return;
pid = tcgetpgrp(fd);
if(pid == tracing_pid)
register_winch_irq(tracer_winch[0], fd, -1, device_data);
else if(pid == -1){
if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) &&
(pid == -1)){
thread = winch_tramp(fd, device_data, &thread_fd);
if(fd != -1){
register_winch_irq(thread_fd, fd, thread, device_data);
......
......@@ -15,6 +15,7 @@ struct fd_chan {
int fd;
int raw;
struct termios tt;
char str[sizeof("1234567890\0")];
};
void *fd_init(char *str, int device, struct chan_opts *opts)
......@@ -40,7 +41,7 @@ void *fd_init(char *str, int device, struct chan_opts *opts)
return(data);
}
int fd_open(int input, int output, int primary, void *d)
int fd_open(int input, int output, int primary, void *d, char **dev_out)
{
struct fd_chan *data = d;
......@@ -48,6 +49,8 @@ int fd_open(int input, int output, int primary, void *d)
tcgetattr(data->fd, &data->tt);
raw(data->fd, 0);
}
sprintf(data->str, "%d", data->fd);
*dev_out = data->str;
return(data->fd);
}
......@@ -69,6 +72,7 @@ int fd_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops fd_ops = {
type: "fd",
init: fd_init,
open: fd_open,
close: fd_close,
......
......@@ -8,11 +8,13 @@
#include "linux/list.h"
#include "linux/devfs_fs_kernel.h"
#include "asm/irq.h"
#include "asm/uaccess.h"
#include "chan_kern.h"
#include "irq_user.h"
#include "line.h"
#include "kern.h"
#include "user_util.h"
#include "kern_util.h"
#include "os.h"
#define LINE_BUFSIZE 4096
......@@ -87,15 +89,26 @@ static int flush_buffer(struct line *line)
return(line->head == line->tail);
}
int line_write(struct line *lines, struct tty_struct *tty, const char *buf,
int len)
int line_write(struct line *lines, struct tty_struct *tty, int from_user,
const char *buf, int len)
{
struct line *line;
char *new;
unsigned long flags;
int n, err, i;
if(tty->stopped) return 0;
if(from_user){
new = kmalloc(len, GFP_KERNEL);
if(new == NULL)
return(0);
n = copy_from_user(new, buf, len);
if(n == len)
return(-EFAULT);
buf = new;
}
i = minor(tty->device) - tty->driver.minor_start;
line = &lines[i];
......@@ -281,7 +294,7 @@ void close_lines(struct line *lines, int nlines)
close_chan(&lines[i].chan_list);
}
void line_setup(struct line *lines, int num, char *init)
int line_setup(struct line *lines, int num, char *init, int all_allowed)
{
int i, n;
char *end;
......@@ -292,12 +305,36 @@ void line_setup(struct line *lines, int num, char *init)
if(*end != '='){
printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
init);
return;
return(1);
}
init = end;
}
init++;
if(n == -1){
if((n >= 0) && (n >= num)){
printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
n, num);
return(1);
}
else if(n >= 0){
if(lines[n].count > 0){
printk("line_setup - device %d is open\n", n);
return(1);
}
if(lines[n].init_pri <= INIT_ONE){
lines[n].init_pri = INIT_ONE;
if(!strcmp(init, "none")) lines[n].valid = 0;
else {
lines[n].init_str = init;
lines[n].valid = 1;
}
}
}
else if(!all_allowed){
printk("line_setup - can't configure all devices from "
"mconsole\n");
return(1);
}
else {
for(i = 0; i < num; i++){
if(lines[i].init_pri <= INIT_ALL){
lines[i].init_pri = INIT_ALL;
......@@ -309,14 +346,57 @@ void line_setup(struct line *lines, int num, char *init)
}
}
}
else if(lines[n].init_pri <= INIT_ONE){
lines[n].init_pri = INIT_ONE;
if(!strcmp(init, "none")) lines[n].valid = 0;
else {
lines[n].init_str = init;
lines[n].valid = 1;
}
return(0);
}
int line_config(struct line *lines, int num, char *str)
{
char *new = uml_strdup(str);
if(new == NULL){
printk("line_config - uml_strdup failed\n");
return(-ENOMEM);
}
return(line_setup(lines, num, new, 0));
}
int line_get_config(char *name, struct line *lines, int num, char *str,
int size, char **error_out)
{
struct line *line;
char *end;
int dev, n = 0;
dev = simple_strtoul(name, &end, 0);
if((*end != '\0') || (end == name)){
*error_out = "line_setup failed to parse device number";
return(0);
}
if((dev < 0) || (dev >= num)){
*error_out = "device number of of range";
return(0);
}
line = &lines[dev];
down(&line->sem);
if(!line->valid)
CONFIG_CHUNK(str, size, n, "none", 1);
else if(line->count == 0)
CONFIG_CHUNK(str, size, n, line->init_str, 1);
else n = chan_config_string(&line->chan_list, str, size, error_out);
up(&line->sem);
return(n);
}
int line_remove(struct line *lines, int num, char *str)
{
char config[sizeof("conxxxx=none\0")];
sprintf(config, "%s=none", str);
return(line_setup(lines, num, config, 0));
}
void line_register_devfs(struct lines *set, struct line_driver *line_driver,
......@@ -366,6 +446,8 @@ void line_register_devfs(struct lines *set, struct line_driver *line_driver,
if(!lines[i].valid)
tty_unregister_devfs(driver, driver->minor_start + i);
}
mconsole_register_dev(&line_driver->mc);
}
void lines_init(struct line *lines, int nlines)
......@@ -451,7 +533,7 @@ static void winch_cleanup(void)
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
close(winch->fd);
if(winch->pid != -1) os_kill_process(winch->pid);
if(winch->pid != -1) os_kill_process(winch->pid, 0);
}
}
......
......@@ -108,6 +108,7 @@ void mconsole_version(struct mc_request *req)
reboot - Reboot UML
config <dev>=<config> - Add a new device to UML;
same syntax as command line
config <dev> - Query the configuration of a device
remove <dev> - Remove a device from UML
sysrq <letter> - Performs the SysRq action controlled by the letter
cad - invoke the Ctl-Alt-Del handler
......@@ -181,10 +182,56 @@ static struct mc_device *mconsole_find_dev(char *name)
return(NULL);
}
#define CONFIG_BUF_SIZE 64
static void mconsole_get_config(int (*get_config)(char *, char *, int,
char **),
struct mc_request *req, char *name)
{
char default_buf[CONFIG_BUF_SIZE], *error, *buf;
int n, size;
if(get_config == NULL){
mconsole_reply(req, "No get_config routine defined", 1, 0);
return;
}
error = NULL;
size = sizeof(default_buf)/sizeof(default_buf[0]);
buf = default_buf;
while(1){
n = (*get_config)(name, buf, size, &error);
if(error != NULL){
mconsole_reply(req, error, 1, 0);
goto out;
}
if(n <= size){
mconsole_reply(req, buf, 0, 0);
goto out;
}
if(buf != default_buf)
kfree(buf);
size = n;
buf = kmalloc(size, GFP_KERNEL);
if(buf == NULL){
mconsole_reply(req, "Failed to allocate buffer", 1, 0);
return;
}
}
out:
if(buf != default_buf)
kfree(buf);
}
void mconsole_config(struct mc_request *req)
{
struct mc_device *dev;
char *ptr = req->request.data;
char *ptr = req->request.data, *name;
int err;
ptr += strlen("config");
......@@ -194,8 +241,17 @@ void mconsole_config(struct mc_request *req)
mconsole_reply(req, "Bad configuration option", 1, 0);
return;
}
err = (*dev->config)(&ptr[strlen(dev->name)]);
mconsole_reply(req, "", err, 0);
name = &ptr[strlen(dev->name)];
ptr = name;
while((*ptr != '=') && (*ptr != '\0'))
ptr++;
if(*ptr == '='){
err = (*dev->config)(name);
mconsole_reply(req, "", err, 0);
}
else mconsole_get_config(dev->get_config, req, name);
}
void mconsole_remove(struct mc_request *req)
......
......@@ -3,6 +3,7 @@
* Licensed under the GPL
*/
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include "chan_user.h"
......@@ -15,8 +16,9 @@ void *null_init(char *str, int device, struct chan_opts *opts)
return(&null_chan);
}
int null_open(int input, int output, int primary, void *d)
int null_open(int input, int output, int primary, void *d, char **dev_out)
{
*dev_out = NULL;
return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
}
......@@ -30,6 +32,7 @@ void null_free(void *data)
}
struct chan_ops null_ops = {
type: "null",
init: null_init,
open: null_open,
close: generic_close,
......
......@@ -99,14 +99,13 @@ static int port_accept(struct port_list *port)
}
list_add(&conn->list, &port->pending);
ret = 1;
goto out;
return(1);
out_free:
kfree(conn);
out_close:
os_close_file(fd);
if(pid != -1) os_kill_process(pid);
if(pid != -1) os_kill_process(pid, 0);
out:
return(ret);
}
......@@ -210,9 +209,9 @@ void port_remove_dev(void *d)
struct port_dev *dev = d;
if(dev->helper_pid != -1)
os_kill_process(dev->helper_pid);
os_kill_process(dev->helper_pid, 0);
if(dev->telnetd_pid != -1)
os_kill_process(dev->telnetd_pid);
os_kill_process(dev->telnetd_pid, 0);
dev->helper_pid = -1;
}
......@@ -275,8 +274,8 @@ void port_kern_free(void *d)
{
struct port_dev *dev = d;
if(dev->helper_pid != -1) os_kill_process(dev->telnetd_pid);
if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid);
if(dev->helper_pid != -1) os_kill_process(dev->helper_pid, 0);
if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid, 0);
kfree(dev);
}
......
......@@ -3,11 +3,12 @@
* Licensed under the GPL
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include <sys/socket.h>
#include <sys/un.h>
......@@ -24,6 +25,7 @@ struct port_chan {
int raw;
struct termios tt;
void *kernel_data;
char dev[sizeof("32768\0")];
};
void *port_init(char *str, int device, struct chan_opts *opts)
......@@ -50,11 +52,12 @@ void *port_init(char *str, int device, struct chan_opts *opts)
if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
*data = ((struct port_chan) { raw : opts->raw,
kernel_data : kern_data });
sprintf(data->dev, "%d", port);
return(data);
}
int port_open(int input, int output, int primary, void *d)
int port_open(int input, int output, int primary, void *d, char **dev_out)
{
struct port_chan *data = d;
int fd;
......@@ -64,6 +67,7 @@ int port_open(int input, int output, int primary, void *d)
tcgetattr(fd, &data->tt);
raw(fd, 0);
}
*dev_out = data->dev;
return(fd);
}
......@@ -91,6 +95,7 @@ void port_free(void *d)
}
struct chan_ops port_ops = {
type: "port",
init: port_init,
open: port_open,
close: port_close,
......
......@@ -19,6 +19,7 @@ struct pty_chan {
int dev;
int raw;
struct termios tt;
char dev_name[sizeof("/dev/pts/0123456\0")];
};
void *pty_chan_init(char *str, int device, struct chan_opts *opts)
......@@ -32,9 +33,10 @@ void *pty_chan_init(char *str, int device, struct chan_opts *opts)
return(data);
}
int pts_open(int input, int output, int primary, void *d)
int pts_open(int input, int output, int primary, void *d, char **dev_out)
{
struct pty_chan *data = d;
char *dev;
int fd;
if((fd = get_pty()) < 0){
......@@ -45,7 +47,11 @@ int pts_open(int input, int output, int primary, void *d)
tcgetattr(fd, &data->tt);
raw(fd, 0);
}
if(data->announce) (*data->announce)(ptsname(fd), data->dev);
dev = ptsname(fd);
sprintf(data->dev_name, "%s", dev);
*dev_out = data->dev_name;
if(data->announce) (*data->announce)(dev, data->dev);
return(fd);
}
......@@ -94,7 +100,7 @@ static void grantpt_cb(void *arg)
info->err = errno;
}
int pty_open(int input, int output, int primary, void *d)
int pty_open(int input, int output, int primary, void *d, char **dev_out)
{
struct pty_chan *data = d;
int fd;
......@@ -105,11 +111,14 @@ int pty_open(int input, int output, int primary, void *d)
if(fd < 0) return(-errno);
info.fd = fd;
tracing_cb(grantpt_cb, &info);
initial_thread_cb(grantpt_cb, &info);
unlockpt(fd);
if(data->raw) raw(fd, 0);
if(data->announce) (*data->announce)(dev, data->dev);
sprintf(data->dev_name, "%s", dev);
*dev_out = data->dev_name;
return(fd);
}
......@@ -121,6 +130,7 @@ int pty_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops pty_ops = {
type: "pty",
init: pty_chan_init,
open: pty_open,
close: generic_close,
......@@ -133,6 +143,7 @@ struct chan_ops pty_ops = {
};
struct chan_ops pts_ops = {
type: "pts",
init: pty_chan_init,
open: pts_open,
close: generic_close,
......
......@@ -20,6 +20,7 @@
#include "kern.h"
#include "init.h"
#include "irq_user.h"
#include "mconsole_kern.h"
#include "2_5compat.h"
static int ssl_version = 1;
......@@ -47,6 +48,10 @@ static struct chan_opts opts = {
in_kernel : 1,
};
static int ssl_config(char *str);
static int ssl_get_config(char *dev, char *str, int size, char **error_out);
static int ssl_remove(char *str);
static struct line_driver driver = {
name : "UML serial line",
devfs_name : "tts/%d",
......@@ -60,6 +65,12 @@ static struct line_driver driver = {
write_irq_name : "ssl-write",
symlink_from : "serial",
symlink_to : "tts",
mc : {
name : "ssl",
config : ssl_config,
get_config : ssl_get_config,
remove : ssl_remove,
},
};
/* The array is initialized by line_init, which is an initcall. The
......@@ -70,6 +81,25 @@ static struct line serial_lines[NR_PORTS] =
static struct lines lines = LINES_INIT(NR_PORTS);
static int ssl_config(char *str)
{
return(line_config(serial_lines,
sizeof(serial_lines)/sizeof(serial_lines[0]), str));
}
static int ssl_get_config(char *dev, char *str, int size, char **error_out)
{
return(line_get_config(dev, serial_lines,
sizeof(serial_lines)/sizeof(serial_lines[0]),
str, size, error_out));
}
static int ssl_remove(char *str)
{
return(line_remove(serial_lines,
sizeof(serial_lines)/sizeof(serial_lines[0]), str));
}
int ssl_open(struct tty_struct *tty, struct file *filp)
{
return(line_open(serial_lines, tty, &opts));
......@@ -83,12 +113,12 @@ static void ssl_close(struct tty_struct *tty, struct file * filp)
static int ssl_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
return(line_write(serial_lines, tty, buf, count));
return(line_write(serial_lines, tty, from_user, buf, count));
}
static void ssl_put_char(struct tty_struct *tty, unsigned char ch)
{
line_write(serial_lines, tty, &ch, sizeof(ch));
line_write(serial_lines, tty, 0, &ch, sizeof(ch));
}
static void ssl_flush_chars(struct tty_struct *tty)
......@@ -207,7 +237,7 @@ __initcall(ssl_init);
static int ssl_chan_setup(char *str)
{
line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]),
str);
str, 1);
return(1);
}
......
......@@ -27,6 +27,7 @@
#include "user_util.h"
#include "kern_util.h"
#include "irq_user.h"
#include "mconsole_kern.h"
#include "init.h"
#include "2_5compat.h"
......@@ -41,6 +42,7 @@ static struct tty_driver console_driver;
static int console_refcount = 0;
static struct chan_ops init_console_ops = {
type: "you shouldn't see this",
init : NULL,
open : NULL,
close : NULL,
......@@ -78,6 +80,10 @@ static struct chan_opts opts = {
in_kernel : 1,
};
static int con_config(char *str);
static int con_get_config(char *dev, char *str, int size, char **error_out);
static int con_remove(char *str);
static struct line_driver driver = {
name : "UML console",
devfs_name : "vc/%d",
......@@ -91,6 +97,12 @@ static struct line_driver driver = {
write_irq_name : "console-write",
symlink_from : "ttys",
symlink_to : "vc",
mc : {
name : "con",
config : con_config,
get_config : con_get_config,
remove : con_remove,
},
};
static struct lines console_lines = LINES_INIT(MAX_TTYS);
......@@ -102,6 +114,22 @@ struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
[ 1 ... MAX_TTYS - 1 ] =
LINE_INIT(CONFIG_CON_CHAN, &driver) };
static int con_config(char *str)
{
return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str));
}
static int con_get_config(char *dev, char *str, int size, char **error_out)
{
return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str,
size, error_out));
}
static int con_remove(char *str)
{
return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
}
static int open_console(struct tty_struct *tty)
{
return(line_open(vts, tty, &opts));
......@@ -120,7 +148,7 @@ static void con_close(struct tty_struct *tty, struct file *filp)
static int con_write(struct tty_struct *tty, int from_user,
const unsigned char *buf, int count)
{
return(line_write(vts, tty, buf, count));
return(line_write(vts, tty, from_user, buf, count));
}
static void set_termios(struct tty_struct *tty, struct termios * old)
......@@ -195,7 +223,7 @@ void stdio_console_init(void)
static int console_chan_setup(char *str)
{
line_setup(vts, sizeof(vts)/sizeof(vts[0]), str);
line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1);
return(1);
}
......
......@@ -30,14 +30,15 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts)
}
str++;
if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
if((data = um_kmalloc(sizeof(*data))) == NULL)
return(NULL);
*data = ((struct tty_chan) { dev : str,
raw : opts->raw });
return(data);
}
int tty_open(int input, int output, int primary, void *d)
int tty_open(int input, int output, int primary, void *d, char **dev_out)
{
struct tty_chan *data = d;
int fd;
......@@ -48,6 +49,8 @@ int tty_open(int input, int output, int primary, void *d)
tcgetattr(fd, &data->tt);
raw(fd, 0);
}
*dev_out = data->dev;
return(fd);
}
......@@ -59,6 +62,7 @@ int tty_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops tty_ops = {
type: "tty",
init: tty_chan_init,
open: tty_open,
close: generic_close,
......
......@@ -574,6 +574,44 @@ static int ubd_config(char *str)
return(err);
}
static int ubd_get_config(char *dev, char *str, int size, char **error_out)
{
struct ubd *ubd;
char *end;
int major, n = 0;
major = simple_strtoul(dev, &end, 0);
if((*end != '\0') || (end == dev)){
*error_out = "ubd_get_config : didn't parse major number";
return(-1);
}
if((major >= MAX_DEV) || (major < 0)){
*error_out = "ubd_get_config : major number out of range";
return(-1);
}
ubd = &ubd_dev[major];
spin_lock(&ubd_lock);
if(ubd->file == NULL){
CONFIG_CHUNK(str, size, n, "", 1);
goto out;
}
CONFIG_CHUNK(str, size, n, ubd->file, 0);
if(ubd->cow.file != NULL){
CONFIG_CHUNK(str, size, n, ",", 0);
CONFIG_CHUNK(str, size, n, ubd->cow.file, 1);
}
else CONFIG_CHUNK(str, size, n, "", 1);
out:
spin_unlock(&ubd_lock);
return(n);
}
static int ubd_remove(char *str)
{
struct ubd *dev;
......@@ -620,6 +658,7 @@ static int ubd_remove(char *str)
static struct mc_device ubd_mc = {
.name = "ubd",
.config = ubd_config,
.get_config = ubd_get_config,
.remove = ubd_remove,
};
......
......@@ -83,7 +83,7 @@ __uml_setup("xterm=", xterm_setup,
" are 'xterm=gnome-terminal,-t,-x'.\n\n"
);
int xterm_open(int input, int output, int primary, void *d)
int xterm_open(int input, int output, int primary, void *d, char **dev_out)
{
struct xterm_chan *data = d;
unsigned long stack;
......@@ -141,6 +141,7 @@ int xterm_open(int input, int output, int primary, void *d)
if(data->raw) raw(new, 0);
data->pid = pid;
*dev_out = NULL;
return(new);
}
......@@ -168,6 +169,7 @@ int xterm_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops xterm_ops = {
type: "xterm",
init: xterm_init,
open: xterm_open,
close: xterm_close,
......
......@@ -12,6 +12,7 @@
struct chan {
struct list_head list;
char *dev;
unsigned int primary:1;
unsigned int input:1;
unsigned int output:1;
......@@ -38,6 +39,8 @@ extern int chan_window_size(struct list_head *chans,
unsigned short *rows_out,
unsigned short *cols_out);
extern int chan_out_fd(struct list_head *chans);
extern int chan_config_string(struct list_head *chans, char *str, int size,
char **error_out);
#endif
......
......@@ -19,8 +19,9 @@ struct chan_opts {
enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
struct chan_ops {
char *type;
void *(*init)(char *, int, struct chan_opts *);
int (*open)(int, int, int, void *);
int (*open)(int, int, int, void *, char **);
void (*close)(int, void *);
int (*read)(int, char *, void *);
int (*write)(int, const char *, int, void *);
......@@ -43,7 +44,6 @@ extern void generic_free(void *data);
extern void register_winch(int fd, void *device_data);
extern void register_winch_irq(int fd, int tty_fd, int pid, void *line);
extern void setup_tracer_winch(void);
#define __channel_help(fn, prefix) \
__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
......
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __CHOOSE_MODE_H__
#define __CHOOSE_MODE_H__
#include "uml-config.h"
#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas))
#elif defined(CONFIG_MODE_SKAS)
#define CHOOSE_MODE(tt, skas) (skas)
#elif defined(CONFIG_MODE_TT)
#define CHOOSE_MODE(tt, skas) (tt)
#endif
#define CHOOSE_MODE_PROC(tt, skas, args...) \
CHOOSE_MODE(tt(args), skas(args))
#endif
/*
* 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:
*/
......@@ -8,34 +8,34 @@
#include "sysdep/frame.h"
struct sc_frame {
struct frame_common {
void *data;
int len;
int sig_index;
int sc_index;
int sr_index;
int sr_relative;
int sp_index;
};
struct sc_frame {
struct frame_common common;
int sc_index;
struct arch_frame_data arch;
};
extern struct sc_frame signal_frame_sc;
extern struct sc_frame signal_frame_sc_sr;
struct si_frame {
void *data;
int len;
int sig_index;
struct frame_common common;
int sip_index;
int si_index;
int sr_index;
int sr_relative;
int sp_index;
};
extern struct si_frame signal_frame_si;
extern void capture_signal_stack(void);
extern void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp);
#endif
......
......@@ -25,7 +25,6 @@ extern void *sbrk(int increment);
extern void *malloc(int size);
extern void perror(char *err);
extern int kill(int pid, int sig);
extern int getpid(void);
extern int getuid(void);
extern int pause(void);
extern int write(int, const void *, int);
......@@ -34,6 +33,7 @@ extern int close(int);
extern int read(unsigned int, char *, int);
extern int pipe(int *);
extern int sched_yield(void);
extern int ptrace(int op, int pid, long addr, long data);
#endif
/*
......
......@@ -15,23 +15,26 @@ extern char *gdb_init;
extern int kmalloc_ok;
extern int timer_irq_inited;
extern int jail;
extern int nsyscalls;
extern struct task_struct *idle_threads[NR_CPUS];
#define ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
#define ROUND_UP(addr) ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
#define UML_ROUND_UP(addr) \
UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
extern unsigned long stack_sp(unsigned long page);
extern int kernel_thread_proc(void *data);
extern void syscall_segv(int sig);
extern int current_pid(void);
extern void set_init_pid(int pid);
extern unsigned long alloc_stack(int order, int atomic);
extern int do_signal(int error);
extern int is_stack_fault(unsigned long sp);
extern unsigned long segv(unsigned long address, unsigned long ip,
int is_write, int is_user, void *sc_ptr);
extern int set_user_mode(void *task);
int is_write, int is_user, void *sc);
extern int handle_page_fault(unsigned long address, unsigned long ip,
int is_write, int is_user, int *code_out);
extern void syscall_ready(void);
extern void set_tracing(void *t, int tracing);
extern int is_tracing(void *task);
......@@ -40,7 +43,6 @@ extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
extern int page_size(void);
extern int page_mask(void);
extern int need_finish_fork(void);
extern int do_proc_op(void *t, int proc_id);
extern void free_stack(unsigned long stack, int order);
extern void add_input_request(int op, void (*proc)(int), void *arg);
extern int sys_execve(char *file, char **argv, char **env);
......@@ -57,7 +59,6 @@ extern int next_trap_index(int max);
extern void default_idle(void);
extern void finish_fork(void);
extern void paging_init(void);
extern unsigned long um_virt_to_phys(void *t, unsigned long addr);
extern void init_flush_vm(void);
extern void *syscall_sp(void *t);
extern void syscall_trace(void);
......@@ -68,35 +69,28 @@ extern int external_pid(void *t);
extern int pid_to_processor_id(int pid);
extern void boot_timer_handler(int sig);
extern void interrupt_end(void);
extern void tracing_reboot(void);
extern void tracing_halt(void);
extern void tracing_cb(void (*proc)(void *), void *arg);
extern void initial_thread_cb(void (*proc)(void *), void *arg);
extern int debugger_signal(int status, int pid);
extern void debugger_parent_signal(int status, int pid);
extern void child_signal(int pid, int status);
extern int init_ptrace_proxy(int idle_pid, int startup, int stop);
extern int init_parent_proxy(int pid);
extern int singlestepping(void *t);
extern void check_stack_overflow(void *ptr);
extern void relay_signal(int sig, struct uml_pt_regs *regs);
extern int singlestepping(void *t);
extern void clear_singlestep(void *t);
extern void not_implemented(void);
extern int user_context(unsigned long sp);
extern void timer_irq(struct uml_pt_regs *regs);
extern void unprotect_stack(unsigned long stack);
extern void do_uml_exitcalls(void);
extern int attach_debugger(int idle_pid, int pid, int stop);
extern void *round_up(unsigned long addr);
extern void *round_down(unsigned long addr);
extern void bad_segv(unsigned long address, unsigned long ip, int is_write);
extern int config_gdb(char *str);
extern int remove_gdb(void);
extern char *uml_strdup(char *string);
extern void unprotect_kernel_mem(void);
extern void protect_kernel_mem(void);
extern unsigned long get_kmem_end(void);
extern void set_kmem_end(unsigned long);
extern void set_task_sizes(int arg);
extern void uml_cleanup(void);
extern int pid_to_processor_id(int pid);
extern void set_current(void *t);
......@@ -107,7 +101,6 @@ extern void *get_init_task(void);
extern int clear_user_proc(void *buf, int size);
extern int copy_to_user_proc(void *to, void *from, int size);
extern int copy_from_user_proc(void *to, void *from, int size);
extern void set_thread_sc(void *sc);
extern void bus_handler(int sig, struct uml_pt_regs *regs);
extern long execute_syscall(void *r);
extern int smp_sigio_handler(void);
......@@ -116,7 +109,6 @@ extern struct task_struct *get_task(int pid, int require);
extern void machine_halt(void);
extern int is_syscall(unsigned long addr);
extern void arch_switch(void);
extern int is_valid_pid(int pid);
extern void free_irq(unsigned int, void *);
extern int um_in_interrupt(void);
extern int cpu(void);
......
......@@ -11,6 +11,7 @@
#include "linux/tty.h"
#include "asm/semaphore.h"
#include "chan_user.h"
#include "mconsole_kern.h"
struct line_driver {
char *name;
......@@ -25,6 +26,7 @@ struct line_driver {
char *write_irq_name;
char *symlink_from;
char *symlink_to;
struct mc_device mc;
};
struct line {
......@@ -70,8 +72,9 @@ extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
extern void line_close(struct line *lines, struct tty_struct *tty);
extern int line_open(struct line *lines, struct tty_struct *tty,
struct chan_opts *opts);
extern void line_setup(struct line *lines, int num, char *init);
extern int line_write(struct line *line, struct tty_struct *tty,
extern int line_setup(struct line *lines, int num, char *init,
int all_allowed);
extern int line_write(struct line *line, struct tty_struct *tty, int from_user,
const char *buf, int len);
extern int line_write_room(struct tty_struct *tty);
extern char *add_xterm_umid(char *base);
......@@ -84,6 +87,10 @@ extern void line_register_devfs(struct lines *set,
int nlines);
extern void lines_init(struct line *lines, int nlines);
extern void close_lines(struct line *lines, int nlines);
extern int line_config(struct line *lines, int num, char *str);
extern int line_remove(struct line *lines, int num, char *str);
extern int line_get_config(char *dev, struct line *lines, int num, char *str,
int size, char **error_out);
#endif
......
/*
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
......@@ -19,9 +19,23 @@ struct mc_device {
struct list_head list;
char *name;
int (*config)(char *);
int (*get_config)(char *, char *, int, char **);
int (*remove)(char *);
};
#define CONFIG_CHUNK(str, size, current, chunk, end) \
do { \
current += strlen(chunk); \
if(current >= size) \
str = NULL; \
if(str != NULL){ \
strcpy(str, chunk); \
str += strlen(chunk); \
} \
if(end) \
current++; \
} while(0)
#ifdef CONFIG_MCONSOLE
extern void mconsole_register_dev(struct mc_device *new);
......
......@@ -13,6 +13,7 @@ struct vm_reserved {
};
extern void set_usable_vm(unsigned long start, unsigned long end);
extern void set_kmem_end(unsigned long new);
#endif
......
......@@ -54,11 +54,6 @@ extern int create_mem_file(unsigned long len);
extern void setup_range(int fd, char *driver, unsigned long start,
unsigned long pfn, unsigned long total, int need_vm,
struct mem_region *region, void *reserved);
extern void map(unsigned long virt, unsigned long p, unsigned long len,
int r, int w, int x);
extern int unmap(void *addr, int len);
extern int protect(unsigned long addr, unsigned long len, int r, int w,
int x, int must_succeed);
extern void setup_memory(void *entry);
extern unsigned long find_iomem(char *driver, unsigned long *len_out);
extern int init_maps(struct mem_region *region);
......@@ -68,10 +63,15 @@ extern unsigned long get_vm(unsigned long len);
extern void setup_physmem(unsigned long start, unsigned long usable,
unsigned long len);
extern int setup_region(struct mem_region *region, void *entry);
extern void add_iomem(char *name, int fd, int size);
extern void add_iomem(char *name, int fd, unsigned long size);
extern struct mem_region *phys_region(unsigned long phys);
extern unsigned long phys_offset(unsigned long phys);
extern void unmap_physmem(void);
extern int map_memory(unsigned long virt, unsigned long phys,
unsigned long len, int r, int w, int x);
extern int protect_memory(unsigned long addr, unsigned long len,
int r, int w, int x, int must_succeed);
extern unsigned long get_kmem_end(void);
#endif
......
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __MODE_H__
#define __MODE_H__
#include "uml-config.h"
#ifdef CONFIG_MODE_TT
#include "../kernel/tt/include/mode.h"
#endif
#ifdef CONFIG_MODE_SKAS
#include "../kernel/skas/include/mode.h"
#endif
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __MODE_KERN_H__
#define __MODE_KERN_H__
#include "linux/config.h"
#ifdef CONFIG_MODE_TT
#include "../kernel/tt/include/mode_kern.h"
#endif
#ifdef CONFIG_MODE_SKAS
#include "../kernel/skas/include/mode_kern.h"
#endif
#endif
/*
* 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:
*/
......@@ -103,10 +103,16 @@ extern int os_write_file(int fd, char *buf, int count);
extern unsigned long os_process_pc(int pid);
extern int os_process_parent(int pid);
extern void os_stop_process(int pid);
extern void os_kill_process(int pid);
extern void os_kill_process(int pid, int reap_child);
extern void os_usr1_process(int pid);
extern int os_getpid(void);
extern int os_map_memory(void *virt, int fd, unsigned long off,
unsigned long len, int r, int w, int x);
extern int os_protect_memory(void *addr, unsigned long len,
int r, int w, int x);
extern int os_unmap_memory(void *addr, int len);
#endif
/*
......
......@@ -9,8 +9,6 @@
#include "sysdep/sigcontext.h"
extern int sc_size(void *data);
extern int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data);
extern int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data);
extern void sc_to_sc(void *to_ptr, void *from_ptr);
#endif
......
/*
* Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SYSCALL_USER_H__
#define __SYSCALL_USER_H__
#ifndef __SYSCALL_USER_H
#define __SYSCALL_USER_H
#include <asm/sigcontext.h>
extern void syscall_handler(int sig, struct uml_pt_regs *regs);
extern void exit_kernel(int pid, void *task);
extern int do_syscall(void *task, int pid);
extern int record_syscall_start(int syscall);
extern void record_syscall_end(int index, int result);
#endif
......
/*
* Licensed under the GPL
*/
#ifndef __UM_SYSDEP_CHECKSUM_H
#define __UM_SYSDEP_CHECKSUM_H
#include "linux/string.h"
/*
* computes the checksum of a memory block at buff, length len,
* and adds in "sum" (32-bit)
*
* returns a 32-bit number suitable for feeding into itself
* or csum_tcpudp_magic
*
* this function must be called with even lengths, except
* for the last fragment, which may be odd
*
* it's best to have buff aligned on a 32-bit boundary
*/
unsigned int csum_partial(const unsigned char * buff, int len,
unsigned int sum);
/*
* the same as csum_partial, but copies from src while it
* checksums, and handles user-space pointer exceptions correctly, when needed.
*
* here even more important to align src and dst on a 32-bit (or even
* better 64-bit) boundary
*/
unsigned int csum_partial_copy_to(const char *src, char *dst, int len,
int sum, int *err_ptr);
unsigned int csum_partial_copy_from(const char *src, char *dst, int len,
int sum, int *err_ptr);
/*
* Note: when you get a NULL pointer exception here this means someone
* passed in an incorrect kernel address to one of these functions.
*
* If you use these functions directly please don't forget the
* verify_area().
*/
static __inline__
unsigned int csum_partial_copy_nocheck(const char *src, char *dst,
int len, int sum)
{
memcpy(dst, src, len);
return(csum_partial(dst, len, sum));
}
static __inline__
unsigned int csum_partial_copy_from_user(const char *src, char *dst,
int len, int sum, int *err_ptr)
{
return csum_partial_copy_from(src, dst, len, sum, err_ptr);
}
/*
* These are the old (and unsafe) way of doing checksums, a warning message
* will be printed if they are used and an exeption occurs.
*
* these functions should go away after some time.
*/
#define csum_partial_copy_fromuser csum_partial_copy_from_user
unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
/*
* This is a version of ip_compute_csum() optimized for IP headers,
* which always checksum on 4 octet boundaries.
*
* By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
* Arnt Gulbrandsen.
*/
static inline unsigned short ip_fast_csum(unsigned char * iph,
unsigned int ihl)
{
unsigned int sum;
__asm__ __volatile__(
"movl (%1), %0 ;\n"
"subl $4, %2 ;\n"
"jbe 2f ;\n"
"addl 4(%1), %0 ;\n"
"adcl 8(%1), %0 ;\n"
"adcl 12(%1), %0 ;\n"
"1: adcl 16(%1), %0 ;\n"
"lea 4(%1), %1 ;\n"
"decl %2 ;\n"
"jne 1b ;\n"
"adcl $0, %0 ;\n"
"movl %0, %2 ;\n"
"shrl $16, %0 ;\n"
"addw %w2, %w0 ;\n"
"adcl $0, %0 ;\n"
"notl %0 ;\n"
"2: ;\n"
/* Since the input registers which are loaded with iph and ipl
are modified, we must also specify them as outputs, or gcc
will assume they contain their original values. */
: "=r" (sum), "=r" (iph), "=r" (ihl)
: "1" (iph), "2" (ihl));
return(sum);
}
/*
* Fold a partial checksum
*/
static inline unsigned int csum_fold(unsigned int sum)
{
__asm__(
"addl %1, %0 ;\n"
"adcl $0xffff, %0 ;\n"
: "=r" (sum)
: "r" (sum << 16), "0" (sum & 0xffff0000)
);
return (~sum) >> 16;
}
static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
unsigned long daddr,
unsigned short len,
unsigned short proto,
unsigned int sum)
{
__asm__(
"addl %1, %0 ;\n"
"adcl %2, %0 ;\n"
"adcl %3, %0 ;\n"
"adcl $0, %0 ;\n"
: "=r" (sum)
: "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
return sum;
}
/*
* computes the checksum of the TCP/UDP pseudo-header
* returns a 16-bit checksum, already complemented
*/
static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
unsigned long daddr,
unsigned short len,
unsigned short proto,
unsigned int sum)
{
return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
}
/*
* this routine is used for miscellaneous IP-like checksums, mainly
* in icmp.c
*/
static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
{
return csum_fold (csum_partial(buff, len, 0));
}
#define _HAVE_ARCH_IPV6_CSUM
static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
struct in6_addr *daddr,
__u32 len,
unsigned short proto,
unsigned int sum)
{
__asm__(
"addl 0(%1), %0 ;\n"
"adcl 4(%1), %0 ;\n"
"adcl 8(%1), %0 ;\n"
"adcl 12(%1), %0 ;\n"
"adcl 0(%2), %0 ;\n"
"adcl 4(%2), %0 ;\n"
"adcl 8(%2), %0 ;\n"
"adcl 12(%2), %0 ;\n"
"adcl %3, %0 ;\n"
"adcl %4, %0 ;\n"
"adcl $0, %0 ;\n"
: "=&r" (sum)
: "r" (saddr), "r" (daddr),
"r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
return csum_fold(sum);
}
/*
* Copy and checksum to user
*/
#define HAVE_CSUM_COPY_USER
static __inline__ unsigned int csum_and_copy_to_user(const char *src,
char *dst, int len,
int sum, int *err_ptr)
{
if (access_ok(VERIFY_WRITE, dst, len))
return(csum_partial_copy_to(src, dst, len, sum, err_ptr));
if (len)
*err_ptr = -EFAULT;
return -1; /* invalid checksum */
}
#endif
/*
* 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:
*/
......@@ -20,7 +20,8 @@ static inline void *sp_to_rt_sc(unsigned long sp)
{
unsigned long sc;
sc = sp - signal_frame_si.sp_index + signal_frame_si.len - 4;
sc = sp - signal_frame_si.common.sp_index +
signal_frame_si.common.len - 4;
return((void *) sc);
}
......@@ -28,7 +29,8 @@ static inline void *sp_to_mask(unsigned long sp)
{
unsigned long mask;
mask = sp - signal_frame_sc.sp_index + signal_frame_sc.len - 8;
mask = sp - signal_frame_sc.common.sp_index +
signal_frame_sc.common.len - 8;
return((void *) mask);
}
......@@ -38,7 +40,8 @@ static inline void *sp_to_rt_mask(unsigned long sp)
{
unsigned long mask;
mask = sp - signal_frame_si.sp_index + signal_frame_si.len +
mask = sp - signal_frame_si.common.sp_index +
signal_frame_si.common.len +
sc_size(&signal_frame_sc.arch) - 4;
return((void *) mask);
}
......
/*
* Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SYSDEP_I386_PTRACE_H
#define __SYSDEP_I386_PTRACE_H
#include "sysdep/sc.h"
#include "uml-config.h"
#include "ptrace-tt.h"
#include "ptrace-skas.h"
#include "choose-mode.h"
struct uml_pt_regs {
unsigned long args[6];
long syscall;
int is_user;
void *sc;
union {
#ifdef CONFIG_MODE_TT
void *tt;
#endif
#ifdef CONFIG_MODE_SKAS
struct {
unsigned long regs[HOST_FRAME_SIZE];
unsigned long fp[HOST_FP_SIZE];
unsigned long xfp[HOST_XFP_SIZE];
unsigned long fault_addr;
unsigned long fault_type;
unsigned long trap_type;
} skas;
#endif
} mode;
};
#define EMPTY_UML_PT_REGS { \
syscall : -1, \
args : { [0 ... 5] = 0 }, \
is_user : 0, \
sc : NULL }
#define UPT_IP(regs) SC_IP((regs)->sc)
#define UPT_SP(regs) SC_SP((regs)->sc)
#define UPT_EFLAGS(regs) SC_EFLAGS((regs)->sc)
#define UPT_EAX(regs) SC_EAX((regs)->sc)
#define UPT_EBX(regs) SC_EBX((regs)->sc)
#define UPT_ECX(regs) SC_ECX((regs)->sc)
#define UPT_EDX(regs) SC_EDX((regs)->sc)
#define UPT_ESI(regs) SC_ESI((regs)->sc)
#define UPT_EDI(regs) SC_EDI((regs)->sc)
#define UPT_EBP(regs) SC_EBP((regs)->sc)
#define UPT_ORIG_EAX(regs) ((regs)->syscall)
#define UPT_CS(regs) SC_CS((regs)->sc)
#define UPT_SS(regs) SC_SS((regs)->sc)
#define UPT_DS(regs) SC_DS((regs)->sc)
#define UPT_ES(regs) SC_ES((regs)->sc)
#define UPT_FS(regs) SC_FS((regs)->sc)
#define UPT_GS(regs) SC_GS((regs)->sc)
#define UPT_SC(regs) ((regs)->sc)
is_user : 0 }
extern int mode_tt;
#define UPT_IP(r) \
CHOOSE_MODE(SC_IP((r)->mode.tt), REGS_IP((r)->mode.skas.regs))
#define UPT_SP(r) \
CHOOSE_MODE(SC_SP((r)->mode.tt), REGS_SP((r)->mode.skas.regs))
#define UPT_EFLAGS(r) \
CHOOSE_MODE(SC_EFLAGS((r)->mode.tt), REGS_EFLAGS((r)->mode.skas.regs))
#define UPT_EAX(r) \
CHOOSE_MODE(SC_EAX((r)->mode.tt), REGS_EAX((r)->mode.skas.regs))
#define UPT_EBX(r) \
CHOOSE_MODE(SC_EBX((r)->mode.tt), REGS_EBX((r)->mode.skas.regs))
#define UPT_ECX(r) \
CHOOSE_MODE(SC_ECX((r)->mode.tt), REGS_ECX((r)->mode.skas.regs))
#define UPT_EDX(r) \
CHOOSE_MODE(SC_EDX((r)->mode.tt), REGS_EDX((r)->mode.skas.regs))
#define UPT_ESI(r) \
CHOOSE_MODE(SC_ESI((r)->mode.tt), REGS_ESI((r)->mode.skas.regs))
#define UPT_EDI(r) \
CHOOSE_MODE(SC_EDI((r)->mode.tt), REGS_EDI((r)->mode.skas.regs))
#define UPT_EBP(r) \
CHOOSE_MODE(SC_EBP((r)->mode.tt), REGS_EBP((r)->mode.skas.regs))
#define UPT_ORIG_EAX(r) ((r)->syscall)
#define UPT_CS(r) \
CHOOSE_MODE(SC_CS((r)->mode.tt), REGS_CS((r)->mode.skas.regs))
#define UPT_SS(r) \
CHOOSE_MODE(SC_SS((r)->mode.tt), REGS_SS((r)->mode.skas.regs))
#define UPT_DS(r) \
CHOOSE_MODE(SC_DS((r)->mode.tt), REGS_DS((r)->mode.skas.regs))
#define UPT_ES(r) \
CHOOSE_MODE(SC_ES((r)->mode.tt), REGS_ES((r)->mode.skas.regs))
#define UPT_FS(r) \
CHOOSE_MODE(SC_FS((r)->mode.tt), REGS_FS((r)->mode.skas.regs))
#define UPT_GS(r) \
CHOOSE_MODE(SC_GS((r)->mode.tt), REGS_GS((r)->mode.skas.regs))
#define UPT_SC(r) ((r)->mode.tt)
#define UPT_REG(regs, reg) \
({ unsigned long val; \
......@@ -94,12 +128,29 @@ struct uml_pt_regs {
} \
} while (0)
#define UPT_SET_SYSCALL_RETURN(regs, res) \
SC_SET_SYSCALL_RETURN((regs)->sc, (res))
#define UPT_RESTART_SYSCALL(regs) SC_RESTART_SYSCALL((regs)->sc)
#define UPT_ORIG_SYSCALL(regs) UPT_EAX(regs)
#define UPT_SYSCALL_NR(regs) ((regs)->syscall)
#define UPT_SYSCALL_RET(regs) UPT_EAX(regs)
#define UPT_SET_SYSCALL_RETURN(r, res) \
CHOOSE_MODE(SC_SET_SYSCALL_RETURN((r)->mode.tt, (res)), \
REGS_SET_SYSCALL_RETURN((r)->mode.skas.regs, (res)))
#define UPT_RESTART_SYSCALL(r) \
CHOOSE_MODE(SC_RESTART_SYSCALL((r)->mode.tt), \
REGS_RESTART_SYSCALL((r)->mode.skas.regs))
#define UPT_ORIG_SYSCALL(r) UPT_EAX(r)
#define UPT_SYSCALL_NR(r) ((r)->syscall)
#define UPT_SYSCALL_RET(r) UPT_EAX(r)
#define UPT_SEGV_IS_FIXABLE(r) \
CHOOSE_MODE(SC_SEGV_IS_FIXABLE(r->mode.tt), \
REGS_SEGV_IS_FIXABLE(&r->mode.skas))
#define UPT_FAULT_ADDR(r) \
CHOOSE_MODE(SC_FAULT_ADDR(r->mode.tt), \
REGS_FAULT_ADDR(&r->mode.skas))
#define UPT_FAULT_WRITE(r) \
CHOOSE_MODE(SC_FAULT_WRITE(r->mode.tt), \
REGS_FAULT_WRITE(&r->mode.skas))
#endif
......
......@@ -6,13 +6,22 @@
#ifndef __SYS_SIGCONTEXT_I386_H
#define __SYS_SIGCONTEXT_I386_H
#include "sc.h"
#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc))
#define SC_SET_SYSCALL_RETURN(sc, result) do SC_EAX(sc) = (result) ; while(0)
#define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result)
#define SC_FAULT_ADDR(sc) SC_CR2(sc)
#define SC_FAULT_WRITE(sc) (SC_ERR(sc) & 2)
#define SC_FAULT_TYPE(sc) SC_ERR(sc)
#define FAULT_WRITE(err) (err & 2)
#define TO_SC_ERR(is_write) ((is_write) ? 2 : 0)
#define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc)))
#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc)
/* ptrace expects that, at the start of a system call, %eax contains
* -ENOSYS, so this makes it so.
......@@ -20,10 +29,12 @@
#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
/* These are General Protection and Page Fault */
#define SEGV_IS_FIXABLE(sc) ((SC_TRAPNO(sc) == 13) || (SC_TRAPNO(sc) == 14))
#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14))
/* XXX struct sigcontext needs declaring by now */
#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc)))
#ifdef CONFIG_MODE_TT
/* XXX struct sigcontext needs declaring by now */
static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc,
unsigned long syscall)
{
......@@ -35,6 +46,20 @@ static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc,
regs->args[4] = SC_EDI(sc);
regs->args[5] = SC_EBP(sc);
}
#endif
#ifdef CONFIG_MODE_SKAS
static inline void host_to_regs(struct uml_pt_regs *regs)
{
regs->syscall = UPT_ORIG_EAX(regs);
regs->args[0] = UPT_EBX(regs);
regs->args[1] = UPT_ECX(regs);
regs->args[2] = UPT_EDX(regs);
regs->args[3] = UPT_ESI(regs);
regs->args[4] = UPT_EDI(regs);
regs->args[5] = UPT_EBP(regs);
}
#endif
extern unsigned long *sc_sigmask(void *sc_ptr);
extern int sc_get_fpregs(unsigned long buf, void *sc_ptr);
......
......@@ -8,7 +8,7 @@
extern void timer(void);
extern void switch_timers(int to_real);
extern void user_time_init(void);
extern void set_interval(int timer_type);
extern void idle_sleep(int secs);
extern void enable_timer(void);
extern void time_lock(void);
......
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __ARCH_UM_MMU_H
#define __ARCH_UM_MMU_H
#include "linux/config.h"
#include "choose-mode.h"
#ifdef CONFIG_MODE_TT
#include "../kernel/tt/include/mmu.h"
#endif
#ifdef CONFIG_MODE_SKAS
#include "../kernel/skas/include/mmu.h"
#endif
typedef union {
#ifdef CONFIG_MODE_TT
struct mmu_context_tt tt;
#endif
#ifdef CONFIG_MODE_SKAS
struct mmu_context_skas skas;
#endif
} mm_context_t;
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __ARCH_UM_UACCESS_H
#define __ARCH_UM_UACCESS_H
#include "linux/config.h"
#include "choose-mode.h"
#ifdef CONFIG_MODE_TT
#include "../kernel/tt/include/uaccess.h"
#endif
#ifdef CONFIG_MODE_SKAS
#include "../kernel/skas/include/uaccess.h"
#endif
#define access_ok(type, addr, size) \
CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
static inline int verify_area(int type, const void * addr, unsigned long size)
{
return(CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr,
size));
}
static inline int copy_from_user(void *to, const void *from, int n)
{
return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to,
from, n));
}
static inline int copy_to_user(void *to, const void *from, int n)
{
return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to,
from, n));
}
static inline int strncpy_from_user(char *dst, const char *src, int count)
{
return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas,
dst, src, count));
}
static inline int __clear_user(void *mem, int len)
{
return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len));
}
static inline int clear_user(void *mem, int len)
{
return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len));
}
static inline int strnlen_user(const void *str, int len)
{
return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len));
}
#endif
/*
* 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:
*/
......@@ -8,6 +8,8 @@
#include "sysdep/ptrace.h"
extern int mode_tt;
extern int grantpt(int __fd);
extern int unlockpt(int __fd);
extern char *ptsname(int __fd);
......@@ -21,6 +23,13 @@ struct cpu_task {
extern struct cpu_task cpu_tasks[];
struct signal_info {
void (*handler)(int, struct uml_pt_regs *);
int is_irq;
};
extern struct signal_info sig_info[];
extern unsigned long low_physmem;
extern unsigned long high_physmem;
extern unsigned long uml_physmem;
......@@ -29,16 +38,11 @@ extern unsigned long end_vm;
extern unsigned long start_vm;
extern unsigned long highmem;
extern int tracing_pid;
extern int honeypot;
extern char host_info[];
extern char saved_command_line[];
extern char command_line[];
extern int gdb_pid;
extern char *tempdir;
extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
......@@ -51,12 +55,10 @@ extern int pty_close_sigio;
extern void stop(void);
extern void stack_protections(unsigned long address);
extern void task_protections(unsigned long address);
extern int signals(int (*init_proc)(void *), void *sp);
extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
extern void *add_signal_handler(int sig, void (*handler)(int));
extern int start_fork_tramp(void *arg, unsigned long temp_stack,
int clone_flags, int (*tramp)(void *));
extern void trace_myself(void);
extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
extern int linux_main(int argc, char **argv);
extern void remap_data(void *segment_start, void *segment_end, int w);
......@@ -69,13 +71,12 @@ extern int switcheroo(int fd, int prot, void *from, void *to, int size);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(void);
extern void add_arg(char *cmd_line, char *arg);
extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int));
extern void attach_process(int pid);
extern int fork_tramp(void *sig_stack);
extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
extern void init_new_thread_signals(int altstack);
extern void do_exec(int old_pid, int new_pid);
extern void tracer_panic(char *msg, ...);
extern char *get_umid(int only_if_set);
extern void do_longjmp(void *p);
extern void do_longjmp(void *p, int val);
extern void suspend_new_thread(int fd);
extern int detach(int pid, int sig);
extern int attach(int pid);
......@@ -89,7 +90,8 @@ extern void arch_check_bugs(void);
extern int arch_handle_signal(int sig, struct uml_pt_regs *regs);
extern int arch_fixup(unsigned long address, void *sc_ptr);
extern void forward_pending_sigio(int target);
extern int can_do_skas(void);
#endif
/*
......
#
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
EXTRA_TARGETS := unmap_fin.o
obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \
obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \
helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \
process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \
sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \
syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \
time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \
time_kern.o tlb.o trap_kern.o trap_user.o um_arch.o \
umid.o user_util.o
obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
obj-$(CONFIG_GPROF) += gprof_syms.o
obj-$(CONFIG_GCOV) += gmon_syms.o
obj-$(CONFIG_TTY_LOG) += tty_log.o
# user_syms.o not included here because kbuild has its own ideas about
# building anything in export-objs
obj-$(CONFIG_MODE_TT) += tt/
obj-$(CONFIG_MODE_SKAS) += skas/
USER_OBJS := $(filter %_user.o,$(obj-y)) config.o helper.o process.o \
tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o
USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/kernel/$(file))
user-objs-$(CONFIG_TTY_LOG) += tty_log.o
export-objs := ksyms.o process_kern.o signal_kern.o gprof_syms.o gmon_syms.o
# user_syms.o not included here because Rules.make has its own ideas about
# building anything in export-objs
USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \
process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
ifeq ($(CONFIG_MODULES), y)
DMODULES = -D__CONFIG_MODULES__
endif
DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__
DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__
ifeq ($(CONFIG_MODVERSIONS), y)
DMODVERSIONS = -D__CONFIG_MODVERSIONS__
endif
export-objs-$(CONFIG_GPROF) += gprof_syms.o
export-objs-$(CONFIG_GCOV) += gmon_syms.o
obj-$(CONFIG_GPROF) += gprof_syms.o
obj-$(CONFIG_GCOV) += gmon_syms.o
obj-$(CONFIG_TTY_LOG) += tty_log.o
export-objs := ksyms.o process_kern.o signal_kern.o $(export-objs-y)
CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES) $(DMODVERSIONS) \
CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \
-I/usr/include -I../include
CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
......@@ -42,27 +49,28 @@ CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
arch/um/kernel/unmap.o: arch/um/kernel/unmap.c
$(obj)/unmap.o: $(src)/unmap.c
$(CC) $(UNMAP_CFLAGS) -c -o $@ $<
arch/um/kernel/unmap_fin.o : arch/um/kernel/unmap.o
$(obj)/unmap_fin.o : $(src)/unmap.o
ld -r -o $@ $< -lc -L/usr/lib
# This has to be separate because it needs be compiled with frame pointers
# regardless of how the rest of the kernel is built.
arch/um/kernel/frame.o: arch/um/kernel/frame.c
$(obj)/frame.o: $(src)/frame.c
$(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $<
QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
arch/um/kernel/config.c : arch/um/kernel/config.c.in $(TOPDIR)/.config
$(PERL) -e $(QUOTE) < arch/um/kernel/config.c.in > $@
$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config
$(PERL) -e $(QUOTE) < $(src)/config.c.in > $@
arch/um/kernel/config.o : arch/um/kernel/config.c
$(obj)/config.o : $(obj)/config.c
clean:
rm -f config.c
for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done
modules:
......
#include "asm/uaccess.h"
#include "linux/errno.h"
extern unsigned int arch_csum_partial(const char *buff, int len, int sum);
extern unsigned int csum_partial(char *buff, int len, int sum)
{
return(arch_csum_partial(buff, len, sum));
}
unsigned int csum_partial_copy_to(const char *src, char *dst, int len,
int sum, int *err_ptr)
{
if(copy_to_user(dst, src, len)){
*err_ptr = -EFAULT;
return(-1);
}
return(arch_csum_partial(src, len, sum));
}
unsigned int csum_partial_copy_from(const char *src, char *dst, int len,
int sum, int *err_ptr)
{
if(copy_from_user(dst, src, len)){
*err_ptr = -EFAULT;
return(-1);
}
return(arch_csum_partial(dst, len, sum));
}
/*
* 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:
*/
......@@ -18,65 +18,17 @@
#include "2_5compat.h"
#include "os.h"
#include "time_user.h"
/* See comment above fork_tramp for why sigstop is defined and used like
* this
*/
static int sigstop = SIGSTOP;
static int exec_tramp(void *sig_stack)
{
int sig = sigstop;
init_new_thread(sig_stack, NULL);
kill(os_getpid(), sig);
return(0);
}
#include "choose-mode.h"
#include "mode_kern.h"
void flush_thread(void)
{
unsigned long stack;
int new_pid;
stack = alloc_stack(0, 0);
if(stack == 0){
printk(KERN_ERR
"flush_thread : failed to allocate temporary stack\n");
do_exit(SIGKILL);
}
new_pid = start_fork_tramp((void *) current->thread.kernel_stack,
stack, 0, exec_tramp);
if(new_pid < 0){
printk(KERN_ERR
"flush_thread : new thread failed, errno = %d\n",
-new_pid);
do_exit(SIGKILL);
}
if(current->thread_info->cpu == 0)
forward_interrupts(new_pid);
current->thread.request.op = OP_EXEC;
current->thread.request.u.exec.pid = new_pid;
unprotect_stack((unsigned long) current->thread_info);
os_usr1_process(os_getpid());
enable_timer();
free_page(stack);
protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
task_protections((unsigned long) current->thread_info);
force_flush_all();
unblock_signals();
CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
}
void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
{
set_fs(USER_DS);
flush_tlb_mm(current->mm);
PT_REGS_IP(regs) = eip;
PT_REGS_SP(regs) = esp;
PT_FIX_EXEC_STACK(esp);
CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
}
static int execve1(char *file, char **argv, char **env)
......@@ -93,8 +45,12 @@ static int execve1(char *file, char **argv, char **env)
int um_execve(char *file, char **argv, char **env)
{
if(execve1(file, argv, env) == 0) do_longjmp(current->thread.jmp);
return(-1);
int err;
err = execve1(file, argv, env);
if(!err)
do_longjmp(current->thread.exec_buf, 1);
return(err);
}
int sys_execve(char *file, char **argv, char **env)
......
......@@ -12,6 +12,7 @@
#include <sched.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <asm/page.h>
#include <asm/ptrace.h>
......@@ -84,8 +85,8 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
printf("capture_stack : waitpid failed - errno = %d\n", errno);
exit(1);
}
if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
printf("capture_stack : Expected exit status 0, "
if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){
printf("capture_stack : Expected exit signal 9, "
"got status = 0x%x\n", status);
exit(1);
}
......@@ -103,28 +104,61 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
return(len);
}
static void child_common(void *sp, int size, sighandler_t handler, int flags)
struct common_raw {
void *stack;
int size;
unsigned long sig;
unsigned long sr;
unsigned long sp;
};
#define SA_RESTORER (0x04000000)
typedef unsigned long old_sigset_t;
struct old_sigaction {
__sighandler_t handler;
old_sigset_t sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
};
static void child_common(struct common_raw *common, sighandler_t handler,
int restorer, int flags)
{
stack_t ss;
struct sigaction sa;
stack_t ss = ((stack_t) { .ss_sp = common->stack,
.ss_flags = 0,
.ss_size = common->size });
int err;
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
printf("PTRACE_TRACEME failed, errno = %d\n", errno);
}
ss.ss_sp = sp;
ss.ss_flags = 0;
ss.ss_size = size;
if(sigaltstack(&ss, NULL) < 0){
printf("sigaltstack failed - errno = %d\n", errno);
_exit(1);
kill(getpid(), SIGKILL);
}
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK | flags;
if(sigaction(SIGUSR1, &sa, NULL) < 0){
if(restorer){
struct sigaction sa;
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK | flags;
err = sigaction(SIGUSR1, &sa, NULL);
}
else {
struct old_sigaction sa;
sa.handler = handler;
sa.sa_mask = 0;
sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER;
err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL);
}
if(err < 0){
printf("sigaction failed - errno = %d\n", errno);
_exit(1);
kill(getpid(), SIGKILL);
}
os_stop_process(os_getpid());
......@@ -133,13 +167,12 @@ static void child_common(void *sp, int size, sighandler_t handler, int flags)
/* Changed only during early boot */
struct sc_frame signal_frame_sc;
struct sc_frame signal_frame_sc_sr;
struct sc_frame_raw {
void *stack;
int size;
unsigned long sig;
struct common_raw common;
unsigned long sc;
unsigned long sr;
unsigned long sp;
int restorer;
struct arch_frame_data_raw arch;
};
......@@ -148,20 +181,20 @@ static struct sc_frame_raw *raw_sc = NULL;
static void sc_handler(int sig, struct sigcontext sc)
{
raw_sc->sig = (unsigned long) &sig;
raw_sc->common.sig = (unsigned long) &sig;
raw_sc->common.sr = frame_restorer();
raw_sc->common.sp = frame_sp();
raw_sc->sc = (unsigned long) &sc;
raw_sc->sr = frame_restorer();
raw_sc->sp = frame_sp();
setup_arch_frame_raw(&raw_sc->arch, &sc);
os_stop_process(os_getpid());
_exit(0);
kill(getpid(), SIGKILL);
}
static int sc_child(void *arg)
{
raw_sc = arg;
child_common(raw_sc->stack, raw_sc->size, (sighandler_t) sc_handler,
0);
child_common(&raw_sc->common, (sighandler_t) sc_handler,
raw_sc->restorer, 0);
return(-1);
}
......@@ -169,13 +202,9 @@ static int sc_child(void *arg)
struct si_frame signal_frame_si;
struct si_frame_raw {
void *stack;
int size;
unsigned long sig;
struct common_raw common;
unsigned long sip;
unsigned long si;
unsigned long sr;
unsigned long sp;
};
/* Changed only during early boot */
......@@ -183,23 +212,59 @@ static struct si_frame_raw *raw_si = NULL;
static void si_handler(int sig, siginfo_t *si)
{
raw_si->sig = (unsigned long) &sig;
raw_si->common.sig = (unsigned long) &sig;
raw_si->common.sr = frame_restorer();
raw_si->common.sp = frame_sp();
raw_si->sip = (unsigned long) &si;
raw_si->si = (unsigned long) si;
raw_si->sr = frame_restorer();
raw_si->sp = frame_sp();
os_stop_process(os_getpid());
_exit(0);
kill(getpid(), SIGKILL);
}
static int si_child(void *arg)
{
raw_si = arg;
child_common(raw_si->stack, raw_si->size, (sighandler_t) si_handler,
SA_SIGINFO);
child_common(&raw_si->common, (sighandler_t) si_handler, 1,
SA_SIGINFO);
return(-1);
}
static int relative_sr(unsigned long sr, int sr_index, void *stack,
void *framep)
{
unsigned long *srp = (unsigned long *) sr;
unsigned long frame = (unsigned long) framep;
if((*srp & PAGE_MASK) == (unsigned long) stack){
*srp -= sr;
*((unsigned long *) (frame + sr_index)) = *srp;
return(1);
}
else return(0);
}
static unsigned long capture_stack_common(int (*proc)(void *), void *arg,
struct common_raw *common_in,
void *top, void *sigstack,
int stack_len,
struct frame_common *common_out)
{
unsigned long sig_top = (unsigned long) sigstack + stack_len, base;
common_in->stack = (void *) sigstack;
common_in->size = stack_len;
common_out->len = capture_stack(proc, arg, top, sig_top,
&common_out->data);
base = sig_top - common_out->len;
common_out->sig_index = common_in->sig - base;
common_out->sp_index = common_in->sp - base;
common_out->sr_index = common_in->sr - base;
common_out->sr_relative = relative_sr(common_in->sr,
common_out->sr_index, sigstack,
common_out->data);
return(base);
}
void capture_signal_stack(void)
{
struct sc_frame_raw raw_sc;
......@@ -220,54 +285,29 @@ void capture_signal_stack(void)
top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
sig_top = (unsigned long) sigstack + PAGE_SIZE;
raw_sc.stack = sigstack;
raw_sc.size = PAGE_SIZE;
signal_frame_sc.len = capture_stack(sc_child, &raw_sc, (void *) top,
sig_top, &signal_frame_sc.data);
/* These are the offsets within signal_frame_sc.data (counting from
* the bottom) of sig, sc, SA_RESTORER, and the initial sp.
*/
/* Get the sigcontext, no sigrestorer layout */
raw_sc.restorer = 0;
base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common,
(void *) top, sigstack, PAGE_SIZE,
&signal_frame_sc.common);
base = sig_top - signal_frame_sc.len;
signal_frame_sc.sig_index = raw_sc.sig - base;
signal_frame_sc.sc_index = raw_sc.sc - base;
signal_frame_sc.sr_index = raw_sc.sr - base;
if((*((unsigned long *) raw_sc.sr) & PAGE_MASK) ==
(unsigned long) sigstack){
unsigned long *sr = (unsigned long *) raw_sc.sr;
unsigned long frame = (unsigned long) signal_frame_sc.data;
signal_frame_sc.sr_relative = 1;
*sr -= raw_sc.sr;
*((unsigned long *) (frame + signal_frame_sc.sr_index)) = *sr;
}
else signal_frame_sc.sr_relative = 0;
signal_frame_sc.sp_index = raw_sc.sp - base;
setup_arch_frame(&raw_sc.arch, &signal_frame_sc.arch);
/* Repeat for the siginfo variant */
/* Ditto for the sigcontext, sigrestorer layout */
raw_sc.restorer = 1;
base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common,
(void *) top, sigstack, PAGE_SIZE,
&signal_frame_sc_sr.common);
signal_frame_sc_sr.sc_index = raw_sc.sc - base;
/* And the siginfo layout */
raw_si.stack = sigstack;
raw_si.size = PAGE_SIZE;
signal_frame_si.len = capture_stack(si_child, &raw_si, (void *) top,
sig_top, &signal_frame_si.data);
base = sig_top - signal_frame_si.len;
signal_frame_si.sig_index = raw_si.sig - base;
base = capture_stack_common(si_child, &raw_si, &raw_si.common,
(void *) top, sigstack, PAGE_SIZE,
&signal_frame_si.common);
signal_frame_si.sip_index = raw_si.sip - base;
signal_frame_si.si_index = raw_si.si - base;
signal_frame_si.sr_index = raw_si.sr - base;
if((*((unsigned long *) raw_si.sr) & PAGE_MASK) ==
(unsigned long) sigstack){
unsigned long *sr = (unsigned long *) raw_si.sr;
unsigned long frame = (unsigned long) signal_frame_si.data;
signal_frame_sc.sr_relative = 1;
*sr -= raw_si.sr;
*((unsigned long *) (frame + signal_frame_si.sr_index)) = *sr;
}
else signal_frame_si.sr_relative = 0;
signal_frame_si.sp_index = raw_si.sp - base;
if((munmap(stack, PAGE_SIZE) < 0) ||
(munmap(sigstack, PAGE_SIZE) < 0)){
......@@ -277,14 +317,6 @@ void capture_signal_stack(void)
}
}
void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp)
{
struct sigcontext *sc = sc_ptr;
SC_IP(sc) = ip;
SC_SP(sc) = sp;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
......
......@@ -9,20 +9,31 @@
#include "frame_kern.h"
#include "sigcontext.h"
#include "sysdep/ptrace.h"
#include "choose-mode.h"
#include "mode.h"
static int copy_restorer(void (*restorer)(void), unsigned long start,
unsigned long sr_index, int sr_relative)
{
if(restorer != 0){
if(copy_to_user((void *) (start + sr_index), &restorer,
sizeof(restorer)))
return(1);
}
else if(sr_relative){
unsigned long *sr = (unsigned long *) (start + sr_index);
*sr += (unsigned long) sr;
unsigned long sr;
if(sr_relative){
sr = (unsigned long) restorer;
sr += start + sr_index;
restorer = (void (*)(void)) sr;
}
return(0);
return(copy_to_user((void *) (start + sr_index), &restorer,
sizeof(restorer)));
}
static int copy_sc_to_user(void *to, struct pt_regs *from)
{
return(CHOOSE_MODE(copy_sc_to_user_tt(to, from->regs.mode.tt,
&signal_frame_sc_sr.arch),
copy_sc_to_user_skas(to, &from->regs,
current->thread.cr2,
current->thread.err)));
}
int setup_signal_stack_si(unsigned long stack_top, int sig,
......@@ -34,27 +45,30 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
void *sip;
int sig_size = _NSIG_WORDS * sizeof(unsigned long);
start = stack_top - signal_frame_si.len -
start = stack_top - signal_frame_si.common.len -
sc_size(&signal_frame_sc.arch) - sig_size;
sip = (void *) (start + signal_frame_si.si_index);
sc = start + signal_frame_si.len;
sc = start + signal_frame_si.common.len;
sigs = sc + sc_size(&signal_frame_sc.arch);
if(copy_sc_to_user((void *) sc, regs->regs.sc,
&signal_frame_sc.arch) ||
copy_to_user((void *) start, signal_frame_si.data,
signal_frame_si.len) ||
copy_to_user((void *) (start + signal_frame_si.sig_index), &sig,
sizeof(sig)) ||
if(restorer == NULL)
panic("setup_signal_stack_si - no restorer");
if(copy_sc_to_user((void *) sc, regs) ||
copy_to_user((void *) start, signal_frame_si.common.data,
signal_frame_si.common.len) ||
copy_to_user((void *) (start + signal_frame_si.common.sig_index),
&sig, sizeof(sig)) ||
copy_siginfo_to_user(sip, info) ||
copy_to_user((void *) (start + signal_frame_si.sip_index), &sip,
sizeof(sip)) ||
copy_to_user((void *) sigs, mask, sig_size) ||
copy_restorer(restorer, start, signal_frame_si.sr_index,
signal_frame_si.sr_relative))
copy_restorer(restorer, start, signal_frame_si.common.sr_index,
signal_frame_si.common.sr_relative))
return(1);
PT_REGS_IP(regs) = handler;
PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
PT_REGS_SP(regs) = start + signal_frame_sc.common.sp_index;
return(0);
}
......@@ -62,26 +76,35 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
unsigned long handler, void (*restorer)(void),
struct pt_regs *regs, sigset_t *mask)
{
struct frame_common *frame = &signal_frame_sc_sr.common;
void *user_sc;
int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
unsigned long sigs, start = stack_top - signal_frame_sc.len - sig_size;
void *user_sc = (void *) (start + signal_frame_sc.sc_index);
unsigned long sigs, sr;
unsigned long start = stack_top - frame->len - sig_size;
user_sc = (void *) (start + signal_frame_sc_sr.sc_index);
if(restorer == NULL){
frame = &signal_frame_sc.common;
user_sc = (void *) (start + signal_frame_sc.sc_index);
sr = (unsigned long) frame->data;
sr += frame->sr_index;
sr = *((unsigned long *) sr);
restorer = ((void (*)(void)) sr);
}
sigs = start + signal_frame_sc.len;
if(copy_to_user((void *) start, signal_frame_sc.data,
signal_frame_sc.len) ||
copy_to_user((void *) (start + signal_frame_sc.sig_index), &sig,
sigs = start + frame->len;
if(copy_to_user((void *) start, frame->data, frame->len) ||
copy_to_user((void *) (start + frame->sig_index), &sig,
sizeof(sig)) ||
copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) ||
copy_sc_to_user(user_sc, regs) ||
copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) ||
copy_to_user((void *) sigs, &mask->sig[1], sig_size) ||
copy_restorer(restorer, start, signal_frame_sc.sr_index,
signal_frame_sc.sr_relative))
copy_restorer(restorer, start, frame->sr_index, frame->sr_relative))
return(1);
PT_REGS_IP(regs) = handler;
PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
PT_REGS_SP(regs) = start + frame->sp_index;
set_sc_ip_sp(regs->regs.sc, handler, start + signal_frame_sc.sp_index);
return(0);
}
......
......@@ -43,9 +43,12 @@ static int helper_child(void *arg)
execvp(argv[0], argv);
printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
write(data->fd, &errno, sizeof(errno));
_exit(1);
os_kill_process(os_getpid(), 0);
return(0);
}
/* XXX The alloc_stack here breaks if this is called in the tracing thread */
int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
unsigned long *stack_out)
{
......
......@@ -47,7 +47,7 @@ struct task_struct *alloc_task_struct(void){
void unprotect_stack(unsigned long stack)
{
protect(stack, 4 * PAGE_SIZE, 1, 1, 0, 1);
protect_memory(stack, 4 * PAGE_SIZE, 1, 1, 0, 1);
}
void free_task_struct(struct task_struct *task)
......
/*
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include "linux/config.h"
#include "linux/module.h"
#include "linux/string.h"
......@@ -19,17 +24,13 @@
EXPORT_SYMBOL(stop);
EXPORT_SYMBOL(uml_physmem);
EXPORT_SYMBOL(set_signals);
EXPORT_SYMBOL(get_signals);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(__const_udelay);
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(sys_waitpid);
EXPORT_SYMBOL(task_size);
EXPORT_SYMBOL(__do_copy_from_user);
EXPORT_SYMBOL(__do_copy_to_user);
EXPORT_SYMBOL(__do_strncpy_from_user);
EXPORT_SYMBOL(__do_strnlen_user);
EXPORT_SYMBOL(flush_tlb_range);
EXPORT_SYMBOL(__do_clear_user);
EXPORT_SYMBOL(honeypot);
EXPORT_SYMBOL(host_task_size);
EXPORT_SYMBOL(arch_validate);
......@@ -37,10 +38,10 @@ EXPORT_SYMBOL(region_pa);
EXPORT_SYMBOL(region_va);
EXPORT_SYMBOL(phys_mem_map);
EXPORT_SYMBOL(page_mem_map);
EXPORT_SYMBOL(get_signals);
EXPORT_SYMBOL(page_to_phys);
EXPORT_SYMBOL(phys_to_page);
EXPORT_SYMBOL(high_physmem);
EXPORT_SYMBOL(empty_zero_page);
EXPORT_SYMBOL(os_open_file);
EXPORT_SYMBOL(os_read_file);
......@@ -53,7 +54,6 @@ EXPORT_SYMBOL(helper_wait);
EXPORT_SYMBOL(os_shutdown_socket);
EXPORT_SYMBOL(os_connect_socket);
EXPORT_SYMBOL(run_helper);
EXPORT_SYMBOL(tracing_pid);
EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(dump_thread);
......@@ -75,6 +75,7 @@ EXPORT_SYMBOL_NOVERS(__write_lock_failed);
extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
EXPORT_SYMBOL_NOVERS(__read_lock_failed);
EXPORT_SYMBOL(smp_num_cpus);
#endif
#ifdef CONFIG_HIGHMEM
......
......@@ -25,6 +25,8 @@
#include "mem.h"
#include "kern.h"
#include "init.h"
#include "os.h"
#include "mode_kern.h"
/* Changed during early boot */
pgd_t swapper_pg_dir[1024];
......@@ -56,12 +58,12 @@ static unsigned long brk_end;
static void map_cb(void *unused)
{
map(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
}
void unmap_physmem(void)
{
unmap((void *) brk_end, uml_reserved - brk_end);
os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
}
extern char __binary_start;
......@@ -81,17 +83,17 @@ void mem_init(void)
/* Map in the area just after the brk now that kmalloc is about
* to be turned on.
*/
brk_end = (unsigned long) ROUND_UP(sbrk(0));
brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
map_cb(NULL);
tracing_cb(map_cb, NULL);
initial_thread_cb(map_cb, NULL);
free_bootmem(__pa(brk_end), uml_reserved - brk_end);
uml_reserved = brk_end;
/* Fill in any hole at the start of the binary */
start = (unsigned long) &__binary_start;
if(uml_physmem != start){
map(uml_physmem, __pa(uml_physmem), start - uml_physmem,
1, 1, 0);
map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem,
1, 1, 0);
}
/* this will put all low memory onto the freelists */
......@@ -106,6 +108,21 @@ void mem_init(void)
kmalloc_ok = 1;
}
/* Changed during early boot */
static unsigned long kmem_top = 0;
unsigned long get_kmem_end(void)
{
if(kmem_top == 0)
kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
return(kmem_top);
}
void set_kmem_end(unsigned long new)
{
kmem_top = new;
}
#if CONFIG_HIGHMEM
/* Changed during early boot */
pte_t *kmap_pte;
......@@ -379,20 +396,6 @@ void show_mem(void)
printk("%d pages swap cached\n", cached);
}
/* Changed during early boot */
static unsigned long kmem_top = 0;
unsigned long get_kmem_end(void)
{
if(kmem_top == 0) kmem_top = host_task_size - ABOVE_KMEM;
return(kmem_top);
}
void set_kmem_end(unsigned long new)
{
kmem_top = new;
}
static int __init uml_mem_setup(char *line, int *add)
{
char *retptr;
......@@ -411,28 +414,8 @@ __uml_setup("mem=", uml_mem_setup,
struct page *arch_validate(struct page *page, int mask, int order)
{
unsigned long addr, zero = 0;
int i;
again:
if(page == NULL) return(page);
if(PageHighMem(page)) return(page);
addr = (unsigned long) page_address(page);
for(i = 0; i < (1 << order); i++){
current->thread.fault_addr = (void *) addr;
if(__do_copy_to_user((void *) addr, &zero,
sizeof(zero),
&current->thread.fault_addr,
&current->thread.fault_catcher)){
if(!(mask & __GFP_WAIT)) return(NULL);
else break;
}
addr += PAGE_SIZE;
}
if(i == (1 << order)) return(page);
page = alloc_pages(mask, order);
goto again;
return(CHOOSE_MODE_PROC(arch_validate_tt, arch_validate_skas, page,
mask, order));
}
DECLARE_MUTEX(vm_reserved_sem);
......@@ -513,7 +496,7 @@ unsigned long get_vm(unsigned long len)
return(0);
found:
up(&vm_reserved_sem);
start = (unsigned long) ROUND_UP(this->end) + PAGE_SIZE;
start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE;
err = reserve_vm(start, start + len, NULL);
if(err) return(0);
return(start);
......@@ -562,7 +545,7 @@ struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] =
int num_iomem_regions = 0;
void add_iomem(char *name, int fd, int size)
void add_iomem(char *name, int fd, unsigned long size)
{
if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0]))
return;
......
......@@ -181,44 +181,22 @@ void log(char *fmt, ...)
}
#endif
void map(unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x)
int map_memory(unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x)
{
struct mem_region *region;
void *loc;
int prot;
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
(x ? PROT_EXEC : 0);
region = phys_region(phys);
loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
region->fd, phys_offset(phys));
if(loc != (void *) virt){
panic("Error mapping a page - errno = %d", errno);
}
}
int unmap(void *addr, int len)
{
int err;
struct mem_region *region = phys_region(phys);
err = munmap(addr, len);
if(err < 0) return(-errno);
else return(err);
return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len,
r, w, x));
}
int protect(unsigned long addr, unsigned long len, int r, int w, int x,
int must_succeed)
int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
int must_succeed)
{
int prot;
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
(x ? PROT_EXEC : 0);
if(mprotect((void *) addr, len, prot) == -1){
if(must_succeed)
panic("protect failed, errno = %d", errno);
else return(-errno);
if(os_protect_memory((void *) addr, len, r, w, x) < 0){
if(must_succeed)
panic("protect failed, errno = %d", errno);
else return(-errno);
}
return(0);
}
......
......@@ -21,9 +21,6 @@
#include <asm/sigcontext.h>
#include <asm/unistd.h>
#include <asm/page.h>
#ifdef PROFILING
#include <sys/gmon.h>
#endif
#include "user_util.h"
#include "kern_util.h"
#include "user.h"
......@@ -33,13 +30,19 @@
#include "sysdep/ptrace.h"
#include "sysdep/sigcontext.h"
#include "irq_user.h"
#include "syscall_user.h"
#include "ptrace_user.h"
#include "time_user.h"
#include "init.h"
#include "os.h"
#include "uml-config.h"
#include "choose-mode.h"
#include "mode.h"
#ifdef CONFIG_MODE_SKAS
#include "skas_ptrace.h"
#include "skas.h"
#endif
void init_new_thread(void *sig_stack, void (*usr1_handler)(int))
void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
{
int flags = 0;
......@@ -47,6 +50,13 @@ void init_new_thread(void *sig_stack, void (*usr1_handler)(int))
set_sigstack(sig_stack, 2 * page_size());
flags = SA_ONSTACK;
}
if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
}
void init_new_thread_signals(int altstack)
{
int flags = altstack ? SA_ONSTACK : 0;
set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
......@@ -61,11 +71,10 @@ void init_new_thread(void *sig_stack, void (*usr1_handler)(int))
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
set_handler(SIGUSR2, (__sighandler_t) sig_handler,
SA_NOMASK | flags, -1);
if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
signal(SIGCHLD, SIG_IGN);
(void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0);
signal(SIGHUP, SIG_IGN);
init_irq_signals(sig_stack != NULL);
init_irq_signals(altstack);
}
struct tramp {
......@@ -122,32 +131,6 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
return(arg.pid);
}
void trace_myself(void)
{
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
panic("ptrace failed in trace_myself");
}
void attach_process(int pid)
{
if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
(ptrace(PTRACE_CONT, pid, 0, 0) < 0))
tracer_panic("OP_FORK failed to attach pid");
wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
tracer_panic("OP_FORK failed to continue process");
}
void tracer_panic(char *format, ...)
{
va_list ap;
va_start(ap, format);
vprintf(format, ap);
printf("\n");
while(1) sleep(10);
}
void suspend_new_thread(int fd)
{
char c;
......@@ -164,19 +147,18 @@ static int ptrace_child(void *arg)
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
perror("ptrace");
_exit(1);
os_kill_process(pid, 0);
}
os_stop_process(pid);
_exit(os_getpid() == pid);
}
void __init check_ptrace(void)
static int start_ptraced_child(void **stack_out)
{
void *stack;
unsigned long sp;
int status, pid, n, syscall;
printk("Checking that ptrace can change system call numbers...");
int pid, n, status;
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(stack == MAP_FAILED)
......@@ -191,6 +173,33 @@ void __init check_ptrace(void)
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
panic("check_ptrace : expected SIGSTOP, got status = %d",
status);
*stack_out = stack;
return(pid);
}
static void stop_ptraced_child(int pid, void *stack, int exitcode)
{
int status, n;
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d", errno);
n = waitpid(pid, &status, 0);
if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode))
panic("check_ptrace : child exited with status 0x%x", status);
if(munmap(stack, PAGE_SIZE) < 0)
panic("check_ptrace : munmap failed, errno = %d", errno);
}
void __init check_ptrace(void)
{
void *stack;
int pid, syscall, n, status;
printk("Checking that ptrace can change system call numbers...");
pid = start_ptraced_child(&stack);
while(1){
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d",
......@@ -213,23 +222,19 @@ void __init check_ptrace(void)
break;
}
}
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d", errno);
n = waitpid(pid, &status, 0);
if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
panic("check_ptrace : child exited with status 0x%x", status);
if(munmap(stack, PAGE_SIZE) < 0)
panic("check_ptrace : munmap failed, errno = %d", errno);
stop_ptraced_child(pid, stack, 0);
printk("OK\n");
}
int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
{
jmp_buf buf;
int n;
*jmp_ptr = &buf;
if(setjmp(buf)) return(1);
n = setjmp(buf);
if(n != 0)
return(n);
(*fn)(arg);
return(0);
}
......@@ -244,6 +249,41 @@ void forward_pending_sigio(int target)
kill(target, SIGIO);
}
int can_do_skas(void)
{
#ifdef CONFIG_MODE_SKAS
struct ptrace_faultinfo fi;
void *stack;
int pid, n, ret = 1;
printk("Checking for the skas3 patch in the host...");
pid = start_ptraced_child(&stack);
n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
if(n < 0){
if(errno == EIO)
printk("not found\n");
else printk("No (unexpected errno - %d)\n", errno);
ret = 0;
}
else printk("found\n");
init_registers(pid);
stop_ptraced_child(pid, stack, 1);
printk("Checking for /proc/mm...");
if(access("/proc/mm", W_OK)){
printk("not found\n");
ret = 0;
}
else printk("found\n");
return(ret);
#else
return(0);
#endif
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
......
This diff is collapsed.
......@@ -9,6 +9,7 @@
#include "linux/smp_lock.h"
#include "linux/security.h"
#include "linux/ptrace.h"
#include "linux/proc_mm.h"
#include "asm/ptrace.h"
#include "asm/uaccess.h"
#include "kern_util.h"
......@@ -21,6 +22,11 @@ void ptrace_disable(struct task_struct *child)
{
}
extern long do_mmap2(struct task_struct *task, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flags, unsigned long fd,
unsigned long pgoff);
int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
......@@ -182,13 +188,13 @@ int sys_ptrace(long request, long pid, long addr, long data)
#ifdef PTRACE_GETREGS
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
if (!access_ok(VERIFY_WRITE, (unsigned *)data,
if (!access_ok(VERIFY_WRITE, (unsigned long *)data,
FRAME_SIZE_OFFSET)) {
ret = -EIO;
break;
}
for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
__put_user(getreg(child, i),(unsigned long *) data);
__put_user(getreg(child, i), (unsigned long *) data);
data += sizeof(long);
}
ret = 0;
......@@ -231,6 +237,57 @@ int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_SETFPXREGS: /* Set the child FPU state. */
ret = set_fpxregs(data, child);
break;
#endif
case PTRACE_FAULTINFO: {
struct ptrace_faultinfo fault;
fault = ((struct ptrace_faultinfo)
{ .is_write = child->thread.err,
.addr = child->thread.cr2 });
ret = copy_to_user((unsigned long *) data, &fault,
sizeof(fault));
if(ret)
break;
break;
}
case PTRACE_SIGPENDING:
ret = copy_to_user((unsigned long *) data,
&child->pending.signal,
sizeof(child->pending.signal));
break;
case PTRACE_LDT: {
struct ptrace_ldt ldt;
if(copy_from_user(&ldt, (unsigned long *) data,
sizeof(ldt))){
ret = -EIO;
break;
}
/* This one is confusing, so just punt and return -EIO for
* now
*/
ret = -EIO;
break;
}
#ifdef CONFIG_PROC_MM
case PTRACE_SWITCH_MM: {
struct mm_struct *old = child->mm;
struct mm_struct *new = proc_mm_get_mm(data);
if(IS_ERR(new)){
ret = PTR_ERR(new);
break;
}
atomic_inc(&new->mm_users);
child->mm = new;
child->active_mm = new;
mmput(old);
ret = 0;
break;
}
#endif
default:
ret = -EIO;
......
......@@ -8,6 +8,8 @@
#include "kern_util.h"
#include "kern.h"
#include "os.h"
#include "mode.h"
#include "choose-mode.h"
#ifdef CONFIG_SMP
static void kill_idlers(int me)
......@@ -17,26 +19,17 @@ static void kill_idlers(int me)
for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){
p = idle_threads[i];
if((p != NULL) && (p->thread.extern_pid != me))
os_kill_process(p->thread.extern_pid);
if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
os_kill_process(p->thread.mode.tt.extern_pid, 0);
}
}
#endif
static void kill_off_processes(void)
{
struct task_struct *p;
int me;
me = os_getpid();
for_each_process(p){
if(p->thread.extern_pid != me)
os_kill_process(p->thread.extern_pid);
}
if(init_task.thread.extern_pid != me)
os_kill_process(init_task.thread.extern_pid);
CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
#ifdef CONFIG_SMP
kill_idlers(me);
kill_idlers(os_getpid());
#endif
}
......@@ -50,16 +43,14 @@ void machine_restart(char * __unused)
{
do_uml_exitcalls();
kill_off_processes();
tracing_reboot();
os_kill_process(os_getpid());
CHOOSE_MODE(reboot_tt(), reboot_skas());
}
void machine_power_off(void)
{
do_uml_exitcalls();
kill_off_processes();
tracing_halt();
os_kill_process(os_getpid());
CHOOSE_MODE(halt_tt(), halt_skas());
}
void machine_halt(void)
......
......@@ -39,14 +39,13 @@ struct openpty_arg {
int err;
};
static int openpty_cb(void *arg)
static void openpty_cb(void *arg)
{
struct openpty_arg *info = arg;
info->err = 0;
if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
info->err = errno;
return(0);
}
void __init check_one_sigio(void (*proc)(int, int))
......@@ -54,13 +53,9 @@ void __init check_one_sigio(void (*proc)(int, int))
struct sigaction old, new;
struct termios tt;
struct openpty_arg pty = { master : -1, slave : -1 };
int master, slave, flags, err;
int master, slave, flags;
err = run_helper_thread(openpty_cb, &pty, CLONE_FILES, NULL, 2);
if(err < 0){
printk("run_helper_thread failed, errno = %d\n", -err);
return;
}
initial_thread_cb(openpty_cb, &pty);
if(pty.err){
printk("openpty failed, errno = %d\n", pty.err);
return;
......@@ -387,7 +382,7 @@ void write_sigio_workaround(void)
goto out_close2;
write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
CLONE_FILES, &stack, 0);
CLONE_FILES | CLONE_VM, &stack, 0);
if(write_sigio_pid < 0) goto out_close2;
......
......@@ -23,6 +23,7 @@
#include "kern.h"
#include "frame_kern.h"
#include "sigcontext.h"
#include "mode.h"
EXPORT_SYMBOL(block_signals);
EXPORT_SYMBOL(unblock_signals);
......@@ -171,7 +172,7 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
*/
if((current->ptrace & PT_DTRACE) &&
is_syscall(PT_REGS_IP(&current->thread.regs)))
current->thread.singlestep_syscall = 1;
(void) CHOOSE_MODE(current->thread.mode.tt.singlestep_syscall = 1, 0);
return(0);
}
......@@ -228,6 +229,16 @@ int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
}
}
static int copy_sc_from_user(struct pt_regs *to, void *from)
{
int ret;
ret = CHOOSE_MODE(copy_sc_from_user_tt(to->regs.mode.tt, from,
&signal_frame_sc.arch),
copy_sc_from_user_skas(&to->regs, from));
return(ret);
}
int sys_sigreturn(struct pt_regs regs)
{
void *sc = sp_to_sc(PT_REGS_SP(&regs));
......@@ -241,8 +252,7 @@ int sys_sigreturn(struct pt_regs regs)
sigdelsetmask(&current->blocked, ~_BLOCKABLE);
recalc_sigpending();
spin_unlock_irq(&current->sig->siglock);
copy_sc_from_user(current->thread.regs.regs.sc, sc,
&signal_frame_sc.arch);
copy_sc_from_user(&current->thread.regs, sc);
return(PT_REGS_SYSCALL_RET(&current->thread.regs));
}
......@@ -257,8 +267,7 @@ int sys_rt_sigreturn(struct pt_regs regs)
sigdelsetmask(&current->blocked, ~_BLOCKABLE);
recalc_sigpending();
spin_unlock_irq(&current->sig->siglock);
copy_sc_from_user(current->thread.regs.regs.sc, sc,
&signal_frame_sc.arch);
copy_sc_from_user(&current->thread.regs, sc);
return(PT_REGS_SYSCALL_RET(&current->thread.regs));
}
......
......@@ -21,13 +21,12 @@
void set_sigstack(void *sig_stack, int size)
{
stack_t stack;
stack_t stack = ((stack_t) { .ss_flags = 0,
.ss_sp = (__ptr_t) sig_stack,
.ss_size = size - sizeof(void *) });
stack.ss_sp = (__ptr_t) sig_stack;
stack.ss_flags = 0;
stack.ss_size = size - sizeof(void *);
if(sigaltstack(&stack, NULL) != 0)
panic("sigaltstack failed");
panic("enabling signal stack failed, errno = %d\n", errno);
}
void set_handler(int sig, void (*handler)(int), int flags, ...)
......
#
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \
process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \
sys-$(SUBARCH)/
USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
include $(TOPDIR)/Rules.make
include/skas_ptregs.h : util/mk_ptregs
util/mk_ptregs > $@
util/mk_ptregs :
$(MAKE) -C util
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
clean :
$(MAKE) -C util clean
$(RM) -f include/skas_ptregs.h
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include "linux/kernel.h"
#include "asm/current.h"
#include "asm/page.h"
#include "asm/signal.h"
#include "asm/ptrace.h"
#include "asm/uaccess.h"
#include "asm/mmu_context.h"
#include "tlb.h"
#include "skas.h"
#include "mmu.h"
#include "os.h"
void flush_thread_skas(void)
{
force_flush_all();
switch_mm_skas(current->mm->context.skas.mm_fd);
}
void start_thread_skas(struct pt_regs *regs, unsigned long eip,
unsigned long esp)
{
set_fs(USER_DS);
PT_REGS_IP(regs) = eip;
PT_REGS_SP(regs) = esp;
}
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <sched.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include "user.h"
#include "kern_util.h"
#include "os.h"
#include "time_user.h"
static int user_thread_tramp(void *arg)
{
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
panic("user_thread_tramp - PTRACE_TRACEME failed, "
"errno = %d\n", errno);
enable_timer();
os_stop_process(os_getpid());
return(0);
}
int user_thread(unsigned long stack, int flags)
{
int pid, status;
pid = clone(user_thread_tramp, (void *) stack_sp(stack),
flags | CLONE_FILES | SIGCHLD, NULL);
if(pid < 0){
printk("user_thread - clone failed, errno = %d\n", errno);
return(pid);
}
if(waitpid(pid, &status, WUNTRACED) < 0){
printk("user_thread - waitpid failed, errno = %d\n", errno);
return(-errno);
}
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
printk("user_thread - trampoline didn't stop, status = %d\n",
status);
return(-EINVAL);
}
return(pid);
}
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SKAS_MMU_H
#define __SKAS_MMU_H
#include "linux/list.h"
#include "linux/spinlock.h"
struct mmu_context_skas {
int mm_fd;
};
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __MODE_SKAS_H__
#define __MODE_SKAS_H__
extern unsigned long exec_regs[];
extern unsigned long exec_fp_regs[];
extern unsigned long exec_fpx_regs[];
extern int have_fpx_regs;
extern void user_time_init_skas(void);
extern int copy_sc_from_user_skas(struct uml_pt_regs *regs, void *from_ptr);
extern int copy_sc_to_user_skas(void *to_ptr, struct uml_pt_regs *regs,
unsigned long fault_addr, int fault_type);
extern void sig_handler_common_skas(int sig, struct sigcontext *sc);
extern void halt_skas(void);
extern void reboot_skas(void);
extern void kill_off_processes_skas(void);
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SKAS_MODE_KERN_H__
#define __SKAS_MODE_KERN_H__
#include "linux/sched.h"
#include "asm/page.h"
#include "asm/ptrace.h"
extern void flush_thread_skas(void);
extern void *switch_to_skas(void *prev, void *next);
extern void start_thread_skas(struct pt_regs *regs, unsigned long eip,
unsigned long esp);
extern int copy_thread_skas(int nr, unsigned long clone_flags,
unsigned long sp, unsigned long stack_top,
struct task_struct *p, struct pt_regs *regs);
extern void release_thread_skas(struct task_struct *task);
extern void exit_thread_skas(void);
extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
extern void init_idle_skas(void);
extern void flush_tlb_kernel_vm_skas(void);
extern void __flush_tlb_one_skas(unsigned long addr);
extern void flush_tlb_range_skas(struct vm_area_struct *vma,
unsigned long start, unsigned long end);
extern void flush_tlb_mm_skas(struct mm_struct *mm);
extern void force_flush_all_skas(void);
extern long execute_syscall_skas(void *r);
extern void before_mem_skas(unsigned long unused);
extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
unsigned long *task_size_out);
extern int start_uml_skas(void);
extern struct page *arch_validate_skas(struct page *page, int mask, int order);
extern int external_pid_skas(struct task_struct *task);
extern int thread_pid_skas(struct task_struct *task);
#define kmem_end_skas (host_task_size)
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SKAS_PROC_MM_H
#define __SKAS_PROC_MM_H
#define MM_MMAP 54
#define MM_MUNMAP 55
#define MM_MPROTECT 56
#define MM_COPY_SEGMENTS 57
struct mm_mmap {
unsigned long addr;
unsigned long len;
unsigned long prot;
unsigned long flags;
unsigned long fd;
unsigned long offset;
};
struct mm_munmap {
unsigned long addr;
unsigned long len;
};
struct mm_mprotect {
unsigned long addr;
unsigned long len;
unsigned int prot;
};
struct proc_mm_op {
int op;
union {
struct mm_mmap mmap;
struct mm_munmap munmap;
struct mm_mprotect mprotect;
int copy_segments;
} u;
};
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __PTRACE_SKAS_H
#define __PTRACE_SKAS_H
#include "uml-config.h"
#ifdef CONFIG_MODE_SKAS
#include "skas_ptregs.h"
#define HOST_FRAME_SIZE 17
#define REGS_IP(r) ((r)[HOST_IP])
#define REGS_SP(r) ((r)[HOST_SP])
#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
#define REGS_EAX(r) ((r)[HOST_EAX])
#define REGS_EBX(r) ((r)[HOST_EBX])
#define REGS_ECX(r) ((r)[HOST_ECX])
#define REGS_EDX(r) ((r)[HOST_EDX])
#define REGS_ESI(r) ((r)[HOST_ESI])
#define REGS_EDI(r) ((r)[HOST_EDI])
#define REGS_EBP(r) ((r)[HOST_EBP])
#define REGS_CS(r) ((r)[HOST_CS])
#define REGS_SS(r) ((r)[HOST_SS])
#define REGS_DS(r) ((r)[HOST_DS])
#define REGS_ES(r) ((r)[HOST_ES])
#define REGS_FS(r) ((r)[HOST_FS])
#define REGS_GS(r) ((r)[HOST_GS])
#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res)
#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type)
#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
#endif
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SKAS_H
#define __SKAS_H
#include "sysdep/ptrace.h"
extern int userspace_pid;
extern void switch_threads(void *me, void *next);
extern void thread_wait(void *sw, void *fb);
extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
void (*handler)(int));
extern int start_idle_thread(void *stack, void *switch_buf_ptr,
void **fork_buf_ptr);
extern int user_thread(unsigned long stack, int flags);
extern void userspace(struct uml_pt_regs *regs);
extern void new_thread_proc(void *stack, void (*handler)(int sig));
extern void remove_sigstack(void);
extern void new_thread_handler(int sig);
extern void handle_syscall(struct uml_pt_regs *regs);
extern void map(int fd, unsigned long virt, unsigned long phys,
unsigned long len, int r, int w, int x);
extern int unmap(int fd, void *addr, int len);
extern int protect(int fd, unsigned long addr, unsigned long len,
int r, int w, int x, int must_succeed);
extern void user_signal(int sig, struct uml_pt_regs *regs);
extern int singlestepping_skas(void);
extern int new_mm(int from);
extern void save_registers(struct uml_pt_regs *regs);
extern void restore_registers(struct uml_pt_regs *regs);
extern void start_userspace(void);
extern void init_registers(int pid);
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SKAS_PTRACE_H
#define __SKAS_PTRACE_H
struct ptrace_faultinfo {
int is_write;
unsigned long addr;
};
struct ptrace_ldt {
int func;
void *ptr;
unsigned long bytecount;
};
#define PTRACE_FAULTINFO 52
#define PTRACE_SIGPENDING 53
#define PTRACE_LDT 54
#define PTRACE_SWITCH_MM 55
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SKAS_UACCESS_H
#define __SKAS_UACCESS_H
#include "linux/string.h"
#include "linux/sched.h"
#include "linux/err.h"
#include "asm/processor.h"
#include "asm/pgtable.h"
#include "asm/errno.h"
#include "asm/current.h"
#include "asm/a.out.h"
#include "kern_util.h"
#define access_ok_skas(type, addr, size) \
((segment_eq(get_fs(), KERNEL_DS)) || \
(((unsigned long) (addr) < TASK_SIZE) && \
((unsigned long) (addr) + (size) < TASK_SIZE)))
static inline int verify_area_skas(int type, const void * addr,
unsigned long size)
{
return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
}
extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt,
pte_t *pte_out);
static inline unsigned long maybe_map(unsigned long virt, int is_write)
{
pte_t pte;
void *phys = um_virt_to_phys(current, virt, &pte);
int dummy_code;
if(IS_ERR(phys) || (is_write && !pte_write(pte))){
if(handle_page_fault(virt, 0, is_write, 0, &dummy_code))
return(0);
phys = um_virt_to_phys(current, virt, NULL);
}
return((unsigned long) __va((unsigned long) phys));
}
static inline int buffer_op(unsigned long addr, int len,
int (*op)(unsigned long addr, int len, void *arg),
void *arg)
{
int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
int remain = len, n;
n = (*op)(addr, size, arg);
if(n != 0)
return(n < 0 ? remain : 0);
addr += size;
remain -= size;
if(remain == 0)
return(0);
while(addr < ((addr + remain) & PAGE_MASK)){
n = (*op)(addr, PAGE_SIZE, arg);
if(n != 0)
return(n < 0 ? remain : 0);
addr += PAGE_SIZE;
remain -= PAGE_SIZE;
}
if(remain == 0)
return(0);
n = (*op)(addr, remain, arg);
if(n != 0)
return(n < 0 ? remain : 0);
return(0);
}
static inline int copy_chunk_from_user(unsigned long from, int len, void *arg)
{
unsigned long *to_ptr = arg, to = *to_ptr;
from = maybe_map(from, 0);
if(from == 0)
return(-1);
memcpy((void *) to, (void *) from, len);
*to_ptr += len;
return(0);
}
static inline int copy_from_user_skas(void *to, const void *from, int n)
{
if(segment_eq(get_fs(), KERNEL_DS)){
memcpy(to, from, n);
return(0);
}
return(access_ok_skas(VERIFY_READ, from, n) ?
buffer_op((unsigned long) from, n, copy_chunk_from_user, &to) :
n);
}
static inline int copy_chunk_to_user(unsigned long to, int len, void *arg)
{
unsigned long *from_ptr = arg, from = *from_ptr;
to = maybe_map(to, 1);
if(to == 0)
return(-1);
memcpy((void *) to, (void *) from, len);
*from_ptr += len;
return(0);
}
static inline int copy_to_user_skas(void *to, const void *from, int n)
{
if(segment_eq(get_fs(), KERNEL_DS)){
memcpy(to, from, n);
return(0);
}
return(access_ok_skas(VERIFY_WRITE, to, n) ?
buffer_op((unsigned long) to, n, copy_chunk_to_user, &from) :
n);
}
static inline int strncpy_chunk_from_user(unsigned long from, int len,
void *arg)
{
char **to_ptr = arg, *to = *to_ptr;
int n;
from = maybe_map(from, 0);
if(from == 0)
return(-1);
strncpy(to, (void *) from, len);
n = strnlen(to, len);
*to_ptr += n;
if(n < len)
return(1);
return(0);
}
static inline int strncpy_from_user_skas(char *dst, const char *src, int count)
{
int n;
char *ptr = dst;
if(segment_eq(get_fs(), KERNEL_DS)){
strncpy(dst, src, count);
return(strnlen(dst, count));
}
if(!access_ok_skas(VERIFY_READ, src, 1))
return(-EFAULT);
n = buffer_op((unsigned long) src, count, strncpy_chunk_from_user,
&ptr);
if(n != 0)
return(-EFAULT);
return(strnlen(dst, count));
}
static inline int clear_chunk(unsigned long addr, int len, void *unused)
{
addr = maybe_map(addr, 1);
if(addr == 0)
return(-1);
memset((void *) addr, 0, len);
return(0);
}
static inline int __clear_user_skas(void *mem, int len)
{
return(buffer_op((unsigned long) mem, len, clear_chunk, NULL));
}
static inline int clear_user_skas(void *mem, int len)
{
if(segment_eq(get_fs(), KERNEL_DS)){
memset(mem, 0, len);
return(0);
}
return(access_ok_skas(VERIFY_WRITE, mem, len) ?
buffer_op((unsigned long) mem, len, clear_chunk, NULL) : len);
}
static inline int strnlen_chunk(unsigned long str, int len, void *arg)
{
int *len_ptr = arg, n;
str = maybe_map(str, 0);
if(str == 0)
return(-1);
n = strnlen((void *) str, len);
*len_ptr += n;
if(n < len)
return(1);
return(0);
}
static inline int strnlen_user_skas(const void *str, int len)
{
int count = 0, n;
if(segment_eq(get_fs(), KERNEL_DS))
return(strnlen(str, len) + 1);
n = buffer_op((unsigned long) str, len, strnlen_chunk, &count);
if(n == 0)
return(count + 1);
return(-EFAULT);
}
#endif
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include "linux/config.h"
#include "linux/mm.h"
#include "mem_user.h"
unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
unsigned long *task_size_out)
{
/* Round up to the nearest 4M */
unsigned long top = ROUND_4M((unsigned long) &arg);
*host_size_out = top;
*task_size_out = top;
return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
}
struct page *arch_validate_skas(struct page *page, int mask, int order)
{
return(page);
}
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <errno.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include "mem_user.h"
#include "user.h"
#include "os.h"
#include "proc_mm.h"
void map(int fd, unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x)
{
struct proc_mm_op map;
struct mem_region *region;
int prot, n;
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
(x ? PROT_EXEC : 0);
region = phys_region(phys);
map = ((struct proc_mm_op) { .op = MM_MMAP,
.u =
{ .mmap =
{ .addr = virt,
.len = len,
.prot = prot,
.flags = MAP_SHARED |
MAP_FIXED,
.fd = region->fd,
.offset = phys_offset(phys)
} } } );
n = os_write_file(fd, (char *) &map, sizeof(map));
if(n != sizeof(map))
printk("map : /proc/mm map failed, errno = %d\n", errno);
}
int unmap(int fd, void *addr, int len)
{
struct proc_mm_op unmap;
int n;
unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
.u =
{ .munmap =
{ .addr = (unsigned long) addr,
.len = len } } } );
n = os_write_file(fd, (char *) &unmap, sizeof(unmap));
if((n != 0) && (n != sizeof(unmap)))
return(-errno);
return(0);
}
int protect(int fd, unsigned long addr, unsigned long len, int r, int w,
int x, int must_succeed)
{
struct proc_mm_op protect;
int prot, n;
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
(x ? PROT_EXEC : 0);
protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
.u =
{ .mprotect =
{ .addr = (unsigned long) addr,
.len = len,
.prot = prot } } } );
n = os_write_file(fd, (char *) &protect, sizeof(protect));
if((n != 0) && (n != sizeof(protect))){
if(must_succeed)
panic("protect failed, errno = %d", errno);
return(-errno);
}
return(0);
}
void before_mem_skas(unsigned long unused)
{
}
/*
* 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:
*/
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include "linux/sched.h"
#include "linux/list.h"
#include "linux/spinlock.h"
#include "linux/slab.h"
#include "asm/current.h"
#include "asm/segment.h"
#include "asm/mmu.h"
#include "os.h"
#include "skas.h"
int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
{
int from;
if((current->mm != NULL) && (current->mm != &init_mm))
from = current->mm->context.skas.mm_fd;
else from = -1;
mm->context.skas.mm_fd = new_mm(from);
if(mm->context.skas.mm_fd < 0)
panic("init_new_context_skas - new_mm failed, errno = %d\n",
mm->context.skas.mm_fd);
return(0);
}
void destroy_context_skas(struct mm_struct *mm)
{
os_close_file(mm->context.skas.mm_fd);
}
/*
* 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:
*/
This diff is collapsed.
This diff is collapsed.
#
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
obj-y = sigcontext.o
USER_OBJS = sigcontext.o
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
include $(TOPDIR)/Rules.make
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
clean :
This diff is collapsed.
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include "linux/sys.h"
#include "asm/errno.h"
#include "asm/unistd.h"
#include "asm/ptrace.h"
#include "asm/current.h"
#include "sysdep/syscalls.h"
#include "kern_util.h"
extern syscall_handler_t *sys_call_table[];
long execute_syscall_skas(void *r)
{
struct pt_regs *regs = r;
long res;
int syscall;
current->thread.nsyscalls++;
nsyscalls++;
syscall = regs->regs.syscall;
if((syscall >= NR_syscalls) || (syscall < 0))
res = -ENOSYS;
else res = EXECUTE_SYSCALL(syscall, regs);
return(res);
}
/*
* 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:
*/
This diff is collapsed.
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <sys/signal.h>
#include <sys/time.h>
#include "time_user.h"
#include "process.h"
#include "user.h"
void user_time_init_skas(void)
{
if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
panic("Couldn't set SIGALRM handler");
if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
panic("Couldn't set SIGVTALRM handler");
set_interval(ITIMER_VIRTUAL);
}
/*
* 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:
*/
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment