aboutsummaryrefslogtreecommitdiff
path: root/arch/um
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-09-25 22:51:50 +1000
committerPaul Mackerras <paulus@samba.org>2005-09-25 22:51:50 +1000
commite5baa396af7560382d2cf3f0871d616b61fc284c (patch)
tree6afc166894b8c8b3b2cf6add72a726be14ae2443 /arch/um
parentd6a4c847e43c851cc0ddf73087a730227223f989 (diff)
parentef6bd6eb90ad72ee8ee7ba8b271f27102e9a90c1 (diff)
Merge from Linus' tree.
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/Makefile6
-rw-r--r--arch/um/drivers/chan_kern.c60
-rw-r--r--arch/um/drivers/mconsole_user.c2
-rw-r--r--arch/um/include/common-offsets.h4
-rw-r--r--arch/um/include/user.h4
-rw-r--r--arch/um/kernel/process_kern.c3
-rw-r--r--arch/um/kernel/sigio_user.c2
-rw-r--r--arch/um/kernel/skas/include/uaccess-skas.h6
-rw-r--r--arch/um/kernel/tlb.c12
-rw-r--r--arch/um/kernel/trap_kern.c18
-rw-r--r--arch/um/kernel/tt/include/uaccess-tt.h6
-rw-r--r--arch/um/kernel/tt/process_kern.c3
-rw-r--r--arch/um/kernel/tt/uaccess_user.c11
-rw-r--r--arch/um/kernel/umid.c41
-rw-r--r--arch/um/kernel/user_util.c6
-rw-r--r--arch/um/os-Linux/aio.c1
-rw-r--r--arch/um/os-Linux/elf_aux.c3
-rw-r--r--arch/um/os-Linux/process.c1
-rw-r--r--arch/um/sys-i386/ldt.c1
19 files changed, 126 insertions, 64 deletions
diff --git a/arch/um/Makefile b/arch/um/Makefile
index ce987266dac..5b5af95721a 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -53,9 +53,13 @@ SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH)
# -Dvmap=kernel_vmap affects everything, and prevents anything from
# referencing the libpcap.o symbol so named.
+#
+# Same things for in6addr_loopback - found in libc.
CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
- $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap
+ $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \
+ -Din6addr_loopback=kernel_in6addr_loopback
+
AFLAGS += $(ARCH_INCLUDE)
USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 14a12d6b3df..16e7dc89f61 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -19,18 +19,44 @@
#include "line.h"
#include "os.h"
-#ifdef CONFIG_NOCONFIG_CHAN
+/* XXX: could well be moved to somewhere else, if needed. */
+static int my_printf(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static int my_printf(const char * fmt, ...)
+{
+ /* Yes, can be called on atomic context.*/
+ char *buf = kmalloc(4096, GFP_ATOMIC);
+ va_list args;
+ int r;
+
+ if (!buf) {
+ /* We print directly fmt.
+ * Yes, yes, yes, feel free to complain. */
+ r = strlen(fmt);
+ } else {
+ va_start(args, fmt);
+ r = vsprintf(buf, fmt, args);
+ va_end(args);
+ fmt = buf;
+ }
-/* The printk's here are wrong because we are complaining that there is no
- * output device, but printk is printing to that output device. The user will
- * never see the error. printf would be better, except it can't run on a
- * kernel stack because it will overflow it.
- * Use printk for now since that will avoid crashing.
- */
+ if (r)
+ r = os_write_file(1, fmt, r);
+ return r;
+
+}
+
+#ifdef CONFIG_NOCONFIG_CHAN
+/* Despite its name, there's no added trailing newline. */
+static int my_puts(const char * buf)
+{
+ return os_write_file(1, buf, strlen(buf));
+}
static void *not_configged_init(char *str, int device, struct chan_opts *opts)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(NULL);
}
@@ -38,27 +64,27 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts)
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 "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-ENODEV);
}
static void not_configged_close(int fd, void *data)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
}
static int not_configged_read(int fd, char *c_out, void *data)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-EIO);
}
static int not_configged_write(int fd, const char *buf, int len, void *data)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-EIO);
}
@@ -66,7 +92,7 @@ static int not_configged_write(int fd, const char *buf, int len, void *data)
static int not_configged_console_write(int fd, const char *buf, int len,
void *data)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-EIO);
}
@@ -74,14 +100,14 @@ static int not_configged_console_write(int fd, const char *buf, int len,
static int not_configged_window_size(int fd, void *data, unsigned short *rows,
unsigned short *cols)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-ENODEV);
}
static void not_configged_free(void *data)
{
- printf(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
}
@@ -457,7 +483,7 @@ static struct chan *parse_chan(char *str, int pri, int device,
}
}
if(ops == NULL){
- printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n",
+ my_printf("parse_chan couldn't parse \"%s\"\n",
str);
return(NULL);
}
@@ -465,7 +491,7 @@ static struct chan *parse_chan(char *str, int pri, int device,
data = (*ops->init)(str, device, opts);
if(data == NULL) return(NULL);
- chan = kmalloc(sizeof(*chan), GFP_KERNEL);
+ chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
if(chan == NULL) return(NULL);
*chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
.primary = 1,
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index 310c1f823f2..04383f98f4d 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -23,7 +23,7 @@ static struct mconsole_command commands[] = {
{ "reboot", mconsole_reboot, MCONSOLE_PROC },
{ "config", mconsole_config, MCONSOLE_PROC },
{ "remove", mconsole_remove, MCONSOLE_PROC },
- { "sysrq", mconsole_sysrq, MCONSOLE_INTR },
+ { "sysrq", mconsole_sysrq, MCONSOLE_PROC },
{ "help", mconsole_help, MCONSOLE_INTR },
{ "cad", mconsole_cad, MCONSOLE_INTR },
{ "stop", mconsole_stop, MCONSOLE_PROC },
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index 0aa620970ad..782ac3a3baf 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -12,4 +12,6 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING);
DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
DEFINE_STR(UM_KERN_INFO, KERN_INFO);
DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
-DEFINE(HOST_ELF_CLASS, ELF_CLASS);
+DEFINE(UM_ELF_CLASS, ELF_CLASS);
+DEFINE(UM_ELFCLASS32, ELFCLASS32);
+DEFINE(UM_ELFCLASS64, ELFCLASS64);
diff --git a/arch/um/include/user.h b/arch/um/include/user.h
index 57ee9e26122..0f865ef4691 100644
--- a/arch/um/include/user.h
+++ b/arch/um/include/user.h
@@ -14,7 +14,9 @@ extern void *um_kmalloc_atomic(int size);
extern void kfree(void *ptr);
extern int in_aton(char *str);
extern int open_gdb_chan(void);
-extern int strlcpy(char *, const char *, int);
+/* These use size_t, however unsigned long is correct on both i386 and x86_64. */
+extern unsigned long strlcpy(char *, const char *, unsigned long);
+extern unsigned long strlcat(char *, const char *, unsigned long);
extern void *um_vmalloc(int size);
extern void vfree(void *ptr);
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index 39cf568ccfa..ea65db679e9 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -82,7 +82,8 @@ unsigned long alloc_stack(int order, int atomic)
unsigned long page;
int flags = GFP_KERNEL;
- if(atomic) flags |= GFP_ATOMIC;
+ if (atomic)
+ flags = GFP_ATOMIC;
page = __get_free_pages(flags, order);
if(page == 0)
return(0);
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
index e89218958f3..a52751108aa 100644
--- a/arch/um/kernel/sigio_user.c
+++ b/arch/um/kernel/sigio_user.c
@@ -340,7 +340,7 @@ static int setup_initial_poll(int fd)
{
struct pollfd *p;
- p = um_kmalloc(sizeof(struct pollfd));
+ p = um_kmalloc_atomic(sizeof(struct pollfd));
if(p == NULL){
printk("setup_initial_poll : failed to allocate poll\n");
return(-1);
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h
index 6ee3f3902e6..7da0c2def0e 100644
--- a/arch/um/kernel/skas/include/uaccess-skas.h
+++ b/arch/um/kernel/skas/include/uaccess-skas.h
@@ -18,12 +18,6 @@
((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
((unsigned long) (addr) + (size) >= (unsigned long)(addr))))
-static inline int verify_area_skas(int type, const void __user * addr,
- unsigned long size)
-{
- return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
-}
-
extern int copy_from_user_skas(void *to, const void __user *from, int n);
extern int copy_to_user_skas(void __user *to, const void *from, int n);
extern int strncpy_from_user_skas(char *dst, const char __user *src, int count);
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 0a562c3c0fd..f5b0636f9ad 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -193,12 +193,12 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
r = pte_read(*npte);
w = pte_write(*npte);
x = pte_exec(*npte);
- if(!pte_dirty(*npte))
- w = 0;
- if(!pte_young(*npte)){
- r = 0;
- w = 0;
- }
+ if (!pte_young(*npte)) {
+ r = 0;
+ w = 0;
+ } else if (!pte_dirty(*npte)) {
+ w = 0;
+ }
if(force || pte_newpage(*npte)){
if(pte_present(*npte))
ret = add_mmap(addr,
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
index 87cc6fd76ce..d297429ac36 100644
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -18,6 +18,7 @@
#include "asm/a.out.h"
#include "asm/current.h"
#include "asm/irq.h"
+#include "sysdep/sigcontext.h"
#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
@@ -39,6 +40,12 @@ int handle_page_fault(unsigned long address, unsigned long ip,
int err = -EFAULT;
*code_out = SEGV_MAPERR;
+
+ /* If the fault was during atomic operation, don't take the fault, just
+ * fail. */
+ if (in_atomic())
+ goto out_nosemaphore;
+
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
if(!vma)
@@ -89,6 +96,7 @@ survive:
flush_tlb_page(vma, address);
out:
up_read(&mm->mmap_sem);
+out_nosemaphore:
return(err);
/*
@@ -125,7 +133,15 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
}
else if(current->mm == NULL)
panic("Segfault with no mm");
- err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
+
+ if (SEGV_IS_FIXABLE(&fi))
+ err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
+ else {
+ err = -EFAULT;
+ /* A thread accessed NULL, we get a fault, but CR2 is invalid.
+ * This code is used in __do_copy_from_user() of TT mode. */
+ address = 0;
+ }
catcher = current->thread.fault_catcher;
if(!err)
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
index aa6db384af8..dc2ebfa8c54 100644
--- a/arch/um/kernel/tt/include/uaccess-tt.h
+++ b/arch/um/kernel/tt/include/uaccess-tt.h
@@ -33,12 +33,6 @@ extern unsigned long uml_physmem;
(((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
(under_task_size(addr, size) || is_stack(addr, size))))
-static inline int verify_area_tt(int type, const void __user * addr,
- unsigned long size)
-{
- return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
-}
-
extern unsigned long get_fault_addr(void);
extern int __do_copy_from_user(void *to, const void *from, int n,
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index 0de05a268b2..cfaa373a6e7 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -23,10 +23,11 @@
#include "mem_user.h"
#include "tlb.h"
#include "mode.h"
+#include "mode_kern.h"
#include "init.h"
#include "tt.h"
-int switch_to_tt(void *prev, void *next, void *last)
+void switch_to_tt(void *prev, void *next)
{
struct task_struct *from, *to, *prev_sched;
unsigned long flags;
diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
index f01475512ec..8c220f054b6 100644
--- a/arch/um/kernel/tt/uaccess_user.c
+++ b/arch/um/kernel/tt/uaccess_user.c
@@ -22,8 +22,15 @@ int __do_copy_from_user(void *to, const void *from, int n,
__do_copy, &faulted);
TASK_REGS(get_current())->tt = save;
- if(!faulted) return(0);
- else return(n - (fault - (unsigned long) from));
+ if(!faulted)
+ return 0;
+ else if (fault)
+ return n - (fault - (unsigned long) from);
+ else
+ /* In case of a general protection fault, we don't have the
+ * fault address, so NULL is used instead. Pretend we didn't
+ * copy anything. */
+ return n;
}
static void __do_strncpy(void *dst, const void *src, int count)
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
index 186c2888501..0b21d59ba0c 100644
--- a/arch/um/kernel/umid.c
+++ b/arch/um/kernel/umid.c
@@ -31,6 +31,8 @@ static char *uml_dir = UML_DIR;
/* Changed by set_umid */
static int umid_is_random = 1;
static int umid_inited = 0;
+/* Have we created the files? Should we remove them? */
+static int umid_owned = 0;
static int make_umid(int (*printer)(const char *fmt, ...));
@@ -82,20 +84,21 @@ int __init umid_file_name(char *name, char *buf, int len)
extern int tracing_pid;
-static int __init create_pid_file(void)
+static void __init create_pid_file(void)
{
char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
char pid[sizeof("nnnnn\0")];
int fd, n;
- if(umid_file_name("pid", file, sizeof(file))) return 0;
+ if(umid_file_name("pid", file, sizeof(file)))
+ return;
fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))),
0644);
if(fd < 0){
printf("Open of machine pid file \"%s\" failed: %s\n",
file, strerror(-fd));
- return 0;
+ return;
}
sprintf(pid, "%d\n", os_getpid());
@@ -103,7 +106,6 @@ static int __init create_pid_file(void)
if(n != strlen(pid))
printf("Write of pid file failed - err = %d\n", -n);
os_close_file(fd);
- return 0;
}
static int actually_do_remove(char *dir)
@@ -147,7 +149,8 @@ static int actually_do_remove(char *dir)
void remove_umid_dir(void)
{
char dir[strlen(uml_dir) + UMID_LEN + 1];
- if(!umid_inited) return;
+ if (!umid_owned)
+ return;
sprintf(dir, "%s%s", uml_dir, umid);
actually_do_remove(dir);
@@ -155,11 +158,12 @@ void remove_umid_dir(void)
char *get_umid(int only_if_set)
{
- if(only_if_set && umid_is_random) return(NULL);
- return(umid);
+ if(only_if_set && umid_is_random)
+ return NULL;
+ return umid;
}
-int not_dead_yet(char *dir)
+static int not_dead_yet(char *dir)
{
char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
char pid[sizeof("nnnnn\0")], *end;
@@ -193,7 +197,8 @@ int not_dead_yet(char *dir)
(p == CHOOSE_MODE(tracing_pid, os_getpid())))
dead = 1;
}
- if(!dead) return(1);
+ if(!dead)
+ return(1);
return(actually_do_remove(dir));
}
@@ -232,16 +237,13 @@ static int __init make_uml_dir(void)
strlcpy(dir, home, sizeof(dir));
uml_dir++;
}
+ strlcat(dir, uml_dir, sizeof(dir));
len = strlen(dir);
- strncat(dir, uml_dir, sizeof(dir) - len);
- len = strlen(dir);
- if((len > 0) && (len < sizeof(dir) - 1) && (dir[len - 1] != '/')){
- dir[len] = '/';
- dir[len + 1] = '\0';
- }
+ if (len > 0 && dir[len - 1] != '/')
+ strlcat(dir, "/", sizeof(dir));
uml_dir = malloc(strlen(dir) + 1);
- if(uml_dir == NULL){
+ if (uml_dir == NULL) {
printf("make_uml_dir : malloc failed, errno = %d\n", errno);
exit(1);
}
@@ -286,6 +288,7 @@ static int __init make_umid(int (*printer)(const char *fmt, ...))
if(errno == EEXIST){
if(not_dead_yet(tmp)){
(*printer)("umid '%s' is in use\n", umid);
+ umid_owned = 0;
return(-1);
}
err = mkdir(tmp, 0777);
@@ -296,7 +299,8 @@ static int __init make_umid(int (*printer)(const char *fmt, ...))
return(-1);
}
- return(0);
+ umid_owned = 1;
+ return 0;
}
__uml_setup("uml_dir=", set_uml_dir,
@@ -309,7 +313,8 @@ static int __init make_umid_setup(void)
/* one function with the ordering we need ... */
make_uml_dir();
make_umid(printf);
- return create_pid_file();
+ create_pid_file();
+ return 0;
}
__uml_postsetup(make_umid_setup);
diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
index a25f3ea11fd..41d17c71511 100644
--- a/arch/um/kernel/user_util.c
+++ b/arch/um/kernel/user_util.c
@@ -128,6 +128,12 @@ void setup_machinename(char *machine_out)
struct utsname host;
uname(&host);
+#if defined(UML_CONFIG_UML_X86) && !defined(UML_CONFIG_64BIT)
+ if (!strcmp(host.machine, "x86_64")) {
+ strcpy(machine_out, "i686");
+ return;
+ }
+#endif
strcpy(machine_out, host.machine);
}
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
index 298d5632128..f6e64026f99 100644
--- a/arch/um/os-Linux/aio.c
+++ b/arch/um/os-Linux/aio.c
@@ -144,6 +144,7 @@ static int aio_thread(void *arg)
"errno = %d\n", errno);
}
else {
+ /* This is safe as we've just a pointer here. */
aio = (struct aio_context *) (long) event.data;
if(update_aio(aio, event.res)){
do_aio(ctx, aio);
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
index e770cb02957..ab33cb3c74e 100644
--- a/arch/um/os-Linux/elf_aux.c
+++ b/arch/um/os-Linux/elf_aux.c
@@ -14,7 +14,8 @@
#include "mem_user.h"
#include <kernel-offsets.h>
-#if HOST_ELF_CLASS == ELFCLASS32
+/* Use the one from the kernel - the host may miss it, if having old headers. */
+#if UM_ELF_CLASS == UM_ELFCLASS32
typedef Elf32_auxv_t elf_auxv_t;
#else
typedef Elf64_auxv_t elf_auxv_t;
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index d32413e4b4c..d9c52387c4a 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -3,6 +3,7 @@
* Licensed under the GPL
*/
+#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index bd3c34aa52e..36b5c2c1328 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -83,6 +83,7 @@ int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
goto out;
}
p = buf;
+ break;
default:
res = -ENOSYS;
goto out;