diff options
Diffstat (limited to 'arch/um')
136 files changed, 1639 insertions, 1908 deletions
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index bab51d619173..09c1aca6339f 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug @@ -47,13 +47,4 @@ config GCOV If you're involved in UML kernel development and want to use gcov, say Y. If you're unsure, say N. -config SYSCALL_DEBUG - bool "Enable system call debugging" - depends on DEBUG_INFO - help - This adds some system debugging to UML, including keeping a ring buffer - with recent system calls and some global and per-task statistics. - - If unsure, say N - endmenu diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index dfd88b652fbe..11154b6773ec 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 @@ -4,11 +4,17 @@ core-y += arch/um/sys-x86_64/ START := 0x60000000 +_extra_flags_ = -fno-builtin -m64 -mcmodel=kernel + #We #undef __x86_64__ for kernelspace, not for userspace where #it's needed for headers to work! -CFLAGS += -U__$(SUBARCH)__ -fno-builtin -USER_CFLAGS += -fno-builtin +CFLAGS += -U__$(SUBARCH)__ $(_extra_flags_) +USER_CFLAGS += $(_extra_flags_) + CHECKFLAGS += -m64 +AFLAGS += -m64 +LDFLAGS += -m elf_x86_64 +CPPFLAGS += -m64 ELF_ARCH := i386:x86-64 ELF_FORMAT := elf64-x86-64 @@ -16,3 +22,4 @@ ELF_FORMAT := elf64-x86-64 # Not on all 64-bit distros /lib is a symlink to /lib64. PLD is an example. LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib64 +LINK-y += -m64 diff --git a/arch/um/defconfig b/arch/um/defconfig index 402a74dc5026..780cc0a4a128 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -526,4 +526,3 @@ CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_GPROF is not set # CONFIG_GCOV is not set -# CONFIG_SYSCALL_DEBUG is not set diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 7218c754505b..3576b3cc505e 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -110,7 +110,7 @@ static void not_configged_free(void *data) "UML\n"); } -static struct chan_ops not_configged_ops = { +static const struct chan_ops not_configged_ops = { .init = not_configged_init, .open = not_configged_open, .close = not_configged_close, @@ -373,7 +373,7 @@ int console_write_chan(struct list_head *chans, const char *buf, int len) } int console_open_chan(struct line *line, struct console *co, - struct chan_opts *opts) + const struct chan_opts *opts) { int err; @@ -494,10 +494,10 @@ int chan_config_string(struct list_head *chans, char *str, int size, struct chan_type { char *key; - struct chan_ops *ops; + const struct chan_ops *ops; }; -static struct chan_type chan_table[] = { +static const struct chan_type chan_table[] = { { "fd", &fd_ops }, #ifdef CONFIG_NULL_CHAN @@ -534,17 +534,17 @@ static struct chan_type chan_table[] = { }; static struct chan *parse_chan(struct line *line, char *str, int device, - struct chan_opts *opts) + const struct chan_opts *opts) { - struct chan_type *entry; - struct chan_ops *ops; + const struct chan_type *entry; + const struct chan_ops *ops; struct chan *chan; void *data; int i; ops = NULL; data = NULL; - for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){ + for(i = 0; i < ARRAY_SIZE(chan_table); i++){ entry = &chan_table[i]; if(!strncmp(str, entry->key, strlen(entry->key))){ ops = entry->ops; @@ -582,7 +582,7 @@ static struct chan *parse_chan(struct line *line, char *str, int device, } int parse_chan_pair(char *str, struct line *line, int device, - struct chan_opts *opts) + const struct chan_opts *opts) { struct list_head *chans = &line->chan_list; struct chan *new, *chan; diff --git a/arch/um/drivers/daemon.h b/arch/um/drivers/daemon.h index 7326c42f7ef9..3bc3cf6b94aa 100644 --- a/arch/um/drivers/daemon.h +++ b/arch/um/drivers/daemon.h @@ -18,7 +18,7 @@ struct daemon_data { void *dev; }; -extern struct net_user_info daemon_user_info; +extern const struct net_user_info daemon_user_info; extern int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri); diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index 53d09ed78b42..824386974f88 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c @@ -57,7 +57,7 @@ static int daemon_write(int fd, struct sk_buff **skb, (struct daemon_data *) &lp->user)); } -static struct net_kern_info daemon_kern_info = { +static const struct net_kern_info daemon_kern_info = { .init = daemon_init, .protocol = eth_protocol, .read = daemon_read, diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c index c944265955e2..77954ea77043 100644 --- a/arch/um/drivers/daemon_user.c +++ b/arch/um/drivers/daemon_user.c @@ -182,7 +182,7 @@ static int daemon_set_mtu(int mtu, void *data) return(mtu); } -struct net_user_info daemon_user_info = { +const struct net_user_info daemon_user_info = { .init = daemon_user_init, .open = daemon_open, .close = NULL, diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index c41f75e4acb5..108b7dafbd0e 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -20,7 +20,7 @@ struct fd_chan { char str[sizeof("1234567890\0")]; }; -static void *fd_init(char *str, int device, struct chan_opts *opts) +static void *fd_init(char *str, int device, const struct chan_opts *opts) { struct fd_chan *data; char *end; @@ -77,7 +77,7 @@ static void fd_close(int fd, void *d) } } -struct chan_ops fd_ops = { +const struct chan_ops fd_ops = { .type = "fd", .init = fd_init, .open = fd_open, diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index d18a974735e6..64ff22aa077b 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c @@ -35,7 +35,6 @@ */ #include <linux/module.h> -#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index 37232f908cd7..d247ef45c374 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -280,7 +280,7 @@ static int hostmixer_release(struct inode *inode, struct file *file) /* kernel module operations */ -static struct file_operations hostaudio_fops = { +static const struct file_operations hostaudio_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = hostaudio_read, @@ -292,7 +292,7 @@ static struct file_operations hostaudio_fops = { .release = hostaudio_release, }; -static struct file_operations hostmixer_fops = { +static const struct file_operations hostmixer_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = hostmixer_ioctl_mixdev, diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 6c2d4ccaf20f..563ce7690a1e 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -8,7 +8,6 @@ #include "linux/list.h" #include "linux/kd.h" #include "linux/interrupt.h" -#include "linux/devfs_fs_kernel.h" #include "asm/uaccess.h" #include "chan_kern.h" #include "irq_user.h" @@ -252,7 +251,7 @@ void line_set_termios(struct tty_struct *tty, struct termios * old) /* nothing */ } -static struct { +static const struct { int cmd; char *level; char *name; @@ -374,7 +373,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data, int err; /* Interrupts are enabled here because we registered the interrupt with - * SA_INTERRUPT (see line_setup_irq).*/ + * IRQF_DISABLED (see line_setup_irq).*/ spin_lock_irq(&line->lock); err = flush_buffer(line); @@ -406,8 +405,8 @@ static irqreturn_t line_write_interrupt(int irq, void *data, int line_setup_irq(int fd, int input, int output, struct line *line, void *data) { - struct line_driver *driver = line->driver; - int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM; + const struct line_driver *driver = line->driver; + int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM; if (input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, @@ -559,7 +558,7 @@ int line_setup(struct line *lines, unsigned int num, char *init) } int line_config(struct line *lines, unsigned int num, char *str, - struct chan_opts *opts) + const struct chan_opts *opts) { struct line *line; char *new; @@ -655,7 +654,6 @@ struct tty_driver *line_register_devfs(struct lines *set, driver->driver_name = line_driver->name; driver->name = line_driver->device_name; - driver->devfs_name = line_driver->devfs_name; driver->major = line_driver->major; driver->minor_start = line_driver->minor_start; driver->type = line_driver->type; @@ -769,7 +767,7 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) spin_unlock(&winch_handler_lock); if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, + IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, "winch", winch) < 0) printk("register_winch_irq - failed to register IRQ\n"); } diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h index a2c6db243458..bc56af9d3e53 100644 --- a/arch/um/drivers/mcast.h +++ b/arch/um/drivers/mcast.h @@ -13,7 +13,7 @@ struct mcast_data { void *dev; }; -extern struct net_user_info mcast_user_info; +extern const struct net_user_info mcast_user_info; extern int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri); diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index 3a7af18cf944..c090fbd464e7 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c @@ -61,7 +61,7 @@ static int mcast_write(int fd, struct sk_buff **skb, (struct mcast_data *) &lp->user); } -static struct net_kern_info mcast_kern_info = { +static const struct net_kern_info mcast_kern_info = { .init = mcast_init, .protocol = eth_protocol, .read = mcast_read, diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c index afe85bfa66e0..4d2bd39a85bc 100644 --- a/arch/um/drivers/mcast_user.c +++ b/arch/um/drivers/mcast_user.c @@ -152,7 +152,7 @@ static int mcast_set_mtu(int mtu, void *data) return(mtu); } -struct net_user_info mcast_user_info = { +const struct net_user_info mcast_user_info = { .init = mcast_user_init, .open = mcast_open, .close = mcast_close, diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 6d7173fc55a3..773a134e7fdb 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -300,8 +300,6 @@ void mconsole_reboot(struct mc_request *req) machine_restart(NULL); } -extern void ctrl_alt_del(void); - void mconsole_cad(struct mc_request *req) { mconsole_reply(req, "", 0, 0); @@ -499,7 +497,7 @@ static void mconsole_get_config(int (*get_config)(char *, char *, int, } error = NULL; - size = sizeof(default_buf)/sizeof(default_buf[0]); + size = ARRAY_SIZE(default_buf); buf = default_buf; while(1){ @@ -600,6 +598,11 @@ out: mconsole_reply(req, err_msg, err, 0); } +struct mconsole_output { + struct list_head list; + struct mc_request *req; +}; + static DEFINE_SPINLOCK(console_lock); static LIST_HEAD(clients); static char console_buf[MCONSOLE_MAX_DATA]; @@ -624,10 +627,10 @@ static void console_write(struct console *console, const char *string, return; list_for_each(ele, &clients){ - struct mconsole_entry *entry; + struct mconsole_output *entry; - entry = list_entry(ele, struct mconsole_entry, list); - mconsole_reply_len(&entry->request, console_buf, + entry = list_entry(ele, struct mconsole_output, list); + mconsole_reply_len(entry->req, console_buf, console_index, 0, 1); } @@ -651,10 +654,10 @@ late_initcall(mc_add_console); static void with_console(struct mc_request *req, void (*proc)(void *), void *arg) { - struct mconsole_entry entry; + struct mconsole_output entry; unsigned long flags; - entry.request = *req; + entry.req = req; list_add(&entry.list, &clients); spin_lock_irqsave(&console_lock, flags); @@ -779,7 +782,7 @@ static int mconsole_init(void) register_reboot_notifier(&reboot_notifier); err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, + IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, "mconsole", (void *)sock); if (err){ printk("Failed to get IRQ for management console\n"); diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index 4b109fe7fff8..17068eb746c0 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c @@ -16,9 +16,15 @@ #include "user.h" #include "mconsole.h" #include "umid.h" +#include "user_util.h" static struct mconsole_command commands[] = { - { "version", mconsole_version, MCONSOLE_INTR }, + /* With uts namespaces, uts information becomes process-specific, so + * we need a process context. If we try handling this in interrupt + * context, we may hit an exiting process without a valid uts + * namespace. + */ + { "version", mconsole_version, MCONSOLE_PROC }, { "halt", mconsole_halt, MCONSOLE_PROC }, { "reboot", mconsole_reboot, MCONSOLE_PROC }, { "config", mconsole_config, MCONSOLE_PROC }, @@ -60,14 +66,14 @@ static struct mconsole_command *mconsole_parse(struct mc_request *req) struct mconsole_command *cmd; int i; - for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){ + for(i = 0; i < ARRAY_SIZE(commands); i++){ cmd = &commands[i]; if(!strncmp(req->request.data, cmd->command, strlen(cmd->command))){ - return(cmd); + return cmd; } } - return(NULL); + return NULL; } #define MIN(a,b) ((a)<(b) ? (a):(b)) @@ -125,6 +131,10 @@ int mconsole_get_request(int fd, struct mc_request *req) int mconsole_reply_len(struct mc_request *req, const char *str, int total, int err, int more) { + /* XXX This is a stack consumption problem. It'd be nice to + * make it global and serialize access to it, but there are a + * ton of callers to this function. + */ struct mconsole_reply reply; int len, n; diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c index 022f67bb6873..9a3b5daf6250 100644 --- a/arch/um/drivers/mmapper_kern.c +++ b/arch/um/drivers/mmapper_kern.c @@ -85,7 +85,7 @@ mmapper_release(struct inode *inode, struct file *file) return 0; } -static struct file_operations mmapper_fops = { +static const struct file_operations mmapper_fops = { .owner = THIS_MODULE, .read = mmapper_read, .write = mmapper_write, @@ -95,7 +95,7 @@ static struct file_operations mmapper_fops = { .release = mmapper_release, }; -static struct miscdevice mmapper_dev = { +static const struct miscdevice mmapper_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "mmapper", .fops = &mmapper_fops diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 8c7279bb353b..300a54a6523e 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -31,6 +31,11 @@ #include "irq_user.h" #include "irq_kern.h" +static inline void set_ether_mac(struct net_device *dev, unsigned char *addr) +{ + memcpy(dev->dev_addr, addr, ETH_ALEN); +} + #define DRIVER_NAME "uml-netdev" static DEFINE_SPINLOCK(opened_lock); @@ -109,18 +114,11 @@ static int uml_net_open(struct net_device *dev) struct uml_net_private *lp = dev->priv; int err; - spin_lock(&lp->lock); - if(lp->fd >= 0){ err = -ENXIO; goto out; } - if(!lp->have_mac){ - dev_ip_addr(dev, &lp->mac[2]); - set_ether_mac(dev, lp->mac); - } - lp->fd = (*lp->open)(&lp->user); if(lp->fd < 0){ err = lp->fd; @@ -128,7 +126,7 @@ static int uml_net_open(struct net_device *dev) } err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt, - SA_INTERRUPT | SA_SHIRQ, dev->name, dev); + IRQF_DISABLED | IRQF_SHARED, dev->name, dev); if(err != 0){ printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err); err = -ENETUNREACH; @@ -144,8 +142,6 @@ static int uml_net_open(struct net_device *dev) */ while((err = uml_net_rx(dev)) > 0) ; - spin_unlock(&lp->lock); - spin_lock(&opened_lock); list_add(&lp->list, &opened); spin_unlock(&opened_lock); @@ -155,7 +151,6 @@ out_close: if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); lp->fd = -1; out: - spin_unlock(&lp->lock); return err; } @@ -164,15 +159,12 @@ static int uml_net_close(struct net_device *dev) struct uml_net_private *lp = dev->priv; netif_stop_queue(dev); - spin_lock(&lp->lock); free_irq(dev->irq, dev); if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); lp->fd = -1; - spin_unlock(&lp->lock); - spin_lock(&opened_lock); list_del(&lp->list); spin_unlock(&opened_lock); @@ -241,9 +233,9 @@ static int uml_net_set_mac(struct net_device *dev, void *addr) struct uml_net_private *lp = dev->priv; struct sockaddr *hwaddr = addr; - spin_lock(&lp->lock); - memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); - spin_unlock(&lp->lock); + spin_lock_irq(&lp->lock); + set_ether_mac(dev, hwaddr->sa_data); + spin_unlock_irq(&lp->lock); return(0); } @@ -253,7 +245,7 @@ static int uml_net_change_mtu(struct net_device *dev, int new_mtu) struct uml_net_private *lp = dev->priv; int err = 0; - spin_lock(&lp->lock); + spin_lock_irq(&lp->lock); new_mtu = (*lp->set_mtu)(new_mtu, &lp->user); if(new_mtu < 0){ @@ -264,7 +256,7 @@ static int uml_net_change_mtu(struct net_device *dev, int new_mtu) dev->mtu = new_mtu; out: - spin_unlock(&lp->lock); + spin_unlock_irq(&lp->lock); return err; } @@ -290,6 +282,37 @@ void uml_net_user_timer_expire(unsigned long _conn) #endif } +static void setup_etheraddr(char *str, unsigned char *addr) +{ + char *end; + int i; + + if(str == NULL) + goto random; + + for(i=0;i<6;i++){ + addr[i] = simple_strtoul(str, &end, 16); + if((end == str) || + ((*end != ':') && (*end != ',') && (*end != '\0'))){ + printk(KERN_ERR + "setup_etheraddr: failed to parse '%s' " + "as an ethernet address\n", str); + goto random; + } + str = end + 1; + } + if(addr[0] & 1){ + printk(KERN_ERR + "Attempt to assign a broadcast ethernet address to a " + "device disallowed\n"); + goto random; + } + return; + +random: + random_ether_addr(addr); +} + static DEFINE_SPINLOCK(devices_lock); static LIST_HEAD(devices); @@ -325,15 +348,13 @@ static int eth_configure(int n, void *init, char *mac, list_add(&device->list, &devices); spin_unlock(&devices_lock); - if (setup_etheraddr(mac, device->mac)) - device->have_mac = 1; + setup_etheraddr(mac, device->mac); printk(KERN_INFO "Netdevice %d ", n); - if (device->have_mac) - printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", - device->mac[0], device->mac[1], - device->mac[2], device->mac[3], - device->mac[4], device->mac[5]); + printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", + device->mac[0], device->mac[1], + device->mac[2], device->mac[3], + device->mac[4], device->mac[5]); printk(": "); dev = alloc_etherdev(size); if (dev == NULL) { @@ -399,7 +420,6 @@ static int eth_configure(int n, void *init, char *mac, .dev = dev, .fd = -1, .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0}, - .have_mac = device->have_mac, .protocol = transport->kern->protocol, .open = transport->user->open, .close = transport->user->close, @@ -414,14 +434,12 @@ static int eth_configure(int n, void *init, char *mac, init_timer(&lp->tl); spin_lock_init(&lp->lock); lp->tl.function = uml_net_user_timer_expire; - if (lp->have_mac) - memcpy(lp->mac, device->mac, sizeof(lp->mac)); + memcpy(lp->mac, device->mac, sizeof(lp->mac)); if (transport->user->init) (*transport->user->init)(&lp->user, dev); - if (device->have_mac) - set_ether_mac(dev, device->mac); + set_ether_mac(dev, device->mac); return 0; } @@ -564,12 +582,13 @@ static int eth_setup(char *str) int n, err; err = eth_parse(str, &n, &str); - if(err) return(1); + if(err) + return 1; - new = alloc_bootmem(sizeof(new)); + new = alloc_bootmem(sizeof(*new)); if (new == NULL){ printk("eth_init : alloc_bootmem failed\n"); - return(1); + return 1; } INIT_LIST_HEAD(&new->list); @@ -577,7 +596,7 @@ static int eth_setup(char *str) new->init = str; list_add_tail(&new->list, ð_cmd_line); - return(1); + return 1; } __setup("eth", eth_setup); @@ -749,54 +768,6 @@ static void close_devices(void) __uml_exitcall(close_devices); -int setup_etheraddr(char *str, unsigned char *addr) -{ - char *end; - int i; - - if(str == NULL) - return(0); - for(i=0;i<6;i++){ - addr[i] = simple_strtoul(str, &end, 16); - if((end == str) || - ((*end != ':') && (*end != ',') && (*end != '\0'))){ - printk(KERN_ERR - "setup_etheraddr: failed to parse '%s' " - "as an ethernet address\n", str); - return(0); - } - str = end + 1; - } - if(addr[0] & 1){ - printk(KERN_ERR - "Attempt to assign a broadcast ethernet address to a " - "device disallowed\n"); - return(0); - } - return(1); -} - -void dev_ip_addr(void *d, unsigned char *bin_buf) -{ - struct net_device *dev = d; - struct in_device *ip = dev->ip_ptr; - struct in_ifaddr *in; - - if((ip == NULL) || ((in = ip->ifa_list) == NULL)){ - printk(KERN_WARNING "dev_ip_addr - device not assigned an " - "IP address\n"); - return; - } - memcpy(bin_buf, &in->ifa_address, sizeof(in->ifa_address)); -} - -void set_ether_mac(void *d, unsigned char *addr) -{ - struct net_device *dev = d; - - memcpy(dev->dev_addr, addr, ETH_ALEN); -} - struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) { if((skb != NULL) && (skb_tailroom(skb) < extra)){ @@ -834,7 +805,7 @@ int dev_netmask(void *d, void *m) struct net_device *dev = d; struct in_device *ip = dev->ip_ptr; struct in_ifaddr *in; - __u32 *mask_out = m; + __be32 *mask_out = m; if(ip == NULL) return(1); diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 0a7786e00cfb..f3a3f8a29c7a 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -12,6 +12,7 @@ #include <string.h> #include <sys/socket.h> #include <sys/wait.h> +#include <sys/time.h> #include "user.h" #include "user_util.h" #include "kern_util.h" @@ -22,13 +23,14 @@ int tap_open_common(void *dev, char *gate_addr) { int tap_addr[4]; - if(gate_addr == NULL) return(0); + if(gate_addr == NULL) + return 0; if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){ printk("Invalid tap IP address - '%s'\n", gate_addr); - return(-EINVAL); + return -EINVAL; } - return(0); + return 0; } void tap_check_ips(char *gate_addr, unsigned char *eth_addr) @@ -94,25 +96,25 @@ int net_read(int fd, void *buf, int len) n = os_read_file(fd, buf, len); if(n == -EAGAIN) - return(0); + return 0; else if(n == 0) - return(-ENOTCONN); - return(n); + return -ENOTCONN; + return n; } int net_recvfrom(int fd, void *buf, int len) { int n; - while(((n = recvfrom(fd, buf, len, 0, NULL, NULL)) < 0) && - (errno == EINTR)) ; - + CATCH_EINTR(n = recvfrom(fd, buf, len, 0, NULL, NULL)); if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); + if(errno == EAGAIN) + return 0; + return -errno; } - else if(n == 0) return(-ENOTCONN); - return(n); + else if(n == 0) + return -ENOTCONN; + return n; } int net_write(int fd, void *buf, int len) @@ -122,37 +124,41 @@ int net_write(int fd, void *buf, int len) n = os_write_file(fd, buf, len); if(n == -EAGAIN) - return(0); + return 0; else if(n == 0) - return(-ENOTCONN); - return(n); + return -ENOTCONN; + return n; } int net_send(int fd, void *buf, int len) { int n; - while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ; + CATCH_EINTR(n = send(fd, buf, len, 0)); if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); + if(errno == EAGAIN) + return 0; + return -errno; } - else if(n == 0) return(-ENOTCONN); - return(n); + else if(n == 0) + return -ENOTCONN; + return n; } int net_sendto(int fd, void *buf, int len, void *to, int sock_len) { int n; - while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to, - sock_len)) < 0) && (errno == EINTR)) ; + CATCH_EINTR(n = sendto(fd, buf, len, 0, (struct sockaddr *) to, + sock_len)); if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); + if(errno == EAGAIN) + return 0; + return -errno; } - else if(n == 0) return(-ENOTCONN); - return(n); + else if(n == 0) + return -ENOTCONN; + return n; } struct change_pre_exec_data { @@ -176,7 +182,7 @@ static int change_tramp(char **argv, char *output, int output_len) err = os_pipe(fds, 1, 0); if(err < 0){ printk("change_tramp - pipe failed, err = %d\n", -err); - return(err); + return err; } pe_data.close_me = fds[0]; pe_data.stdout = fds[1]; @@ -190,7 +196,7 @@ static int change_tramp(char **argv, char *output, int output_len) if (pid > 0) CATCH_EINTR(err = waitpid(pid, NULL, 0)); - return(pid); + return pid; } static void change(char *dev, char *what, unsigned char *addr, @@ -241,26 +247,15 @@ char *split_if_spec(char *str, ...) va_start(ap, str); while((arg = va_arg(ap, char **)) != NULL){ if(*str == '\0') - return(NULL); + return NULL; end = strchr(str, ','); if(end != str) *arg = str; if(end == NULL) - return(NULL); + return NULL; *end++ = '\0'; str = end; } va_end(ap); - return(str); + return str; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c index 14cc5f78398a..9016c68beee8 100644 --- a/arch/um/drivers/null.c +++ b/arch/um/drivers/null.c @@ -8,9 +8,10 @@ #include "chan_user.h" #include "os.h" +/* This address is used only as a unique identifer */ static int null_chan; -static void *null_init(char *str, int device, struct chan_opts *opts) +static void *null_init(char *str, int device, const struct chan_opts *opts) { return(&null_chan); } @@ -31,7 +32,7 @@ static void null_free(void *data) { } -struct chan_ops null_ops = { +const struct chan_ops null_ops = { .type = "null", .init = null_init, .open = null_open, diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 466ff2c2f918..6e1ef8558283 100644 --- a/arch/um/drivers/pcap_kern.c +++ b/arch/um/drivers/pcap_kern.c @@ -46,7 +46,7 @@ static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) return(-EPERM); } -static struct net_kern_info pcap_kern_info = { +static const struct net_kern_info pcap_kern_info = { .init = pcap_init, .protocol = eth_protocol, .read = pcap_read, @@ -76,7 +76,7 @@ int pcap_setup(char *str, char **mac_out, void *data) if(host_if != NULL) init->host_if = host_if; - for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){ + for(i = 0; i < ARRAY_SIZE(options); i++){ if(options[i] == NULL) continue; if(!strcmp(options[i], "promisc")) diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c index edfcb29273e1..2ef641ded960 100644 --- a/arch/um/drivers/pcap_user.c +++ b/arch/um/drivers/pcap_user.c @@ -120,7 +120,7 @@ int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri) return(hdata.len); } -struct net_user_info pcap_user_info = { +const struct net_user_info pcap_user_info = { .init = pcap_user_init, .open = pcap_open, .close = NULL, diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 189839e4f1d4..73755f37a8a8 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -105,7 +105,7 @@ static int port_accept(struct port_list *port) .port = port }); if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, + IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, "telnetd", conn)){ printk(KERN_ERR "port_accept : failed to get IRQ for " "telnetd\n"); @@ -186,7 +186,7 @@ void *port_data(int port_num) goto out_free; } if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port", + IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, "port", port)){ printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num); goto out_close; diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index c43e8bb32502..f2e8fc42ecc2 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -27,7 +27,7 @@ struct port_chan { char dev[sizeof("32768\0")]; }; -static void *port_init(char *str, int device, struct chan_opts *opts) +static void *port_init(char *str, int device, const struct chan_opts *opts) { struct port_chan *data; void *kern_data; @@ -100,7 +100,7 @@ static void port_close(int fd, void *d) os_close_file(fd); } -struct chan_ops port_ops = { +const struct chan_ops port_ops = { .type = "port", .init = port_init, .open = port_open, diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index 1c555c38de4d..abec620e8380 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -22,7 +22,7 @@ struct pty_chan { char dev_name[sizeof("/dev/pts/0123456\0")]; }; -static void *pty_chan_init(char *str, int device, struct chan_opts *opts) +static void *pty_chan_init(char *str, int device, const struct chan_opts *opts) { struct pty_chan *data; @@ -118,7 +118,7 @@ static int pty_open(int input, int output, int primary, void *d, return(fd); } -struct chan_ops pty_ops = { +const struct chan_ops pty_ops = { .type = "pty", .init = pty_chan_init, .open = pty_open, @@ -131,7 +131,7 @@ struct chan_ops pty_ops = { .winch = 0, }; -struct chan_ops pts_ops = { +const struct chan_ops pts_ops = { .type = "pts", .init = pty_chan_init, .open = pts_open, diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index ba471f5864a6..73b2bdd6d2d3 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c @@ -20,6 +20,10 @@ #define RNG_MISCDEV_MINOR 183 /* official */ +/* Changed at init time, in the non-modular case, and at module load + * time, in the module case. Presumably, the module subsystem + * protects against a module being loaded twice at the same time. + */ static int random_fd = -1; static int rng_dev_open (struct inode *inode, struct file *filp) @@ -68,7 +72,7 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, return ret; } -static struct file_operations rng_chrdev_ops = { +static const struct file_operations rng_chrdev_ops = { .owner = THIS_MODULE, .open = rng_dev_open, .read = rng_dev_read, diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h index bb0dab41c2e4..c64f8c61d274 100644 --- a/arch/um/drivers/slip.h +++ b/arch/um/drivers/slip.h @@ -12,7 +12,7 @@ struct slip_data { struct slip_proto slip; }; -extern struct net_user_info slip_user_info; +extern const struct net_user_info slip_user_info; extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri); extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri); diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index 163ee0d5f75e..ccea2d7885e5 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -61,7 +61,7 @@ static int slip_write(int fd, struct sk_buff **skb, (struct slip_data *) &lp->user)); } -struct net_kern_info slip_kern_info = { +const struct net_kern_info slip_kern_info = { .init = slip_init, .protocol = slip_protocol, .read = slip_read, diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index 89fbec185cc1..8460285c69a5 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -241,7 +241,7 @@ static void slip_del_addr(unsigned char *addr, unsigned char *netmask, close_addr(addr, netmask, pri->name); } -struct net_user_info slip_user_info = { +const struct net_user_info slip_user_info = { .init = slip_user_init, .open = slip_open, .close = slip_close, diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h index 6cf88ab580c9..89ccf83b7577 100644 --- a/arch/um/drivers/slirp.h +++ b/arch/um/drivers/slirp.h @@ -24,7 +24,7 @@ struct slirp_data { struct slip_proto slip; }; -extern struct net_user_info slirp_user_info; +extern const struct net_user_info slirp_user_info; extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri); extern int slirp_user_write(int fd, void *buf, int len, diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c index 95e50c943e14..ae322e1c8a87 100644 --- a/arch/um/drivers/slirp_kern.c +++ b/arch/um/drivers/slirp_kern.c @@ -64,7 +64,7 @@ static int slirp_write(int fd, struct sk_buff **skb, (struct slirp_data *) &lp->user)); } -struct net_kern_info slirp_kern_info = { +const struct net_kern_info slirp_kern_info = { .init = slirp_init, .protocol = slirp_protocol, .read = slirp_read, diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index 33c5f6e625e8..ce5e85d1de3d 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -126,7 +126,7 @@ static int slirp_set_mtu(int mtu, void *data) return(mtu); } -struct net_user_info slirp_user_info = { +const struct net_user_info slirp_user_info = { .init = slirp_user_init, .open = slirp_open, .close = slirp_close, diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index a4d6415bc8c4..6f13e7c71a82 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -23,7 +23,7 @@ #include "irq_user.h" #include "mconsole_kern.h" -static int ssl_version = 1; +static const int ssl_version = 1; /* Referenced only by tty_driver below - presumably it's locked correctly * by the tty driver. @@ -54,7 +54,6 @@ static int ssl_remove(int n); static struct line_driver driver = { .name = "UML serial line", .device_name = "ttyS", - .devfs_name = "tts/", .major = TTY_MAJOR, .minor_start = 64, .type = TTY_DRIVER_TYPE_SERIAL, @@ -124,7 +123,7 @@ void ssl_hangup(struct tty_struct *tty) } #endif -static struct tty_operations ssl_ops = { +static const struct tty_operations ssl_ops = { .open = ssl_open, .close = line_close, .write = line_write, diff --git a/arch/um/drivers/stderr_console.c b/arch/um/drivers/stderr_console.c index 429ae8e6c7e5..911539293871 100644 --- a/arch/um/drivers/stderr_console.c +++ b/arch/um/drivers/stderr_console.c @@ -8,10 +8,9 @@ /* * Don't register by default -- as this registeres very early in the - * boot process it becomes the default console. And as this isn't a - * real tty driver init isn't able to open /dev/console then. + * boot process it becomes the default console. * - * In most cases this isn't what you want ... + * Initialized at init time. */ static int use_stderr_console = 0; @@ -43,3 +42,20 @@ static int stderr_setup(char *str) return 1; } __setup("stderr=", stderr_setup); + +/* The previous behavior of not unregistering led to /dev/console being + * impossible to open. My FC5 filesystem started having init die, and the + * system panicing because of this. Unregistering causes the real + * console to become the default console, and /dev/console can then be + * opened. Making this an initcall makes this happen late enough that + * there is no added value in dumping everything to stderr, and the + * normal console is good enough to show you all available output. + */ +static int __init unregister_stderr(void) +{ + unregister_console(&stderr_console); + + return 0; +} + +__initcall(unregister_stderr); diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 61db8b2fc83f..e4bfcfe8550b 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -60,7 +60,6 @@ static int con_remove(int n); static struct line_driver driver = { .name = "UML console", .device_name = "tty", - .devfs_name = "vc/", .major = TTY_MAJOR, .minor_start = 0, .type = TTY_DRIVER_TYPE_CONSOLE, @@ -109,9 +108,10 @@ static int con_open(struct tty_struct *tty, struct file *filp) return line_open(vts, tty); } +/* Set in an initcall, checked in an exitcall */ static int con_init_done = 0; -static struct tty_operations console_ops = { +static const struct tty_operations console_ops = { .open = con_open, .close = line_close, .write = line_write, diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c index 94c9265a4f2c..11de3ac1eb5c 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -18,24 +18,24 @@ struct tty_chan { struct termios tt; }; -static void *tty_chan_init(char *str, int device, struct chan_opts *opts) +static void *tty_chan_init(char *str, int device, const struct chan_opts *opts) { struct tty_chan *data; if(*str != ':'){ printk("tty_init : channel type 'tty' must specify " "a device\n"); - return(NULL); + return NULL; } str++; data = um_kmalloc(sizeof(*data)); if(data == NULL) - return(NULL); + return NULL; *data = ((struct tty_chan) { .dev = str, .raw = opts->raw }); - - return(data); + + return data; } static int tty_open(int input, int output, int primary, void *d, @@ -45,22 +45,24 @@ static int tty_open(int input, int output, int primary, void *d, int fd, err; fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0); - if(fd < 0) return(fd); + if(fd < 0) + return fd; + if(data->raw){ CATCH_EINTR(err = tcgetattr(fd, &data->tt)); if(err) - return(err); + return err; err = raw(fd); if(err) - return(err); + return err; } *dev_out = data->dev; - return(fd); + return fd; } -struct chan_ops tty_ops = { +const struct chan_ops tty_ops = { .type = "tty", .init = tty_chan_init, .open = tty_open, @@ -72,14 +74,3 @@ struct chan_ops tty_ops = { .free = generic_free, .winch = 0, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 0897852b09a3..5fa4c8e258a4 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -25,7 +25,6 @@ #include "linux/blkdev.h" #include "linux/hdreg.h" #include "linux/init.h" -#include "linux/devfs_fs_kernel.h" #include "linux/cdrom.h" #include "linux/proc_fs.h" #include "linux/ctype.h" @@ -628,8 +627,6 @@ static int ubd_new_disk(int major, u64 size, int unit, { struct gendisk *disk; - char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")]; - int err; disk = alloc_disk(1 << UBD_SHIFT); if(disk == NULL) @@ -639,20 +636,10 @@ static int ubd_new_disk(int major, u64 size, int unit, disk->first_minor = unit << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); - if(major == MAJOR_NR){ + if(major == MAJOR_NR) sprintf(disk->disk_name, "ubd%c", 'a' + unit); - sprintf(disk->devfs_name, "ubd/disc%d", unit); - sprintf(from, "ubd/%d", unit); - sprintf(to, "disc%d/disc", unit); - err = devfs_mk_symlink(from, to); - if(err) - printk("ubd_new_disk failed to make link from %s to " - "%s, error = %d\n", from, to, err); - } - else { + else sprintf(disk->disk_name, "ubd_fake%d", unit); - sprintf(disk->devfs_name, "ubd_fake/disc%d", unit); - } /* sysfs register (not for ide fake devices) */ if (major == MAJOR_NR) { @@ -681,18 +668,15 @@ static int ubd_add(int n) if(dev->file == NULL) goto out; - if (ubd_open_dev(dev)) - goto out; - err = ubd_file_size(dev, &dev->size); if(err < 0) - goto out_close; + goto out; dev->size = ROUND_BLOCK(dev->size); err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); if(err) - goto out_close; + goto out; if(fake_major != MAJOR_NR) ubd_new_disk(fake_major, dev->size, n, @@ -704,8 +688,6 @@ static int ubd_add(int n) make_ide_entries(ubd_gendisk[n]->disk_name); err = 0; -out_close: - ubd_close(dev); out: return err; } @@ -841,7 +823,6 @@ int ubd_init(void) { int i; - devfs_mk_dir("ubd"); if (register_blkdev(MAJOR_NR, "ubd")) return -1; @@ -855,7 +836,6 @@ int ubd_init(void) char name[sizeof("ubd_nnn\0")]; snprintf(name, sizeof(name), "ubd_%d", fake_major); - devfs_mk_dir(name); if (register_blkdev(fake_major, "ubd")) return -1; } @@ -888,7 +868,7 @@ int ubd_driver_init(void){ return(0); } err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, - SA_INTERRUPT, "ubd", ubd_dev); + IRQF_DISABLED, "ubd", ubd_dev); if(err != 0) printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); return 0; @@ -1222,7 +1202,7 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared, } } - /* Succesful return case! */ + /* Successful return case! */ if(backing_file_out == NULL) return(fd); diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index aaa636661043..386f8b952982 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -31,7 +31,7 @@ struct xterm_chan { }; /* Not static because it's called directly by the tt mode gdb code */ -void *xterm_init(char *str, int device, struct chan_opts *opts) +void *xterm_init(char *str, int device, const struct chan_opts *opts) { struct xterm_chan *data; @@ -194,7 +194,7 @@ static void xterm_free(void *d) free(d); } -struct chan_ops xterm_ops = { +const struct chan_ops xterm_ops = { .type = "xterm", .init = xterm_init, .open = xterm_open, diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c index d269a80f4b0c..6036ec85895a 100644 --- a/arch/um/drivers/xterm_kern.c +++ b/arch/um/drivers/xterm_kern.c @@ -54,7 +54,7 @@ int xterm_fd(int socket, int *pid_out) init_completion(&data->ready); err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, + IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, "xterm", data); if (err){ printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h index 1bb5e9d94270..572d286ed2c6 100644 --- a/arch/um/include/chan_kern.h +++ b/arch/um/include/chan_kern.h @@ -23,21 +23,21 @@ struct chan { unsigned int opened:1; unsigned int enabled:1; int fd; - struct chan_ops *ops; + const struct chan_ops *ops; void *data; }; extern void chan_interrupt(struct list_head *chans, struct work_struct *task, struct tty_struct *tty, int irq); extern int parse_chan_pair(char *str, struct line *line, int device, - struct chan_opts *opts); + const struct chan_opts *opts); extern int open_chan(struct list_head *chans); extern int write_chan(struct list_head *chans, const char *buf, int len, int write_irq); extern int console_write_chan(struct list_head *chans, const char *buf, int len); extern int console_open_chan(struct line *line, struct console *co, - struct chan_opts *opts); + const struct chan_opts *opts); extern void deactivate_chan(struct list_head *chans, int irq); extern void reactivate_chan(struct list_head *chans, int irq); extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h index 659bb3cac32f..a795547a1dbd 100644 --- a/arch/um/include/chan_user.h +++ b/arch/um/include/chan_user.h @@ -20,7 +20,7 @@ enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; struct chan_ops { char *type; - void *(*init)(char *, int, struct chan_opts *); + void *(*init)(char *, int, const struct chan_opts *); int (*open)(int, int, int, void *, char **); void (*close)(int, void *); int (*read)(int, char *, void *); @@ -31,8 +31,8 @@ struct chan_ops { int winch; }; -extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops, - xterm_ops; +extern const struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, + tty_ops, xterm_ops; extern void generic_close(int fd, void *unused); extern int generic_read(int fd, char *c_out, void *unused); diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h index 69a93c804f0e..15d311b9be9e 100644 --- a/arch/um/include/irq_user.h +++ b/arch/um/include/irq_user.h @@ -6,6 +6,8 @@ #ifndef __IRQ_USER_H__ #define __IRQ_USER_H__ +#include "uml-config.h" + struct irq_fd { struct irq_fd *next; void *id; @@ -26,9 +28,10 @@ extern void free_irq_by_fd(int fd); extern void reactivate_fd(int fd, int irqnum); extern void deactivate_fd(int fd, int irqnum); extern int deactivate_all_fds(void); -extern void forward_interrupts(int pid); extern int activate_ipi(int fd, int pid); -extern unsigned long irq_lock(void); -extern void irq_unlock(unsigned long flags); + +#ifdef CONFIG_MODE_TT +extern void forward_interrupts(int pid); +#endif #endif diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 310980b32173..59cfa9e0cad0 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -21,13 +21,12 @@ struct kern_handlers { kern_hndl timer_handler; }; -extern struct kern_handlers handlinfo_kern; +extern const struct kern_handlers handlinfo_kern; extern int ncpus; extern char *linux_prog; extern char *gdb_init; extern int kmalloc_ok; -extern int timer_irq_inited; extern int jail; extern int nsyscalls; @@ -72,10 +71,8 @@ extern void init_flush_vm(void); extern void *syscall_sp(void *t); extern void syscall_trace(union uml_pt_regs *regs, int entryexit); extern int hz(void); -extern void uml_idle_timer(void); extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs); extern int external_pid(void *t); -extern void boot_timer_handler(int sig); extern void interrupt_end(void); extern void initial_thread_cb(void (*proc)(void *), void *arg); extern int debugger_signal(int status, int pid); diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 6ac0f8252e21..642c9a0320f9 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -17,7 +17,6 @@ struct line_driver { char *name; char *device_name; - char *devfs_name; short major; short minor_start; short type; @@ -53,7 +52,7 @@ struct line { int sigio; struct work_struct task; - struct line_driver *driver; + const struct line_driver *driver; int have_irq; }; @@ -100,7 +99,7 @@ extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts); extern void close_lines(struct line *lines, int nlines); extern int line_config(struct line *lines, unsigned int sizeof_lines, - char *str, struct chan_opts *opts); + char *str, const struct chan_opts *opts); extern int line_id(char **str, int *start_out, int *end_out); extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n); extern int line_get_config(char *dev, struct line *lines, diff --git a/arch/um/include/longjmp.h b/arch/um/include/longjmp.h index 8e7053013f7b..e93c6d3e893b 100644 --- a/arch/um/include/longjmp.h +++ b/arch/um/include/longjmp.h @@ -1,15 +1,18 @@ #ifndef __UML_LONGJMP_H #define __UML_LONGJMP_H -#include <setjmp.h> +#include "sysdep/archsetjmp.h" #include "os.h" +extern int setjmp(jmp_buf); +extern void longjmp(jmp_buf, int); + #define UML_LONGJMP(buf, val) do { \ longjmp(*buf, val); \ } while(0) -#define UML_SETJMP(buf, enable) ({ \ - int n; \ +#define UML_SETJMP(buf) ({ \ + int n, enable; \ enable = get_signals(); \ n = setjmp(*buf); \ if(n != 0) \ diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h index f7de6df60dd7..280459fb0b26 100644 --- a/arch/um/include/net_kern.h +++ b/arch/um/include/net_kern.h @@ -18,7 +18,6 @@ struct uml_net { struct platform_device pdev; int index; unsigned char mac[ETH_ALEN]; - int have_mac; }; struct uml_net_private { @@ -29,7 +28,6 @@ struct uml_net_private { struct net_device_stats stats; int fd; unsigned char mac[ETH_ALEN]; - int have_mac; unsigned short (*protocol)(struct sk_buff *); int (*open)(void *); void (*close)(int, void *); @@ -54,15 +52,14 @@ struct transport { struct list_head list; char *name; int (*setup)(char *, char **, void *); - struct net_user_info *user; - struct net_kern_info *kern; + const struct net_user_info *user; + const struct net_kern_info *kern; int private_size; int setup_size; }; extern struct net_device *ether_init(int); extern unsigned short ether_protocol(struct sk_buff *); -extern int setup_etheraddr(char *str, unsigned char *addr); extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra); extern int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, char **gate_addr); @@ -70,14 +67,3 @@ extern void register_transport(struct transport *new); extern unsigned short eth_protocol(struct sk_buff *skb); #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: - */ diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h index 800c403920bc..19f207cd70fe 100644 --- a/arch/um/include/net_user.h +++ b/arch/um/include/net_user.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -25,10 +25,8 @@ struct net_user_info { }; extern void ether_user_init(void *data, void *dev); -extern void dev_ip_addr(void *d, unsigned char *bin_buf); -extern void set_ether_mac(void *d, unsigned char *addr); -extern void iter_addresses(void *d, void (*cb)(unsigned char *, - unsigned char *, void *), +extern void iter_addresses(void *d, void (*cb)(unsigned char *, + unsigned char *, void *), void *arg); extern void *get_output_buffer(int *len_out); @@ -53,14 +51,3 @@ extern char *split_if_spec(char *str, ...); extern int dev_netmask(void *d, void *m); #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: - */ diff --git a/arch/um/include/os.h b/arch/um/include/os.h index f88856c28a66..120ca21a513a 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -14,10 +14,11 @@ #include "skas/mm_id.h" #include "irq_user.h" #include "sysdep/tls.h" +#include "sysdep/archsetjmp.h" -#define OS_TYPE_FILE 1 -#define OS_TYPE_DIR 2 -#define OS_TYPE_SYMLINK 3 +#define OS_TYPE_FILE 1 +#define OS_TYPE_DIR 2 +#define OS_TYPE_SYMLINK 3 #define OS_TYPE_CHARDEV 4 #define OS_TYPE_BLOCKDEV 5 #define OS_TYPE_FIFO 6 @@ -61,68 +62,68 @@ struct openflags { }; #define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \ - .t = 0, .a = 0, .e = 0, .cl = 0 }) + .t = 0, .a = 0, .e = 0, .cl = 0 }) static inline struct openflags of_read(struct openflags flags) { - flags.r = 1; - return(flags); + flags.r = 1; + return flags; } static inline struct openflags of_write(struct openflags flags) { - flags.w = 1; - return(flags); + flags.w = 1; + return flags; } static inline struct openflags of_rdwr(struct openflags flags) { - return(of_read(of_write(flags))); + return of_read(of_write(flags)); } static inline struct openflags of_set_rw(struct openflags flags, int r, int w) { flags.r = r; flags.w = w; - return(flags); + return flags; } static inline struct openflags of_sync(struct openflags flags) -{ - flags.s = 1; - return(flags); +{ + flags.s = 1; + return flags; } static inline struct openflags of_create(struct openflags flags) -{ - flags.c = 1; - return(flags); +{ + flags.c = 1; + return flags; } - + static inline struct openflags of_trunc(struct openflags flags) -{ - flags.t = 1; - return(flags); +{ + flags.t = 1; + return flags; } - + static inline struct openflags of_append(struct openflags flags) -{ - flags.a = 1; - return(flags); +{ + flags.a = 1; + return flags; } - + static inline struct openflags of_excl(struct openflags flags) -{ - flags.e = 1; - return(flags); +{ + flags.e = 1; + return flags; } static inline struct openflags of_cloexec(struct openflags flags) -{ - flags.cl = 1; - return(flags); +{ + flags.cl = 1; + return flags; } - + /* file.c */ extern int os_stat_file(const char *file_name, struct uml_stat *buf); extern int os_stat_fd(const int fd, struct uml_stat *buf); @@ -198,13 +199,15 @@ extern long os_ptrace_ldt(long pid, long addr, long data); extern int os_getpid(void); extern int os_getpgrp(void); +#ifdef UML_CONFIG_MODE_TT extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); -extern void init_new_thread_signals(int altstack); +#endif +extern void init_new_thread_signals(void); extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); extern int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x); -extern int os_protect_memory(void *addr, unsigned long len, +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); extern int os_drop_memory(void *addr, int length); @@ -216,7 +219,6 @@ extern void os_flush_stdout(void); */ extern void forward_ipi(int fd, int pid); extern void kill_child_dead(int pid); -extern void stop(void); extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); extern int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, int must_succeed); @@ -276,9 +278,11 @@ extern int setjmp_wrapper(void (*proc)(void *, void *), ...); extern void switch_timers(int to_real); extern void idle_sleep(int secs); +extern int set_interval(int is_virtual); +#ifdef CONFIG_MODE_TT extern void enable_timer(void); +#endif extern void disable_timer(void); -extern void user_time_init(void); extern void uml_idle_timer(void); extern unsigned long long os_nsecs(void); @@ -305,12 +309,9 @@ extern int copy_context_skas0(unsigned long stack, int pid); extern void userspace(union uml_pt_regs *regs); extern void map_stub_pages(int fd, unsigned long code, unsigned long data, unsigned long stack); -extern void new_thread(void *stack, void **switch_buf_ptr, - void **fork_buf_ptr, void (*handler)(int)); -extern void thread_wait(void *sw, void *fb); -extern void switch_threads(void *me, void *next); -extern int start_idle_thread(void *stack, void *switch_buf_ptr, - void **fork_buf_ptr); +extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); +extern void switch_threads(jmp_buf *me, jmp_buf *you); +extern int start_idle_thread(void *stack, jmp_buf *switch_buf); extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); extern void halt_skas(void); @@ -318,7 +319,6 @@ extern void reboot_skas(void); /* irq.c */ extern int os_waiting_for_events(struct irq_fd *active_fds); -extern int os_isatty(int fd); extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds); extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2); @@ -330,9 +330,9 @@ extern void os_set_ioignore(void); extern void init_irq_signals(int on_sigstack); /* sigio.c */ -extern void write_sigio_workaround(void); -extern int add_sigio_fd(int fd, int read); +extern int add_sigio_fd(int fd); extern int ignore_sigio_fd(int fd); +extern void maybe_sigio_broken(int fd, int read); /* skas/trap */ extern void sig_handler_common_skas(int sig, void *sc_ptr); diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h index 83b688ca198f..f845b3629a6d 100644 --- a/arch/um/include/registers.h +++ b/arch/um/include/registers.h @@ -7,6 +7,7 @@ #define __REGISTERS_H #include "sysdep/ptrace.h" +#include "sysdep/archsetjmp.h" extern void init_thread_registers(union uml_pt_regs *to); extern int save_fp_registers(int pid, unsigned long *fp_regs); @@ -15,6 +16,6 @@ extern void save_registers(int pid, union uml_pt_regs *regs); extern void restore_registers(int pid, union uml_pt_regs *regs); extern void init_registers(int pid); extern void get_safe_registers(unsigned long * regs, unsigned long * fp_regs); -extern void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer); +extern unsigned long get_thread_reg(int reg, jmp_buf *buf); #endif diff --git a/arch/um/include/skas/mode_kern_skas.h b/arch/um/include/skas/mode_kern_skas.h index 63c58739bde0..9cd9c6ec9a63 100644 --- a/arch/um/include/skas/mode_kern_skas.h +++ b/arch/um/include/skas/mode_kern_skas.h @@ -29,8 +29,7 @@ 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 unsigned long set_task_sizes_skas(unsigned long *task_size_out); extern int start_uml_skas(void); extern int external_pid_skas(struct task_struct *task); extern int thread_pid_skas(struct task_struct *task); diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h index 853b26f148c5..e88926b16072 100644 --- a/arch/um/include/skas/skas.h +++ b/arch/um/include/skas/skas.h @@ -14,8 +14,7 @@ extern int proc_mm, ptrace_faultinfo, ptrace_ldt; extern int skas_needs_stub; extern int user_thread(unsigned long stack, int flags); -extern void new_thread_proc(void *stack, void (*handler)(int sig)); -extern void new_thread_handler(int sig); +extern void new_thread_handler(void); extern void handle_syscall(union uml_pt_regs *regs); extern int new_mm(unsigned long stack); extern void get_skas_faultinfo(int pid, struct faultinfo * fi); diff --git a/arch/um/include/sysdep-i386/archsetjmp.h b/arch/um/include/sysdep-i386/archsetjmp.h new file mode 100644 index 000000000000..11bafab669e9 --- /dev/null +++ b/arch/um/include/sysdep-i386/archsetjmp.h @@ -0,0 +1,22 @@ +/* + * arch/i386/include/klibc/archsetjmp.h + */ + +#ifndef _KLIBC_ARCHSETJMP_H +#define _KLIBC_ARCHSETJMP_H + +struct __jmp_buf { + unsigned int __ebx; + unsigned int __esp; + unsigned int __ebp; + unsigned int __esi; + unsigned int __edi; + unsigned int __eip; +}; + +typedef struct __jmp_buf jmp_buf[1]; + +#define JB_IP __eip +#define JB_SP __esp + +#endif /* _SETJMP_H */ diff --git a/arch/um/include/sysdep-i386/signal.h b/arch/um/include/sysdep-i386/signal.h deleted file mode 100644 index 07518b162136..000000000000 --- a/arch/um/include/sysdep-i386/signal.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2004 PathScale, Inc - * Licensed under the GPL - */ - -#ifndef __I386_SIGNAL_H_ -#define __I386_SIGNAL_H_ - -#include <signal.h> - -#define ARCH_SIGHDLR_PARAM int sig - -#define ARCH_GET_SIGCONTEXT(sc, sig) \ - do sc = (struct sigcontext *) (&sig + 1); while(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 - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-x86_64/archsetjmp.h b/arch/um/include/sysdep-x86_64/archsetjmp.h new file mode 100644 index 000000000000..9a5e1a6ec800 --- /dev/null +++ b/arch/um/include/sysdep-x86_64/archsetjmp.h @@ -0,0 +1,24 @@ +/* + * arch/x86_64/include/klibc/archsetjmp.h + */ + +#ifndef _KLIBC_ARCHSETJMP_H +#define _KLIBC_ARCHSETJMP_H + +struct __jmp_buf { + unsigned long __rbx; + unsigned long __rsp; + unsigned long __rbp; + unsigned long __r12; + unsigned long __r13; + unsigned long __r14; + unsigned long __r15; + unsigned long __rip; +}; + +typedef struct __jmp_buf jmp_buf[1]; + +#define JB_IP __rip +#define JB_SP __rsp + +#endif /* _SETJMP_H */ diff --git a/arch/um/include/sysdep-x86_64/kernel-offsets.h b/arch/um/include/sysdep-x86_64/kernel-offsets.h index 939cc475757a..91d129fb3930 100644 --- a/arch/um/include/sysdep-x86_64/kernel-offsets.h +++ b/arch/um/include/sysdep-x86_64/kernel-offsets.h @@ -1,4 +1,3 @@ -#include <linux/config.h> #include <linux/stddef.h> #include <linux/sched.h> #include <linux/time.h> diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h index 8d353f0feec1..617bb9efc934 100644 --- a/arch/um/include/sysdep-x86_64/ptrace.h +++ b/arch/um/include/sysdep-x86_64/ptrace.h @@ -50,6 +50,21 @@ #define HOST_FS 25 #define HOST_GS 26 +/* Also defined in asm/ptrace-x86_64.h, but not in libc headers. So, these + * are already defined for kernel code, but not for userspace code. + */ +#ifndef FS_BASE +/* These aren't defined in ptrace.h, but exist in struct user_regs_struct, + * which is what x86_64 ptrace actually uses. + */ +#define FS_BASE (HOST_FS_BASE * sizeof(long)) +#define GS_BASE (HOST_GS_BASE * sizeof(long)) +#define DS (HOST_DS * sizeof(long)) +#define ES (HOST_ES * sizeof(long)) +#define FS (HOST_FS * sizeof(long)) +#define GS (HOST_GS * sizeof(long)) +#endif + #define REGS_FS_BASE(r) ((r)[HOST_FS_BASE]) #define REGS_GS_BASE(r) ((r)[HOST_GS_BASE]) #define REGS_DS(r) ((r)[HOST_DS]) @@ -89,9 +104,12 @@ union uml_pt_regs { #endif #ifdef UML_CONFIG_MODE_SKAS struct skas_regs { - /* XXX */ - unsigned long regs[27]; - unsigned long fp[65]; + /* x86_64 ptrace uses sizeof(user_regs_struct) as its register + * file size, while i386 uses FRAME_SIZE. Therefore, we need + * to use UM_FRAME_SIZE here instead of HOST_FRAME_SIZE. + */ + unsigned long regs[UM_FRAME_SIZE]; + unsigned long fp[HOST_FP_SIZE]; struct faultinfo faultinfo; long syscall; int is_user; @@ -120,11 +138,16 @@ extern int mode_tt; #define UPT_R14(r) __CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs)) #define UPT_R15(r) __CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs)) #define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs)) +#define UPT_FS_BASE(r) \ + __CHOOSE_MODE(SC_FS_BASE(UPT_SC(r)), REGS_FS_BASE((r)->skas.regs)) #define UPT_FS(r) __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs)) +#define UPT_GS_BASE(r) \ + __CHOOSE_MODE(SC_GS_BASE(UPT_SC(r)), REGS_GS_BASE((r)->skas.regs)) #define UPT_GS(r) __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs)) #define UPT_DS(r) __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs)) #define UPT_ES(r) __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs)) #define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs)) +#define UPT_SS(r) __CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs)) #define UPT_ORIG_RAX(r) \ __CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs)) @@ -183,6 +206,13 @@ struct syscall_args { case RBP: val = UPT_RBP(regs); break; \ case ORIG_RAX: val = UPT_ORIG_RAX(regs); break; \ case CS: val = UPT_CS(regs); break; \ + case SS: val = UPT_SS(regs); break; \ + case FS_BASE: val = UPT_FS_BASE(regs); break; \ + case GS_BASE: val = UPT_GS_BASE(regs); break; \ + case DS: val = UPT_DS(regs); break; \ + case ES: val = UPT_ES(regs); break; \ + case FS : val = UPT_FS (regs); break; \ + case GS: val = UPT_GS(regs); break; \ case EFLAGS: val = UPT_EFLAGS(regs); break; \ default : \ panic("Bad register in UPT_REG : %d\n", reg); \ @@ -214,6 +244,13 @@ struct syscall_args { case RBP: UPT_RBP(regs) = __upt_val; break; \ case ORIG_RAX: UPT_ORIG_RAX(regs) = __upt_val; break; \ case CS: UPT_CS(regs) = __upt_val; break; \ + case SS: UPT_SS(regs) = __upt_val; break; \ + case FS_BASE: UPT_FS_BASE(regs) = __upt_val; break; \ + case GS_BASE: UPT_GS_BASE(regs) = __upt_val; break; \ + case DS: UPT_DS(regs) = __upt_val; break; \ + case ES: UPT_ES(regs) = __upt_val; break; \ + case FS: UPT_FS(regs) = __upt_val; break; \ + case GS: UPT_GS(regs) = __upt_val; break; \ case EFLAGS: UPT_EFLAGS(regs) = __upt_val; break; \ default : \ panic("Bad register in UPT_SET : %d\n", reg); \ diff --git a/arch/um/include/sysdep-x86_64/sc.h b/arch/um/include/sysdep-x86_64/sc.h index a160d9fcc596..8aee45b07434 100644 --- a/arch/um/include/sysdep-x86_64/sc.h +++ b/arch/um/include/sysdep-x86_64/sc.h @@ -35,11 +35,11 @@ #define SC_GS(sc) SC_OFFSET(sc, SC_GS) #define SC_EFLAGS(sc) SC_OFFSET(sc, SC_EFLAGS) #define SC_SIGMASK(sc) SC_OFFSET(sc, SC_SIGMASK) +#define SC_SS(sc) SC_OFFSET(sc, SC_SS) #if 0 #define SC_ORIG_RAX(sc) SC_OFFSET(sc, SC_ORIG_RAX) #define SC_DS(sc) SC_OFFSET(sc, SC_DS) #define SC_ES(sc) SC_OFFSET(sc, SC_ES) -#define SC_SS(sc) SC_OFFSET(sc, SC_SS) #endif #endif diff --git a/arch/um/include/sysdep-x86_64/signal.h b/arch/um/include/sysdep-x86_64/signal.h deleted file mode 100644 index 6142897af3d1..000000000000 --- a/arch/um/include/sysdep-x86_64/signal.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2004 PathScale, Inc - * Licensed under the GPL - */ - -#ifndef __X86_64_SIGNAL_H_ -#define __X86_64_SIGNAL_H_ - -#define ARCH_SIGHDLR_PARAM int sig - -#define ARCH_GET_SIGCONTEXT(sc, sig_addr) \ - do { \ - struct ucontext *__uc; \ - asm("movq %%rdx, %0" : "=r" (__uc)); \ - sc = (struct sigcontext *) &__uc->uc_mcontext; \ - } while(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 - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h index e06f83e80f4a..5e86aa047b2b 100644 --- a/arch/um/include/sysdep-x86_64/syscalls.h +++ b/arch/um/include/sysdep-x86_64/syscalls.h @@ -12,8 +12,6 @@ typedef long syscall_handler_t(void); -extern syscall_handler_t *ia32_sys_call_table[]; - extern syscall_handler_t *sys_call_table[]; #define EXECUTE_SYSCALL(syscall, regs) \ diff --git a/arch/um/include/tt/mode_kern_tt.h b/arch/um/include/tt/mode_kern_tt.h index efa0012550d0..a4fc63057195 100644 --- a/arch/um/include/tt/mode_kern_tt.h +++ b/arch/um/include/tt/mode_kern_tt.h @@ -30,8 +30,7 @@ extern void flush_tlb_mm_tt(struct mm_struct *mm); extern void force_flush_all_tt(void); extern long execute_syscall_tt(void *r); extern void before_mem_tt(unsigned long brk_start); -extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, - unsigned long *task_size_out); +extern unsigned long set_task_sizes_tt(unsigned long *task_size_out); extern int start_uml_tt(void); extern int external_pid_tt(struct task_struct *task); extern int thread_pid_tt(struct task_struct *task); diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index fe08971b64cf..6fa63a2a89e3 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -6,16 +6,14 @@ extra-y := vmlinux.lds clean-files := -obj-y = config.o exec_kern.o exitcode.o \ - init_task.o irq.o ksyms.o mem.o physmem.o \ - process_kern.o ptrace.o reboot.o resource.o sigio_kern.o \ - signal_kern.o smp.o syscall_kern.o sysrq.o \ - time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o +obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \ + physmem.o process.o ptrace.o reboot.o resource.o sigio.o \ + signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \ + um_arch.o umid.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o -obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o obj-$(CONFIG_MODE_TT) += tt/ obj-$(CONFIG_MODE_SKAS) += skas/ diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 2517ecb8bf27..68ed24df5c8f 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -26,6 +26,7 @@ SECTIONS /* Read-only sections, merged into text segment: */ .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec.c index c0cb627bf594..0561c43b4685 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -31,18 +31,29 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); } +#ifdef CONFIG_TTY_LOG +extern void log_exec(char **argv, void *tty); +#endif + static long execve1(char *file, char __user * __user *argv, char __user *__user *env) { long error; #ifdef CONFIG_TTY_LOG - log_exec(argv, current->tty); + mutex_lock(&tty_mutex); + task_lock(current); /* FIXME: is this needed ? */ + log_exec(argv, current->signal->tty); + task_unlock(current); + mutex_unlock(&tty_mutex); #endif error = do_execve(file, argv, env, ¤t->thread.regs); if (error == 0){ task_lock(current); current->ptrace &= ~PT_DTRACE; +#ifdef SUBARCH_EXECVE1 + SUBARCH_EXECVE1(¤t->thread.regs.regs); +#endif task_unlock(current); set_cmdline(current_cmd()); } diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index d21ebad666b4..8b7f2cdedf94 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -16,9 +16,13 @@ int uml_exitcode = 0; static int read_proc_exitcode(char *page, char **start, off_t off, int count, int *eof, void *data) { - int len; + int len, val; - len = sprintf(page, "%d\n", uml_exitcode); + /* Save uml_exitcode in a local so that we don't need to guarantee + * that sprintf accesses it atomically. + */ + val = uml_exitcode; + len = sprintf(page, "%d\n", val); len -= off; if(len <= off+count) *eof = 1; *start = page + off; diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c index 2c86e7fdb014..13aa115cd1b4 100644 --- a/arch/um/kernel/gmon_syms.c +++ b/arch/um/kernel/gmon_syms.c @@ -5,7 +5,7 @@ #include "linux/module.h" -extern void __bb_init_func(void *); +extern void __bb_init_func(void *) __attribute__((weak)); EXPORT_SYMBOL(__bb_init_func); /* This is defined (and referred to in profiling stub code) only by some GCC @@ -21,14 +21,3 @@ EXPORT_SYMBOL(__gcov_init); extern void __gcov_merge_add(void *) __attribute__((weak)); EXPORT_SYMBOL(__gcov_merge_add); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 2ffda012385e..ce7f233fc490 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -63,7 +63,7 @@ int show_interrupts(struct seq_file *p, void *v) for_each_online_cpu(j) seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif - seq_printf(p, " %14s", irq_desc[i].handler->typename); + seq_printf(p, " %14s", irq_desc[i].chip->typename); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) @@ -110,18 +110,7 @@ void sigio_handler(int sig, union uml_pt_regs *regs) free_irqs(); } -static void maybe_sigio_broken(int fd, int type) -{ - if (os_isatty(fd)) { - if ((type == IRQ_WRITE) && !pty_output_sigio) { - write_sigio_workaround(); - add_sigio_fd(fd, 0); - } else if ((type == IRQ_READ) && !pty_close_sigio) { - write_sigio_workaround(); - add_sigio_fd(fd, 1); - } - } -} +static DEFINE_SPINLOCK(irq_lock); int activate_fd(int irq, int fd, int type, void *dev_id) { @@ -153,20 +142,7 @@ int activate_fd(int irq, int fd, int type, void *dev_id) .events = events, .current_events = 0 } ); - /* Critical section - locked by a spinlock because this stuff can - * be changed from interrupt handlers. The stuff above is done - * outside the lock because it allocates memory. - */ - - /* Actually, it only looks like it can be called from interrupt - * context. The culprit is reactivate_fd, which calls - * maybe_sigio_broken, which calls write_sigio_workaround, - * which calls activate_fd. However, write_sigio_workaround should - * only be called once, at boot time. That would make it clear that - * this is called only from process context, and can be locked with - * a semaphore. - */ - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) { if ((irq_fd->fd == fd) && (irq_fd->type == type)) { printk("Registering fd %d twice\n", fd); @@ -176,7 +152,6 @@ int activate_fd(int irq, int fd, int type, void *dev_id) } } - /*-------------*/ if (type == IRQ_WRITE) fd = -1; @@ -199,7 +174,7 @@ int activate_fd(int irq, int fd, int type, void *dev_id) * so we will not be able to put new pollfd struct to pollfds * then we free the buffer tmp_fds and try again. */ - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); kfree(tmp_pfd); tmp_pfd = NULL; @@ -207,37 +182,36 @@ int activate_fd(int irq, int fd, int type, void *dev_id) if (tmp_pfd == NULL) goto out_kfree; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); } - /*-------------*/ *last_irq_ptr = new_fd; last_irq_ptr = &new_fd->next; - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); /* This calls activate_fd, so it has to be outside the critical * section. */ - maybe_sigio_broken(fd, type); + maybe_sigio_broken(fd, (type == IRQ_READ)); - return(0); + return 0; out_unlock: - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); out_kfree: kfree(new_fd); out: - return(err); + return err; } static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) { unsigned long flags; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr); - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); } struct irq_and_dev { @@ -304,19 +278,16 @@ void reactivate_fd(int fd, int irqnum) unsigned long flags; int i; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); irq = find_irq_by_fd(fd, irqnum, &i); if (irq == NULL) { - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); return; } os_set_pollfd(i, irq->fd); - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); - /* This calls activate_fd, so it has to be outside the critical - * section. - */ - maybe_sigio_broken(fd, irq->type); + add_sigio_fd(fd); } void deactivate_fd(int fd, int irqnum) @@ -325,13 +296,17 @@ void deactivate_fd(int fd, int irqnum) unsigned long flags; int i; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); irq = find_irq_by_fd(fd, irqnum, &i); - if (irq == NULL) - goto out; + if(irq == NULL){ + spin_unlock_irqrestore(&irq_lock, flags); + return; + } + os_set_pollfd(i, -1); - out: - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); + + ignore_sigio_fd(fd); } int deactivate_all_fds(void) @@ -350,13 +325,14 @@ int deactivate_all_fds(void) return 0; } +#ifdef CONFIG_MODE_TT void forward_interrupts(int pid) { struct irq_fd *irq; unsigned long flags; int err; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); for (irq = active_fds; irq != NULL; irq = irq->next) { err = os_set_owner(irq->fd, pid); if (err < 0) { @@ -369,8 +345,9 @@ void forward_interrupts(int pid) irq->pid = pid; } - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); } +#endif /* * do_IRQ handles all normal device IRQ's (the special @@ -403,21 +380,6 @@ int um_request_irq(unsigned int irq, int fd, int type, EXPORT_SYMBOL(um_request_irq); EXPORT_SYMBOL(reactivate_fd); -static DEFINE_SPINLOCK(irq_spinlock); - -unsigned long irq_lock(void) -{ - unsigned long flags; - - spin_lock_irqsave(&irq_spinlock, flags); - return flags; -} - -void irq_unlock(unsigned long flags) -{ - spin_unlock_irqrestore(&irq_spinlock, flags); -} - /* hw_interrupt_type must define (startup || enable) && * (shutdown || disable) && end */ static void dummy(unsigned int irq) @@ -451,13 +413,13 @@ void __init init_IRQ(void) irq_desc[TIMER_IRQ].status = IRQ_DISABLED; irq_desc[TIMER_IRQ].action = NULL; irq_desc[TIMER_IRQ].depth = 1; - irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type; + irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type; enable_irq(TIMER_IRQ); for (i = 1; i < NR_IRQS; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; irq_desc[i].depth = 1; - irq_desc[i].handler = &normal_irq_type; + irq_desc[i].chip = &normal_irq_type; enable_irq(i); } } @@ -474,7 +436,7 @@ int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *, } err = um_request_irq(irq, fds[0], IRQ_READ, handler, - SA_INTERRUPT | SA_SAMPLE_RANDOM, name, + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, name, (void *) (long) fds[0]); if (err) { printk("init_aio_irq - : um_request_irq failed, err = %d\n", diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 432cf0b97a13..f030e44262ba 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -21,7 +21,6 @@ #include "mem_user.h" #include "os.h" -EXPORT_SYMBOL(stop); EXPORT_SYMBOL(uml_physmem); EXPORT_SYMBOL(set_signals); EXPORT_SYMBOL(get_signals); @@ -41,12 +40,14 @@ EXPORT_SYMBOL(handle_page_fault); EXPORT_SYMBOL(find_iomem); #ifdef CONFIG_MODE_TT +EXPORT_SYMBOL(stop); EXPORT_SYMBOL(strncpy_from_user_tt); EXPORT_SYMBOL(copy_from_user_tt); EXPORT_SYMBOL(copy_to_user_tt); #endif #ifdef CONFIG_MODE_SKAS +EXPORT_SYMBOL(strnlen_user_skas); EXPORT_SYMBOL(strncpy_from_user_skas); EXPORT_SYMBOL(copy_to_user_skas); EXPORT_SYMBOL(copy_from_user_skas); @@ -88,12 +89,6 @@ EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(do_gettimeofday); EXPORT_SYMBOL(do_settimeofday); -/* This is here because UML expands lseek to sys_lseek, not to a system - * call instruction. - */ -EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_wait4); - #ifdef CONFIG_SMP /* required for SMP */ diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 44e41a35f000..c95855ba6ab5 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -24,8 +24,6 @@ #include "init.h" #include "kern_constants.h" -extern char __binary_start; - /* Changed during early boot */ unsigned long *empty_zero_page = NULL; unsigned long *empty_bad_page = NULL; @@ -65,8 +63,6 @@ static void setup_highmem(unsigned long highmem_start, void mem_init(void) { - unsigned long start; - max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT; /* clear the zero-page */ @@ -81,17 +77,12 @@ void mem_init(void) 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 & PAGE_MASK; - if(uml_physmem != start){ - map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem, - 1, 1, 0); - } - /* this will put all low memory onto the freelists */ totalram_pages = free_all_bootmem(); +#ifdef CONFIG_HIGHMEM totalhigh_pages = highmem >> PAGE_SHIFT; totalram_pages += totalhigh_pages; +#endif num_physpages = totalram_pages; max_pfn = totalram_pages; printk(KERN_INFO "Memory: %luk available\n", @@ -232,10 +223,14 @@ void paging_init(void) empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); - for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) + for(i = 0; i < ARRAY_SIZE(zones_size); i++) zones_size[i] = 0; - zones_size[ZONE_DMA] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); + + zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) - + (uml_physmem >> PAGE_SHIFT); +#ifdef CONFIG_HIGHMEM zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT; +#endif free_area_init(zones_size); /* diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 166cb09cae4c..abafa64b8727 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -317,7 +317,7 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, } } -extern int __syscall_stub_start, __binary_start; +extern int __syscall_stub_start; void setup_physmem(unsigned long start, unsigned long reserve_end, unsigned long len, unsigned long long highmem) diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process.c index f6a5a502120b..fe6c64abda5b 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process.c @@ -1,10 +1,9 @@ -/* +/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Copyright 2003 PathScale, Inc. * Licensed under the GPL */ -#include "linux/config.h" #include "linux/kernel.h" #include "linux/sched.h" #include "linux/interrupt.h" @@ -23,6 +22,7 @@ #include "linux/proc_fs.h" #include "linux/ptrace.h" #include "linux/random.h" +#include "linux/personality.h" #include "asm/unistd.h" #include "asm/mman.h" #include "asm/segment.h" @@ -112,11 +112,11 @@ void set_current(void *t) void *_switch_to(void *prev, void *next, void *last) { - struct task_struct *from = prev; - struct task_struct *to= next; + struct task_struct *from = prev; + struct task_struct *to= next; - to->thread.prev_sched = from; - set_current(to); + to->thread.prev_sched = from; + set_current(to); do { current->thread.saved_task = NULL ; @@ -127,7 +127,7 @@ void *_switch_to(void *prev, void *next, void *last) prev= current; } while(current->thread.saved_task); - return(current->thread.prev_sched); + return(current->thread.prev_sched); } @@ -141,19 +141,19 @@ void release_thread(struct task_struct *task) { CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task)); } - + void exit_thread(void) { unprotect_stack((unsigned long) current_thread); } - + void *get_current(void) { return(current); } int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, - unsigned long stack_top, struct task_struct * p, + unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { int ret; @@ -182,11 +182,11 @@ void initial_thread_cb(void (*proc)(void *), void *arg) int save_kmalloc_ok = kmalloc_ok; kmalloc_ok = 0; - CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, + CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, arg); kmalloc_ok = save_kmalloc_ok; } - + unsigned long stack_sp(unsigned long page) { return(page + PAGE_SIZE - sizeof(void *)); @@ -210,7 +210,7 @@ void default_idle(void) */ if(need_resched()) schedule(); - + idle_sleep(10); } } @@ -225,7 +225,7 @@ int page_size(void) return(PAGE_SIZE); } -void *um_virt_to_phys(struct task_struct *task, unsigned long addr, +void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte_out) { pgd_t *pgd; @@ -234,7 +234,7 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte; pte_t ptent; - if(task->mm == NULL) + if(task->mm == NULL) return(ERR_PTR(-EINVAL)); pgd = pgd_offset(task->mm, addr); if(!pgd_present(*pgd)) @@ -245,7 +245,7 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr, return(ERR_PTR(-EINVAL)); pmd = pmd_offset(pud, addr); - if(!pmd_present(*pmd)) + if(!pmd_present(*pmd)) return(ERR_PTR(-EINVAL)); pte = pte_offset_kernel(pmd, addr); @@ -270,7 +270,7 @@ char *current_cmd(void) void force_sigbus(void) { - printk(KERN_ERR "Killing pid %d because of a lack of memory\n", + printk(KERN_ERR "Killing pid %d because of a lack of memory\n", current->pid); lock_kernel(); sigaddset(¤t->pending.signal, SIGBUS); @@ -476,7 +476,7 @@ int singlestepping(void * t) #ifndef arch_align_stack unsigned long arch_align_stack(unsigned long sp) { - if (randomize_va_space) + if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) sp -= get_random_int() % 8192; return sp & ~0xf; } diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 3ef73bf2e781..f602623644aa 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -22,7 +22,7 @@ static void kill_idlers(int me) struct task_struct *p; int i; - for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){ + for(i = 0; i < ARRAY_SIZE(idle_threads); i++){ p = idle_threads[i]; if((p != NULL) && (p->thread.mode.tt.extern_pid != me)) os_kill_process(p->thread.mode.tt.extern_pid, 0); @@ -62,14 +62,3 @@ void machine_halt(void) { machine_power_off(); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio.c index 1c1300fb1e95..0ad755ceb212 100644 --- a/arch/um/kernel/sigio_kern.c +++ b/arch/um/kernel/sigio.c @@ -31,7 +31,7 @@ int write_sigio_irq(int fd) int err; err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, - SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", + IRQF_DISABLED|IRQF_SAMPLE_RANDOM, "write sigio", NULL); if(err){ printk("write_sigio_irq : um_request_irq failed, err = %d\n", @@ -53,17 +53,3 @@ void sigio_unlock(void) { spin_unlock(&sigio_spinlock); } - -extern void sigio_cleanup(void); -__uml_exitcall(sigio_cleanup); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal.c index da17b7541e08..4aa9808ba264 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -36,7 +36,7 @@ EXPORT_SYMBOL(unblock_signals); /* * OK, we're invoking a handler - */ + */ static int handle_signal(struct pt_regs *regs, unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset) @@ -88,7 +88,7 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, force_sigsegv(signr, current); } else { spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); if(!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked, signr); @@ -136,7 +136,7 @@ static int kern_do_signal(struct pt_regs *regs) PT_REGS_RESTART_SYSCALL(regs); break; case -ERESTART_RESTARTBLOCK: - PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall; + PT_REGS_ORIG_SYSCALL(regs) = __NR_restart_syscall; PT_REGS_RESTART_SYSCALL(regs); break; } @@ -146,7 +146,7 @@ static int kern_do_signal(struct pt_regs *regs) * you set a breakpoint on a system call instruction and singlestep * from it, the tracing thread used to PTRACE_SINGLESTEP the process * rather than PTRACE_SYSCALL it, allowing the system call to execute - * on the host. The tracing thread will check this flag and + * on the host. The tracing thread will check this flag and * PTRACE_SYSCALL if necessary. */ if(current->ptrace & PT_DTRACE) diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index ea3a8e409a6e..3e3fa7e7e3cf 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -3,8 +3,7 @@ # Licensed under the GPL # -obj-y := clone.o exec_kern.o mem.o mmu.o process_kern.o \ - syscall.o tlb.o uaccess.o +obj-y := clone.o exec.o mem.o mmu.o process.o syscall.o tlb.o uaccess.o # clone.o is in the stub, so it can't be built with profiling # GCC hardened also auto-enables -fpic, but we need %ebx so it can't work -> diff --git a/arch/um/kernel/skas/exec.c b/arch/um/kernel/skas/exec.c new file mode 100644 index 000000000000..54b795951372 --- /dev/null +++ b/arch/um/kernel/skas/exec.c @@ -0,0 +1,30 @@ +/* + * 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 "um_mmu.h" +#include "os.h" + +void flush_thread_skas(void) +{ + force_flush_all(); + switch_mm_skas(¤t->mm->context.skas.id); +} + +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; +} diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c deleted file mode 100644 index 77ed7bbab219..000000000000 --- a/arch/um/kernel/skas/exec_kern.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 "um_mmu.h" -#include "os.h" - -void flush_thread_skas(void) -{ - force_flush_all(); - switch_mm_skas(¤t->mm->context.skas.id); -} - -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: - */ diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c index 88ab96c609ce..27bbf54b1e52 100644 --- a/arch/um/kernel/skas/mem.c +++ b/arch/um/kernel/skas/mem.c @@ -9,31 +9,19 @@ #include "mem_user.h" #include "skas.h" -unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, - unsigned long *task_size_out) +unsigned long set_task_sizes_skas(unsigned long *task_size_out) { /* Round up to the nearest 4M */ - unsigned long top = ROUND_4M((unsigned long) &arg); + unsigned long host_task_size = ROUND_4M((unsigned long) + &host_task_size); #ifdef CONFIG_HOST_TASK_SIZE - *host_size_out = CONFIG_HOST_TASK_SIZE; + *host_size_out = ROUND_4M(CONFIG_HOST_TASK_SIZE); *task_size_out = CONFIG_HOST_TASK_SIZE; #else - *host_size_out = top; if (!skas_needs_stub) - *task_size_out = top; + *task_size_out = host_task_size; else *task_size_out = CONFIG_STUB_START & PGDIR_MASK; #endif - return(((unsigned long) set_task_sizes_skas) & ~0xffffff); + return host_task_size; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index c5c9885a8297..4cd2ff546ef6 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -55,14 +55,16 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc, * destroy_context_skas. */ - mm->context.skas.last_page_table = pmd_page_kernel(*pmd); + mm->context.skas.last_page_table = pmd_page_vaddr(*pmd); #ifdef CONFIG_3_LEVEL_PGTABLES mm->context.skas.last_pmd = (unsigned long) __va(pud_val(*pud)); #endif *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT)); - *pte = pte_mkexec(*pte); - *pte = pte_wrprotect(*pte); + /* This is wrong for the code page, but it doesn't matter since the + * stub is mapped by hand with the correct permissions. + */ + *pte = pte_mkwrite(*pte); return(0); out_pmd: @@ -152,7 +154,7 @@ void destroy_context_skas(struct mm_struct *mm) free_page(mmu->id.stack); pte_lock_deinit(virt_to_page(mmu->last_page_table)); pte_free_kernel((pte_t *) mmu->last_page_table); - dec_page_state(nr_page_table_pages); + dec_zone_page_state(virt_to_page(mmu->last_page_table), NR_PAGETABLE); #ifdef CONFIG_3_LEVEL_PGTABLES pmd_free((pmd_t *) mmu->last_pmd); #endif diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process.c index 2135eaf98a93..ae4fa71d3b8b 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process.c @@ -33,7 +33,7 @@ void switch_to_skas(void *prev, void *next) switch_timers(0); switch_threads(&from->thread.mode.skas.switch_buf, - to->thread.mode.skas.switch_buf); + &to->thread.mode.skas.switch_buf); arch_switch_to_skas(current->thread.prev_sched, current); @@ -43,21 +43,21 @@ void switch_to_skas(void *prev, void *next) extern void schedule_tail(struct task_struct *prev); -void new_thread_handler(int sig) +/* This is called magically, by its address being stuffed in a jmp_buf + * and being longjmp-d to. + */ +void new_thread_handler(void) { int (*fn)(void *), n; void *arg; - fn = current->thread.request.u.thread.proc; - arg = current->thread.request.u.thread.arg; - os_usr1_signal(1); - thread_wait(¤t->thread.mode.skas.switch_buf, - current->thread.mode.skas.fork_buf); - if(current->thread.prev_sched != NULL) schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + /* The return value is 1 if the kernel thread execs a process, * 0 if it just exits */ @@ -70,22 +70,13 @@ void new_thread_handler(int sig) else do_exit(0); } -void new_thread_proc(void *stack, void (*handler)(int sig)) -{ - init_new_thread_stack(stack, handler); - os_usr1_process(os_getpid()); -} - void release_thread_skas(struct task_struct *task) { } -void fork_handler(int sig) +/* Called magically, see new_thread_handler above */ +void fork_handler(void) { - os_usr1_signal(1); - thread_wait(¤t->thread.mode.skas.switch_buf, - current->thread.mode.skas.fork_buf); - force_flush_all(); if(current->thread.prev_sched == NULL) panic("blech"); @@ -109,7 +100,7 @@ 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) { - void (*handler)(int); + void (*handler)(void); if(current->thread.forking){ memcpy(&p->thread.regs.regs.skas, ®s->regs.skas, @@ -123,12 +114,12 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, } else { init_thread_registers(&p->thread.regs.regs); - p->thread.request.u.thread = current->thread.request.u.thread; + p->thread.request.u.thread = current->thread.request.u.thread; handler = new_thread_handler; } new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf, - &p->thread.mode.skas.fork_buf, handler); + handler); return(0); } @@ -164,7 +155,7 @@ static int start_kernel_proc(void *unused) cpu_tasks[0].pid = pid; cpu_tasks[0].task = current; #ifdef CONFIG_SMP - cpu_online_map = cpumask_of_cpu(0); + cpu_online_map = cpumask_of_cpu(0); #endif start_kernel(); return(0); @@ -177,13 +168,12 @@ int start_uml_skas(void) if(proc_mm) userspace_pid[0] = start_userspace(0); - init_new_thread_signals(1); + init_new_thread_signals(); init_task.thread.request.u.thread.proc = start_kernel_proc; init_task.thread.request.u.thread.arg = NULL; return(start_idle_thread(task_stack_page(&init_task), - &init_task.thread.mode.skas.switch_buf, - &init_task.thread.mode.skas.fork_buf)); + &init_task.thread.mode.skas.switch_buf)); } int external_pid_skas(struct task_struct *task) diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index 51fb94076fcf..0ae4eea21be4 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -18,11 +18,7 @@ void handle_syscall(union uml_pt_regs *r) struct pt_regs *regs = container_of(r, struct pt_regs, regs); long result; int syscall; -#ifdef UML_CONFIG_SYSCALL_DEBUG - int index; - index = record_syscall_start(UPT_SYSCALL_NR(r)); -#endif syscall_trace(r, 0); current->thread.nsyscalls++; @@ -44,7 +40,4 @@ void handle_syscall(union uml_pt_regs *r) REGS_SET_SYSCALL_RETURN(r->skas.regs, result); syscall_trace(r, 1); -#ifdef UML_CONFIG_SYSCALL_DEBUG - record_syscall_end(index, result); -#endif } diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 5992c3257167..8912cec0fe43 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -8,6 +8,7 @@ #include "linux/kernel.h" #include "linux/string.h" #include "linux/fs.h" +#include "linux/hardirq.h" #include "linux/highmem.h" #include "asm/page.h" #include "asm/pgtable.h" @@ -38,7 +39,7 @@ static unsigned long maybe_map(unsigned long virt, int is_write) return((unsigned long) phys); } -static int do_op(unsigned long addr, int len, int is_write, +static int do_op_one_page(unsigned long addr, int len, int is_write, int (*op)(unsigned long addr, int len, void *arg), void *arg) { struct page *page; @@ -49,9 +50,11 @@ static int do_op(unsigned long addr, int len, int is_write, return(-1); page = phys_to_page(addr); - addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); + addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + (addr & ~PAGE_MASK); + n = (*op)(addr, len, arg); - kunmap(page); + + kunmap_atomic(page, KM_UML_USERCOPY); return(n); } @@ -77,7 +80,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) remain = len; current->thread.fault_catcher = jmpbuf; - n = do_op(addr, size, is_write, op, arg); + n = do_op_one_page(addr, size, is_write, op, arg); if(n != 0){ *res = (n < 0 ? remain : 0); goto out; @@ -91,7 +94,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) } while(addr < ((addr + remain) & PAGE_MASK)){ - n = do_op(addr, PAGE_SIZE, is_write, op, arg); + n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg); if(n != 0){ *res = (n < 0 ? remain : 0); goto out; @@ -105,7 +108,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) goto out; } - n = do_op(addr, remain, is_write, op, arg); + n = do_op_one_page(addr, remain, is_write, op, arg); if(n != 0) *res = (n < 0 ? remain : 0); else *res = 0; diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 1731d90e6850..48cf88dd02d4 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -1,36 +1,166 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ +#include "linux/sched.h" +#include "linux/file.h" +#include "linux/smp_lock.h" +#include "linux/mm.h" +#include "linux/utsname.h" +#include "linux/msg.h" +#include "linux/shm.h" +#include "linux/sys.h" +#include "linux/syscalls.h" +#include "linux/unistd.h" +#include "linux/slab.h" +#include "linux/utime.h" +#include "asm/mman.h" +#include "asm/uaccess.h" #include "kern_util.h" -#include "syscall.h" -#include "os.h" +#include "user_util.h" +#include "sysdep/syscalls.h" +#include "mode_kern.h" +#include "choose-mode.h" -struct { - int syscall; - int pid; - long result; - unsigned long long start; - unsigned long long end; -} syscall_record[1024]; +/* Unlocked, I don't care if this is a bit off */ +int nsyscalls = 0; -int record_syscall_start(int syscall) +long sys_fork(void) { - int max, index; + long ret; - max = sizeof(syscall_record)/sizeof(syscall_record[0]); - index = next_syscall_index(max); + current->thread.forking = 1; + ret = do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs), + ¤t->thread.regs, 0, NULL, NULL); + current->thread.forking = 0; + return(ret); +} + +long sys_vfork(void) +{ + long ret; + + current->thread.forking = 1; + ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, + UPT_SP(¤t->thread.regs.regs), + ¤t->thread.regs, 0, NULL, NULL); + current->thread.forking = 0; + return(ret); +} + +/* common code for old and new mmaps */ +long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + long error = -EBADF; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); + out: + return error; +} + +long old_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long offset) +{ + long err = -EINVAL; + if (offset & ~PAGE_MASK) + goto out; + + err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + out: + return err; +} +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +long sys_pipe(unsigned long __user * fildes) +{ + int fd[2]; + long error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, sizeof(fd))) + error = -EFAULT; + } + return error; +} - syscall_record[index].syscall = syscall; - syscall_record[index].pid = current_pid(); - syscall_record[index].result = 0xdeadbeef; - syscall_record[index].start = os_nsecs(); - return(index); + +long sys_uname(struct old_utsname __user * name) +{ + long err; + if (!name) + return -EFAULT; + down_read(&uts_sem); + err = copy_to_user(name, &system_utsname, sizeof (*name)); + up_read(&uts_sem); + return err?-EFAULT:0; } -void record_syscall_end(int index, long result) +long sys_olduname(struct oldold_utsname __user * name) { - syscall_record[index].result = result; - syscall_record[index].end = os_nsecs(); + long error; + + if (!name) + return -EFAULT; + if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) + return -EFAULT; + + down_read(&uts_sem); + + error = __copy_to_user(&name->sysname,&system_utsname.sysname, + __OLD_UTS_LEN); + error |= __put_user(0,name->sysname+__OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename,&system_utsname.nodename, + __OLD_UTS_LEN); + error |= __put_user(0,name->nodename+__OLD_UTS_LEN); + error |= __copy_to_user(&name->release,&system_utsname.release, + __OLD_UTS_LEN); + error |= __put_user(0,name->release+__OLD_UTS_LEN); + error |= __copy_to_user(&name->version,&system_utsname.version, + __OLD_UTS_LEN); + error |= __put_user(0,name->version+__OLD_UTS_LEN); + error |= __copy_to_user(&name->machine,&system_utsname.machine, + __OLD_UTS_LEN); + error |= __put_user(0,name->machine+__OLD_UTS_LEN); + + up_read(&uts_sem); + + error = error ? -EFAULT : 0; + + return error; +} + +DEFINE_SPINLOCK(syscall_lock); + +static int syscall_index = 0; + +int next_syscall_index(int limit) +{ + int ret; + + spin_lock(&syscall_lock); + ret = syscall_index; + if(++syscall_index == limit) + syscall_index = 0; + spin_unlock(&syscall_lock); + return(ret); } diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c deleted file mode 100644 index 37d3978337d8..000000000000 --- a/arch/um/kernel/syscall_kern.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/file.h" -#include "linux/smp_lock.h" -#include "linux/mm.h" -#include "linux/utsname.h" -#include "linux/msg.h" -#include "linux/shm.h" -#include "linux/sys.h" -#include "linux/syscalls.h" -#include "linux/unistd.h" -#include "linux/slab.h" -#include "linux/utime.h" -#include "asm/mman.h" -#include "asm/uaccess.h" -#include "kern_util.h" -#include "user_util.h" -#include "sysdep/syscalls.h" -#include "mode_kern.h" -#include "choose-mode.h" - -/* Unlocked, I don't care if this is a bit off */ -int nsyscalls = 0; - -long sys_fork(void) -{ - long ret; - - current->thread.forking = 1; - ret = do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs), - ¤t->thread.regs, 0, NULL, NULL); - current->thread.forking = 0; - return(ret); -} - -long sys_vfork(void) -{ - long ret; - - current->thread.forking = 1; - ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, - UPT_SP(¤t->thread.regs.regs), - ¤t->thread.regs, 0, NULL, NULL); - current->thread.forking = 0; - return(ret); -} - -/* common code for old and new mmaps */ -long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - long error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); - out: - return error; -} - -long old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long offset) -{ - long err = -EINVAL; - if (offset & ~PAGE_MASK) - goto out; - - err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); - out: - return err; -} -/* - * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix traditionally does this, though. - */ -long sys_pipe(unsigned long __user * fildes) -{ - int fd[2]; - long error; - - error = do_pipe(fd); - if (!error) { - if (copy_to_user(fildes, fd, sizeof(fd))) - error = -EFAULT; - } - return error; -} - - -long sys_uname(struct old_utsname __user * name) -{ - long err; - if (!name) - return -EFAULT; - down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); - up_read(&uts_sem); - return err?-EFAULT:0; -} - -long sys_olduname(struct oldold_utsname __user * name) -{ - long error; - - if (!name) - return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - down_read(&uts_sem); - - error = __copy_to_user(&name->sysname,&system_utsname.sysname, - __OLD_UTS_LEN); - error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename, - __OLD_UTS_LEN); - error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release, - __OLD_UTS_LEN); - error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version, - __OLD_UTS_LEN); - error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine, - __OLD_UTS_LEN); - error |= __put_user(0,name->machine+__OLD_UTS_LEN); - - up_read(&uts_sem); - - error = error ? -EFAULT : 0; - - return error; -} - -DEFINE_SPINLOCK(syscall_lock); - -static int syscall_index = 0; - -int next_syscall_index(int limit) -{ - int ret; - - spin_lock(&syscall_lock); - ret = syscall_index; - if(++syscall_index == limit) - syscall_index = 0; - spin_unlock(&syscall_lock); - return(ret); -} diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 8fa2ae7f3026..a92965f8f9cd 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -1,172 +1,180 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <time.h> -#include <sys/time.h> -#include <signal.h> -#include <errno.h> -#include "user_util.h" +#include "linux/kernel.h" +#include "linux/module.h" +#include "linux/unistd.h" +#include "linux/stddef.h" +#include "linux/spinlock.h" +#include "linux/time.h" +#include "linux/sched.h" +#include "linux/interrupt.h" +#include "linux/init.h" +#include "linux/delay.h" +#include "linux/hrtimer.h" +#include "asm/irq.h" +#include "asm/param.h" +#include "asm/current.h" #include "kern_util.h" -#include "user.h" -#include "process.h" -#include "time_user.h" -#include "kern_constants.h" +#include "user_util.h" +#include "mode.h" #include "os.h" -/* XXX This really needs to be declared and initialized in a kernel file since - * it's in <linux/time.h> - */ -extern struct timespec wall_to_monotonic; - -extern struct timeval xtime; - -struct timeval local_offset = { 0, 0 }; - -void timer(void) +int hz(void) { - gettimeofday(&xtime, NULL); - timeradd(&xtime, &local_offset, &xtime); + return(HZ); } -static void set_interval(int timer_type) +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) { - int usec = 1000000/hz(); - struct itimerval interval = ((struct itimerval) { { 0, usec }, - { 0, usec } }); - - if(setitimer(timer_type, &interval, NULL) == -1) - panic("setitimer failed - errno = %d\n", errno); + return (unsigned long long)jiffies_64 * (1000000000 / HZ); } -void enable_timer(void) -{ - set_interval(ITIMER_VIRTUAL); -} +static unsigned long long prev_nsecs; +#ifdef CONFIG_UML_REAL_TIME_CLOCK +static long long delta; /* Deviation per interval */ +#endif -void prepare_timer(void * ptr) +void timer_irq(union uml_pt_regs *regs) { - int usec = 1000000/hz(); - *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec }, - { 0, usec }}); + unsigned long long ticks = 0; + +#ifdef CONFIG_UML_REAL_TIME_CLOCK + if(prev_nsecs){ + /* We've had 1 tick */ + unsigned long long nsecs = os_nsecs(); + + delta += nsecs - prev_nsecs; + prev_nsecs = nsecs; + + /* Protect against the host clock being set backwards */ + if(delta < 0) + delta = 0; + + ticks += (delta * HZ) / BILLION; + delta -= (ticks * BILLION) / HZ; + } + else prev_nsecs = os_nsecs(); +#else + ticks = 1; +#endif + while(ticks > 0){ + do_IRQ(TIMER_IRQ, regs); + ticks--; + } } -void disable_timer(void) +static DEFINE_SPINLOCK(timer_spinlock); + +static unsigned long long local_offset = 0; + +static inline unsigned long long get_time(void) { - struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); - if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) || - (setitimer(ITIMER_REAL, &disable, NULL) < 0)) - printk("disnable_timer - setitimer failed, errno = %d\n", - errno); - /* If there are signals already queued, after unblocking ignore them */ - set_handler(SIGALRM, SIG_IGN, 0, -1); - set_handler(SIGVTALRM, SIG_IGN, 0, -1); + unsigned long long nsecs; + unsigned long flags; + + spin_lock_irqsave(&timer_spinlock, flags); + nsecs = os_nsecs(); + nsecs += local_offset; + spin_unlock_irqrestore(&timer_spinlock, flags); + + return nsecs; } -void switch_timers(int to_real) +irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) { - struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); - struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() }, - { 0, 1000000/hz() }}); - int old, new; - - if(to_real){ - old = ITIMER_VIRTUAL; - new = ITIMER_REAL; - } - else { - old = ITIMER_REAL; - new = ITIMER_VIRTUAL; - } + unsigned long long nsecs; + unsigned long flags; + + write_seqlock_irqsave(&xtime_lock, flags); + + do_timer(1); - if((setitimer(old, &disable, NULL) < 0) || - (setitimer(new, &enable, NULL))) - printk("switch_timers - setitimer failed, errno = %d\n", - errno); + nsecs = get_time(); + xtime.tv_sec = nsecs / NSEC_PER_SEC; + xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC; + + write_sequnlock_irqrestore(&xtime_lock, flags); + + return IRQ_HANDLED; } -void uml_idle_timer(void) +static void register_timer(void) { - if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) - panic("Couldn't unset SIGVTALRM handler"); - - set_handler(SIGALRM, (__sighandler_t) alarm_handler, - SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_interval(ITIMER_REAL); + int err; + + err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL); + if(err != 0) + printk(KERN_ERR "register_timer : request_irq failed - " + "errno = %d\n", -err); + + err = set_interval(1); + if(err != 0) + printk(KERN_ERR "register_timer : set_interval failed - " + "errno = %d\n", -err); } -extern void ktime_get_ts(struct timespec *ts); -#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts) +extern void (*late_time_init)(void); void time_init(void) { - struct timespec now; - - if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) - panic("Couldn't set SIGVTALRM handler"); - set_interval(ITIMER_VIRTUAL); + long long nsecs; - do_posix_clock_monotonic_gettime(&now); - wall_to_monotonic.tv_sec = -now.tv_sec; - wall_to_monotonic.tv_nsec = -now.tv_nsec; + nsecs = os_nsecs(); + set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION, + -nsecs % BILLION); + late_time_init = register_timer; } -/* Defined in linux/ktimer.h, which can't be included here */ -#define clock_was_set() do { } while (0) - void do_gettimeofday(struct timeval *tv) { - unsigned long flags; - - flags = time_lock(); - gettimeofday(tv, NULL); - timeradd(tv, &local_offset, tv); - time_unlock(flags); - clock_was_set(); + unsigned long long nsecs = get_time(); + + tv->tv_sec = nsecs / NSEC_PER_SEC; + /* Careful about calculations here - this was originally done as + * (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC + * which gave bogus (> 1000000) values. Dunno why, suspect gcc + * (4.0.0) miscompiled it, or there's a subtle 64/32-bit conversion + * problem that I missed. + */ + nsecs -= tv->tv_sec * NSEC_PER_SEC; + tv->tv_usec = (unsigned long) nsecs / NSEC_PER_USEC; } -int do_settimeofday(struct timespec *tv) +static inline void set_time(unsigned long long nsecs) { - struct timeval now; + unsigned long long now; unsigned long flags; - struct timeval tv_in; - if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC) - return -EINVAL; + spin_lock_irqsave(&timer_spinlock, flags); + now = os_nsecs(); + local_offset = nsecs - now; + spin_unlock_irqrestore(&timer_spinlock, flags); - tv_in.tv_sec = tv->tv_sec; - tv_in.tv_usec = tv->tv_nsec / 1000; - - flags = time_lock(); - gettimeofday(&now, NULL); - timersub(&tv_in, &now, &local_offset); - time_unlock(flags); - - return(0); + clock_was_set(); } -void idle_sleep(int secs) +int do_settimeofday(struct timespec *tv) { - struct timespec ts; + set_time((unsigned long long) tv->tv_sec * NSEC_PER_SEC + tv->tv_nsec); - ts.tv_sec = secs; - ts.tv_nsec = 0; - nanosleep(&ts, NULL); + return 0; } -/* XXX This partly duplicates init_irq_signals */ - -void user_time_init(void) +void timer_handler(int sig, union uml_pt_regs *regs) { - set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, - SIGALRM, SIGUSR2, -1); - set_handler(SIGALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, - SIGVTALRM, SIGUSR2, -1); - set_interval(ITIMER_VIRTUAL); + local_irq_disable(); + irq_enter(); + update_process_times(CHOOSE_MODE( + (UPT_SC(regs) && user_context(UPT_SP(regs))), + (regs)->skas.is_user)); + irq_exit(); + local_irq_enable(); + if(current_thread->cpu == 0) + timer_irq(regs); } diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c deleted file mode 100644 index 87cdbc560d36..000000000000 --- a/arch/um/kernel/time_kern.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "linux/module.h" -#include "linux/unistd.h" -#include "linux/stddef.h" -#include "linux/spinlock.h" -#include "linux/time.h" -#include "linux/sched.h" -#include "linux/interrupt.h" -#include "linux/init.h" -#include "linux/delay.h" -#include "linux/hrtimer.h" -#include "asm/irq.h" -#include "asm/param.h" -#include "asm/current.h" -#include "kern_util.h" -#include "user_util.h" -#include "mode.h" -#include "os.h" - -int hz(void) -{ - return(HZ); -} - -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies_64 * (1000000000 / HZ); -} - -/* Changed at early boot */ -int timer_irq_inited = 0; - -static int first_tick; -static unsigned long long prev_nsecs; -#ifdef CONFIG_UML_REAL_TIME_CLOCK -static long long delta; /* Deviation per interval */ -#endif - -void timer_irq(union uml_pt_regs *regs) -{ - unsigned long long ticks = 0; - - if(!timer_irq_inited){ - /* This is to ensure that ticks don't pile up when - * the timer handler is suspended */ - first_tick = 0; - return; - } - - if(first_tick){ -#ifdef CONFIG_UML_REAL_TIME_CLOCK - /* We've had 1 tick */ - unsigned long long nsecs = os_nsecs(); - - delta += nsecs - prev_nsecs; - prev_nsecs = nsecs; - - /* Protect against the host clock being set backwards */ - if(delta < 0) - delta = 0; - - ticks += (delta * HZ) / BILLION; - delta -= (ticks * BILLION) / HZ; -#else - ticks = 1; -#endif - } - else { - prev_nsecs = os_nsecs(); - first_tick = 1; - } - - while(ticks > 0){ - do_IRQ(TIMER_IRQ, regs); - ticks--; - } -} - - -void time_init_kern(void) -{ - long long nsecs; - - nsecs = os_nsecs(); - set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION, - -nsecs % BILLION); -} - -void do_boot_timer_handler(struct sigcontext * sc) -{ - struct pt_regs regs; - - CHOOSE_MODE((void) (UPT_SC(®s.regs) = sc), - (void) (regs.regs.skas.is_user = 0)); - do_timer(®s); -} - -static DEFINE_SPINLOCK(timer_spinlock); - -static unsigned long long local_offset = 0; - -static inline unsigned long long get_time(void) -{ - unsigned long long nsecs; - unsigned long flags; - - spin_lock_irqsave(&timer_spinlock, flags); - nsecs = os_nsecs(); - nsecs += local_offset; - spin_unlock_irqrestore(&timer_spinlock, flags); - - return nsecs; -} - -irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) -{ - unsigned long long nsecs; - unsigned long flags; - - do_timer(regs); - - write_seqlock_irqsave(&xtime_lock, flags); - nsecs = get_time() + local_offset; - xtime.tv_sec = nsecs / NSEC_PER_SEC; - xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC; - write_sequnlock_irqrestore(&xtime_lock, flags); - - return(IRQ_HANDLED); -} - -long um_time(int __user *tloc) -{ - long ret = get_time() / NSEC_PER_SEC; - - if((tloc != NULL) && put_user(ret, tloc)) - return -EFAULT; - - return ret; -} - -void do_gettimeofday(struct timeval *tv) -{ - unsigned long long nsecs = get_time(); - - tv->tv_sec = nsecs / NSEC_PER_SEC; - /* Careful about calculations here - this was originally done as - * (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC - * which gave bogus (> 1000000) values. Dunno why, suspect gcc - * (4.0.0) miscompiled it, or there's a subtle 64/32-bit conversion - * problem that I missed. - */ - nsecs -= tv->tv_sec * NSEC_PER_SEC; - tv->tv_usec = (unsigned long) nsecs / NSEC_PER_USEC; -} - -static inline void set_time(unsigned long long nsecs) -{ - unsigned long long now; - unsigned long flags; - - spin_lock_irqsave(&timer_spinlock, flags); - now = os_nsecs(); - local_offset = nsecs - now; - spin_unlock_irqrestore(&timer_spinlock, flags); - - clock_was_set(); -} - -long um_stime(int __user *tptr) -{ - int value; - - if (get_user(value, tptr)) - return -EFAULT; - - set_time((unsigned long long) value * NSEC_PER_SEC); - - return 0; -} - -int do_settimeofday(struct timespec *tv) -{ - set_time((unsigned long long) tv->tv_sec * NSEC_PER_SEC + tv->tv_nsec); - - return 0; -} - -void timer_handler(int sig, union uml_pt_regs *regs) -{ - local_irq_disable(); - irq_enter(); - update_process_times(CHOOSE_MODE( - (UPT_SC(regs) && user_context(UPT_SP(regs))), - (regs)->skas.is_user)); - irq_exit(); - local_irq_enable(); - if(current_thread->cpu == 0) - timer_irq(regs); -} - -int __init timer_init(void) -{ - int err; - - user_time_init(); - err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL); - if(err != 0) - printk(KERN_ERR "timer_init : request_irq failed - " - "errno = %d\n", -err); - timer_irq_inited = 1; - return(0); -} - -arch_initcall(timer_init); diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index f5b0636f9ad7..54a5ff25645a 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -16,12 +16,12 @@ #include "os.h" static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x, struct host_vm_op *ops, int *index, + int r, int w, int x, struct host_vm_op *ops, int *index, int last_filled, union mm_context *mmu, void **flush, int (*do_ops)(union mm_context *, struct host_vm_op *, int, int, void **)) { - __u64 offset; + __u64 offset; struct host_vm_op *last; int fd, ret = 0; @@ -89,7 +89,7 @@ static int add_munmap(unsigned long addr, unsigned long len, static int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, struct host_vm_op *ops, int *index, int last_filled, union mm_context *mmu, void **flush, - int (*do_ops)(union mm_context *, struct host_vm_op *, + int (*do_ops)(union mm_context *, struct host_vm_op *, int, int, void **)) { struct host_vm_op *last; @@ -124,105 +124,105 @@ static int add_mprotect(unsigned long addr, unsigned long len, int r, int w, #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) void fix_range_common(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force, + unsigned long end_addr, int force, int (*do_ops)(union mm_context *, struct host_vm_op *, int, int, void **)) { - pgd_t *npgd; - pud_t *npud; - pmd_t *npmd; - pte_t *npte; - union mm_context *mmu = &mm->context; - unsigned long addr, end; - int r, w, x; - struct host_vm_op ops[1]; - void *flush = NULL; - int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1; - int ret = 0; - - if(mm == NULL) return; - - ops[0].type = NONE; - for(addr = start_addr; addr < end_addr && !ret;){ - npgd = pgd_offset(mm, addr); - if(!pgd_present(*npgd)){ - end = ADD_ROUND(addr, PGDIR_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pgd_newpage(*npgd)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pgd_mkuptodate(*npgd); - } - addr = end; - continue; - } - - npud = pud_offset(npgd, addr); - if(!pud_present(*npud)){ - end = ADD_ROUND(addr, PUD_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pud_newpage(*npud)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pud_mkuptodate(*npud); - } - addr = end; - continue; - } - - npmd = pmd_offset(npud, addr); - if(!pmd_present(*npmd)){ - end = ADD_ROUND(addr, PMD_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pmd_newpage(*npmd)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pmd_mkuptodate(*npmd); - } - addr = end; - continue; - } - - npte = pte_offset_kernel(npmd, addr); - r = pte_read(*npte); - w = pte_write(*npte); - x = pte_exec(*npte); + pgd_t *npgd; + pud_t *npud; + pmd_t *npmd; + pte_t *npte; + union mm_context *mmu = &mm->context; + unsigned long addr, end; + int r, w, x; + struct host_vm_op ops[1]; + void *flush = NULL; + int op_index = -1, last_op = ARRAY_SIZE(ops) - 1; + int ret = 0; + + if(mm == NULL) + return; + + ops[0].type = NONE; + for(addr = start_addr; addr < end_addr && !ret;){ + npgd = pgd_offset(mm, addr); + if(!pgd_present(*npgd)){ + end = ADD_ROUND(addr, PGDIR_SIZE); + if(end > end_addr) + end = end_addr; + if(force || pgd_newpage(*npgd)){ + ret = add_munmap(addr, end - addr, ops, + &op_index, last_op, mmu, + &flush, do_ops); + pgd_mkuptodate(*npgd); + } + addr = end; + continue; + } + + npud = pud_offset(npgd, addr); + if(!pud_present(*npud)){ + end = ADD_ROUND(addr, PUD_SIZE); + if(end > end_addr) + end = end_addr; + if(force || pud_newpage(*npud)){ + ret = add_munmap(addr, end - addr, ops, + &op_index, last_op, mmu, + &flush, do_ops); + pud_mkuptodate(*npud); + } + addr = end; + continue; + } + + npmd = pmd_offset(npud, addr); + if(!pmd_present(*npmd)){ + end = ADD_ROUND(addr, PMD_SIZE); + if(end > end_addr) + end = end_addr; + if(force || pmd_newpage(*npmd)){ + ret = add_munmap(addr, end - addr, ops, + &op_index, last_op, mmu, + &flush, do_ops); + pmd_mkuptodate(*npmd); + } + addr = end; + continue; + } + + npte = pte_offset_kernel(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); 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, - pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x, ops, - &op_index, last_op, mmu, - &flush, do_ops); + if(force || pte_newpage(*npte)){ + if(pte_present(*npte)) + ret = add_mmap(addr, + pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x, ops, + &op_index, last_op, mmu, + &flush, do_ops); else ret = add_munmap(addr, PAGE_SIZE, ops, &op_index, last_op, mmu, &flush, do_ops); - } - else if(pte_newprot(*npte)) + } + else if(pte_newprot(*npte)) ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, &op_index, last_op, mmu, &flush, do_ops); - *npte = pte_mkuptodate(*npte); - addr += PAGE_SIZE; - } - + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; + } if(!ret) ret = (*do_ops)(mmu, ops, op_index, 1, &flush); - /* This is not an else because ret is modified above */ +/* This is not an else because ret is modified above */ if(ret) { printk("fix_range_common: failed, killing current process\n"); force_sig(SIGKILL, current); @@ -231,160 +231,160 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) { - struct mm_struct *mm; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - unsigned long addr, last; - int updated = 0, err; - - mm = &init_mm; - for(addr = start; addr < end;){ - pgd = pgd_offset(mm, addr); - if(!pgd_present(*pgd)){ - last = ADD_ROUND(addr, PGDIR_SIZE); - if(last > end) - last = end; - if(pgd_newpage(*pgd)){ - updated = 1; - err = os_unmap_memory((void *) addr, - last - addr); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr = last; - continue; - } - - pud = pud_offset(pgd, addr); - if(!pud_present(*pud)){ - last = ADD_ROUND(addr, PUD_SIZE); - if(last > end) - last = end; - if(pud_newpage(*pud)){ - updated = 1; - err = os_unmap_memory((void *) addr, - last - addr); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr = last; - continue; - } - - pmd = pmd_offset(pud, addr); - if(!pmd_present(*pmd)){ - last = ADD_ROUND(addr, PMD_SIZE); - if(last > end) - last = end; - if(pmd_newpage(*pmd)){ - updated = 1; - err = os_unmap_memory((void *) addr, - last - addr); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr = last; - continue; - } - - pte = pte_offset_kernel(pmd, addr); - if(!pte_present(*pte) || pte_newpage(*pte)){ - updated = 1; - err = os_unmap_memory((void *) addr, - PAGE_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - if(pte_present(*pte)) - map_memory(addr, - pte_val(*pte) & PAGE_MASK, - PAGE_SIZE, 1, 1, 1); - } - else if(pte_newprot(*pte)){ - updated = 1; - os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1); - } - addr += PAGE_SIZE; - } - return(updated); + struct mm_struct *mm; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + unsigned long addr, last; + int updated = 0, err; + + mm = &init_mm; + for(addr = start; addr < end;){ + pgd = pgd_offset(mm, addr); + if(!pgd_present(*pgd)){ + last = ADD_ROUND(addr, PGDIR_SIZE); + if(last > end) + last = end; + if(pgd_newpage(*pgd)){ + updated = 1; + err = os_unmap_memory((void *) addr, + last - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr = last; + continue; + } + + pud = pud_offset(pgd, addr); + if(!pud_present(*pud)){ + last = ADD_ROUND(addr, PUD_SIZE); + if(last > end) + last = end; + if(pud_newpage(*pud)){ + updated = 1; + err = os_unmap_memory((void *) addr, + last - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr = last; + continue; + } + + pmd = pmd_offset(pud, addr); + if(!pmd_present(*pmd)){ + last = ADD_ROUND(addr, PMD_SIZE); + if(last > end) + last = end; + if(pmd_newpage(*pmd)){ + updated = 1; + err = os_unmap_memory((void *) addr, + last - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr = last; + continue; + } + + pte = pte_offset_kernel(pmd, addr); + if(!pte_present(*pte) || pte_newpage(*pte)){ + updated = 1; + err = os_unmap_memory((void *) addr, + PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + if(pte_present(*pte)) + map_memory(addr, + pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, 1, 1, 1); + } + else if(pte_newprot(*pte)){ + updated = 1; + os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1); + } + addr += PAGE_SIZE; + } + return(updated); } pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) { - return(pgd_offset(mm, address)); + return(pgd_offset(mm, address)); } pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address) { - return(pud_offset(pgd, address)); + return(pud_offset(pgd, address)); } pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address) { - return(pmd_offset(pud, address)); + return(pmd_offset(pud, address)); } pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address) { - return(pte_offset_kernel(pmd, address)); + return(pte_offset_kernel(pmd, address)); } pte_t *addr_pte(struct task_struct *task, unsigned long addr) { - pgd_t *pgd = pgd_offset(task->mm, addr); - pud_t *pud = pud_offset(pgd, addr); - pmd_t *pmd = pmd_offset(pud, addr); + pgd_t *pgd = pgd_offset(task->mm, addr); + pud_t *pud = pud_offset(pgd, addr); + pmd_t *pmd = pmd_offset(pud, addr); - return(pte_offset_map(pmd, addr)); + return(pte_offset_map(pmd, addr)); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) { - address &= PAGE_MASK; - flush_tlb_range(vma, address, address + PAGE_SIZE); + address &= PAGE_MASK; + flush_tlb_range(vma, address, address + PAGE_SIZE); } void flush_tlb_all(void) { - flush_tlb_mm(current->mm); + flush_tlb_mm(current->mm); } void flush_tlb_kernel_range(unsigned long start, unsigned long end) { - CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt, - flush_tlb_kernel_range_common, start, end); + CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt, + flush_tlb_kernel_range_common, start, end); } void flush_tlb_kernel_vm(void) { - CHOOSE_MODE(flush_tlb_kernel_vm_tt(), - flush_tlb_kernel_range_common(start_vm, end_vm)); + CHOOSE_MODE(flush_tlb_kernel_vm_tt(), + flush_tlb_kernel_range_common(start_vm, end_vm)); } void __flush_tlb_one(unsigned long addr) { - CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); + CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); } void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, - end); + CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, + end); } void flush_tlb_mm(struct mm_struct *mm) { - CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); + CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); } void force_flush_all(void) { - CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); + CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); } diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap.c index 02f6d4d8dc3a..c7b195c7e51f 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap.c @@ -35,7 +35,7 @@ #include "os.h" /* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */ -int handle_page_fault(unsigned long address, unsigned long ip, +int handle_page_fault(unsigned long address, unsigned long ip, int is_write, int is_user, int *code_out) { struct mm_struct *mm = current->mm; @@ -55,20 +55,20 @@ int handle_page_fault(unsigned long address, unsigned long ip, down_read(&mm->mmap_sem); vma = find_vma(mm, address); - if(!vma) + if(!vma) goto out; - else if(vma->vm_start <= address) + else if(vma->vm_start <= address) goto good_area; - else if(!(vma->vm_flags & VM_GROWSDOWN)) + else if(!(vma->vm_flags & VM_GROWSDOWN)) goto out; else if(is_user && !ARCH_IS_STACKGROW(address)) goto out; - else if(expand_stack(vma, address)) + else if(expand_stack(vma, address)) goto out; good_area: *code_out = SEGV_ACCERR; - if(is_write && !(vma->vm_flags & VM_WRITE)) + if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; /* Don't require VM_READ|VM_EXEC for write faults! */ @@ -120,7 +120,7 @@ out_nosemaphore: * us unable to handle the page fault gracefully. */ out_of_memory: - if (current->pid == 1) { + if (is_init(current)) { up_read(&mm->mmap_sem); yield(); down_read(&mm->mmap_sem); @@ -140,14 +140,6 @@ void segv_handler(int sig, union uml_pt_regs *regs) segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); } -struct kern_handlers handlinfo_kern = { - .relay_signal = relay_signal, - .winch = winch, - .bus_handler = relay_signal, - .page_fault = segv_handler, - .sigio_handler = sigio_handler, - .timer_handler = timer_handler -}; /* * We give a *copy* of the faultinfo in the regs to segv. * This must be done, since nesting SEGVs could overwrite @@ -184,14 +176,14 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) else if(catcher != NULL){ current->thread.fault_addr = (void *) address; do_longjmp(catcher, 1); - } + } else if(current->thread.fault_addr != NULL) panic("fault_addr set but no fault catcher"); else if(!is_user && arch_fixup(ip, sc)) return(0); - if(!is_user) - panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", + if(!is_user) + panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", address, ip); if (err == -EACCES) { @@ -227,9 +219,16 @@ void bad_segv(struct faultinfo fi, unsigned long ip) void relay_signal(int sig, union uml_pt_regs *regs) { - if(arch_handle_signal(sig, regs)) return; - if(!UPT_IS_USER(regs)) + if(arch_handle_signal(sig, regs)) + return; + + if(!UPT_IS_USER(regs)){ + if(sig == SIGBUS) + printk("Bus error - the /dev/shm or /tmp mount likely " + "just ran out of space\n"); panic("Kernel mode signal %d", sig); + } + current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); force_sig(sig, current); } @@ -246,6 +245,15 @@ void winch(int sig, union uml_pt_regs *regs) do_IRQ(WINCH_IRQ, regs); } +const struct kern_handlers handlinfo_kern = { + .relay_signal = relay_signal, + .winch = winch, + .bus_handler = bus_handler, + .page_fault = segv_handler, + .sigio_handler = sigio_handler, + .timer_handler = timer_handler +}; + void trap_init(void) { } diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index 5c1e4cc1c049..ad66df17d9d7 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -21,7 +21,7 @@ static int exec_tramp(void *sig_stack) { init_new_thread_stack(sig_stack, NULL); - init_new_thread_signals(1); + init_new_thread_signals(); os_stop_process(os_getpid()); return(0); } diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c index bcb8796c3cb1..84a23b14f770 100644 --- a/arch/um/kernel/tt/mem.c +++ b/arch/um/kernel/tt/mem.c @@ -24,22 +24,13 @@ void before_mem_tt(unsigned long brk_start) #define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) #define START (CONFIG_TOP_ADDR - SIZE) -unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, - unsigned long *task_size_out) +unsigned long set_task_sizes_tt(unsigned long *task_size_out) { + unsigned long host_task_size; + /* Round up to the nearest 4M */ - *host_size_out = ROUND_4M((unsigned long) &arg); + host_task_size = ROUND_4M((unsigned long) &host_task_size); *task_size_out = START; - return(START); -} -/* - * 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: - */ + return host_task_size; +} diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index a9c1443fc548..1e86f0bfef72 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -119,7 +119,7 @@ void suspend_new_thread(int fd) panic("read failed in suspend_new_thread, err = %d", -err); } -void schedule_tail(task_t *prev); +void schedule_tail(struct task_struct *prev); static void new_thread_handler(int sig) { @@ -142,7 +142,7 @@ static void new_thread_handler(int sig) schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; - init_new_thread_signals(1); + init_new_thread_signals(); enable_timer(); free_page(current->thread.temp_stack); set_cmdline("(kernel thread)"); diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c index 3fda9a03c59a..293caa6d0c2d 100644 --- a/arch/um/kernel/tt/syscall_kern.c +++ b/arch/um/kernel/tt/syscall_kern.c @@ -21,18 +21,11 @@ void syscall_handler_tt(int sig, struct pt_regs *regs) void *sc; long result; int syscall; -#ifdef CONFIG_SYSCALL_DEBUG - int index; -#endif + sc = UPT_SC(®s->regs); SC_START_SYSCALL(sc); syscall = UPT_SYSCALL_NR(®s->regs); - -#ifdef CONFIG_SYSCALL_DEBUG - index = record_syscall_start(syscall); -#endif - syscall_trace(®s->regs, 0); current->thread.nsyscalls++; @@ -50,7 +43,4 @@ void syscall_handler_tt(int sig, struct pt_regs *regs) SC_SET_SYSCALL_RETURN(sc, result); syscall_trace(®s->regs, 1); -#ifdef CONFIG_SYSCALL_DEBUG - record_syscall_end(index, result); -#endif } diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index 71daae24e48a..9882342206ec 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c @@ -188,10 +188,7 @@ int tracer(int (*init_proc)(void *), void *sp) int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; int proc_id = 0, n, err, old_tracing = 0, strace = 0; int local_using_sysemu = 0; -#ifdef UML_CONFIG_SYSCALL_DEBUG - unsigned long eip = 0; - int last_index; -#endif + signal(SIGPIPE, SIG_IGN); setup_tracer_winch(); tracing_pid = os_getpid(); @@ -282,23 +279,6 @@ int tracer(int (*init_proc)(void *), void *sp) else if(WIFSTOPPED(status)){ proc_id = pid_to_processor_id(pid); sig = WSTOPSIG(status); -#ifdef UML_CONFIG_SYSCALL_DEBUG - if(signal_index[proc_id] == 1024){ - signal_index[proc_id] = 0; - last_index = 1023; - } - else last_index = signal_index[proc_id] - 1; - if(((sig == SIGPROF) || (sig == SIGVTALRM) || - (sig == SIGALRM)) && - (signal_record[proc_id][last_index].signal == sig)&& - (signal_record[proc_id][last_index].pid == pid)) - signal_index[proc_id] = last_index; - signal_record[proc_id][signal_index[proc_id]].pid = pid; - gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL); - eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0); - signal_record[proc_id][signal_index[proc_id]].addr = eip; - signal_record[proc_id][signal_index[proc_id]++].signal = sig; -#endif if(proc_id == -1){ sleeping_process_signal(pid, sig); continue; diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 7d51dd7201c3..55005710dcbb 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -106,7 +106,7 @@ static void c_stop(struct seq_file *m, void *v) { } -struct seq_operations cpuinfo_op = { +const struct seq_operations cpuinfo_op = { .start = c_start, .next = c_next, .stop = c_stop, @@ -330,6 +330,8 @@ EXPORT_SYMBOL(end_iomem); #define MIN_VMALLOC (32 * 1024 * 1024) +extern char __binary_start; + int linux_main(int argc, char **argv) { unsigned long avail, diff; @@ -374,8 +376,9 @@ int linux_main(int argc, char **argv) printf("UML running in %s mode\n", mode); - uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, - &host_task_size, &task_size); + uml_start = (unsigned long) &__binary_start; + host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt, + set_task_sizes_skas, &task_size); /* * Setting up handlers to 'sig_info' struct @@ -395,7 +398,7 @@ int linux_main(int argc, char **argv) physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); } - uml_physmem = uml_start; + uml_physmem = uml_start & PAGE_MASK; /* Reserve up to 4M after the current brk */ uml_reserved = ROUND_4M(brk_start) + (1 << 22); @@ -495,6 +498,7 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end) { } +#ifdef CONFIG_SMP void alternatives_smp_module_add(struct module *mod, char *name, void *locks, void *locks_end, void *text, void *text_end) @@ -504,3 +508,4 @@ void alternatives_smp_module_add(struct module *mod, char *name, void alternatives_smp_module_del(struct module *mod) { } +#endif diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index af11915ce0a8..8eca47a6ff08 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -7,13 +7,16 @@ jiffies = jiffies_64; SECTIONS { - /*This must contain the right address - not quite the default ELF one.*/ + /* This must contain the right address - not quite the default ELF one.*/ PROVIDE (__executable_start = START); - . = START + SIZEOF_HEADERS; + /* Static binaries stick stuff here, like the sigreturn trampoline, + * invisibly to objdump. So, just make __binary_start equal to the very + * beginning of the executable, and if there are unmapped pages after this, + * they are forever unusable. + */ + __binary_start = START; - /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start - * is remapped.*/ - __binary_start = .; + . = START + SIZEOF_HEADERS; #ifdef MODE_TT .remap_data : { UNMAP_PATH (.data .bss) } diff --git a/arch/um/kernel/vmlinux.lds.S b/arch/um/kernel/vmlinux.lds.S index 1660a769674b..f8aeb448aab6 100644 --- a/arch/um/kernel/vmlinux.lds.S +++ b/arch/um/kernel/vmlinux.lds.S @@ -1,4 +1,3 @@ -#include <linux/config.h> #ifdef CONFIG_LD_SCRIPT_STATIC #include "uml.lds.S" #else diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index f4bfc4c7ccac..b4183929b32c 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -4,15 +4,19 @@ # obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ - signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o tls.o \ + signal.o start_up.o time.o trap.o tty.o uaccess.o umid.o tls.o \ user_syms.o util.o drivers/ sys-$(SUBARCH)/ obj-$(CONFIG_MODE_SKAS) += skas/ + +obj-$(CONFIG_MODE_TT) += tt.o +user-objs-$(CONFIG_MODE_TT) += tt.o + obj-$(CONFIG_TTY_LOG) += tty_log.o user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ - process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o tls.o \ + process.o sigio.o signal.o start_up.o time.o trap.o tty.o tls.o \ uaccess.o umid.o util.o CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h index b84f6c4740f7..57ecdaf2f67e 100644 --- a/arch/um/os-Linux/drivers/etap.h +++ b/arch/um/os-Linux/drivers/etap.h @@ -13,7 +13,7 @@ struct ethertap_data { void *dev; }; -extern struct net_user_info ethertap_user_info; +extern const struct net_user_info ethertap_user_info; /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 768606bec233..16385e2ada85 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c @@ -65,7 +65,7 @@ static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) return(net_send(fd, (*skb)->data, (*skb)->len)); } -struct net_kern_info ethertap_kern_info = { +const struct net_kern_info ethertap_kern_info = { .init = etap_init, .protocol = eth_protocol, .read = etap_read, diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index 8f49507e64ef..f559bdf746e6 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -216,7 +216,7 @@ static void etap_del_addr(unsigned char *addr, unsigned char *netmask, etap_close_addr(addr, netmask, &pri->control_fd); } -struct net_user_info ethertap_user_info = { +const struct net_user_info ethertap_user_info = { .init = etap_user_init, .open = etap_open, .close = etap_close, diff --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h index 25d4a2868814..d3e8d3af6245 100644 --- a/arch/um/os-Linux/drivers/tuntap.h +++ b/arch/um/os-Linux/drivers/tuntap.h @@ -16,7 +16,7 @@ struct tuntap_data { void *dev; }; -extern struct net_user_info tuntap_user_info; +extern const struct net_user_info tuntap_user_info; #endif diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 190009a6f89c..0edbac63c527 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c @@ -53,7 +53,7 @@ static int tuntap_write(int fd, struct sk_buff **skb, return(net_write(fd, (*skb)->data, (*skb)->len)); } -struct net_kern_info tuntap_kern_info = { +const struct net_kern_info tuntap_kern_info = { .init = tuntap_init, .protocol = eth_protocol, .read = tuntap_read, diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 87c3aa0252db..e846b23f7558 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -205,7 +205,7 @@ static int tuntap_set_mtu(int mtu, void *data) return(mtu); } -struct net_user_info tuntap_user_info = { +const struct net_user_info tuntap_user_info = { .init = tuntap_user_init, .open = tuntap_open, .close = tuntap_close, diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index 09251338d99e..189fa677085a 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -18,6 +18,7 @@ #include "os.h" #include "user.h" #include "kern_util.h" +#include "user_util.h" static void copy_stat(struct uml_stat *dst, struct stat64 *src) { @@ -42,16 +43,13 @@ int os_stat_fd(const int fd, struct uml_stat *ubuf) struct stat64 sbuf; int err; - do { - err = fstat64(fd, &sbuf); - } while((err < 0) && (errno == EINTR)) ; - + CATCH_EINTR(err = fstat64(fd, &sbuf)); if(err < 0) - return(-errno); + return -errno; if(ubuf != NULL) copy_stat(ubuf, &sbuf); - return(err); + return err; } int os_stat_file(const char *file_name, struct uml_stat *ubuf) @@ -64,11 +62,11 @@ int os_stat_file(const char *file_name, struct uml_stat *ubuf) } while((err < 0) && (errno == EINTR)) ; if(err < 0) - return(-errno); + return -errno; if(ubuf != NULL) copy_stat(ubuf, &sbuf); - return(err); + return err; } int os_access(const char* file, int mode) @@ -80,9 +78,9 @@ int os_access(const char* file, int mode) err = access(file, amode); if(err < 0) - return(-errno); + return -errno; - return(0); + return 0; } void os_print_error(int error, const char* str) @@ -99,9 +97,9 @@ int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg) err = ioctl(fd, cmd, arg); if(err < 0) - return(-errno); + return -errno; - return(err); + return err; } int os_window_size(int fd, int *rows, int *cols) @@ -109,12 +107,12 @@ int os_window_size(int fd, int *rows, int *cols) struct winsize size; if(ioctl(fd, TIOCGWINSZ, &size) < 0) - return(-errno); + return -errno; *rows = size.ws_row; *cols = size.ws_col; - return(0); + return 0; } int os_new_tty_pgrp(int fd, int pid) @@ -125,16 +123,16 @@ int os_new_tty_pgrp(int fd, int pid) if(tcsetpgrp(fd, pid) < 0) return -errno; - return(0); + return 0; } /* FIXME: ensure namebuf in os_get_if_name is big enough */ int os_get_ifname(int fd, char* namebuf) { if(ioctl(fd, SIOCGIFNAME, namebuf) < 0) - return(-errno); + return -errno; - return(0); + return 0; } int os_set_slip(int fd) @@ -149,7 +147,7 @@ int os_set_slip(int fd) if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0) return -errno; - return(0); + return 0; } int os_set_owner(int fd, int pid) @@ -158,10 +156,10 @@ int os_set_owner(int fd, int pid) int save_errno = errno; if(fcntl(fd, F_GETOWN, 0) != pid) - return(-save_errno); + return -save_errno; } - return(0); + return 0; } /* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ @@ -192,9 +190,9 @@ int os_mode_fd(int fd, int mode) } while((err < 0) && (errno==EINTR)) ; if(err < 0) - return(-errno); + return -errno; - return(0); + return 0; } int os_file_type(char *file) @@ -204,15 +202,21 @@ int os_file_type(char *file) err = os_stat_file(file, &buf); if(err < 0) - return(err); + return err; - if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR); - else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK); - else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV); - else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV); - else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO); - else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK); - else return(OS_TYPE_FILE); + if(S_ISDIR(buf.ust_mode)) + return OS_TYPE_DIR; + else if(S_ISLNK(buf.ust_mode)) + return OS_TYPE_SYMLINK; + else if(S_ISCHR(buf.ust_mode)) + return OS_TYPE_CHARDEV; + else if(S_ISBLK(buf.ust_mode)) + return OS_TYPE_BLOCKDEV; + else if(S_ISFIFO(buf.ust_mode)) + return OS_TYPE_FIFO; + else if(S_ISSOCK(buf.ust_mode)) + return OS_TYPE_SOCK; + else return OS_TYPE_FILE; } int os_file_mode(char *file, struct openflags *mode_out) @@ -302,8 +306,8 @@ int os_seek_file(int fd, __u64 offset) actual = lseek64(fd, offset, SEEK_SET); if(actual != offset) - return(-errno); - return(0); + return -errno; + return 0; } static int fault_buffer(void *start, int len, @@ -314,13 +318,13 @@ static int fault_buffer(void *start, int len, for(i = 0; i < len; i += page){ if((*copy_proc)(start + i, &c, sizeof(c))) - return(-EFAULT); + return -EFAULT; } if((len % page) != 0){ if((*copy_proc)(start + len - 1, &c, sizeof(c))) - return(-EFAULT); + return -EFAULT; } - return(0); + return 0; } static int file_io(int fd, void *buf, int len, @@ -334,26 +338,26 @@ static int file_io(int fd, void *buf, int len, if((n < 0) && (errno == EFAULT)){ err = fault_buffer(buf, len, copy_user_proc); if(err) - return(err); + return err; n = (*io_proc)(fd, buf, len); } } while((n < 0) && (errno == EINTR)); if(n < 0) - return(-errno); - return(n); + return -errno; + return n; } int os_read_file(int fd, void *buf, int len) { - return(file_io(fd, buf, len, (int (*)(int, void *, int)) read, - copy_from_user_proc)); + return file_io(fd, buf, len, (int (*)(int, void *, int)) read, + copy_from_user_proc); } int os_write_file(int fd, const void *buf, int len) { - return(file_io(fd, (void *) buf, len, - (int (*)(int, void *, int)) write, copy_to_user_proc)); + return file_io(fd, (void *) buf, len, + (int (*)(int, void *, int)) write, copy_to_user_proc); } int os_file_size(char *file, unsigned long long *size_out) @@ -398,11 +402,11 @@ int os_file_modtime(char *file, unsigned long *modtime) err = os_stat_file(file, &buf); if(err < 0){ printk("Couldn't stat \"%s\" : err = %d\n", file, -err); - return(err); + return err; } *modtime = buf.ust_mtime; - return(0); + return 0; } int os_get_exec_close(int fd, int* close_on_exec) @@ -455,7 +459,7 @@ int os_pipe(int *fds, int stream, int close_on_exec) if(err < 0) goto error; - return(0); + return 0; error: printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err); @@ -486,12 +490,12 @@ int os_set_fd_async(int fd, int owner) (fcntl(fd, F_SETOWN, owner) < 0)){ err = -errno; printk("os_set_fd_async : Failed to fcntl F_SETOWN " - "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd, + "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd, owner, errno); return err; } - return(0); + return 0; } int os_clear_fd_async(int fd) @@ -500,8 +504,8 @@ int os_clear_fd_async(int fd) flags &= ~(O_ASYNC | O_NONBLOCK); if(fcntl(fd, F_SETFL, flags) < 0) - return(-errno); - return(0); + return -errno; + return 0; } int os_set_fd_block(int fd, int blocking) @@ -516,7 +520,7 @@ int os_set_fd_block(int fd, int blocking) if(fcntl(fd, F_SETFL, flags) < 0) return -errno; - return(0); + return 0; } int os_accept_connection(int fd) @@ -524,9 +528,9 @@ int os_accept_connection(int fd) int new; new = accept(fd, NULL, 0); - if(new < 0) - return(-errno); - return(new); + if(new < 0) + return -errno; + return new; } #ifndef SHUT_RD @@ -550,12 +554,12 @@ int os_shutdown_socket(int fd, int r, int w) else if(w) what = SHUT_WR; else { printk("os_shutdown_socket : neither r or w was set\n"); - return(-EINVAL); + return -EINVAL; } err = shutdown(fd, what); if(err < 0) - return(-errno); - return(0); + return -errno; + return 0; } int os_rcv_fd(int fd, int *helper_pid_out) @@ -578,7 +582,7 @@ int os_rcv_fd(int fd, int *helper_pid_out) n = recvmsg(fd, &msg, 0); if(n < 0) - return(-errno); + return -errno; else if(n != sizeof(iov.iov_len)) *helper_pid_out = -1; @@ -586,16 +590,16 @@ int os_rcv_fd(int fd, int *helper_pid_out) cmsg = CMSG_FIRSTHDR(&msg); if(cmsg == NULL){ printk("rcv_fd didn't receive anything, error = %d\n", errno); - return(-1); + return -1; } - if((cmsg->cmsg_level != SOL_SOCKET) || + if((cmsg->cmsg_level != SOL_SOCKET) || (cmsg->cmsg_type != SCM_RIGHTS)){ printk("rcv_fd didn't receive a descriptor\n"); - return(-1); + return -1; } new = ((int *) CMSG_DATA(cmsg))[0]; - return(new); + return new; } int os_create_unix_socket(char *file, int len, int close_on_exec) @@ -623,7 +627,7 @@ int os_create_unix_socket(char *file, int len, int close_on_exec) if(err < 0) return -errno; - return(sock); + return sock; } void os_flush_stdout(void) @@ -654,16 +658,5 @@ int os_lock_file(int fd, int excl) printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid); err = save; out: - return(err); + return err; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 6987d1d247a2..cd15b9df5b5c 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -42,7 +42,7 @@ static int helper_child(void *arg) if(data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); execvp(argv[0], argv); - errval = errno; + errval = -errno; printk("helper_child - execve of '%s' failed - errno = %d\n", argv[0], errno); os_write_file(data->fd, &errval, sizeof(errval)); kill(os_getpid(), SIGKILL); @@ -62,7 +62,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, stack = *stack_out; else stack = alloc_stack(0, __cant_sleep()); if(stack == 0) - return(-ENOMEM); + return -ENOMEM; ret = os_pipe(fds, 1, 0); if(ret < 0){ @@ -95,16 +95,16 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, /* Read the errno value from the child, if the exec failed, or get 0 if * the exec succeeded because the pipe fd was set as close-on-exec. */ n = os_read_file(fds[0], &ret, sizeof(ret)); - if (n < 0) { - printk("run_helper : read on pipe failed, ret = %d\n", -n); - ret = n; - kill(pid, SIGKILL); - CATCH_EINTR(waitpid(pid, NULL, 0)); - } else if(n != 0){ - CATCH_EINTR(n = waitpid(pid, NULL, 0)); - ret = -errno; - } else { + if(n == 0) ret = pid; + else { + if(n < 0){ + printk("run_helper : read on pipe failed, ret = %d\n", + -n); + ret = n; + kill(pid, SIGKILL); + } + CATCH_EINTR(waitpid(pid, NULL, 0)); } out_close: diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c index 3788d4568d33..a97206df5b52 100644 --- a/arch/um/os-Linux/irq.c +++ b/arch/um/os-Linux/irq.c @@ -52,11 +52,6 @@ int os_waiting_for_events(struct irq_fd *active_fds) return n; } -int os_isatty(int fd) -{ - return isatty(fd); -} - int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds) { if (pollfds_num == pollfds_size) { @@ -137,22 +132,19 @@ void os_set_pollfd(int i, int fd) void os_set_ioignore(void) { - set_handler(SIGIO, SIG_IGN, 0, -1); + signal(SIGIO, SIG_IGN); } void init_irq_signals(int on_sigstack) { - __sighandler_t h; int flags; flags = on_sigstack ? SA_ONSTACK : 0; - if (timer_irq_inited) - h = (__sighandler_t)alarm_handler; - else - h = boot_timer_handler; - set_handler(SIGVTALRM, h, flags | SA_RESTART, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); + set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, + flags | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); + set_handler(SIGALRM, (__sighandler_t) alarm_handler, + flags | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); signal(SIGWINCH, SIG_IGN); diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index 90912aaca7aa..d1c5670787dc 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -67,13 +67,32 @@ static __init void do_uml_initcalls(void) static void last_ditch_exit(int sig) { - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); uml_cleanup(); exit(1); } +static void install_fatal_handler(int sig) +{ + struct sigaction action; + + /* All signals are enabled in this handler ... */ + sigemptyset(&action.sa_mask); + + /* ... including the signal being handled, plus we want the + * handler reset to the default behavior, so that if an exit + * handler is hanging for some reason, the UML will just die + * after this signal is sent a second time. + */ + action.sa_flags = SA_RESETHAND | SA_NODEFER; + action.sa_restorer = NULL; + action.sa_handler = last_ditch_exit; + if(sigaction(sig, &action, NULL) < 0){ + printf("failed to install handler for signal %d - errno = %d\n", + errno); + exit(1); + } +} + #define UML_LIB_PATH ":/usr/lib/uml" static void setup_env_path(void) @@ -158,9 +177,12 @@ int main(int argc, char **argv, char **envp) } new_argv[argc] = NULL; - set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); - set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); - set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); + /* Allow these signals to bring down a UML if all other + * methods of control fail. + */ + install_fatal_handler(SIGINT); + install_fatal_handler(SIGTERM); + install_fatal_handler(SIGHUP); scan_elf_aux( envp); diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index c6432e729241..4203681e508d 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -55,7 +55,7 @@ static void __init find_tempdir(void) */ static int next(int fd, char *buf, int size, char c) { - int n; + int n, len; char *ptr; while((ptr = strchr(buf, c)) == NULL){ @@ -69,7 +69,17 @@ static int next(int fd, char *buf, int size, char c) } ptr++; - memmove(buf, ptr, strlen(ptr) + 1); + len = strlen(ptr); + memmove(buf, ptr, len + 1); + + /* Refill the buffer so that if there's a partial string that we care + * about, it will be completed, and we can recognize it. + */ + n = read(fd, &buf[len], size - len - 1); + if(n < 0) + return -errno; + + buf[len + n] = '\0'; return 1; } @@ -104,14 +114,14 @@ static void which_tmpdir(void) } while(1){ - found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' '); + found = next(fd, buf, ARRAY_SIZE(buf), ' '); if(found != 1) break; if(!strncmp(buf, "/dev/shm", strlen("/dev/shm"))) goto found; - found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), '\n'); + found = next(fd, buf, ARRAY_SIZE(buf), '\n'); if(found != 1) break; } @@ -122,20 +132,24 @@ err: else if(found < 0) printf("read returned errno %d\n", -found); +out: + close(fd); + return; found: - found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' '); + found = next(fd, buf, ARRAY_SIZE(buf), ' '); if(found != 1) goto err; if(strncmp(buf, "tmpfs", strlen("tmpfs"))){ printf("not tmpfs\n"); - return; + goto out; } printf("OK\n"); default_tmpdir = "/dev/shm"; + goto out; } /* @@ -200,8 +214,11 @@ int create_tmp_file(unsigned long long len) exit(1); } - if (lseek64(fd, len, SEEK_SET) < 0) { - perror("os_seek_file"); + /* Seek to len - 1 because writing a character there will + * increase the file size by one byte, to the desired length. + */ + if (lseek64(fd, len - 1, SEEK_SET) < 0) { + perror("os_seek_file"); exit(1); } diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 233be2f4f8cb..ff203625a4bd 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -7,7 +7,6 @@ #include <stdio.h> #include <errno.h> #include <signal.h> -#include <setjmp.h> #include <linux/unistd.h> #include <sys/mman.h> #include <sys/wait.h> @@ -247,39 +246,48 @@ void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) set_sigstack(sig_stack, pages * page_size()); flags = SA_ONSTACK; } - if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); + if(usr1_handler){ + struct sigaction sa; + + sa.sa_handler = usr1_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = flags; + sa.sa_restorer = NULL; + if(sigaction(SIGUSR1, &sa, NULL) < 0) + panic("init_new_thread_stack - sigaction failed - " + "errno = %d\n", errno); + } } -void init_new_thread_signals(int altstack) +void init_new_thread_signals(void) { - int flags = altstack ? SA_ONSTACK : 0; - - set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, + set_handler(SIGSEGV, (__sighandler_t) sig_handler, SA_ONSTACK, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, + set_handler(SIGTRAP, (__sighandler_t) sig_handler, SA_ONSTACK, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, + set_handler(SIGFPE, (__sighandler_t) sig_handler, SA_ONSTACK, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGILL, (__sighandler_t) sig_handler, flags, + set_handler(SIGILL, (__sighandler_t) sig_handler, SA_ONSTACK, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, + set_handler(SIGBUS, (__sighandler_t) sig_handler, SA_ONSTACK, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGUSR2, (__sighandler_t) sig_handler, - flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + SA_ONSTACK, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, + -1); signal(SIGHUP, SIG_IGN); - init_irq_signals(altstack); + init_irq_signals(1); } int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) { jmp_buf buf; - int n, enable; + int n; *jmp_ptr = &buf; - n = UML_SETJMP(&buf, enable); + n = UML_SETJMP(&buf); if(n != 0) - return(n); + return n; (*fn)(arg); - return(0); + return 0; } diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 00e9388e947a..f6457765b17d 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -43,17 +43,9 @@ struct pollfds { /* Protected by sigio_lock(). Used by the sigio thread, but the UML thread * synchronizes with it. */ -struct pollfds current_poll = { - .poll = NULL, - .size = 0, - .used = 0 -}; - -struct pollfds next_poll = { - .poll = NULL, - .size = 0, - .used = 0 -}; +static struct pollfds current_poll; +static struct pollfds next_poll; +static struct pollfds all_sigio_fds; static int write_sigio_thread(void *unused) { @@ -78,7 +70,8 @@ static int write_sigio_thread(void *unused) n = os_read_file(sigio_private[1], &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : " - "read failed, err = %d\n", -n); + "read on socket failed, " + "err = %d\n", -n); tmp = current_poll; current_poll = next_poll; next_poll = tmp; @@ -93,35 +86,36 @@ static int write_sigio_thread(void *unused) n = os_write_file(respond_fd, &c, sizeof(c)); if(n != sizeof(c)) - printk("write_sigio_thread : write failed, " - "err = %d\n", -n); + printk("write_sigio_thread : write on socket " + "failed, err = %d\n", -n); } } return 0; } -static int need_poll(int n) +static int need_poll(struct pollfds *polls, int n) { - if(n <= next_poll.size){ - next_poll.used = n; - return(0); + if(n <= polls->size){ + polls->used = n; + return 0; } - kfree(next_poll.poll); - next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); - if(next_poll.poll == NULL){ + kfree(polls->poll); + polls->poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); + if(polls->poll == NULL){ printk("need_poll : failed to allocate new pollfds\n"); - next_poll.size = 0; - next_poll.used = 0; - return(-1); + polls->size = 0; + polls->used = 0; + return -ENOMEM; } - next_poll.size = n; - next_poll.used = n; - return(0); + polls->size = n; + polls->used = n; + return 0; } /* Must be called with sigio_lock held, because it's needed by the marked - * critical section. */ + * critical section. + */ static void update_thread(void) { unsigned long flags; @@ -156,34 +150,39 @@ static void update_thread(void) set_signals(flags); } -int add_sigio_fd(int fd, int read) +int add_sigio_fd(int fd) { - int err = 0, i, n, events; + struct pollfd *p; + int err = 0, i, n; sigio_lock(); + for(i = 0; i < all_sigio_fds.used; i++){ + if(all_sigio_fds.poll[i].fd == fd) + break; + } + if(i == all_sigio_fds.used) + goto out; + + p = &all_sigio_fds.poll[i]; + for(i = 0; i < current_poll.used; i++){ if(current_poll.poll[i].fd == fd) goto out; } n = current_poll.used + 1; - err = need_poll(n); + err = need_poll(&next_poll, n); if(err) goto out; for(i = 0; i < current_poll.used; i++) next_poll.poll[i] = current_poll.poll[i]; - if(read) events = POLLIN; - else events = POLLOUT; - - next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd, - .events = events, - .revents = 0 }); + next_poll.poll[n - 1] = *p; update_thread(); out: sigio_unlock(); - return(err); + return err; } int ignore_sigio_fd(int fd) @@ -191,6 +190,13 @@ int ignore_sigio_fd(int fd) struct pollfd *p; int err = 0, i, n = 0; + /* This is called from exitcalls elsewhere in UML - if + * sigio_cleanup has already run, then update_thread will hang + * or fail because the thread is no longer running. + */ + if(write_sigio_pid == -1) + return -EIO; + sigio_lock(); for(i = 0; i < current_poll.used; i++){ if(current_poll.poll[i].fd == fd) break; @@ -198,24 +204,20 @@ int ignore_sigio_fd(int fd) if(i == current_poll.used) goto out; - err = need_poll(current_poll.used - 1); + err = need_poll(&next_poll, current_poll.used - 1); if(err) goto out; for(i = 0; i < current_poll.used; i++){ p = ¤t_poll.poll[i]; - if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i]; - } - if(n == i){ - printk("ignore_sigio_fd : fd %d not found\n", fd); - err = -1; - goto out; + if(p->fd != fd) + next_poll.poll[n++] = *p; } update_thread(); out: sigio_unlock(); - return(err); + return err; } static struct pollfd *setup_initial_poll(int fd) @@ -227,13 +229,13 @@ static struct pollfd *setup_initial_poll(int fd) printk("setup_initial_poll : failed to allocate poll\n"); return NULL; } - *p = ((struct pollfd) { .fd = fd, + *p = ((struct pollfd) { .fd = fd, .events = POLLIN, .revents = 0 }); return p; } -void write_sigio_workaround(void) +static void write_sigio_workaround(void) { unsigned long stack; struct pollfd *p; @@ -314,10 +316,38 @@ out_close1: close(l_write_sigio_fds[1]); } -void sigio_cleanup(void) +void maybe_sigio_broken(int fd, int read) +{ + int err; + + if(!isatty(fd)) + return; + + if((read || pty_output_sigio) && (!read || pty_close_sigio)) + return; + + write_sigio_workaround(); + + sigio_lock(); + err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); + if(err){ + printk("maybe_sigio_broken - failed to add pollfd\n"); + goto out; + } + all_sigio_fds.poll[all_sigio_fds.used++] = + ((struct pollfd) { .fd = fd, + .events = read ? POLLIN : POLLOUT, + .revents = 0 }); +out: + sigio_unlock(); +} + +static void sigio_cleanup(void) { if(write_sigio_pid != -1){ os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; } } + +__uml_exitcall(sigio_cleanup); diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index f11b3124a0c8..6b81739279d1 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -15,7 +15,6 @@ #include "user.h" #include "signal_kern.h" #include "sysdep/sigcontext.h" -#include "sysdep/signal.h" #include "sigcontext.h" #include "mode.h" #include "os.h" @@ -38,18 +37,10 @@ static int signals_enabled = 1; static int pending = 0; -void sig_handler(ARCH_SIGHDLR_PARAM) +void sig_handler(int sig, struct sigcontext *sc) { - struct sigcontext *sc; int enabled; - /* Must be the first thing that this handler does - x86_64 stores - * the sigcontext in %rdx, and we need to save it before it has a - * chance to get trashed. - */ - - ARCH_GET_SIGCONTEXT(sc, sig); - enabled = signals_enabled; if(!enabled && (sig == SIGIO)){ pending |= SIGIO_MASK; @@ -64,15 +55,8 @@ void sig_handler(ARCH_SIGHDLR_PARAM) set_signals(enabled); } -extern int timer_irq_inited; - static void real_alarm_handler(int sig, struct sigcontext *sc) { - if(!timer_irq_inited){ - signals_enabled = 1; - return; - } - if(sig == SIGALRM) switch_timers(0); @@ -84,13 +68,10 @@ static void real_alarm_handler(int sig, struct sigcontext *sc) } -void alarm_handler(ARCH_SIGHDLR_PARAM) +void alarm_handler(int sig, struct sigcontext *sc) { - struct sigcontext *sc; int enabled; - ARCH_GET_SIGCONTEXT(sc, sig); - enabled = signals_enabled; if(!signals_enabled){ if(sig == SIGVTALRM) @@ -106,29 +87,6 @@ void alarm_handler(ARCH_SIGHDLR_PARAM) set_signals(enabled); } -extern void do_boot_timer_handler(struct sigcontext * sc); - -void boot_timer_handler(ARCH_SIGHDLR_PARAM) -{ - struct sigcontext *sc; - int enabled; - - ARCH_GET_SIGCONTEXT(sc, sig); - - enabled = signals_enabled; - if(!enabled){ - if(sig == SIGVTALRM) - pending |= SIGVTALRM_MASK; - else pending |= SIGALRM_MASK; - return; - } - - block_signals(); - - do_boot_timer_handler(sc); - set_signals(enabled); -} - void set_sigstack(void *sig_stack, int size) { stack_t stack = ((stack_t) { .ss_flags = 0, @@ -149,6 +107,10 @@ void remove_sigstack(void) panic("disabling signal stack failed, errno = %d\n", errno); } +void (*handlers[_NSIG])(int sig, struct sigcontext *sc); + +extern void hard_handler(int sig); + void set_handler(int sig, void (*handler)(int), int flags, ...) { struct sigaction action; @@ -156,13 +118,16 @@ void set_handler(int sig, void (*handler)(int), int flags, ...) sigset_t sig_mask; int mask; - va_start(ap, flags); - action.sa_handler = handler; + handlers[sig] = (void (*)(int, struct sigcontext *)) handler; + action.sa_handler = hard_handler; + sigemptyset(&action.sa_mask); - while((mask = va_arg(ap, int)) != -1){ + + va_start(ap, flags); + while((mask = va_arg(ap, int)) != -1) sigaddset(&action.sa_mask, mask); - } va_end(ap); + action.sa_flags = flags; action.sa_restorer = NULL; if(sigaction(sig, &action, NULL) < 0) diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index bd89c6b99d5d..cb9ab54146cc 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -8,7 +8,6 @@ #include <unistd.h> #include <errno.h> #include <signal.h> -#include <setjmp.h> #include <sched.h> #include "ptrace_user.h" #include <sys/wait.h> @@ -156,11 +155,15 @@ extern int __syscall_stub_start; static int userspace_tramp(void *stack) { void *addr; + int err; ptrace(PTRACE_TRACEME, 0, 0, 0); - init_new_thread_signals(1); - enable_timer(); + init_new_thread_signals(); + err = set_interval(1); + if(err) + panic("userspace_tramp - setting timer failed, errno = %d\n", + err); if(!proc_mm){ /* This has a pte, but it can't be mapped in with the usual @@ -190,14 +193,25 @@ static int userspace_tramp(void *stack) } } if(!ptrace_faultinfo && (stack != NULL)){ + struct sigaction sa; + unsigned long v = UML_CONFIG_STUB_CODE + (unsigned long) stub_segv_handler - (unsigned long) &__syscall_stub_start; set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size()); - set_handler(SIGSEGV, (void *) v, SA_ONSTACK, - SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, - SIGUSR1, -1); + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGIO); + sigaddset(&sa.sa_mask, SIGWINCH); + sigaddset(&sa.sa_mask, SIGALRM); + sigaddset(&sa.sa_mask, SIGVTALRM); + sigaddset(&sa.sa_mask, SIGUSR1); + sa.sa_flags = SA_ONSTACK; + sa.sa_handler = (void *) v; + sa.sa_restorer = NULL; + if(sigaction(SIGSEGV, &sa, NULL) < 0) + panic("userspace_tramp - setting SIGSEGV handler " + "failed - errno = %d\n", errno); } os_stop_process(os_getpid()); @@ -430,59 +444,22 @@ void map_stub_pages(int fd, unsigned long code, } } -void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, - void (*handler)(int)) +void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) { - unsigned long flags; - jmp_buf switch_buf, fork_buf; - int enable; - - *switch_buf_ptr = &switch_buf; - *fork_buf_ptr = &fork_buf; - - /* Somewhat subtle - siglongjmp restores the signal mask before doing - * the longjmp. This means that when jumping from one stack to another - * when the target stack has interrupts enabled, an interrupt may occur - * on the source stack. This is bad when starting up a process because - * it's not supposed to get timer ticks until it has been scheduled. - * So, we disable interrupts around the sigsetjmp to ensure that - * they can't happen until we get back here where they are safe. - */ - flags = get_signals(); - block_signals(); - if(UML_SETJMP(&fork_buf, enable) == 0) - new_thread_proc(stack, handler); - - remove_sigstack(); - - set_signals(flags); + (*buf)[0].JB_IP = (unsigned long) handler; + (*buf)[0].JB_SP = (unsigned long) stack + + (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *); } #define INIT_JMP_NEW_THREAD 0 -#define INIT_JMP_REMOVE_SIGSTACK 1 -#define INIT_JMP_CALLBACK 2 -#define INIT_JMP_HALT 3 -#define INIT_JMP_REBOOT 4 +#define INIT_JMP_CALLBACK 1 +#define INIT_JMP_HALT 2 +#define INIT_JMP_REBOOT 3 -void thread_wait(void *sw, void *fb) +void switch_threads(jmp_buf *me, jmp_buf *you) { - jmp_buf buf, **switch_buf = sw, *fork_buf; - int enable; - - *switch_buf = &buf; - fork_buf = fb; - if(UML_SETJMP(&buf, enable) == 0) - siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK); -} - -void switch_threads(void *me, void *next) -{ - jmp_buf my_buf, **me_ptr = me, *next_buf = next; - int enable; - - *me_ptr = &my_buf; - if(UML_SETJMP(&my_buf, enable) == 0) - UML_LONGJMP(next_buf, 1); + if(UML_SETJMP(me) == 0) + UML_LONGJMP(you, 1); } static jmp_buf initial_jmpbuf; @@ -492,23 +469,21 @@ static void (*cb_proc)(void *arg); static void *cb_arg; static jmp_buf *cb_back; -int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) +int start_idle_thread(void *stack, jmp_buf *switch_buf) { - jmp_buf **switch_buf = switch_buf_ptr; - int n, enable; + int n; set_handler(SIGWINCH, (__sighandler_t) sig_handler, SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, SIGVTALRM, -1); - *fork_buf_ptr = &initial_jmpbuf; - n = UML_SETJMP(&initial_jmpbuf, enable); + n = UML_SETJMP(&initial_jmpbuf); switch(n){ case INIT_JMP_NEW_THREAD: - new_thread_proc((void *) stack, new_thread_handler); - break; - case INIT_JMP_REMOVE_SIGSTACK: - remove_sigstack(); + (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; + (*switch_buf)[0].JB_SP = (unsigned long) stack + + (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - + sizeof(void *); break; case INIT_JMP_CALLBACK: (*cb_proc)(cb_arg); @@ -523,20 +498,19 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) default: panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); } - UML_LONGJMP(*switch_buf, 1); + UML_LONGJMP(switch_buf, 1); } void initial_thread_cb_skas(void (*proc)(void *), void *arg) { jmp_buf here; - int enable; cb_proc = proc; cb_arg = arg; cb_back = &here; block_signals(); - if(UML_SETJMP(&here, enable) == 0) + if(UML_SETJMP(&here) == 0) UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK); unblock_signals(); diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 503148504009..7fe92680c7dd 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -14,7 +14,6 @@ #include <sched.h> #include <fcntl.h> #include <errno.h> -#include <setjmp.h> #include <sys/time.h> #include <sys/wait.h> #include <sys/mman.h> diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile index b3213613c41c..37806621b25d 100644 --- a/arch/um/os-Linux/sys-i386/Makefile +++ b/arch/um/os-Linux/sys-i386/Makefile @@ -3,7 +3,7 @@ # Licensed under the GPL # -obj-$(CONFIG_MODE_SKAS) = registers.o tls.o +obj-$(CONFIG_MODE_SKAS) = registers.o signal.o tls.o USER_OBJS := $(obj-y) diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c index 516f66dd87e3..7cd0369e02b3 100644 --- a/arch/um/os-Linux/sys-i386/registers.c +++ b/arch/um/os-Linux/sys-i386/registers.c @@ -5,12 +5,12 @@ #include <errno.h> #include <string.h> -#include <setjmp.h> #include "sysdep/ptrace_user.h" #include "sysdep/ptrace.h" #include "uml-config.h" #include "skas_ptregs.h" #include "registers.h" +#include "longjmp.h" #include "user.h" /* These are set once at boot time and not changed thereafter */ @@ -130,11 +130,14 @@ void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) HOST_FP_SIZE * sizeof(unsigned long)); } -void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) +unsigned long get_thread_reg(int reg, jmp_buf *buf) { - struct __jmp_buf_tag *jmpbuf = buffer; - - UPT_SET(uml_regs, EIP, jmpbuf->__jmpbuf[JB_PC]); - UPT_SET(uml_regs, UESP, jmpbuf->__jmpbuf[JB_SP]); - UPT_SET(uml_regs, EBP, jmpbuf->__jmpbuf[JB_BP]); + switch(reg){ + case EIP: return buf[0]->__eip; + case UESP: return buf[0]->__esp; + case EBP: return buf[0]->__ebp; + default: + printk("get_thread_regs - unknown register %d\n", reg); + return 0; + } } diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c new file mode 100644 index 000000000000..0d3eae518352 --- /dev/null +++ b/arch/um/os-Linux/sys-i386/signal.c @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include <signal.h> + +extern void (*handlers[])(int sig, struct sigcontext *sc); + +void hard_handler(int sig) +{ + struct sigcontext *sc = (struct sigcontext *) (&sig + 1); + + (*handlers[sig])(sig, sc); +} diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile index 340ef26f5944..f67842a7735b 100644 --- a/arch/um/os-Linux/sys-x86_64/Makefile +++ b/arch/um/os-Linux/sys-x86_64/Makefile @@ -3,7 +3,7 @@ # Licensed under the GPL # -obj-$(CONFIG_MODE_SKAS) = registers.o +obj-$(CONFIG_MODE_SKAS) = registers.o signal.o USER_OBJS := $(obj-y) diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c index becd898d9398..cb8e8a263280 100644 --- a/arch/um/os-Linux/sys-x86_64/registers.c +++ b/arch/um/os-Linux/sys-x86_64/registers.c @@ -5,11 +5,11 @@ #include <errno.h> #include <string.h> -#include <setjmp.h> #include "ptrace_user.h" #include "uml-config.h" #include "skas_ptregs.h" #include "registers.h" +#include "longjmp.h" #include "user.h" /* These are set once at boot time and not changed thereafter */ @@ -78,11 +78,14 @@ void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) HOST_FP_SIZE * sizeof(unsigned long)); } -void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) +unsigned long get_thread_reg(int reg, jmp_buf *buf) { - struct __jmp_buf_tag *jmpbuf = buffer; - - UPT_SET(uml_regs, RIP, jmpbuf->__jmpbuf[JB_PC]); - UPT_SET(uml_regs, RSP, jmpbuf->__jmpbuf[JB_RSP]); - UPT_SET(uml_regs, RBP, jmpbuf->__jmpbuf[JB_RBP]); + switch(reg){ + case RIP: return buf[0]->__rip; + case RSP: return buf[0]->__rsp; + case RBP: return buf[0]->__rbp; + default: + printk("get_thread_regs - unknown register %d\n", reg); + return 0; + } } diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c new file mode 100644 index 000000000000..3f369e5f976b --- /dev/null +++ b/arch/um/os-Linux/sys-x86_64/signal.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include <signal.h> + +extern void (*handlers[])(int sig, struct sigcontext *sc); + +void hard_handler(int sig) +{ + struct ucontext *uc; + asm("movq %%rdx, %0" : "=r" (uc)); + + (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext); +} diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index 280c4fb9b585..38be096e750f 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -17,25 +17,25 @@ #include "kern_constants.h" #include "os.h" -/* XXX This really needs to be declared and initialized in a kernel file since - * it's in <linux/time.h> - */ -extern struct timespec wall_to_monotonic; - -static void set_interval(int timer_type) +int set_interval(int is_virtual) { int usec = 1000000/hz(); + int timer_type = is_virtual ? ITIMER_VIRTUAL : ITIMER_REAL; struct itimerval interval = ((struct itimerval) { { 0, usec }, { 0, usec } }); if(setitimer(timer_type, &interval, NULL) == -1) - panic("setitimer failed - errno = %d\n", errno); + return -errno; + + return 0; } +#ifdef CONFIG_MODE_TT void enable_timer(void) { - set_interval(ITIMER_VIRTUAL); + set_interval(1); } +#endif void disable_timer(void) { @@ -45,8 +45,8 @@ void disable_timer(void) printk("disnable_timer - setitimer failed, errno = %d\n", errno); /* If there are signals already queued, after unblocking ignore them */ - set_handler(SIGALRM, SIG_IGN, 0, -1); - set_handler(SIGVTALRM, SIG_IGN, 0, -1); + signal(SIGALRM, SIG_IGN); + signal(SIGVTALRM, SIG_IGN); } void switch_timers(int to_real) @@ -71,6 +71,7 @@ void switch_timers(int to_real) errno); } +#ifdef UML_CONFIG_MODE_TT void uml_idle_timer(void) { if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) @@ -78,16 +79,9 @@ void uml_idle_timer(void) set_handler(SIGALRM, (__sighandler_t) alarm_handler, SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_interval(ITIMER_REAL); -} - -void time_init(void) -{ - if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) - panic("Couldn't set SIGVTALRM handler"); - set_interval(ITIMER_VIRTUAL); - time_init_kern(); + set_interval(0); } +#endif unsigned long long os_nsecs(void) { @@ -105,16 +99,3 @@ void idle_sleep(int secs) ts.tv_nsec = 0; nanosleep(&ts, NULL); } - -/* XXX This partly duplicates init_irq_signals */ - -void user_time_init(void) -{ - set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, - SIGALRM, SIGUSR2, -1); - set_handler(SIGALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, - SIGVTALRM, SIGUSR2, -1); - set_interval(ITIMER_VIRTUAL); -} diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c index 90b29ae9af46..1df231a26244 100644 --- a/arch/um/os-Linux/trap.c +++ b/arch/um/os-Linux/trap.c @@ -5,7 +5,6 @@ #include <stdlib.h> #include <signal.h> -#include <setjmp.h> #include "kern_util.h" #include "user_util.h" #include "os.h" diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c index e523719330b2..bbb73a650370 100644 --- a/arch/um/os-Linux/uaccess.c +++ b/arch/um/os-Linux/uaccess.c @@ -4,8 +4,7 @@ * Licensed under the GPL */ -#include <setjmp.h> -#include <string.h> +#include <stddef.h> #include "longjmp.h" unsigned long __do_user_copy(void *to, const void *from, int n, @@ -14,11 +13,10 @@ unsigned long __do_user_copy(void *to, const void *from, int n, int n), int *faulted_out) { unsigned long *faddrp = (unsigned long *) fault_addr, ret; - int enable; jmp_buf jbuf; *fault_catcher = &jbuf; - if(UML_SETJMP(&jbuf, enable) == 0){ + if(UML_SETJMP(&jbuf) == 0){ (*op)(to, from, n); ret = 0; *faulted_out = 0; diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index 362db059fe30..48092b95c8ab 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c @@ -67,32 +67,53 @@ err: return err; } -static int actually_do_remove(char *dir) +/* + * Unlinks the files contained in @dir and then removes @dir. + * Doesn't handle directory trees, so it's not like rm -rf, but almost such. We + * ignore ENOENT errors for anything (they happen, strangely enough - possibly due + * to races between multiple dying UML threads). + */ +static int remove_files_and_dir(char *dir) { DIR *directory; struct dirent *ent; int len; char file[256]; + int ret; directory = opendir(dir); - if(directory == NULL) - return -errno; + if (directory == NULL) { + if (errno != ENOENT) + return -errno; + else + return 0; + } - while((ent = readdir(directory)) != NULL){ - if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + while ((ent = readdir(directory)) != NULL) { + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1; - if(len > sizeof(file)) - return -E2BIG; + if (len > sizeof(file)) { + ret = -E2BIG; + goto out; + } sprintf(file, "%s/%s", dir, ent->d_name); - if(unlink(file) < 0) - return -errno; + if (unlink(file) < 0 && errno != ENOENT) { + ret = -errno; + goto out; + } } - if(rmdir(dir) < 0) - return -errno; - return 0; + if (rmdir(dir) < 0 && errno != ENOENT) { + ret = -errno; + goto out; + } + + ret = 0; +out: + closedir(directory); + return ret; } /* This says that there isn't already a user of the specified directory even if @@ -103,9 +124,10 @@ static int actually_do_remove(char *dir) * something other than UML sticking stuff in the directory * this boot racing with a shutdown of the other UML * In any of these cases, the directory isn't useful for anything else. + * + * Boolean return: 1 if in use, 0 otherwise. */ - -static int not_dead_yet(char *dir) +static inline int is_umdir_used(char *dir) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")], *end; @@ -113,7 +135,7 @@ static int not_dead_yet(char *dir) n = snprintf(file, sizeof(file), "%s/pid", dir); if(n >= sizeof(file)){ - printk("not_dead_yet - pid filename too long\n"); + printk("is_umdir_used - pid filename too long\n"); err = -E2BIG; goto out; } @@ -123,7 +145,7 @@ static int not_dead_yet(char *dir) if(fd < 0) { fd = -errno; if(fd != -ENOENT){ - printk("not_dead_yet : couldn't open pid file '%s', " + printk("is_umdir_used : couldn't open pid file '%s', " "err = %d\n", file, -fd); } goto out; @@ -132,18 +154,18 @@ static int not_dead_yet(char *dir) err = 0; n = read(fd, pid, sizeof(pid)); if(n < 0){ - printk("not_dead_yet : couldn't read pid file '%s', " + printk("is_umdir_used : couldn't read pid file '%s', " "err = %d\n", file, errno); goto out_close; } else if(n == 0){ - printk("not_dead_yet : couldn't read pid file '%s', " + printk("is_umdir_used : couldn't read pid file '%s', " "0-byte read\n", file); goto out_close; } p = strtoul(pid, &end, 0); if(end == pid){ - printk("not_dead_yet : couldn't parse pid file '%s', " + printk("is_umdir_used : couldn't parse pid file '%s', " "errno = %d\n", file, errno); goto out_close; } @@ -153,19 +175,32 @@ static int not_dead_yet(char *dir) return 1; } - err = actually_do_remove(dir); - if(err) - printk("not_dead_yet - actually_do_remove failed with " - "err = %d\n", err); - - return err; - out_close: close(fd); out: return 0; } +/* + * Try to remove the directory @dir unless it's in use. + * Precondition: @dir exists. + * Returns 0 for success, < 0 for failure in removal or if the directory is in + * use. + */ +static int umdir_take_if_dead(char *dir) +{ + int ret; + if (is_umdir_used(dir)) + return -EEXIST; + + ret = remove_files_and_dir(dir); + if (ret) { + printk("is_umdir_used - remove_files_and_dir failed with " + "err = %d\n", ret); + } + return ret; +} + static void __init create_pid_file(void) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; @@ -244,11 +279,7 @@ int __init make_umid(void) if(err != -EEXIST) goto err; - /* 1 -> this umid is already in use - * < 0 -> we couldn't remove the umid directory - * In either case, we can't use this umid, so return -EEXIST. - */ - if(not_dead_yet(tmp) != 0) + if (umdir_take_if_dead(tmp) < 0) goto err; err = mkdir(tmp, 0777); @@ -344,9 +375,9 @@ static void remove_umid_dir(void) char dir[strlen(uml_dir) + UMID_LEN + 1], err; sprintf(dir, "%s%s", uml_dir, umid); - err = actually_do_remove(dir); + err = remove_files_and_dir(dir); if(err) - printf("remove_umid_dir - actually_do_remove failed with " + printf("remove_umid_dir - remove_files_and_dir failed with " "err = %d\n", err); } diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index c47a2a7ce70e..3f5b1514e8a7 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -7,7 +7,6 @@ #include <stdlib.h> #include <unistd.h> #include <limits.h> -#include <setjmp.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/utsname.h> @@ -107,11 +106,11 @@ int setjmp_wrapper(void (*proc)(void *, void *), ...) jmp_buf buf; int n; - n = sigsetjmp(buf, 1); + n = UML_SETJMP(&buf); if(n == 0){ va_start(args, proc); (*proc)(&buf, &args); } va_end(args); - return(n); + return n; } diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 1347dc6d5218..813077fb1e5b 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -8,7 +8,7 @@ USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS:.o=.%): \ - c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(*F).o) + c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(basetarget).o) $(USER_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ -Dunix -D__unix__ -D__$(SUBARCH)__ @@ -17,7 +17,7 @@ $(USER_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ UNPROFILE_OBJS := $(foreach file,$(UNPROFILE_OBJS),$(obj)/$(file)) $(UNPROFILE_OBJS:.o=.%): \ - c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) $(CFLAGS_$(*F).o) + c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) $(CFLAGS_$(basetarget).o) $(UNPROFILE_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ -Dunix -D__unix__ -D__$(SUBARCH)__ diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 374d61a19439..0e32adf03be1 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,10 +1,10 @@ obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ - ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o \ + ptrace_user.o setjmp.o signal.o sigcontext.o syscalls.o sysrq.o \ sys_call_table.o tls.o obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o -subarch-obj-y = lib/bitops.o kernel/semaphore.o +subarch-obj-y = lib/bitops.o lib/semaphore.o subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o subarch-obj-$(CONFIG_MODULES) += kernel/module.o diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c index 41b0ab2fe830..f1bcd399ac90 100644 --- a/arch/um/sys-i386/bugs.c +++ b/arch/um/sys-i386/bugs.c @@ -13,6 +13,7 @@ #include "sysdep/ptrace.h" #include "task.h" #include "os.h" +#include "user_util.h" #define MAXTOKEN 64 @@ -104,17 +105,17 @@ int cpu_feature(char *what, char *buf, int len) static int check_cpu_flag(char *feature, int *have_it) { char buf[MAXTOKEN], c; - int fd, len = sizeof(buf)/sizeof(buf[0]); + int fd, len = ARRAY_SIZE(buf); printk("Checking for host processor %s support...", feature); fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); if(fd < 0){ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); - return(0); + return 0; } *have_it = 0; - if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0]))) + if(!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf))) goto out; c = token(fd, buf, len - 1, ' '); @@ -138,7 +139,7 @@ static int check_cpu_flag(char *feature, int *have_it) if(*have_it == 0) printk("No\n"); else if(*have_it == 1) printk("Yes\n"); os_close_file(fd); - return(1); + return 1; } #if 0 /* This doesn't work in tt mode, plus it's causing compilation problems diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S index d98b2fff3d08..62c7e564f22e 100644 --- a/arch/um/sys-i386/checksum.S +++ b/arch/um/sys-i386/checksum.S @@ -25,7 +25,6 @@ * 2 of the License, or (at your option) any later version. */ -#include <linux/config.h> #include <asm/errno.h> /* diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index fe0877b3509c..69971b78beaf 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -424,9 +424,8 @@ void ldt_get_host_info(void) size++; } - if(size < sizeof(dummy_list)/sizeof(dummy_list[0])) { + if(size < ARRAY_SIZE(dummy_list)) host_ldt_entries = dummy_list; - } else { size = (size + 1) * sizeof(dummy_list[0]); host_ldt_entries = (short *)kmalloc(size, GFP_KERNEL); diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index 6028bc7cc01b..28bf01150323 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include <linux/config.h> #include <linux/compiler.h> #include "linux/sched.h" #include "linux/mm.h" diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 40aa88531446..5f3cc6685820 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -15,6 +15,7 @@ #include "user.h" #include "os.h" #include "uml-config.h" +#include "user_util.h" int ptrace_getregs(long pid, unsigned long *regs_out) { @@ -51,7 +52,7 @@ static void write_debugregs(int pid, unsigned long *regs) int nregs, i; dummy = NULL; - nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); + nregs = ARRAY_SIZE(dummy->u_debugreg); for(i = 0; i < nregs; i++){ if((i == 4) || (i == 5)) continue; if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], @@ -68,7 +69,7 @@ static void read_debugregs(int pid, unsigned long *regs) int nregs, i; dummy = NULL; - nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); + nregs = ARRAY_SIZE(dummy->u_debugreg); for(i = 0; i < nregs; i++){ regs[i] = ptrace(PTRACE_PEEKUSR, pid, &dummy->u_debugreg[i], 0); diff --git a/arch/um/sys-i386/setjmp.S b/arch/um/sys-i386/setjmp.S new file mode 100644 index 000000000000..b766792c9933 --- /dev/null +++ b/arch/um/sys-i386/setjmp.S @@ -0,0 +1,58 @@ +# +# arch/i386/setjmp.S +# +# setjmp/longjmp for the i386 architecture +# + +# +# The jmp_buf is assumed to contain the following, in order: +# %ebx +# %esp +# %ebp +# %esi +# %edi +# <return address> +# + + .text + .align 4 + .globl setjmp + .type setjmp, @function +setjmp: +#ifdef _REGPARM + movl %eax,%edx +#else + movl 4(%esp),%edx +#endif + popl %ecx # Return address, and adjust the stack + xorl %eax,%eax # Return value + movl %ebx,(%edx) + movl %esp,4(%edx) # Post-return %esp! + pushl %ecx # Make the call/return stack happy + movl %ebp,8(%edx) + movl %esi,12(%edx) + movl %edi,16(%edx) + movl %ecx,20(%edx) # Return address + ret + + .size setjmp,.-setjmp + + .text + .align 4 + .globl longjmp + .type longjmp, @function +longjmp: +#ifdef _REGPARM + xchgl %eax,%edx +#else + movl 4(%esp),%edx # jmp_ptr address + movl 8(%esp),%eax # Return value +#endif + movl (%edx),%ebx + movl 4(%edx),%esp + movl 8(%edx),%ebp + movl 12(%edx),%esi + movl 16(%edx),%edi + jmp *20(%edx) + + .size longjmp,.-longjmp diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S index 1ff61474b25c..2497554b7b95 100644 --- a/arch/um/sys-i386/sys_call_table.S +++ b/arch/um/sys-i386/sys_call_table.S @@ -7,8 +7,6 @@ #define sys_vm86old sys_ni_syscall #define sys_vm86 sys_ni_syscall -#define sys_stime um_stime -#define sys_time um_time #define old_mmap old_mmap_i386 #include "../../i386/kernel/syscall_table.S" diff --git a/arch/um/sys-ppc/misc.S b/arch/um/sys-ppc/misc.S index f0c971db47e4..1364b7da578c 100644 --- a/arch/um/sys-ppc/misc.S +++ b/arch/um/sys-ppc/misc.S @@ -15,7 +15,6 @@ * */ -#include <linux/config.h> #include <asm/processor.h> #include "ppc_asm.h" diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index c19794d435d6..f41768b8e25e 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -5,8 +5,8 @@ # obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ - sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o ksyms.o \ - tls.o + setjmp.o sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o \ + ksyms.o tls.o obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o obj-$(CONFIG_MODULES) += um_module.o diff --git a/arch/um/sys-x86_64/setjmp.S b/arch/um/sys-x86_64/setjmp.S new file mode 100644 index 000000000000..45f547b4043e --- /dev/null +++ b/arch/um/sys-x86_64/setjmp.S @@ -0,0 +1,54 @@ +# +# arch/x86_64/setjmp.S +# +# setjmp/longjmp for the x86-64 architecture +# + +# +# The jmp_buf is assumed to contain the following, in order: +# %rbx +# %rsp (post-return) +# %rbp +# %r12 +# %r13 +# %r14 +# %r15 +# <return address> +# + + .text + .align 4 + .globl setjmp + .type setjmp, @function +setjmp: + pop %rsi # Return address, and adjust the stack + xorl %eax,%eax # Return value + movq %rbx,(%rdi) + movq %rsp,8(%rdi) # Post-return %rsp! + push %rsi # Make the call/return stack happy + movq %rbp,16(%rdi) + movq %r12,24(%rdi) + movq %r13,32(%rdi) + movq %r14,40(%rdi) + movq %r15,48(%rdi) + movq %rsi,56(%rdi) # Return address + ret + + .size setjmp,.-setjmp + + .text + .align 4 + .globl longjmp + .type longjmp, @function +longjmp: + movl %esi,%eax # Return value (int) + movq (%rdi),%rbx + movq 8(%rdi),%rsp + movq 16(%rdi),%rbp + movq 24(%rdi),%r12 + movq 32(%rdi),%r13 + movq 40(%rdi),%r14 + movq 48(%rdi),%r15 + jmp *56(%rdi) + + .size longjmp,.-longjmp diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c index 34b2e842864f..9e9ad72c2ba4 100644 --- a/arch/um/sys-x86_64/syscall_table.c +++ b/arch/um/sys-x86_64/syscall_table.c @@ -4,7 +4,6 @@ #include <linux/linkage.h> #include <linux/sys.h> #include <linux/cache.h> -#include <linux/config.h> #define __NO_STUBS @@ -20,12 +19,6 @@ /*#define sys_set_thread_area sys_ni_syscall #define sys_get_thread_area sys_ni_syscall*/ -/* For __NR_time. The x86-64 name hopefully will change from sys_time64 to - * sys_time (since the current situation is bogus). I've sent a patch to cleanup - * this. Remove below the obsoleted line. */ -#define sys_time64 um_time -#define sys_time um_time - /* On UML we call it this way ("old" means it's not mmap2) */ #define sys_mmap old_mmap /* On x86-64 sys_uname is actually sys_newuname plus a compatibility trick. |