From 47280afb780c9111c017cd2f0c6276635067ba6d Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sun, 17 Nov 2002 03:00:11 -0500 Subject: Moved the net changes to arch/um/drivers/Makefile into updates to a void a merge conflict. --- arch/um/drivers/Makefile | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index 2d1aad156a03..58bad64e54c0 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile @@ -5,23 +5,14 @@ CHAN_OBJS := chan_kern.o chan_user.o line.o -# This nonsense is due to kbuild. In the 2.4 build, I stick -lpcap in -# pcap-objs, and that is just included in the link command. The 2.5 kbuild -# filters out everything from pcap-objs which are not in the built-in.o -# dependencies, which are $(obj-y). So, -lpcap must be in $(obj-y), too. -# However, make magically expands -lfoo prerequisites into /usr/lib/libfoo.a -# file names. This causes the kbuild filtering to filter the -lpcap from -# pcap-objs, causing the link to fail. -# So, what this does is figure out by hand (crudely) what file -lpcap really -# is and just use it. - -PCAP = $(shell for f in echo {/lib,/usr/lib}/libpcap.a; do \ - [ -f $$f ] && echo $$f ; done | head -1) +# pcap is broken in 2.5 because kbuild doesn't allow pcap.a to be linked +# in to pcap.o slip-objs := slip_kern.o slip_user.o +slirp-objs := slirp_kern.o slirp_user.o daemon-objs := daemon_kern.o daemon_user.o mcast-objs := mcast_kern.o mcast_user.o -pcap-objs := pcap_kern.o pcap_user.o $(PCAP) +#pcap-objs := pcap_kern.o pcap_user.o $(PCAP) net-objs := net_kern.o net_user.o mconsole-objs := mconsole_kern.o mconsole_user.o hostaudio-objs := hostaudio_kern.o hostaudio_user.o @@ -34,9 +25,10 @@ export-objs := mconsole_kern.o obj-y = obj-$(CONFIG_SSL) += ssl.o obj-$(CONFIG_UML_NET_SLIP) += slip.o +obj-$(CONFIG_UML_NET_SLIRP) += slirp.o obj-$(CONFIG_UML_NET_DAEMON) += daemon.o obj-$(CONFIG_UML_NET_MCAST) += mcast.o -obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP) +#obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP) obj-$(CONFIG_UML_NET) += net.o obj-$(CONFIG_MCONSOLE) += mconsole.o obj-$(CONFIG_MMAPPER) += mmapper_kern.o @@ -50,8 +42,6 @@ obj-$(CONFIG_TTY_CHAN) += tty.o obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o obj-$(CONFIG_UML_WATCHDOG) += harddog.o -CFLAGS_pcap_user.o = -I/usr/include/pcap - obj-y += stdio_console.o $(CHAN_OBJS) USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs)) @@ -63,7 +53,7 @@ USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file)) include $(TOPDIR)/Rules.make $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< clean: -- cgit v1.2.3 From 5d61c16871912ceef4a2e35f2963a1d04b013a42 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sun, 17 Nov 2002 03:26:59 -0500 Subject: Merged the network fixes from the 2.4 pool. --- arch/um/Kconfig_net | 147 ++++++++++++++++++++++++++++++++++++++++++++ arch/um/drivers/net_kern.c | 111 +++++++++++++++++++-------------- arch/um/drivers/slip.h | 10 +-- arch/um/drivers/slip_kern.c | 9 ++- arch/um/drivers/slip_user.c | 106 ++++++++------------------------ arch/um/include/net_kern.h | 5 ++ arch/um/include/net_user.h | 5 ++ 7 files changed, 258 insertions(+), 135 deletions(-) diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig_net index ba311513abc3..443a74bd622d 100644 --- a/arch/um/Kconfig_net +++ b/arch/um/Kconfig_net @@ -5,30 +5,177 @@ menu "Network Devices" # UML virtual driver config UML_NET bool "Virtual network device" + help + While the User-Mode port cannot directly talk to any physical + hardware devices, this choice and the following transport options + provide one or more virtual network devices through which the UML + kernels can talk to each other, the host, and with the host's help, + machines on the outside world. + + For more information, including explanations of the networking and + sample configurations, see + . + + If you'd like to be able to enable networking in the User-Mode + linux environment, say Y; otherwise say N. Note that you must + enable at least one of the following transport options to actually + make use of UML networking. config UML_NET_ETHERTAP bool "Ethertap transport" depends on UML_NET + help + The Ethertap User-Mode Linux network transport allows a single + running UML to exchange packets with its host over one of the + host's Ethertap devices, such as /dev/tap0. Additional running + UMLs can use additional Ethertap devices, one per running UML. + While the UML believes it's on a (multi-device, broadcast) virtual + Ethernet network, it's in fact communicating over a point-to-point + link with the host. + + To use this, your host kernel must have support for Ethertap + devices. Also, if your host kernel is 2.4.x, it must have + CONFIG_NETLINK_DEV configured as Y or M. + + For more information, see + That site + has examples of the UML command line to use to enable Ethertap + networking. + + If you'd like to set up an IP network with the host and/or the + outside world, say Y to this, the Daemon Transport and/or the + Slip Transport. You'll need at least one of them, but may choose + more than one without conflict. If you don't need UML networking, + say N. config UML_NET_TUNTAP bool "TUN/TAP transport" depends on UML_NET + help + The UML TUN/TAP network transport allows a UML instance to exchange + packets with the host over a TUN/TAP device. This option will only + work with a 2.4 host, unless you've applied the TUN/TAP patch to + your 2.2 host kernel. + + To use this transport, your host kernel must have support for TUN/TAP + devices, either built-in or as a module. config UML_NET_SLIP bool "SLIP transport" depends on UML_NET + help + The slip User-Mode Linux network transport allows a running UML to + network with its host over a point-to-point link. Unlike Ethertap, + which can carry any Ethernet frame (and hence even non-IP packets), + the slip transport can only carry IP packets. + + To use this, your host must support slip devices. + + For more information, see + . That site + has examples of the UML command line to use to enable slip + networking, and details of a few quirks with it. + + The Ethertap Transport is preferred over slip because of its + limitations. If you prefer slip, however, say Y here. Otherwise + choose the Multicast transport (to network multiple UMLs on + multiple hosts), Ethertap (to network with the host and the + outside world), and/or the Daemon transport (to network multiple + UMLs on a single host). You may choose more than one without + conflict. If you don't need UML networking, say N. config UML_NET_DAEMON bool "Daemon transport" depends on UML_NET + help + This User-Mode Linux network transport allows one or more running + UMLs on a single host to communicate with each other, but not to + the host. + + To use this form of networking, you'll need to run the UML + networking daemon on the host. + + For more information, see + That site + has examples of the UML command line to use to enable Daemon + networking. + + If you'd like to set up a network with other UMLs on a single host, + say Y. If you need a network between UMLs on multiple physical + hosts, choose the Multicast Transport. To set up a network with + the host and/or other IP machines, say Y to the Ethertap or Slip + transports. You'll need at least one of them, but may choose + more than one without conflict. If you don't need UML networking, + say N. config UML_NET_MCAST bool "Multicast transport" depends on UML_NET + help + This Multicast User-Mode Linux network transport allows multiple + UMLs (even ones running on different host machines!) to talk to + each other over a virtual ethernet network. However, it requires + at least one UML with one of the other transports to act as a + bridge if any of them need to be able to talk to their hosts or any + other IP machines. + + To use this, your host kernel(s) must support IP Multicasting. + + For more information, see + That site + has examples of the UML command line to use to enable Multicast + networking, and notes about the security of this approach. + + If you need UMLs on multiple physical hosts to communicate as if + they shared an Ethernet network, say Y. If you need to communicate + with other IP machines, make sure you select one of the other + transports (possibly in addition to Multicast; they're not + exclusive). If you don't need to network UMLs say N to each of + the transports. config UML_NET_PCAP bool "pcap transport" depends on UML_NET + help + The pcap transport makes a pcap packet stream on the host look + like an ethernet device inside UML. This is useful for making + UML act as a network monitor for the host. You must have libcap + installed in order to build the pcap transport into UML. + + For more information, see + That site + has examples of the UML command line to use to enable this option. + + If you intend to use UML as a network monitor for the host, say + Y here. Otherwise, say N. + +config UML_NET_SLIRP + bool "SLiRP transport" + depends on UML_NET + help + The SLiRP User-Mode Linux network transport allows a running UML + to network by invoking a program that can handle SLIP encapsulated + packets. This is commonly (but not limited to) the application + known as SLiRP, a program that can re-socket IP packets back onto + the host on which it is run. Only IP packets are supported, + unlike other network transports that can handle all Ethernet + frames. In general, slirp allows the UML the same IP connectivity + to the outside world that the host user is permitted, and unlike + other transports, SLiRP works without the need of root level + privleges, setuid binaries, or SLIP devices on the host. This + also means not every type of connection is possible, but most + situations can be accomodated with carefully crafted slirp + commands that can be passed along as part of the network device's + setup string. The effect of this transport on the UML is similar + that of a host behind a firewall that masquerades all network + connections passing through it (but is less secure). + + To use this you should first have slirp compiled somewhere + accessible on the host, and have read its documentation. If you + don't need UML networking, say N. + + Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" + # Below are hardware-independent drivers mirrored from # drivers/net/Config.in. It would be nice if Linux diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index deef1a0a75e3..f6bda1b3b1fe 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -39,7 +39,6 @@ static int uml_net_rx(struct net_device *dev) /* If we can't allocate memory, try again next round. */ if ((skb = dev_alloc_skb(dev->mtu)) == NULL) { lp->stats.rx_dropped++; - reactivate_fd(lp->fd, UM_ETH_IRQ); return 0; } @@ -48,7 +47,6 @@ static int uml_net_rx(struct net_device *dev) skb->mac.raw = skb->data; pkt_len = (*lp->read)(lp->fd, &skb, lp); - reactivate_fd(lp->fd, UM_ETH_IRQ); if (pkt_len > 0) { skb_trim(skb, pkt_len); skb->protocol = (*lp->protocol)(skb); @@ -69,18 +67,22 @@ void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct uml_net_private *lp = dev->priv; int err; - if (netif_running(dev)) { - spin_lock(&lp->lock); - while((err = uml_net_rx(dev)) > 0) ; - if(err < 0) { - printk(KERN_ERR - "Device '%s' read returned %d, shutting it " - "down\n", dev->name, err); - dev->flags &= ~IFF_UP; - dev_close(dev); - } - spin_unlock(&lp->lock); + if(!netif_running(dev)) + return; + + spin_lock(&lp->lock); + while((err = uml_net_rx(dev)) > 0) ; + if(err < 0) { + printk(KERN_ERR + "Device '%s' read returned %d, shutting it down\n", + dev->name, err); + dev_close(dev); + goto out; } + reactivate_fd(lp->fd, UM_ETH_IRQ); + + out: + spin_unlock(&lp->lock); } static int uml_net_open(struct net_device *dev) @@ -250,6 +252,37 @@ void uml_net_user_timer_expire(unsigned long _conn) #endif } +/* + * default do nothing hard header packet routines for struct net_device init. + * real ethernet transports will overwrite with real routines. + */ +static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + return(0); /* no change */ +} + +static int uml_net_rebuild_header(struct sk_buff *skb) +{ + return(0); /* ignore */ +} + +static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh) +{ + return(-1); /* fail */ +} + +static void uml_net_header_cache_update(struct hh_cache *hh, + struct net_device *dev, unsigned char * haddr) +{ + /* ignore */ +} + +static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr) +{ + return(0); /* nothing */ +} + static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED; static struct list_head devices = LIST_HEAD_INIT(devices); @@ -261,21 +294,25 @@ static int eth_configure(int n, void *init, char *mac, struct uml_net_private *lp; int save, err, size; + size = transport->private_size + sizeof(struct uml_net_private) + + sizeof(((struct uml_net_private *) 0)->user); + device = kmalloc(sizeof(*device), GFP_KERNEL); if(device == NULL){ printk(KERN_ERR "eth_configure failed to allocate uml_net\n"); return(1); } + *device = ((struct uml_net) { .list = LIST_HEAD_INIT(device->list), + .dev = NULL, + .index = n, + .mac = { [ 0 ... 5 ] = 0 }, + .have_mac = 0 }); + spin_lock(&devices_lock); list_add(&device->list, &devices); spin_unlock(&devices_lock); - device->index = n; - - size = transport->private_size + sizeof(struct uml_net_private) + - sizeof(((struct uml_net_private *) 0)->user); - if(setup_etheraddr(mac, device->mac)) device->have_mac = 1; @@ -290,10 +327,18 @@ static int eth_configure(int n, void *init, char *mac, printk(KERN_ERR "eth_configure: failed to allocate device\n"); return(1); } + memset(dev, 0, sizeof(*dev) + size); + snprintf(dev->name, sizeof(dev->name), "eth%d", n); dev->priv = (void *) &dev[1]; device->dev = dev; + dev->hard_header = uml_net_hard_header; + dev->rebuild_header = uml_net_rebuild_header; + dev->hard_header_cache = uml_net_header_cache; + dev->header_cache_update= uml_net_header_cache_update; + dev->hard_header_parse = uml_net_header_parse; + (*transport->kern->init)(dev, init); dev->mtu = transport->user->max_packet; @@ -308,32 +353,6 @@ static int eth_configure(int n, void *init, char *mac, dev->do_ioctl = uml_net_ioctl; dev->watchdog_timeo = (HZ >> 1); dev->irq = UM_ETH_IRQ; - dev->init = NULL; - dev->master = NULL; - dev->neigh_setup = NULL; - dev->owner = NULL; - dev->state = 0; - dev->next_sched = 0; - dev->get_wireless_stats = 0; - dev->wireless_handlers = 0; - dev->gflags = 0; - dev->mc_list = NULL; - dev->mc_count = 0; - dev->promiscuity = 0; - dev->atalk_ptr = NULL; - dev->ip_ptr = NULL; - dev->dn_ptr = NULL; - dev->ip6_ptr = NULL; - dev->ec_ptr = NULL; - atomic_set(&dev->refcnt, 0); - dev->features = 0; - dev->uninit = NULL; - dev->destructor = NULL; - dev->set_config = NULL; - dev->accept_fastpath = 0; - dev->br_port = 0; - dev->mem_start = 0; - dev->mem_end = 0; rtnl_lock(); err = register_netdevice(dev); @@ -372,6 +391,7 @@ static int eth_configure(int n, void *init, char *mac, if(transport->user->init) (*transport->user->init)(&lp->user, dev); + if(device->have_mac) set_ether_mac(dev, device->mac); return(0); @@ -486,7 +506,6 @@ void register_transport(struct transport *new) kfree(init); } list_del(ð->list); - return; } } @@ -580,7 +599,7 @@ static int net_remove(char *str) int n; n = simple_strtoul(str, &end, 0); - if(*end != '\0') + if((*end != '\0') || (end == str)) return(-1); device = find_device(n); diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h index 6fe5588e8a21..495f2f1b1420 100644 --- a/arch/um/drivers/slip.h +++ b/arch/um/drivers/slip.h @@ -2,6 +2,9 @@ #define __UM_SLIP_H #define BUF_SIZE 1500 + /* two bytes each for a (pathological) max packet of escaped chars + * + * terminating END char + initial END char */ +#define ENC_BUF_SIZE (2 * BUF_SIZE + 2) struct slip_data { void *dev; @@ -9,10 +12,9 @@ struct slip_data { char *addr; char *gate_addr; int slave; - /* two bytes each for a (pathological) max packet of escaped chars + - * terminating END char + inital END char - */ - char buf[2 * BUF_SIZE + 2]; + char ibuf[ENC_BUF_SIZE]; + char obuf[ENC_BUF_SIZE]; + int more; /* more data: do not read fd until ibuf has been drained */ int pos; int esc; }; diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index 1ca56f563757..f498a83d9db5 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -1,3 +1,4 @@ +#include "linux/config.h" #include "linux/kernel.h" #include "linux/stddef.h" #include "linux/init.h" @@ -24,21 +25,19 @@ void slip_init(struct net_device *dev, void *data) { name : { '\0' }, addr: NULL, gate_addr : init->gate_addr, - slave : 0, - buf : { '\0' }, + slave : -1, + ibuf : { '\0' }, + obuf : { '\0' }, pos : 0, esc : 0, dev : dev }); - strncpy(dev->name, "umn", IFNAMSIZ); dev->init = NULL; dev->hard_header_len = 0; dev->addr_len = 4; dev->type = ARPHRD_ETHER; dev->tx_queue_len = 256; dev->flags = IFF_NOARP; - if(register_netdev(dev)) - printk(KERN_ERR "Couldn't initialize umn\n"); printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr); } diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index d8cd43c2f555..e36e8213671b 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -15,6 +15,7 @@ #include "user.h" #include "net_user.h" #include "slip.h" +#include "slip_proto.h" #include "helper.h" #include "os.h" @@ -66,7 +67,7 @@ static void slip_pre_exec(void *arg) if(data->stdin != -1) dup2(data->stdin, 0); dup2(data->stdout, 1); - close(data->close_me); + if(data->close_me != -1) close(data->close_me); } static int slip_tramp(char **argv, int fd) @@ -156,7 +157,7 @@ static int slip_open(void *data) } sencap = 0; if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){ - printk("Failed to sett slip encapsulation - " + printk("Failed to set slip encapsulation - " "errno = %d\n", errno); return(-errno); } @@ -186,103 +187,48 @@ static void slip_close(int fd, void *data) pri->slave = -1; } -/* SLIP protocol characters. */ -#define END 0300 /* indicates end of frame */ -#define ESC 0333 /* indicates byte stuffing */ -#define ESC_END 0334 /* ESC ESC_END means END 'data' */ -#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ - -static int slip_unesc(struct slip_data *sl, unsigned char c) -{ - int ret; - - switch(c){ - case END: - sl->esc = 0; - ret = sl->pos; - sl->pos = 0; - return(ret); - case ESC: - sl->esc = 1; - return(0); - case ESC_ESC: - if(sl->esc){ - sl->esc = 0; - c = ESC; - } - break; - case ESC_END: - if(sl->esc){ - sl->esc = 0; - c = END; - } - break; - } - sl->buf[sl->pos++] = c; - return(0); -} - int slip_user_read(int fd, void *buf, int len, struct slip_data *pri) { int i, n, size, start; - n = net_read(fd, &pri->buf[pri->pos], sizeof(pri->buf) - pri->pos); + if(pri->more>0) { + i = 0; + while(i < pri->more) { + size = slip_unesc(pri->ibuf[i++], + pri->ibuf, &pri->pos, &pri->esc); + if(size){ + memcpy(buf, pri->ibuf, size); + memmove(pri->ibuf, &pri->ibuf[i], pri->more-i); + pri->more=pri->more-i; + return(size); + } + } + pri->more=0; + } + + n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos); if(n <= 0) return(n); start = pri->pos; for(i = 0; i < n; i++){ - size = slip_unesc(pri, pri->buf[start + i]); + size = slip_unesc(pri->ibuf[start + i], + pri->ibuf, &pri->pos, &pri->esc); if(size){ - memcpy(buf, pri->buf, size); + memcpy(buf, pri->ibuf, size); + memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1)); + pri->more=n-(i+1); return(size); } } return(0); } -static int slip_esc(unsigned char *s, unsigned char *d, int len) -{ - unsigned char *ptr = d; - unsigned char c; - - /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. - */ - - *ptr++ = END; - - /* - * For each byte in the packet, send the appropriate - * character sequence, according to the SLIP protocol. - */ - - while (len-- > 0) { - switch(c = *s++) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; - } - } - *ptr++ = END; - return (ptr - d); -} - int slip_user_write(int fd, void *buf, int len, struct slip_data *pri) { int actual, n; - actual = slip_esc(buf, pri->buf, len); - n = net_write(fd, pri->buf, actual); + actual = slip_esc(buf, pri->obuf, len); + n = net_write(fd, pri->obuf, actual); if(n < 0) return(n); else return(len); } diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h index 22d43acb78f1..de793e9bf438 100644 --- a/arch/um/include/net_kern.h +++ b/arch/um/include/net_kern.h @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #ifndef __UM_NET_KERN_H #define __UM_NET_KERN_H diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h index 01867cae92e2..36807b796e9f 100644 --- a/arch/um/include/net_user.h +++ b/arch/um/include/net_user.h @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #ifndef __UM_NET_USER_H__ #define __UM_NET_USER_H__ -- cgit v1.2.3 From 26e8f3d297aead8a3dc137e5294780b6ea30203a Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sun, 17 Nov 2002 03:37:34 -0500 Subject: Copied in the new files for the slirp transport and slip cleanup. --- arch/um/drivers/slip_proto.h | 93 ++++++++++++++++++++ arch/um/drivers/slirp.h | 51 +++++++++++ arch/um/drivers/slirp_kern.c | 132 ++++++++++++++++++++++++++++ arch/um/drivers/slirp_user.c | 202 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 478 insertions(+) create mode 100644 arch/um/drivers/slip_proto.h create mode 100644 arch/um/drivers/slirp.h create mode 100644 arch/um/drivers/slirp_kern.c create mode 100644 arch/um/drivers/slirp_user.c diff --git a/arch/um/drivers/slip_proto.h b/arch/um/drivers/slip_proto.h new file mode 100644 index 000000000000..7206361ace45 --- /dev/null +++ b/arch/um/drivers/slip_proto.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __UM_SLIP_PROTO_H__ +#define __UM_SLIP_PROTO_H__ + +/* SLIP protocol characters. */ +#define SLIP_END 0300 /* indicates end of frame */ +#define SLIP_ESC 0333 /* indicates byte stuffing */ +#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + +static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc) +{ + int ret; + + switch(c){ + case SLIP_END: + *esc = 0; + ret=*pos; + *pos=0; + return(ret); + case SLIP_ESC: + *esc = 1; + return(0); + case SLIP_ESC_ESC: + if(*esc){ + *esc = 0; + c = SLIP_ESC; + } + break; + case SLIP_ESC_END: + if(*esc){ + *esc = 0; + c = SLIP_END; + } + break; + } + buf[(*pos)++] = c; + return(0); +} + +static inline int slip_esc(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = SLIP_END; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while (len-- > 0) { + switch(c = *s++) { + case SLIP_END: + *ptr++ = SLIP_ESC; + *ptr++ = SLIP_ESC_END; + break; + case SLIP_ESC: + *ptr++ = SLIP_ESC; + *ptr++ = SLIP_ESC_ESC; + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = SLIP_END; + return (ptr - d); +} + +#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/drivers/slirp.h b/arch/um/drivers/slirp.h new file mode 100644 index 000000000000..04e407d1e44a --- /dev/null +++ b/arch/um/drivers/slirp.h @@ -0,0 +1,51 @@ +#ifndef __UM_SLIRP_H +#define __UM_SLIRP_H + +#define BUF_SIZE 1500 + /* two bytes each for a (pathological) max packet of escaped chars + * + * terminating END char + initial END char */ +#define ENC_BUF_SIZE (2 * BUF_SIZE + 2) + +#define SLIRP_MAX_ARGS 100 +/* + * XXX this next definition is here because I don't understand why this + * initializer doesn't work in slirp_kern.c: + * + * argv : { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] }, + * + * or why I can't typecast like this: + * + * argv : (char* [SLIRP_MAX_ARGS])(init->argv), + */ +struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; }; + +struct slirp_data { + void *dev; + struct arg_list_dummy_wrapper argw; + int pid; + int slave; + char ibuf[ENC_BUF_SIZE]; + char obuf[ENC_BUF_SIZE]; + int more; /* more data: do not read fd until ibuf has been drained */ + int pos; + int esc; +}; + +extern struct net_user_info slirp_user_info; + +extern int set_umn_addr(int fd, char *addr, char *ptp_addr); +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, struct slirp_data *pri); + +#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/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c new file mode 100644 index 000000000000..1a459dd94d76 --- /dev/null +++ b/arch/um/drivers/slirp_kern.c @@ -0,0 +1,132 @@ +#include "linux/kernel.h" +#include "linux/stddef.h" +#include "linux/init.h" +#include "linux/netdevice.h" +#include "linux/if_arp.h" +#include "net_kern.h" +#include "net_user.h" +#include "kern.h" +#include "slirp.h" + +struct slirp_init { + struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */ +}; + +void slirp_init(struct net_device *dev, void *data) +{ + struct uml_net_private *private; + struct slirp_data *spri; + struct slirp_init *init = data; + int i; + + private = dev->priv; + spri = (struct slirp_data *) private->user; + *spri = ((struct slirp_data) + { argw : init->argw, + pid : -1, + slave : -1, + ibuf : { '\0' }, + obuf : { '\0' }, + pos : 0, + esc : 0, + dev : dev }); + + dev->init = NULL; + dev->hard_header_len = 0; + dev->addr_len = 4; + dev->type = ARPHRD_ETHER; + dev->tx_queue_len = 256; + dev->flags = IFF_NOARP; + printk("SLIRP backend - command line:"); + for(i=0;spri->argw.argv[i]!=NULL;i++) { + printk(" '%s'",spri->argw.argv[i]); + } + printk("\n"); +} + +static unsigned short slirp_protocol(struct sk_buff *skbuff) +{ + return(htons(ETH_P_IP)); +} + +static int slirp_read(int fd, struct sk_buff **skb, + struct uml_net_private *lp) +{ + return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, + (struct slirp_data *) &lp->user)); +} + +static int slirp_write(int fd, struct sk_buff **skb, + struct uml_net_private *lp) +{ + return(slirp_user_write(fd, (*skb)->data, (*skb)->len, + (struct slirp_data *) &lp->user)); +} + +struct net_kern_info slirp_kern_info = { + init: slirp_init, + protocol: slirp_protocol, + read: slirp_read, + write: slirp_write, +}; + +static int slirp_setup(char *str, char **mac_out, void *data) +{ + struct slirp_init *init = data; + int i=0; + + *init = ((struct slirp_init) + { argw : { { "slirp", NULL } } }); + + str = split_if_spec(str, mac_out, NULL); + + if(str == NULL) { /* no command line given after MAC addr */ + return(1); + } + + do { + if(i>=SLIRP_MAX_ARGS-1) { + printk("slirp_setup: truncating slirp arguments\n"); + break; + } + init->argw.argv[i++] = str; + while(*str && *str!=',') { + if(*str=='_') *str=' '; + str++; + } + if(*str!=',') + break; + *str++='\0'; + } while(1); + init->argw.argv[i]=NULL; + return(1); +} + +static struct transport slirp_transport = { + list : LIST_HEAD_INIT(slirp_transport.list), + name : "slirp", + setup : slirp_setup, + user : &slirp_user_info, + kern : &slirp_kern_info, + private_size : sizeof(struct slirp_data), + setup_size : sizeof(struct slirp_init), +}; + +static int register_slirp(void) +{ + register_transport(&slirp_transport); + return(1); +} + +__initcall(register_slirp); + +/* + * 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/slirp_user.c b/arch/um/drivers/slirp_user.c new file mode 100644 index 000000000000..bba76df0f33d --- /dev/null +++ b/arch/um/drivers/slirp_user.c @@ -0,0 +1,202 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "net_user.h" +#include "slirp.h" +#include "slip_proto.h" +#include "helper.h" +#include "os.h" + +void slirp_user_init(void *data, void *dev) +{ + struct slirp_data *pri = data; + + pri->dev = dev; +} + +struct slirp_pre_exec_data { + int stdin; + int stdout; +}; + +static void slirp_pre_exec(void *arg) +{ + struct slirp_pre_exec_data *data = arg; + + if(data->stdin != -1) dup2(data->stdin, 0); + if(data->stdout != -1) dup2(data->stdout, 1); +} + +static int slirp_tramp(char **argv, int fd) +{ + struct slirp_pre_exec_data pe_data; + int pid; + + pe_data.stdin = fd; + pe_data.stdout = fd; + pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL); + + return(pid); +} + +static int slirp_datachan(int *mfd, int *sfd) +{ + int fds[2], err; + + err = os_pipe(fds, 1, 1); + if(err){ + printk("slirp_datachan: Failed to open pipe, errno = %d\n", + -err); + return(err); + } + + *mfd = fds[0]; + *sfd = fds[1]; + return(0); +} + +static int slirp_open(void *data) +{ + struct slirp_data *pri = data; + int sfd, mfd, pid, err; + + err = slirp_datachan(&mfd, &sfd); + if(err) + return(err); + + pid = slirp_tramp(pri->argw.argv, sfd); + + if(pid < 0){ + printk("slirp_tramp failed - errno = %d\n", pid); + os_close_file(sfd); + os_close_file(mfd); + return(pid); + } + + pri->slave = sfd; + pri->pos = 0; + pri->esc = 0; + + pri->pid = pid; + + return(mfd); +} + +static void slirp_close(int fd, void *data) +{ + struct slirp_data *pri = data; + int status,err; + + close(fd); + close(pri->slave); + + pri->slave = -1; + + if(pri->pid<1) { + printk("slirp_close: no child process to shut down\n"); + return; + } + +#if 0 + if(kill(pri->pid, SIGHUP)<0) { + printk("slirp_close: sending hangup to %d failed (%d)\n", + pri->pid, errno); + } +#endif + + err = waitpid(pri->pid, &status, WNOHANG); + if(err<0) { + printk("slirp_close: waitpid returned %d\n", errno); + return; + } + + if(err==0) { + printk("slirp_close: process %d has not exited\n"); + return; + } + + pri->pid = -1; +} + +int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri) +{ + int i, n, size, start; + + if(pri->more>0) { + i = 0; + while(i < pri->more) { + size = slip_unesc(pri->ibuf[i++], + pri->ibuf,&pri->pos,&pri->esc); + if(size){ + memcpy(buf, pri->ibuf, size); + memmove(pri->ibuf, &pri->ibuf[i], pri->more-i); + pri->more=pri->more-i; + return(size); + } + } + pri->more=0; + } + + n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos); + if(n <= 0) return(n); + + start = pri->pos; + for(i = 0; i < n; i++){ + size = slip_unesc(pri->ibuf[start + i], + pri->ibuf,&pri->pos,&pri->esc); + if(size){ + memcpy(buf, pri->ibuf, size); + memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1)); + pri->more=n-(i+1); + return(size); + } + } + return(0); +} + +int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri) +{ + int actual, n; + + actual = slip_esc(buf, pri->obuf, len); + n = net_write(fd, pri->obuf, actual); + if(n < 0) return(n); + else return(len); +} + +static int slirp_set_mtu(int mtu, void *data) +{ + return(mtu); +} + +struct net_user_info slirp_user_info = { + init: slirp_user_init, + open: slirp_open, + close: slirp_close, + remove: NULL, + set_mtu: slirp_set_mtu, + add_address: NULL, + delete_address: NULL, + max_packet: BUF_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: + */ -- cgit v1.2.3 From 7aa67c91df62143f332423fbee581b35d386bbb7 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sun, 17 Nov 2002 05:36:15 -0500 Subject: Merged the help text from the 2.4 Configure.help. --- arch/um/Kconfig | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ arch/um/Kconfig_block | 34 ++++++++++++++++++++ arch/um/Kconfig_char | 76 +++++++++++++++++++++++++++++++++++++++++-- arch/um/config_block.in | 16 ---------- arch/um/config_char.in | 37 --------------------- arch/um/config_net.in | 46 -------------------------- arch/um/config_scsi.in | 30 ----------------- 7 files changed, 192 insertions(+), 132 deletions(-) delete mode 100644 arch/um/config_block.in delete mode 100644 arch/um/config_char.in delete mode 100644 arch/um/config_net.in delete mode 100644 arch/um/config_scsi.in diff --git a/arch/um/Kconfig b/arch/um/Kconfig index f7e8005ebf38..7ec20e05959b 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -64,9 +64,41 @@ config BINFMT_MISC config HOSTFS tristate "Host filesystem" + help + While the User-Mode Linux port uses its own root file system for + booting and normal file access, this module lets the UML user + access files stored on the host. It does not require any + network connection between the Host and UML. An example use of + this might be: + + mount none /tmp/fromhost -t hostfs -o /tmp/umlshare + + where /tmp/fromhost is an empty directory inside UML and + /tmp/umlshare is a directory on the host with files the UML user + wishes to access. + + For more information, see + . + + If you'd like to be able to work with files stored on the host, + say Y or M here; otherwise say N. + config MCONSOLE bool "Management console" + help + The user mode linux management console is a low-level interface to + the kernel, somewhat like the i386 SysRq interface. Since there is + a full-blown operating system running under every user mode linux + instance, there is much greater flexibility possible than with the + SysRq mechanism. + + If you answer 'Y' to this option, to use this feature, you need the + mconsole client (called uml_mconsole) which is present in CVS in + 2.4.5-9um and later (path /tools/mconsole), and is also in the + distribution RPM package in 2.4.6 and later. + + It is safe to say 'Y' here. config MAGIC_SYSRQ bool "Magic SysRq key" @@ -77,6 +109,16 @@ config HOST_2G_2G config UML_SMP bool "Symmetric multi-processing support" + help + This option enables UML SMP support. UML implements virtual SMP by + allowing as many processes to run simultaneously on the host as + there are virtual processors configured. Obviously, if the host is + a uniprocessor, those processes will timeshare, but, inside UML, + will appear to be running simultaneously. If the host is a + multiprocessor, then UML processes may run simultaneously, depending + on the host scheduler. + CONFIG_SMP will be set to whatever this option is set to. + It is safe to leave this unchanged. config SMP bool @@ -90,10 +132,27 @@ config NR_CPUS config NEST_LEVEL int "Nesting level" default "0" + help + This is set to the number of layers of UMLs that this UML will be run + in. Normally, this is zero, meaning that it will run directly on the + host. Setting it to one will build a UML that can run inside a UML + that is running on the host. Generally, if you intend this UML to run + inside another UML, set CONFIG_NEST_LEVEL to one more than the host + UML. + + Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to + greater than one, then the guest UML should have its CONFIG_NEST_LEVEL + set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS. + Only change this if you are running nested UMLs. config KERNEL_HALF_GIGS int "Kernel address space size (in .5G units)" default "1" + help + This determines the amount of address space that UML will allocate for + its own, measured in half Gigabyte units. The default is 1. + Change this only if you need to boot UML with an unusually large amount + of physical memory. config HIGHMEM bool "Highmem support" @@ -156,6 +215,14 @@ config DEBUG_SLAB config DEBUGSYM bool "Enable kernel debugging symbols" + help + When this is enabled, the User-Mode Linux binary will include + debugging symbols. This enlarges the binary by a few megabytes, + but aids in tracking down kernel problems in UML. It is required + if you intend to do any kernel development. + + If you're truly short on disk space or don't expect to report any + bugs back to the UML developers, say N, otherwise say Y. config PT_PROXY bool "Enable ptrace proxy" @@ -164,10 +231,28 @@ config PT_PROXY config GPROF bool "Enable gprof support" depends on DEBUGSYM + help + This allows profiling of a User-Mode Linux kernel with the gprof + utility. + + See for more + details. + + If you're involved in UML kernel development and want to use gprof, + say Y. If you're unsure, say N. config GCOV bool "Enable gcov support" depends on DEBUGSYM + help + This option allows developers to retrieve coverage data from a UML + session. + + See for more + details. + + If you're involved in UML kernel development and want to use gcov, + say Y. If you're unsure, say N. endmenu diff --git a/arch/um/Kconfig_block b/arch/um/Kconfig_block index 542627172e92..fba53d9bb983 100644 --- a/arch/um/Kconfig_block +++ b/arch/um/Kconfig_block @@ -3,10 +3,31 @@ menu "Block Devices" config BLK_DEV_UBD bool "Virtual block device" + help + The User-Mode Linux port includes a driver called UBD which will let + you access arbitrary files on the host computer as block devices. + Unless you know that you do not need such virtual block devices say + Y here. config BLK_DEV_UBD_SYNC bool "Always do synchronous disk IO for UBD" depends on BLK_DEV_UBD + help + Writes to the virtual block device are not immediately written to the + host's disk; this may cause problems if, for example, the + User-Mode Linux 'Virtual Machine' uses a journalling filesystem and + the host computer crashes. + + Synchronous operation (i.e. always writing data to the host's disk + immediately) is configurable on a per-UBD basis by using a special + kernel command line option. Alternatively, you can say Y here to + turn on synchronous operation by default for all block devices. + + If you're running a journalling file system (like reiserfs, for + example) in your virtual machine, you will want to say Y here. If + you care for the safety of the data in your virtual machine, Y is a + wise choice too. In all other cases (for example, if you're just + playing around with User-Mode Linux) you can choose N. config BLK_DEV_LOOP tristate "Loopback device support" @@ -29,6 +50,19 @@ config BLK_DEV_INITRD config MMAPPER tristate "Example IO memory driver" + help + The User-Mode Linux port can provide support for IO Memory + emulation with this option. This allows a host file to be + specified as an I/O region on the kernel command line. That file + will be mapped into UML's kernel address space where a driver can + locate it and do whatever it wants with the memory, including + providing an interface to it for UML processes to use. + + For more information, see + . + + If you'd like to be able to provide a simulated IO port space for + User-Mode Linux processes, say Y. If unsure, say N. endmenu diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig_char index 8a3367c10310..a21cbbc7efde 100644 --- a/arch/um/Kconfig_char +++ b/arch/um/Kconfig_char @@ -7,36 +7,104 @@ config STDIO_CONSOLE config SSL bool "Virtual serial line" + help + The User-Mode Linux environment allows you to create virtual serial + lines on the UML that are usually made to show up on the host as + ttys or ptys. + + See for more + information and command line examples of how to use this facility. + + Unless you have a specific reason for disabling this, say Y. config FD_CHAN bool "file descriptor channel support" + help + This option enables support for attaching UML consoles and serial + lines to already set up file descriptors. Generally, the main + console is attached to file descriptors 0 and 1 (stdin and stdout), + so it would be wise to leave this enabled unless you intend to + attach it to some other host device. config NULL_CHAN bool "null channel support" + help + This option enables support for attaching UML consoles and serial + lines to a device similar to /dev/null. Data written to it disappears + and there is never any data to be read. config PORT_CHAN bool "port channel support" + help + This option enables support for attaching UML consoles and serial + lines to host portals. They may be accessed with 'telnet + '. Any number of consoles and serial lines may be + attached to a single portal, although what UML device you get when + you telnet to that portal will be unpredictable. + It is safe to say 'Y' here. config PTY_CHAN bool "pty channel support" + help + This option enables support for attaching UML consoles and serial + lines to host pseudo-terminals. Access to both traditional + pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled + with this option. The assignment of UML devices to host devices + will be announced in the kernel message log. + It is safe to say 'Y' here. config TTY_CHAN bool "tty channel support" + help + This option enables support for attaching UML consoles and serial + lines to host terminals. Access to both virtual consoles + (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and + /dev/pts/*) are controlled by this option. + It is safe to say 'Y' here. config XTERM_CHAN bool "xterm channel support" + help + This option enables support for attaching UML consoles and serial + lines to xterms. Each UML device so assigned will be brought up in + its own xterm. + If you disable this option, then CONFIG_PT_PROXY will be disabled as + well, since UML's gdb currently requires an xterm. + It is safe to say 'Y' here. config CON_ZERO_CHAN string "Default main console channel initialization" default "fd:0,fd:1" + help + This is the string describing the channel to which the main console + will be attached by default. This value can be overridden from the + command line. The default value is "fd:0,fd:1", which attaches the + main console to stdin and stdout. + It is safe to leave this unchanged. config CON_CHAN string "Default console channel initialization" default "xterm" + help + This is the string describing the channel to which all consoles + except the main console will be attached by default. This value can + be overridden from the command line. The default value is "xterm", + which brings them up in xterms. + It is safe to leave this unchanged, although you may wish to change + this if you expect the UML that you build to be run in environments + which don't have X or xterm available. config SSL_CHAN string "Default serial line channel initialization" default "pty" + help + This is the string describing the channel to which the serial lines + will be attached by default. This value can be overridden from the + command line. The default value is "pty", which attaches them to + traditional pseudo-terminals. + It is safe to leave this unchanged, although you may wish to change + this if you expect the UML that you build to be run in environments + which don't have a set of /dev/pty* devices. config UNIX98_PTYS bool "Unix98 PTY support" @@ -63,6 +131,11 @@ config UML_WATCHDOG config UML_SOUND tristate "Sound support" + help + This option enables UML sound support. If enabled, it will pull in + soundcore and the UML hostaudio relay, which acts as a intermediary + between the host's dsp and mixer devices and the UML sound system. + It is safe to say 'Y' here. config SOUND tristate @@ -72,8 +145,5 @@ config HOSTAUDIO tristate default UML_SOUND -config TTY_LOG - bool "Enable tty logging" - endmenu diff --git a/arch/um/config_block.in b/arch/um/config_block.in deleted file mode 100644 index 419bb713354a..000000000000 --- a/arch/um/config_block.in +++ /dev/null @@ -1,16 +0,0 @@ -mainmenu_option next_comment -comment 'Block Devices' - -bool 'Virtual block device' CONFIG_BLK_DEV_UBD -dep_bool ' Always do synchronous disk IO for UBD' CONFIG_BLK_DEV_UBD_SYNC $CONFIG_BLK_DEV_UBD -tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP -dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET -tristate 'RAM disk support' CONFIG_BLK_DEV_RAM -if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then - int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 -fi -dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM - -tristate 'Example IO memory driver' CONFIG_MMAPPER - -endmenu diff --git a/arch/um/config_char.in b/arch/um/config_char.in deleted file mode 100644 index dfb87d66b8de..000000000000 --- a/arch/um/config_char.in +++ /dev/null @@ -1,37 +0,0 @@ -mainmenu_option next_comment -comment 'Character Devices' - -define_bool CONFIG_STDIO_CONSOLE y - -bool 'Virtual serial line' CONFIG_SSL - -bool 'file descriptor channel support' CONFIG_FD_CHAN -bool 'null channel support' CONFIG_NULL_CHAN -bool 'port channel support' CONFIG_PORT_CHAN -bool 'pty channel support' CONFIG_PTY_CHAN -bool 'tty channel support' CONFIG_TTY_CHAN -bool 'xterm channel support' CONFIG_XTERM_CHAN -string 'Default main console channel initialization' CONFIG_CON_ZERO_CHAN \ - "fd:0,fd:1" -string 'Default console channel initialization' CONFIG_CON_CHAN "xterm" -string 'Default serial line channel initialization' CONFIG_SSL_CHAN "pty" - - -bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS -if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 -fi - -bool 'Watchdog Timer Support' CONFIG_WATCHDOG -dep_bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT \ - $CONFIG_WATCHDOG -dep_tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG $CONFIG_WATCHDOG -dep_tristate ' UML watchdog' CONFIG_UML_WATCHDOG $CONFIG_WATCHDOG - -tristate 'Sound support' CONFIG_UML_SOUND -define_tristate CONFIG_SOUND $CONFIG_UML_SOUND -define_tristate CONFIG_HOSTAUDIO $CONFIG_UML_SOUND - -bool 'Enable tty logging' CONFIG_TTY_LOG - -endmenu diff --git a/arch/um/config_net.in b/arch/um/config_net.in deleted file mode 100644 index f1f6a6e9b13f..000000000000 --- a/arch/um/config_net.in +++ /dev/null @@ -1,46 +0,0 @@ -mainmenu_option next_comment -comment 'Network Devices' - -# UML virtual driver -bool 'Virtual network device' CONFIG_UML_NET - -dep_bool ' Ethertap transport' CONFIG_UML_NET_ETHERTAP $CONFIG_UML_NET -dep_bool ' TUN/TAP transport' CONFIG_UML_NET_TUNTAP $CONFIG_UML_NET -dep_bool ' SLIP transport' CONFIG_UML_NET_SLIP $CONFIG_UML_NET -dep_bool ' Daemon transport' CONFIG_UML_NET_DAEMON $CONFIG_UML_NET -dep_bool ' Multicast transport' CONFIG_UML_NET_MCAST $CONFIG_UML_NET -dep_bool ' pcap transport' CONFIG_UML_NET_PCAP $CONFIG_UML_NET - -# Below are hardware-independent drivers mirrored from -# drivers/net/Config.in. It would be nice if Linux -# had HW independent drivers separated from the other -# but it does not. Until then each non-ISA/PCI arch -# needs to provide it's own menu of network drivers - -tristate 'Dummy net driver support' CONFIG_DUMMY -tristate 'Bonding driver support' CONFIG_BONDING -tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER -tristate 'Universal TUN/TAP device driver support' CONFIG_TUN -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_NETLINK" = "y" ]; then - tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP - fi -fi - -tristate 'PPP (point-to-point protocol) support' CONFIG_PPP -if [ ! "$CONFIG_PPP" = "n" ]; then - dep_bool ' PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL - dep_bool ' PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER - dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP - dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP - dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP - dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP - dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP $CONFIG_EXPERIMENTAL -fi - -tristate 'SLIP (serial line) support' CONFIG_SLIP -dep_bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED $CONFIG_SLIP -dep_bool ' Keepalive and linefill' CONFIG_SLIP_SMART $CONFIG_SLIP -dep_bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 $CONFIG_SLIP - -endmenu diff --git a/arch/um/config_scsi.in b/arch/um/config_scsi.in deleted file mode 100644 index ed363965b73f..000000000000 --- a/arch/um/config_scsi.in +++ /dev/null @@ -1,30 +0,0 @@ -comment 'SCSI support type (disk, tape, CD-ROM)' - -dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI - -if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then - int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 -fi - -dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI - -dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI - -if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR - int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 -fi -dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI - -comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' - -#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Enable extra checks in new queueing code' CONFIG_SCSI_DEBUG_QUEUES -#fi - -bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN - -bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS -bool ' SCSI logging facility' CONFIG_SCSI_LOGGING - -dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI -- cgit v1.2.3 From c26437a82e509e32300fd5f7c040c1c5e5addca2 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 04:22:01 -0500 Subject: Added the UML HOWTO in Documentation/uml. --- Documentation/uml/UserModeLinux-HOWTO.txt | 4686 +++++++++++++++++++++++++++++ 1 file changed, 4686 insertions(+) create mode 100644 Documentation/uml/UserModeLinux-HOWTO.txt diff --git a/Documentation/uml/UserModeLinux-HOWTO.txt b/Documentation/uml/UserModeLinux-HOWTO.txt new file mode 100644 index 000000000000..2950ab0012bf --- /dev/null +++ b/Documentation/uml/UserModeLinux-HOWTO.txt @@ -0,0 +1,4686 @@ + User Mode Linux HOWTO + User Mode Linux Core Team + Mon Nov 18 14:16:16 EST 2002 + + This document describes the use and abuse of Jeff Dike's User Mode + Linux: a port of the Linux kernel as a normal Intel Linux process. + ______________________________________________________________________ + + Table of Contents + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1. Introduction + + 1.1 How is User Mode Linux Different? + 1.2 Why Would I Want User Mode Linux? + + 2. Compiling the kernel and modules + + 2.1 Compiling the kernel + 2.2 Compiling and installing kernel modules + 2.3 Compiling and installing uml_utilities + + 3. Running UML and logging in + + 3.1 Running UML + 3.2 Logging in + 3.3 Examples + + 4. UML on 2G/2G hosts + + 4.1 Introduction + 4.2 The problem + 4.3 The solution + + 5. Setting up serial lines and consoles + + 5.1 Specifying the device + 5.2 Specifying the channel + 5.3 Examples + + 6. Setting up the network + + 6.1 General setup + 6.2 Userspace daemons + 6.3 Specifying ethernet addresses + 6.4 UML interface setup + 6.5 Multicast + 6.6 TUN/TAP with the uml_net helper + 6.7 TUN/TAP with a preconfigured tap device + 6.8 Ethertap + 6.9 The switch daemon + 6.10 Slip + 6.11 Slirp + 6.12 pcap + 6.13 Setting up the host yourself + + 7. Sharing Filesystems between Virtual Machines + + 7.1 A warning + 7.2 Using layered block devices + 7.3 Note! + 7.4 Another warning + 7.5 uml_moo : Merging a COW file with its backing file + + 8. Creating filesystems + + 8.1 Create the filesystem file + 8.2 Assign the file to a UML device + 8.3 Creating and mounting the filesystem + + 9. Host file access + + 9.1 Using hostfs + 9.2 hostfs as the root filesystem + 9.3 Building hostfs + + 10. The Management Console + 10.1 version + 10.2 halt and reboot + 10.3 config + 10.4 remove + 10.5 sysrq + 10.6 help + 10.7 cad + 10.8 stop + 10.9 go + + 11. Kernel debugging + + 11.1 Starting the kernel under gdb + 11.2 Examining sleeping processes + 11.3 Running ddd on UML + 11.4 Debugging modules + 11.5 Attaching gdb to the kernel + 11.6 Using alternate debuggers + + 12. Kernel debugging examples + + 12.1 The case of the hung fsck + 12.2 Episode 2: The case of the hung fsck + + 13. What to do when UML doesn't work + + 13.1 Strange compilation errors when you build from source + 13.2 UML hangs on boot after mounting devfs + 13.3 A variety of panics and hangs with /tmp on a reiserfs filesystem + 13.4 The compile fails with errors about conflicting types for 'open', 'dup', and 'waitpid' + 13.5 UML doesn't work when /tmp is an NFS filesystem + 13.6 UML hangs on boot when compiled with gprof support + 13.7 syslogd dies with a SIGTERM on startup + 13.8 TUN/TAP networking doesn't work on a 2.4 host + 13.9 You can network to the host but not to other machines on the net + 13.10 I have no root and I want to scream + 13.11 UML build conflict between ptrace.h and ucontext.h + 13.12 The UML BogoMips is exactly half the host's BogoMips + 13.13 When you run UML, it immediately segfaults + 13.14 xterms appear, then immediately disappear + 13.15 Any other panic, hang, or strange behavior + + 14. Diagnosing Problems + + 14.1 Case 1 : Normal kernel panics + 14.2 Case 2 : Tracing thread panics + 14.3 Case 3 : Tracing thread panics caused by other threads + 14.4 Case 4 : Hangs + + 15. Thanks + + 15.1 Code and Documentation + 15.2 Flushing out bugs + 15.3 Buglets and clean-ups + 15.4 Case Studies + 15.5 Other contributions + + + ______________________________________________________________________ + + 11.. IInnttrroodduuccttiioonn + + Welcome to User Mode Linux. It's going to be fun. + + + + 11..11.. HHooww iiss UUsseerr MMooddee LLiinnuuxx DDiiffffeerreenntt?? + + Normally, the Linux Kernel talks straight to your hardware (video + card, keyboard, hard drives, etc), and any programs which run ask the + kernel to operate the hardware, like so: + + + + +-----------+-----------+----+ + | Process 1 | Process 2 | ...| + +-----------+-----------+----+ + | Linux Kernel | + +----------------------------+ + | Hardware | + +----------------------------+ + + + + + The User Mode Linux Kernel is different; instead of talking to the + hardware, it talks to a `real' Linux kernel (called the `host kernel' + from now on), like any other program. Programs can then run inside + User-Mode Linux as if they were running under a normal kernel, like + so: + + + + +----------------+ + | Process 2 | ...| + +-----------+----------------+ + | Process 1 | User-Mode Linux| + +----------------------------+ + | Linux Kernel | + +----------------------------+ + | Hardware | + +----------------------------+ + + + + + + 11..22.. WWhhyy WWoouulldd II WWaanntt UUsseerr MMooddee LLiinnuuxx?? + + + 1. If User Mode Linux crashes, your host kernel is still fine. + + 2. You can run a usermode kernel as a non-root user. + + 3. You can debug the User Mode Linux like any normal process. + + 4. You can run gprof (profiling) and gcov (coverage testing). + + 5. You can play with your kernel without breaking things. + + 6. You can use it as a sandbox for testing new apps. + + 7. You can try new development kernels safely. + + 8. You can run different distributions simultaneously. + + 9. It's extremely fun. + + + + + + 22.. CCoommppiilliinngg tthhee kkeerrnneell aanndd mmoodduulleess + + + + + 22..11.. CCoommppiilliinngg tthhee kkeerrnneell + + + Compiling the user mode kernel is just like compiling any other + kernel. Let's go through the steps, using 2.4.0-prerelease (current + as of this writing) as an example: + + + 1. Download the latest UML patch from + + the download page + + In this example, the file is uml-patch-2.4.0-prerelease.bz2. + + + 2. Download the matching kernel from your favourite kernel mirror, + such as: + + ftp://ftp.ca.kernel.org/pub/kernel/v2.4/linux-2.4.0-prerelease.tar.bz2 + + . + + + 3. Make a directory and unpack the kernel into it. + + + + host% + mkdir ~/uml + + + + + + + host% + cd ~/uml + + + + + + + host% + tar -xzvf linux-2.4.0-prerelease.tar.bz2 + + + + + + + 4. Apply the patch using + + + + host% + cd ~/uml/linux + + + + host% + bzcat uml-patch-2.4.0-prerelease.bz2 | patch -p1 + + + + + + + 5. Run your favorite config; `make xconfig ARCH=um' is the most + convenient. `make config ARCH=um' and 'make menuconfig ARCH=um' + will work as well. The defaults will give you a useful kernel. If + you want to change something, go ahead, it probably won't hurt + anything. + + + Note: If the host is configured with a 2G/2G address space split + rather than the usual 3G/1G split, then the packaged UML binaries + will not run. They will immediately segfault. See ``UML on 2G/2G + hosts'' for the scoop on running UML on your system. + + + + 6. Finish with `make linux ARCH=um': the result is a file called + `linux' in the top directory of your source tree. + + Make sure that you don't build this kernel in /usr/src/linux. On some + distributions, /usr/include/asm is a link into this pool. The user- + mode build changes the other end of that link, and things that include + stop compiling. + + The sources are also available from cvs at the project's cvs page, + which has directions on getting the sources. You can also browse the + CVS pool from there. + + If you get the CVS sources, you will have to check them out into an + empty directory. You will then have to copy each file into the + corresponding directory in the appropriate kernel pool. + + If you don't have the latest kernel pool, you can get the + corresponding user-mode sources with + + + host% cvs co -r v_2_3_x linux + + + + + where 'x' is the version in your pool. Note that you will not get the + bug fixes and enhancements that have gone into subsequent releases. + + + If you build your own kernel, and want to boot it from one of the + filesystems distributed from this site, then, in nearly all cases, + devfs must be compiled into the kernel and mounted at boot time. The + exception is the SuSE filesystem. For this, devfs must either not be + in the kernel at all, or "devfs=nomount" must be on the kernel command + line. Any disagreement between the kernel and the filesystem being + booted about whether devfs is being used will result in the boot + getting no further than single-user mode. + + + If you don't want to use devfs, you can remove the need for it from a + filesystem by copying /dev from someplace, making a bunch of /dev/ubd + devices: + + + UML# for i in 0 1 2 3 4 5 6 7; do mknod ubd$i b 98 $i; done + + + + + and changing /etc/fstab and /etc/inittab to refer to the non-devfs + devices. + + + + 22..22.. CCoommppiilliinngg aanndd iinnssttaalllliinngg kkeerrnneell mmoodduulleess + + UML modules are built in the same way as the native kernel (with the + exception of the 'ARCH=um' that you always need for UML): + + + host% make modules ARCH=um + + + + + Any modules that you want to load into this kernel need to be built in + the user-mode pool. Modules from the native kernel won't work. + + You can install them by using ftp or something to copy them into the + virtual machine and dropping them into /lib/modules/`uname -r`. + + You can also get the kernel build process to install them as follows: + + 1. with the kernel not booted, mount the root filesystem in the top + level of the kernel pool: + + + host% mount root_fs mnt -o loop + + + + + + + 2. run + + + host% + make modules_install INSTALL_MOD_PATH=`pwd`/mnt ARCH=um + + + + + + + 3. unmount the filesystem + + + host% umount mnt + + + + + + + 4. boot the kernel on it + + + When the system is booted, you can use insmod as usual to get the + modules into the kernel. A number of things have been loaded into UML + as modules, especially filesystems and network protocols and filters, + so most symbols which need to be exported probably already are. + However, if you do find symbols that need exporting, let us + know, and + they'll be "taken care of". + + + + 22..33.. CCoommppiilliinngg aanndd iinnssttaalllliinngg uummll__uuttiilliittiieess + + Many features of the UML kernel require a user-space helper program, + so a uml_utilities package is distributed separately from the kernel + patch which provides these helpers. Included within this is: + + +o port-helper - Used by consoles which connect to xterms or ports + + +o tunctl - Configuration tool to create and delete tap devices + + +o uml_net - Setuid binary for automatic tap device configuration + + +o uml_switch - User-space virtual switch required for daemon + transport + + The uml_utilities tree is compiled with: + + + host# + make && make install + + + + + Note that UML kernel patches may require a specific version of the + uml_utilities distribution. If you don't keep up with the mailing + lists, ensure that you have the latest release of uml_utilities if you + are experiencing problems with your UML kernel, particularly when + dealing with consoles or command-line switches to the helper programs + + + + + + + + + 33.. RRuunnnniinngg UUMMLL aanndd llooggggiinngg iinn + + + + 33..11.. RRuunnnniinngg UUMMLL + + It runs on 2.2.15 or later, and all 2.4 kernels. + + + Booting UML is straightforward. Simply run 'linux': it will try to + mount the file `root_fs' in the current directory. You do not need to + run it as root. If your root filesystem is not named `root_fs', then + you need to put a `ubd0=root_fs_whatever' switch on the linux command + line. + + + You will need a filesystem to boot UML from. There are a number + available for download from here . There are also several tools + which can be + used to generate UML-compatible filesystem images from media. + The kernel will boot up and present you with a login prompt. + + + Note: If the host is configured with a 2G/2G address space split + rather than the usual 3G/1G split, then the packaged UML binaries will + not run. They will immediately segfault. See ``UML on 2G/2G hosts'' + for the scoop on running UML on your system. + + + + 33..22.. LLooggggiinngg iinn + + + + The prepackaged filesystems have a root account with password 'root' + and a user account with password 'user'. The login banner will + generally tell you how to log in. So, you log in and you will find + yourself inside a little virtual machine. Our filesystems have a + variety of commands and utilities installed (and it is fairly easy to + add more), so you will have a lot of tools with which to poke around + the system. + + There are a couple of other ways to log in: + + +o On a virtual console + + + + Each virtual console that is configured (i.e. the device exists in + /dev and /etc/inittab runs a getty on it) will come up in its own + xterm. If you get tired of the xterms, read ``Setting up serial + lines and consoles'' to see how to attach the consoles to + something else, like host ptys. + + + + +o Over the serial line + + + In the boot output, find a line that looks like: + + + + serial line 0 assigned pty /dev/ptyp1 + + + + + Attach your favorite terminal program to the corresponding tty. I.e. + for minicom, the command would be + + + host% minicom -o -p /dev/ttyp1 + + + + + + + +o Over the net + + + If the network is running, then you can telnet to the virtual + machine and log in to it. See ``Setting up the network'' to learn + about setting up a virtual network. + + When you're done using it, run halt, and the kernel will bring itself + down and the process will exit. + + + 33..33.. EExxaammpplleess + + Here are some examples of UML in action: + + +o A login session + + +o A virtual network + + + + + + + + 44.. UUMMLL oonn 22GG//22GG hhoossttss + + + + + 44..11.. IInnttrroodduuccttiioonn + + + Most Linux machines are configured so that the kernel occupies the + upper 1G (0xc0000000 - 0xffffffff) of the 4G address space and + processes use the lower 3G (0x00000000 - 0xbfffffff). However, some + machine are configured with a 2G/2G split, with the kernel occupying + the upper 2G (0x80000000 - 0xffffffff) and processes using the lower + 2G (0x00000000 - 0x7fffffff). + + + + + 44..22.. TThhee pprroobblleemm + + + The prebuilt UML binaries on this site will not run on 2G/2G hosts + because UML occupies the upper .5G of the 3G process address space + (0xa0000000 - 0xbfffffff). Obviously, on 2G/2G hosts, this is right + in the middle of the kernel address space, so UML won't even load - it + will immediately segfault. + + + + + 44..33.. TThhee ssoolluuttiioonn + + + The fix for this is to rebuild UML from source after enabling + CONFIG_HOST_2G_2G (under 'General Setup'). This will cause UML to + load itself in the top .5G of that smaller process address space, + where it will run fine. See ``Compiling the kernel and modules'' if + you need help building UML from source. + + + + + + + + + + + 55.. SSeettttiinngg uupp sseerriiaall lliinneess aanndd ccoonnssoolleess + + + It is possible to attach UML serial lines and consoles to many types + of host I/O channels by specifying them on the command line. + + + You can attach them to host ptys, ttys, file descriptors, and ports. + This allows you to do things like + + +o have a UML console appear on an unused host console, + + +o hook two virtual machines together by having one attach to a pty + and having the other attach to the corresponding tty + + +o make a virtual machine accessible from the net by attaching a + console to a port on the host. + + + The general format of the command line option is device=channel. + + + + 55..11.. SSppeecciiffyyiinngg tthhee ddeevviiccee + + Devices are specified with "con" or "ssl" (console or serial line, + respectively), optionally with a device number if you are talking + about a specific device. + + + Using just "con" or "ssl" describes all of the consoles or serial + lines. If you want to talk about console #3 or serial line #10, they + would be "con3" and "ssl10", respectively. + + + A specific device name will override a less general "con=" or "ssl=". + So, for example, you can assign a pty to each of the serial lines + except for the first two like this: + + + ssl=pty ssl0=tty:/dev/tty0 ssl1=tty:/dev/tty1 + + + + + The specificity of the device name is all that matters; order on the + command line is irrelevant. + + + + 55..22.. SSppeecciiffyyiinngg tthhee cchhaannnneell + + There are a number of different types of channels to attach a UML + device to, each with a different way of specifying exactly what to + attach to. + + +o pseudo-terminals - device=pty pts terminals - device=pts + + + This will cause UML to allocate a free host pseudo-terminal for the + device. The terminal that it got will be announced in the boot + log. You access it by attaching a terminal program to the + corresponding tty: + + +o screen /dev/pts/n + + +o screen /dev/ttyxx + + +o minicom -o -p /dev/ttyxx - minicom seems not able to handle pts + devices + + +o kermit - start it up, 'open' the device, then 'connect' + + + + + + +o terminals - device=tty:tty device file + + + This will make UML attach the device to the specified tty (i.e + + + con1=tty:/dev/tty3 + + + + + will attach UML's console 1 to the host's /dev/tty3). If the tty that + you specify is the slave end of a tty/pty pair, something else must + have already opened the corresponding pty in order for this to work. + + + + + + +o xterms - device=xterm + + + UML will run an xterm and the device will be attached to it. + + + + + + +o Port - device=port:port number + + + This will attach the UML devices to the specified host port. + Attaching console 1 to the host's port 9000 would be done like + this: + + + con1=port:9000 + + + + + Attaching all the serial lines to that port would be done similarly: + + + ssl=port:9000 + + + + + You access these devices by telnetting to that port. Each active tel- + net session gets a different device. If there are more telnets to a + port than UML devices attached to it, then the extra telnet sessions + will block until an existing telnet detaches, or until another device + becomes active (i.e. by being activated in /etc/inittab). + + This channel has the advantage that you can both attach multiple UML + devices to it and know how to access them without reading the UML boot + log. It is also unique in allowing access to a UML from remote + machines without requiring that the UML be networked. This could be + useful in allowing public access to UMLs because they would be + accessible from the net, but wouldn't need any kind of network + filtering or access control because they would have no network access. + + + If you attach the main console to a portal, then the UML boot will + appear to hang. In reality, it's waiting for a telnet to connect, at + which point the boot will proceed. + + + + + + +o already-existing file descriptors - device=file descriptor + + + If you set up a file descriptor on the UML command line, you can + attach a UML device to it. This is most commonly used to put the + main console back on stdin and stdout after assigning all the other + consoles to something else: + + + con0=fd:0,fd:1 con=pts + + + + + + + + + +o Nothing - device=null + + + This allows the device to be opened, in contrast to 'none', but + reads will block, and writes will succeed and the data will be + thrown out. + + + + + + +o None - device=none + + + This causes the device to disappear. If you are using devfs, the + device will not appear in /dev. If not, then attempts to open it + will return -ENODEV. + + + + You can also specify different input and output channels for a device + by putting a comma between them: + + + ssl3=tty:/dev/tty2,xterm + + + + + will cause serial line 3 to accept input on the host's /dev/tty3 and + display output on an xterm. That's a silly example - the most common + use of this syntax is to reattach the main console to stdin and stdout + as shown above. + + + If you decide to move the main console away from stdin/stdout, the + initial boot output will appear in the terminal that you're running + UML in. However, once the console driver has been officially + initialized, then the boot output will start appearing wherever you + specified that console 0 should be. That device will receive all + subsequent output. + + + + 55..33.. EExxaammpplleess + + There are a number of interesting things you can do with this + capability. + + + First, this is how you get rid of those bleeding console xterms by + attaching them to host ptys: + + + con=pty con0=fd:0,fd:1 + + + + + This will make a UML console take over an unused host virtual console, + so that when you switch to it, you will see the UML login prompt + rather than the host login prompt: + + + con1=tty:/dev/tty6 + + + + + You can attach two virtual machines together with what amounts to a + serial line as follows: + + Run one UML with a serial line attached to a pty - + + + ssl1=pty + + + + + Look at the boot log to see what pty it got (this example will assume + that it got /dev/ptyp1). + + Boot the other UML with a serial line attached to the corresponding + tty - + + + ssl1=tty:/dev/ttyp1 + + + + + Log in, make sure that it has no getty on that serial line, attach a + terminal program like minicom to it, and you should see the login + prompt of the other virtual machine. + + + 66.. SSeettttiinngg uupp tthhee nneettwwoorrkk + + + + This page describes how to set up the various transports and to + provide a UML instance with network access to the host, other machines + on the local net, and the rest of the net. + + + As of 2.4.5, UML networking has been completely redone to make it much + easier to set up, fix bugs, and add new features. + + + There is a new helper, uml_net, which does the host setup that + requires root privileges. + + + There are currently five transport types available for a UML virtual + machine to exchange packets with other hosts: + + +o ethertap + + +o TUN/TAP + + +o Multicast + + +o a switch daemon + + +o slip + + +o slirp + + +o pcap + + The TUN/TAP, ethertap, slip, and slirp transports allow a UML + instance to exchange packets with the host. They may be directed + to the host or the host may just act as a router to provide access + to other physical or virtual machines. + + + The pcap transport is a synthetic read-only interface, using the + libpcap binary to collect packets from interfaces on the host and + filter them. This is useful for building preconfigured traffic + monitors or sniffers. + + + The daemon and multicast transports provide a completely virtual + network to other virtual machines. This network is completely + disconnected from the physical network unless one of the virtual + machines on it is acting as a gateway. + + + With so many host transports, which one should you use? Here's when + you should use each one: + + +o ethertap - if you want access to the host networking and it is + running 2.2 + + +o TUN/TAP - if you want access to the host networking and it is + running 2.4. Also, the TUN/TAP transport is able to use a + preconfigured device, allowing it to avoid using the setuid uml_net + helper, which is a security advantage. + + +o Multicast - if you want a purely virtual network and you don't want + to set up anything but the UML + + +o a switch daemon - if you want a purely virtual network and you + don't mind running the daemon in order to get somewhat better + performance + + +o slip - there is no particular reason to run the slip backend unless + ethertap and TUN/TAP are just not available for some reason + + +o slirp - if you don't have root access on the host to setup + networking, or if you don't want to allocate an IP to your UML + + +o pcap - not much use for actual network connectivity, but great for + monitoring traffic on the host + + Ethertap is available on 2.4 and works fine. TUN/TAP is preferred + to it because it has better performance and ethertap is officially + considered obsolete in 2.4. Also, the root helper only needs to + run occasionally for TUN/TAP, rather than handling every packet, as + it does with ethertap. This is a slight security advantage since + it provides fewer opportunities for a nasty UML user to somehow + exploit the helper's root privileges. + + + 66..11.. GGeenneerraall sseettuupp + + First, you must have the virtual network enabled in your UML. If are + running a prebuilt kernel from this site, everything is already + enabled. If you build the kernel yourself, under the "Network device + support" menu, enable "Network device support", and then the three + transports. + + + The next step is to provide a network device to the virtual machine. + This is done by describing it on the kernel command line. + + The general format is + + + eth = , + + + + + For example, a virtual ethernet device may be attached to a host + ethertap device as follows: + + + eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254 + + + + + This sets up eth0 inside the virtual machine to attach itself to the + host /dev/tap0, assigns it an ethernet address, and assigns the host + tap0 interface an IP address. + + + + Note that the IP address you assign to the host end of the tap device + must be different than the IP you assign to the eth device inside UML. + If you are short on IPs and don't want to comsume two per UML, then + you can reuse the host's eth IP address for the host ends of the tap + devices. Internally, the UMLs must still get unique IPs for their eth + devices. You can also give the UMLs non-routable IPs (192.168.x.x or + 10.x.x.x) and have the host masquerade them. This will let outgoing + connections work, but incoming connections won't without more work, + such as port forwarding from the host. + Also note that when you configure the host side of an interface, it is + only acting as a gateway. It will respond to pings sent to it + locally, but is not useful to do that since it's a host interface. + You are not talking to the UML when you ping that interface and get a + response. + + + You can also add devices to a UML and remove them at runtime. See the + ``The Management Console'' page for details. + + + The sections below describe this in more detail. + + + Once you've decided how you're going to set up the devices, you boot + UML, log in, configure the UML side of the devices, and set up routes + to the outside world. At that point, you will be able to talk to any + other machines, physical or virtual, on the net. + + + If ifconfig inside UML fails and the network refuses to come up, run + tell you what went wrong. + + + + 66..22.. UUsseerrssppaaccee ddaaeemmoonnss + + You will likely need the setuid helper, or the switch daemon, or both. + They are both installed with the RPM and deb, so if you've installed + either, you can skip the rest of this section. + + + If not, then you need to check them out of CVS, build them, and + install them. The helper is uml_net, in CVS /tools/uml_net, and the + daemon is uml_switch, in CVS /tools/uml_router. They are both built + with a plain 'make'. Both need to be installed in a directory that's + in your path - /usr/bin is recommend. On top of that, uml_net needs + to be setuid root. + + + + 66..33.. SSppeecciiffyyiinngg eetthheerrnneett aaddddrreesssseess + + Below, you will see that the TUN/TAP, ethertap, and daemon interfaces + allow you to specify hardware addresses for the virtual ethernet + devices. This is generally not necessary. If you don't have a + specific reason to do it, you probably shouldn't. If one is not + specified on the command line, the driver will assign one based on the + device IP address. It will provide the address fe:fd:nn:nn:nn:nn + where nn.nn.nn.nn is the device IP address. This is nearly always + sufficient to guarantee a unique hardware address for the device. A + couple of exceptions are: + + +o Another set of virtual ethernet devices are on the same network and + they are assigned hardware addresses using a different scheme which + may conflict with the UML IP address-based scheme + + +o You aren't going to use the device for IP networking, so you don't + assign the device an IP address + + If you let the driver provide the hardware address, you should make + sure that the device IP address is known before the interface is + brought up. So, inside UML, this will guarantee that: + + + + UML# + ifconfig eth0 192.168.0.250 up + + + + + If you decide to assign the hardware address yourself, make sure that + the first byte of the address is even. Addresses with an odd first + byte are broadcast addresses, which you don't want assigned to a + device. + + + + 66..44.. UUMMLL iinntteerrffaaccee sseettuupp + + Once the network devices have been described on the command line, you + should boot UML and log in. + + + The first thing to do is bring the interface up: + + + UML# ifconfig ethn ip-address up + + + + + You should be able to ping the host at this point. + + + To reach the rest of the world, you should set a default route to the + host: + + + UML# route add default gw host ip + + + + + Again, with host ip of 192.168.0.4: + + + UML# route add default gw 192.168.0.4 + + + + + This page used to recommend setting a network route to your local net. + This is wrong, because it will cause UML to try to figure out hardware + addresses of the local machines by arping on the interface to the + host. Since that interface is basically a single strand of ethernet + with two nodes on it (UML and the host) and arp requests don't cross + networks, they will fail to elicit any responses. So, what you want + is for UML to just blindly throw all packets at the host and let it + figure out what to do with them, which is what leaving out the network + route and adding the default route does. + + + Note: If you can't communicate with other hosts on your physical + ethernet, it's probably because of a network route that's + automatically set up. If you run 'route -n' and see a route that + looks like this: + + + + + Destination Gateway Genmask Flags Metric Ref Use Iface + 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 + + + + + with a mask that's not 255.255.255.255, then replace it with a route + to your host: + + + UML# + route del -net 192.168.0.0 dev eth0 netmask 255.255.255.0 + + + + + + + UML# + route add -host 192.168.0.4 dev eth0 + + + + + This, plus the default route to the host, will allow UML to exchange + packets with any machine on your ethernet. + + + + 66..55.. MMuullttiiccaasstt + + The simplest way to set up a virtual network between multiple UMLs is + to use the mcast transport. This was written by Harald Welte and is + present in UML version 2.4.5-5um and later. Your system must have + multicast enabled in the kernel and there must be a multicast-capable + network device on the host. Normally, this is eth0, but if there is + no ethernet card on the host, then you will likely get strange error + messages when you bring the device up inside UML. + + + To use it, run two UMLs with + + + eth0=mcast + + + + + on their command lines. Log in, configure the ethernet device in each + machine with different IP addresses: + + + UML1# ifconfig eth0 192.168.0.254 + + + + + + + UML2# ifconfig eth0 192.168.0.253 + + + + + and they should be able to talk to each other. + + The full set of command line options for this transport are + + + + ethn=mcast,ethernet address,multicast + address,multicast port,ttl + + + + + Harald's original README is here and explains these in detail, as well as + some other issues. + + + + 66..66.. TTUUNN//TTAAPP wwiitthh tthhee uummll__nneett hheellppeerr + + TUN/TAP is the preferred mechanism on 2.4 to exchange packets with the + host. The TUN/TAP backend has been in UML since 2.4.9-3um. + + + The easiest way to get up and running is to let the setuid uml_net + helper do the host setup for you. This involves insmod-ing the tun.o + module if necessary, configuring the device, and setting up IP + forwarding, routing, and proxy arp. If you are new to UML networking, + do this first. If you're concerned about the security implications of + the setuid helper, use it to get up and running, then read the next + section to see how to have UML use a preconfigured tap device, which + avoids the use of uml_net. + + + If you specify an IP address for the host side of the device, the + uml_net helper will do all necessary setup on the host - the only + requirement is that TUN/TAP be available, either built in to the host + kernel or as the tun.o module. + + The format of the command line switch to attach a device to a TUN/TAP + device is + + + eth =tuntap,,, + + + + + For example, this argument will attach the UML's eth0 to the next + available tap device and assign an ethernet address to it based on its + IP address + + + eth0=tuntap,,,192.168.0.254 + + + + + + + Note that the IP address that must be used for the eth device inside + UML is fixed by the routing and proxy arp that is set up on the + TUN/TAP device on the host. You can use a different one, but it won't + work because reply packets won't reach the UML. This is a feature. + It prevents a nasty UML user from doing things like setting the UML IP + to the same as the network's nameserver or mail server. + + + There are a couple potential problems with running the TUN/TAP + transport on a 2.4 host kernel + + +o TUN/TAP seems not to work on 2.4.3 and earlier. Upgrade the host + kernel or use the ethertap transport. + + +o With an upgraded kernel, TUN/TAP may fail with + + + File descriptor in bad state + + + + + This is due to a header mismatch between the upgraded kernel and the + kernel that was originally installed on the machine. The fix is to + make sure that /usr/src/linux points to the headers for the running + kernel. + + These were pointed out by Tim Robinson in + name="this uml- + user post"> . + + + + 66..77.. TTUUNN//TTAAPP wwiitthh aa pprreeccoonnffiigguurreedd ttaapp ddeevviiccee + + If you prefer not to have UML use uml_net (which is somewhat + insecure), with UML 2.4.17-11, you can set up a TUN/TAP device + beforehand. The setup needs to be done as root, but once that's done, + there is no need for root assistance. Setting up the device is done + as follows: + + +o Create the device with tunctl (available from the UML utilities + tarball) + + + + + host# tunctl -u uid + + + + + where uid is the user id or username that UML will be run as. This + will tell you what device was created. + + +o Configure the device IP (change IP addresses and device name to + suit) + + + + + host# ifconfig tap0 192.168.0.254 up + + + + + + +o Set up routing and arping if desired - this is my recipe, there are + other ways of doing the same thing + + + host# + bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward' + + host# + route add -host 192.168.0.253 dev tap0 + + + + + + + host# + bash -c 'echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp' + + + + + + + host# + arp -Ds 192.168.0.253 eth0 pub + + + + + Note that this must be done every time the host boots - this configu- + ration is not stored across host reboots. So, it's probably a good + idea to stick it in an rc file. An even better idea would be a little + utility which reads the information from a config file and sets up + devices at boot time. + + +o Rather than using up two IPs and ARPing for one of them, you can + also provide direct access to your LAN by the UML by using a + bridge. + + + host# + brctl addbr br0 + + + + + + + host# + ifconfig eth0 0.0.0.0 promisc up + + + + + + + host# + ifconfig tap0 0.0.0.0 promisc up + + + + + + + host# + ifconfig br0 192.168.0.1 netmask 255.255.255.0 up + + + + + + + + host# + brctl stp br0 off + + + + + + + host# + brctl setfd br0 1 + + + + + + + host# + brctl sethello br0 1 + + + + + + + host# + brctl addif br0 eth0 + + + + + + + host# + brctl addif br0 tap0 + + + + + Note that 'br0' should be setup using ifconfig with the existing IP + address of eth0, as eth0 no longer has its own IP. + + +o + + + Also, the /dev/net/tun device must be writable by the user running + UML in order for the UML to use the device that's been configured + for it. The simplest thing to do is + + + host# chmod 666 /dev/net/tun + + + + + Making it world-writeable looks bad, but it seems not to be + exploitable as a security hole. However, it does allow anyone to cre- + ate useless tap devices (useless because they can't configure them), + which is a DOS attack. A somewhat more secure alternative would to be + to create a group containing all the users who have preconfigured tap + devices and chgrp /dev/net/tun to that group with mode 664 or 660. + + + +o Once the device is set up, run UML with 'eth0=tuntap,device name' + (i.e. 'eth0=tuntap,tap0') on the command line (or do it with the + mconsole config command). + + +o Bring the eth device up in UML and you're in business. + + If you don't want that tap device any more, you can make it non- + persistent with + + + host# tunctl -d tap device + + + + + Finally, tunctl has a -b (for brief mode) switch which causes it to + output only the name of the tap device it created. This makes it + suitable for capture by a script: + + + host# TAP=`tunctl -u 1000 -b` + + + + + + + 66..88.. EEtthheerrttaapp + + Ethertap is the general mechanism on 2.2 for userspace processes to + exchange packets with the kernel. + + + + To use this transport, you need to describe the virtual network device + on the UML command line. The general format for this is + + + eth =ethertap, , , + + + + + So, the previous example + + + eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254 + + + + + attaches the UML eth0 device to the host /dev/tap0, assigns it the + ethernet address fe:fd:0:0:0:1, and assigns the IP address + 192.168.0.254 to the tap device. + + + + The tap device is mandatory, but the others are optional. If the + ethernet address is omitted, one will be assigned to it. + + + The presence of the tap IP address will cause the helper to run and do + whatever host setup is needed to allow the virtual machine to + communicate with the outside world. If you're not sure you know what + you're doing, this is the way to go. + + + If it is absent, then you must configure the tap device and whatever + arping and routing you will need on the host. However, even in this + case, the uml_net helper still needs to be in your path and it must be + setuid root if you're not running UML as root. This is because the + tap device doesn't support SIGIO, which UML needs in order to use + something as a source of input. So, the helper is used as a + convenient asynchronous IO thread. + + If you're using the uml_net helper, you can ignore the following host + setup - uml_net will do it for you. You just need to make sure you + have ethertap available, either built in to the host kernel or + available as a module. + + + If you want to set things up yourself, you need to make sure that the + appropriate /dev entry exists. If it doesn't, become root and create + it as follows: + + + mknod /dev/tap c 36 + 16 + + + + + For example, this is how to create /dev/tap0: + + + mknod /dev/tap0 c 36 0 + 16 + + + + + You also need to make sure that the host kernel has ethertap support. + If ethertap is enabled as a module, you apparently need to insmod + ethertap once for each ethertap device you want to enable. So, + + + host# + insmod ethertap + + + + + will give you the tap0 interface. To get the tap1 interface, you need + to run + + + host# + insmod ethertap unit=1 -o ethertap1 + + + + + + + + 66..99.. TThhee sswwiittcchh ddaaeemmoonn + + NNoottee: This is the daemon formerly known as uml_router, but which was + renamed so the network weenies of the world would stop growling at me. + + + The switch daemon, uml_switch, provides a mechanism for creating a + totally virtual network. By default, it provides no connection to the + host network (but see -tap, below). + + + The first thing you need to do is run the daemon. Running it with no + arguments will make it listen on a default pair of unix domain + sockets. + + + If you want it to listen on a different pair of sockets, use + + + -unix control socket data socket + + + + + + If you want it to act as a hub rather than a switch, use + + + -hub + + + + + + If you want the switch to be connected to host networking (allowing + the umls to get access to the outside world through the host), use + + + -tap tap0 + + + + + + Note that the tap device must be preconfigured (see "TUN/TAP with a + preconfigured tap device", above). If you're using a different tap + device than tap0, specify that instead of tap0. + + + uml_switch can be backgrounded as follows + + + host% + uml_switch [ options ] < /dev/null > /dev/null + + + + + The reason it doesn't background by default is that it listens to + stdin for EOF. When it sees that, it exits. + + + The general format of the kernel command line switch is + + + + ethn=daemon,ethernet address,socket + type,control socket,data socket + + + + + You can leave off everything except the 'daemon'. You only need to + specify the ethernet address if the one that will be assigned to it + isn't acceptable for some reason. The rest of the arguments describe + how to communicate with the daemon. You should only specify them if + you told the daemon to use different sockets than the default. So, if + you ran the daemon with no arguments, running the UML on the same + machine with + eth0=daemon + + + + + will cause the eth0 driver to attach itself to the daemon correctly. + + + + 66..1100.. SSlliipp + + Slip is another, less general, mechanism for a process to communicate + with the host networking. In contrast to the ethertap interface, + which exchanges ethernet frames with the host and can be used to + transport any higher-level protocol, it can only be used to transport + IP. + + + The general format of the command line switch is + + + + ethn=slip,slip IP + + + + + The slip IP argument is the IP address that will be assigned to the + host end of the slip device. If it is specified, the helper will run + and will set up the host so that the virtual machine can reach it and + the rest of the network. + + + There are some oddities with this interface that you should be aware + of. You should only specify one slip device on a given virtual + machine, and its name inside UML will be 'umn', not 'eth0' or whatever + you specified on the command line. These problems will be fixed at + some point. + + + + 66..1111.. SSlliirrpp + + slirp uses an external program, usually /usr/bin/slirp, to provide IP + only networking connectivity through the host. This is similar to IP + masquerading with a firewall, although the translation is performed in + user-space, rather than by the kernel. As slirp does not set up any + interfaces on the host, or changes routing, slirp does not require + root access or setuid binaries on the host. + + + The general format of the command line switch for slirp is: + + + + ethn=slirp,ethernet address,slirp path + + + + + The ethernet address is optional, as UML will set up the interface + with an ethernet address based upon the initial IP address of the + interface. The slirp path is generally /usr/bin/slirp, although it + will depend on distribution. + + + The slirp program can have a number of options passed to the command + line and we can't add them to the UML command line, as they will be + parsed incorrectly. Instead, a wrapper shell script can be written or + the options inserted into the /.slirprc file. More information on + all of the slirp options can be found in its man pages. + + + The eth0 interface on UML should be set up with the IP 10.2.0.15, + although you can use anything as long as it is not used by a network + you will be connecting to. The default route on UML should be set to + use + + + UML# + route add default dev eth0 + + + + + slirp provides a number of useful IP addresses which can be used by + UML, such as 10.0.2.3 which is an alias for the DNS server specified + in /etc/resolv.conf on the host or the IP given in the 'dns' option + for slirp. + + + Even with a baudrate setting higher than 115200, the slirp connection + is limited to 115200. If you need it to go faster, the slirp binary + needs to be compiled with FULL_BOLT defined in config.h. + + + + 66..1122.. ppccaapp + + The pcap transport is attached to a UML ethernet device on the command + line or with uml_mconsole with the following syntax: + + + + ethn=pcap,host interface,filter + expression,option1,option2 + + + + + The expression and options are optional. + + + The interface is whatever network device on the host you want to + sniff. The expression is a pcap filter expression, which is also what + tcpdump uses, so if you know how to specify tcpdump filters, you will + use the same expressions here. The options are up to two of + 'promisc', control whether pcap puts the host interface into + promiscuous mode. 'optimize' and 'nooptimize' control whether the pcap + expression optimizer is used. + + + Example: + + + + eth0=pcap,eth0,tcp + + eth1=pcap,eth0,!tcp + + + + will cause the UML eth0 to emit all tcp packets on the host eth0 and + the UML eth1 to emit all non-tcp packets on the host eth0. + + + + 66..1133.. SSeettttiinngg uupp tthhee hhoosstt yyoouurrsseellff + + If you don't specify an address for the host side of the ethertap or + slip device, UML won't do any setup on the host. So this is what is + needed to get things working (the examples use a host-side IP of + 192.168.0.251 and a UML-side IP of 192.168.0.250 - adjust to suit your + own network): + + +o The device needs to be configured with its IP address. Tap devices + are also configured with an mtu of 1484. Slip devices are + configured with a point-to-point address pointing at the UML ip + address. + + + host# ifconfig tap0 arp mtu 1484 192.168.0.251 up + + + + + + + host# + ifconfig sl0 192.168.0.251 pointopoint 192.168.0.250 up + + + + + + +o If a tap device is being set up, a route is set to the UML IP. + + + UML# route add -host 192.168.0.250 gw 192.168.0.251 + + + + + + +o To allow other hosts on your network to see the virtual machine, + proxy arp is set up for it. + + + host# arp -Ds 192.168.0.250 eth0 pub + + + + + + +o Finally, the host is set up to route packets. + + + host# echo 1 > /proc/sys/net/ipv4/ip_forward + + + + + + + + + + + 77.. SShhaarriinngg FFiilleessyysstteemmss bbeettwweeeenn VViirrttuuaall MMaacchhiinneess + + + + + 77..11.. AA wwaarrnniinngg + + Don't attempt to share filesystems simply by booting two UMLs from the + same file. That's the same thing as booting two physical machines + from a shared disk. It will result in filesystem corruption. + + + + 77..22.. UUssiinngg llaayyeerreedd bblloocckk ddeevviicceess + + The way to share a filesystem between two virtual machines is to use + the copy-on-write (COW) layering capability of the ubd block driver. + As of 2.4.6-2um, the driver supports layering a read-write private + device over a read-only shared device. A machine's writes are stored + in the private device, while reads come from either device - the + private one if the requested block is valid in it, the shared one if + not. Using this scheme, the majority of data which is unchanged is + shared between an arbitrary number of virtual machines, each of which + has a much smaller file containing the changes that it has made. With + a large number of UMLs booting from a large root filesystem, this + leads to a huge disk space saving. It will also help performance, + since the host will be able to cache the shared data using a much + smaller amount of memory, so UML disk requests will be served from the + host's memory rather than its disks. + + + + + To add a copy-on-write layer to an existing block device file, simply + add the name of the COW file to the appropriate ubd switch: + + + ubd0=root_fs_cow,root_fs_debian_22 + + + + + where 'root_fs_cow' is the private COW file and 'root_fs_debian_22' is + the existing shared filesystem. The COW file need not exist. If it + doesn't, the driver will create and initialize it. Once the COW file + has been initialized, it can be used on its own on the command line: + + + ubd0=root_fs_cow + + + + + The name of the backing file is stored in the COW file header, so it + would be redundant to continue specifying it on the command line. + + + + 77..33.. NNoottee!! + + When checking the size of the COW file in order to see the gobs of + space that you're saving, make sure you use 'ls -ls' to see the actual + disk consumption rather than the length of the file. The COW file is + sparse, so the length will be very different from the disk usage. + Here is a 'ls -l' of a COW file and backing file from one boot and + shutdown: + host% ls -l cow.debian debian2.2 + -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian + -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2 + + + + + Doesn't look like much saved space, does it? Well, here's 'ls -ls': + + + host% ls -ls cow.debian debian2.2 + 880 -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian + 525832 -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2 + + + + + Now, you can see that the COW file has less than a meg of disk, rather + than 492 meg. + + + + 77..44.. AAnnootthheerr wwaarrnniinngg + + Once a filesystem is being used as a readonly backing file for a COW + file, do not boot directly from it or modify it in any way. Doing so + will invalidate any COW files that are using it. The mtime and size + of the backing file are stored in the COW file header at its creation, + and they must continue to match. If they don't, the driver will + refuse to use the COW file. + + + + + If you attempt to evade this restriction by changing either the + backing file or the COW header by hand, you will get a corrupted + filesystem. + + + + + Among other things, this means that upgrading the distribution in a + backing file and expecting that all of the COW files using it will see + the upgrade will not work. + + + + + 77..55.. uummll__mmoooo :: MMeerrggiinngg aa CCOOWW ffiillee wwiitthh iittss bbaacckkiinngg ffiillee + + Depending on how you use UML and COW devices, it may be advisable to + merge the changes in the COW file into the backing file every once in + a while. + + + + + The utility that does this is uml_moo. Its usage is + + + host% uml_moo COW file new backing file + + + + + There's no need to specify the backing file since that information is + already in the COW file header. If you're paranoid, boot the new + merged file, and if you're happy with it, move it over the old backing + file. + + + + + uml_moo creates a new backing file by default as a safety measure. It + also has a destructive merge option which will merge the COW file + directly into its current backing file. This is really only usable + when the backing file only has one COW file associated with it. If + there are multiple COWs associated with a backing file, a -d merge of + one of them will invalidate all of the others. However, it is + convenient if you're short of disk space, and it should also be + noticably faster than a non-destructive merge. + + + + + uml_moo is installed with the UML deb and RPM. If you didn't install + UML from one of those packages, you can also get it from the UML + utilities tar file in tools/moo. + + + + + + + + + 88.. CCrreeaattiinngg ffiilleessyysstteemmss + + + You may want to create and mount new UML filesystems, either because + your root filesystem isn't large enough or because you want to use a + filesystem other than ext2. + + + This was written on the occasion of reiserfs being included in the + 2.4.1 kernel pool, and therefore the 2.4.1 UML, so the examples will + talk about reiserfs. This information is generic, and the examples + should be easy to translate to the filesystem of your choice. + + + 88..11.. CCrreeaattee tthhee ffiilleessyysstteemm ffiillee + + dd is your friend. All you need to do is tell dd to create an empty + file of the appropriate size. I usually make it sparse to save time + and to avoid allocating disk space until it's actually used. For + example, the following command will create a sparse 100 meg file full + of zeroes. + + + host% + dd if=/dev/zero of=new_filesystem seek=100 count=1 bs=1M + + + + + + + 88..22.. AAssssiiggnn tthhee ffiillee ttoo aa UUMMLL ddeevviiccee + + Add an argument like the following to the UML command line: + + ubd4=new_filesystem + + + + + making sure that you use an unassigned ubd device number. + + + + 88..33.. CCrreeaattiinngg aanndd mmoouunnttiinngg tthhee ffiilleessyysstteemm + + Make sure that the filesystem is available, either by being built into + the kernel, or available as a module, then boot up UML and log in. If + the root filesystem doesn't have the filesystem utilities (mkfs, fsck, + etc), then get them into UML by way of the net or hostfs. + + + Make the new filesystem on the device assigned to the new file: + + + host# mkreiserfs /dev/ubd/4 + + + <----------- MKREISERFSv2 -----------> + + ReiserFS version 3.6.25 + Block size 4096 bytes + Block count 25856 + Used blocks 8212 + Journal - 8192 blocks (18-8209), journal header is in block 8210 + Bitmaps: 17 + Root block 8211 + Hash function "r5" + ATTENTION: ALL DATA WILL BE LOST ON '/dev/ubd/4'! (y/n)y + journal size 8192 (from 18) + Initializing journal - 0%....20%....40%....60%....80%....100% + Syncing..done. + + + + + Now, mount it: + + + UML# + mount /dev/ubd/4 /mnt + + + + + and you're in business. + + + + + + + + + + 99.. HHoosstt ffiillee aacccceessss + + + If you want to access files on the host machine from inside UML, you + can treat it as a separate machine and either nfs mount directories + from the host or copy files into the virtual machine with scp or rcp. + However, since UML is running on the the host, it can access those + files just like any other process and make them available inside the + virtual machine without needing to use the network. + + + This is now possible with the hostfs virtual filesystem. With it, you + can mount a host directory into the UML filesystem and access the + files contained in it just as you would on the host. + + + 99..11.. UUssiinngg hhoossttffss + + To begin with, make sure that hostfs is available inside the virtual + machine with + + + UML# cat /proc/filesystems + + + + . hostfs should be listed. If it's not, either rebuild the kernel + with hostfs configured into it or make sure that hostfs is built as a + module and available inside the virtual machine, and insmod it. + + + Now all you need to do is run mount: + + + UML# mount none /mnt/host -t hostfs + + + + + will mount the host's / on the virtual machine's /mnt/host. + + + If you don't want to mount the host root directory, then you can + specify a subdirectory to mount with the -o switch to mount: + + + UML# mount none /mnt/home -t hostfs -o /home + + + + + will mount the hosts's /home on the virtual machine's /mnt/home. + + + + 99..22.. hhoossttffss aass tthhee rroooott ffiilleessyysstteemm + + It's possible to boot from a directory hierarchy on the host using + hostfs rather than using the standard filesystem in a file. + + To start, you need that hierarchy. The easiest way is to loop mount + an existing root_fs file: + + + host# mount root_fs uml_root_dir -o loop + + + + + You need to change the filesystem type of / in etc/fstab to be + 'hostfs', so that line looks like this: + + /dev/ubd/0 / hostfs defaults 1 1 + + + + + Then you need to chown to yourself all the files in that directory + that are owned by root. This worked for me: + + + host# find . -uid 0 -exec chown jdike {} \; + + + + + Next, make sure that your UML kernel has hostfs compiled in, not as a + module. Then run UML with the boot device pointing at that directory: + + + ubd0=/path/to/uml/root/directory + + + + + UML should then boot as it does normally. + + + 99..33.. BBuuiillddiinngg hhoossttffss + + If you need to build hostfs because it's not in your kernel, you have + two choices: + + + + +o Compiling hostfs into the kernel: + + + Reconfigure the kernel and set the 'Host filesystem' option under + + + +o Compiling hostfs as a module: + + + Reconfigure the kernel and set the 'Host filesystem' option under + be in arch/um/fs/hostfs/hostfs.o. Install that in + /lib/modules/`uname -r`/fs in the virtual machine, boot it up, and + + + UML# insmod hostfs + + + + + + + + + + + + + 1100.. TThhee MMaannaaggeemmeenntt CCoonnssoollee + + + + The UML management console is a low-level interface to the kernel, + somewhat like the i386 SysRq interface. Since there is a full-blown + operating system under UML, there is much greater flexibility possible + than with the SysRq mechanism. + + + There are a number of things you can do with the mconsole interface: + + +o get the kernel version + + +o add and remove devices + + +o halt or reboot the machine + + +o Send SysRq commands + + +o Pause and resume the UML + + + You need the mconsole client (uml_mconsole) which is present in CVS + (/tools/mconsole) in 2.4.5-9um and later, and will be in the RPM in + 2.4.6. + + + You also need CONFIG_MCONSOLE (under 'General Setup') enabled in UML. + When you boot UML, you'll see a line like: + + + mconsole initialized on /home/jdike/.uml/umlNJ32yL/mconsole + + + + + If you specify a unique machine id one the UML command line, i.e. + + + umid=debian + + + + + you'll see this + + + mconsole initialized on /home/jdike/.uml/debian/mconsole + + + + + That file is the socket that uml_mconsole will use to communicate with + UML. Run it with either the umid or the full path as its argument: + + + host% uml_mconsole debian + + + + + or + + + host% uml_mconsole /home/jdike/.uml/debian/mconsole + + + + + You'll get a prompt, at which you can run one of these commands: + + +o version + + +o halt + + +o reboot + + +o config + + +o remove + + +o sysrq + + +o help + + +o cad + + +o stop + + +o go + + + 1100..11.. vveerrssiioonn + + This takes no arguments. It prints the UML version. + + + (mconsole) version + OK Linux usermode 2.4.5-9um #1 Wed Jun 20 22:47:08 EDT 2001 i686 + + + + + There are a couple actual uses for this. It's a simple no-op which + can be used to check that a UML is running. It's also a way of + sending an interrupt to the UML. This is sometimes useful on SMP + hosts, where there's a bug which causes signals to UML to be lost, + often causing it to appear to hang. Sending such a UML the mconsole + version command is a good way to 'wake it up' before networking has + been enabled, as it does not do anything to the function of the UML. + + + + 1100..22.. hhaalltt aanndd rreebboooott + + These take no arguments. They shut the machine down immediately, with + no syncing of disks and no clean shutdown of userspace. So, they are + pretty close to crashing the machine. + + + (mconsole) halt + OK + + + + + + + 1100..33.. ccoonnffiigg + + "config" adds a new device to the virtual machine. Currently the ubd + and network drivers support this. It takes one argument, which is the + device to add, with the same syntax as the kernel command line. + + + + + (mconsole) + config ubd3=/home/jdike/incoming/roots/root_fs_debian22 + + OK + (mconsole) config eth1=mcast + OK + + + + + + + 1100..44.. rreemmoovvee + + "remove" deletes a device from the system. Its argument is just the + name of the device to be removed. The device must be idle in whatever + sense the driver considers necessary. In the case of the ubd driver, + the removed block device must not be mounted, swapped on, or otherwise + open, and in the case of the network driver, the device must be down. + + + (mconsole) remove ubd3 + OK + (mconsole) remove eth1 + OK + + + + + + + 1100..55.. ssyyssrrqq + + This takes one argument, which is a single letter. It calls the + generic kernel's SysRq driver, which does whatever is called for by + that argument. See the SysRq documentation in Documentation/sysrq.txt + in your favorite kernel tree to see what letters are valid and what + they do. + + + + 1100..66.. hheellpp + + "help" returns a string listing the valid commands and what each one + does. + + + + 1100..77.. ccaadd + + This invokes the Ctl-Alt-Del action on init. What exactly this ends + up doing is up to /etc/inittab. Normally, it reboots the machine. + With UML, this is usually not desired, so if a halt would be better, + then find the section of inittab that looks like this + + + # What to do when CTRL-ALT-DEL is pressed. + ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now + + + + + and change the command to halt. + + + + 1100..88.. ssttoopp + + This puts the UML in a loop reading mconsole requests until a 'go' + mconsole command is recieved. This is very useful for making backups + of UML filesystems, as the UML can be stopped, then synced via 'sysrq + s', so that everything is written to the filesystem. You can then copy + the filesystem and then send the UML 'go' via mconsole. + + + Note that a UML running with more than one CPU will have problems + after you send the 'stop' command, as only one CPU will be held in a + mconsole loop and all others will continue as normal. This is a bug, + and will be fixed. + + + + 1100..99.. ggoo + + This resumes a UML after being paused by a 'stop' command. Note that + when the UML has resumed, TCP connections may have timed out and if + the UML is paused for a long period of time, crond might go a little + crazy, running all the jobs it didn't do earlier. + + + + + + + + + 1111.. KKeerrnneell ddeebbuuggggiinngg + + + NNoottee:: The interface that makes debugging, as described here, possible + is present in 2.4.0-test6 kernels and later. + + + Since the user-mode kernel runs as a normal Linux process, it is + possible to debug it with gdb almost like any other process. It is + slightly different because the kernel's threads are already being + ptraced for system call interception, so gdb can't ptrace them. + However, a mechanism has been added to work around that problem. + + + In order to debug the kernel, you need build it from source. See + ``Compiling the kernel and modules'' for information on doing that. + Make sure that you enable CONFIG_DEBUGSYM and CONFIG_PT_PROXY during + the config. These will compile the kernel with -g, and enable the + ptrace proxy so that gdb works with UML, respectively. + + + + + 1111..11.. SSttaarrttiinngg tthhee kkeerrnneell uunnddeerr ggddbb + + You can have the kernel running under the control of gdb from the + beginning by putting 'debug' on the command line. You will get an + xterm with gdb running inside it. The kernel will send some commands + to gdb which will leave it stopped at the beginning of start_kernel. + At this point, you can get things going with 'next', 'step', or + 'cont'. + + + There is a transcript of a debugging session here , with breakpoints being set in the scheduler and in an + interrupt handler. + 1111..22.. EExxaammiinniinngg sslleeeeppiinngg pprroocceesssseess + + Not every bug is evident in the currently running process. Sometimes, + processes hang in the kernel when they shouldn't because they've + deadlocked on a semaphore or something similar. In this case, when + you ^C gdb and get a backtrace, you will see the idle thread, which + isn't very relevant. + + + What you want is the stack of whatever process is sleeping when it + shouldn't be. You need to figure out which process that is, which is + generally fairly easy. Then you need to get its host process id, + which you can do either by looking at ps on the host or at + task.thread.extern_pid in gdb. + + + Now what you do is this: + + +o detach from the current thread + + + (UML gdb) det + + + + + + +o attach to the thread you are interested in + + + (UML gdb) att + + + + + + +o look at its stack and anything else of interest + + + (UML gdb) bt + + + + + Note that you can't do anything at this point that requires that a + process execute, e.g. calling a function + + +o when you're done looking at that process, reattach to the current + thread and continue it + + + (UML gdb) + att 1 + + + + + + + (UML gdb) + c + + + + + Here, specifying any pid which is not the process id of a UML thread + will cause gdb to reattach to the current thread. I commonly use 1, + but any other invalid pid would work. + + + + 1111..33.. RRuunnnniinngg dddddd oonn UUMMLL + + ddd works on UML, but requires a special kludge. The process goes + like this: + + +o Start ddd + + + host% ddd linux + + + + + + +o With ps, get the pid of the gdb that ddd started. You can ask the + gdb to tell you, but for some reason that confuses things and + causes a hang. + + +o run UML with 'debug=parent gdb-pid=' added to the command line + - it will just sit there after you hit return + + +o type 'att 1' to the ddd gdb and you will see something like + + + 0xa013dc51 in __kill () + + + (gdb) + + + + + + +o At this point, type 'c', UML will boot up, and you can use ddd just + as you do on any other process. + + + + 1111..44.. DDeebbuuggggiinngg mmoodduulleess + + gdb has support for debugging code which is dynamically loaded into + the process. This support is what is needed to debug kernel modules + under UML. + + + Using that support is somewhat complicated. You have to tell gdb what + object file you just loaded into UML and where in memory it is. Then, + it can read the symbol table, and figure out where all the symbols are + from the load address that you provided. It gets more interesting + when you load the module again (i.e. after an rmmod). You have to + tell gdb to forget about all its symbols, including the main UML ones + for some reason, then load then all back in again. + + + There's an easy way and a hard way to do this. The easy way is to use + the umlgdb expect script written by Chandan Kudige. It basically + automates the process for you. + + + First, you must tell it where your modules are. There is a list in + the script that looks like this: + set MODULE_PATHS { + "fat" "/usr/src/uml/linux-2.4.18/fs/fat/fat.o" + "isofs" "/usr/src/uml/linux-2.4.18/fs/isofs/isofs.o" + "minix" "/usr/src/uml/linux-2.4.18/fs/minix/minix.o" + } + + + + + You change that to list the names and paths of the modules that you + are going to debug. Then you run it from the toplevel directory of + your UML pool and it basically tells you what to do: + + + + + ******** GDB pid is 21903 ******** + Start UML as: ./linux debug gdb-pid=21903 + + + + GNU gdb 5.0rh-5 Red Hat Linux 7.1 + Copyright 2001 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux"... + (gdb) b sys_init_module + Breakpoint 1 at 0xa0011923: file module.c, line 349. + (gdb) att 1 + + + + + After you run UML and it sits there doing nothing, you hit return at + the 'att 1' and continue it: + + + Attaching to program: /home/jdike/linux/2.4/um/./linux, process 1 + 0xa00f4221 in __kill () + (UML gdb) c + Continuing. + + + + + At this point, you debug normally. When you insmod something, the + expect magic will kick in and you'll see something like: + + + + + + + + + + + + + + + + + + *** Module hostfs loaded *** + Breakpoint 1, sys_init_module (name_user=0x805abb0 "hostfs", + mod_user=0x8070e00) at module.c:349 + 349 char *name, *n_name, *name_tmp = NULL; + (UML gdb) finish + Run till exit from #0 sys_init_module (name_user=0x805abb0 "hostfs", + mod_user=0x8070e00) at module.c:349 + 0xa00e2e23 in execute_syscall (r=0xa8140284) at syscall_kern.c:411 + 411 else res = EXECUTE_SYSCALL(syscall, regs); + Value returned is $1 = 0 + (UML gdb) + p/x (int)module_list + module_list->size_of_struct + + $2 = 0xa9021054 + (UML gdb) symbol-file ./linux + Load new symbol table from "./linux"? (y or n) y + Reading symbols from ./linux... + done. + (UML gdb) + add-symbol-file /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o 0xa9021054 + + add symbol table from file "/home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o" at + .text_addr = 0xa9021054 + (y or n) y + + Reading symbols from /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o... + done. + (UML gdb) p *module_list + $1 = {size_of_struct = 84, next = 0xa0178720, name = 0xa9022de0 "hostfs", + size = 9016, uc = {usecount = {counter = 0}, pad = 0}, flags = 1, + nsyms = 57, ndeps = 0, syms = 0xa9023170, deps = 0x0, refs = 0x0, + init = 0xa90221f0 , cleanup = 0xa902222c , + ex_table_start = 0x0, ex_table_end = 0x0, persist_start = 0x0, + persist_end = 0x0, can_unload = 0, runsize = 0, kallsyms_start = 0x0, + kallsyms_end = 0x0, + archdata_start = 0x1b855
, + archdata_end = 0xe5890000
, + kernel_data = 0xf689c35d
} + >> Finished loading symbols for hostfs ... + + + + + That's the easy way. It's highly recommended. The hard way is + described below in case you're interested in what's going on. + + + Boot the kernel under the debugger and load the module with insmod or + modprobe. With gdb, do: + + + (UML gdb) p module_list + + + + + This is a list of modules that have been loaded into the kernel, with + the most recently loaded module first. Normally, the module you want + is at module_list. If it's not, walk down the next links, looking at + the name fields until find the module you want to debug. Take the + address of that structure, and add module.size_of_struct (which in + 2.4.10 kernels is 96 (0x60)) to it. Gdb can make this hard addition + for you :-): + + + + (UML gdb) + printf "%#x\n", (int)module_list module_list->size_of_struct + + + + + The offset from the module start occasionally changes (before 2.4.0, + it was module.size_of_struct + 4), so it's a good idea to check the + init and cleanup addresses once in a while, as describe below. Now + do: + + + (UML gdb) + add-symbol-file /path/to/module/on/host that_address + + + + + Tell gdb you really want to do it, and you're in business. + + + If there's any doubt that you got the offset right, like breakpoints + appear not to work, or they're appearing in the wrong place, you can + check it by looking at the module structure. The init and cleanup + fields should look like: + + + init = 0x588066b0 , cleanup = 0x588066c0 + + + + + with no offsets on the symbol names. If the names are right, but they + are offset, then the offset tells you how much you need to add to the + address you gave to add-symbol-file. + + + When you want to load in a new version of the module, you need to get + gdb to forget about the old one. The only way I've found to do that + is to tell gdb to forget about all symbols that it knows about: + + + (UML gdb) symbol-file + + + + + Then reload the symbols from the kernel binary: + + + (UML gdb) symbol-file /path/to/kernel + + + + + and repeat the process above. You'll also need to re-enable break- + points. They were disabled when you dumped all the symbols because + gdb couldn't figure out where they should go. + + + + 1111..55.. AAttttaacchhiinngg ggddbb ttoo tthhee kkeerrnneell + + If you don't have the kernel running under gdb, you can attach gdb to + it later by sending the tracing thread a SIGUSR1. The first line of + the console output identifies its pid: + tracing thread pid = 20093 + + + + + When you send it the signal: + + + host% kill -USR1 20093 + + + + + you will get an xterm with gdb running in it. + + + If you have the mconsole compiled into UML, then the mconsole client + can be used to start gdb: + + + (mconsole) (mconsole) config gdb=xterm + + + + + will fire up an xterm with gdb running in it. + + + + 1111..66.. UUssiinngg aalltteerrnnaattee ddeebbuuggggeerrss + + UML has support for attaching to an already running debugger rather + than starting gdb itself. This is present in CVS as of 17 Apr 2001. + I sent it to Alan for inclusion in the ac tree, and it will be in my + 2.4.4 release. + + + This is useful when gdb is a subprocess of some UI, such as emacs or + ddd. It can also be used to run debuggers other than gdb on UML. + Below is an example of using strace as an alternate debugger. + + + To do this, you need to get the pid of the debugger and pass it in + with the + + + If you are using gdb under some UI, then tell it to 'att 1', and + you'll find yourself attached to UML. + + + If you are using something other than gdb as your debugger, then + you'll need to get it to do the equivalent of 'att 1' if it doesn't do + it automatically. + + + An example of an alternate debugger is strace. You can strace the + actual kernel as follows: + + +o Run the following in a shell + + + host% + sh -c 'echo pid=$$; echo -n hit return; read x; exec strace -p 1 -o strace.out' + + + + +o Run UML with 'debug' and 'gdb-pid=' with the pid printed out + by the previous command + + +o Hit return in the shell, and UML will start running, and strace + output will start accumulating in the output file. + + Note that this is different from running + + + host% strace ./linux + + + + + That will strace only the main UML thread, the tracing thread, which + doesn't do any of the actual kernel work. It just oversees the vir- + tual machine. In contrast, using strace as described above will show + you the low-level activity of the virtual machine. + + + + + + 1122.. KKeerrnneell ddeebbuuggggiinngg eexxaammpplleess + + 1122..11.. TThhee ccaassee ooff tthhee hhuunngg ffsscckk + + When booting up the kernel, fsck failed, and dropped me into a shell + to fix things up. I ran fsck -y, which hung: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Setting hostname uml [ OK ] + Checking root filesystem + /dev/fhd0 was not cleanly unmounted, check forced. + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. + + /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. + (i.e., without -a or -p options) + [ FAILED ] + + *** An error occurred during the file system check. + *** Dropping you to a shell; the system will reboot + *** when you leave the shell. + Give root password for maintenance + (or type Control-D for normal startup): + + [root@uml /root]# fsck -y /dev/fhd0 + fsck -y /dev/fhd0 + Parallelizing fsck version 1.14 (9-Jan-1999) + e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09 + /dev/fhd0 contains a file system with errors, check forced. + Pass 1: Checking inodes, blocks, and sizes + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes + + Inode 19780, i_blocks is 1548, should be 540. Fix? yes + + Pass 2: Checking directory structure + Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes + + Directory inode 11858, block 0, offset 0: directory corrupted + Salvage? yes + + Missing '.' in directory inode 11858. + Fix? yes + + Missing '..' in directory inode 11858. + Fix? yes + + + + + + The standard drill in this sort of situation is to fire up gdb on the + signal thread, which, in this case, was pid 1935. In another window, + I run gdb and attach pid 1935. + + + + + ~/linux/2.3.26/um 1016: gdb linux + GNU gdb 4.17.0.11 with Linux support + Copyright 1998 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux"... + + (gdb) att 1935 + Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1935 + 0x100756d9 in __wait4 () + + + + + + + Let's see what's currently running: + + + + (gdb) p current_task.pid + $1 = 0 + + + + + + It's the idle thread, which means that fsck went to sleep for some + reason and never woke up. + + + Let's guess that the last process in the process list is fsck: + + + + (gdb) p current_task.prev_task.comm + $13 = "fsck.ext2\000\000\000\000\000\000" + + + + + + It is, so let's see what it thinks it's up to: + + + + (gdb) p current_task.prev_task.thread + $14 = {extern_pid = 1980, tracing = 0, want_tracing = 0, forking = 0, + kernel_stack_page = 0, signal_stack = 1342627840, syscall = {id = 4, args = { + 3, 134973440, 1024, 0, 1024}, have_result = 0, result = 50590720}, + request = {op = 2, u = {exec = {ip = 1350467584, sp = 2952789424}, fork = { + regs = {1350467584, 2952789424, 0 }, sigstack = 0, + pid = 0}, switch_to = 0x507e8000, thread = {proc = 0x507e8000, + arg = 0xaffffdb0, flags = 0, new_pid = 0}, input_request = { + op = 1350467584, fd = -1342177872, proc = 0, pid = 0}}}} + + + + + + The interesting things here are the fact that its .thread.syscall.id + is __NR_write (see the big switch in arch/um/kernel/syscall_kern.c or + the defines in include/asm-um/arch/unistd.h), and that it never + returned. Also, its .request.op is OP_SWITCH (see + arch/um/include/user_util.h). These mean that it went into a write, + and, for some reason, called schedule(). + + + The fact that it never returned from write means that its stack should + be fairly interesting. Its pid is 1980 (.thread.extern_pid). That + process is being ptraced by the signal thread, so it must be detached + before gdb can attach it: + + + + + + + + + + + (gdb) call detach(1980) + + Program received signal SIGSEGV, Segmentation fault. + + The program being debugged stopped while in a function called from GDB. + When the function (detach) is done executing, GDB will silently + stop (instead of continuing to evaluate the expression containing + the function call). + (gdb) call detach(1980) + $15 = 0 + + + + + + The first detach segfaults for some reason, and the second one + succeeds. + + + Now I detach from the signal thread, attach to the fsck thread, and + look at its stack: + + + (gdb) det + Detaching from program: /home/dike/linux/2.3.26/um/linux Pid 1935 + (gdb) att 1980 + Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1980 + 0x10070451 in __kill () + (gdb) bt + #0 0x10070451 in __kill () + #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30 + #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000) + at process_kern.c:156 + #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000) + at process_kern.c:161 + #4 0x10001d12 in schedule () at sched.c:777 + #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71 + #6 0x1006aa10 in __down_failed () at semaphore.c:157 + #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174 + #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 + #9 + #10 0x10155404 in errno () + #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50 + #12 0x1006c5d8 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 + #13 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 + #14 + #15 0xc0fd in ?? () + #16 0x10016647 in sys_write (fd=3, + buf=0x80b8800
, count=1024) + at read_write.c:159 + #17 0x1006d5b3 in execute_syscall (syscall=4, args=0x5006ef08) + at syscall_kern.c:254 + #18 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35 + #19 + #20 0x400dc8b0 in ?? () + + + + + + The interesting things here are : + + +o There are two segfaults on this stack (frames 9 and 14) + + +o The first faulting address (frame 11) is 0x50000800 + + (gdb) p (void *)1342179328 + $16 = (void *) 0x50000800 + + + + + + The initial faulting address is interesting because it is on the idle + thread's stack. I had been seeing the idle thread segfault for no + apparent reason, and the cause looked like stack corruption. In hopes + of catching the culprit in the act, I had turned off all protections + to that stack while the idle thread wasn't running. This apparently + tripped that trap. + + + However, the more immediate problem is that second segfault and I'm + going to concentrate on that. First, I want to see where the fault + happened, so I have to go look at the sigcontent struct in frame 8: + + + + (gdb) up + #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30 + 30 kill(pid, SIGUSR1); + (gdb) + #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000) + at process_kern.c:156 + 156 usr1_pid(getpid()); + (gdb) + #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000) + at process_kern.c:161 + 161 _switch_to(prev, next); + (gdb) + #4 0x10001d12 in schedule () at sched.c:777 + 777 switch_to(prev, next, prev); + (gdb) + #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71 + 71 schedule(); + (gdb) + #6 0x1006aa10 in __down_failed () at semaphore.c:157 + 157 } + (gdb) + #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174 + 174 segv(sc->cr2, sc->err & 2); + (gdb) + #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 + 182 segv_handler(sc); + (gdb) p *sc + Cannot access memory at address 0x0. + + + + + That's not very useful, so I'll try a more manual method: + + + (gdb) p *((struct sigcontext *) (&sig + 1)) + $19 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43, + __dsh = 0, edi = 1342179328, esi = 1350378548, ebp = 1342630440, + esp = 1342630420, ebx = 1348150624, edx = 1280, ecx = 0, eax = 0, + trapno = 14, err = 4, eip = 268480945, cs = 35, __csh = 0, eflags = 66118, + esp_at_signal = 1342630420, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0, + cr2 = 1280} + + + + The ip is in handle_mm_fault: + + + (gdb) p (void *)268480945 + $20 = (void *) 0x1000b1b1 + (gdb) i sym $20 + handle_mm_fault + 57 in section .text + + + + + + Specifically, it's in pte_alloc: + + + (gdb) i line *$20 + Line 124 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1b1 + and ends at 0x1000b1b7 . + + + + + + To find where in handle_mm_fault this is, I'll jump forward in the + code until I see an address in that procedure: + + + + (gdb) i line *0x1000b1c0 + Line 126 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1b7 + and ends at 0x1000b1c3 . + (gdb) i line *0x1000b1d0 + Line 131 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1d0 + and ends at 0x1000b1da . + (gdb) i line *0x1000b1e0 + Line 61 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1da + and ends at 0x1000b1e1 . + (gdb) i line *0x1000b1f0 + Line 134 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1f0 + and ends at 0x1000b200 . + (gdb) i line *0x1000b200 + Line 135 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b200 + and ends at 0x1000b208 . + (gdb) i line *0x1000b210 + Line 139 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b210 + and ends at 0x1000b219 . + (gdb) i line *0x1000b220 + Line 1168 of "memory.c" starts at address 0x1000b21e + and ends at 0x1000b222 . + + + + + + Something is apparently wrong with the page tables or vma_structs, so + lets go back to frame 11 and have a look at them: + + + + #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50 + 50 handle_mm_fault(current, vma, address, is_write); + (gdb) call pgd_offset_proc(vma->vm_mm, address) + $22 = (pgd_t *) 0x80a548c + + + + + + That's pretty bogus. Page tables aren't supposed to be in process + text or data areas. Let's see what's in the vma: + + + (gdb) p *vma + $23 = {vm_mm = 0x507d2434, vm_start = 0, vm_end = 134512640, + vm_next = 0x80a4f8c, vm_page_prot = {pgprot = 0}, vm_flags = 31200, + vm_avl_height = 2058, vm_avl_left = 0x80a8c94, vm_avl_right = 0x80d1000, + vm_next_share = 0xaffffdb0, vm_pprev_share = 0xaffffe63, + vm_ops = 0xaffffe7a, vm_pgoff = 2952789626, vm_file = 0xafffffec, + vm_private_data = 0x62} + (gdb) p *vma.vm_mm + $24 = {mmap = 0x507d2434, mmap_avl = 0x0, mmap_cache = 0x8048000, + pgd = 0x80a4f8c, mm_users = {counter = 0}, mm_count = {counter = 134904288}, + map_count = 134909076, mmap_sem = {count = {counter = 135073792}, + sleepers = -1342177872, wait = {lock = , + task_list = {next = 0xaffffe63, prev = 0xaffffe7a}, + __magic = -1342177670, __creator = -1342177300}, __magic = 98}, + page_table_lock = {}, context = 138, start_code = 0, end_code = 0, + start_data = 0, end_data = 0, start_brk = 0, brk = 0, start_stack = 0, + arg_start = 0, arg_end = 0, env_start = 0, env_end = 0, rss = 1350381536, + total_vm = 0, locked_vm = 0, def_flags = 0, cpu_vm_mask = 0, swap_cnt = 0, + swap_address = 0, segments = 0x0} + + + + + + This also pretty bogus. With all of the 0x80xxxxx and 0xaffffxxx + addresses, this is looking like a stack was plonked down on top of + these structures. Maybe it's a stack overflow from the next page: + + + + (gdb) p vma + $25 = (struct vm_area_struct *) 0x507d2434 + + + + + + That's towards the lower quarter of the page, so that would have to + have been pretty heavy stack overflow: + + + + + + + + + + + + + + + (gdb) x/100x $25 + 0x507d2434: 0x507d2434 0x00000000 0x08048000 0x080a4f8c + 0x507d2444: 0x00000000 0x080a79e0 0x080a8c94 0x080d1000 + 0x507d2454: 0xaffffdb0 0xaffffe63 0xaffffe7a 0xaffffe7a + 0x507d2464: 0xafffffec 0x00000062 0x0000008a 0x00000000 + 0x507d2474: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2484: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2494: 0x00000000 0x00000000 0x507d2fe0 0x00000000 + 0x507d24a4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24b4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24c4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24d4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24e4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24f4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2504: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2514: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2524: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2534: 0x00000000 0x00000000 0x507d25dc 0x00000000 + 0x507d2544: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2554: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2564: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2574: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2584: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2594: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d25a4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d25b4: 0x00000000 0x00000000 0x00000000 0x00000000 + + + + + + It's not stack overflow. The only "stack-like" piece of this data is + the vma_struct itself. + + + At this point, I don't see any avenues to pursue, so I just have to + admit that I have no idea what's going on. What I will do, though, is + stick a trap on the segfault handler which will stop if it sees any + writes to the idle thread's stack. That was the thing that happened + first, and it may be that if I can catch it immediately, what's going + on will be somewhat clearer. + + + 1122..22.. EEppiissooddee 22:: TThhee ccaassee ooff tthhee hhuunngg ffsscckk + + After setting a trap in the SEGV handler for accesses to the signal + thread's stack, I reran the kernel. + + + fsck hung again, this time by hitting the trap: + + + + + + + + + + + + + + + + + Setting hostname uml [ OK ] + Checking root filesystem + /dev/fhd0 contains a file system with errors, check forced. + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. + + /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. + (i.e., without -a or -p options) + [ FAILED ] + + *** An error occurred during the file system check. + *** Dropping you to a shell; the system will reboot + *** when you leave the shell. + Give root password for maintenance + (or type Control-D for normal startup): + + [root@uml /root]# fsck -y /dev/fhd0 + fsck -y /dev/fhd0 + Parallelizing fsck version 1.14 (9-Jan-1999) + e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09 + /dev/fhd0 contains a file system with errors, check forced. + Pass 1: Checking inodes, blocks, and sizes + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes + + Pass 2: Checking directory structure + Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes + + Directory inode 11858, block 0, offset 0: directory corrupted + Salvage? yes + + Missing '.' in directory inode 11858. + Fix? yes + + Missing '..' in directory inode 11858. + Fix? yes + + Untested (4127) [100fe44c]: trap_kern.c line 31 + + + + + + I need to get the signal thread to detach from pid 4127 so that I can + attach to it with gdb. This is done by sending it a SIGUSR1, which is + caught by the signal thread, which detaches the process: + + + kill -USR1 4127 + + + + + + Now I can run gdb on it: + + + + + + + + + + + + + + ~/linux/2.3.26/um 1034: gdb linux + GNU gdb 4.17.0.11 with Linux support + Copyright 1998 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux"... + (gdb) att 4127 + Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 4127 + 0x10075891 in __libc_nanosleep () + + + + + + The backtrace shows that it was in a write and that the fault address + (address in frame 3) is 0x50000800, which is right in the middle of + the signal thread's stack page: + + + (gdb) bt + #0 0x10075891 in __libc_nanosleep () + #1 0x1007584d in __sleep (seconds=1000000) + at ../sysdeps/unix/sysv/linux/sleep.c:78 + #2 0x1006ce9a in stop () at user_util.c:191 + #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31 + #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 + #5 0x1006c63c in kern_segv_handler (sig=11) at trap_user.c:182 + #6 + #7 0xc0fd in ?? () + #8 0x10016647 in sys_write (fd=3, buf=0x80b8800 "R.", count=1024) + at read_write.c:159 + #9 0x1006d603 in execute_syscall (syscall=4, args=0x5006ef08) + at syscall_kern.c:254 + #10 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35 + #11 + #12 0x400dc8b0 in ?? () + #13 + #14 0x400dc8b0 in ?? () + #15 0x80545fd in ?? () + #16 0x804daae in ?? () + #17 0x8054334 in ?? () + #18 0x804d23e in ?? () + #19 0x8049632 in ?? () + #20 0x80491d2 in ?? () + #21 0x80596b5 in ?? () + (gdb) p (void *)1342179328 + $3 = (void *) 0x50000800 + + + + + + Going up the stack to the segv_handler frame and looking at where in + the code the access happened shows that it happened near line 110 of + block_dev.c: + + + + + + + + + + (gdb) up + #1 0x1007584d in __sleep (seconds=1000000) + at ../sysdeps/unix/sysv/linux/sleep.c:78 + ../sysdeps/unix/sysv/linux/sleep.c:78: No such file or directory. + (gdb) + #2 0x1006ce9a in stop () at user_util.c:191 + 191 while(1) sleep(1000000); + (gdb) + #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31 + 31 KERN_UNTESTED(); + (gdb) + #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 + 174 segv(sc->cr2, sc->err & 2); + (gdb) p *sc + $1 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43, + __dsh = 0, edi = 1342179328, esi = 134973440, ebp = 1342631484, + esp = 1342630864, ebx = 256, edx = 0, ecx = 256, eax = 1024, trapno = 14, + err = 6, eip = 268550834, cs = 35, __csh = 0, eflags = 66070, + esp_at_signal = 1342630864, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0, + cr2 = 1342179328} + (gdb) p (void *)268550834 + $2 = (void *) 0x1001c2b2 + (gdb) i sym $2 + block_write + 1090 in section .text + (gdb) i line *$2 + Line 209 of "/home/dike/linux/2.3.26/um/include/asm/arch/string.h" + starts at address 0x1001c2a1 + and ends at 0x1001c2bf . + (gdb) i line *0x1001c2c0 + Line 110 of "block_dev.c" starts at address 0x1001c2bf + and ends at 0x1001c2e3 . + + + + + + Looking at the source shows that the fault happened during a call to + copy_to_user to copy the data into the kernel: + + + 107 count -= chars; + 108 copy_from_user(p,buf,chars); + 109 p += chars; + 110 buf += chars; + + + + + + p is the pointer which must contain 0x50000800, since buf contains + 0x80b8800 (frame 8 above). It is defined as: + + + p = offset + bh->b_data; + + + + + + I need to figure out what bh is, and it just so happens that bh is + passed as an argument to mark_buffer_uptodate and mark_buffer_dirty a + few lines later, so I do a little disassembly: + + + + + (gdb) disas 0x1001c2bf 0x1001c2e0 + Dump of assembler code from 0x1001c2bf to 0x1001c2d0: + 0x1001c2bf : addl %eax,0xc(%ebp) + 0x1001c2c2 : movl 0xfffffdd4(%ebp),%edx + 0x1001c2c8 : btsl $0x0,0x18(%edx) + 0x1001c2cd : btsl $0x1,0x18(%edx) + 0x1001c2d2 : sbbl %ecx,%ecx + 0x1001c2d4 : testl %ecx,%ecx + 0x1001c2d6 : jne 0x1001c2e3 + 0x1001c2d8 : pushl $0x0 + 0x1001c2da : pushl %edx + 0x1001c2db : call 0x1001819c <__mark_buffer_dirty> + End of assembler dump. + + + + + + At that point, bh is in %edx (address 0x1001c2da), which is calculated + at 0x1001c2c2 as %ebp + 0xfffffdd4, so I figure exactly what that is, + taking %ebp from the sigcontext_struct above: + + + (gdb) p (void *)1342631484 + $5 = (void *) 0x5006ee3c + (gdb) p 0x5006ee3c+0xfffffdd4 + $6 = 1342630928 + (gdb) p (void *)$6 + $7 = (void *) 0x5006ec10 + (gdb) p *((void **)$7) + $8 = (void *) 0x50100200 + + + + + + Now, I look at the structure to see what's in it, and particularly, + what its b_data field contains: + + + (gdb) p *((struct buffer_head *)0x50100200) + $13 = {b_next = 0x50289380, b_blocknr = 49405, b_size = 1024, b_list = 0, + b_dev = 15872, b_count = {counter = 1}, b_rdev = 15872, b_state = 24, + b_flushtime = 0, b_next_free = 0x501001a0, b_prev_free = 0x50100260, + b_this_page = 0x501001a0, b_reqnext = 0x0, b_pprev = 0x507fcf58, + b_data = 0x50000800 "", b_page = 0x50004000, + b_end_io = 0x10017f60 , b_dev_id = 0x0, + b_rsector = 98810, b_wait = {lock = , + task_list = {next = 0x50100248, prev = 0x50100248}, __magic = 1343226448, + __creator = 0}, b_kiobuf = 0x0} + + + + + + The b_data field is indeed 0x50000800, so the question becomes how + that happened. The rest of the structure looks fine, so this probably + is not a case of data corruption. It happened on purpose somehow. + + + The b_page field is a pointer to the page_struct representing the + 0x50000000 page. Looking at it shows the kernel's idea of the state + of that page: + + + + (gdb) p *$13.b_page + $17 = {list = {next = 0x50004a5c, prev = 0x100c5174}, mapping = 0x0, + index = 0, next_hash = 0x0, count = {counter = 1}, flags = 132, lru = { + next = 0x50008460, prev = 0x50019350}, wait = { + lock = , task_list = {next = 0x50004024, + prev = 0x50004024}, __magic = 1342193708, __creator = 0}, + pprev_hash = 0x0, buffers = 0x501002c0, virtual = 1342177280, + zone = 0x100c5160} + + + + + + Some sanity-checking: the virtual field shows the "virtual" address of + this page, which in this kernel is the same as its "physical" address, + and the page_struct itself should be mem_map[0], since it represents + the first page of memory: + + + + (gdb) p (void *)1342177280 + $18 = (void *) 0x50000000 + (gdb) p mem_map + $19 = (mem_map_t *) 0x50004000 + + + + + + These check out fine. + + + Now to check out the page_struct itself. In particular, the flags + field shows whether the page is considered free or not: + + + (gdb) p (void *)132 + $21 = (void *) 0x84 + + + + + + The "reserved" bit is the high bit, which is definitely not set, so + the kernel considers the signal stack page to be free and available to + be used. + + + At this point, I jump to conclusions and start looking at my early + boot code, because that's where that page is supposed to be reserved. + + + In my setup_arch procedure, I have the following code which looks just + fine: + + + + bootmap_size = init_bootmem(start_pfn, end_pfn - start_pfn); + free_bootmem(__pa(low_physmem) + bootmap_size, high_physmem - low_physmem); + + + + + + Two stack pages have already been allocated, and low_physmem points to + the third page, which is the beginning of free memory. + The init_bootmem call declares the entire memory to the boot memory + manager, which marks it all reserved. The free_bootmem call frees up + all of it, except for the first two pages. This looks correct to me. + + + So, I decide to see init_bootmem run and make sure that it is marking + those first two pages as reserved. I never get that far. + + + Stepping into init_bootmem, and looking at bootmem_map before looking + at what it contains shows the following: + + + + (gdb) p bootmem_map + $3 = (void *) 0x50000000 + + + + + + Aha! The light dawns. That first page is doing double duty as a + stack and as the boot memory map. The last thing that the boot memory + manager does is to free the pages used by its memory map, so this page + is getting freed even its marked as reserved. + + + The fix was to initialize the boot memory manager before allocating + those two stack pages, and then allocate them through the boot memory + manager. After doing this, and fixing a couple of subsequent buglets, + the stack corruption problem disappeared. + + + + + + 1133.. WWhhaatt ttoo ddoo wwhheenn UUMMLL ddooeessnn''tt wwoorrkk + + + + + 1133..11.. SSttrraannggee ccoommppiillaattiioonn eerrrroorrss wwhheenn yyoouu bbuuiilldd ffrroomm ssoouurrccee + + As of test11, it is necessary to have "ARCH=um" in the environment or + on the make command line for all steps in building UML, including + clean, distclean, or mrproper, config, menuconfig, or xconfig, dep, + and linux. If you forget for any of them, the i386 build seems to + contaminate the UML build. If this happens, start from scratch with + + + host% + make mrproper ARCH=um + + + + + and repeat the build process with ARCH=um on all the steps. + + + See ``Compiling the kernel and modules'' for more details. + + + Another cause of strange compilation errors is building UML in + /usr/src/linux. If you do this, the first thing you need to do is + clean up the mess you made. The /usr/src/linux/asm link will now + point to /usr/src/linux/asm-um. Make it point back to + /usr/src/linux/asm-i386. Then, move your UML pool someplace else and + build it there. Also see below, where a more specific set of symptoms + is described. + + + + 1133..22.. UUMMLL hhaannggss oonn bboooott aafftteerr mmoouunnttiinngg ddeevvffss + + The boot looks like this: + + + VFS: Mounted root (ext2 filesystem) readonly. + Mounted devfs on /dev + + + + + You're probably running a recent distribution on an old machine. I + saw this with the RH7.1 filesystem running on a Pentium. The shared + library loader, ld.so, was executing an instruction (cmove) which the + Pentium didn't support. That instruction was apparently added later. + If you run UML under the debugger, you'll see the hang caused by one + instruction causing an infinite SIGILL stream. + + + The fix is to boot UML on an older filesystem. + + + + 1133..33.. AA vvaarriieettyy ooff ppaanniiccss aanndd hhaannggss wwiitthh //ttmmpp oonn aa rreeiisseerrffss ffiilleessyyss-- + tteemm + + I saw this on reiserfs 3.5.21 and it seems to be fixed in 3.5.27. + Panics preceded by + + + Detaching pid nnnn + + + + are diagnostic of this problem. This is a reiserfs bug which causes a + thread to occasionally read stale data from a mmapped page shared with + another thread. The fix is to upgrade the filesystem or to have /tmp + be an ext2 filesystem. + + + + 1133..44.. TThhee ccoommppiillee ffaaiillss wwiitthh eerrrroorrss aabboouutt ccoonnfflliiccttiinngg ttyyppeess ffoorr + ''ooppeenn'',, ''dduupp'',, aanndd ''wwaaiittppiidd'' + + This happens when you build in /usr/src/linux. The UML build makes + the include/asm link point to include/asm-um. /usr/include/asm points + to /usr/src/linux/include/asm, so when that link gets moved, files + which need to include the asm-i386 versions of headers get the + incompatible asm-um versions. The fix is to move the include/asm link + back to include/asm-i386 and to do UML builds someplace else. + + + + 1133..55.. UUMMLL ddooeessnn''tt wwoorrkk wwhheenn //ttmmpp iiss aann NNFFSS ffiilleessyysstteemm + + This seems to be a similar situation with the resierfs problem above. + Some versions of NFS seems not to handle mmap correctly, which UML + depends on. The workaround is have /tmp be non-NFS directory. + + + 1133..66.. UUMMLL hhaannggss oonn bboooott wwhheenn ccoommppiilleedd wwiitthh ggpprrooff ssuuppppoorrtt + + If you build UML with gprof support and, early in the boot, it does + this + + + kernel BUG at page_alloc.c:100! + + + + + you have a buggy gcc. You can work around the problem by removing + UM_FASTCALL from CFLAGS in arch/um/Makefile-i386. This will open up + another bug, but that one is fairly hard to reproduce. + + + + 1133..77.. ssyyssllooggdd ddiieess wwiitthh aa SSIIGGTTEERRMM oonn ssttaarrttuupp + + The exact boot error depends on the distribution that you're booting, + but Debian produces this: + + + /etc/rc2.d/S10sysklogd: line 49: 93 Terminated + start-stop-daemon --start --quiet --exec /sbin/syslogd -- $SYSLOGD + + + + + This is a syslogd bug. There's a race between a parent process + installing a signal handler and its child sending the signal. See + this uml-devel post for the details. + + + + 1133..88.. TTUUNN//TTAAPP nneettwwoorrkkiinngg ddooeessnn''tt wwoorrkk oonn aa 22..44 hhoosstt + + There are a couple of problems which were + name="pointed + out"> by Tim Robinson + + +o It doesn't work on hosts running 2.4.7 (or thereabouts) or earlier. + The fix is to upgrade to something more recent and then read the + next item. + + +o If you see + + + File descriptor in bad state + + + + when you bring up the device inside UML, you have a header mismatch + between the original kernel and the upgraded one. Make /usr/src/linux + point at the new headers. This will only be a problem if you build + uml_net yourself. + + + + 1133..99.. YYoouu ccaann nneettwwoorrkk ttoo tthhee hhoosstt bbuutt nnoott ttoo ootthheerr mmaacchhiinneess oonn tthhee + nneett + + If you can connect to the host, and the host can connect to UML, but + you can not connect to any other machines, then you may need to enable + IP Masquerading on the host. Usually this is only experienced when + using private IP addresses (192.168.x.x or 10.x.x.x) for host/UML + networking, rather than the public address space that your host is + connected to. UML does not enable IP Masquerading, so you will need + to create a static rule to enable it: + + + host% + iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE + + + + + Replace eth0 with the interface that you use to talk to the rest of + the world. + + + Documentation on IP Masquerading, and SNAT, can be found at + www.netfilter.org . + + + If you can reach the local net, but not the outside Internet, then + that is usually a routing problem. The UML needs a default route: + + + UML# + route add default gw gateway IP + + + + + The gateway IP can be any machine on the local net that knows how to + reach the outside world. Usually, this is the host or the local net- + work's gateway. + + + Occasionally, we hear from someone who can reach some machines, but + not others on the same net, or who can reach some ports on other + machines, but not others. These are usually caused by strange + firewalling somewhere between the UML and the other box. You track + this down by running tcpdump on every interface the packets travel + over and see where they disappear. When you find a machine that takes + the packets in, but does not send them onward, that's the culprit. + + + + 1133..1100.. II hhaavvee nnoo rroooott aanndd II wwaanntt ttoo ssccrreeaamm + + Thanks to Birgit Wahlich for telling me about this strange one. It + turns out that there's a limit of six environment variables on the + kernel command line. When that limit is reached or exceeded, argument + processing stops, which means that the 'root=' argument that UML + usually adds is not seen. So, the filesystem has no idea what the + root device is, so it panics. + + + The fix is to put less stuff on the command line. Glomming all your + setup variables into one is probably the best way to go. + + + + 1133..1111.. UUMMLL bbuuiilldd ccoonnfflliicctt bbeettwweeeenn ppttrraaccee..hh aanndd uuccoonntteexxtt..hh + + On some older systems, /usr/include/asm/ptrace.h and + /usr/include/sys/ucontext.h define the same names. So, when they're + included together, the defines from one completely mess up the parsing + of the other, producing errors like: + /usr/include/sys/ucontext.h:47: parse error before + `10' + + + + + plus a pile of warnings. + + + This is a libc botch, which has since been fixed, and I don't see any + way around it besides upgrading. + + + + 1133..1122.. TThhee UUMMLL BBooggooMMiippss iiss eexxaaccttllyy hhaallff tthhee hhoosstt''ss BBooggooMMiippss + + On i386 kernels, there are two ways of running the loop that is used + to calculate the BogoMips rating, using the TSC if it's there or using + a one-instruction loop. The TSC produces twice the BogoMips as the + loop. UML uses the loop, since it has nothing resembling a TSC, and + will get almost exactly the same BogoMips as a host using the loop. + However, on a host with a TSC, its BogoMips will be double the loop + BogoMips, and therefore double the UML BogoMips. + + + + 1133..1133.. WWhheenn yyoouu rruunn UUMMLL,, iitt iimmmmeeddiiaatteellyy sseeggffaauullttss + + If the host is configured with the 2G/2G address space split, that's + why. See ``UML on 2G/2G hosts'' for the details on getting UML to + run on your host. + + + + 1133..1144.. xxtteerrmmss aappppeeaarr,, tthheenn iimmmmeeddiiaatteellyy ddiissaappppeeaarr + + If you're running an up to date kernel with an old release of + uml_utilities, the port-helper program will not work properly, so + xterms will exit straight after they appear. The solution is to + upgrade to the latest release of uml_utilities. Usually this problem + occurs when you have installed a packaged release of UML then compiled + your own development kernel without upgrading the uml_utilities from + the source distribution. + + + + 1133..1155.. AAnnyy ootthheerr ppaanniicc,, hhaanngg,, oorr ssttrraannggee bbeehhaavviioorr + + If you're seeing truly strange behavior, such as hangs or panics that + happen in random places, or you try running the debugger to see what's + happening and it acts strangely, then it could be a problem in the + host kernel. If you're not running a stock Linus or -ac kernel, then + try that. An early version of the preemption patch and a 2.4.10 SuSE + kernel have caused very strange problems in UML. + + + Otherwise, let me know about it. Send a message to one of the UML + mailing lists - either the developer list - user-mode-linux-devel at + lists dot sourceforge dot net (subscription info) or the user list - + user-mode-linux-user at lists dot sourceforge do net (subscription + info), whichever you prefer. Don't assume that everyone knows about + it and that a fix is imminent. + + + If you want to be super-helpful, read ``Diagnosing Problems'' and + follow the instructions contained therein. + 1144.. DDiiaaggnnoossiinngg PPrroobblleemmss + + + If you get UML to crash, hang, or otherwise misbehave, you should + report this on one of the project mailing lists, either the developer + list - user-mode-linux-devel at lists dot sourceforge dot net + (subscription info) or the user list - user-mode-linux-user at lists + dot sourceforge dot net (subscription info). When you do, it is + likely that I will want more information. So, it would be helpful to + read the stuff below, do whatever is applicable in your case, and + report the results to the list. + + + For any diagnosis, you're going to need to build a debugging kernel. + The binaries from this site aren't debuggable. If you haven't done + this before, read about ``Compiling the kernel and modules'' and + ``Kernel debugging'' UML first. + + + 1144..11.. CCaassee 11 :: NNoorrmmaall kkeerrnneell ppaanniiccss + + The most common case is for a normal thread to panic. To debug this, + you will need to run it under the debugger (add 'debug' to the command + line). An xterm will start up with gdb running inside it. Continue + it when it stops in start_kernel and make it crash. Now ^C gdb and + + + If the panic was a "Kernel mode fault", then there will be a segv + frame on the stack and I'm going to want some more information. The + stack might look something like this: + + + (UML gdb) backtrace + #0 0x1009bf76 in __sigprocmask (how=1, set=0x5f347940, oset=0x0) + at ../sysdeps/unix/sysv/linux/sigprocmask.c:49 + #1 0x10091411 in change_sig (signal=10, on=1) at process.c:218 + #2 0x10094785 in timer_handler (sig=26) at time_kern.c:32 + #3 0x1009bf38 in __restore () + at ../sysdeps/unix/sysv/linux/i386/sigaction.c:125 + #4 0x1009534c in segv (address=8, ip=268849158, is_write=2, is_user=0) + at trap_kern.c:66 + #5 0x10095c04 in segv_handler (sig=11) at trap_user.c:285 + #6 0x1009bf38 in __restore () + + + + + I'm going to want to see the symbol and line information for the value + of ip in the segv frame. In this case, you would do the following: + + + (UML gdb) i sym 268849158 + + + + + and + + + (UML gdb) i line *268849158 + + + + + The reason for this is the __restore frame right above the segv_han- + dler frame is hiding the frame that actually segfaulted. So, I have + to get that information from the faulting ip. + + + 1144..22.. CCaassee 22 :: TTrraacciinngg tthhrreeaadd ppaanniiccss + + The less common and more painful case is when the tracing thread + panics. In this case, the kernel debugger will be useless because it + needs a healthy tracing thread in order to work. The first thing to + do is get a backtrace from the tracing thread. This is done by + figuring out what its pid is, firing up gdb, and attaching it to that + pid. You can figure out the tracing thread pid by looking at the + first line of the console output, which will look like this: + + + tracing thread pid = 15851 + + + + + or by running ps on the host and finding the line that looks like + this: + + + jdike 15851 4.5 0.4 132568 1104 pts/0 S 21:34 0:05 ./linux [(tracing thread)] + + + + + If the panic was 'segfault in signals', then follow the instructions + above for collecting information about the location of the seg fault. + + + If the tracing thread flaked out all by itself, then send that + backtrace in and wait for our crack debugging team to fix the problem. + + + 1144..33.. CCaassee 33 :: TTrraacciinngg tthhrreeaadd ppaanniiccss ccaauusseedd bbyy ootthheerr tthhrreeaaddss + + However, there are cases where the misbehavior of another thread + caused the problem. The most common panic of this type is: + + + wait_for_stop failed to wait for to stop with + + + + + In this case, you'll need to get a backtrace from the process men- + tioned in the panic, which is complicated by the fact that the kernel + debugger is defunct and without some fancy footwork, another gdb can't + attach to it. So, this is how the fancy footwork goes: + + In a shell: + + + host% kill -STOP pid + + + + + Run gdb on the tracing thread as described in case 2 and do: + + + (host gdb) call detach(pid) + + + If you get a segfault, do it again. It always works the second time. + + Detach from the tracing thread and attach to that other thread: + + + (host gdb) detach + + + + + + + (host gdb) attach pid + + + + + If gdb hangs when attaching to that process, go back to a shell and + do: + + + host% + kill -CONT pid + + + + + And then get the backtrace: + + + (host gdb) backtrace + + + + + + 1144..44.. CCaassee 44 :: HHaannggss + + Hangs seem to be fairly rare, but they sometimes happen. When a hang + happens, we need a backtrace from the offending process. Run the + kernel debugger as described in case 1 and get a backtrace. If the + current process is not the idle thread, then send in the backtrace. + You can tell that it's the idle thread if the stack looks like this: + + + #0 0x100b1401 in __libc_nanosleep () + #1 0x100a2885 in idle_sleep (secs=10) at time.c:122 + #2 0x100a546f in do_idle () at process_kern.c:445 + #3 0x100a5508 in cpu_idle () at process_kern.c:471 + #4 0x100ec18f in start_kernel () at init/main.c:592 + #5 0x100a3e10 in start_kernel_proc (unused=0x0) at um_arch.c:71 + #6 0x100a383f in signal_tramp (arg=0x100a3dd8) at trap_user.c:50 + + + + + If this is the case, then some other process is at fault, and went to + sleep when it shouldn't have. Run ps on the host and figure out which + process should not have gone to sleep and stayed asleep. Then attach + to it with gdb and get a backtrace as described in case 3. + + + + + + + 1155.. TThhaannkkss + + + A number of people have helped this project in various ways, and this + page gives recognition where recognition is due. + + + If you're listed here and you would prefer a real link on your name, + or no link at all, instead of the despammed email address pseudo-link, + let me know. + + + If you're not listed here and you think maybe you should be, please + let me know that as well. I try to get everyone, but sometimes my + bookkeeping lapses and I forget about contributions. + + + 1155..11.. CCooddee aanndd DDooccuummeennttaattiioonn + + Rusty Russell - + + +o wrote the HOWTO + + +o prodded me into making this project official and putting it on + SourceForge + + +o came up with the way cool UML logo + + +o redid the config process + + + Peter Moulder - Fixed my config and build + processes, and added some useful code to the block driver + + + Bill Stearns - + + +o HOWTO updates + + +o lots of bug reports + + +o lots of testing + + +o dedicated a box (uml.ists.dartmouth.edu) to support UML development + + +o wrote the mkrootfs script, which allows bootable filesystems of + RPM-based distributions to be cranked out + + +o cranked out a large number of filesystems with said script + + + Jim Leu - Wrote the virtual ethernet driver + and associated usermode tools + + Lars Brinkhoff - Contributed the ptrace + proxy from his own project to allow easier + kernel debugging + + + Andrea Arcangeli - Redid some of the early boot + code so that it would work on machines with Large File Support + + + Chris Emerson - Did + the first UML port to Linux/ppc + + + Harald Welte - Wrote the multicast + transport for the network driver + + + Jorgen Cederlof - Added special file support to hostfs + + + Greg Lonnon - Changed the ubd driver + to allow it to layer a COW file on a shared read-only filesystem and + wrote the iomem emulation support + + + Henrik Nordstrom - Provided a variety + of patches, fixes, and clues + + + Lennert Buytenhek - Contributed various patches, a rewrite of the + network driver, the first implementation of the mconsole driver, and + did the bulk of the work needed to get SMP working again. + + + Yon Uriarte - Fixed the TUN/TAP network backend while I slept. + + + Adam Heath - Made a bunch of nice cleanups to the initialization code, + plus various other small patches. + + + Matt Zimmerman - Matt volunteered to be the UML Debian maintainer and + is doing a real nice job of it. He also noticed and fixed a number of + actually and potentially exploitable security holes in uml_net. Plus + the occasional patch. I like patches. + + + James McMechan - James seems to have taken over maintenance of the ubd + driver and is doing a nice job of it. + + + Chandan Kudige - wrote the umlgdb script which automates the reloading + of module symbols. + + + Steve Schmidtke - wrote the UML slirp transport and hostaudio drivers, + enabling UML processes to access audio devices on the host. He also + submitted patches for the slip transport and lots of other things. + + + David Coulson - + + +o Set up the usermodelinux.org site, + which is a great way of keeping the UML user community on top of + UML goings-on. + + +o Site documentation and updates + + +o Nifty little UML management daemon UMLd + + + +o Lots of testing and bug reports + + + + + 1155..22.. FFlluusshhiinngg oouutt bbuuggss + + + + +o Yuri Pudgorodsky + + +o Gerald Britton + + +o Ian Wehrman + + +o Gord Lamb + + +o Eugene Koontz + + +o John H. Hartman + + +o Anders Karlsson + + +o Daniel Phillips + + +o John Fremlin + + +o Rainer Burgstaller + + +o James Stevenson + + +o Matt Clay + + +o Cliff Jefferies + + +o Geoff Hoff + + +o Lennert Buytenhek + + +o Al Viro + + +o Frank Klingenhoefer + + +o Livio Baldini Soares + + +o Jon Burgess + + +o Petru Paler + + +o Paul + + +o Chris Reahard + + +o Sverker Nilsson + + +o Gong Su + + +o johan verrept + + +o Bjorn Eriksson + + +o Lorenzo Allegrucci + + +o Muli Ben-Yehuda + + +o David Mansfield + + +o Howard Goff + + +o Mike Anderson + + +o John Byrne + + +o Sapan J. Batia + + +o Iris Huang + + +o Jan Hudec + + +o Voluspa + + + + + 1155..33.. BBuugglleettss aanndd cclleeaann--uuppss + + + + +o Dave Zarzycki + + +o Adam Lazur + + +o Boria Feigin + + +o Brian J. Murrell + + +o JS + + +o Roman Zippel + + +o Wil Cooley + + +o Ayelet Shemesh + + +o Will Dyson + + +o Sverker Nilsson + + +o dvorak + + +o v.naga srinivas + + +o Shlomi Fish + + +o Roger Binns + + +o johan verrept + + +o MrChuoi + + +o Peter Cleve + + +o Vincent Guffens + + +o Nathan Scott + + +o Patrick Caulfield + + +o jbearce + + +o Catalin Marinas + + +o Shane Spencer + + +o Zou Min + + + +o Ryan Boder + + +o Lorenzo Colitti + + +o Gwendal Grignou + + +o Andre' Breiler + + +o Tsutomu Yasuda + + + + 1155..44.. CCaassee SSttuuddiieess + + + +o Jon Wright + + +o William McEwan + + +o Michael Richardson + + + + 1155..55.. OOtthheerr ccoonnttrriibbuuttiioonnss + + + Bill Carr made the Red Hat mkrootfs script + work with RH 6.2. + + Michael Jennings sent in some material which + is now gracing the top of the index page of this site. + + SGI (and more specifically Ralf Baechle ) gave me an account on oss.sgi.com + . The bandwidth there made it possible to + produce most of the filesystems available on the project download + page. + + Laurent Bonnaud took the old grotty + Debian filesystem that I've been distributing and updated it to 2.2. + It is now available by itself here. + + Rik van Riel gave me some ftp space on ftp.nl.linux.org so I can make + releases even when Sourceforge is broken. + + Rodrigo de Castro looked at my broken pte code and told me what was + wrong with it, letting me fix a long-standing (several weeks) and + serious set of bugs. + + Chris Reahard built a specialized root filesystem for running a DNS + server jailed inside UML. It's available from the download + page in the Jail + Filesysems section. + + + + + + + + + + + + -- cgit v1.2.3 From d6d05310c819d39ce14819a938a07109ad5c0c51 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 05:57:00 -0500 Subject: Updated to 2.5.48 --- arch/um/kernel/sys_call_table.c | 15 +++++++-------- arch/um/kernel/sysrq.c | 4 ++-- arch/um/uml.lds.S | 1 + include/asm-um/uaccess.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c index 70bab83af292..9613cc13f9e3 100644 --- a/arch/um/kernel/sys_call_table.c +++ b/arch/um/kernel/sys_call_table.c @@ -125,10 +125,8 @@ extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_adjtimex; extern syscall_handler_t sys_mprotect; extern syscall_handler_t sys_sigprocmask; -extern syscall_handler_t sys_create_module; extern syscall_handler_t sys_init_module; extern syscall_handler_t sys_delete_module; -extern syscall_handler_t sys_get_kernel_syms; extern syscall_handler_t sys_quotactl; extern syscall_handler_t sys_getpgid; extern syscall_handler_t sys_fchdir; @@ -162,7 +160,6 @@ extern syscall_handler_t sys_mremap; extern syscall_handler_t sys_setresuid16; extern syscall_handler_t sys_getresuid16; extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_query_module; extern syscall_handler_t sys_poll; extern syscall_handler_t sys_nfsservctl; extern syscall_handler_t sys_setresgid16; @@ -236,9 +233,10 @@ extern syscall_handler_t sys_epoll_create; extern syscall_handler_t sys_epoll_ctl; extern syscall_handler_t sys_epoll_wait; extern syscall_handler_t sys_remap_file_pages; +extern syscall_handler_t sys_set_tid_address; #if CONFIG_NFSD -#define NFSSERVCTL sys_nfsserctl +#define NFSSERVCTL sys_nfsservctl #else #define NFSSERVCTL sys_ni_syscall #endif @@ -247,7 +245,7 @@ extern syscall_handler_t um_mount; extern syscall_handler_t um_time; extern syscall_handler_t um_stime; -#define LAST_GENERIC_SYSCALL __NR_remap_file_pages +#define LAST_GENERIC_SYSCALL __NR_set_tid_address #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL #define LAST_SYSCALL LAST_GENERIC_SYSCALL @@ -385,10 +383,10 @@ syscall_handler_t *sys_call_table[] = { [ __NR_adjtimex ] = sys_adjtimex, [ __NR_mprotect ] = sys_mprotect, [ __NR_sigprocmask ] = sys_sigprocmask, - [ __NR_create_module ] = sys_create_module, + [ __NR_create_module ] = sys_ni_syscall, [ __NR_init_module ] = sys_init_module, [ __NR_delete_module ] = sys_delete_module, - [ __NR_get_kernel_syms ] = sys_get_kernel_syms, + [ __NR_get_kernel_syms ] = sys_ni_syscall, [ __NR_quotactl ] = sys_quotactl, [ __NR_getpgid ] = sys_getpgid, [ __NR_fchdir ] = sys_fchdir, @@ -425,7 +423,7 @@ syscall_handler_t *sys_call_table[] = { [ __NR_setresuid ] = sys_setresuid16, [ __NR_getresuid ] = sys_getresuid16, [ __NR_vm86 ] = sys_ni_syscall, - [ __NR_query_module ] = sys_query_module, + [ __NR_query_module ] = sys_ni_syscall, [ __NR_poll ] = sys_poll, [ __NR_nfsservctl ] = NFSSERVCTL, [ __NR_setresgid ] = sys_setresgid16, @@ -491,6 +489,7 @@ syscall_handler_t *sys_call_table[] = { [ __NR_sys_epoll_ctl ] = sys_epoll_ctl, [ __NR_sys_epoll_wait ] = sys_epoll_wait, [ __NR_remap_file_pages ] = sys_remap_file_pages, + [ __NR_set_tid_address ] = sys_set_tid_address, ARCH_SYSCALLS [ LAST_SYSCALL + 1 ... NR_syscalls ] = diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 5a05d66a125f..a9c43cad6780 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -31,11 +31,11 @@ static inline int kernel_text_address(unsigned long addr) addr <= (unsigned long) &_etext) return 1; - for (mod = module_list; mod != &kernel_module; mod = mod->next) { + list_for_each_entry(mod, &modules, list) { /* mod_bound tests for addr being inside the vmalloc'ed * module area. Of course it'd be better to test only * for the .text subset... */ - if (mod_bound(addr, 0, mod)) { + if (mod_bound((void *) addr, 0, mod)) { retval = 1; break; } diff --git a/arch/um/uml.lds.S b/arch/um/uml.lds.S index c15bc24842c3..cd4b487e0fa5 100644 --- a/arch/um/uml.lds.S +++ b/arch/um/uml.lds.S @@ -38,6 +38,7 @@ SECTIONS __ex_table : { *(__ex_table) } __stop___ex_table = .; + . = ALIGN(64); __start___ksymtab = .; /* Kernel symbol table */ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h index a8a7dfb7e4c8..0a24a9b5497f 100644 --- a/include/asm-um/uaccess.h +++ b/include/asm-um/uaccess.h @@ -164,7 +164,7 @@ static inline int clear_user(void *mem, int len) extern int __do_strnlen_user(const char *str, unsigned long n, void **fault_addr, void **fault_catcher); -static inline int strnlen_user(void *str, int len) +static inline int strnlen_user(const void *str, int len) { return(__do_strnlen_user(str, len, ¤t->thread.fault_addr, -- cgit v1.2.3 From 341d04a98d72b0693909f8e8a7ef3b064f07167d Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 05:57:40 -0500 Subject: Merged the get_config changes from 2.4. --- arch/um/drivers/chan_kern.c | 66 +++++++++++++++++++++++++++++- arch/um/drivers/fd.c | 6 ++- arch/um/drivers/line.c | 91 ++++++++++++++++++++++++++++++++++++----- arch/um/drivers/mconsole_kern.c | 62 ++++++++++++++++++++++++++-- arch/um/drivers/null.c | 5 ++- arch/um/drivers/port_user.c | 9 +++- arch/um/drivers/pty.c | 17 ++++++-- arch/um/drivers/ssl.c | 32 ++++++++++++++- arch/um/drivers/stdio_console.c | 30 +++++++++++++- arch/um/drivers/tty.c | 8 +++- arch/um/drivers/ubd_kern.c | 39 ++++++++++++++++++ arch/um/drivers/xterm.c | 4 +- arch/um/include/chan_kern.h | 3 ++ arch/um/include/chan_user.h | 3 +- arch/um/include/line.h | 11 ++++- arch/um/include/mconsole_kern.h | 16 +++++++- 16 files changed, 371 insertions(+), 31 deletions(-) diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 46a84e8e916c..119cce1bb689 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -24,7 +24,8 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts) return(NULL); } -static int not_configged_open(int input, int output, int primary, void *data) +static int not_configged_open(int input, int output, int primary, void *data, + char **dev_out) { printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); @@ -112,7 +113,8 @@ static int open_one_chan(struct chan *chan, int input, int output, int primary) if(chan->opened) return(0); if(chan->ops->open == NULL) fd = 0; - else fd = (*chan->ops->open)(input, output, primary, chan->data); + else fd = (*chan->ops->open)(input, output, primary, chan->data, + &chan->dev); if(fd < 0) return(fd); chan->fd = fd; @@ -258,6 +260,66 @@ void free_chan(struct list_head *chans) } } +static int one_chan_config_string(struct chan *chan, char *str, int size, + char **error_out) +{ + int n = 0; + + CONFIG_CHUNK(str, size, n, chan->ops->type, 0); + + if(chan->dev == NULL){ + CONFIG_CHUNK(str, size, n, "", 1); + return(n); + } + + CONFIG_CHUNK(str, size, n, ":", 0); + CONFIG_CHUNK(str, size, n, chan->dev, 0); + + return(n); +} + +static int chan_pair_config_string(struct chan *in, struct chan *out, + char *str, int size, char **error_out) +{ + int n; + + n = one_chan_config_string(in, str, size, error_out); + str += n; + size -= n; + + if(in == out){ + CONFIG_CHUNK(str, size, n, "", 1); + return(n); + } + + CONFIG_CHUNK(str, size, n, ",", 1); + n = one_chan_config_string(out, str, size, error_out); + str += n; + size -= n; + CONFIG_CHUNK(str, size, n, "", 1); + + return(n); +} + +int chan_config_string(struct list_head *chans, char *str, int size, + char **error_out) +{ + struct list_head *ele; + struct chan *chan, *in = NULL, *out = NULL; + + list_for_each(ele, chans){ + chan = list_entry(ele, struct chan, list); + if(!chan->primary) + continue; + if(chan->input) + in = chan; + if(chan->output) + out = chan; + } + + return(chan_pair_config_string(in, out, str, size, error_out)); +} + struct chan_type { char *key; struct chan_ops *ops; diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index e31620d15a77..9e13ba713b28 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -15,6 +15,7 @@ struct fd_chan { int fd; int raw; struct termios tt; + char str[sizeof("1234567890\0")]; }; void *fd_init(char *str, int device, struct chan_opts *opts) @@ -40,7 +41,7 @@ void *fd_init(char *str, int device, struct chan_opts *opts) return(data); } -int fd_open(int input, int output, int primary, void *d) +int fd_open(int input, int output, int primary, void *d, char **dev_out) { struct fd_chan *data = d; @@ -48,6 +49,8 @@ int fd_open(int input, int output, int primary, void *d) tcgetattr(data->fd, &data->tt); raw(data->fd, 0); } + sprintf(data->str, "%d", data->fd); + *dev_out = data->str; return(data->fd); } @@ -69,6 +72,7 @@ int fd_console_write(int fd, const char *buf, int n, void *d) } struct chan_ops fd_ops = { + type: "fd", init: fd_init, open: fd_open, close: fd_close, diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 837c07f41669..e851b0e53f80 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -8,11 +8,13 @@ #include "linux/list.h" #include "linux/devfs_fs_kernel.h" #include "asm/irq.h" +#include "asm/uaccess.h" #include "chan_kern.h" #include "irq_user.h" #include "line.h" #include "kern.h" #include "user_util.h" +#include "kern_util.h" #include "os.h" #define LINE_BUFSIZE 4096 @@ -281,7 +283,7 @@ void close_lines(struct line *lines, int nlines) close_chan(&lines[i].chan_list); } -void line_setup(struct line *lines, int num, char *init) +int line_setup(struct line *lines, int num, char *init, int all_allowed) { int i, n; char *end; @@ -292,12 +294,36 @@ void line_setup(struct line *lines, int num, char *init) if(*end != '='){ printk(KERN_ERR "line_setup failed to parse \"%s\"\n", init); - return; + return(1); } init = end; } init++; - if(n == -1){ + if((n >= 0) && (n >= num)){ + printk("line_setup - %d out of range ((0 ... %d) allowed)\n", + n, num); + return(1); + } + else if(n >= 0){ + if(lines[n].count > 0){ + printk("line_setup - device %d is open\n", n); + return(1); + } + if(lines[n].init_pri <= INIT_ONE){ + lines[n].init_pri = INIT_ONE; + if(!strcmp(init, "none")) lines[n].valid = 0; + else { + lines[n].init_str = init; + lines[n].valid = 1; + } + } + } + else if(!all_allowed){ + printk("line_setup - can't configure all devices from " + "mconsole\n"); + return(1); + } + else { for(i = 0; i < num; i++){ if(lines[i].init_pri <= INIT_ALL){ lines[i].init_pri = INIT_ALL; @@ -309,14 +335,57 @@ void line_setup(struct line *lines, int num, char *init) } } } - else if(lines[n].init_pri <= INIT_ONE){ - lines[n].init_pri = INIT_ONE; - if(!strcmp(init, "none")) lines[n].valid = 0; - else { - lines[n].init_str = init; - lines[n].valid = 1; - } + return(0); +} + +int line_config(struct line *lines, int num, char *str) +{ + char *new = uml_strdup(str); + + if(new == NULL){ + printk("line_config - uml_strdup failed\n"); + return(-ENOMEM); + } + return(line_setup(lines, num, new, 0)); +} + +int line_get_config(char *name, struct line *lines, int num, char *str, + int size, char **error_out) +{ + struct line *line; + char *end; + int dev, n = 0; + + dev = simple_strtoul(name, &end, 0); + if((*end != '\0') || (end == name)){ + *error_out = "line_setup failed to parse device number"; + return(0); } + + if((dev < 0) || (dev >= num)){ + *error_out = "device number of of range"; + return(0); + } + + line = &lines[dev]; + down(&line->sem); + + if(!line->valid) + CONFIG_CHUNK(str, size, n, "none", 1); + else if(line->count == 0) + CONFIG_CHUNK(str, size, n, line->init_str, 1); + else n = chan_config_string(&line->chan_list, str, size, error_out); + + up(&line->sem); + return(n); +} + +int line_remove(struct line *lines, int num, char *str) +{ + char config[sizeof("conxxxx=none\0")]; + + sprintf(config, "%s=none", str); + return(line_setup(lines, num, config, 0)); } void line_register_devfs(struct lines *set, struct line_driver *line_driver, @@ -366,6 +435,8 @@ void line_register_devfs(struct lines *set, struct line_driver *line_driver, if(!lines[i].valid) tty_unregister_devfs(driver, driver->minor_start + i); } + + mconsole_register_dev(&line_driver->mc); } void lines_init(struct line *lines, int nlines) diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 49c1773e0c9b..8ba898759587 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -108,6 +108,7 @@ void mconsole_version(struct mc_request *req) reboot - Reboot UML config = - Add a new device to UML; same syntax as command line + config - Query the configuration of a device remove - Remove a device from UML sysrq - Performs the SysRq action controlled by the letter cad - invoke the Ctl-Alt-Del handler @@ -181,10 +182,56 @@ static struct mc_device *mconsole_find_dev(char *name) return(NULL); } +#define CONFIG_BUF_SIZE 64 + +static void mconsole_get_config(int (*get_config)(char *, char *, int, + char **), + struct mc_request *req, char *name) +{ + char default_buf[CONFIG_BUF_SIZE], *error, *buf; + int n, size; + + if(get_config == NULL){ + mconsole_reply(req, "No get_config routine defined", 1, 0); + return; + } + + error = NULL; + size = sizeof(default_buf)/sizeof(default_buf[0]); + buf = default_buf; + + while(1){ + n = (*get_config)(name, buf, size, &error); + if(error != NULL){ + mconsole_reply(req, error, 1, 0); + goto out; + } + + if(n <= size){ + mconsole_reply(req, buf, 0, 0); + goto out; + } + + if(buf != default_buf) + kfree(buf); + + size = n; + buf = kmalloc(size, GFP_KERNEL); + if(buf == NULL){ + mconsole_reply(req, "Failed to allocate buffer", 1, 0); + return; + } + } + out: + if(buf != default_buf) + kfree(buf); + +} + void mconsole_config(struct mc_request *req) { struct mc_device *dev; - char *ptr = req->request.data; + char *ptr = req->request.data, *name; int err; ptr += strlen("config"); @@ -194,8 +241,17 @@ void mconsole_config(struct mc_request *req) mconsole_reply(req, "Bad configuration option", 1, 0); return; } - err = (*dev->config)(&ptr[strlen(dev->name)]); - mconsole_reply(req, "", err, 0); + + name = &ptr[strlen(dev->name)]; + ptr = name; + while((*ptr != '=') && (*ptr != '\0')) + ptr++; + + if(*ptr == '='){ + err = (*dev->config)(name); + mconsole_reply(req, "", err, 0); + } + else mconsole_get_config(dev->get_config, req, name); } void mconsole_remove(struct mc_request *req) diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c index 08cc7b0a165e..6a41c213e0d6 100644 --- a/arch/um/drivers/null.c +++ b/arch/um/drivers/null.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include #include #include #include "chan_user.h" @@ -15,8 +16,9 @@ void *null_init(char *str, int device, struct chan_opts *opts) return(&null_chan); } -int null_open(int input, int output, int primary, void *d) +int null_open(int input, int output, int primary, void *d, char **dev_out) { + *dev_out = NULL; return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0)); } @@ -30,6 +32,7 @@ void null_free(void *data) } struct chan_ops null_ops = { + type: "null", init: null_init, open: null_open, close: generic_close, diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index 35f163da9d32..1dc8a492a3c8 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -3,11 +3,12 @@ * Licensed under the GPL */ +#include #include #include +#include #include #include -#include #include #include #include @@ -24,6 +25,7 @@ struct port_chan { int raw; struct termios tt; void *kernel_data; + char dev[sizeof("32768\0")]; }; void *port_init(char *str, int device, struct chan_opts *opts) @@ -50,11 +52,12 @@ void *port_init(char *str, int device, struct chan_opts *opts) if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); *data = ((struct port_chan) { raw : opts->raw, kernel_data : kern_data }); + sprintf(data->dev, "%d", port); return(data); } -int port_open(int input, int output, int primary, void *d) +int port_open(int input, int output, int primary, void *d, char **dev_out) { struct port_chan *data = d; int fd; @@ -64,6 +67,7 @@ int port_open(int input, int output, int primary, void *d) tcgetattr(fd, &data->tt); raw(fd, 0); } + *dev_out = data->dev; return(fd); } @@ -91,6 +95,7 @@ void port_free(void *d) } struct chan_ops port_ops = { + type: "port", init: port_init, open: port_open, close: port_close, diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index 6054dd6aa9ac..3cc207ae08a2 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -19,6 +19,7 @@ struct pty_chan { int dev; int raw; struct termios tt; + char dev_name[sizeof("/dev/pts/0123456\0")]; }; void *pty_chan_init(char *str, int device, struct chan_opts *opts) @@ -32,9 +33,10 @@ void *pty_chan_init(char *str, int device, struct chan_opts *opts) return(data); } -int pts_open(int input, int output, int primary, void *d) +int pts_open(int input, int output, int primary, void *d, char **dev_out) { struct pty_chan *data = d; + char *dev; int fd; if((fd = get_pty()) < 0){ @@ -45,7 +47,11 @@ int pts_open(int input, int output, int primary, void *d) tcgetattr(fd, &data->tt); raw(fd, 0); } - if(data->announce) (*data->announce)(ptsname(fd), data->dev); + + dev = ptsname(fd); + sprintf(data->dev_name, "%s", dev); + *dev_out = data->dev_name; + if(data->announce) (*data->announce)(dev, data->dev); return(fd); } @@ -94,7 +100,7 @@ static void grantpt_cb(void *arg) info->err = errno; } -int pty_open(int input, int output, int primary, void *d) +int pty_open(int input, int output, int primary, void *d, char **dev_out) { struct pty_chan *data = d; int fd; @@ -110,6 +116,9 @@ int pty_open(int input, int output, int primary, void *d) if(data->raw) raw(fd, 0); if(data->announce) (*data->announce)(dev, data->dev); + + sprintf(data->dev_name, "%s", dev); + *dev_out = data->dev_name; return(fd); } @@ -121,6 +130,7 @@ int pty_console_write(int fd, const char *buf, int n, void *d) } struct chan_ops pty_ops = { + type: "pty", init: pty_chan_init, open: pty_open, close: generic_close, @@ -133,6 +143,7 @@ struct chan_ops pty_ops = { }; struct chan_ops pts_ops = { + type: "pts", init: pty_chan_init, open: pts_open, close: generic_close, diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index c0cd826d9d8b..c2bbade3644b 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -20,6 +20,7 @@ #include "kern.h" #include "init.h" #include "irq_user.h" +#include "mconsole_kern.h" #include "2_5compat.h" static int ssl_version = 1; @@ -47,6 +48,10 @@ static struct chan_opts opts = { in_kernel : 1, }; +static int ssl_config(char *str); +static int ssl_get_config(char *dev, char *str, int size, char **error_out); +static int ssl_remove(char *str); + static struct line_driver driver = { name : "UML serial line", devfs_name : "tts/%d", @@ -60,6 +65,12 @@ static struct line_driver driver = { write_irq_name : "ssl-write", symlink_from : "serial", symlink_to : "tts", + mc : { + name : "ssl", + config : ssl_config, + get_config : ssl_get_config, + remove : ssl_remove, + }, }; /* The array is initialized by line_init, which is an initcall. The @@ -70,6 +81,25 @@ static struct line serial_lines[NR_PORTS] = static struct lines lines = LINES_INIT(NR_PORTS); +static int ssl_config(char *str) +{ + return(line_config(serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), str)); +} + +static int ssl_get_config(char *dev, char *str, int size, char **error_out) +{ + return(line_get_config(dev, serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), + str, size, error_out)); +} + +static int ssl_remove(char *str) +{ + return(line_remove(serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), str)); +} + int ssl_open(struct tty_struct *tty, struct file *filp) { return(line_open(serial_lines, tty, &opts)); @@ -207,7 +237,7 @@ __initcall(ssl_init); static int ssl_chan_setup(char *str) { line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]), - str); + str, 1); return(1); } diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 4803c3e071b0..ecc06a36188d 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -27,6 +27,7 @@ #include "user_util.h" #include "kern_util.h" #include "irq_user.h" +#include "mconsole_kern.h" #include "init.h" #include "2_5compat.h" @@ -41,6 +42,7 @@ static struct tty_driver console_driver; static int console_refcount = 0; static struct chan_ops init_console_ops = { + type: "you shouldn't see this", init : NULL, open : NULL, close : NULL, @@ -78,6 +80,10 @@ static struct chan_opts opts = { in_kernel : 1, }; +static int con_config(char *str); +static int con_get_config(char *dev, char *str, int size, char **error_out); +static int con_remove(char *str); + static struct line_driver driver = { name : "UML console", devfs_name : "vc/%d", @@ -91,6 +97,12 @@ static struct line_driver driver = { write_irq_name : "console-write", symlink_from : "ttys", symlink_to : "vc", + mc : { + name : "con", + config : con_config, + get_config : con_get_config, + remove : con_remove, + }, }; static struct lines console_lines = LINES_INIT(MAX_TTYS); @@ -102,6 +114,22 @@ struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), [ 1 ... MAX_TTYS - 1 ] = LINE_INIT(CONFIG_CON_CHAN, &driver) }; +static int con_config(char *str) +{ + return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str)); +} + +static int con_get_config(char *dev, char *str, int size, char **error_out) +{ + return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str, + size, error_out)); +} + +static int con_remove(char *str) +{ + return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str)); +} + static int open_console(struct tty_struct *tty) { return(line_open(vts, tty, &opts)); @@ -195,7 +223,7 @@ void stdio_console_init(void) static int console_chan_setup(char *str) { - line_setup(vts, sizeof(vts)/sizeof(vts[0]), str); + line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1); return(1); } diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c index 75b4b93102b0..438e72268ef6 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -30,14 +30,15 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts) } str++; - if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); + if((data = um_kmalloc(sizeof(*data))) == NULL) + return(NULL); *data = ((struct tty_chan) { dev : str, raw : opts->raw }); return(data); } -int tty_open(int input, int output, int primary, void *d) +int tty_open(int input, int output, int primary, void *d, char **dev_out) { struct tty_chan *data = d; int fd; @@ -48,6 +49,8 @@ int tty_open(int input, int output, int primary, void *d) tcgetattr(fd, &data->tt); raw(fd, 0); } + + *dev_out = data->dev; return(fd); } @@ -59,6 +62,7 @@ int tty_console_write(int fd, const char *buf, int n, void *d) } struct chan_ops tty_ops = { + type: "tty", init: tty_chan_init, open: tty_open, close: generic_close, diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 93228f048940..970290cc9072 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -574,6 +574,44 @@ static int ubd_config(char *str) return(err); } +static int ubd_get_config(char *dev, char *str, int size, char **error_out) +{ + struct ubd *ubd; + char *end; + int major, n = 0; + + major = simple_strtoul(dev, &end, 0); + if((*end != '\0') || (end == dev)){ + *error_out = "ubd_get_config : didn't parse major number"; + return(-1); + } + + if((major >= MAX_DEV) || (major < 0)){ + *error_out = "ubd_get_config : major number out of range"; + return(-1); + } + + ubd = &ubd_dev[major]; + spin_lock(&ubd_lock); + + if(ubd->file == NULL){ + CONFIG_CHUNK(str, size, n, "", 1); + goto out; + } + + CONFIG_CHUNK(str, size, n, ubd->file, 0); + + if(ubd->cow.file != NULL){ + CONFIG_CHUNK(str, size, n, ",", 0); + CONFIG_CHUNK(str, size, n, ubd->cow.file, 1); + } + else CONFIG_CHUNK(str, size, n, "", 1); + + out: + spin_unlock(&ubd_lock); + return(n); +} + static int ubd_remove(char *str) { struct ubd *dev; @@ -620,6 +658,7 @@ static int ubd_remove(char *str) static struct mc_device ubd_mc = { .name = "ubd", .config = ubd_config, + .get_config = ubd_get_config, .remove = ubd_remove, }; diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index e7b4ab83c8f7..463040a242a0 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -83,7 +83,7 @@ __uml_setup("xterm=", xterm_setup, " are 'xterm=gnome-terminal,-t,-x'.\n\n" ); -int xterm_open(int input, int output, int primary, void *d) +int xterm_open(int input, int output, int primary, void *d, char **dev_out) { struct xterm_chan *data = d; unsigned long stack; @@ -141,6 +141,7 @@ int xterm_open(int input, int output, int primary, void *d) if(data->raw) raw(new, 0); data->pid = pid; + *dev_out = NULL; return(new); } @@ -168,6 +169,7 @@ int xterm_console_write(int fd, const char *buf, int n, void *d) } struct chan_ops xterm_ops = { + type: "xterm", init: xterm_init, open: xterm_open, close: xterm_close, diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h index 8c2bb85c9edf..d2cd02a03c61 100644 --- a/arch/um/include/chan_kern.h +++ b/arch/um/include/chan_kern.h @@ -12,6 +12,7 @@ struct chan { struct list_head list; + char *dev; unsigned int primary:1; unsigned int input:1; unsigned int output:1; @@ -38,6 +39,8 @@ extern int chan_window_size(struct list_head *chans, unsigned short *rows_out, unsigned short *cols_out); extern int chan_out_fd(struct list_head *chans); +extern int chan_config_string(struct list_head *chans, char *str, int size, + char **error_out); #endif diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h index 639ca8d6121a..c016c2aab72e 100644 --- a/arch/um/include/chan_user.h +++ b/arch/um/include/chan_user.h @@ -19,8 +19,9 @@ struct chan_opts { enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; struct chan_ops { + char *type; void *(*init)(char *, int, struct chan_opts *); - int (*open)(int, int, int, void *); + int (*open)(int, int, int, void *, char **); void (*close)(int, void *); int (*read)(int, char *, void *); int (*write)(int, const char *, int, void *); diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 4d45c270a80e..e7bdbceb54c3 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -11,6 +11,7 @@ #include "linux/tty.h" #include "asm/semaphore.h" #include "chan_user.h" +#include "mconsole_kern.h" struct line_driver { char *name; @@ -25,6 +26,7 @@ struct line_driver { char *write_irq_name; char *symlink_from; char *symlink_to; + struct mc_device mc; }; struct line { @@ -70,8 +72,9 @@ extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused); extern void line_close(struct line *lines, struct tty_struct *tty); extern int line_open(struct line *lines, struct tty_struct *tty, struct chan_opts *opts); -extern void line_setup(struct line *lines, int num, char *init); -extern int line_write(struct line *line, struct tty_struct *tty, +extern int line_setup(struct line *lines, int num, char *init, + int all_allowed); +extern int line_write(struct line *line, struct tty_struct *tty, const char *buf, int len); extern int line_write_room(struct tty_struct *tty); extern char *add_xterm_umid(char *base); @@ -84,6 +87,10 @@ extern void line_register_devfs(struct lines *set, int nlines); extern void lines_init(struct line *lines, int nlines); extern void close_lines(struct line *lines, int nlines); +extern int line_config(struct line *lines, int num, char *str); +extern int line_remove(struct line *lines, int num, char *str); +extern int line_get_config(char *dev, struct line *lines, int num, char *str, + int size, char **error_out); #endif diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h index 03c6d1734a28..61c274fcee5d 100644 --- a/arch/um/include/mconsole_kern.h +++ b/arch/um/include/mconsole_kern.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -19,9 +19,23 @@ struct mc_device { struct list_head list; char *name; int (*config)(char *); + int (*get_config)(char *, char *, int, char **); int (*remove)(char *); }; +#define CONFIG_CHUNK(str, size, current, chunk, end) \ +do { \ + current += strlen(chunk); \ + if(current >= size) \ + str = NULL; \ + if(str != NULL){ \ + strcpy(str, chunk); \ + str += strlen(chunk); \ + } \ + if(end) \ + current++; \ +} while(0) + #ifdef CONFIG_MCONSOLE extern void mconsole_register_dev(struct mc_device *new); -- cgit v1.2.3 From a8ddf6c1442521a0f4c6d67cfb8923263128c422 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 10:03:13 -0500 Subject: A few more fixes to get 2.4.48 to boot. --- arch/um/drivers/line.c | 1 + arch/um/kernel/sysrq.c | 4 ++-- arch/um/sys-i386/Makefile | 34 +++++++++++++++++----------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 837c07f41669..e2afb4271c34 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -13,6 +13,7 @@ #include "line.h" #include "kern.h" #include "user_util.h" +#include "kern_util.h" #include "os.h" #define LINE_BUFSIZE 4096 diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index a9c43cad6780..2bf29ad7ad27 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -19,8 +19,8 @@ #ifdef CONFIG_MODULES -extern struct module *module_list; -extern struct module kernel_module; +/* FIXME: Accessed without a lock --RR */ +extern struct list_head modules; static inline int kernel_text_address(unsigned long addr) { diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index d409f97fae0f..c96a75fe3fdb 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,4 +1,4 @@ -obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o \ +obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o module.o \ ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o obj-$(CONFIG_HIGHMEM) += highmem.o @@ -6,30 +6,30 @@ obj-$(CONFIG_HIGHMEM) += highmem.o export-objs = ksyms.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o -USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/sys-i386/$(file)) -SYMLINKS = semaphore.c checksum.S extable.c highmem.c +SYMLINKS = semaphore.c checksum.S extable.c highmem.c module.c + +semaphore.c-dir = kernel +checksum.S-dir = lib +extable.c-dir = mm +highmem.c-dir = mm +module.c-dir = kernel + +define make_link + -rm -f $1 + ln -sf $(TOPDIR)/arch/i386/$($(notdir $1)-dir)/$(notdir $1) $1 +endef include $(TOPDIR)/Rules.make +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< -arch/um/sys-i386/checksum.S: - -rm -f $@ - -ln -s $(TOPDIR)/arch/i386/lib/$(notdir $@) $@ - -arch/um/sys-i386/semaphore.c: - -rm -f $@ - -ln -s $(TOPDIR)/arch/i386/kernel/$(notdir $@) $@ - -arch/um/sys-i386/extable.c: - -rm -f $@ - -ln -s $(TOPDIR)/arch/i386/mm/$(notdir $@) $@ +$(foreach f,$(SYMLINKS),$(src)/$f): + $(call make_link,$@) -arch/um/sys-i386/highmem.c: - -rm -f $@ - -ln -s $(TOPDIR)/arch/i386/mm/$(notdir $@) $@ clean: $(MAKE) -C util clean -- cgit v1.2.3 From 2f167bfa0c0317a0575dd7df2e651c61a1af1d63 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 11:53:20 -0500 Subject: Merged a number of bug fixes from the 2.4 pool. --- arch/um/drivers/fd.c | 2 +- arch/um/drivers/mcast_kern.c | 4 ++-- arch/um/drivers/port_user.c | 2 +- arch/um/drivers/ubd_kern.c | 9 ++++++--- arch/um/drivers/xterm.c | 3 +++ arch/um/kernel/exitcode.c | 2 +- arch/um/kernel/helper.c | 5 ++++- arch/um/kernel/irq_user.c | 3 ++- arch/um/kernel/tty_log.c | 2 +- arch/um/os-Linux/file.c | 3 ++- include/asm-um/system-generic.h | 1 + 11 files changed, 24 insertions(+), 12 deletions(-) diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index e31620d15a77..efe5b6a0d476 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -30,7 +30,7 @@ void *fd_init(char *str, int device, struct chan_opts *opts) } str++; n = strtoul(str, &end, 0); - if(*end != '\0'){ + if((*end != '\0') || (end == str)){ printk("fd_init : couldn't parse file descriptor '%s'\n", str); return(NULL); } diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index 25158ba650c2..a0cbc72b8cd3 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c @@ -92,7 +92,7 @@ int mcast_setup(char *str, char **mac_out, void *data) if(port_str != NULL){ n = simple_strtoul(port_str, &last, 10); - if(*last != '\0'){ + if((*last != '\0') || (last == port_str)){ printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", port_str); return(0); @@ -102,7 +102,7 @@ int mcast_setup(char *str, char **mac_out, void *data) if(ttl_str != NULL){ init->ttl = simple_strtoul(ttl_str, &last, 10); - if(*last != '\0'){ + if((*last != '\0') || (last == ttl_str)){ printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", ttl_str); return(0); diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index 35f163da9d32..23ee0a6d1398 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -40,7 +40,7 @@ void *port_init(char *str, int device, struct chan_opts *opts) } str++; port = strtoul(str, &end, 0); - if(*end != '\0'){ + if((*end != '\0') || (end == str)){ printk("port_init : couldn't parse port '%s'\n", str); return(NULL); } diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 93228f048940..9198fcb1b2dd 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -218,7 +218,7 @@ static int ubd_setup_common(char *str, int *index_out) return(0); } major = simple_strtoul(str, &end, 0); - if(*end != '\0'){ + if((*end != '\0') || (end == str)){ printk(KERN_ERR "ubd_setup : didn't parse major number\n"); return(1); @@ -520,7 +520,10 @@ static int ubd_add(int n) struct ubd *dev = &ubd_dev[n]; int err; - if (!dev->file || dev->is_dir) + if(dev->is_dir) + return(-EISDIR); + + if (!dev->file) return(-ENODEV); if (ubd_open_dev(dev)) @@ -583,7 +586,7 @@ static int ubd_remove(char *str) return(err); /* it should be a number 0-7/a-h */ n = *str - '0'; - if(n > MAX_DEV) + if(n >= MAX_DEV) return(err); dev = &ubd_dev[n]; diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index e7b4ab83c8f7..f531010a128c 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -93,6 +93,9 @@ int xterm_open(int input, int output, int primary, void *d) "/usr/lib/uml/port-helper", "-uml-socket", file, NULL }; + if(access(argv[4], X_OK)) + argv[4] = "port-helper"; + fd = mkstemp(file); if(fd < 0){ printk("xterm_open : mkstemp failed, errno = %d\n", errno); diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index 788f914d8510..14a748e2e25a 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -42,7 +42,7 @@ static int write_proc_exitcode(struct file *file, const char *buffer, return(count); } -int make_proc_exitcode(void) +static int make_proc_exitcode(void) { struct proc_dir_entry *ent; diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c index 5d8fb7bba2b1..ede382d9b356 100644 --- a/arch/um/kernel/helper.c +++ b/arch/um/kernel/helper.c @@ -86,7 +86,10 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, errno); return(-errno); } - else if(n != 0) pid = -err; + else if(n != 0){ + waitpid(pid, NULL, 0); + pid = -err; + } if(stack_out == NULL) free_stack(stack, 0); else *stack_out = stack; diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index a5abb61536cf..97575314113b 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -188,7 +188,8 @@ int activate_fd(int irq, int fd, int type, void *dev_id) pollfds_size++; } - if(type == IRQ_WRITE) events = 0; + if(type == IRQ_WRITE) + fd = -1; pollfds[pollfds_num] = ((struct pollfd) { fd : fd, events : events, diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c index 7d53a6ea2ab0..61c4cc3af749 100644 --- a/arch/um/kernel/tty_log.c +++ b/arch/um/kernel/tty_log.c @@ -103,7 +103,7 @@ static int __init set_tty_log_fd(char *name, int *add) char *end; tty_log_fd = strtoul(name, &end, 0); - if(*end != '\0'){ + if((*end != '\0') || (end == name)){ printk("set_tty_log_fd - strtoul failed on '%s'\n", name); tty_log_fd = -1; } diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index 53e83d6607e1..ff024452f113 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -171,7 +171,8 @@ int os_pipe(int *fds, int stream, int close_on_exec) int err, type = stream ? SOCK_STREAM : SOCK_DGRAM; err = socketpair(AF_UNIX, type, 0, fds); - if(err) return(-errno); + if(err) + return(-errno); if(!close_on_exec) return(0); diff --git a/include/asm-um/system-generic.h b/include/asm-um/system-generic.h index 24d97e5fcf20..80b24a31b5fe 100644 --- a/include/asm-um/system-generic.h +++ b/include/asm-um/system-generic.h @@ -17,6 +17,7 @@ extern void *switch_to(void *prev, void *next, void *last); +extern int get_signals(void); extern int set_signals(int enable); extern int get_signals(void); extern void block_signals(void); -- cgit v1.2.3 From 422749644f3c79eae8c9c88575ab67c5031598b9 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 12:47:18 -0500 Subject: Moved the ptproxy code from arch/um/ptproxy to arch/um/kernel/tt/ptproxy. --- arch/um/kernel/Makefile | 35 ++-- arch/um/kernel/tt/Makefile | 9 + arch/um/kernel/tt/ptproxy/Makefile | 12 ++ arch/um/kernel/tt/ptproxy/proxy.c | 370 ++++++++++++++++++++++++++++++++++++ arch/um/kernel/tt/ptproxy/ptproxy.h | 61 ++++++ arch/um/kernel/tt/ptproxy/ptrace.c | 238 +++++++++++++++++++++++ arch/um/kernel/tt/ptproxy/sysdep.c | 71 +++++++ arch/um/kernel/tt/ptproxy/sysdep.h | 25 +++ arch/um/kernel/tt/ptproxy/wait.c | 86 +++++++++ arch/um/kernel/tt/ptproxy/wait.h | 15 ++ arch/um/ptproxy/Makefile | 12 -- arch/um/ptproxy/proxy.c | 370 ------------------------------------ arch/um/ptproxy/ptproxy.h | 61 ------ arch/um/ptproxy/ptrace.c | 238 ----------------------- arch/um/ptproxy/sysdep.c | 71 ------- arch/um/ptproxy/sysdep.h | 25 --- arch/um/ptproxy/wait.c | 86 --------- arch/um/ptproxy/wait.h | 15 -- 18 files changed, 908 insertions(+), 892 deletions(-) create mode 100644 arch/um/kernel/tt/Makefile create mode 100644 arch/um/kernel/tt/ptproxy/Makefile create mode 100644 arch/um/kernel/tt/ptproxy/proxy.c create mode 100644 arch/um/kernel/tt/ptproxy/ptproxy.h create mode 100644 arch/um/kernel/tt/ptproxy/ptrace.c create mode 100644 arch/um/kernel/tt/ptproxy/sysdep.c create mode 100644 arch/um/kernel/tt/ptproxy/sysdep.h create mode 100644 arch/um/kernel/tt/ptproxy/wait.c create mode 100644 arch/um/kernel/tt/ptproxy/wait.h delete mode 100644 arch/um/ptproxy/Makefile delete mode 100644 arch/um/ptproxy/proxy.c delete mode 100644 arch/um/ptproxy/ptproxy.h delete mode 100644 arch/um/ptproxy/ptrace.c delete mode 100644 arch/um/ptproxy/sysdep.c delete mode 100644 arch/um/ptproxy/sysdep.h delete mode 100644 arch/um/ptproxy/wait.c delete mode 100644 arch/um/ptproxy/wait.h diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 673ad57d31fa..c2d92d8140db 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -1,3 +1,8 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + EXTRA_TARGETS := unmap_fin.o obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \ @@ -9,32 +14,33 @@ obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \ umid.o user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o +obj-$(CONFIG_GPROF) += gprof_syms.o +obj-$(CONFIG_GCOV) += gmon_syms.o +obj-$(CONFIG_TTY_LOG) += tty_log.o + +subdir-$(CONFIG_PTPROXY) += tt + +user-objs-$(CONFIG_TTY_LOG) += tty_log.o # user_syms.o not included here because Rules.make has its own ideas about # building anything in export-objs -USER_OBJS := $(filter %_user.o,$(obj-y)) config.o helper.o process.o \ - tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o +USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o + process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/kernel/$(file)) -export-objs := ksyms.o process_kern.o signal_kern.o gprof_syms.o gmon_syms.o - UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS)) UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS)) -ifeq ($(CONFIG_MODULES), y) - DMODULES = -D__CONFIG_MODULES__ -endif +DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__ +DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__ -ifeq ($(CONFIG_MODVERSIONS), y) - DMODVERSIONS = -D__CONFIG_MODVERSIONS__ -endif +export-objs-$(CONFIG_GPROF) += gprof_syms.o +export-objs-$(CONFIG_GCOV) += gmon_syms.o -obj-$(CONFIG_GPROF) += gprof_syms.o -obj-$(CONFIG_GCOV) += gmon_syms.o -obj-$(CONFIG_TTY_LOG) += tty_log.o +export-objs := ksyms.o process_kern.o signal_kern.o $(export-objs-y) -CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES) $(DMODVERSIONS) \ +CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \ -I/usr/include -I../include CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS)) @@ -65,6 +71,7 @@ arch/um/kernel/config.o : arch/um/kernel/config.c clean: rm -f config.c + for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done modules: diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile new file mode 100644 index 000000000000..2bce5f2b6ceb --- /dev/null +++ b/arch/um/kernel/tt/Makefile @@ -0,0 +1,9 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +subdir-$(CONFIG_PT_PROXY) += ptproxy + +include $(TOPDIR)/Rules.make + diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile new file mode 100644 index 000000000000..9e9d42817bf2 --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/Makefile @@ -0,0 +1,12 @@ +obj-y = proxy.o ptrace.o sysdep.o wait.o + +USER_OBJS := $(foreach file,$(obj-y),arch/um/ptproxy/$(file)) + +include $(TOPDIR)/Rules.make + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + +clean: + rm -f *.o core child ptproxy + diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c new file mode 100644 index 000000000000..d5cd8c8919ba --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/proxy.c @@ -0,0 +1,370 @@ +/********************************************************************** +proxy.c + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. + +Jeff Dike (jdike@karaya.com) : Modified for integration into uml +**********************************************************************/ + +/* XXX This file shouldn't refer to CONFIG_* */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ptproxy.h" +#include "sysdep.h" +#include "wait.h" + +#include "user_util.h" +#include "user.h" +#include "os.h" +#include "tempfile.h" + +static int debugger_wait(debugger_state *debugger, int *status, int options, + int (*syscall)(debugger_state *debugger, pid_t child), + int (*normal_return)(debugger_state *debugger, + pid_t unused), + int (*wait_return)(debugger_state *debugger, + pid_t unused)) +{ + if(debugger->real_wait){ + debugger->handle_trace = normal_return; + syscall_continue(debugger->pid); + debugger->real_wait = 0; + return(1); + } + debugger->wait_status_ptr = status; + debugger->wait_options = options; + if((debugger->debugee != NULL) && debugger->debugee->event){ + syscall_continue(debugger->pid); + wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL, + NULL); + (*wait_return)(debugger, -1); + return(0); + } + else if(debugger->wait_options & WNOHANG){ + syscall_cancel(debugger->pid, 0); + debugger->handle_trace = syscall; + return(0); + } + else { + syscall_pause(debugger->pid); + debugger->handle_trace = wait_return; + debugger->waiting = 1; + } + return(1); +} + +/* + * Handle debugger trap, i.e. syscall. + */ + +int debugger_syscall(debugger_state *debugger, pid_t child) +{ + long arg1, arg2, arg3, arg4, arg5, result; + int syscall, ret = 0; + + syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4, + &arg5); + + switch(syscall){ + case __NR_execve: + /* execve never returns */ + debugger->handle_trace = debugger_syscall; + break; + + case __NR_ptrace: + if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid; + if(!debugger->debugee->in_context) + child = debugger->debugee->pid; + result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child, + &ret); + syscall_cancel(debugger->pid, result); + debugger->handle_trace = debugger_syscall; + return(ret); + + case __NR_waitpid: + case __NR_wait4: + if(!debugger_wait(debugger, (int *) arg2, arg3, + debugger_syscall, debugger_normal_return, + proxy_wait_return)) + return(0); + break; + + case __NR_kill: + if(!debugger->debugee->in_context) + child = debugger->debugee->pid; + if(arg1 == debugger->debugee->pid){ + result = kill(child, arg2); + syscall_cancel(debugger->pid, result); + debugger->handle_trace = debugger_syscall; + return(0); + } + else debugger->handle_trace = debugger_normal_return; + break; + + default: + debugger->handle_trace = debugger_normal_return; + } + + syscall_continue(debugger->pid); + return(0); +} + +/* Used by the tracing thread */ +static debugger_state parent; +static int parent_syscall(debugger_state *debugger, int pid); + +int init_parent_proxy(int pid) +{ + parent = ((debugger_state) { pid : pid, + wait_options : 0, + wait_status_ptr : NULL, + waiting : 0, + real_wait : 0, + expecting_child : 0, + handle_trace : parent_syscall, + debugee : NULL } ); + return(0); +} + +int parent_normal_return(debugger_state *debugger, pid_t unused) +{ + debugger->handle_trace = parent_syscall; + syscall_continue(debugger->pid); + return(0); +} + +static int parent_syscall(debugger_state *debugger, int pid) +{ + long arg1, arg2, arg3, arg4, arg5; + int syscall; + + syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5); + + if((syscall == __NR_waitpid) || (syscall == __NR_wait4)){ + debugger_wait(&parent, (int *) arg2, arg3, parent_syscall, + parent_normal_return, parent_wait_return); + } + else ptrace(PTRACE_SYSCALL, pid, 0, 0); + return(0); +} + +int debugger_normal_return(debugger_state *debugger, pid_t unused) +{ + debugger->handle_trace = debugger_syscall; + syscall_continue(debugger->pid); + return(0); +} + +void debugger_cancelled_return(debugger_state *debugger, int result) +{ + debugger->handle_trace = debugger_syscall; + syscall_set_result(debugger->pid, result); + syscall_continue(debugger->pid); +} + +/* Used by the tracing thread */ +static debugger_state debugger; +static debugee_state debugee; + +void init_proxy (pid_t debugger_pid, int stopped, int status) +{ + debugger.pid = debugger_pid; + debugger.handle_trace = debugger_syscall; + debugger.debugee = &debugee; + debugger.waiting = 0; + debugger.real_wait = 0; + debugger.expecting_child = 0; + + debugee.pid = 0; + debugee.traced = 0; + debugee.stopped = stopped; + debugee.event = 0; + debugee.zombie = 0; + debugee.died = 0; + debugee.wait_status = status; + debugee.in_context = 1; +} + +int debugger_proxy(int status, int pid) +{ + int ret = 0, sig; + + if(WIFSTOPPED(status)){ + sig = WSTOPSIG(status); + if (sig == SIGTRAP) + ret = (*debugger.handle_trace)(&debugger, pid); + + else if(sig == SIGCHLD){ + if(debugger.expecting_child){ + ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); + debugger.expecting_child = 0; + } + else if(debugger.waiting) + real_wait_return(&debugger); + else { + ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); + debugger.real_wait = 1; + } + } + else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); + } + else if(WIFEXITED(status)){ + tracer_panic("debugger (pid %d) exited with status %d", + debugger.pid, WEXITSTATUS(status)); + } + else if(WIFSIGNALED(status)){ + tracer_panic("debugger (pid %d) exited with signal %d", + debugger.pid, WTERMSIG(status)); + } + else { + tracer_panic("proxy got unknown status (0x%x) on debugger " + "(pid %d)", status, debugger.pid); + } + return(ret); +} + +void child_proxy(pid_t pid, int status) +{ + debugee.event = 1; + debugee.wait_status = status; + + if(WIFSTOPPED(status)){ + debugee.stopped = 1; + debugger.expecting_child = 1; + kill(debugger.pid, SIGCHLD); + } + else if(WIFEXITED(status) || WIFSIGNALED(status)){ + debugee.zombie = 1; + debugger.expecting_child = 1; + kill(debugger.pid, SIGCHLD); + } + else panic("proxy got unknown status (0x%x) on child (pid %d)", + status, pid); +} + +void debugger_parent_signal(int status, int pid) +{ + int sig; + + if(WIFSTOPPED(status)){ + sig = WSTOPSIG(status); + if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid); + else ptrace(PTRACE_SYSCALL, pid, 0, sig); + } +} + +void fake_child_exit(void) +{ + int status, pid; + + child_proxy(1, W_EXITCODE(0, 0)); + while(debugger.waiting == 1){ + pid = waitpid(debugger.pid, &status, WUNTRACED); + if(pid != debugger.pid){ + printk("fake_child_exit - waitpid failed, " + "errno = %d\n", errno); + return; + } + debugger_proxy(status, debugger.pid); + } + pid = waitpid(debugger.pid, &status, WUNTRACED); + if(pid != debugger.pid){ + printk("fake_child_exit - waitpid failed, " + "errno = %d\n", errno); + return; + } + if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0) + printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n", + errno); +} + +char gdb_init_string[] = +"att 1 +b panic +b stop +handle SIGWINCH nostop noprint pass +"; + +int start_debugger(char *prog, int startup, int stop, int *fd_out) +{ + int slave, child; + + slave = open_gdb_chan(); + if((child = fork()) == 0){ + char *tempname = NULL; + int fd; + + if(setsid() < 0) perror("setsid"); + if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || + (dup2(slave, 2) < 0)){ + printk("start_debugger : dup2 failed, errno = %d\n", + errno); + exit(1); + } + if(ioctl(0, TIOCSCTTY, 0) < 0){ + printk("start_debugger : TIOCSCTTY failed, " + "errno = %d\n", errno); + exit(1); + } + if(tcsetpgrp (1, os_getpid()) < 0){ + printk("start_debugger : tcsetpgrp failed, " + "errno = %d\n", errno); +#ifdef notdef + exit(1); +#endif + } + if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){ + printk("start_debugger : make_tempfile failed, errno = %d\n", + errno); + exit(1); + } + write(fd, gdb_init_string, sizeof(gdb_init_string) - 1); + if(startup){ + if(stop){ + write(fd, "b start_kernel\n", + strlen("b start_kernel\n")); + } + write(fd, "c\n", strlen("c\n")); + } + if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ + printk("start_debugger : PTRACE_TRACEME failed, " + "errno = %d\n", errno); + exit(1); + } + execlp("gdb", "gdb", "--command", tempname, prog, NULL); + printk("start_debugger : exec of gdb failed, errno = %d\n", + errno); + } + if(child < 0){ + printk("start_debugger : fork for gdb failed, errno = %d\n", + errno); + return(-1); + } + *fd_out = slave; + return(child); +} + +/* + * 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/tt/ptproxy/ptproxy.h b/arch/um/kernel/tt/ptproxy/ptproxy.h new file mode 100644 index 000000000000..5eb0285b1968 --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/ptproxy.h @@ -0,0 +1,61 @@ +/********************************************************************** +ptproxy.h + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. +**********************************************************************/ + +#ifndef __PTPROXY_H +#define __PTPROXY_H + +#include + +typedef struct debugger debugger_state; +typedef struct debugee debugee_state; + +struct debugger +{ + pid_t pid; + int wait_options; + int *wait_status_ptr; + unsigned int waiting : 1; + unsigned int real_wait : 1; + unsigned int expecting_child : 1; + int (*handle_trace) (debugger_state *, pid_t); + + debugee_state *debugee; +}; + +struct debugee +{ + pid_t pid; + int wait_status; + unsigned int died : 1; + unsigned int event : 1; + unsigned int stopped : 1; + unsigned int trace_singlestep : 1; + unsigned int trace_syscall : 1; + unsigned int traced : 1; + unsigned int zombie : 1; + unsigned int in_context : 1; +}; + +extern int debugger_syscall(debugger_state *debugger, pid_t pid); +extern int debugger_normal_return (debugger_state *debugger, pid_t unused); + +extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t, + int *strace_out); +extern void debugger_cancelled_return(debugger_state *debugger, int result); + +#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/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c new file mode 100644 index 000000000000..910d026677ca --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/ptrace.c @@ -0,0 +1,238 @@ +/********************************************************************** +ptrace.c + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. + +Jeff Dike (jdike@karaya.com) : Modified for integration into uml +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ptproxy.h" +#include "debug.h" +#include "user_util.h" +#include "kern_util.h" +#include "ptrace_user.h" + +long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, + long arg3, long arg4, pid_t child, int *ret) +{ + sigset_t relay; + long result; + int status; + + *ret = 0; + if(debugger->debugee->died) return(-ESRCH); + + switch(arg1){ + case PTRACE_ATTACH: + if(debugger->debugee->traced) return(-EPERM); + + debugger->debugee->pid = arg2; + debugger->debugee->traced = 1; + + if(is_valid_pid(arg2) && (arg2 != child)){ + debugger->debugee->in_context = 0; + kill(arg2, SIGSTOP); + debugger->debugee->event = 1; + debugger->debugee->wait_status = W_STOPCODE(SIGSTOP); + } + else { + debugger->debugee->in_context = 1; + if(debugger->debugee->stopped) + child_proxy(child, W_STOPCODE(SIGSTOP)); + else kill(child, SIGSTOP); + } + + return(0); + + case PTRACE_DETACH: + if(!debugger->debugee->traced) return(-EPERM); + + debugger->debugee->traced = 0; + debugger->debugee->pid = 0; + if(!debugger->debugee->in_context) + kill(child, SIGCONT); + + return(0); + + case PTRACE_CONT: + if(!debugger->debugee->in_context) return(-EPERM); + *ret = PTRACE_CONT; + return(ptrace(PTRACE_CONT, child, arg3, arg4)); + +#ifdef UM_HAVE_GETFPREGS + case PTRACE_GETFPREGS: + { + long regs[FP_FRAME_SIZE]; + int i, result; + + result = ptrace(PTRACE_GETFPREGS, child, 0, regs); + if(result == -1) return(-errno); + + for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) + ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, + regs[i]); + return(result); + } +#endif + +#ifdef UM_HAVE_GETFPXREGS + case PTRACE_GETFPXREGS: + { + long regs[FPX_FRAME_SIZE]; + int i, result; + + result = ptrace(PTRACE_GETFPXREGS, child, 0, regs); + if(result == -1) return(-errno); + + for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) + ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, + regs[i]); + return(result); + } +#endif + +#ifdef UM_HAVE_GETREGS + case PTRACE_GETREGS: + { + long regs[FRAME_SIZE]; + int i, result; + + result = ptrace(PTRACE_GETREGS, child, 0, regs); + if(result == -1) return(-errno); + + for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) + ptrace (PTRACE_POKEDATA, debugger->pid, + arg4 + 4 * i, regs[i]); + return(result); + } + break; +#endif + + case PTRACE_KILL: + result = ptrace(PTRACE_KILL, child, arg3, arg4); + if(result == -1) return(-errno); + + return(result); + + case PTRACE_PEEKDATA: + case PTRACE_PEEKTEXT: + case PTRACE_PEEKUSER: + /* The value being read out could be -1, so we have to + * check errno to see if there's an error, and zero it + * beforehand so we're not faked out by an old error + */ + + errno = 0; + result = ptrace(arg1, child, arg3, 0); + if((result == -1) && (errno != 0)) return(-errno); + + result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result); + if(result == -1) return(-errno); + + return(result); + + case PTRACE_POKEDATA: + case PTRACE_POKETEXT: + case PTRACE_POKEUSER: + result = ptrace(arg1, child, arg3, arg4); + if(result == -1) return(-errno); + + if(arg1 == PTRACE_POKEUSER) ptrace_pokeuser(arg3, arg4); + return(result); + +#ifdef UM_HAVE_SETFPREGS + case PTRACE_SETFPREGS: + { + long regs[FP_FRAME_SIZE]; + int i; + + for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) + regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, + arg4 + 4 * i, 0); + result = ptrace(PTRACE_SETFPREGS, child, 0, regs); + if(result == -1) return(-errno); + + return(result); + } +#endif + +#ifdef UM_HAVE_SETFPXREGS + case PTRACE_SETFPXREGS: + { + long regs[FPX_FRAME_SIZE]; + int i; + + for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) + regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, + arg4 + 4 * i, 0); + result = ptrace(PTRACE_SETFPXREGS, child, 0, regs); + if(result == -1) return(-errno); + + return(result); + } +#endif + +#ifdef UM_HAVE_SETREGS + case PTRACE_SETREGS: + { + long regs[FRAME_SIZE]; + int i; + + for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) + regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid, + arg4 + 4 * i, 0); + result = ptrace(PTRACE_SETREGS, child, 0, regs); + if(result == -1) return(-errno); + + return(result); + } +#endif + + case PTRACE_SINGLESTEP: + if(!debugger->debugee->in_context) return(-EPERM); + sigemptyset(&relay); + sigaddset(&relay, SIGSEGV); + sigaddset(&relay, SIGILL); + sigaddset(&relay, SIGBUS); + result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4); + if(result == -1) return(-errno); + + status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP, + &relay); + child_proxy(child, status); + return(result); + + case PTRACE_SYSCALL: + if(!debugger->debugee->in_context) return(-EPERM); + result = ptrace(PTRACE_SYSCALL, child, arg3, arg4); + if(result == -1) return(-errno); + + *ret = PTRACE_SYSCALL; + return(result); + + case PTRACE_TRACEME: + default: + return(-EINVAL); + } +} + +/* + * 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/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c new file mode 100644 index 000000000000..50a120d5e65c --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/sysdep.c @@ -0,0 +1,71 @@ +/********************************************************************** +sysdep.c + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ptrace_user.h" +#include "user_util.h" +#include "user.h" + +int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, + long *arg5) +{ + *arg1 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG1_OFFSET, 0); + *arg2 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG2_OFFSET, 0); + *arg3 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG3_OFFSET, 0); + *arg4 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG4_OFFSET, 0); + *arg5 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG5_OFFSET, 0); + return(ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0)); +} + +void syscall_cancel(pid_t pid, int result) +{ + if((ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, + __NR_getpid) < 0) || + (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) || + (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) || + (ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result) < 0) || + (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)) + printk("ptproxy: couldn't cancel syscall: errno = %d\n", + errno); +} + +void syscall_set_result(pid_t pid, long result) +{ + ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result); +} + +void syscall_continue(pid_t pid) +{ + ptrace(PTRACE_SYSCALL, pid, 0, 0); +} + +int syscall_pause(pid_t pid) +{ + if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){ + printk("syscall_change - ptrace failed, errno = %d\n", errno); + return(-1); + } + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/ptproxy/sysdep.h b/arch/um/kernel/tt/ptproxy/sysdep.h new file mode 100644 index 000000000000..735f488049aa --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/sysdep.h @@ -0,0 +1,25 @@ +/********************************************************************** +sysdep.h + +Copyright (C) 1999 Lars Brinkhoff. +Copyright (C) 2001 Jeff Dike (jdike@karaya.com) +See the file COPYING for licensing terms and conditions. +**********************************************************************/ + +extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, + long *arg4, long *arg5); +extern void syscall_cancel (pid_t pid, long result); +extern void syscall_set_result (pid_t pid, long result); +extern void syscall_continue (pid_t pid); +extern int syscall_pause(pid_t pid); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c new file mode 100644 index 000000000000..aad7e4b62ee5 --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/wait.c @@ -0,0 +1,86 @@ +/********************************************************************** +wait.c + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. + +**********************************************************************/ + +#include +#include +#include +#include +#include + +#include "ptproxy.h" +#include "sysdep.h" +#include "wait.h" +#include "user_util.h" +#include "sysdep/ptrace.h" +#include "sysdep/ptrace_user.h" +#include "sysdep/sigcontext.h" + +int proxy_wait_return(struct debugger *debugger, pid_t unused) +{ + debugger->waiting = 0; + + if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){ + debugger_cancelled_return(debugger, -ECHILD); + return(0); + } + + if(debugger->debugee->zombie && debugger->debugee->event) + debugger->debugee->died = 1; + + if(debugger->debugee->event){ + debugger->debugee->event = 0; + ptrace(PTRACE_POKEDATA, debugger->pid, + debugger->wait_status_ptr, + debugger->debugee->wait_status); + /* if (wait4) + ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */ + debugger_cancelled_return(debugger, debugger->debugee->pid); + return(0); + } + + /* pause will return -EINTR, which happens to be right for wait */ + debugger_normal_return(debugger, -1); + return(0); +} + +int parent_wait_return(struct debugger *debugger, pid_t unused) +{ + return(debugger_normal_return(debugger, -1)); +} + +int real_wait_return(struct debugger *debugger) +{ + unsigned long ip; + int err, pid; + + pid = debugger->pid; + ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0); + ip = IP_RESTART_SYSCALL(ip); + err = ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip); + if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0) + tracer_panic("real_wait_return : Failed to restart system " + "call, errno = %d\n"); + if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) || + (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || + (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || + debugger_normal_return(debugger, -1)) + tracer_panic("real_wait_return : gdb failed to wait, " + "errno = %d\n"); + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/ptproxy/wait.h b/arch/um/kernel/tt/ptproxy/wait.h new file mode 100644 index 000000000000..542e73ee2cee --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/wait.h @@ -0,0 +1,15 @@ +/********************************************************************** +wait.h + +Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing +terms and conditions. +**********************************************************************/ + +#ifndef __PTPROXY_WAIT_H +#define __PTPROXY_WAIT_H + +extern int proxy_wait_return(struct debugger *debugger, pid_t unused); +extern int real_wait_return(struct debugger *debugger); +extern int parent_wait_return(struct debugger *debugger, pid_t unused); + +#endif diff --git a/arch/um/ptproxy/Makefile b/arch/um/ptproxy/Makefile deleted file mode 100644 index 9e9d42817bf2..000000000000 --- a/arch/um/ptproxy/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -obj-y = proxy.o ptrace.o sysdep.o wait.o - -USER_OBJS := $(foreach file,$(obj-y),arch/um/ptproxy/$(file)) - -include $(TOPDIR)/Rules.make - -$(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< - -clean: - rm -f *.o core child ptproxy - diff --git a/arch/um/ptproxy/proxy.c b/arch/um/ptproxy/proxy.c deleted file mode 100644 index d5cd8c8919ba..000000000000 --- a/arch/um/ptproxy/proxy.c +++ /dev/null @@ -1,370 +0,0 @@ -/********************************************************************** -proxy.c - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. - -Jeff Dike (jdike@karaya.com) : Modified for integration into uml -**********************************************************************/ - -/* XXX This file shouldn't refer to CONFIG_* */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ptproxy.h" -#include "sysdep.h" -#include "wait.h" - -#include "user_util.h" -#include "user.h" -#include "os.h" -#include "tempfile.h" - -static int debugger_wait(debugger_state *debugger, int *status, int options, - int (*syscall)(debugger_state *debugger, pid_t child), - int (*normal_return)(debugger_state *debugger, - pid_t unused), - int (*wait_return)(debugger_state *debugger, - pid_t unused)) -{ - if(debugger->real_wait){ - debugger->handle_trace = normal_return; - syscall_continue(debugger->pid); - debugger->real_wait = 0; - return(1); - } - debugger->wait_status_ptr = status; - debugger->wait_options = options; - if((debugger->debugee != NULL) && debugger->debugee->event){ - syscall_continue(debugger->pid); - wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL, - NULL); - (*wait_return)(debugger, -1); - return(0); - } - else if(debugger->wait_options & WNOHANG){ - syscall_cancel(debugger->pid, 0); - debugger->handle_trace = syscall; - return(0); - } - else { - syscall_pause(debugger->pid); - debugger->handle_trace = wait_return; - debugger->waiting = 1; - } - return(1); -} - -/* - * Handle debugger trap, i.e. syscall. - */ - -int debugger_syscall(debugger_state *debugger, pid_t child) -{ - long arg1, arg2, arg3, arg4, arg5, result; - int syscall, ret = 0; - - syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4, - &arg5); - - switch(syscall){ - case __NR_execve: - /* execve never returns */ - debugger->handle_trace = debugger_syscall; - break; - - case __NR_ptrace: - if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid; - if(!debugger->debugee->in_context) - child = debugger->debugee->pid; - result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child, - &ret); - syscall_cancel(debugger->pid, result); - debugger->handle_trace = debugger_syscall; - return(ret); - - case __NR_waitpid: - case __NR_wait4: - if(!debugger_wait(debugger, (int *) arg2, arg3, - debugger_syscall, debugger_normal_return, - proxy_wait_return)) - return(0); - break; - - case __NR_kill: - if(!debugger->debugee->in_context) - child = debugger->debugee->pid; - if(arg1 == debugger->debugee->pid){ - result = kill(child, arg2); - syscall_cancel(debugger->pid, result); - debugger->handle_trace = debugger_syscall; - return(0); - } - else debugger->handle_trace = debugger_normal_return; - break; - - default: - debugger->handle_trace = debugger_normal_return; - } - - syscall_continue(debugger->pid); - return(0); -} - -/* Used by the tracing thread */ -static debugger_state parent; -static int parent_syscall(debugger_state *debugger, int pid); - -int init_parent_proxy(int pid) -{ - parent = ((debugger_state) { pid : pid, - wait_options : 0, - wait_status_ptr : NULL, - waiting : 0, - real_wait : 0, - expecting_child : 0, - handle_trace : parent_syscall, - debugee : NULL } ); - return(0); -} - -int parent_normal_return(debugger_state *debugger, pid_t unused) -{ - debugger->handle_trace = parent_syscall; - syscall_continue(debugger->pid); - return(0); -} - -static int parent_syscall(debugger_state *debugger, int pid) -{ - long arg1, arg2, arg3, arg4, arg5; - int syscall; - - syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5); - - if((syscall == __NR_waitpid) || (syscall == __NR_wait4)){ - debugger_wait(&parent, (int *) arg2, arg3, parent_syscall, - parent_normal_return, parent_wait_return); - } - else ptrace(PTRACE_SYSCALL, pid, 0, 0); - return(0); -} - -int debugger_normal_return(debugger_state *debugger, pid_t unused) -{ - debugger->handle_trace = debugger_syscall; - syscall_continue(debugger->pid); - return(0); -} - -void debugger_cancelled_return(debugger_state *debugger, int result) -{ - debugger->handle_trace = debugger_syscall; - syscall_set_result(debugger->pid, result); - syscall_continue(debugger->pid); -} - -/* Used by the tracing thread */ -static debugger_state debugger; -static debugee_state debugee; - -void init_proxy (pid_t debugger_pid, int stopped, int status) -{ - debugger.pid = debugger_pid; - debugger.handle_trace = debugger_syscall; - debugger.debugee = &debugee; - debugger.waiting = 0; - debugger.real_wait = 0; - debugger.expecting_child = 0; - - debugee.pid = 0; - debugee.traced = 0; - debugee.stopped = stopped; - debugee.event = 0; - debugee.zombie = 0; - debugee.died = 0; - debugee.wait_status = status; - debugee.in_context = 1; -} - -int debugger_proxy(int status, int pid) -{ - int ret = 0, sig; - - if(WIFSTOPPED(status)){ - sig = WSTOPSIG(status); - if (sig == SIGTRAP) - ret = (*debugger.handle_trace)(&debugger, pid); - - else if(sig == SIGCHLD){ - if(debugger.expecting_child){ - ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); - debugger.expecting_child = 0; - } - else if(debugger.waiting) - real_wait_return(&debugger); - else { - ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); - debugger.real_wait = 1; - } - } - else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); - } - else if(WIFEXITED(status)){ - tracer_panic("debugger (pid %d) exited with status %d", - debugger.pid, WEXITSTATUS(status)); - } - else if(WIFSIGNALED(status)){ - tracer_panic("debugger (pid %d) exited with signal %d", - debugger.pid, WTERMSIG(status)); - } - else { - tracer_panic("proxy got unknown status (0x%x) on debugger " - "(pid %d)", status, debugger.pid); - } - return(ret); -} - -void child_proxy(pid_t pid, int status) -{ - debugee.event = 1; - debugee.wait_status = status; - - if(WIFSTOPPED(status)){ - debugee.stopped = 1; - debugger.expecting_child = 1; - kill(debugger.pid, SIGCHLD); - } - else if(WIFEXITED(status) || WIFSIGNALED(status)){ - debugee.zombie = 1; - debugger.expecting_child = 1; - kill(debugger.pid, SIGCHLD); - } - else panic("proxy got unknown status (0x%x) on child (pid %d)", - status, pid); -} - -void debugger_parent_signal(int status, int pid) -{ - int sig; - - if(WIFSTOPPED(status)){ - sig = WSTOPSIG(status); - if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid); - else ptrace(PTRACE_SYSCALL, pid, 0, sig); - } -} - -void fake_child_exit(void) -{ - int status, pid; - - child_proxy(1, W_EXITCODE(0, 0)); - while(debugger.waiting == 1){ - pid = waitpid(debugger.pid, &status, WUNTRACED); - if(pid != debugger.pid){ - printk("fake_child_exit - waitpid failed, " - "errno = %d\n", errno); - return; - } - debugger_proxy(status, debugger.pid); - } - pid = waitpid(debugger.pid, &status, WUNTRACED); - if(pid != debugger.pid){ - printk("fake_child_exit - waitpid failed, " - "errno = %d\n", errno); - return; - } - if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0) - printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n", - errno); -} - -char gdb_init_string[] = -"att 1 -b panic -b stop -handle SIGWINCH nostop noprint pass -"; - -int start_debugger(char *prog, int startup, int stop, int *fd_out) -{ - int slave, child; - - slave = open_gdb_chan(); - if((child = fork()) == 0){ - char *tempname = NULL; - int fd; - - if(setsid() < 0) perror("setsid"); - if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || - (dup2(slave, 2) < 0)){ - printk("start_debugger : dup2 failed, errno = %d\n", - errno); - exit(1); - } - if(ioctl(0, TIOCSCTTY, 0) < 0){ - printk("start_debugger : TIOCSCTTY failed, " - "errno = %d\n", errno); - exit(1); - } - if(tcsetpgrp (1, os_getpid()) < 0){ - printk("start_debugger : tcsetpgrp failed, " - "errno = %d\n", errno); -#ifdef notdef - exit(1); -#endif - } - if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){ - printk("start_debugger : make_tempfile failed, errno = %d\n", - errno); - exit(1); - } - write(fd, gdb_init_string, sizeof(gdb_init_string) - 1); - if(startup){ - if(stop){ - write(fd, "b start_kernel\n", - strlen("b start_kernel\n")); - } - write(fd, "c\n", strlen("c\n")); - } - if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ - printk("start_debugger : PTRACE_TRACEME failed, " - "errno = %d\n", errno); - exit(1); - } - execlp("gdb", "gdb", "--command", tempname, prog, NULL); - printk("start_debugger : exec of gdb failed, errno = %d\n", - errno); - } - if(child < 0){ - printk("start_debugger : fork for gdb failed, errno = %d\n", - errno); - return(-1); - } - *fd_out = slave; - return(child); -} - -/* - * 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/ptproxy/ptproxy.h b/arch/um/ptproxy/ptproxy.h deleted file mode 100644 index 5eb0285b1968..000000000000 --- a/arch/um/ptproxy/ptproxy.h +++ /dev/null @@ -1,61 +0,0 @@ -/********************************************************************** -ptproxy.h - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. -**********************************************************************/ - -#ifndef __PTPROXY_H -#define __PTPROXY_H - -#include - -typedef struct debugger debugger_state; -typedef struct debugee debugee_state; - -struct debugger -{ - pid_t pid; - int wait_options; - int *wait_status_ptr; - unsigned int waiting : 1; - unsigned int real_wait : 1; - unsigned int expecting_child : 1; - int (*handle_trace) (debugger_state *, pid_t); - - debugee_state *debugee; -}; - -struct debugee -{ - pid_t pid; - int wait_status; - unsigned int died : 1; - unsigned int event : 1; - unsigned int stopped : 1; - unsigned int trace_singlestep : 1; - unsigned int trace_syscall : 1; - unsigned int traced : 1; - unsigned int zombie : 1; - unsigned int in_context : 1; -}; - -extern int debugger_syscall(debugger_state *debugger, pid_t pid); -extern int debugger_normal_return (debugger_state *debugger, pid_t unused); - -extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t, - int *strace_out); -extern void debugger_cancelled_return(debugger_state *debugger, int result); - -#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/ptproxy/ptrace.c b/arch/um/ptproxy/ptrace.c deleted file mode 100644 index 910d026677ca..000000000000 --- a/arch/um/ptproxy/ptrace.c +++ /dev/null @@ -1,238 +0,0 @@ -/********************************************************************** -ptrace.c - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. - -Jeff Dike (jdike@karaya.com) : Modified for integration into uml -**********************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ptproxy.h" -#include "debug.h" -#include "user_util.h" -#include "kern_util.h" -#include "ptrace_user.h" - -long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, - long arg3, long arg4, pid_t child, int *ret) -{ - sigset_t relay; - long result; - int status; - - *ret = 0; - if(debugger->debugee->died) return(-ESRCH); - - switch(arg1){ - case PTRACE_ATTACH: - if(debugger->debugee->traced) return(-EPERM); - - debugger->debugee->pid = arg2; - debugger->debugee->traced = 1; - - if(is_valid_pid(arg2) && (arg2 != child)){ - debugger->debugee->in_context = 0; - kill(arg2, SIGSTOP); - debugger->debugee->event = 1; - debugger->debugee->wait_status = W_STOPCODE(SIGSTOP); - } - else { - debugger->debugee->in_context = 1; - if(debugger->debugee->stopped) - child_proxy(child, W_STOPCODE(SIGSTOP)); - else kill(child, SIGSTOP); - } - - return(0); - - case PTRACE_DETACH: - if(!debugger->debugee->traced) return(-EPERM); - - debugger->debugee->traced = 0; - debugger->debugee->pid = 0; - if(!debugger->debugee->in_context) - kill(child, SIGCONT); - - return(0); - - case PTRACE_CONT: - if(!debugger->debugee->in_context) return(-EPERM); - *ret = PTRACE_CONT; - return(ptrace(PTRACE_CONT, child, arg3, arg4)); - -#ifdef UM_HAVE_GETFPREGS - case PTRACE_GETFPREGS: - { - long regs[FP_FRAME_SIZE]; - int i, result; - - result = ptrace(PTRACE_GETFPREGS, child, 0, regs); - if(result == -1) return(-errno); - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, - regs[i]); - return(result); - } -#endif - -#ifdef UM_HAVE_GETFPXREGS - case PTRACE_GETFPXREGS: - { - long regs[FPX_FRAME_SIZE]; - int i, result; - - result = ptrace(PTRACE_GETFPXREGS, child, 0, regs); - if(result == -1) return(-errno); - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, - regs[i]); - return(result); - } -#endif - -#ifdef UM_HAVE_GETREGS - case PTRACE_GETREGS: - { - long regs[FRAME_SIZE]; - int i, result; - - result = ptrace(PTRACE_GETREGS, child, 0, regs); - if(result == -1) return(-errno); - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - ptrace (PTRACE_POKEDATA, debugger->pid, - arg4 + 4 * i, regs[i]); - return(result); - } - break; -#endif - - case PTRACE_KILL: - result = ptrace(PTRACE_KILL, child, arg3, arg4); - if(result == -1) return(-errno); - - return(result); - - case PTRACE_PEEKDATA: - case PTRACE_PEEKTEXT: - case PTRACE_PEEKUSER: - /* The value being read out could be -1, so we have to - * check errno to see if there's an error, and zero it - * beforehand so we're not faked out by an old error - */ - - errno = 0; - result = ptrace(arg1, child, arg3, 0); - if((result == -1) && (errno != 0)) return(-errno); - - result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result); - if(result == -1) return(-errno); - - return(result); - - case PTRACE_POKEDATA: - case PTRACE_POKETEXT: - case PTRACE_POKEUSER: - result = ptrace(arg1, child, arg3, arg4); - if(result == -1) return(-errno); - - if(arg1 == PTRACE_POKEUSER) ptrace_pokeuser(arg3, arg4); - return(result); - -#ifdef UM_HAVE_SETFPREGS - case PTRACE_SETFPREGS: - { - long regs[FP_FRAME_SIZE]; - int i; - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, - arg4 + 4 * i, 0); - result = ptrace(PTRACE_SETFPREGS, child, 0, regs); - if(result == -1) return(-errno); - - return(result); - } -#endif - -#ifdef UM_HAVE_SETFPXREGS - case PTRACE_SETFPXREGS: - { - long regs[FPX_FRAME_SIZE]; - int i; - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, - arg4 + 4 * i, 0); - result = ptrace(PTRACE_SETFPXREGS, child, 0, regs); - if(result == -1) return(-errno); - - return(result); - } -#endif - -#ifdef UM_HAVE_SETREGS - case PTRACE_SETREGS: - { - long regs[FRAME_SIZE]; - int i; - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid, - arg4 + 4 * i, 0); - result = ptrace(PTRACE_SETREGS, child, 0, regs); - if(result == -1) return(-errno); - - return(result); - } -#endif - - case PTRACE_SINGLESTEP: - if(!debugger->debugee->in_context) return(-EPERM); - sigemptyset(&relay); - sigaddset(&relay, SIGSEGV); - sigaddset(&relay, SIGILL); - sigaddset(&relay, SIGBUS); - result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4); - if(result == -1) return(-errno); - - status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP, - &relay); - child_proxy(child, status); - return(result); - - case PTRACE_SYSCALL: - if(!debugger->debugee->in_context) return(-EPERM); - result = ptrace(PTRACE_SYSCALL, child, arg3, arg4); - if(result == -1) return(-errno); - - *ret = PTRACE_SYSCALL; - return(result); - - case PTRACE_TRACEME: - default: - return(-EINVAL); - } -} - -/* - * 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/ptproxy/sysdep.c b/arch/um/ptproxy/sysdep.c deleted file mode 100644 index 50a120d5e65c..000000000000 --- a/arch/um/ptproxy/sysdep.c +++ /dev/null @@ -1,71 +0,0 @@ -/********************************************************************** -sysdep.c - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. -**********************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "ptrace_user.h" -#include "user_util.h" -#include "user.h" - -int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, - long *arg5) -{ - *arg1 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG1_OFFSET, 0); - *arg2 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG2_OFFSET, 0); - *arg3 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG3_OFFSET, 0); - *arg4 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG4_OFFSET, 0); - *arg5 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG5_OFFSET, 0); - return(ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0)); -} - -void syscall_cancel(pid_t pid, int result) -{ - if((ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, - __NR_getpid) < 0) || - (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) || - (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) || - (ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result) < 0) || - (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)) - printk("ptproxy: couldn't cancel syscall: errno = %d\n", - errno); -} - -void syscall_set_result(pid_t pid, long result) -{ - ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result); -} - -void syscall_continue(pid_t pid) -{ - ptrace(PTRACE_SYSCALL, pid, 0, 0); -} - -int syscall_pause(pid_t pid) -{ - if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){ - printk("syscall_change - ptrace failed, errno = %d\n", errno); - return(-1); - } - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/ptproxy/sysdep.h b/arch/um/ptproxy/sysdep.h deleted file mode 100644 index 735f488049aa..000000000000 --- a/arch/um/ptproxy/sysdep.h +++ /dev/null @@ -1,25 +0,0 @@ -/********************************************************************** -sysdep.h - -Copyright (C) 1999 Lars Brinkhoff. -Copyright (C) 2001 Jeff Dike (jdike@karaya.com) -See the file COPYING for licensing terms and conditions. -**********************************************************************/ - -extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, - long *arg4, long *arg5); -extern void syscall_cancel (pid_t pid, long result); -extern void syscall_set_result (pid_t pid, long result); -extern void syscall_continue (pid_t pid); -extern int syscall_pause(pid_t pid); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/ptproxy/wait.c b/arch/um/ptproxy/wait.c deleted file mode 100644 index aad7e4b62ee5..000000000000 --- a/arch/um/ptproxy/wait.c +++ /dev/null @@ -1,86 +0,0 @@ -/********************************************************************** -wait.c - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. - -**********************************************************************/ - -#include -#include -#include -#include -#include - -#include "ptproxy.h" -#include "sysdep.h" -#include "wait.h" -#include "user_util.h" -#include "sysdep/ptrace.h" -#include "sysdep/ptrace_user.h" -#include "sysdep/sigcontext.h" - -int proxy_wait_return(struct debugger *debugger, pid_t unused) -{ - debugger->waiting = 0; - - if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){ - debugger_cancelled_return(debugger, -ECHILD); - return(0); - } - - if(debugger->debugee->zombie && debugger->debugee->event) - debugger->debugee->died = 1; - - if(debugger->debugee->event){ - debugger->debugee->event = 0; - ptrace(PTRACE_POKEDATA, debugger->pid, - debugger->wait_status_ptr, - debugger->debugee->wait_status); - /* if (wait4) - ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */ - debugger_cancelled_return(debugger, debugger->debugee->pid); - return(0); - } - - /* pause will return -EINTR, which happens to be right for wait */ - debugger_normal_return(debugger, -1); - return(0); -} - -int parent_wait_return(struct debugger *debugger, pid_t unused) -{ - return(debugger_normal_return(debugger, -1)); -} - -int real_wait_return(struct debugger *debugger) -{ - unsigned long ip; - int err, pid; - - pid = debugger->pid; - ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0); - ip = IP_RESTART_SYSCALL(ip); - err = ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip); - if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0) - tracer_panic("real_wait_return : Failed to restart system " - "call, errno = %d\n"); - if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) || - (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || - (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || - debugger_normal_return(debugger, -1)) - tracer_panic("real_wait_return : gdb failed to wait, " - "errno = %d\n"); - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/ptproxy/wait.h b/arch/um/ptproxy/wait.h deleted file mode 100644 index 542e73ee2cee..000000000000 --- a/arch/um/ptproxy/wait.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************** -wait.h - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. -**********************************************************************/ - -#ifndef __PTPROXY_WAIT_H -#define __PTPROXY_WAIT_H - -extern int proxy_wait_return(struct debugger *debugger, pid_t unused); -extern int real_wait_return(struct debugger *debugger); -extern int parent_wait_return(struct debugger *debugger, pid_t unused); - -#endif -- cgit v1.2.3 From 8c04ef75cd9c5a91a5af8e7871bbfeb419aa2fc2 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 13:28:32 -0500 Subject: Fixed the Makefiles so that the ptproxy move from arch/um/ptproxy to arch/um/kernel/tt/ptproxy works. --- arch/um/Makefile | 2 -- arch/um/kernel/Makefile | 4 ++-- arch/um/kernel/tt/Makefile | 2 +- arch/um/kernel/tt/ptproxy/Makefile | 10 +++++++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/um/Makefile b/arch/um/Makefile index e4ad81702045..7d404a6126a7 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -31,8 +31,6 @@ core-y += $(ARCH_DIR)/kernel/ \ $(ARCH_DIR)/drivers/ \ $(ARCH_DIR)/sys-$(SUBARCH)/ -core-$(CONFIG_PT_PROXY) += $(ARCH_DIR)/ptproxy/ - ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include # -Derrno=kernel_errno - This turns all kernel references to errno into diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index c2d92d8140db..19b3ff84109c 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -18,14 +18,14 @@ obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o obj-$(CONFIG_TTY_LOG) += tty_log.o -subdir-$(CONFIG_PTPROXY) += tt +obj-$(CONFIG_PT_PROXY) += tt/ user-objs-$(CONFIG_TTY_LOG) += tty_log.o # user_syms.o not included here because Rules.make has its own ideas about # building anything in export-objs -USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o +USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \ process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/kernel/$(file)) diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 2bce5f2b6ceb..b2c6c5045eac 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -3,7 +3,7 @@ # Licensed under the GPL # -subdir-$(CONFIG_PT_PROXY) += ptproxy +obj-$(CONFIG_PT_PROXY) += ptproxy/ include $(TOPDIR)/Rules.make diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile index 9e9d42817bf2..cf94d8b61c88 100644 --- a/arch/um/kernel/tt/ptproxy/Makefile +++ b/arch/um/kernel/tt/ptproxy/Makefile @@ -1,12 +1,16 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + obj-y = proxy.o ptrace.o sysdep.o wait.o -USER_OBJS := $(foreach file,$(obj-y),arch/um/ptproxy/$(file)) +USER_OBJS := $(foreach file,$(obj-y),$(src)/$(file)) include $(TOPDIR)/Rules.make $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< clean: rm -f *.o core child ptproxy - -- cgit v1.2.3 From 952b67f179cf2b69f9d8061d6ee566cb3b9b3c0b Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 14:13:26 -0500 Subject: Merged the os_kill_process and the driver from_user changes from the 2.4 pool. Also merged some other cleanups. --- arch/um/drivers/line.c | 19 +++++- arch/um/drivers/port_kern.c | 13 ++-- arch/um/drivers/ssl.c | 4 +- arch/um/drivers/stdio_console.c | 2 +- arch/um/include/debug.h | 26 ------- arch/um/include/line.h | 5 +- arch/um/include/os.h | 8 ++- arch/um/kernel/helper.c | 5 +- arch/um/kernel/process.c | 109 ++++++++++++++++++++++++++---- arch/um/kernel/signal_user.c | 18 +++-- arch/um/kernel/tt/ptproxy/include/debug.h | 26 +++++++ arch/um/os-Linux/process.c | 5 +- 12 files changed, 177 insertions(+), 63 deletions(-) delete mode 100644 arch/um/include/debug.h create mode 100644 arch/um/kernel/tt/ptproxy/include/debug.h diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 837c07f41669..4a6540ec6d11 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -8,11 +8,13 @@ #include "linux/list.h" #include "linux/devfs_fs_kernel.h" #include "asm/irq.h" +#include "asm/uaccess.h" #include "chan_kern.h" #include "irq_user.h" #include "line.h" #include "kern.h" #include "user_util.h" +#include "kern_util.h" #include "os.h" #define LINE_BUFSIZE 4096 @@ -87,15 +89,26 @@ static int flush_buffer(struct line *line) return(line->head == line->tail); } -int line_write(struct line *lines, struct tty_struct *tty, const char *buf, - int len) +int line_write(struct line *lines, struct tty_struct *tty, int from_user, + const char *buf, int len) { struct line *line; + char *new; unsigned long flags; int n, err, i; if(tty->stopped) return 0; + if(from_user){ + new = kmalloc(len, GFP_KERNEL); + if(new == NULL) + return(0); + n = copy_from_user(new, buf, len); + if(n == len) + return(-EFAULT); + buf = new; + } + i = minor(tty->device) - tty->driver.minor_start; line = &lines[i]; @@ -451,7 +464,7 @@ static void winch_cleanup(void) list_for_each(ele, &winch_handlers){ winch = list_entry(ele, struct winch, list); close(winch->fd); - if(winch->pid != -1) os_kill_process(winch->pid); + if(winch->pid != -1) os_kill_process(winch->pid, 0); } } diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 25a1c47c116f..ecbd41f7c3f9 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -99,14 +99,13 @@ static int port_accept(struct port_list *port) } list_add(&conn->list, &port->pending); - ret = 1; - goto out; + return(1); out_free: kfree(conn); out_close: os_close_file(fd); - if(pid != -1) os_kill_process(pid); + if(pid != -1) os_kill_process(pid, 0); out: return(ret); } @@ -210,9 +209,9 @@ void port_remove_dev(void *d) struct port_dev *dev = d; if(dev->helper_pid != -1) - os_kill_process(dev->helper_pid); + os_kill_process(dev->helper_pid, 0); if(dev->telnetd_pid != -1) - os_kill_process(dev->telnetd_pid); + os_kill_process(dev->telnetd_pid, 0); dev->helper_pid = -1; } @@ -275,8 +274,8 @@ void port_kern_free(void *d) { struct port_dev *dev = d; - if(dev->helper_pid != -1) os_kill_process(dev->telnetd_pid); - if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid); + if(dev->helper_pid != -1) os_kill_process(dev->helper_pid, 0); + if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid, 0); kfree(dev); } diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index c0cd826d9d8b..3dc4c0fc0f88 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -83,12 +83,12 @@ static void ssl_close(struct tty_struct *tty, struct file * filp) static int ssl_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { - return(line_write(serial_lines, tty, buf, count)); + return(line_write(serial_lines, tty, from_user, buf, count)); } static void ssl_put_char(struct tty_struct *tty, unsigned char ch) { - line_write(serial_lines, tty, &ch, sizeof(ch)); + line_write(serial_lines, tty, 0, &ch, sizeof(ch)); } static void ssl_flush_chars(struct tty_struct *tty) diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 4803c3e071b0..1a73476b26d1 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -120,7 +120,7 @@ static void con_close(struct tty_struct *tty, struct file *filp) static int con_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) { - return(line_write(vts, tty, buf, count)); + return(line_write(vts, tty, from_user, buf, count)); } static void set_termios(struct tty_struct *tty, struct termios * old) diff --git a/arch/um/include/debug.h b/arch/um/include/debug.h deleted file mode 100644 index 1d8b0a2638a8..000000000000 --- a/arch/um/include/debug.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and - * Lars Brinkhoff. - * Licensed under the GPL - */ -#ifndef __DEBUG_H -#define __DEBUG_H - -extern int debugger_proxy(int status, pid_t pid); -extern void child_proxy(pid_t pid, int status); -extern void init_proxy (pid_t pid, int waiting, int status); -extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); -extern void fake_child_exit(void); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 4d45c270a80e..4acc3d973c2d 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -70,8 +70,9 @@ extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused); extern void line_close(struct line *lines, struct tty_struct *tty); extern int line_open(struct line *lines, struct tty_struct *tty, struct chan_opts *opts); -extern void line_setup(struct line *lines, int num, char *init); -extern int line_write(struct line *line, struct tty_struct *tty, +extern int line_setup(struct line *lines, int num, char *init, + int all_allowed); +extern int line_write(struct line *line, struct tty_struct *tty, int from_user, const char *buf, int len); extern int line_write_room(struct tty_struct *tty); extern char *add_xterm_umid(char *base); diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 1c1e3a8b5eb6..524a60875d7b 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -103,10 +103,16 @@ extern int os_write_file(int fd, char *buf, int count); extern unsigned long os_process_pc(int pid); extern int os_process_parent(int pid); extern void os_stop_process(int pid); -extern void os_kill_process(int pid); +extern void os_kill_process(int pid, int reap_child); extern void os_usr1_process(int pid); extern int os_getpid(void); +extern int os_map_memory(void *virt, int fd, unsigned long off, + unsigned long len, int r, int w, int x); +extern int os_protect_memory(void *addr, unsigned long len, + int r, int w, int x); +extern int os_unmap_memory(void *addr, int len); + #endif /* diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c index 5d8fb7bba2b1..3afab4bb9852 100644 --- a/arch/um/kernel/helper.c +++ b/arch/um/kernel/helper.c @@ -43,9 +43,12 @@ static int helper_child(void *arg) execvp(argv[0], argv); printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); write(data->fd, &errno, sizeof(errno)); - _exit(1); + os_kill_process(os_getpid(), 0); + return(0); } +/* XXX The alloc_stack here breaks if this is called in the tracing thread */ + int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, unsigned long *stack_out) { diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index d410aaa7332b..892399b0d07d 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -164,19 +164,18 @@ static int ptrace_child(void *arg) if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ perror("ptrace"); - _exit(1); + os_kill_process(pid, 0); } os_stop_process(pid); _exit(os_getpid() == pid); } -void __init check_ptrace(void) +static int start_ptraced_child(void **stack_out) { void *stack; unsigned long sp; - int status, pid, n, syscall; - - printk("Checking that ptrace can change system call numbers..."); + int pid, n, status; + stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if(stack == MAP_FAILED) @@ -191,6 +190,33 @@ void __init check_ptrace(void) if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) panic("check_ptrace : expected SIGSTOP, got status = %d", status); + + *stack_out = stack; + return(pid); +} + +static void stop_ptraced_child(int pid, void *stack, int exitcode) +{ + int status, n; + + if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) + panic("check_ptrace : ptrace failed, errno = %d", errno); + n = waitpid(pid, &status, 0); + if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) + panic("check_ptrace : child exited with status 0x%x", status); + + if(munmap(stack, PAGE_SIZE) < 0) + panic("check_ptrace : munmap failed, errno = %d", errno); +} + +void __init check_ptrace(void) +{ + void *stack; + int pid, syscall, n, status; + + printk("Checking that ptrace can change system call numbers..."); + pid = start_ptraced_child(&stack); + while(1){ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", @@ -213,23 +239,19 @@ void __init check_ptrace(void) break; } } - if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) - panic("check_ptrace : ptrace failed, errno = %d", errno); - n = waitpid(pid, &status, 0); - if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) - panic("check_ptrace : child exited with status 0x%x", status); - - if(munmap(stack, PAGE_SIZE) < 0) - panic("check_ptrace : munmap failed, errno = %d", errno); + stop_ptraced_child(pid, stack, 0); printk("OK\n"); } int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) { jmp_buf buf; + int n; *jmp_ptr = &buf; - if(setjmp(buf)) return(1); + n = setjmp(buf); + if(n != 0) + return(n); (*fn)(arg); return(0); } @@ -244,6 +266,65 @@ void forward_pending_sigio(int target) kill(target, SIGIO); } +#ifdef CONFIG_MODE_SKAS +static void init_registers(int pid) +{ + int err; + + if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0) + panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", + errno); + + err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs); + if(!err) + return; + + have_fpx_regs = 0; + if(errno != EIO) + panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", + errno); + + err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs); + if(err) + panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", + errno); +} +#endif + +int can_do_skas(void) +{ + struct ptrace_faultinfo fi; + void *stack; + int pid, n, ret = 1; + + printk("Checking for the skas3 patch in the host..."); + pid = start_ptraced_child(&stack); + + n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); + if(n < 0){ + if(errno == EIO) + printk("not found\n"); + else printk("No (unexpected errno - %d)\n", errno); + ret = 0; + } + else printk("found\n"); + + init_registers(pid); + stop_ptraced_child(pid, stack, 1); + + printk("Checking for /proc/mm..."); + if(access("/proc/mm", W_OK)){ + printk("not found\n"); + ret = 0; + } + else printk("found\n"); + + return(ret); +#else + return(0); +#endif +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c index 2ef64a89e014..f9ccbada8a1a 100644 --- a/arch/um/kernel/signal_user.c +++ b/arch/um/kernel/signal_user.c @@ -21,13 +21,12 @@ void set_sigstack(void *sig_stack, int size) { - stack_t stack; + stack_t stack = ((stack_t) { .ss_flags = 0, + .ss_sp = (__ptr_t) sig_stack, + .ss_size = size - sizeof(void *) }); - stack.ss_sp = (__ptr_t) sig_stack; - stack.ss_flags = 0; - stack.ss_size = size - sizeof(void *); if(sigaltstack(&stack, NULL) != 0) - panic("sigaltstack failed"); + panic("enabling signal stack failed, errno = %d\n", errno); } void set_handler(int sig, void (*handler)(int), int flags, ...) @@ -103,6 +102,15 @@ int get_signals(void) return(enable_mask(&mask)); } +int get_signals(void) +{ + sigset_t mask; + + if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0) + panic("Failed to get signal mask"); + return(enable_mask(&mask)); +} + int set_signals(int enable) { sigset_t mask; diff --git a/arch/um/kernel/tt/ptproxy/include/debug.h b/arch/um/kernel/tt/ptproxy/include/debug.h new file mode 100644 index 000000000000..1d8b0a2638a8 --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/include/debug.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and + * Lars Brinkhoff. + * Licensed under the GPL + */ +#ifndef __DEBUG_H +#define __DEBUG_H + +extern int debugger_proxy(int status, pid_t pid); +extern void child_proxy(pid_t pid, int status); +extern void init_proxy (pid_t pid, int waiting, int status); +extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); +extern void fake_child_exit(void); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index ca5df7d03495..ca9548a81364 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -75,9 +75,12 @@ void os_stop_process(int pid) kill(pid, SIGSTOP); } -void os_kill_process(int pid) +void os_kill_process(int pid, int reap_child) { kill(pid, SIGKILL); + if(reap_child) + waitpid(pid, NULL, 0); + } void os_usr1_process(int pid) -- cgit v1.2.3 From 31a471894106864111f0936f4e73bc92b976ed85 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 14:47:18 -0500 Subject: Fixes to the last merge. --- arch/um/Makefile | 10 +++++++--- arch/um/kernel/process.c | 1 + arch/um/kernel/process_kern.c | 4 ++-- arch/um/kernel/reboot.c | 10 +++++----- arch/um/kernel/signal_user.c | 9 --------- arch/um/kernel/tt/include/debug.h | 26 ++++++++++++++++++++++++++ arch/um/kernel/tt/ptproxy/include/debug.h | 26 -------------------------- 7 files changed, 41 insertions(+), 45 deletions(-) create mode 100644 arch/um/kernel/tt/include/debug.h delete mode 100644 arch/um/kernel/tt/ptproxy/include/debug.h diff --git a/arch/um/Makefile b/arch/um/Makefile index 7d404a6126a7..714ee1d00eec 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -31,7 +31,9 @@ core-y += $(ARCH_DIR)/kernel/ \ $(ARCH_DIR)/drivers/ \ $(ARCH_DIR)/sys-$(SUBARCH)/ -ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include +ARCH_INCLUDE = $(ARCH_DIR)/include +MODE_INCLUDE = -I$(ARCH_DIR)/kernel/tt/include \ + -I$(ARCH_DIR)/kernel/skas/include # -Derrno=kernel_errno - This turns all kernel references to errno into # kernel_errno to separate them from the libc errno. This allows -fno-common @@ -39,7 +41,8 @@ ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include # errnos. CFLAGS += $(DEBUG) $(PROFILE) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ - -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) -Derrno=kernel_errno + -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) -Derrno=kernel_errno \ + $(MODE_INCLUDE) LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc @@ -79,7 +82,8 @@ linux: arch/um/uml.lds.s vmlinux USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS)) -USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE) +USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE) \ + $(MODE_INCLUDE) # To get a definition of F_SETSIG USER_CFLAGS += -D_GNU_SOURCE diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 892399b0d07d..da86f77b0d96 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -293,6 +293,7 @@ static void init_registers(int pid) int can_do_skas(void) { +#ifdef CONFIG_MODE_SKAS struct ptrace_faultinfo fi; void *stack; int pid, n, ret = 1; diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 1588e175b4db..8d9333e398d9 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -251,7 +251,7 @@ void *switch_to(void *prev, void *next, void *last) reading = 1; if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) - os_kill_process(os_getpid()); + os_kill_process(os_getpid(), 0); err = os_read_file(from->thread.switch_pipe[0], &c, sizeof(c)); if(err != sizeof(c)) @@ -295,7 +295,7 @@ void interrupt_end(void) void release_thread(struct task_struct *task) { - os_kill_process(task->thread.extern_pid); + os_kill_process(task->thread.extern_pid, 0); } void exit_thread(void) diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 41b1faec8140..a9b9a91b9afb 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -18,7 +18,7 @@ static void kill_idlers(int me) for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){ p = idle_threads[i]; if((p != NULL) && (p->thread.extern_pid != me)) - os_kill_process(p->thread.extern_pid); + os_kill_process(p->thread.extern_pid, 0); } } #endif @@ -31,10 +31,10 @@ static void kill_off_processes(void) me = os_getpid(); for_each_process(p){ if(p->thread.extern_pid != me) - os_kill_process(p->thread.extern_pid); + os_kill_process(p->thread.extern_pid, 0); } if(init_task.thread.extern_pid != me) - os_kill_process(init_task.thread.extern_pid); + os_kill_process(init_task.thread.extern_pid, 0); #ifdef CONFIG_SMP kill_idlers(me); #endif @@ -51,7 +51,7 @@ void machine_restart(char * __unused) do_uml_exitcalls(); kill_off_processes(); tracing_reboot(); - os_kill_process(os_getpid()); + os_kill_process(os_getpid(), 0); } void machine_power_off(void) @@ -59,7 +59,7 @@ void machine_power_off(void) do_uml_exitcalls(); kill_off_processes(); tracing_halt(); - os_kill_process(os_getpid()); + os_kill_process(os_getpid(), 0); } void machine_halt(void) diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c index f9ccbada8a1a..52cfd60a1433 100644 --- a/arch/um/kernel/signal_user.c +++ b/arch/um/kernel/signal_user.c @@ -102,15 +102,6 @@ int get_signals(void) return(enable_mask(&mask)); } -int get_signals(void) -{ - sigset_t mask; - - if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0) - panic("Failed to get signal mask"); - return(enable_mask(&mask)); -} - int set_signals(int enable) { sigset_t mask; diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h new file mode 100644 index 000000000000..1d8b0a2638a8 --- /dev/null +++ b/arch/um/kernel/tt/include/debug.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and + * Lars Brinkhoff. + * Licensed under the GPL + */ +#ifndef __DEBUG_H +#define __DEBUG_H + +extern int debugger_proxy(int status, pid_t pid); +extern void child_proxy(pid_t pid, int status); +extern void init_proxy (pid_t pid, int waiting, int status); +extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); +extern void fake_child_exit(void); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/ptproxy/include/debug.h b/arch/um/kernel/tt/ptproxy/include/debug.h deleted file mode 100644 index 1d8b0a2638a8..000000000000 --- a/arch/um/kernel/tt/ptproxy/include/debug.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and - * Lars Brinkhoff. - * Licensed under the GPL - */ -#ifndef __DEBUG_H -#define __DEBUG_H - -extern int debugger_proxy(int status, pid_t pid); -extern void child_proxy(pid_t pid, int status); -extern void init_proxy (pid_t pid, int waiting, int status); -extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); -extern void fake_child_exit(void); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ -- cgit v1.2.3 From fd3f9c88a67fd45142c2f82f979f48f6f4a2f6e4 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 14:54:26 -0500 Subject: Merged the signal frame cleanups and fixes from 2.4. --- arch/um/include/frame.h | 18 +-- arch/um/include/sysdep-i386/frame_kern.h | 9 +- arch/um/kernel/frame.c | 202 ++++++++++++++++++------------- arch/um/kernel/frame_kern.c | 83 ++++++++----- 4 files changed, 184 insertions(+), 128 deletions(-) diff --git a/arch/um/include/frame.h b/arch/um/include/frame.h index 9df95a5f00a1..b4e12946f54f 100644 --- a/arch/um/include/frame.h +++ b/arch/um/include/frame.h @@ -8,34 +8,34 @@ #include "sysdep/frame.h" -struct sc_frame { +struct frame_common { void *data; int len; int sig_index; - int sc_index; int sr_index; int sr_relative; int sp_index; +}; + +struct sc_frame { + struct frame_common common; + int sc_index; struct arch_frame_data arch; }; extern struct sc_frame signal_frame_sc; +extern struct sc_frame signal_frame_sc_sr; + struct si_frame { - void *data; - int len; - int sig_index; + struct frame_common common; int sip_index; int si_index; - int sr_index; - int sr_relative; - int sp_index; }; extern struct si_frame signal_frame_si; extern void capture_signal_stack(void); -extern void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp); #endif diff --git a/arch/um/include/sysdep-i386/frame_kern.h b/arch/um/include/sysdep-i386/frame_kern.h index ec234c6e15c1..f469b8c6ea23 100644 --- a/arch/um/include/sysdep-i386/frame_kern.h +++ b/arch/um/include/sysdep-i386/frame_kern.h @@ -20,7 +20,8 @@ static inline void *sp_to_rt_sc(unsigned long sp) { unsigned long sc; - sc = sp - signal_frame_si.sp_index + signal_frame_si.len - 4; + sc = sp - signal_frame_si.common.sp_index + + signal_frame_si.common.len - 4; return((void *) sc); } @@ -28,7 +29,8 @@ static inline void *sp_to_mask(unsigned long sp) { unsigned long mask; - mask = sp - signal_frame_sc.sp_index + signal_frame_sc.len - 8; + mask = sp - signal_frame_sc.common.sp_index + + signal_frame_sc.common.len - 8; return((void *) mask); } @@ -38,7 +40,8 @@ static inline void *sp_to_rt_mask(unsigned long sp) { unsigned long mask; - mask = sp - signal_frame_si.sp_index + signal_frame_si.len + + mask = sp - signal_frame_si.common.sp_index + + signal_frame_si.common.len + sc_size(&signal_frame_sc.arch) - 4; return((void *) mask); } diff --git a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c index 28793041426a..ae5b0e3e5158 100644 --- a/arch/um/kernel/frame.c +++ b/arch/um/kernel/frame.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -84,8 +85,8 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp, printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); } - if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ - printf("capture_stack : Expected exit status 0, " + if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){ + printf("capture_stack : Expected exit signal 9, " "got status = 0x%x\n", status); exit(1); } @@ -103,28 +104,61 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp, return(len); } -static void child_common(void *sp, int size, sighandler_t handler, int flags) +struct common_raw { + void *stack; + int size; + unsigned long sig; + unsigned long sr; + unsigned long sp; +}; + +#define SA_RESTORER (0x04000000) + +typedef unsigned long old_sigset_t; + +struct old_sigaction { + __sighandler_t handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +static void child_common(struct common_raw *common, sighandler_t handler, + int restorer, int flags) { - stack_t ss; - struct sigaction sa; + stack_t ss = ((stack_t) { .ss_sp = common->stack, + .ss_flags = 0, + .ss_size = common->size }); + int err; if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ printf("PTRACE_TRACEME failed, errno = %d\n", errno); } - ss.ss_sp = sp; - ss.ss_flags = 0; - ss.ss_size = size; if(sigaltstack(&ss, NULL) < 0){ printf("sigaltstack failed - errno = %d\n", errno); - _exit(1); + kill(getpid(), SIGKILL); } - sa.sa_handler = handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_ONSTACK | flags; - if(sigaction(SIGUSR1, &sa, NULL) < 0){ + if(restorer){ + struct sigaction sa; + + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_ONSTACK | flags; + err = sigaction(SIGUSR1, &sa, NULL); + } + else { + struct old_sigaction sa; + + sa.handler = handler; + sa.sa_mask = 0; + sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER; + err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL); + } + + if(err < 0){ printf("sigaction failed - errno = %d\n", errno); - _exit(1); + kill(getpid(), SIGKILL); } os_stop_process(os_getpid()); @@ -133,13 +167,12 @@ static void child_common(void *sp, int size, sighandler_t handler, int flags) /* Changed only during early boot */ struct sc_frame signal_frame_sc; +struct sc_frame signal_frame_sc_sr; + struct sc_frame_raw { - void *stack; - int size; - unsigned long sig; + struct common_raw common; unsigned long sc; - unsigned long sr; - unsigned long sp; + int restorer; struct arch_frame_data_raw arch; }; @@ -148,20 +181,20 @@ static struct sc_frame_raw *raw_sc = NULL; static void sc_handler(int sig, struct sigcontext sc) { - raw_sc->sig = (unsigned long) &sig; + raw_sc->common.sig = (unsigned long) &sig; + raw_sc->common.sr = frame_restorer(); + raw_sc->common.sp = frame_sp(); raw_sc->sc = (unsigned long) ≻ - raw_sc->sr = frame_restorer(); - raw_sc->sp = frame_sp(); setup_arch_frame_raw(&raw_sc->arch, &sc); os_stop_process(os_getpid()); - _exit(0); + kill(getpid(), SIGKILL); } static int sc_child(void *arg) { raw_sc = arg; - child_common(raw_sc->stack, raw_sc->size, (sighandler_t) sc_handler, - 0); + child_common(&raw_sc->common, (sighandler_t) sc_handler, + raw_sc->restorer, 0); return(-1); } @@ -169,13 +202,9 @@ static int sc_child(void *arg) struct si_frame signal_frame_si; struct si_frame_raw { - void *stack; - int size; - unsigned long sig; + struct common_raw common; unsigned long sip; unsigned long si; - unsigned long sr; - unsigned long sp; }; /* Changed only during early boot */ @@ -183,23 +212,59 @@ static struct si_frame_raw *raw_si = NULL; static void si_handler(int sig, siginfo_t *si) { - raw_si->sig = (unsigned long) &sig; + raw_si->common.sig = (unsigned long) &sig; + raw_si->common.sr = frame_restorer(); + raw_si->common.sp = frame_sp(); raw_si->sip = (unsigned long) &si; raw_si->si = (unsigned long) si; - raw_si->sr = frame_restorer(); - raw_si->sp = frame_sp(); os_stop_process(os_getpid()); - _exit(0); + kill(getpid(), SIGKILL); } static int si_child(void *arg) { raw_si = arg; - child_common(raw_si->stack, raw_si->size, (sighandler_t) si_handler, - SA_SIGINFO); + child_common(&raw_si->common, (sighandler_t) si_handler, 1, + SA_SIGINFO); return(-1); } +static int relative_sr(unsigned long sr, int sr_index, void *stack, + void *framep) +{ + unsigned long *srp = (unsigned long *) sr; + unsigned long frame = (unsigned long) framep; + + if((*srp & PAGE_MASK) == (unsigned long) stack){ + *srp -= sr; + *((unsigned long *) (frame + sr_index)) = *srp; + return(1); + } + else return(0); +} + +static unsigned long capture_stack_common(int (*proc)(void *), void *arg, + struct common_raw *common_in, + void *top, void *sigstack, + int stack_len, + struct frame_common *common_out) +{ + unsigned long sig_top = (unsigned long) sigstack + stack_len, base; + + common_in->stack = (void *) sigstack; + common_in->size = stack_len; + common_out->len = capture_stack(proc, arg, top, sig_top, + &common_out->data); + base = sig_top - common_out->len; + common_out->sig_index = common_in->sig - base; + common_out->sp_index = common_in->sp - base; + common_out->sr_index = common_in->sr - base; + common_out->sr_relative = relative_sr(common_in->sr, + common_out->sr_index, sigstack, + common_out->data); + return(base); +} + void capture_signal_stack(void) { struct sc_frame_raw raw_sc; @@ -220,54 +285,29 @@ void capture_signal_stack(void) top = (unsigned long) stack + PAGE_SIZE - sizeof(void *); sig_top = (unsigned long) sigstack + PAGE_SIZE; - raw_sc.stack = sigstack; - raw_sc.size = PAGE_SIZE; - signal_frame_sc.len = capture_stack(sc_child, &raw_sc, (void *) top, - sig_top, &signal_frame_sc.data); - - /* These are the offsets within signal_frame_sc.data (counting from - * the bottom) of sig, sc, SA_RESTORER, and the initial sp. - */ + /* Get the sigcontext, no sigrestorer layout */ + raw_sc.restorer = 0; + base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, + (void *) top, sigstack, PAGE_SIZE, + &signal_frame_sc.common); - base = sig_top - signal_frame_sc.len; - signal_frame_sc.sig_index = raw_sc.sig - base; signal_frame_sc.sc_index = raw_sc.sc - base; - signal_frame_sc.sr_index = raw_sc.sr - base; - if((*((unsigned long *) raw_sc.sr) & PAGE_MASK) == - (unsigned long) sigstack){ - unsigned long *sr = (unsigned long *) raw_sc.sr; - unsigned long frame = (unsigned long) signal_frame_sc.data; - - signal_frame_sc.sr_relative = 1; - *sr -= raw_sc.sr; - *((unsigned long *) (frame + signal_frame_sc.sr_index)) = *sr; - } - else signal_frame_sc.sr_relative = 0; - signal_frame_sc.sp_index = raw_sc.sp - base; setup_arch_frame(&raw_sc.arch, &signal_frame_sc.arch); - /* Repeat for the siginfo variant */ + /* Ditto for the sigcontext, sigrestorer layout */ + raw_sc.restorer = 1; + base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, + (void *) top, sigstack, PAGE_SIZE, + &signal_frame_sc_sr.common); + signal_frame_sc_sr.sc_index = raw_sc.sc - base; + + /* And the siginfo layout */ - raw_si.stack = sigstack; - raw_si.size = PAGE_SIZE; - signal_frame_si.len = capture_stack(si_child, &raw_si, (void *) top, - sig_top, &signal_frame_si.data); - base = sig_top - signal_frame_si.len; - signal_frame_si.sig_index = raw_si.sig - base; + base = capture_stack_common(si_child, &raw_si, &raw_si.common, + (void *) top, sigstack, PAGE_SIZE, + &signal_frame_si.common); signal_frame_si.sip_index = raw_si.sip - base; signal_frame_si.si_index = raw_si.si - base; - signal_frame_si.sr_index = raw_si.sr - base; - if((*((unsigned long *) raw_si.sr) & PAGE_MASK) == - (unsigned long) sigstack){ - unsigned long *sr = (unsigned long *) raw_si.sr; - unsigned long frame = (unsigned long) signal_frame_si.data; - - signal_frame_sc.sr_relative = 1; - *sr -= raw_si.sr; - *((unsigned long *) (frame + signal_frame_si.sr_index)) = *sr; - } - else signal_frame_si.sr_relative = 0; - signal_frame_si.sp_index = raw_si.sp - base; if((munmap(stack, PAGE_SIZE) < 0) || (munmap(sigstack, PAGE_SIZE) < 0)){ @@ -277,14 +317,6 @@ void capture_signal_stack(void) } } -void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp) -{ - struct sigcontext *sc = sc_ptr; - - SC_IP(sc) = ip; - SC_SP(sc) = sp; -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c index f71451c4c780..1b87f71d4ad3 100644 --- a/arch/um/kernel/frame_kern.c +++ b/arch/um/kernel/frame_kern.c @@ -13,16 +13,25 @@ static int copy_restorer(void (*restorer)(void), unsigned long start, unsigned long sr_index, int sr_relative) { - if(restorer != 0){ - if(copy_to_user((void *) (start + sr_index), &restorer, - sizeof(restorer))) - return(1); - } - else if(sr_relative){ - unsigned long *sr = (unsigned long *) (start + sr_index); - *sr += (unsigned long) sr; + unsigned long sr; + + if(sr_relative){ + sr = (unsigned long) restorer; + sr += start + sr_index; + restorer = (void (*)(void)) sr; } - return(0); + + return(copy_to_user((void *) (start + sr_index), &restorer, + sizeof(restorer))); +} + +static int copy_sc_to_user(void *to, struct pt_regs *from) +{ + return(CHOOSE_MODE(copy_sc_to_user_tt(to, from->regs.mode.tt, + &signal_frame_sc_sr.arch), + copy_sc_to_user_skas(to, &from->regs, + current->thread.cr2, + current->thread.err))); } int setup_signal_stack_si(unsigned long stack_top, int sig, @@ -34,27 +43,30 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, void *sip; int sig_size = _NSIG_WORDS * sizeof(unsigned long); - start = stack_top - signal_frame_si.len - + start = stack_top - signal_frame_si.common.len - sc_size(&signal_frame_sc.arch) - sig_size; sip = (void *) (start + signal_frame_si.si_index); - sc = start + signal_frame_si.len; + sc = start + signal_frame_si.common.len; sigs = sc + sc_size(&signal_frame_sc.arch); - if(copy_sc_to_user((void *) sc, regs->regs.sc, - &signal_frame_sc.arch) || - copy_to_user((void *) start, signal_frame_si.data, - signal_frame_si.len) || - copy_to_user((void *) (start + signal_frame_si.sig_index), &sig, - sizeof(sig)) || + + if(restorer == NULL) + panic("setup_signal_stack_si - no restorer"); + + if(copy_sc_to_user((void *) sc, regs) || + copy_to_user((void *) start, signal_frame_si.common.data, + signal_frame_si.common.len) || + copy_to_user((void *) (start + signal_frame_si.common.sig_index), + &sig, sizeof(sig)) || copy_siginfo_to_user(sip, info) || copy_to_user((void *) (start + signal_frame_si.sip_index), &sip, sizeof(sip)) || copy_to_user((void *) sigs, mask, sig_size) || - copy_restorer(restorer, start, signal_frame_si.sr_index, - signal_frame_si.sr_relative)) + copy_restorer(restorer, start, signal_frame_si.common.sr_index, + signal_frame_si.common.sr_relative)) return(1); PT_REGS_IP(regs) = handler; - PT_REGS_SP(regs) = start + signal_frame_sc.sp_index; + PT_REGS_SP(regs) = start + signal_frame_sc.common.sp_index; return(0); } @@ -62,26 +74,35 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, unsigned long handler, void (*restorer)(void), struct pt_regs *regs, sigset_t *mask) { + struct frame_common *frame = &signal_frame_sc_sr.common; + void *user_sc; int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); - unsigned long sigs, start = stack_top - signal_frame_sc.len - sig_size; - void *user_sc = (void *) (start + signal_frame_sc.sc_index); + unsigned long sigs, sr; + unsigned long start = stack_top - frame->len - sig_size; + + user_sc = (void *) (start + signal_frame_sc_sr.sc_index); + if(restorer == NULL){ + frame = &signal_frame_sc.common; + user_sc = (void *) (start + signal_frame_sc.sc_index); + sr = (unsigned long) frame->data; + sr += frame->sr_index; + sr = *((unsigned long *) sr); + restorer = ((void (*)(void)) sr); + } - sigs = start + signal_frame_sc.len; - if(copy_to_user((void *) start, signal_frame_sc.data, - signal_frame_sc.len) || - copy_to_user((void *) (start + signal_frame_sc.sig_index), &sig, + sigs = start + frame->len; + if(copy_to_user((void *) start, frame->data, frame->len) || + copy_to_user((void *) (start + frame->sig_index), &sig, sizeof(sig)) || - copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) || + copy_sc_to_user(user_sc, regs) || copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) || copy_to_user((void *) sigs, &mask->sig[1], sig_size) || - copy_restorer(restorer, start, signal_frame_sc.sr_index, - signal_frame_sc.sr_relative)) + copy_restorer(restorer, start, frame->sr_index, frame->sr_relative)) return(1); PT_REGS_IP(regs) = handler; - PT_REGS_SP(regs) = start + signal_frame_sc.sp_index; + PT_REGS_SP(regs) = start + frame->sp_index; - set_sc_ip_sp(regs->regs.sc, handler, start + signal_frame_sc.sp_index); return(0); } -- cgit v1.2.3 From 08cca5ac9c788bb0430cdadc987b446666de7b2c Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 19 Nov 2002 03:47:41 -0500 Subject: Fixed a couple of buglets in the signal frame merge. --- arch/um/kernel/frame_kern.c | 14 +++----------- arch/um/os-Linux/process.c | 2 ++ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c index 1b87f71d4ad3..574ddce69065 100644 --- a/arch/um/kernel/frame_kern.c +++ b/arch/um/kernel/frame_kern.c @@ -25,15 +25,6 @@ static int copy_restorer(void (*restorer)(void), unsigned long start, sizeof(restorer))); } -static int copy_sc_to_user(void *to, struct pt_regs *from) -{ - return(CHOOSE_MODE(copy_sc_to_user_tt(to, from->regs.mode.tt, - &signal_frame_sc_sr.arch), - copy_sc_to_user_skas(to, &from->regs, - current->thread.cr2, - current->thread.err))); -} - int setup_signal_stack_si(unsigned long stack_top, int sig, unsigned long handler, void (*restorer)(void), struct pt_regs *regs, siginfo_t *info, @@ -52,7 +43,8 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, if(restorer == NULL) panic("setup_signal_stack_si - no restorer"); - if(copy_sc_to_user((void *) sc, regs) || + if(copy_sc_to_user((void *) sc, regs->regs.sc, + &signal_frame_sc.arch) || copy_to_user((void *) start, signal_frame_si.common.data, signal_frame_si.common.len) || copy_to_user((void *) (start + signal_frame_si.common.sig_index), @@ -94,7 +86,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, if(copy_to_user((void *) start, frame->data, frame->len) || copy_to_user((void *) (start + frame->sig_index), &sig, sizeof(sig)) || - copy_sc_to_user(user_sc, regs) || + copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) || copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) || copy_to_user((void *) sigs, &mask->sig[1], sig_size) || copy_restorer(restorer, start, frame->sr_index, frame->sr_relative)) diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index ca9548a81364..042df18a4eab 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "os.h" #include "user.h" -- cgit v1.2.3 From c438a80a5b27ec7a139e6fcef110c36ace8c4769 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 19 Nov 2002 04:53:18 -0500 Subject: Merged the skas exec reorg. --- arch/um/Kconfig | 7 ++++ arch/um/Makefile | 17 +++++---- arch/um/include/choose-mode.h | 35 +++++++++++++++++ arch/um/kernel/Makefile | 9 +++-- arch/um/kernel/exec_kern.c | 8 +++- arch/um/kernel/exec_user.c | 49 ------------------------ arch/um/kernel/skas/exec_kern.c | 41 ++++++++++++++++++++ arch/um/kernel/skas/exec_user.c | 61 ++++++++++++++++++++++++++++++ arch/um/kernel/tt/Makefile | 4 ++ arch/um/kernel/tt/exec_kern.c | 83 +++++++++++++++++++++++++++++++++++++++++ arch/um/kernel/tt/exec_user.c | 49 ++++++++++++++++++++++++ arch/um/kernel/um_arch.c | 3 ++ 12 files changed, 304 insertions(+), 62 deletions(-) create mode 100644 arch/um/include/choose-mode.h delete mode 100644 arch/um/kernel/exec_user.c create mode 100644 arch/um/kernel/skas/exec_kern.c create mode 100644 arch/um/kernel/skas/exec_user.c create mode 100644 arch/um/kernel/tt/exec_kern.c create mode 100644 arch/um/kernel/tt/exec_user.c diff --git a/arch/um/Kconfig b/arch/um/Kconfig index f7e8005ebf38..2437e90f08a7 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -30,6 +30,13 @@ config RWSEM_GENERIC_SPINLOCK bool default y +config MODE_TT + bool + default y + +config MODE_SKAS + bool + default y menu "Code maturity level options" diff --git a/arch/um/Makefile b/arch/um/Makefile index 714ee1d00eec..bf9a4550947a 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -52,8 +52,8 @@ SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ include/asm-um/sigcontext.h include/asm-um/processor.h \ include/asm-um/ptrace.h include/asm-um/arch-signal.h -ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep arch/um/os \ - $(SYMLINK_HEADERS) +ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ + $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h GEN_HEADERS = $(ARCH_DIR)/include/task.h @@ -75,8 +75,8 @@ $(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S scripts FORCE AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \ -DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum -linux: arch/um/uml.lds.s vmlinux - $(CC) -Wl,-T,arch/um/uml.lds.s -o $@ $(LINK_PROFILE) \ +linux: $(ARCH_DIR)/uml.lds.s vmlinux + $(CC) -Wl,-T,$(ARCH_DIR)/uml.lds.s -o $@ $(LINK_PROFILE) \ $(LINK_WRAPS) -static vmlinux -L/usr/lib -lutil @@ -121,12 +121,15 @@ $(SYMLINK_HEADERS): include/asm-um/arch: cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch -arch/um/include/sysdep: - cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep +$(ARCH_DIR)/include/sysdep: + cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep -arch/um/os: +$(ARCH_DIR)/os: cd $(ARCH_DIR) && ln -sf os-$(OS) os +$(ARCH_DIR)/include/uml-config.h : + ln -sf $(TOPDIR)/include/linux/autoconf.h $@ + $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task $< > $@ diff --git a/arch/um/include/choose-mode.h b/arch/um/include/choose-mode.h new file mode 100644 index 000000000000..55548984bd85 --- /dev/null +++ b/arch/um/include/choose-mode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __CHOOSE_MODE_H__ +#define __CHOOSE_MODE_H__ + +#include "uml-config.h" + +#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) +#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas)) + +#elif defined(CONFIG_MODE_SKAS) +#define CHOOSE_MODE(tt, skas) (skas) + +#elif defined(CONFIG_MODE_TT) +#define CHOOSE_MODE(tt, skas) (tt) +#endif + +#define CHOOSE_MODE_PROC(tt, skas, args...) \ + CHOOSE_MODE(tt(args), skas(args)) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 19b3ff84109c..4fb60e8af16c 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -5,9 +5,9 @@ EXTRA_TARGETS := unmap_fin.o -obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \ - helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \ - process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ +obj-y = config.o exec_kern.o exitcode.o frame_kern.o frame.o helper.o \ + init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o process.o \ + process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \ syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \ time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ @@ -18,7 +18,8 @@ obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o obj-$(CONFIG_TTY_LOG) += tty_log.o -obj-$(CONFIG_PT_PROXY) += tt/ +obj-$(CONFIG_MODE_TT) += tt/ +obj-$(CONFIG_MODE_SKAS) += tt/ user-objs-$(CONFIG_TTY_LOG) += tty_log.o diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index 353bfa4da610..cdbb95f6d0bd 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -93,8 +93,12 @@ static int execve1(char *file, char **argv, char **env) int um_execve(char *file, char **argv, char **env) { - if(execve1(file, argv, env) == 0) do_longjmp(current->thread.jmp); - return(-1); + int err; + + err = execve1(file, argv, env); + if(!err) + do_longjmp(current->thread.exec_buf, 1); + return(err); } int sys_execve(char *file, char **argv, char **env) diff --git a/arch/um/kernel/exec_user.c b/arch/um/kernel/exec_user.c deleted file mode 100644 index 35d108266d41..000000000000 --- a/arch/um/kernel/exec_user.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "ptrace_user.h" - -void do_exec(int old_pid, int new_pid) -{ - unsigned long regs[FRAME_SIZE]; - - if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || - (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) || - (waitpid(new_pid, 0, WUNTRACED) < 0)) - tracer_panic("do_exec failed to attach proc - errno = %d", - errno); - - if(ptrace_getregs(old_pid, regs) < 0) - tracer_panic("do_exec failed to get registers - errno = %d", - errno); - - kill(old_pid, SIGKILL); - - if(ptrace_setregs(new_pid, regs) < 0) - tracer_panic("do_exec failed to start new proc - errno = %d", - errno); -} - -/* - * 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/exec_kern.c b/arch/um/kernel/skas/exec_kern.c new file mode 100644 index 000000000000..49356d26ac28 --- /dev/null +++ b/arch/um/kernel/skas/exec_kern.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/kernel.h" +#include "asm/current.h" +#include "asm/page.h" +#include "asm/signal.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" +#include "asm/mmu_context.h" +#include "tlb.h" +#include "skas.h" +#include "mmu.h" +#include "os.h" + +void flush_thread_skas(void) +{ + force_flush_all(); + switch_mm_skas(current->mm->context.skas.mm_fd); +} + +void start_thread_skas(struct pt_regs *regs, unsigned long eip, + unsigned long esp) +{ + set_fs(USER_DS); + PT_REGS_IP(regs) = eip; + PT_REGS_SP(regs) = esp; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/exec_user.c b/arch/um/kernel/skas/exec_user.c new file mode 100644 index 000000000000..c9942b6fc79b --- /dev/null +++ b/arch/um/kernel/skas/exec_user.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include "user.h" +#include "kern_util.h" +#include "os.h" +#include "time_user.h" + +static int user_thread_tramp(void *arg) +{ + if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) + panic("user_thread_tramp - PTRACE_TRACEME failed, " + "errno = %d\n", errno); + enable_timer(); + os_stop_process(os_getpid()); + return(0); +} + +int user_thread(unsigned long stack, int flags) +{ + int pid, status; + + pid = clone(user_thread_tramp, (void *) stack_sp(stack), + flags | CLONE_FILES | SIGCHLD, NULL); + if(pid < 0){ + printk("user_thread - clone failed, errno = %d\n", errno); + return(pid); + } + + if(waitpid(pid, &status, WUNTRACED) < 0){ + printk("user_thread - waitpid failed, errno = %d\n", errno); + return(-errno); + } + + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){ + printk("user_thread - trampoline didn't stop, status = %d\n", + status); + return(-EINVAL); + } + + return(pid); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index b2c6c5045eac..224f15c7ba54 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -3,6 +3,10 @@ # Licensed under the GPL # +O_TARGET = tt.o + +obj-y = exec_kern.o exec_user.o + obj-$(CONFIG_PT_PROXY) += ptproxy/ include $(TOPDIR)/Rules.make diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c new file mode 100644 index 000000000000..b928324d7096 --- /dev/null +++ b/arch/um/kernel/tt/exec_kern.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/kernel.h" +#include "linux/mm.h" +#include "asm/signal.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" +#include "asm/pgalloc.h" +#include "user_util.h" +#include "kern_util.h" +#include "irq_user.h" +#include "time_user.h" +#include "mem_user.h" +#include "os.h" +#include "tlb.h" + +static int exec_tramp(void *sig_stack) +{ + init_new_thread_stack(sig_stack, NULL); + init_new_thread_signals(1); + os_stop_process(os_getpid()); + return(0); +} + +void flush_thread_tt(void) +{ + unsigned long stack; + int new_pid; + + stack = alloc_stack(0, 0); + if(stack == 0){ + printk(KERN_ERR + "flush_thread : failed to allocate temporary stack\n"); + do_exit(SIGKILL); + } + + new_pid = start_fork_tramp((void *) current->thread.kernel_stack, + stack, 0, exec_tramp); + if(new_pid < 0){ + printk(KERN_ERR + "flush_thread : new thread failed, errno = %d\n", + -new_pid); + do_exit(SIGKILL); + } + + if(current->processor == 0) + forward_interrupts(new_pid); + current->thread.request.op = OP_EXEC; + current->thread.request.u.exec.pid = new_pid; + unprotect_stack((unsigned long) current); + os_usr1_process(os_getpid()); + + enable_timer(); + free_page(stack); + protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); + task_protections((unsigned long) current); + force_flush_all(); + unblock_signals(); +} + +void start_thread_tt(struct pt_regs *regs, unsigned long eip, + unsigned long esp) +{ + set_fs(USER_DS); + flush_tlb_mm(current->mm); + PT_REGS_IP(regs) = eip; + PT_REGS_SP(regs) = esp; + PT_FIX_EXEC_STACK(esp); +} + +/* + * 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/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c new file mode 100644 index 000000000000..35d108266d41 --- /dev/null +++ b/arch/um/kernel/tt/exec_user.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "ptrace_user.h" + +void do_exec(int old_pid, int new_pid) +{ + unsigned long regs[FRAME_SIZE]; + + if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || + (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) || + (waitpid(new_pid, 0, WUNTRACED) < 0)) + tracer_panic("do_exec failed to attach proc - errno = %d", + errno); + + if(ptrace_getregs(old_pid, regs) < 0) + tracer_panic("do_exec failed to get registers - errno = %d", + errno); + + kill(old_pid, SIGKILL); + + if(ptrace_setregs(new_pid, regs) < 0) + tracer_panic("do_exec failed to start new proc - errno = %d", + errno); +} + +/* + * 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/um_arch.c b/arch/um/kernel/um_arch.c index b7d436981572..ba4410ad739b 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -293,6 +293,9 @@ int linux_main(int argc, char **argv) if(!jail || debug) remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext), 1); remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata), 1); + + mode_tt = 1; + brk_start = (unsigned long) sbrk(0); remap_data(ROUND_DOWN(&__bss_start), ROUND_UP(brk_start), 1); -- cgit v1.2.3 From 721c18656222f73dc0d66cddb7eb6e58e760dc45 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 19 Nov 2002 04:54:08 -0500 Subject: Declared mode_tt in user_util.h. --- arch/um/include/user_util.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index 5f50aed753b2..f4aea6b27411 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -8,6 +8,8 @@ #include "sysdep/ptrace.h" +extern int mode_tt; + extern int grantpt(int __fd); extern int unlockpt(int __fd); extern char *ptsname(int __fd); -- cgit v1.2.3 From 46228a2bfeb95ec9635a41aff5e5f0e071c92d63 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Wed, 20 Nov 2002 13:04:22 -0500 Subject: Merged most of the rest of the skas changes. --- arch/um/Makefile | 56 ++-- arch/um/Makefile-i386 | 4 +- arch/um/drivers/chan_user.c | 35 +-- arch/um/drivers/pty.c | 2 +- arch/um/include/kern_util.h | 28 +- arch/um/include/mem_user.h | 12 +- arch/um/include/syscall_user.h | 13 +- arch/um/include/sysdep-i386/ptrace.h | 111 +++++-- arch/um/include/sysdep-i386/sigcontext.h | 33 +- arch/um/include/user_util.h | 23 +- arch/um/kernel/Makefile | 16 +- arch/um/kernel/exec_kern.c | 56 +--- arch/um/kernel/frame_kern.c | 5 +- arch/um/kernel/init_task.c | 2 +- arch/um/kernel/ksyms.c | 17 +- arch/um/kernel/mem.c | 47 +-- arch/um/kernel/mem_user.c | 44 +-- arch/um/kernel/process.c | 44 +-- arch/um/kernel/process_kern.c | 449 ++------------------------- arch/um/kernel/reboot.c | 25 +- arch/um/kernel/signal_kern.c | 6 +- arch/um/kernel/skas/Makefile | 27 ++ arch/um/kernel/skas/include/mode_kern.h | 52 ++++ arch/um/kernel/skas/mmu.c | 46 +++ arch/um/kernel/syscall_kern.c | 4 +- arch/um/kernel/syscall_user.c | 81 +---- arch/um/kernel/tlb.c | 34 +- arch/um/kernel/trap_kern.c | 248 +-------------- arch/um/kernel/trap_user.c | 453 ++------------------------- arch/um/kernel/tt/Makefile | 12 +- arch/um/kernel/tt/exec_kern.c | 6 +- arch/um/kernel/tt/gdb_kern.c | 40 +++ arch/um/kernel/tt/include/mode_kern.h | 53 ++++ arch/um/kernel/tt/mem.c | 77 +++++ arch/um/kernel/tt/process_kern.c | 512 +++++++++++++++++++++++++++++++ arch/um/kernel/um_arch.c | 60 ++-- arch/um/main.c | 64 +--- arch/um/os-Linux/process.c | 35 +++ arch/um/os-Linux/tty.c | 2 +- arch/um/sys-i386/ptrace_user.c | 2 +- arch/um/sys-i386/util/mk_thread_kern.c | 16 +- arch/um/sys-i386/util/mk_thread_user.c | 32 +- arch/um/util/Makefile | 11 +- include/asm-um/a.out.h | 8 +- include/asm-um/mmu.h | 18 +- include/asm-um/mmu_context.h | 51 ++- include/asm-um/processor-generic.h | 40 ++- 47 files changed, 1383 insertions(+), 1629 deletions(-) create mode 100644 arch/um/kernel/skas/Makefile create mode 100644 arch/um/kernel/skas/include/mode_kern.h create mode 100644 arch/um/kernel/skas/mmu.c create mode 100644 arch/um/kernel/tt/gdb_kern.c create mode 100644 arch/um/kernel/tt/include/mode_kern.h create mode 100644 arch/um/kernel/tt/mem.c create mode 100644 arch/um/kernel/tt/process_kern.c diff --git a/arch/um/Makefile b/arch/um/Makefile index bf9a4550947a..c202cad12325 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -1,3 +1,8 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + ARCH_DIR = arch/um OS := $(shell uname -s) @@ -11,27 +16,20 @@ include/linux/version.h: arch/$(ARCH)/Makefile # EXTRAVERSION... MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) -MAKEBOOT = $(MAKE) -C $(ARCH_DIR)/boot - ifeq ($(CONFIG_DEBUGSYM),y) -DEBUG = -g CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) endif -ifeq ($(CONFIG_GCOV),y) -CFLAGS += -fprofile-arcs -ftest-coverage -endif - -ifeq ($(CONFIG_GPROF), y) -PROFILE += -pg -DPROFILING -LINK_PROFILE = $(PROFILE) -Wl,--wrap,__monstartup -endif +CFLAGS-$(CONFIG_DEBUGSYM) += -g +CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage +CFLAGS-$(CONFIG_GPROF) += $(PROFILE) +LINK-$(CONFIG_GPROF) += $(PROFILE) -Wl,--wrap,__monstartup core-y += $(ARCH_DIR)/kernel/ \ $(ARCH_DIR)/drivers/ \ $(ARCH_DIR)/sys-$(SUBARCH)/ -ARCH_INCLUDE = $(ARCH_DIR)/include +ARCH_INCLUDE = -I$(ARCH_DIR)/include MODE_INCLUDE = -I$(ARCH_DIR)/kernel/tt/include \ -I$(ARCH_DIR)/kernel/skas/include @@ -40,8 +38,8 @@ MODE_INCLUDE = -I$(ARCH_DIR)/kernel/tt/include \ # in CFLAGS. Otherwise, it would cause ld to complain about the two different # errnos. -CFLAGS += $(DEBUG) $(PROFILE) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ - -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) -Derrno=kernel_errno \ +CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ + -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \ $(MODE_INCLUDE) LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc @@ -55,7 +53,13 @@ SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h -GEN_HEADERS = $(ARCH_DIR)/include/task.h +ifeq ($(CONFIG_MODE_SKAS), y) +GEN_HEADERS = $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h + +$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h +endif + +GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h include $(ARCH_DIR)/Makefile-$(SUBARCH) include $(ARCH_DIR)/Makefile-os-$(OS) @@ -63,9 +67,9 @@ include $(ARCH_DIR)/Makefile-os-$(OS) $(ARCH_DIR)/vmlinux.lds.S : touch $@ -prepare: $(ARCH_SYMLINKS) $(GEN_HEADERS) +prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) -LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o +LDFLAGS_vmlinux = -r vmlinux: $(ARCH_DIR)/main.o @@ -76,18 +80,20 @@ AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \ -DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum linux: $(ARCH_DIR)/uml.lds.s vmlinux - $(CC) -Wl,-T,$(ARCH_DIR)/uml.lds.s -o $@ $(LINK_PROFILE) \ - $(LINK_WRAPS) -static vmlinux -L/usr/lib -lutil + $(CC) -Wl,-T,$(ARCH_DIR)/uml.lds.s -static $(LINK-y) $(LINK_WRAPS) \ + -o linux $(ARCH_DIR)/main.o vmlinux -L/usr/lib -lutil USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS)) -USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE) \ +USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ $(MODE_INCLUDE) # To get a definition of F_SETSIG USER_CFLAGS += -D_GNU_SOURCE +CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS) + $(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< @@ -108,7 +114,6 @@ archclean: sysclean find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ -o -name '*.gcov' \) -type f -print | xargs rm -f rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS) - @$(MAKEBOOT) clean archdep: for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done @@ -133,9 +138,16 @@ $(ARCH_DIR)/include/uml-config.h : $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task $< > $@ -$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util FORCE ; +$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants + $< > $@ + +$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \ + $(ARCH_DIR)/util FORCE ; $(ARCH_DIR)/util: FORCE @$(call descend,$@,) +$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h : + $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h + export SUBARCH USER_CFLAGS OS diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index e4a66c4fbacf..3bd90fbdb7e0 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -21,13 +21,13 @@ prepare: $(SYS_HEADERS) $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc $< > $@ -$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread +$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread $< > $@ $(SYS_UTIL_DIR)/mk_sc: FORCE ; @$(call descend,$(SYS_UTIL_DIR),$@) -$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) FORCE ; +$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ; @$(call descend,$(SYS_UTIL_DIR),$@) $(SYS_UTIL_DIR): include/asm FORCE diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 79879f30aef5..62d30a693f52 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -19,6 +19,8 @@ #include "user.h" #include "helper.h" #include "os.h" +#include "choose-mode.h" +#include "mode.h" void generic_close(int fd, void *unused) { @@ -144,32 +146,6 @@ static int winch_thread(void *arg) } } -static int tracer_winch[2]; - -static void tracer_winch_handler(int sig) -{ - char c = 1; - - if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c)) - printk("tracer_winch_handler - write failed, errno = %d\n", - errno); -} - -/* Called only by the tracing thread during initialization */ - -void setup_tracer_winch(void) -{ - int err; - - err = os_pipe(tracer_winch, 1, 1); - if(err){ - printk("setup_tracer_winch : os_pipe failed, errno = %d\n", - -err); - return; - } - signal(SIGWINCH, tracer_winch_handler); -} - static int winch_tramp(int fd, void *device_data, int *fd_out) { struct winch_data data; @@ -211,10 +187,9 @@ void register_winch(int fd, void *device_data) if(!isatty(fd)) return; - pid = tcgetpgrp(fd); - if(pid == tracing_pid) - register_winch_irq(tracer_winch[0], fd, -1, device_data); - else if(pid == -1){ + pid = tcgetpgrp(fd); + if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && + (pid == -1)){ thread = winch_tramp(fd, device_data, &thread_fd); if(fd != -1){ register_winch_irq(thread_fd, fd, thread, device_data); diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index 6054dd6aa9ac..fc5f1d2f7d92 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -105,7 +105,7 @@ int pty_open(int input, int output, int primary, void *d) if(fd < 0) return(-errno); info.fd = fd; - tracing_cb(grantpt_cb, &info); + initial_thread_cb(grantpt_cb, &info); unlockpt(fd); if(data->raw) raw(fd, 0); diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 076b94d75765..1567cb6a79dd 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -15,23 +15,27 @@ extern char *gdb_init; extern int kmalloc_ok; extern int timer_irq_inited; extern int jail; +extern int nsyscalls; + extern struct task_struct *idle_threads[NR_CPUS]; -#define ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK)) -#define ROUND_UP(addr) ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) +#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK)) +#define UML_ROUND_UP(addr) \ + UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg); extern unsigned long stack_sp(unsigned long page); extern int kernel_thread_proc(void *data); extern void syscall_segv(int sig); extern int current_pid(void); -extern void set_init_pid(int pid); extern unsigned long alloc_stack(int order, int atomic); extern int do_signal(int error); extern int is_stack_fault(unsigned long sp); extern unsigned long segv(unsigned long address, unsigned long ip, - int is_write, int is_user, void *sc_ptr); -extern int set_user_mode(void *task); + int is_write, int is_user, void *sc); +extern unsigned long handle_page_fault(unsigned long address, unsigned long ip, + int is_write, int is_user, + int *code_out); extern void syscall_ready(void); extern void set_tracing(void *t, int tracing); extern int is_tracing(void *task); @@ -40,7 +44,6 @@ extern void kern_finish_exec(void *task, int new_pid, unsigned long stack); extern int page_size(void); extern int page_mask(void); extern int need_finish_fork(void); -extern int do_proc_op(void *t, int proc_id); extern void free_stack(unsigned long stack, int order); extern void add_input_request(int op, void (*proc)(int), void *arg); extern int sys_execve(char *file, char **argv, char **env); @@ -57,7 +60,6 @@ extern int next_trap_index(int max); extern void default_idle(void); extern void finish_fork(void); extern void paging_init(void); -extern unsigned long um_virt_to_phys(void *t, unsigned long addr); extern void init_flush_vm(void); extern void *syscall_sp(void *t); extern void syscall_trace(void); @@ -68,9 +70,7 @@ extern int external_pid(void *t); extern int pid_to_processor_id(int pid); extern void boot_timer_handler(int sig); extern void interrupt_end(void); -extern void tracing_reboot(void); -extern void tracing_halt(void); -extern void tracing_cb(void (*proc)(void *), void *arg); +extern void initial_thread_cb(void (*proc)(void *), void *arg); extern int debugger_signal(int status, int pid); extern void debugger_parent_signal(int status, int pid); extern void child_signal(int pid, int status); @@ -78,25 +78,19 @@ extern int init_ptrace_proxy(int idle_pid, int startup, int stop); extern int init_parent_proxy(int pid); extern void check_stack_overflow(void *ptr); extern void relay_signal(int sig, struct uml_pt_regs *regs); -extern int singlestepping(void *t); -extern void clear_singlestep(void *t); extern void not_implemented(void); extern int user_context(unsigned long sp); extern void timer_irq(struct uml_pt_regs *regs); extern void unprotect_stack(unsigned long stack); extern void do_uml_exitcalls(void); extern int attach_debugger(int idle_pid, int pid, int stop); -extern void *round_up(unsigned long addr); -extern void *round_down(unsigned long addr); extern void bad_segv(unsigned long address, unsigned long ip, int is_write); extern int config_gdb(char *str); extern int remove_gdb(void); extern char *uml_strdup(char *string); extern void unprotect_kernel_mem(void); extern void protect_kernel_mem(void); -extern unsigned long get_kmem_end(void); extern void set_kmem_end(unsigned long); -extern void set_task_sizes(int arg); extern void uml_cleanup(void); extern int pid_to_processor_id(int pid); extern void set_current(void *t); @@ -107,7 +101,6 @@ extern void *get_init_task(void); extern int clear_user_proc(void *buf, int size); extern int copy_to_user_proc(void *to, void *from, int size); extern int copy_from_user_proc(void *to, void *from, int size); -extern void set_thread_sc(void *sc); extern void bus_handler(int sig, struct uml_pt_regs *regs); extern long execute_syscall(void *r); extern int smp_sigio_handler(void); @@ -116,7 +109,6 @@ extern struct task_struct *get_task(int pid, int require); extern void machine_halt(void); extern int is_syscall(unsigned long addr); extern void arch_switch(void); -extern int is_valid_pid(int pid); extern void free_irq(unsigned int, void *); extern int um_in_interrupt(void); extern int cpu(void); diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index 4a3e68d56a5a..d80ac354bf28 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h @@ -54,11 +54,6 @@ extern int create_mem_file(unsigned long len); extern void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn, unsigned long total, int need_vm, struct mem_region *region, void *reserved); -extern void map(unsigned long virt, unsigned long p, unsigned long len, - int r, int w, int x); -extern int unmap(void *addr, int len); -extern int protect(unsigned long addr, unsigned long len, int r, int w, - int x, int must_succeed); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); extern int init_maps(struct mem_region *region); @@ -68,10 +63,15 @@ extern unsigned long get_vm(unsigned long len); extern void setup_physmem(unsigned long start, unsigned long usable, unsigned long len); extern int setup_region(struct mem_region *region, void *entry); -extern void add_iomem(char *name, int fd, int size); +extern void add_iomem(char *name, int fd, unsigned long size); extern struct mem_region *phys_region(unsigned long phys); extern unsigned long phys_offset(unsigned long phys); extern void unmap_physmem(void); +extern int map_memory(unsigned long virt, unsigned long phys, + unsigned long len, int r, int w, int x); +extern int protect_memory(unsigned long addr, unsigned long len, + int r, int w, int x, int must_succeed); +extern unsigned long get_kmem_end(void); #endif diff --git a/arch/um/include/syscall_user.h b/arch/um/include/syscall_user.h index e430752cb7ec..bc7be6293702 100644 --- a/arch/um/include/syscall_user.h +++ b/arch/um/include/syscall_user.h @@ -1,16 +1,13 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -#ifndef __SYSCALL_USER_H__ -#define __SYSCALL_USER_H__ +#ifndef __SYSCALL_USER_H +#define __SYSCALL_USER_H -#include - -extern void syscall_handler(int sig, struct uml_pt_regs *regs); -extern void exit_kernel(int pid, void *task); -extern int do_syscall(void *task, int pid); +extern int record_syscall_start(int syscall); +extern void record_syscall_end(int index, int result); #endif diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h index 46aa12342153..e658d491bc5b 100644 --- a/arch/um/include/sysdep-i386/ptrace.h +++ b/arch/um/include/sysdep-i386/ptrace.h @@ -1,44 +1,78 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ #ifndef __SYSDEP_I386_PTRACE_H #define __SYSDEP_I386_PTRACE_H -#include "sysdep/sc.h" +#include "uml-config.h" +#include "ptrace-tt.h" +#include "ptrace-skas.h" +#include "choose-mode.h" struct uml_pt_regs { unsigned long args[6]; long syscall; int is_user; - void *sc; + union { +#ifdef CONFIG_MODE_TT + void *tt; +#endif +#ifdef CONFIG_MODE_SKAS + struct { + unsigned long regs[HOST_FRAME_SIZE]; + unsigned long fp[HOST_FP_SIZE]; + unsigned long xfp[HOST_XFP_SIZE]; + unsigned long fault_addr; + unsigned long fault_type; + unsigned long trap_type; + } skas; +#endif + } mode; }; #define EMPTY_UML_PT_REGS { \ syscall : -1, \ args : { [0 ... 5] = 0 }, \ - is_user : 0, \ - sc : NULL } - -#define UPT_IP(regs) SC_IP((regs)->sc) -#define UPT_SP(regs) SC_SP((regs)->sc) -#define UPT_EFLAGS(regs) SC_EFLAGS((regs)->sc) -#define UPT_EAX(regs) SC_EAX((regs)->sc) -#define UPT_EBX(regs) SC_EBX((regs)->sc) -#define UPT_ECX(regs) SC_ECX((regs)->sc) -#define UPT_EDX(regs) SC_EDX((regs)->sc) -#define UPT_ESI(regs) SC_ESI((regs)->sc) -#define UPT_EDI(regs) SC_EDI((regs)->sc) -#define UPT_EBP(regs) SC_EBP((regs)->sc) -#define UPT_ORIG_EAX(regs) ((regs)->syscall) -#define UPT_CS(regs) SC_CS((regs)->sc) -#define UPT_SS(regs) SC_SS((regs)->sc) -#define UPT_DS(regs) SC_DS((regs)->sc) -#define UPT_ES(regs) SC_ES((regs)->sc) -#define UPT_FS(regs) SC_FS((regs)->sc) -#define UPT_GS(regs) SC_GS((regs)->sc) -#define UPT_SC(regs) ((regs)->sc) + is_user : 0 } + +extern int mode_tt; + +#define UPT_IP(r) \ + CHOOSE_MODE(SC_IP((r)->mode.tt), REGS_IP((r)->mode.skas.regs)) +#define UPT_SP(r) \ + CHOOSE_MODE(SC_SP((r)->mode.tt), REGS_SP((r)->mode.skas.regs)) +#define UPT_EFLAGS(r) \ + CHOOSE_MODE(SC_EFLAGS((r)->mode.tt), REGS_EFLAGS((r)->mode.skas.regs)) +#define UPT_EAX(r) \ + CHOOSE_MODE(SC_EAX((r)->mode.tt), REGS_EAX((r)->mode.skas.regs)) +#define UPT_EBX(r) \ + CHOOSE_MODE(SC_EBX((r)->mode.tt), REGS_EBX((r)->mode.skas.regs)) +#define UPT_ECX(r) \ + CHOOSE_MODE(SC_ECX((r)->mode.tt), REGS_ECX((r)->mode.skas.regs)) +#define UPT_EDX(r) \ + CHOOSE_MODE(SC_EDX((r)->mode.tt), REGS_EDX((r)->mode.skas.regs)) +#define UPT_ESI(r) \ + CHOOSE_MODE(SC_ESI((r)->mode.tt), REGS_ESI((r)->mode.skas.regs)) +#define UPT_EDI(r) \ + CHOOSE_MODE(SC_EDI((r)->mode.tt), REGS_EDI((r)->mode.skas.regs)) +#define UPT_EBP(r) \ + CHOOSE_MODE(SC_EBP((r)->mode.tt), REGS_EBP((r)->mode.skas.regs)) +#define UPT_ORIG_EAX(r) ((r)->syscall) +#define UPT_CS(r) \ + CHOOSE_MODE(SC_CS((r)->mode.tt), REGS_CS((r)->mode.skas.regs)) +#define UPT_SS(r) \ + CHOOSE_MODE(SC_SS((r)->mode.tt), REGS_SS((r)->mode.skas.regs)) +#define UPT_DS(r) \ + CHOOSE_MODE(SC_DS((r)->mode.tt), REGS_DS((r)->mode.skas.regs)) +#define UPT_ES(r) \ + CHOOSE_MODE(SC_ES((r)->mode.tt), REGS_ES((r)->mode.skas.regs)) +#define UPT_FS(r) \ + CHOOSE_MODE(SC_FS((r)->mode.tt), REGS_FS((r)->mode.skas.regs)) +#define UPT_GS(r) \ + CHOOSE_MODE(SC_GS((r)->mode.tt), REGS_GS((r)->mode.skas.regs)) +#define UPT_SC(r) ((r)->mode.tt) #define UPT_REG(regs, reg) \ ({ unsigned long val; \ @@ -94,12 +128,29 @@ struct uml_pt_regs { } \ } while (0) -#define UPT_SET_SYSCALL_RETURN(regs, res) \ - SC_SET_SYSCALL_RETURN((regs)->sc, (res)) -#define UPT_RESTART_SYSCALL(regs) SC_RESTART_SYSCALL((regs)->sc) -#define UPT_ORIG_SYSCALL(regs) UPT_EAX(regs) -#define UPT_SYSCALL_NR(regs) ((regs)->syscall) -#define UPT_SYSCALL_RET(regs) UPT_EAX(regs) +#define UPT_SET_SYSCALL_RETURN(r, res) \ + CHOOSE_MODE(SC_SET_SYSCALL_RETURN((r)->mode.tt, (res)), \ + REGS_SET_SYSCALL_RETURN((r)->mode.skas.regs, (res))) + +#define UPT_RESTART_SYSCALL(r) \ + CHOOSE_MODE(SC_RESTART_SYSCALL((r)->mode.tt), \ + REGS_RESTART_SYSCALL((r)->mode.skas.regs)) + +#define UPT_ORIG_SYSCALL(r) UPT_EAX(r) +#define UPT_SYSCALL_NR(r) ((r)->syscall) +#define UPT_SYSCALL_RET(r) UPT_EAX(r) + +#define UPT_SEGV_IS_FIXABLE(r) \ + CHOOSE_MODE(SC_SEGV_IS_FIXABLE(r->mode.tt), \ + REGS_SEGV_IS_FIXABLE(&r->mode.skas)) + +#define UPT_FAULT_ADDR(r) \ + CHOOSE_MODE(SC_FAULT_ADDR(r->mode.tt), \ + REGS_FAULT_ADDR(&r->mode.skas)) + +#define UPT_FAULT_WRITE(r) \ + CHOOSE_MODE(SC_FAULT_WRITE(r->mode.tt), \ + REGS_FAULT_WRITE(&r->mode.skas)) #endif diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h index f445f375c9a4..d52262e31499 100644 --- a/arch/um/include/sysdep-i386/sigcontext.h +++ b/arch/um/include/sysdep-i386/sigcontext.h @@ -6,13 +6,22 @@ #ifndef __SYS_SIGCONTEXT_I386_H #define __SYS_SIGCONTEXT_I386_H +#include "sc.h" + #define IP_RESTART_SYSCALL(ip) ((ip) -= 2) #define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc)) -#define SC_SET_SYSCALL_RETURN(sc, result) do SC_EAX(sc) = (result) ; while(0) +#define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result) #define SC_FAULT_ADDR(sc) SC_CR2(sc) -#define SC_FAULT_WRITE(sc) (SC_ERR(sc) & 2) +#define SC_FAULT_TYPE(sc) SC_ERR(sc) + +#define FAULT_WRITE(err) (err & 2) +#define TO_SC_ERR(is_write) ((is_write) ? 2 : 0) + +#define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc))) + +#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc) /* ptrace expects that, at the start of a system call, %eax contains * -ENOSYS, so this makes it so. @@ -20,10 +29,12 @@ #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0) /* These are General Protection and Page Fault */ -#define SEGV_IS_FIXABLE(sc) ((SC_TRAPNO(sc) == 13) || (SC_TRAPNO(sc) == 14)) +#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14)) -/* XXX struct sigcontext needs declaring by now */ +#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc))) +#ifdef CONFIG_MODE_TT +/* XXX struct sigcontext needs declaring by now */ static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc, unsigned long syscall) { @@ -35,6 +46,20 @@ static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc, regs->args[4] = SC_EDI(sc); regs->args[5] = SC_EBP(sc); } +#endif + +#ifdef CONFIG_MODE_SKAS +static inline void host_to_regs(struct uml_pt_regs *regs) +{ + regs->syscall = UPT_ORIG_EAX(regs); + regs->args[0] = UPT_EBX(regs); + regs->args[1] = UPT_ECX(regs); + regs->args[2] = UPT_EDX(regs); + regs->args[3] = UPT_ESI(regs); + regs->args[4] = UPT_EDI(regs); + regs->args[5] = UPT_EBP(regs); +} +#endif extern unsigned long *sc_sigmask(void *sc_ptr); extern int sc_get_fpregs(unsigned long buf, void *sc_ptr); diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index f4aea6b27411..f1d3bca2bd27 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -23,6 +23,13 @@ struct cpu_task { extern struct cpu_task cpu_tasks[]; +struct signal_info { + void (*handler)(int, struct uml_pt_regs *); + int is_irq; +}; + +extern struct signal_info sig_info[]; + extern unsigned long low_physmem; extern unsigned long high_physmem; extern unsigned long uml_physmem; @@ -31,16 +38,11 @@ extern unsigned long end_vm; extern unsigned long start_vm; extern unsigned long highmem; -extern int tracing_pid; -extern int honeypot; - extern char host_info[]; extern char saved_command_line[]; extern char command_line[]; -extern int gdb_pid; - extern char *tempdir; extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; @@ -53,12 +55,10 @@ extern int pty_close_sigio; extern void stop(void); extern void stack_protections(unsigned long address); extern void task_protections(unsigned long address); -extern int signals(int (*init_proc)(void *), void *sp); extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); extern void *add_signal_handler(int sig, void (*handler)(int)); extern int start_fork_tramp(void *arg, unsigned long temp_stack, int clone_flags, int (*tramp)(void *)); -extern void trace_myself(void); extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags); extern int linux_main(int argc, char **argv); extern void remap_data(void *segment_start, void *segment_end, int w); @@ -71,13 +71,13 @@ extern int switcheroo(int fd, int prot, void *from, void *to, int size); extern void setup_machinename(char *machine_out); extern void setup_hostinfo(void); extern void add_arg(char *cmd_line, char *arg); -extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int)); +extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); +extern void init_new_thread_signals(int altstack); extern void attach_process(int pid); -extern int fork_tramp(void *sig_stack); extern void do_exec(int old_pid, int new_pid); extern void tracer_panic(char *msg, ...); extern char *get_umid(int only_if_set); -extern void do_longjmp(void *p); +extern void do_longjmp(void *p, int val); extern void suspend_new_thread(int fd); extern int detach(int pid, int sig); extern int attach(int pid); @@ -91,7 +91,8 @@ extern void arch_check_bugs(void); extern int arch_handle_signal(int sig, struct uml_pt_regs *regs); extern int arch_fixup(unsigned long address, void *sc_ptr); extern void forward_pending_sigio(int target); - +extern int can_do_skas(void); + #endif /* diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 4fb60e8af16c..889fd82f1638 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_GCOV) += gmon_syms.o obj-$(CONFIG_TTY_LOG) += tty_log.o obj-$(CONFIG_MODE_TT) += tt/ -obj-$(CONFIG_MODE_SKAS) += tt/ +obj-$(CONFIG_MODE_SKAS) += skas/ user-objs-$(CONFIG_TTY_LOG) += tty_log.o @@ -28,7 +28,7 @@ user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \ process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o -USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/kernel/$(file)) +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS)) UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS)) @@ -51,24 +51,24 @@ include $(TOPDIR)/Rules.make $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< -arch/um/kernel/unmap.o: arch/um/kernel/unmap.c +$(obj)/unmap.o: $(src)/unmap.c $(CC) $(UNMAP_CFLAGS) -c -o $@ $< -arch/um/kernel/unmap_fin.o : arch/um/kernel/unmap.o +$(obj)/unmap_fin.o : $(src)/unmap.o ld -r -o $@ $< -lc -L/usr/lib # This has to be separate because it needs be compiled with frame pointers # regardless of how the rest of the kernel is built. -arch/um/kernel/frame.o: arch/um/kernel/frame.c +$(obj)/frame.o: $(src)/frame.c $(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $< QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' -arch/um/kernel/config.c : arch/um/kernel/config.c.in $(TOPDIR)/.config - $(PERL) -e $(QUOTE) < arch/um/kernel/config.c.in > $@ +$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config + $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@ -arch/um/kernel/config.o : arch/um/kernel/config.c +$(obj)/config.o : $(obj)/config.c clean: rm -f config.c diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index cdbb95f6d0bd..eaae628fa902 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -18,65 +18,17 @@ #include "2_5compat.h" #include "os.h" #include "time_user.h" - -/* See comment above fork_tramp for why sigstop is defined and used like - * this - */ - -static int sigstop = SIGSTOP; - -static int exec_tramp(void *sig_stack) -{ - int sig = sigstop; - - init_new_thread(sig_stack, NULL); - kill(os_getpid(), sig); - return(0); -} +#include "choose-mode.h" +#include "mode_kern.h" void flush_thread(void) { - unsigned long stack; - int new_pid; - - stack = alloc_stack(0, 0); - if(stack == 0){ - printk(KERN_ERR - "flush_thread : failed to allocate temporary stack\n"); - do_exit(SIGKILL); - } - - new_pid = start_fork_tramp((void *) current->thread.kernel_stack, - stack, 0, exec_tramp); - if(new_pid < 0){ - printk(KERN_ERR - "flush_thread : new thread failed, errno = %d\n", - -new_pid); - do_exit(SIGKILL); - } - - if(current->thread_info->cpu == 0) - forward_interrupts(new_pid); - current->thread.request.op = OP_EXEC; - current->thread.request.u.exec.pid = new_pid; - unprotect_stack((unsigned long) current->thread_info); - os_usr1_process(os_getpid()); - - enable_timer(); - free_page(stack); - protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); - force_flush_all(); - unblock_signals(); + CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); } void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) { - set_fs(USER_DS); - flush_tlb_mm(current->mm); - PT_REGS_IP(regs) = eip; - PT_REGS_SP(regs) = esp; - PT_FIX_EXEC_STACK(esp); + CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); } static int execve1(char *file, char **argv, char **env) diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c index 574ddce69065..8726b2a1a439 100644 --- a/arch/um/kernel/frame_kern.c +++ b/arch/um/kernel/frame_kern.c @@ -43,7 +43,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, if(restorer == NULL) panic("setup_signal_stack_si - no restorer"); - if(copy_sc_to_user((void *) sc, regs->regs.sc, + if(copy_sc_to_user((void *) sc, regs->regs.mode.tt, &signal_frame_sc.arch) || copy_to_user((void *) start, signal_frame_si.common.data, signal_frame_si.common.len) || @@ -86,7 +86,8 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, if(copy_to_user((void *) start, frame->data, frame->len) || copy_to_user((void *) (start + frame->sig_index), &sig, sizeof(sig)) || - copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) || + copy_sc_to_user(user_sc, regs->regs.mode.tt, + &signal_frame_sc.arch) || copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) || copy_to_user((void *) sigs, &mask->sig[1], sig_size) || copy_restorer(restorer, start, frame->sr_index, frame->sr_relative)) diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index f06162f5a113..c9bc00a19403 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c @@ -47,7 +47,7 @@ struct task_struct *alloc_task_struct(void){ void unprotect_stack(unsigned long stack) { - protect(stack, 4 * PAGE_SIZE, 1, 1, 0, 1); + protect_memory(stack, 4 * PAGE_SIZE, 1, 1, 0, 1); } void free_task_struct(struct task_struct *task) diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 28e728347041..7de3e05edbab 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #include "linux/config.h" #include "linux/module.h" #include "linux/string.h" @@ -19,17 +24,13 @@ EXPORT_SYMBOL(stop); EXPORT_SYMBOL(uml_physmem); EXPORT_SYMBOL(set_signals); +EXPORT_SYMBOL(get_signals); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(__const_udelay); +EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(sys_waitpid); EXPORT_SYMBOL(task_size); -EXPORT_SYMBOL(__do_copy_from_user); -EXPORT_SYMBOL(__do_copy_to_user); -EXPORT_SYMBOL(__do_strncpy_from_user); -EXPORT_SYMBOL(__do_strnlen_user); EXPORT_SYMBOL(flush_tlb_range); -EXPORT_SYMBOL(__do_clear_user); -EXPORT_SYMBOL(honeypot); EXPORT_SYMBOL(host_task_size); EXPORT_SYMBOL(arch_validate); @@ -37,10 +38,10 @@ EXPORT_SYMBOL(region_pa); EXPORT_SYMBOL(region_va); EXPORT_SYMBOL(phys_mem_map); EXPORT_SYMBOL(page_mem_map); -EXPORT_SYMBOL(get_signals); EXPORT_SYMBOL(page_to_phys); EXPORT_SYMBOL(phys_to_page); EXPORT_SYMBOL(high_physmem); +EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(os_open_file); EXPORT_SYMBOL(os_read_file); @@ -53,7 +54,6 @@ EXPORT_SYMBOL(helper_wait); EXPORT_SYMBOL(os_shutdown_socket); EXPORT_SYMBOL(os_connect_socket); EXPORT_SYMBOL(run_helper); -EXPORT_SYMBOL(tracing_pid); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(dump_thread); @@ -75,6 +75,7 @@ EXPORT_SYMBOL_NOVERS(__write_lock_failed); extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); EXPORT_SYMBOL_NOVERS(__read_lock_failed); +EXPORT_SYMBOL(smp_num_cpus); #endif #ifdef CONFIG_HIGHMEM diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 5a582a8de7d1..3db5375ebe04 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -25,6 +25,8 @@ #include "mem.h" #include "kern.h" #include "init.h" +#include "os.h" +#include "mode_kern.h" /* Changed during early boot */ pgd_t swapper_pg_dir[1024]; @@ -56,12 +58,12 @@ static unsigned long brk_end; static void map_cb(void *unused) { - map(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); + map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); } void unmap_physmem(void) { - unmap((void *) brk_end, uml_reserved - brk_end); + os_unmap_memory((void *) brk_end, uml_reserved - brk_end); } extern char __binary_start; @@ -81,17 +83,17 @@ void mem_init(void) /* Map in the area just after the brk now that kmalloc is about * to be turned on. */ - brk_end = (unsigned long) ROUND_UP(sbrk(0)); + brk_end = (unsigned long) UML_ROUND_UP(sbrk(0)); map_cb(NULL); - tracing_cb(map_cb, NULL); + initial_thread_cb(map_cb, NULL); free_bootmem(__pa(brk_end), uml_reserved - brk_end); uml_reserved = brk_end; /* Fill in any hole at the start of the binary */ start = (unsigned long) &__binary_start; if(uml_physmem != start){ - map(uml_physmem, __pa(uml_physmem), start - uml_physmem, - 1, 1, 0); + map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem, + 1, 1, 0); } /* this will put all low memory onto the freelists */ @@ -106,6 +108,21 @@ void mem_init(void) kmalloc_ok = 1; } +/* Changed during early boot */ +static unsigned long kmem_top = 0; + +unsigned long get_kmem_end(void) +{ + if(kmem_top == 0) + kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); + return(kmem_top); +} + +void set_kmem_end(unsigned long new) +{ + kmem_top = new; +} + #if CONFIG_HIGHMEM /* Changed during early boot */ pte_t *kmap_pte; @@ -379,20 +396,6 @@ void show_mem(void) printk("%d pages swap cached\n", cached); } -/* Changed during early boot */ -static unsigned long kmem_top = 0; - -unsigned long get_kmem_end(void) -{ - if(kmem_top == 0) kmem_top = host_task_size - ABOVE_KMEM; - return(kmem_top); -} - -void set_kmem_end(unsigned long new) -{ - kmem_top = new; -} - static int __init uml_mem_setup(char *line, int *add) { char *retptr; @@ -513,7 +516,7 @@ unsigned long get_vm(unsigned long len) return(0); found: up(&vm_reserved_sem); - start = (unsigned long) ROUND_UP(this->end) + PAGE_SIZE; + start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE; err = reserve_vm(start, start + len, NULL); if(err) return(0); return(start); @@ -562,7 +565,7 @@ struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = int num_iomem_regions = 0; -void add_iomem(char *name, int fd, int size) +void add_iomem(char *name, int fd, unsigned long size) { if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0])) return; diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c index af857510d17a..d90345b5fd44 100644 --- a/arch/um/kernel/mem_user.c +++ b/arch/um/kernel/mem_user.c @@ -181,44 +181,22 @@ void log(char *fmt, ...) } #endif -void map(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x) +int map_memory(unsigned long virt, unsigned long phys, unsigned long len, + int r, int w, int x) { - struct mem_region *region; - void *loc; - int prot; - - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); - region = phys_region(phys); - - loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, - region->fd, phys_offset(phys)); - if(loc != (void *) virt){ - panic("Error mapping a page - errno = %d", errno); - } -} - -int unmap(void *addr, int len) -{ - int err; + struct mem_region *region = phys_region(phys); - err = munmap(addr, len); - if(err < 0) return(-errno); - else return(err); + return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len, + r, w, x)); } -int protect(unsigned long addr, unsigned long len, int r, int w, int x, - int must_succeed) +int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, + int must_succeed) { - int prot; - - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); - if(mprotect((void *) addr, len, prot) == -1){ - if(must_succeed) - panic("protect failed, errno = %d", errno); - else return(-errno); + if(os_protect_memory((void *) addr, len, r, w, x) < 0){ + if(must_succeed) + panic("protect failed, errno = %d", errno); + else return(-errno); } return(0); } diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index da86f77b0d96..1119d6b2b922 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -21,9 +21,6 @@ #include #include #include -#ifdef PROFILING -#include -#endif #include "user_util.h" #include "kern_util.h" #include "user.h" @@ -33,13 +30,18 @@ #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" #include "irq_user.h" -#include "syscall_user.h" #include "ptrace_user.h" #include "time_user.h" #include "init.h" #include "os.h" +#include "uml-config.h" +#include "choose-mode.h" +#include "mode.h" +#ifdef CONFIG_MODE_SKAS +#include "skas_ptrace.h" +#endif -void init_new_thread(void *sig_stack, void (*usr1_handler)(int)) +void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) { int flags = 0; @@ -47,6 +49,13 @@ void init_new_thread(void *sig_stack, void (*usr1_handler)(int)) set_sigstack(sig_stack, 2 * page_size()); flags = SA_ONSTACK; } + if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); +} + +void init_new_thread_signals(int altstack) +{ + int flags = altstack ? SA_ONSTACK : 0; + set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, @@ -61,11 +70,10 @@ void init_new_thread(void *sig_stack, void (*usr1_handler)(int)) SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGUSR2, (__sighandler_t) sig_handler, SA_NOMASK | flags, -1); - if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); - signal(SIGCHLD, SIG_IGN); + (void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0); signal(SIGHUP, SIG_IGN); - init_irq_signals(sig_stack != NULL); + init_irq_signals(altstack); } struct tramp { @@ -128,26 +136,6 @@ void trace_myself(void) panic("ptrace failed in trace_myself"); } -void attach_process(int pid) -{ - if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) || - (ptrace(PTRACE_CONT, pid, 0, 0) < 0)) - tracer_panic("OP_FORK failed to attach pid"); - wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); - if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) - tracer_panic("OP_FORK failed to continue process"); -} - -void tracer_panic(char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vprintf(format, ap); - printf("\n"); - while(1) sleep(10); -} - void suspend_new_thread(int fd) { char c; diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 8d9333e398d9..991b2097dc9d 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -40,6 +40,9 @@ #include "sigcontext.h" #include "2_5compat.h" #include "os.h" +#include "mode.h" +#include "mode_kern.h" +#include "choose-mode.h" /* This is a per-cpu array. A processor only modifies its entry and it only * cares about its entry, so it's OK if another processor is modifying its @@ -64,26 +67,11 @@ struct task_struct *get_task(int pid, int require) return(ret); } -int is_valid_pid(int pid) -{ - struct task_struct *task; - - read_lock(&tasklist_lock); - for_each_process(task){ - if(task->thread.extern_pid == pid){ - read_unlock(&tasklist_lock); - return(1); - } - } - read_unlock(&tasklist_lock); - return(0); -} - int external_pid(void *t) { struct task_struct *task = t ? t : current; - return(task->thread.extern_pid); + return(task->thread.mode.tt.extern_pid); } int pid_to_processor_id(int pid) @@ -101,37 +89,6 @@ void free_stack(unsigned long stack, int order) free_pages(stack, order); } -void set_init_pid(int pid) -{ - int err; - - init_task.thread.extern_pid = pid; - err = os_pipe(init_task.thread.switch_pipe, 1, 1); - if(err) panic("Can't create switch pipe for init_task, errno = %d", - err); -} - -int set_user_mode(void *t) -{ - struct task_struct *task; - - task = t ? t : current; - if(task->thread.tracing) return(1); - task->thread.request.op = OP_TRACE_ON; - os_usr1_process(os_getpid()); - return(0); -} - -void set_tracing(void *task, int tracing) -{ - ((struct task_struct *) task)->thread.tracing = tracing; -} - -int is_tracing(void *t) -{ - return (((struct task_struct *) t)->thread.tracing); -} - unsigned long alloc_stack(int order, int atomic) { unsigned long page; @@ -144,46 +101,6 @@ unsigned long alloc_stack(int order, int atomic) return(page); } -extern void schedule_tail(struct task_struct *prev); - -static void new_thread_handler(int sig) -{ - int (*fn)(void *); - void *arg; - - fn = current->thread.request.u.thread.proc; - arg = current->thread.request.u.thread.arg; - current->thread.regs.regs.sc = (void *) (&sig + 1); - suspend_new_thread(current->thread.switch_pipe[0]); - - block_signals(); -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif - enable_timer(); - free_page(current->thread.temp_stack); - set_cmdline("(kernel thread)"); - force_flush_all(); - - current->thread.prev_sched = NULL; - change_sig(SIGUSR1, 1); - change_sig(SIGVTALRM, 1); - change_sig(SIGPROF, 1); - unblock_signals(); - if(!run_kernel_thread(fn, arg, ¤t->thread.jmp)) - do_exit(0); -} - -static int new_thread_proc(void *stack) -{ - change_sig(SIGIO, 0); - change_sig(SIGVTALRM, 0); - change_sig(SIGPROF, 0); - init_new_thread(stack, new_thread_handler); - os_usr1_process(os_getpid()); - return(0); -} - int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { struct task_struct *p; @@ -208,83 +125,13 @@ void set_current(void *t) struct task_struct *task = t; cpu_tasks[task->thread_info->cpu] = ((struct cpu_task) - { task->thread.extern_pid, task }); + { external_pid(task), task }); } void *switch_to(void *prev, void *next, void *last) { - struct task_struct *from, *to; - unsigned long flags; - int vtalrm, alrm, prof, err, cpu; - char c; - /* jailing and SMP are incompatible, so this doesn't need to be - * made per-cpu - */ - static int reading; - - from = prev; - to = next; - - to->thread.prev_sched = from; - - cpu = from->thread_info->cpu; - if(cpu == 0) - forward_interrupts(to->thread.extern_pid); -#ifdef CONFIG_SMP - forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.extern_pid); -#endif - local_irq_save(flags); - - vtalrm = change_sig(SIGVTALRM, 0); - alrm = change_sig(SIGALRM, 0); - prof = change_sig(SIGPROF, 0); - - forward_pending_sigio(to->thread.extern_pid); - - c = 0; - set_current(to); - - reading = 0; - err = os_write_file(to->thread.switch_pipe[1], &c, sizeof(c)); - if(err != sizeof(c)) - panic("write of switch_pipe failed, errno = %d", -err); - - reading = 1; - if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) - os_kill_process(os_getpid(), 0); - - err = os_read_file(from->thread.switch_pipe[0], &c, sizeof(c)); - if(err != sizeof(c)) - panic("read of switch_pipe failed, errno = %d", -err); - - /* This works around a nasty race with 'jail'. If we are switching - * between two threads of a threaded app and the incoming process - * runs before the outgoing process reaches the read, and it makes - * it all the way out to userspace, then it will have write-protected - * the outgoing process stack. Then, when the outgoing process - * returns from the write, it will segfault because it can no longer - * write its own stack. So, in order to avoid that, the incoming - * thread sits in a loop yielding until 'reading' is set. This - * isn't entirely safe, since there may be a reschedule from a timer - * happening between setting 'reading' and sleeping in read. But, - * it should get a whole quantum in which to reach the read and sleep, - * which should be enough. - */ - - if(jail){ - while(!reading) sched_yield(); - } - - change_sig(SIGVTALRM, vtalrm); - change_sig(SIGALRM, alrm); - change_sig(SIGPROF, prof); - - arch_switch(); - - flush_tlb_all(); - local_irq_restore(flags); - - return(current->thread.prev_sched); + return(CHOOSE_MODE(switch_to_tt(prev, next), + switch_to_skas(prev, next))); } void interrupt_end(void) @@ -295,193 +142,37 @@ void interrupt_end(void) void release_thread(struct task_struct *task) { - os_kill_process(task->thread.extern_pid, 0); + CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task)); } - + void exit_thread(void) { - close(current->thread.switch_pipe[0]); - close(current->thread.switch_pipe[1]); + CHOOSE_MODE(exit_thread_tt(), exit_thread_skas()); unprotect_stack((unsigned long) current->thread_info); } - -/* Signal masking - signals are blocked at the start of fork_tramp. They - * are re-enabled when finish_fork_handler is entered by fork_tramp hitting - * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, - * so it is blocked before it's called. They are re-enabled on sigreturn - * despite the fact that they were blocked when the SIGUSR1 was issued because - * copy_thread copies the parent's signcontext, including the signal mask - * onto the signal frame. - */ - -void finish_fork_handler(int sig) -{ - current->thread.regs.regs.sc = (void *) (&sig + 1); - suspend_new_thread(current->thread.switch_pipe[0]); - -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif - enable_timer(); - change_sig(SIGVTALRM, 1); - force_flush_all(); - if(current->mm != current->parent->mm) - protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); - - current->thread.prev_sched = NULL; - - free_page(current->thread.temp_stack); - change_sig(SIGUSR1, 0); - set_user_mode(current); -} - + void *get_current(void) { return(current); } -/* This sigusr1 business works around a bug in gcc's -pg support. - * Normally a procedure's mcount call comes after esp has been copied to - * ebp and the new frame is constructed. With procedures with no locals, - * the mcount comes before, as the first thing that the procedure does. - * When that procedure is main for a thread, ebp comes in as NULL. So, - * when mcount dereferences it, it segfaults. So, UML works around this - * by adding a non-optimizable local to the various trampolines, fork_tramp - * and outer_tramp below, and exec_tramp. - */ - -static int sigusr1 = SIGUSR1; - -int fork_tramp(void *stack) -{ - int sig = sigusr1; - - change_sig(SIGIO, 0); - change_sig(SIGVTALRM, 0); - change_sig(SIGPROF, 0); - init_new_thread(stack, finish_fork_handler); - - kill(os_getpid(), sig); - return(0); -} - int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { - int new_pid, err; - unsigned long stack; - int (*tramp)(void *); - p->thread = (struct thread_struct) INIT_THREAD; p->thread.kernel_stack = (unsigned long) p->thread_info + 2 * PAGE_SIZE; - - if(current->thread.forking) - tramp = fork_tramp; - else { - tramp = new_thread_proc; - p->thread.request.u.thread = current->thread.request.u.thread; - } - - err = os_pipe(p->thread.switch_pipe, 1, 1); - if(err){ - printk("copy_thread : pipe failed, errno = %d\n", -err); - return(err); - } - - stack = alloc_stack(0, 0); - if(stack == 0){ - printk(KERN_ERR "copy_thread : failed to allocate " - "temporary stack\n"); - return(-ENOMEM); - } - - clone_flags &= CLONE_VM; - p->thread.temp_stack = stack; - new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack, - clone_flags, tramp); - if(new_pid < 0){ - printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", - -new_pid); - return(new_pid); - } - - if(current->thread.forking){ - sc_to_sc(p->thread.regs.regs.sc, current->thread.regs.regs.sc); - PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0); - if(sp != 0) PT_REGS_SP(&p->thread.regs) = sp; - } - p->thread.extern_pid = new_pid; - - current->thread.request.op = OP_FORK; - current->thread.request.u.fork.pid = new_pid; - os_usr1_process(os_getpid()); - return(0); -} - -void tracing_reboot(void) -{ - current->thread.request.op = OP_REBOOT; - os_usr1_process(os_getpid()); -} - -void tracing_halt(void) -{ - current->thread.request.op = OP_HALT; - os_usr1_process(os_getpid()); + return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, + clone_flags, sp, stack_top, p, regs)); } -void tracing_cb(void (*proc)(void *), void *arg) +void initial_thread_cb(void (*proc)(void *), void *arg) { - if(os_getpid() == tracing_pid){ - (*proc)(arg); - } - else { - current->thread.request.op = OP_CB; - current->thread.request.u.cb.proc = proc; - current->thread.request.u.cb.arg = arg; - os_usr1_process(os_getpid()); - } -} - -int do_proc_op(void *t, int proc_id) -{ - struct task_struct *task; - struct thread_struct *thread; - int op, pid; - - task = t; - thread = &task->thread; - op = thread->request.op; - switch(op){ - case OP_NONE: - case OP_TRACE_ON: - break; - case OP_EXEC: - pid = thread->request.u.exec.pid; - do_exec(thread->extern_pid, pid); - thread->extern_pid = pid; - cpu_tasks[task->thread_info->cpu].pid = pid; - break; - case OP_FORK: - attach_process(thread->request.u.fork.pid); - break; - case OP_CB: - (*thread->request.u.cb.proc)(thread->request.u.cb.arg); - break; - case OP_REBOOT: - case OP_HALT: - break; - default: - tracer_panic("Bad op in do_proc_op"); - break; - } - thread->request.op = OP_NONE; - return(op); + CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, + arg); } - + unsigned long stack_sp(unsigned long page) { return(page + PAGE_SIZE - sizeof(void *)); @@ -518,7 +209,7 @@ void default_idle(void) void cpu_idle(void) { - default_idle(); + CHOOSE_MODE(init_idle_tt(), init_idle_skas()); } int page_size(void) @@ -602,22 +293,6 @@ unsigned long get_fault_addr(void) EXPORT_SYMBOL(get_fault_addr); -void clear_singlestep(void *t) -{ - struct task_struct *task = (struct task_struct *) t; - - task->ptrace &= ~PT_DTRACE; -} - -int singlestepping(void *t) -{ - struct task_struct *task = (struct task_struct *) t; - - if(task->thread.singlestep_syscall) - return(0); - return(task->ptrace & PT_DTRACE); -} - void not_implemented(void) { printk(KERN_DEBUG "Something isn't implemented in here\n"); @@ -644,16 +319,6 @@ void do_uml_exitcalls(void) (*call)(); } -void *round_up(unsigned long addr) -{ - return(ROUND_UP(addr)); -} - -void *round_down(unsigned long addr) -{ - return(ROUND_DOWN(addr)); -} - char *uml_strdup(char *string) { char *new; @@ -664,82 +329,6 @@ char *uml_strdup(char *string) return(new); } -/* Changed by jail_setup, which is a setup */ -int jail = 0; - -int __init jail_setup(char *line, int *add) -{ - int ok = 1; - - if(jail) return(0); -#ifdef CONFIG_SMP - printf("'jail' may not used used in a kernel with CONFIG_SMP " - "enabled\n"); - ok = 0; -#endif -#ifdef CONFIG_HOSTFS - printf("'jail' may not used used in a kernel with CONFIG_HOSTFS " - "enabled\n"); - ok = 0; -#endif -#ifdef CONFIG_MODULES - printf("'jail' may not used used in a kernel with CONFIG_MODULES " - "enabled\n"); - ok = 0; -#endif - if(!ok) exit(1); - - /* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem. - * Removing it from the bounding set eliminates the ability of anything - * to acquire it, and thus read or write kernel memory. - */ - cap_lower(cap_bset, CAP_SYS_RAWIO); - jail = 1; - return(0); -} - -__uml_setup("jail", jail_setup, -"jail\n" -" Enables the protection of kernel memory from processes.\n\n" -); - -static void mprotect_kernel_mem(int w) -{ - unsigned long start, end; - - if(!jail || (current == &init_task)) return; - - start = (unsigned long) current->thread_info + PAGE_SIZE; - end = (unsigned long) current->thread_info + PAGE_SIZE * 4; - protect(uml_reserved, start - uml_reserved, 1, w, 1, 1); - protect(end, high_physmem - end, 1, w, 1, 1); - - start = (unsigned long) ROUND_DOWN(&_stext); - end = (unsigned long) ROUND_UP(&_etext); - protect(start, end - start, 1, w, 1, 1); - - start = (unsigned long) ROUND_DOWN(&_unprotected_end); - end = (unsigned long) ROUND_UP(&_edata); - protect(start, end - start, 1, w, 1, 1); - - start = (unsigned long) ROUND_DOWN(&__bss_start); - end = (unsigned long) ROUND_UP(brk_start); - protect(start, end - start, 1, w, 1, 1); - - mprotect_kernel_vm(w); -} - -/* No SMP problems since jailing and SMP are incompatible */ -void unprotect_kernel_mem(void) -{ - mprotect_kernel_mem(1); -} - -void protect_kernel_mem(void) -{ - mprotect_kernel_mem(0); -} - void *get_init_task(void) { return(&init_thread_union.thread_info.task); @@ -762,7 +351,7 @@ int clear_user_proc(void *buf, int size) void set_thread_sc(void *sc) { - current->thread.regs.regs.sc = sc; + current->thread.regs.regs.mode.tt = sc; } int smp_sigio_handler(void) diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index a9b9a91b9afb..61d7a4e6000f 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -8,6 +8,8 @@ #include "kern_util.h" #include "kern.h" #include "os.h" +#include "mode.h" +#include "choose-mode.h" #ifdef CONFIG_SMP static void kill_idlers(int me) @@ -17,26 +19,17 @@ static void kill_idlers(int me) for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){ p = idle_threads[i]; - if((p != NULL) && (p->thread.extern_pid != me)) - os_kill_process(p->thread.extern_pid, 0); + if((p != NULL) && (p->thread.mode.tt.extern_pid != me)) + os_kill_process(p->thread.mode.tt.extern_pid, 0); } } #endif static void kill_off_processes(void) { - struct task_struct *p; - int me; - - me = os_getpid(); - for_each_process(p){ - if(p->thread.extern_pid != me) - os_kill_process(p->thread.extern_pid, 0); - } - if(init_task.thread.extern_pid != me) - os_kill_process(init_task.thread.extern_pid, 0); + CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas()); #ifdef CONFIG_SMP - kill_idlers(me); + kill_idlers(os_getpid()); #endif } @@ -50,16 +43,14 @@ void machine_restart(char * __unused) { do_uml_exitcalls(); kill_off_processes(); - tracing_reboot(); - os_kill_process(os_getpid(), 0); + CHOOSE_MODE(reboot_tt(), reboot_skas()); } void machine_power_off(void) { do_uml_exitcalls(); kill_off_processes(); - tracing_halt(); - os_kill_process(os_getpid(), 0); + CHOOSE_MODE(halt_tt(), halt_skas()); } void machine_halt(void) diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index be60440cf012..83db897787ee 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -171,7 +171,7 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) */ if((current->ptrace & PT_DTRACE) && is_syscall(PT_REGS_IP(¤t->thread.regs))) - current->thread.singlestep_syscall = 1; + current->thread.mode.tt.singlestep_syscall = 1; return(0); } @@ -241,7 +241,7 @@ int sys_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs.regs.sc, sc, + copy_sc_from_user(current->thread.regs.regs.mode.tt, sc, &signal_frame_sc.arch); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } @@ -257,7 +257,7 @@ int sys_rt_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs.regs.sc, sc, + copy_sc_from_user(current->thread.regs.regs.mode.tt, sc, &signal_frame_sc.arch); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile new file mode 100644 index 000000000000..cb83a2255fa9 --- /dev/null +++ b/arch/um/kernel/skas/Makefile @@ -0,0 +1,27 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +obj-y = exec_kern.o exec_user.o mem_user.o mmu.o process.o process_kern.o \ + syscall_user.o trap_user.o + +obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) + +USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + +include $(TOPDIR)/Rules.make + +include/skas_ptregs.h : util/mk_ptregs + util/mk_ptregs > $@ + +util/mk_ptregs : + $(MAKE) -C util + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +clean : + $(MAKE) -C util clean + $(RM) -f include/skas_ptregs.h diff --git a/arch/um/kernel/skas/include/mode_kern.h b/arch/um/kernel/skas/include/mode_kern.h new file mode 100644 index 000000000000..dcbc70345a56 --- /dev/null +++ b/arch/um/kernel/skas/include/mode_kern.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_MODE_KERN_H__ +#define __SKAS_MODE_KERN_H__ + +#include "linux/sched.h" +#include "asm/page.h" +#include "asm/ptrace.h" + +extern void flush_thread_skas(void); +extern void *switch_to_skas(void *prev, void *next); +extern void start_thread_skas(struct pt_regs *regs, unsigned long eip, + unsigned long esp); +extern int copy_thread_skas(int nr, unsigned long clone_flags, + unsigned long sp, unsigned long stack_top, + struct task_struct *p, struct pt_regs *regs); +extern void release_thread_skas(struct task_struct *task); +extern void exit_thread_skas(void); +extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); +extern void init_idle_skas(void); +extern void flush_tlb_kernel_vm_skas(void); +extern void __flush_tlb_one_skas(unsigned long addr); +extern void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start, + unsigned long end); +extern void flush_tlb_mm_skas(struct mm_struct *mm); +extern void force_flush_all_skas(void); +extern long execute_syscall_skas(void *r); +extern void before_mem_skas(unsigned long unused); +extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, + unsigned long *task_size_out); +extern int start_uml_skas(void); +extern struct page *arch_validate_skas(struct page *page, int mask, int order); +extern int external_pid_skas(struct task_struct *task); +extern int thread_pid_skas(struct thread_struct *thread); + +#define kmem_end_skas (host_task_size) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c new file mode 100644 index 000000000000..5911cdd0c0b7 --- /dev/null +++ b/arch/um/kernel/skas/mmu.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/list.h" +#include "linux/spinlock.h" +#include "linux/slab.h" +#include "asm/current.h" +#include "asm/segment.h" +#include "asm/mmu.h" +#include "os.h" +#include "skas.h" + +int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) +{ + int from; + + if((current->mm != NULL) && (current->mm != &init_mm)) + from = current->mm->context.skas.mm_fd; + else from = -1; + + mm->context.skas.mm_fd = new_mm(from); + if(mm->context.skas.mm_fd < 0) + panic("init_new_context_skas - new_mm failed, errno = %d\n", + mm->context.skas.mm_fd); + + return(0); +} + +void destroy_context_skas(struct mm_struct *mm) +{ + os_close_file(mm->context.skas.mm_fd); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index b15340a6b837..adc52d2dccf2 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -407,8 +407,8 @@ long execute_syscall(void *r) set_fs(USER_DS); - if(current->thread.singlestep_syscall){ - current->thread.singlestep_syscall = 0; + if(current->thread.mode.tt.singlestep_syscall){ + current->thread.mode.tt.singlestep_syscall = 0; current->ptrace &= ~PT_DTRACE; force_sig(SIGTRAP, current); } diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c index 5da5aefce6d8..00e8fcc10f27 100644 --- a/arch/um/kernel/syscall_user.c +++ b/arch/um/kernel/syscall_user.c @@ -1,30 +1,12 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -/* XXX FIXME : Ensure that SIGIO and SIGVTALRM can't happen immediately - * after setting up syscall stack - * block SIGVTALRM in any code that's under wait_for_stop - */ - -#include +#include #include -#include -#include -#include -#include -#include "sysdep/ptrace.h" -#include "sigcontext.h" -#include "ptrace_user.h" -#include "task.h" -#include "user_util.h" #include "kern_util.h" - -/* XXX Bogus */ -#define ERESTARTSYS 512 -#define ERESTARTNOINTR 513 -#define ERESTARTNOHAND 514 +#include "syscall_user.h" struct { int syscall; @@ -34,67 +16,24 @@ struct { struct timeval end; } syscall_record[1024]; -void syscall_handler(int sig, struct uml_pt_regs *regs) +int record_syscall_start(int syscall) { - void *sc; - long result; - int index, max, syscall; - + int max, index; + max = sizeof(syscall_record)/sizeof(syscall_record[0]); index = next_syscall_index(max); - syscall = regs->syscall; - sc = regs->sc; - sc_to_regs(regs, sc, syscall); - SC_START_SYSCALL(sc); - syscall_record[index].syscall = syscall; syscall_record[index].pid = current_pid(); syscall_record[index].result = 0xdeadbeef; gettimeofday(&syscall_record[index].start, NULL); - syscall_trace(); - result = execute_syscall(regs); - - /* regs->sc may have changed while the system call ran (there may - * have been an interrupt or segfault), so it needs to be refreshed. - */ - regs->sc = sc; - - SC_SET_SYSCALL_RETURN(sc, result); - if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || - (result == -ERESTARTNOINTR)) - do_signal(result); - - syscall_trace(); - syscall_record[index].result = result; - gettimeofday(&syscall_record[index].end, NULL); + return(index); } -int do_syscall(void *task, int pid) +void record_syscall_end(int index, int result) { - unsigned long proc_regs[FRAME_SIZE]; - struct uml_pt_regs *regs; - int syscall; - - if(ptrace_getregs(pid, proc_regs) < 0) - tracer_panic("Couldn't read registers"); - syscall = PT_SYSCALL_NR(proc_regs); - - regs = TASK_REGS(task); - UPT_SYSCALL_NR(regs) = syscall; - - if(syscall < 1) return(0); - - if((syscall != __NR_sigreturn) && - ((unsigned long *) PT_IP(proc_regs) >= &_stext) && - ((unsigned long *) PT_IP(proc_regs) <= &_etext)) - tracer_panic("I'm tracing myself and I can't get out"); - - if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, - __NR_getpid) < 0) - tracer_panic("do_syscall : Nullifying syscall failed, " - "errno = %d", errno); - return(1); + syscall_record[index].result = result; + gettimeofday(&syscall_record[index].end, NULL); } /* diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index f5e8458ff866..000a26862ec5 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -30,8 +30,8 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, unsigned long addr; int r, w, x, err; - if((current->thread.extern_pid != -1) && - (current->thread.extern_pid != os_getpid())) + if((current->thread.mode.tt.extern_pid != -1) && + (current->thread.mode.tt.extern_pid != os_getpid())) panic("fix_range fixing wrong address space, current = 0x%p", current); if(mm == NULL) return; @@ -60,23 +60,25 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, w = 0; } if(force || pte_newpage(*npte)){ - err = unmap((void *) addr, PAGE_SIZE); + err = os_unmap_memory((void *) addr, + PAGE_SIZE); if(err < 0) panic("munmap failed, errno = %d\n", -err); if(pte_present(*npte)) - map(addr, pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x); + map_memory(addr, + pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x); } else if(pte_newprot(*npte)){ - protect(addr, PAGE_SIZE, r, w, x, 1); + protect_memory(addr, PAGE_SIZE, r, w, x, 1); } *npte = pte_mkuptodate(*npte); addr += PAGE_SIZE; } else { if(force || pmd_newpage(*npmd)){ - err = unmap((void *) addr, PMD_SIZE); + err = os_unmap_memory((void *) addr, PMD_SIZE); if(err < 0) panic("munmap failed, errno = %d\n", -err); @@ -106,24 +108,26 @@ void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) pte = pte_offset_kernel(pmd, addr); if(!pte_present(*pte) || pte_newpage(*pte)){ updated = 1; - err = unmap((void *) addr, PAGE_SIZE); + err = os_unmap_memory((void *) addr, + PAGE_SIZE); if(err < 0) panic("munmap failed, errno = %d\n", -err); if(pte_present(*pte)) - map(addr, pte_val(*pte) & PAGE_MASK, - PAGE_SIZE, 1, 1, 1); + map_memory(addr, + pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, 1, 1, 1); } else if(pte_newprot(*pte)){ updated = 1; - protect(addr, PAGE_SIZE, 1, 1, 1, 1); + protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); } addr += PAGE_SIZE; } else { if(pmd_newpage(*pmd)){ updated = 1; - err = unmap((void *) addr, PMD_SIZE); + err = os_unmap_memory((void *) addr, PMD_SIZE); if(err < 0) panic("munmap failed, errno = %d\n", -err); @@ -143,7 +147,7 @@ static void protect_vm_page(unsigned long addr, int w, int must_succeed) { int err; - err = protect(addr, PAGE_SIZE, 1, w, 1, must_succeed); + err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed); if(err == 0) return; else if((err == -EFAULT) || (err == -ENOMEM)){ flush_tlb_kernel_range(addr, addr + PAGE_SIZE); @@ -207,8 +211,8 @@ void flush_tlb_mm(struct mm_struct *mm) fix_range(mm, 0, STACK_TOP, 0); seq = atomic_read(&vmchange_seq); - if(current->thread.vm_seq == seq) return; - current->thread.vm_seq = seq; + if(current->thread.mode.tt.vm_seq == seq) return; + current->thread.mode.tt.vm_seq = seq; flush_kernel_range(start_vm, end_vm, 0); } diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 33bfc04fc5d0..5a9ed1c89478 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -117,7 +117,7 @@ out_of_memory: if(catcher != NULL){ current->thread.fault_addr = (void *) address; up_read(&mm->mmap_sem); - do_longjmp(catcher); + do_longjmp(catcher, 1); } else if(current->thread.fault_addr != NULL){ panic("fault_addr set but no fault catcher"); @@ -161,7 +161,7 @@ void relay_signal(int sig, struct uml_pt_regs *regs) void bus_handler(int sig, struct uml_pt_regs *regs) { if(current->thread.fault_catcher != NULL) - do_longjmp(current->thread.fault_catcher); + do_longjmp(current->thread.fault_catcher, 1); else relay_signal(sig, regs); } @@ -185,250 +185,6 @@ int next_trap_index(int limit) return(ret); } -extern int debugger_pid; -extern int debugger_fd; -extern int debugger_parent; - -#ifdef CONFIG_PT_PROXY - -int debugger_signal(int status, pid_t pid) -{ - return(debugger_proxy(status, pid)); -} - -void child_signal(pid_t pid, int status) -{ - child_proxy(pid, status); -} - -static void gdb_announce(char *dev_name, int dev) -{ - printf("gdb assigned device '%s'\n", dev_name); -} - -static struct chan_opts opts = { - announce : gdb_announce, - xterm_title : "UML kernel debugger", - raw : 0, - tramp_stack : 0, - in_kernel : 0, -}; - -/* Accessed by the tracing thread, which automatically serializes access */ -static void *xterm_data; -static int xterm_fd; - -extern void *xterm_init(char *, int, struct chan_opts *); -extern int xterm_open(int, int, int, void *); -extern void xterm_close(int, void *); - -int open_gdb_chan(void) -{ - char stack[PAGE_SIZE]; - - opts.tramp_stack = (unsigned long) stack; - xterm_data = xterm_init("", 0, &opts); - xterm_fd = xterm_open(1, 1, 1, xterm_data); - return(xterm_fd); -} - -static void exit_debugger_cb(void *unused) -{ - if(debugger_pid != -1){ - if(gdb_pid != -1){ - fake_child_exit(); - gdb_pid = -1; - } - else kill_child_dead(debugger_pid); - debugger_pid = -1; - if(debugger_parent != -1) - detach(debugger_parent, SIGINT); - } - if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data); -} - -static void exit_debugger(void) -{ - tracing_cb(exit_debugger_cb, NULL); -} - -__uml_exitcall(exit_debugger); - -struct gdb_data { - char *str; - int err; -}; - -static void config_gdb_cb(void *arg) -{ - struct gdb_data *data = arg; - struct task_struct *task; - int pid; - - data->err = -1; - if(debugger_pid != -1) exit_debugger_cb(NULL); - if(!strncmp(data->str, "pid,", strlen("pid,"))){ - data->str += strlen("pid,"); - pid = simple_strtoul(data->str, NULL, 0); - task = cpu_tasks[0].task; - debugger_pid = attach_debugger(task->thread.extern_pid, - pid, 0); - if(debugger_pid != -1){ - data->err = 0; - gdb_pid = pid; - } - return; - } - data->err = 0; - debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); - init_proxy(debugger_pid, 0, 0); -} - -int gdb_config(char *str) -{ - struct gdb_data data; - - if(*str++ != '=') return(-1); - data.str = str; - tracing_cb(config_gdb_cb, &data); - return(data.err); -} - -void remove_gdb_cb(void *unused) -{ - exit_debugger_cb(NULL); -} - -int gdb_remove(char *unused) -{ - tracing_cb(remove_gdb_cb, NULL); - return(0); -} - -#ifdef CONFIG_MCONSOLE - -static struct mc_device gdb_mc = { - name: "gdb", - config: gdb_config, - remove: gdb_remove, -}; - -int gdb_mc_init(void) -{ - mconsole_register_dev(&gdb_mc); - return(0); -} - -__initcall(gdb_mc_init); - -#endif - -void signal_usr1(int sig) -{ - if(debugger_pid != -1){ - printk(KERN_ERR "The debugger is already running\n"); - return; - } - debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); - init_proxy(debugger_pid, 0, 0); -} - -int init_ptrace_proxy(int idle_pid, int startup, int stop) -{ - int pid, status; - - pid = start_debugger(linux_prog, startup, stop, &debugger_fd); - status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); - if(pid < 0){ - cont(idle_pid); - return(-1); - } - init_proxy(pid, 1, status); - return(pid); -} - -int attach_debugger(int idle_pid, int pid, int stop) -{ - int status = 0, err; - - err = attach(pid); - if(err < 0){ - printf("Failed to attach pid %d, errno = %d\n", pid, -err); - return(-1); - } - if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); - init_proxy(pid, 1, status); - return(pid); -} - -#ifdef notdef /* Put this back in when it does something useful */ -static int __init uml_gdb_init_setup(char *line, int *add) -{ - gdb_init = uml_strdup(line); - return 0; -} - -__uml_setup("gdb=", uml_gdb_init_setup, -"gdb=\n\n" -); -#endif - -static int __init uml_gdb_pid_setup(char *line, int *add) -{ - gdb_pid = simple_strtoul(line, NULL, 0); - *add = 0; - return 0; -} - -__uml_setup("gdb-pid=", uml_gdb_pid_setup, -"gdb-pid=\n" -" gdb-pid is used to attach an external debugger to UML. This may be\n" -" an already-running gdb or a debugger-like process like strace.\n\n" -); - -#else - -int debugger_signal(int status, pid_t pid){ return(0); } -void child_signal(pid_t pid, int status){ } -int init_ptrace_proxy(int idle_pid, int startup, int stop) -{ - printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); - kill_child_dead(idle_pid); - exit(1); -} - -void signal_usr1(int sig) -{ - printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); -} - -int attach_debugger(int idle_pid, int pid, int stop) -{ - printk(KERN_ERR "attach_debugger called when CONFIG_PT_PROXY " - "is off\n"); - return(-1); -} - -int config_gdb(char *str) -{ - return(-1); -} - -int remove_gdb(void) -{ - return(-1); -} - -int init_parent_proxy(int pid) -{ - return(-1); -} - -void debugger_parent_signal(int status, int pid) -{ -} - -#endif /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 8971a61c8310..38872e7a288b 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -3,66 +3,33 @@ * Licensed under the GPL */ -#include #include -#include -#include #include -#include #include #include -#include -#include +#include #include -#include -#include #include +#include +#include #include #include #include -#include "user_util.h" -#include "kern_util.h" -#include "signal_user.h" -#include "mem_user.h" -#include "user.h" -#include "process.h" +#include "init.h" +#include "sysdep/ptrace.h" #include "sigcontext.h" #include "sysdep/sigcontext.h" -#include "init.h" -#include "chan_user.h" #include "irq_user.h" #include "frame_user.h" -#include "syscall_user.h" -#include "ptrace_user.h" +#include "signal_user.h" #include "time_user.h" #include "task.h" +#include "mode.h" +#include "choose-mode.h" +#include "kern_util.h" +#include "user_util.h" #include "os.h" -static void signal_segv(int sig) -{ - write(2, "Seg fault in signals\n", strlen("Seg fault in signals\n")); - for(;;) ; -} - -int detach(int pid, int sig) -{ - return(ptrace(PTRACE_DETACH, pid, 0, sig)); -} - -int attach(int pid) -{ - int err; - - err = ptrace(PTRACE_ATTACH, pid, 0, 0); - if(err < 0) return(-errno); - else return(err); -} - -int cont(int pid) -{ - return(ptrace(PTRACE_CONT, pid, 0, 0)); -} - void kill_child_dead(int pid) { kill(pid, SIGKILL); @@ -70,336 +37,6 @@ void kill_child_dead(int pid) while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT); } -/* Changed early in boot, and then only read */ -int debug = 0; -int debug_stop = 1; -int debug_parent = 0; -int honeypot = 0; - -static int signal_tramp(void *arg) -{ - int (*proc)(void *); - - if(honeypot && munmap((void *) (host_task_size - 0x10000000), - 0x10000000)) - panic("Unmapping stack failed"); - if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) - panic("ptrace PTRACE_TRACEME failed"); - os_stop_process(os_getpid()); - change_sig(SIGWINCH, 0); - signal(SIGUSR1, SIG_IGN); - change_sig(SIGCHLD, 0); - signal(SIGSEGV, (__sighandler_t) sig_handler); - set_cmdline("(idle thread)"); - set_init_pid(os_getpid()); - proc = arg; - return((*proc)(NULL)); -} - -static void last_ditch_exit(int sig) -{ - kmalloc_ok = 0; - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); - uml_cleanup(); - exit(1); -} - -static void sleeping_process_signal(int pid, int sig) -{ - switch(sig){ - /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is - * right because the process must be in the kernel already. - */ - case SIGCONT: - case SIGTSTP: - if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) - tracer_panic("sleeping_process_signal : Failed to " - "continue pid %d, errno = %d\n", pid, - sig); - break; - - /* This happens when the debugger (e.g. strace) is doing system call - * tracing on the kernel. During a context switch, the current task - * will be set to the incoming process and the outgoing process will - * hop into write and then read. Since it's not the current process - * any more, the trace of those will land here. So, we need to just - * PTRACE_SYSCALL it. - */ - case SIGTRAP: - if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) - tracer_panic("sleeping_process_signal : Failed to " - "PTRACE_SYSCALL pid %d, errno = %d\n", - pid, sig); - break; - case SIGSTOP: - break; - default: - tracer_panic("sleeping process %d got unexpected " - "signal : %d\n", pid, sig); - break; - } -} - -/* Accessed only by the tracing thread */ -int debugger_pid = -1; -int debugger_parent = -1; -int debugger_fd = -1; -int gdb_pid = -1; - -struct { - int pid; - int signal; - unsigned long addr; - struct timeval time; -} signal_record[1024][32]; - -int signal_index[32]; -int nsignals = 0; -int debug_trace = 0; -extern int io_nsignals, io_count, intr_count; - -extern void signal_usr1(int sig); - -int tracing_pid = -1; - -int signals(int (*init_proc)(void *), void *sp) -{ - void *task = NULL; - unsigned long eip = 0; - int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; - int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0; - - capture_signal_stack(); - signal(SIGPIPE, SIG_IGN); - setup_tracer_winch(); - tracing_pid = os_getpid(); - printf("tracing thread pid = %d\n", tracing_pid); - - pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); - n = waitpid(pid, &status, WUNTRACED); - if(n < 0){ - printf("waitpid on idle thread failed, errno = %d\n", errno); - exit(1); - } - if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ - printf("Failed to continue idle thread, errno = %d\n", errno); - exit(1); - } - - signal(SIGSEGV, signal_segv); - signal(SIGUSR1, signal_usr1); - 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); - if(debug_trace){ - printf("Tracing thread pausing to be attached\n"); - stop(); - } - if(debug){ - if(gdb_pid != -1) - debugger_pid = attach_debugger(pid, gdb_pid, 1); - else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); - if(debug_parent){ - debugger_parent = os_process_parent(debugger_pid); - init_parent_proxy(debugger_parent); - err = attach(debugger_parent); - if(err){ - printf("Failed to attach debugger parent %d, " - "errno = %d\n", debugger_parent, err); - debugger_parent = -1; - } - else { - if(ptrace(PTRACE_SYSCALL, debugger_parent, - 0, 0) < 0){ - printf("Failed to continue debugger " - "parent, errno = %d\n", errno); - debugger_parent = -1; - } - } - } - } - set_cmdline("(tracing thread)"); - while(1){ - if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){ - if(errno != ECHILD){ - printf("wait failed - errno = %d\n", errno); - } - continue; - } - if(pid == debugger_pid){ - int cont = 0; - - if(WIFEXITED(status) || WIFSIGNALED(status)) - debugger_pid = -1; - /* XXX Figure out how to deal with gdb and SMP */ - else cont = debugger_signal(status, cpu_tasks[0].pid); - if(cont == PTRACE_SYSCALL) strace = 1; - continue; - } - else if(pid == debugger_parent){ - debugger_parent_signal(status, pid); - continue; - } - nsignals++; - if(WIFEXITED(status)) ; -#ifdef notdef - { - printf("Child %d exited with status %d\n", pid, - WEXITSTATUS(status)); - } -#endif - else if(WIFSIGNALED(status)){ - sig = WTERMSIG(status); - if(sig != 9){ - printf("Child %d exited with signal %d\n", pid, - sig); - } - } - else if(WIFSTOPPED(status)){ - proc_id = pid_to_processor_id(pid); - sig = WSTOPSIG(status); - 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_PEEKUSER, 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; - - if(proc_id == -1){ - sleeping_process_signal(pid, sig); - continue; - } - - task = cpu_tasks[proc_id].task; - tracing = is_tracing(task); - old_tracing = tracing; - - switch(sig){ - case SIGUSR1: - sig = 0; - op = do_proc_op(task, proc_id); - switch(op){ - case OP_TRACE_ON: - arch_leave_kernel(task, pid); - tracing = 1; - break; - case OP_REBOOT: - case OP_HALT: - unmap_physmem(); - kmalloc_ok = 0; - ptrace(PTRACE_KILL, pid, 0, 0); - return(op == OP_REBOOT); - case OP_NONE: - printf("Detaching pid %d\n", pid); - detach(pid, SIGSTOP); - continue; - default: - break; - } - /* OP_EXEC switches host processes on us, - * we want to continue the new one. - */ - pid = cpu_tasks[proc_id].pid; - break; - case SIGTRAP: - if(!tracing && (debugger_pid != -1)){ - child_signal(pid, status); - continue; - } - tracing = 0; - if(do_syscall(task, pid)) sig = SIGUSR2; - else clear_singlestep(task); - break; - case SIGPROF: - if(tracing) sig = 0; - break; - case SIGCHLD: - case SIGHUP: - sig = 0; - break; - case SIGSEGV: - case SIGIO: - case SIGALRM: - case SIGVTALRM: - case SIGFPE: - case SIGBUS: - case SIGILL: - case SIGWINCH: - default: - tracing = 0; - break; - } - set_tracing(task, tracing); - - if(!tracing && old_tracing) - arch_enter_kernel(task, pid); - - if(!tracing && (debugger_pid != -1) && (sig != 0) && - (sig != SIGALRM) && (sig != SIGVTALRM) && - (sig != SIGSEGV) && (sig != SIGTRAP) && - (sig != SIGUSR2) && (sig != SIGIO)){ - child_signal(pid, status); - continue; - } - - if(tracing){ - if(singlestepping(task)) - cont_type = PTRACE_SINGLESTEP; - else cont_type = PTRACE_SYSCALL; - } - else cont_type = PTRACE_CONT; - - if((cont_type == PTRACE_CONT) && - (debugger_pid != -1) && strace) - cont_type = PTRACE_SYSCALL; - - if(ptrace(cont_type, pid, 0, sig) != 0){ - tracer_panic("ptrace failed to continue " - "process - errno = %d\n", - errno); - } - } - } - return(0); -} - -static int __init uml_debugtrace_setup(char *line, int *add) -{ - debug_trace = 1; - return 0; -} -__uml_setup("debugtrace", uml_debugtrace_setup, -"debugtrace\n" -" Causes the tracing thread to pause until it is attached by a\n" -" debugger and continued. This is mostly for debugging crashes\n" -" early during boot, and should be pretty much obsoleted by\n" -" the debug switch.\n\n" -); - -static int __init uml_honeypot_setup(char *line, int *add) -{ - jail_setup("", add); - honeypot = 1; - return 0; -} -__uml_setup("honeypot", uml_honeypot_setup, -"honeypot\n" -" This makes UML put process stacks in the same location as they are\n" -" on the host, allowing expoits such as stack smashes to work against\n" -" UML. This implies 'jail'.\n\n" -); - /* Unlocked - don't care if this is a bit off */ int nsegfaults = 0; @@ -413,33 +50,32 @@ struct { void segv_handler(int sig, struct uml_pt_regs *regs) { - struct sigcontext *context = regs->sc; int index, max; - if(regs->is_user && !SEGV_IS_FIXABLE(context)){ - bad_segv(SC_FAULT_ADDR(context), SC_IP(context), - SC_FAULT_WRITE(context)); + if(regs->is_user && !UPT_SEGV_IS_FIXABLE(regs)){ + bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), + UPT_FAULT_WRITE(regs)); return; } max = sizeof(segfault_record)/sizeof(segfault_record[0]); index = next_trap_index(max); nsegfaults++; - segfault_record[index].address = SC_FAULT_ADDR(context); + segfault_record[index].address = UPT_FAULT_ADDR(regs); segfault_record[index].pid = os_getpid(); - segfault_record[index].is_write = SC_FAULT_WRITE(context); - segfault_record[index].sp = SC_SP(context); + segfault_record[index].is_write = UPT_FAULT_WRITE(regs); + segfault_record[index].sp = UPT_SP(regs); segfault_record[index].is_user = regs->is_user; - segv(SC_FAULT_ADDR(context), SC_IP(context), SC_FAULT_WRITE(context), - regs->is_user, context); + segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs), + regs->is_user, regs); } -struct signal_info { - void (*handler)(int, struct uml_pt_regs *); - int is_irq; -}; - -static struct signal_info sig_info[] = { +void usr2_handler(int sig, struct uml_pt_regs *regs) +{ + CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); +} + +struct signal_info sig_info[] = { [ SIGTRAP ] { handler : relay_signal, is_irq : 0 }, [ SIGFPE ] { handler : relay_signal, @@ -454,9 +90,9 @@ static struct signal_info sig_info[] = { is_irq : 1 }, [ SIGVTALRM ] { handler : timer_handler, is_irq : 1 }, - [ SIGALRM ] { handler : timer_handler, - is_irq : 1 }, - [ SIGUSR2 ] { handler : syscall_handler, + [ SIGALRM ] { handler : timer_handler, + is_irq : 1 }, + [ SIGUSR2 ] { handler : usr2_handler, is_irq : 0 }, }; @@ -472,7 +108,7 @@ void sig_handler_common(int sig, struct sigcontext *sc) save_regs = *r; is_user = user_context(SC_SP(sc)); r->is_user = is_user; - r->sc = sc; + r->mode.tt = sc; if(sig != SIGUSR2) r->syscall = -1; change_sig(SIGUSR1, 1); @@ -516,42 +152,13 @@ void alarm_handler(int sig, struct sigcontext sc) switch_timers(1); } -void do_longjmp(void *p) +void do_longjmp(void *p, int val) { jmp_buf *jbuf = (jmp_buf *) p; - longjmp(*jbuf, 1); -} - -static int __init uml_debug_setup(char *line, int *add) -{ - char *next; - - debug = 1; - *add = 0; - if(*line != '=') return(0); - line++; - - while(line != NULL){ - next = strchr(line, ','); - if(next) *next++ = '\0'; - - if(!strcmp(line, "go")) debug_stop = 0; - else if(!strcmp(line, "parent")) debug_parent = 1; - else printk("Unknown debug option : '%s'\n", line); - - line = next; - } - return(0); + longjmp(*jbuf, val); } -__uml_setup("debug", uml_debug_setup, -"debug\n" -" Starts up the kernel under the control of gdb. See the \n" -" kernel debugging tutorial and the debugging session pages\n" -" at http://user-mode-linux.sourceforge.net/ for more information.\n\n" -); - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 224f15c7ba54..8b0dd44a11c6 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -3,11 +3,17 @@ # Licensed under the GPL # -O_TARGET = tt.o - -obj-y = exec_kern.o exec_user.o +obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o mem.o process_kern.o \ + syscall_user.o tracer.o obj-$(CONFIG_PT_PROXY) += ptproxy/ +USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o tracer.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + include $(TOPDIR)/Rules.make +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +clean : diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index b928324d7096..dd52d8751c5c 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -46,17 +46,17 @@ void flush_thread_tt(void) do_exit(SIGKILL); } - if(current->processor == 0) + if(current->thread_info->cpu == 0) forward_interrupts(new_pid); current->thread.request.op = OP_EXEC; current->thread.request.u.exec.pid = new_pid; - unprotect_stack((unsigned long) current); + unprotect_stack((unsigned long) current->thread_info); os_usr1_process(os_getpid()); enable_timer(); free_page(stack); protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current); + task_protections((unsigned long) current->thread_info); force_flush_all(); unblock_signals(); } diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c new file mode 100644 index 000000000000..2b4320c1480c --- /dev/null +++ b/arch/um/kernel/tt/gdb_kern.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/init.h" +#include "linux/config.h" +#include "mconsole_kern.h" + +#ifdef CONFIG_MCONSOLE + +extern int gdb_config(char *str); +extern int gdb_remove(char *unused); + +static struct mc_device gdb_mc = { + name: "gdb", + config: gdb_config, + remove: gdb_remove, +}; + +int gdb_mc_init(void) +{ + mconsole_register_dev(&gdb_mc); + return(0); +} + +__initcall(gdb_mc_init); + +#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/kernel/tt/include/mode_kern.h b/arch/um/kernel/tt/include/mode_kern.h new file mode 100644 index 000000000000..7482e345f1c9 --- /dev/null +++ b/arch/um/kernel/tt/include/mode_kern.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TT_MODE_KERN_H__ +#define __TT_MODE_KERN_H__ + +#include "linux/sched.h" +#include "asm/page.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" + +extern void *switch_to_tt(void *prev, void *next); +extern void flush_thread_tt(void); +extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, + unsigned long esp); +extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long stack_top, struct task_struct *p, + struct pt_regs *regs); +extern void release_thread_tt(struct task_struct *task); +extern void exit_thread_tt(void); +extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); +extern void init_idle_tt(void); +extern void flush_tlb_kernel_vm_tt(void); +extern void __flush_tlb_one_tt(unsigned long addr); +extern void flush_tlb_range_tt(struct mm_struct *mm, unsigned long start, + unsigned long end); +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 int start_uml_tt(void); +extern struct page *arch_validate_tt(struct page *page, int mask, int order); +extern int external_pid_tt(struct task_struct *task); +extern int thread_pid_tt(struct thread_struct *thread); + +#define kmem_end_tt (host_task_size - ABOVE_KMEM) + +#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/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c new file mode 100644 index 000000000000..ff92e59bd86b --- /dev/null +++ b/arch/um/kernel/tt/mem.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/config.h" +#include "linux/mm.h" +#include "asm/uaccess.h" +#include "mem_user.h" +#include "kern_util.h" +#include "user_util.h" +#include "kern.h" +#include "tt.h" + +void before_mem_tt(unsigned long brk_start) +{ + if(!jail || debug) + remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1); + remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1); + remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(brk_start), 1); +} + +#ifdef CONFIG_HOST_2G_2G +#define TOP 0x80000000 +#else +#define TOP 0xc0000000 +#endif + +#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) +#define START (TOP - SIZE) + +unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, + unsigned long *task_size_out) +{ + /* Round up to the nearest 4M */ + *host_size_out = ROUND_4M((unsigned long) &arg); + *task_size_out = START; + return(START); +} + +struct page *arch_validate_tt(struct page *page, int mask, int order) +{ + unsigned long addr, zero = 0; + int i; + + again: + if(page == NULL) return(page); + if(PageHighMem(page)) return(page); + + addr = (unsigned long) page_address(page); + for(i = 0; i < (1 << order); i++){ + current->thread.fault_addr = (void *) addr; + if(__do_copy_to_user((void *) addr, &zero, + sizeof(zero), + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)){ + if(!(mask & __GFP_WAIT)) return(NULL); + else break; + } + addr += PAGE_SIZE; + } + if(i == (1 << order)) return(page); + page = alloc_pages(mask, order); + goto again; +} + +/* + * 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/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c new file mode 100644 index 000000000000..db9cfc294bb7 --- /dev/null +++ b/arch/um/kernel/tt/process_kern.c @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/signal.h" +#include "linux/kernel.h" +#include "asm/system.h" +#include "asm/pgalloc.h" +#include "asm/ptrace.h" +#include "irq_user.h" +#include "signal_user.h" +#include "kern_util.h" +#include "user_util.h" +#include "os.h" +#include "kern.h" +#include "sigcontext.h" +#include "time_user.h" +#include "mem_user.h" +#include "tlb.h" +#include "mode.h" +#include "init.h" +#include "tt.h" + +extern void start_kernel(void); + +static int start_kernel_proc(void *unused) +{ + int pid; + + block_signals(); + pid = os_getpid(); + + cpu_tasks[0].pid = pid; + cpu_tasks[0].task = current; +#ifdef CONFIG_SMP + cpu_online_map = 1; +#endif + if(debug) os_stop_process(pid); + start_kernel(); + return(0); +} + +void *switch_to_tt(void *prev, void *next, void *last) +{ + struct task_struct *from, *to; + unsigned long flags; + int vtalrm, alrm, prof, err, cpu; + char c; + /* jailing and SMP are incompatible, so this doesn't need to be + * made per-cpu + */ + static int reading; + + from = prev; + to = next; + + to->thread.prev_sched = from; + + cpu = from->thread_info->cpu; + if(cpu == 0) + forward_interrupts(to->thread.mode.tt.extern_pid); +#ifdef CONFIG_SMP + forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid); +#endif + local_irq_save(flags); + + vtalrm = change_sig(SIGVTALRM, 0); + alrm = change_sig(SIGALRM, 0); + prof = change_sig(SIGPROF, 0); + + forward_pending_sigio(to->thread.mode.tt.extern_pid); + + c = 0; + set_current(to); + + reading = 0; + err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); + if(err != sizeof(c)) + panic("write of switch_pipe failed, errno = %d", -err); + + reading = 1; + if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) + os_kill_process(os_getpid(), 0); + + err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); + if(err != sizeof(c)) + panic("read of switch_pipe failed, errno = %d", -err); + + /* This works around a nasty race with 'jail'. If we are switching + * between two threads of a threaded app and the incoming process + * runs before the outgoing process reaches the read, and it makes + * it all the way out to userspace, then it will have write-protected + * the outgoing process stack. Then, when the outgoing process + * returns from the write, it will segfault because it can no longer + * write its own stack. So, in order to avoid that, the incoming + * thread sits in a loop yielding until 'reading' is set. This + * isn't entirely safe, since there may be a reschedule from a timer + * happening between setting 'reading' and sleeping in read. But, + * it should get a whole quantum in which to reach the read and sleep, + * which should be enough. + */ + + if(jail){ + while(!reading) sched_yield(); + } + + change_sig(SIGVTALRM, vtalrm); + change_sig(SIGALRM, alrm); + change_sig(SIGPROF, prof); + + arch_switch(); + + flush_tlb_all(); + local_irq_restore(flags); + + return(current->thread.prev_sched); +} + +void release_thread_tt(struct task_struct *task) +{ + os_kill_process(task->thread.mode.tt.extern_pid, 0); +} + +void exit_thread_tt(void) +{ + close(current->thread.mode.tt.switch_pipe[0]); + close(current->thread.mode.tt.switch_pipe[1]); +} + +void reboot_tt(void) +{ + current->thread.request.op = OP_REBOOT; + os_usr1_process(os_getpid()); +} + +void halt_tt(void) +{ + current->thread.request.op = OP_HALT; + os_usr1_process(os_getpid()); +} + +extern void schedule_tail(struct task_struct *prev); + +static void new_thread_handler(int sig) +{ + int (*fn)(void *); + void *arg; + + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + current->thread.regs.regs.mode.tt = (void *) (&sig + 1); + suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); + + block_signals(); + init_new_thread_signals(1); +#ifdef CONFIG_SMP + schedule_tail(NULL); +#endif + enable_timer(); + free_page(current->thread.temp_stack); + set_cmdline("(kernel thread)"); + force_flush_all(); + + current->thread.prev_sched = NULL; + change_sig(SIGUSR1, 1); + change_sig(SIGVTALRM, 1); + change_sig(SIGPROF, 1); + unblock_signals(); + if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) + do_exit(0); +} + +static int new_thread_proc(void *stack) +{ + init_new_thread_stack(stack, new_thread_handler); + os_usr1_process(os_getpid()); + return(0); +} + +/* Signal masking - signals are blocked at the start of fork_tramp. They + * are re-enabled when finish_fork_handler is entered by fork_tramp hitting + * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, + * so it is blocked before it's called. They are re-enabled on sigreturn + * despite the fact that they were blocked when the SIGUSR1 was issued because + * copy_thread copies the parent's signcontext, including the signal mask + * onto the signal frame. + */ + +void finish_fork_handler(int sig) +{ + current->thread.regs.regs.mode.tt = (void *) (&sig + 1); + suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); + +#ifdef CONFIG_SMP + schedule_tail(NULL); +#endif + enable_timer(); + change_sig(SIGVTALRM, 1); + force_flush_all(); + if(current->mm != current->parent->mm) + protect_memory(uml_reserved, high_physmem - uml_reserved, 1, + 1, 0, 1); + task_protections((unsigned long) current->thread_info); + + current->thread.prev_sched = NULL; + + free_page(current->thread.temp_stack); + change_sig(SIGUSR1, 0); + set_user_mode(current); +} + +static int sigusr1 = SIGUSR1; + +int fork_tramp(void *stack) +{ + int sig = sigusr1; + + init_new_thread_stack(stack, finish_fork_handler); + + kill(os_getpid(), sig); + return(0); +} + +int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long stack_top, struct task_struct * p, + struct pt_regs *regs) +{ + int (*tramp)(void *); + int new_pid, err; + unsigned long stack; + + if(current->thread.forking) + tramp = fork_tramp; + else { + tramp = new_thread_proc; + p->thread.request.u.thread = current->thread.request.u.thread; + } + + err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1); + if(err){ + printk("copy_thread : pipe failed, errno = %d\n", -err); + return(err); + } + + stack = alloc_stack(0, 0); + if(stack == 0){ + printk(KERN_ERR "copy_thread : failed to allocate " + "temporary stack\n"); + return(-ENOMEM); + } + + clone_flags &= CLONE_VM; + p->thread.temp_stack = stack; + new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack, + clone_flags, tramp); + if(new_pid < 0){ + printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", + -new_pid); + return(new_pid); + } + + if(current->thread.forking){ + sc_to_sc(p->thread.regs.regs.mode.tt, + current->thread.regs.regs.mode.tt); + SC_SET_SYSCALL_RETURN(p->thread.regs.regs.mode.tt, 0); + if(sp != 0) SC_SP(p->thread.regs.regs.mode.tt) = sp; + } + p->thread.mode.tt.extern_pid = new_pid; + + current->thread.request.op = OP_FORK; + current->thread.request.u.fork.pid = new_pid; + os_usr1_process(os_getpid()); + return(0); +} + +void initial_thread_cb_tt(void (*proc)(void *), void *arg) +{ + if(os_getpid() == tracing_pid){ + (*proc)(arg); + } + else { + current->thread.request.op = OP_CB; + current->thread.request.u.cb.proc = proc; + current->thread.request.u.cb.arg = arg; + os_usr1_process(os_getpid()); + } +} + +int do_proc_op(void *t, int proc_id) +{ + struct task_struct *task; + struct thread_struct *thread; + int op, pid; + + task = t; + thread = &task->thread; + op = thread->request.op; + switch(op){ + case OP_NONE: + case OP_TRACE_ON: + break; + case OP_EXEC: + pid = thread->request.u.exec.pid; + do_exec(thread->mode.tt.extern_pid, pid); + thread->mode.tt.extern_pid = pid; + cpu_tasks[task->thread_info->cpu].pid = pid; + break; + case OP_FORK: + attach_process(thread->request.u.fork.pid); + break; + case OP_CB: + (*thread->request.u.cb.proc)(thread->request.u.cb.arg); + break; + case OP_REBOOT: + case OP_HALT: + break; + default: + tracer_panic("Bad op in do_proc_op"); + break; + } + thread->request.op = OP_NONE; + return(op); +} + +void init_idle_tt(void) +{ + default_idle(); +} + +/* Changed by jail_setup, which is a setup */ +int jail = 0; + +int __init jail_setup(char *line, int *add) +{ + int ok = 1; + + if(jail) return(0); +#ifdef CONFIG_SMP + printf("'jail' may not used used in a kernel with CONFIG_SMP " + "enabled\n"); + ok = 0; +#endif +#ifdef CONFIG_HOSTFS + printf("'jail' may not used used in a kernel with CONFIG_HOSTFS " + "enabled\n"); + ok = 0; +#endif +#ifdef CONFIG_MODULES + printf("'jail' may not used used in a kernel with CONFIG_MODULES " + "enabled\n"); + ok = 0; +#endif + if(!ok) exit(1); + + /* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem. + * Removing it from the bounding set eliminates the ability of anything + * to acquire it, and thus read or write kernel memory. + */ + cap_lower(cap_bset, CAP_SYS_RAWIO); + jail = 1; + return(0); +} + +__uml_setup("jail", jail_setup, +"jail\n" +" Enables the protection of kernel memory from processes.\n\n" +); + +static void mprotect_kernel_mem(int w) +{ + unsigned long start, end; + + if(!jail || (current == &init_task)) return; + + start = (unsigned long) current->thread_info + PAGE_SIZE; + end = (unsigned long) current->thread_info + PAGE_SIZE * 4; + protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1); + protect_memory(end, high_physmem - end, 1, w, 1, 1); + + start = (unsigned long) UML_ROUND_DOWN(&_stext); + end = (unsigned long) UML_ROUND_UP(&_etext); + protect_memory(start, end - start, 1, w, 1, 1); + + start = (unsigned long) UML_ROUND_DOWN(&_unprotected_end); + end = (unsigned long) UML_ROUND_UP(&_edata); + protect_memory(start, end - start, 1, w, 1, 1); + + start = (unsigned long) UML_ROUND_DOWN(&__bss_start); + end = (unsigned long) UML_ROUND_UP(brk_start); + protect_memory(start, end - start, 1, w, 1, 1); + + mprotect_kernel_vm(w); +} + +/* No SMP problems since jailing and SMP are incompatible */ +void unprotect_kernel_mem(void) +{ + mprotect_kernel_mem(1); +} + +void protect_kernel_mem(void) +{ + mprotect_kernel_mem(0); +} + +void kill_off_processes_tt(void) +{ + struct task_struct *p; + int me; + + me = os_getpid(); + for_each_process(p){ + if(p->thread.mode.tt.extern_pid != me) + os_kill_process(p->thread.mode.tt.extern_pid, 0); + } + if(init_task.thread.mode.tt.extern_pid != me) + os_kill_process(init_task.thread.mode.tt.extern_pid, 0); +} + +void set_tracing(void *task, int tracing) +{ + ((struct task_struct *) task)->thread.mode.tt.tracing = tracing; +} + +int is_tracing(void *t) +{ + return (((struct task_struct *) t)->thread.mode.tt.tracing); +} + +int set_user_mode(void *t) +{ + struct task_struct *task; + + task = t ? t : current; + if(task->thread.mode.tt.tracing) return(1); + task->thread.request.op = OP_TRACE_ON; + os_usr1_process(os_getpid()); + return(0); +} + +void set_init_pid(int pid) +{ + int err; + + init_task.thread.mode.tt.extern_pid = pid; + err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1); + if(err) panic("Can't create switch pipe for init_task, errno = %d", + err); +} + +void clear_singlestep(void *t) +{ + struct task_struct *task = (struct task_struct *) t; + + task->ptrace &= ~PT_DTRACE; +} + +int singlestepping(void *t) +{ + struct task_struct *task = (struct task_struct *) t; + + if(task->thread.mode.tt.singlestep_syscall) + return(0); + return(task->ptrace & PT_DTRACE); +} + +int start_uml_tt(void) +{ + void *sp; + + sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE - + sizeof(unsigned long); + return(tracer(start_kernel_proc, sp)); +} + +int external_pid_tt(struct task_struct *task) +{ + return(task->thread.mode.tt.extern_pid); +} + +int thread_pid_tt(struct thread_struct *thread) +{ + return(thread->mode.tt.extern_pid); +} + +int is_valid_pid(int pid) +{ + struct task_struct *task; + + read_lock(&tasklist_lock); + for_each_process(task){ + if(task->thread.mode.tt.extern_pid == pid){ + read_unlock(&tasklist_lock); + return(1); + } + } + read_unlock(&tasklist_lock); + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index ba4410ad739b..eb5a5e6eef42 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -34,6 +34,9 @@ #include "initrd.h" #include "init.h" #include "os.h" +#include "choose-mode.h" +#include "mode_kern.h" +#include "mode.h" #define DEFAULT_COMMAND_LINE "root=6200" @@ -44,7 +47,7 @@ struct cpuinfo_um boot_cpu_data = { unsigned long thread_saved_pc(struct task_struct *task) { - return(os_process_pc(task->thread.extern_pid)); + return(os_process_pc(task->thread.mode.tt.extern_pid)); } static int show_cpuinfo(struct seq_file *m, void *v) @@ -93,28 +96,6 @@ pte_t * __bad_pagetable(void) return(NULL); } -extern void start_kernel(void); - -extern int debug; -extern int debug_stop; - -static int start_kernel_proc(void *unused) -{ - int pid; - - block_signals(); - pid = os_getpid(); - - cpu_tasks[0].pid = pid; - cpu_tasks[0].task = current; -#ifdef CONFIG_SMP - cpu_online_map = 1; -#endif - if(debug) os_stop_process(pid); - start_kernel(); - return(0); -} - #ifdef CONFIG_HOST_2G_2G #define TOP 0x80000000 #else @@ -128,12 +109,7 @@ static int start_kernel_proc(void *unused) unsigned long host_task_size; unsigned long task_size; -void set_task_sizes(int arg) -{ - /* Round up to the nearest 4M */ - host_task_size = ROUND_4M((unsigned long) &arg); - task_size = START; -} +unsigned long uml_start; /* Set in early boot */ unsigned long uml_physmem; @@ -156,7 +132,8 @@ long physmem_size = 32 * 1024 * 1024; void set_cmdline(char *cmd) { char *umid, *ptr; - if(honeypot) return; + + if(CHOOSE_MODE(honeypot, 0)) return; umid = get_umid(1); if(umid != NULL){ @@ -268,6 +245,7 @@ static void __init uml_postsetup(void) } extern int debug_trace; +int mode_tt = 1; /* Set during early boot */ unsigned long brk_start; @@ -280,7 +258,6 @@ int linux_main(int argc, char **argv) unsigned long avail; unsigned long virtmem_size, max_physmem; unsigned int i, add, err; - void *sp; for (i = 1; i < argc; i++){ if((i == 1) && (argv[i][0] == ' ')) continue; @@ -290,16 +267,14 @@ int linux_main(int argc, char **argv) } if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE); - if(!jail || debug) - remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext), 1); - remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata), 1); - mode_tt = 1; + uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, + &host_task_size, &task_size); brk_start = (unsigned long) sbrk(0); - remap_data(ROUND_DOWN(&__bss_start), ROUND_UP(brk_start), 1); + CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); - uml_physmem = START; + uml_physmem = uml_start; /* Reserve up to 4M after the current brk */ uml_reserved = ROUND_4M(brk_start) + (1 << 22); @@ -334,8 +309,10 @@ int linux_main(int argc, char **argv) virtmem_size); err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved); - if(err) - tracer_panic("Failed to reserve VM area for kernel VM\n"); + if(err){ + printf("Failed to reserve VM area for kernel VM\n"); + exit(1); + } uml_postsetup(); @@ -343,9 +320,8 @@ int linux_main(int argc, char **argv) 2 * PAGE_SIZE; task_protections((unsigned long) &init_thread_info); - sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE - - sizeof(unsigned long); - return(signals(start_kernel_proc, sp)); + + return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); } static int panic_exit(struct notifier_block *self, unsigned long unused1, diff --git a/arch/um/main.c b/arch/um/main.c index 204c7a189fdd..ffe6ed6f6289 100644 --- a/arch/um/main.c +++ b/arch/um/main.c @@ -17,6 +17,8 @@ #include "mem_user.h" #include "user.h" #include "init.h" +#include "mode.h" +#include "choose-mode.h" /* Set in set_stklim, which is called from main and __wrap_malloc. * __wrap_malloc only calls it if main hasn't started. @@ -97,9 +99,6 @@ int main(int argc, char **argv, char **envp) new_argv[i] = argv[i - 1]; new_argv[argc + 1] = NULL; -#ifdef PROFILING - disable_profile_timer(); -#endif execvp(new_argv[0], new_argv); perror("execing with extended args"); exit(1); @@ -108,7 +107,6 @@ int main(int argc, char **argv, char **envp) linux_prog = argv[0]; set_stklim(); - set_task_sizes(0); if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){ perror("Mallocing argv"); @@ -136,60 +134,14 @@ int main(int argc, char **argv, char **envp) return(uml_exitcode); } -/* Changed in __wrap___monstartup and __wrap_malloc very early */ -static int allocating_monbuf = 0; - -#ifdef PROFILING -extern void __real___monstartup (unsigned long, unsigned long); - -void __wrap___monstartup (unsigned long lowpc, unsigned long highpc) -{ - allocating_monbuf = 1; - __real___monstartup(lowpc, highpc); - allocating_monbuf = 0; - get_profile_timer(); -} -#endif +#define CAN_KMALLOC() \ + (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1)) extern void *__real_malloc(int); -extern unsigned long host_task_size; - -/* Set in __wrap_malloc early */ -static void *gmon_buf = NULL; void *__wrap_malloc(int size) { - if(allocating_monbuf){ - unsigned long start, end; - int fd; - - /* Turn this off now in case create_mem_file tries allocating - * memory - */ - allocating_monbuf = 0; - fd = create_mem_file(size); - - /* Calculate this here because linux_main hasn't run yet - * and host_task_size figures in STACK_TOP, which figures - * in kmem_end. - */ - set_task_sizes(0); - - /* Same with stacksizelim */ - set_stklim(); - - end = get_kmem_end(); - start = (end - size) & PAGE_MASK; - gmon_buf = mmap((void *) start, size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_FIXED, fd, 0); - if(gmon_buf != (void *) start){ - perror("Creating gprof buffer"); - exit(1); - } - set_kmem_end(start); - return(gmon_buf); - } - if(kmalloc_ok) return(um_kmalloc(size)); + if(CAN_KMALLOC()) return(um_kmalloc(size)); else return(__real_malloc(size)); } @@ -206,11 +158,7 @@ extern void __real_free(void *); void __wrap_free(void *ptr) { - /* Could maybe unmap the gmon buffer, but we're just about to - * exit anyway - */ - if(ptr == gmon_buf) return; - if(kmalloc_ok) kfree(ptr); + if(CAN_KMALLOC()) kfree(ptr); else __real_free(ptr); } diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 042df18a4eab..b7a565a2d721 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -95,6 +95,41 @@ int os_getpid(void) return(getpid()); } +int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len, + int r, int w, int x) +{ + void *loc; + int prot; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + + loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, + fd, off); + if(loc < 0) + return(-errno); + return(0); +} + +int os_protect_memory(void *addr, unsigned long len, int r, int w, int x) +{ + int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0)); + + if(mprotect(addr, len, prot) < 0) + return(-errno); + return(0); +} + +int os_unmap_memory(void *addr, int len) +{ + int err; + + err = munmap(addr, len); + if(err < 0) return(-errno); + return(0); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c index 64a5c21bda29..2866ddbc9203 100644 --- a/arch/um/os-Linux/tty.c +++ b/arch/um/os-Linux/tty.c @@ -35,7 +35,7 @@ int get_pty(void) } info.fd = fd; - tracing_cb(grantpt_cb, &info); + initial_thread_cb(grantpt_cb, &info); if(info.res < 0){ printk("get_pty : Couldn't grant pty - errno = %d\n", diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 659db8a6e2d8..70da62313616 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -102,7 +102,7 @@ void update_debugregs(int seq) if(seq == debugregs_seq) return; me = os_getpid(); - tracing_cb(update_debugregs_cb, &me); + initial_thread_cb(update_debugregs_cb, &me); } /* diff --git a/arch/um/sys-i386/util/mk_thread_kern.c b/arch/um/sys-i386/util/mk_thread_kern.c index 6d7b853a6157..ad3671423d41 100644 --- a/arch/um/sys-i386/util/mk_thread_kern.c +++ b/arch/um/sys-i386/util/mk_thread_kern.c @@ -1,7 +1,19 @@ #include "linux/stddef.h" #include "linux/sched.h" -int debugreg(void) +extern void print_head(void); +extern void print_constant_ptr(char *name, int value); +extern void print_constant(char *name, char *type, int value); +extern void print_tail(void); + +#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field) + +int main(int argc, char **argv) { - return(offsetof(struct task_struct, thread.arch.debugregs)); + print_head(); + print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs)); + print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid)); + print_tail(); + return(0); } + diff --git a/arch/um/sys-i386/util/mk_thread_user.c b/arch/um/sys-i386/util/mk_thread_user.c index 997a02e9b35a..2620cd6aa1f1 100644 --- a/arch/um/sys-i386/util/mk_thread_user.c +++ b/arch/um/sys-i386/util/mk_thread_user.c @@ -1,12 +1,30 @@ #include -#include -#include -extern int debugreg(void); +void print_head(void) +{ + printf("/*\n"); + printf(" * Generated by mk_thread\n"); + printf(" */\n"); + printf("\n"); + printf("#ifndef __UM_THREAD_H\n"); + printf("#define __UM_THREAD_H\n"); + printf("\n"); +} + +void print_constant_ptr(char *name, int value) +{ + printf("#define %s(task) ((unsigned long *) " + "&(((char *) (task))[%d]))\n", name, value); +} + +void print_constant(char *name, char *type, int value) +{ + printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type, + value); +} -int main(int argc, char **argv) +void print_tail(void) { - printf("#define TASK_DEBUGREGS(task) ((unsigned long *) " - "&(((char *) (task))[%d]))\n", debugreg()); - return(0); + printf("\n"); + printf("#endif\n"); } diff --git a/arch/um/util/Makefile b/arch/um/util/Makefile index 96568b8ce61e..cde9e8ac75a5 100644 --- a/arch/um/util/Makefile +++ b/arch/um/util/Makefile @@ -1,4 +1,4 @@ -EXTRA_TARGETS := mk_task mk_task_kern.o +EXTRA_TARGETS := mk_task mk_constants include $(TOPDIR)/Rules.make @@ -8,6 +8,15 @@ $(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o $(obj)/mk_task_user.o: $(src)/mk_task_user.c $(CC) -o $@ -c $< +$(obj)/mk_constants : $(obj)/mk_constants_user.o $(obj)/mk_constants_kern.o + $(CC) -o $@ $^ + +$(obj)/mk_constants_user.o : $(src)/mk_constants_user.c + $(CC) -c $< -o $@ + +$(obj)/mk_constants_kern.o : $(src)/mk_constants_kern.c + $(CC) $(CFLAGS) -c $< -o $@ + clean: $(RM) $(EXTRA_TARGETS) diff --git a/include/asm-um/a.out.h b/include/asm-um/a.out.h index 2e208223f860..7c26265e1d7a 100644 --- a/include/asm-um/a.out.h +++ b/include/asm-um/a.out.h @@ -1,7 +1,9 @@ #ifndef __UM_A_OUT_H #define __UM_A_OUT_H +#include "linux/config.h" #include "asm/arch/a.out.h" +#include "choose-mode.h" #undef STACK_TOP @@ -9,10 +11,10 @@ extern unsigned long stacksizelim; extern unsigned long host_task_size; -extern int honeypot; - #define STACK_ROOM (stacksizelim) -#define STACK_TOP (honeypot ? host_task_size : task_size) +extern int honeypot; +#define STACK_TOP \ + CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size) #endif diff --git a/include/asm-um/mmu.h b/include/asm-um/mmu.h index d276d24f07df..2cf35c21d694 100644 --- a/include/asm-um/mmu.h +++ b/include/asm-um/mmu.h @@ -1,6 +1,22 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #ifndef __MMU_H #define __MMU_H -#include "asm/arch/mmu.h" +#include "um_mmu.h" #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/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h index 56ef77e1c1c8..e735fe0a95a9 100644 --- a/include/asm-um/mmu_context.h +++ b/include/asm-um/mmu_context.h @@ -1,20 +1,33 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #ifndef __UM_MMU_CONTEXT_H #define __UM_MMU_CONTEXT_H #include "linux/sched.h" +#include "choose-mode.h" -#define init_new_context(task, mm) (0) #define get_mmu_context(task) do ; while(0) #define activate_context(tsk) do ; while(0) -#define destroy_context(mm) do ; while(0) static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) { } +extern void switch_mm_skas(int mm_fd); + static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) { + if(prev != next){ + clear_bit(cpu, &prev->cpu_vm_mask); + set_bit(cpu, &next->cpu_vm_mask); + if(next != &init_mm) + CHOOSE_MODE((void) 0, + switch_mm_skas(next->context.skas.mm_fd)); + } } static inline void enter_lazy_tlb(struct mm_struct *mm, @@ -22,4 +35,38 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, { } +extern int init_new_context_skas(struct task_struct *task, + struct mm_struct *mm); + +static inline int init_new_context_tt(struct task_struct *task, + struct mm_struct *mm) +{ + return(0); +} + +static inline int init_new_context(struct task_struct *task, + struct mm_struct *mm) +{ + return(CHOOSE_MODE_PROC(init_new_context_tt, init_new_context_skas, + task, mm)); +} + +extern void destroy_context_skas(struct mm_struct *mm); + +static inline void destroy_context(struct mm_struct *mm) +{ + CHOOSE_MODE((void) 0, destroy_context_skas(mm)); +} + #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/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index 7e771b8ca7db..596257f5bd15 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -12,9 +12,9 @@ struct task_struct; #include "linux/config.h" #include "linux/signal.h" -#include "asm/segment.h" #include "asm/ptrace.h" #include "asm/siginfo.h" +#include "choose-mode.h" struct mm_struct; @@ -22,8 +22,24 @@ struct mm_struct; #define cpu_relax() do ; while (0) +#ifdef CONFIG_MODE_TT +struct proc_tt_mode { + int extern_pid; + int tracing; + int switch_pipe[2]; + int singlestep_syscall; + int vm_seq; +}; +#endif + +#ifdef CONFIG_MODE_SKAS +struct proc_skas_mode { + void *switch_buf; + void *fork_buf; +}; +#endif + struct thread_struct { - int extern_pid; int tracing; int forking; unsigned long kernel_stack; @@ -33,13 +49,18 @@ struct thread_struct { int err; void *fault_addr; void *fault_catcher; - int vm_seq; struct task_struct *prev_sched; unsigned long temp_stack; - int switch_pipe[2]; - void *jmp; + void *exec_buf; struct arch_thread arch; - int singlestep_syscall; + union { +#ifdef CONFIG_MODE_TT + struct proc_tt_mode tt; +#endif +#ifdef CONFIG_MODE_SKAS + struct proc_skas_mode skas; +#endif + } mode; struct { int op; union { @@ -60,8 +81,6 @@ struct thread_struct { #define INIT_THREAD \ { \ - extern_pid: -1, \ - tracing: 0, \ forking: 0, \ kernel_stack: 0, \ nsyscalls: 0, \ @@ -69,13 +88,10 @@ struct thread_struct { cr2: 0, \ err: 0, \ fault_addr: NULL, \ - vm_seq: 0, \ prev_sched: NULL, \ temp_stack: 0, \ - switch_pipe: { -1, -1 }, \ - jmp: NULL, \ + exec_buf: NULL, \ arch: INIT_ARCH_THREAD, \ - singlestep_syscall: 0, \ request: { 0 } \ } -- cgit v1.2.3 From f62fb4cf888e8440717b1605c05b14b2bad64076 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 02:52:36 -0500 Subject: Added arch/um/kernel/skas/util/*, which I missed somehow. --- arch/um/kernel/skas/util/Makefile | 10 ++++++++ arch/um/kernel/skas/util/mk_ptregs.c | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 arch/um/kernel/skas/util/Makefile create mode 100644 arch/um/kernel/skas/util/mk_ptregs.c diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile new file mode 100644 index 000000000000..e62dc253e895 --- /dev/null +++ b/arch/um/kernel/skas/util/Makefile @@ -0,0 +1,10 @@ +all: mk_ptregs + +mk_ptregs : mk_ptregs.o + $(CC) -o mk_ptregs mk_ptregs.o + +mk_ptregs.o : mk_ptregs.c + $(CC) -c $< + +clean : + $(RM) -f mk_ptregs *.o *~ diff --git a/arch/um/kernel/skas/util/mk_ptregs.c b/arch/um/kernel/skas/util/mk_ptregs.c new file mode 100644 index 000000000000..658791017373 --- /dev/null +++ b/arch/um/kernel/skas/util/mk_ptregs.c @@ -0,0 +1,50 @@ +#include +#include + +#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val)) + +int main(int argc, char **argv) +{ + printf("/* Automatically generated by " + "arch/um/kernel/skas/util/mk_ptregs */\n"); + printf("\n"); + printf("#ifndef __SKAS_PT_REGS_\n"); + printf("#define __SKAS_PT_REGS_\n"); + printf("\n"); + printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE); + printf("#define HOST_FP_SIZE %d\n", + sizeof(struct user_i387_struct) / sizeof(unsigned long)); + printf("#define HOST_XFP_SIZE %d\n", + sizeof(struct user_fxsr_struct) / sizeof(unsigned long)); + + PRINT_REG("IP", EIP); + PRINT_REG("SP", UESP); + PRINT_REG("EFLAGS", EFL); + PRINT_REG("EAX", EAX); + PRINT_REG("EBX", EBX); + PRINT_REG("ECX", ECX); + PRINT_REG("EDX", EDX); + PRINT_REG("ESI", ESI); + PRINT_REG("EDI", EDI); + PRINT_REG("EBP", EBP); + PRINT_REG("CS", CS); + PRINT_REG("SS", SS); + PRINT_REG("DS", DS); + PRINT_REG("FS", FS); + PRINT_REG("ES", ES); + PRINT_REG("GS", GS); + printf("\n"); + printf("#endif\n"); + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ -- cgit v1.2.3 From 9641b8e63ccf9732016777e67e0590c311c58b6f Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 02:58:41 -0500 Subject: Added ptrace-skas.h and ptrace-tt.h. --- arch/um/kernel/skas/include/ptrace-skas.h | 57 +++++++++++++++++++++++++++++++ arch/um/kernel/tt/include/ptrace-tt.h | 26 ++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 arch/um/kernel/skas/include/ptrace-skas.h create mode 100644 arch/um/kernel/tt/include/ptrace-tt.h diff --git a/arch/um/kernel/skas/include/ptrace-skas.h b/arch/um/kernel/skas/include/ptrace-skas.h new file mode 100644 index 000000000000..f4ab3fb43339 --- /dev/null +++ b/arch/um/kernel/skas/include/ptrace-skas.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __PTRACE_SKAS_H +#define __PTRACE_SKAS_H + +#include "uml-config.h" + +#ifdef CONFIG_MODE_SKAS + +#include "skas_ptregs.h" + +#define HOST_FRAME_SIZE 17 + +#define REGS_IP(r) ((r)[HOST_IP]) +#define REGS_SP(r) ((r)[HOST_SP]) +#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) +#define REGS_EAX(r) ((r)[HOST_EAX]) +#define REGS_EBX(r) ((r)[HOST_EBX]) +#define REGS_ECX(r) ((r)[HOST_ECX]) +#define REGS_EDX(r) ((r)[HOST_EDX]) +#define REGS_ESI(r) ((r)[HOST_ESI]) +#define REGS_EDI(r) ((r)[HOST_EDI]) +#define REGS_EBP(r) ((r)[HOST_EBP]) +#define REGS_CS(r) ((r)[HOST_CS]) +#define REGS_SS(r) ((r)[HOST_SS]) +#define REGS_DS(r) ((r)[HOST_DS]) +#define REGS_ES(r) ((r)[HOST_ES]) +#define REGS_FS(r) ((r)[HOST_FS]) +#define REGS_GS(r) ((r)[HOST_GS]) + +#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res) + +#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) + +#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type) + +#define REGS_FAULT_ADDR(r) ((r)->fault_addr) + +#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type) + +#endif + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/include/ptrace-tt.h b/arch/um/kernel/tt/include/ptrace-tt.h new file mode 100644 index 000000000000..4e22b772c8f5 --- /dev/null +++ b/arch/um/kernel/tt/include/ptrace-tt.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __PTRACE_TT_H +#define __PTRACE_TT_H + +#include "uml-config.h" + +#ifdef CONFIG_MODE_TT +#include "sysdep/sc.h" +#endif + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ -- cgit v1.2.3 From bc758b0aaf57ad293671905e42b9b0813847d615 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 03:15:09 -0500 Subject: Added mode.h, mk_constants_kern.c, mk_constants_user.c, and um_mmu.h --- arch/um/include/mode.h | 30 ++++++++++++++++++++++++++++++ arch/um/include/um_mmu.h | 40 ++++++++++++++++++++++++++++++++++++++++ arch/um/util/mk_constants_kern.c | 24 ++++++++++++++++++++++++ arch/um/util/mk_constants_user.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 arch/um/include/mode.h create mode 100644 arch/um/include/um_mmu.h create mode 100644 arch/um/util/mk_constants_kern.c create mode 100644 arch/um/util/mk_constants_user.c diff --git a/arch/um/include/mode.h b/arch/um/include/mode.h new file mode 100644 index 000000000000..ba7f6ff04121 --- /dev/null +++ b/arch/um/include/mode.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_H__ +#define __MODE_H__ + +#include "uml-config.h" + +#ifdef CONFIG_MODE_TT +#include "../kernel/tt/include/mode.h" +#endif + +#ifdef CONFIG_MODE_SKAS +#include "../kernel/skas/include/mode.h" +#endif + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/um_mmu.h b/arch/um/include/um_mmu.h new file mode 100644 index 000000000000..3c5660ff97d7 --- /dev/null +++ b/arch/um/include/um_mmu.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __ARCH_UM_MMU_H +#define __ARCH_UM_MMU_H + +#include "linux/config.h" +#include "choose-mode.h" + +#ifdef CONFIG_MODE_TT +#include "../kernel/tt/include/mmu.h" +#endif + +#ifdef CONFIG_MODE_SKAS +#include "../kernel/skas/include/mmu.h" +#endif + +typedef union { +#ifdef CONFIG_MODE_TT + struct mmu_context_tt tt; +#endif +#ifdef CONFIG_MODE_SKAS + struct mmu_context_skas skas; +#endif +} mm_context_t; + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/util/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c new file mode 100644 index 000000000000..7e74934318c4 --- /dev/null +++ b/arch/um/util/mk_constants_kern.c @@ -0,0 +1,24 @@ +#include "linux/kernel.h" +#include "linux/stringify.h" +#include "asm/page.h" + +extern void print_head(void); +extern void print_constant_str(char *name, char *value); +extern void print_constant_int(char *name, int value); +extern void print_tail(void); + +int main(int argc, char **argv) +{ + print_head(); + print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE); + print_constant_str("UM_KERN_EMERG", KERN_EMERG); + print_constant_str("UM_KERN_ALERT", KERN_ALERT); + print_constant_str("UM_KERN_CRIT", KERN_CRIT); + print_constant_str("UM_KERN_ERR", KERN_ERR); + print_constant_str("UM_KERN_WARNING", KERN_WARNING); + print_constant_str("UM_KERN_NOTICE", KERN_NOTICE); + print_constant_str("UM_KERN_INFO", KERN_INFO); + print_constant_str("UM_KERN_DEBUG", KERN_DEBUG); + print_tail(); + return(0); +} diff --git a/arch/um/util/mk_constants_user.c b/arch/um/util/mk_constants_user.c new file mode 100644 index 000000000000..8f4d7e50be7c --- /dev/null +++ b/arch/um/util/mk_constants_user.c @@ -0,0 +1,28 @@ +#include + +void print_head(void) +{ + printf("/*\n"); + printf(" * Generated by mk_constants\n"); + printf(" */\n"); + printf("\n"); + printf("#ifndef __UM_CONSTANTS_H\n"); + printf("#define __UM_CONSTANTS_H\n"); + printf("\n"); +} + +void print_constant_str(char *name, char *value) +{ + printf("#define %s \"%s\"\n", name, value); +} + +void print_constant_int(char *name, int value) +{ + printf("#define %s %d\n", name, value); +} + +void print_tail(void) +{ + printf("\n"); + printf("#endif\n"); +} -- cgit v1.2.3 From d3185e602ad286f04a4bbbab39b5f226ee725687 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 03:23:40 -0500 Subject: Added the mode mmu.h and mode.h headers. --- arch/um/kernel/skas/include/mmu.h | 27 +++++++++++++++++++++++++++ arch/um/kernel/skas/include/mode.h | 34 ++++++++++++++++++++++++++++++++++ arch/um/kernel/tt/include/mmu.h | 23 +++++++++++++++++++++++ arch/um/kernel/tt/include/mode.h | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 arch/um/kernel/skas/include/mmu.h create mode 100644 arch/um/kernel/skas/include/mode.h create mode 100644 arch/um/kernel/tt/include/mmu.h create mode 100644 arch/um/kernel/tt/include/mode.h diff --git a/arch/um/kernel/skas/include/mmu.h b/arch/um/kernel/skas/include/mmu.h new file mode 100644 index 000000000000..cfbc062bd9dc --- /dev/null +++ b/arch/um/kernel/skas/include/mmu.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_MMU_H +#define __SKAS_MMU_H + +#include "linux/list.h" +#include "linux/spinlock.h" + +struct mmu_context_skas { + int mm_fd; +}; + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/mode.h b/arch/um/kernel/skas/include/mode.h new file mode 100644 index 000000000000..09cadc99edc5 --- /dev/null +++ b/arch/um/kernel/skas/include/mode.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_SKAS_H__ +#define __MODE_SKAS_H__ + +extern unsigned long exec_regs[]; +extern unsigned long exec_fp_regs[]; +extern unsigned long exec_fpx_regs[]; +extern int have_fpx_regs; + +extern void user_time_init_skas(void); +extern int copy_sc_from_user_skas(struct uml_pt_regs *regs, void *from_ptr); +extern int copy_sc_to_user_skas(void *to_ptr, struct uml_pt_regs *regs, + unsigned long fault_addr, int fault_type); +extern void sig_handler_common_skas(int sig, struct sigcontext *sc); +extern void halt_skas(void); +extern void reboot_skas(void); +extern void kill_off_processes_skas(void); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/include/mmu.h b/arch/um/kernel/tt/include/mmu.h new file mode 100644 index 000000000000..6b146bd84ca7 --- /dev/null +++ b/arch/um/kernel/tt/include/mmu.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TT_MMU_H +#define __TT_MMU_H + +struct mmu_context_tt { +}; + +#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/kernel/tt/include/mode.h b/arch/um/kernel/tt/include/mode.h new file mode 100644 index 000000000000..183a61d40453 --- /dev/null +++ b/arch/um/kernel/tt/include/mode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_TT_H__ +#define __MODE_TT_H__ + +#include "sysdep/ptrace.h" + +extern int tracing_pid; + +extern int tracer(int (*init_proc)(void *), void *sp); +extern void user_time_init_tt(void); +extern int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data); +extern int copy_sc_to_user_tt(void *to_ptr, void *from_ptr, void *data); +extern void sig_handler_common_tt(int sig, struct sigcontext *sc); +extern void syscall_handler_tt(int sig, struct uml_pt_regs *regs); +extern void reboot_tt(void); +extern void halt_tt(void); +extern int is_tracer_winch(int pid, int fd, void *data); +extern void kill_off_processes_tt(void); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ -- cgit v1.2.3 From 52e618df69e89ef2ab151c845f453a37e3812c6c Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 04:05:13 -0500 Subject: Changed the config to pull in zlib. --- arch/um/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index f7e8005ebf38..761bb8627ffc 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -128,6 +128,7 @@ source "net/Kconfig" source "fs/Kconfig" +source "lib/Kconfig" menu "SCSI support" -- cgit v1.2.3 From 66805bba44e9a02999d24a176cd6b1d8b04eb4ed Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 04:09:26 -0500 Subject: Added arch/um/include/mode_kern.h --- arch/um/include/mode_kern.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 arch/um/include/mode_kern.h diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h new file mode 100644 index 000000000000..562174bf48a0 --- /dev/null +++ b/arch/um/include/mode_kern.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_KERN_H__ +#define __MODE_KERN_H__ + +#include "linux/config.h" + +#ifdef CONFIG_MODE_TT +#include "../kernel/tt/include/mode_kern.h" +#endif + +#ifdef CONFIG_MODE_SKAS +#include "../kernel/skas/include/mode_kern.h" +#endif + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ -- cgit v1.2.3 From 651542f6dd0d1a4a33ce15bcb855fe4057701edb Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 04:31:45 -0500 Subject: Added a batch of files under arch/um/kernel/skas. --- arch/um/kernel/skas/include/skas.h | 48 ++++ arch/um/kernel/skas/include/skas_ptrace.h | 36 +++ arch/um/kernel/skas/process.c | 360 ++++++++++++++++++++++++++++++ arch/um/kernel/skas/process_kern.c | 194 ++++++++++++++++ arch/um/kernel/skas/syscall_user.c | 47 ++++ arch/um/kernel/skas/trap_user.c | 64 ++++++ arch/um/kernel/tt/include/tt.h | 45 ++++ 7 files changed, 794 insertions(+) create mode 100644 arch/um/kernel/skas/include/skas.h create mode 100644 arch/um/kernel/skas/include/skas_ptrace.h create mode 100644 arch/um/kernel/skas/process.c create mode 100644 arch/um/kernel/skas/process_kern.c create mode 100644 arch/um/kernel/skas/syscall_user.c create mode 100644 arch/um/kernel/skas/trap_user.c create mode 100644 arch/um/kernel/tt/include/tt.h diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h new file mode 100644 index 000000000000..6732307894d5 --- /dev/null +++ b/arch/um/kernel/skas/include/skas.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_H +#define __SKAS_H + +#include "sysdep/ptrace.h" + +extern int userspace_pid; + +extern void switch_threads(void *me, void *next); +extern void thread_wait(void *sw, void *fb); +extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, + void (*handler)(int)); +extern int start_idle_thread(void *stack, void *switch_buf_ptr, + void **fork_buf_ptr); +extern int user_thread(unsigned long stack, int flags); +extern void userspace(struct uml_pt_regs *regs); +extern void new_thread_proc(void *stack, void (*handler)(int sig)); +extern void remove_sigstack(void); +extern void new_thread_handler(int sig); +extern void handle_syscall(struct uml_pt_regs *regs); +extern void map(int fd, unsigned long virt, unsigned long phys, + unsigned long len, int r, int w, int x); +extern int unmap(int fd, void *addr, int len); +extern int protect(int fd, unsigned long addr, unsigned long len, + int r, int w, int x, int must_succeed); +extern void user_signal(int sig, struct uml_pt_regs *regs); +extern int singlestepping_skas(void); +extern int new_mm(int from); +extern void save_registers(struct uml_pt_regs *regs); +extern void restore_registers(struct uml_pt_regs *regs); +extern void start_userspace(void); + +#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/kernel/skas/include/skas_ptrace.h b/arch/um/kernel/skas/include/skas_ptrace.h new file mode 100644 index 000000000000..7cd983d88d51 --- /dev/null +++ b/arch/um/kernel/skas/include/skas_ptrace.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_PTRACE_H +#define __SKAS_PTRACE_H + +struct ptrace_faultinfo { + int is_write; + unsigned long addr; +}; + +struct ptrace_ldt { + int func; + void *ptr; + unsigned long bytecount; +}; + +#define PTRACE_FAULTINFO 52 +#define PTRACE_SIGPENDING 53 +#define PTRACE_LDT 54 +#define PTRACE_SWITCH_MM 55 + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c new file mode 100644 index 000000000000..c3283a366cb8 --- /dev/null +++ b/arch/um/kernel/skas/process.c @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user.h" +#include "ptrace_user.h" +#include "time_user.h" +#include "sysdep/ptrace.h" +#include "user_util.h" +#include "kern_util.h" +#include "skas.h" +#include "skas_ptrace.h" +#include "sysdep/sigcontext.h" +#include "os.h" +#include "proc_mm.h" + +unsigned long exec_regs[FRAME_SIZE]; +unsigned long exec_fp_regs[HOST_FP_SIZE]; +unsigned long exec_fpx_regs[HOST_XFP_SIZE]; +int have_fpx_regs = 1; + +static void handle_segv(int pid) +{ + struct ptrace_faultinfo fault; + int err; + + err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault); + if(err) + panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n", + errno); + segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL); +} + +static void handle_trap(int pid, struct uml_pt_regs *regs) +{ + int err, syscall_nr, status; + + syscall_nr = PT_SYSCALL_NR(regs->mode.skas.regs); + if(syscall_nr < 1){ + relay_signal(SIGTRAP, regs); + return; + } + UPT_SYSCALL_NR(regs) = syscall_nr; + + err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); + if(err < 0) + panic("handle_trap - nullifying syscall failed errno = %d\n", + errno); + + err = ptrace(PTRACE_SYSCALL, pid, 0, 0); + if(err < 0) + panic("handle_trap - continuing to end of syscall failed, " + "errno = %d\n", errno); + + err = waitpid(pid, &status, WUNTRACED); + if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + panic("handle_trap - failed to wait at end of syscall, " + "errno = %d, status = %d\n", errno, status); + + handle_syscall(regs); +} + +int userspace_pid; + +static int userspace_tramp(void *arg) +{ + init_new_thread_signals(0); + enable_timer(); + ptrace(PTRACE_TRACEME, 0, 0, 0); + os_stop_process(os_getpid()); +} + +void start_userspace(void) +{ + void *stack; + unsigned long sp; + int pid, status, n; + + stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if(stack == MAP_FAILED) + panic("start_userspace : mmap failed, errno = %d", errno); + sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); + + pid = clone(userspace_tramp, (void *) sp, + CLONE_FILES | CLONE_VM | SIGCHLD, NULL); + if(pid < 0) + panic("start_userspace : clone failed, errno = %d", errno); + + do { + n = waitpid(pid, &status, WUNTRACED); + if(n < 0) + panic("start_userspace : wait failed, errno = %d", + errno); + } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); + + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) + panic("start_userspace : expected SIGSTOP, got status = %d", + status); + + if(munmap(stack, PAGE_SIZE) < 0) + panic("start_userspace : munmap failed, errno = %d\n", errno); + + userspace_pid = pid; +} + +void userspace(struct uml_pt_regs *regs) +{ + int err, status, op; + + restore_registers(regs); + + err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0); + if(err) + panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", + errno); + while(1){ + err = waitpid(userspace_pid, &status, WUNTRACED); + if(err < 0) + panic("userspace - waitpid failed, errno = %d\n", + errno); + + regs->is_user = 1; + save_registers(regs); + + if(WIFSTOPPED(status)){ + switch(WSTOPSIG(status)){ + case SIGSEGV: + handle_segv(userspace_pid); + break; + case SIGTRAP: + handle_trap(userspace_pid, regs); + break; + case SIGIO: + case SIGVTALRM: + case SIGILL: + case SIGBUS: + case SIGFPE: + user_signal(WSTOPSIG(status), regs); + break; + default: + printk("userspace - child stopped with signal " + "%d\n", WSTOPSIG(status)); + } + interrupt_end(); + } + + restore_registers(regs); + + op = singlestepping_skas() ? PTRACE_SINGLESTEP : + PTRACE_SYSCALL; + err = ptrace(op, userspace_pid, 0, 0); + if(err) + panic("userspace - PTRACE_SYSCALL failed, " + "errno = %d\n", errno); + } +} + +void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, + void (*handler)(int)) +{ + jmp_buf switch_buf, fork_buf; + + *switch_buf_ptr = &switch_buf; + *fork_buf_ptr = &fork_buf; + + if(setjmp(fork_buf) == 0) + new_thread_proc(stack, handler); + + remove_sigstack(); +} + +void thread_wait(void *sw, void *fb) +{ + jmp_buf buf, **switch_buf = sw, *fork_buf; + + *switch_buf = &buf; + fork_buf = fb; + if(setjmp(buf) == 0) + longjmp(*fork_buf, 1); +} + +static int move_registers(int int_op, int fp_op, struct uml_pt_regs *regs, + unsigned long *fp_regs) +{ + if(ptrace(int_op, userspace_pid, 0, regs->mode.skas.regs) < 0) + return(-errno); + if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0) + return(-errno); + return(0); +} + +void save_registers(struct uml_pt_regs *regs) +{ + unsigned long *fp_regs; + int err, fp_op; + + if(have_fpx_regs){ + fp_op = PTRACE_GETFPXREGS; + fp_regs = regs->mode.skas.xfp; + } + else { + fp_op = PTRACE_GETFPREGS; + fp_regs = regs->mode.skas.fp; + } + + err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs); + if(err) + panic("save_registers - saving registers failed, errno = %d\n", + err); +} + +void restore_registers(struct uml_pt_regs *regs) +{ + unsigned long *fp_regs; + int err, fp_op; + + if(have_fpx_regs){ + fp_op = PTRACE_SETFPXREGS; + fp_regs = regs->mode.skas.xfp; + } + else { + fp_op = PTRACE_SETFPREGS; + fp_regs = regs->mode.skas.fp; + } + + err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs); + if(err) + panic("restore_registers - saving registers failed, " + "errno = %d\n", err); +} + +void switch_threads(void *me, void *next) +{ + jmp_buf my_buf, **me_ptr = me, *next_buf = next; + + *me_ptr = &my_buf; + if(setjmp(my_buf) == 0) + longjmp(*next_buf, 1); +} + +static jmp_buf initial_jmpbuf; + +/* XXX Make these percpu */ +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) +{ + jmp_buf **switch_buf = switch_buf_ptr; + int n; + + *fork_buf_ptr = &initial_jmpbuf; + n = setjmp(initial_jmpbuf); + if(n == 0) + new_thread_proc((void *) stack, new_thread_handler); + else if(n == 1) + remove_sigstack(); + else if(n == 2){ + (*cb_proc)(cb_arg); + longjmp(*cb_back, 1); + } + else if(n == 3) + return(0); + else if(n == 4) + return(1); + longjmp(**switch_buf, 1); +} + +void remove_sigstack(void) +{ + stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE, + .ss_sp = NULL, + .ss_size = 0 }); + + if(sigaltstack(&stack, NULL) != 0) + panic("disabling signal stack failed, errno = %d\n", errno); +} + +void initial_thread_cb_skas(void (*proc)(void *), void *arg) +{ + jmp_buf here; + + cb_proc = proc; + cb_arg = arg; + cb_back = &here; + if(setjmp(here) == 0) + longjmp(initial_jmpbuf, 2); + +} + +void halt_skas(void) +{ + block_signals(); + longjmp(initial_jmpbuf, 3); +} + +void reboot_skas(void) +{ + block_signals(); + longjmp(initial_jmpbuf, 4); +} + +int new_mm(int from) +{ + struct proc_mm_op copy; + int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0); + + if(fd < 0) + return(-errno); + + if(from != -1){ + copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, + .u = + { .copy_segments = from } } ); + n = os_write_file(fd, (char *) ©, sizeof(copy)); + if(n != sizeof(copy)) + printk("new_mm : /proc/mm copy_segments failed, " + "errno = %d\n", errno); + } + return(fd); +} + +void switch_mm_skas(int mm_fd) +{ + int err; + + err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd); + if(err) + panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", + errno); +} + +void kill_off_processes_skas(void) +{ + os_kill_process(userspace_pid, 1); +} + +/* + * 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/process_kern.c b/arch/um/kernel/skas/process_kern.c new file mode 100644 index 000000000000..bc3394b04343 --- /dev/null +++ b/arch/um/kernel/skas/process_kern.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/slab.h" +#include "kern_util.h" +#include "time_user.h" +#include "signal_user.h" +#include "skas.h" +#include "os.h" +#include "user_util.h" +#include "tlb.h" +#include "frame.h" +#include "kern.h" +#include "mode.h" + +int singlestepping_skas(void) +{ + int ret = current->ptrace & PT_DTRACE; + + current->ptrace &= ~PT_DTRACE; + return(ret); +} + +void *switch_to_skas(void *prev, void *next) +{ + struct task_struct *from, *to; + + from = prev; + to = next; + + /* XXX need to check runqueues[cpu].idle */ + if(current->pid == 0) + switch_timers(0); + + to->thread.prev_sched = from; + set_current(to); + + switch_threads(&from->thread.mode.skas.switch_buf, + to->thread.mode.skas.switch_buf); + + if(current->pid == 0) + switch_timers(1); + + return(current->thread.prev_sched); +} + +extern void schedule_tail(struct task_struct *prev); + +void new_thread_handler(int sig) +{ + int (*fn)(void *), n; + void *arg; + + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + change_sig(SIGUSR1, 1); + thread_wait(¤t->thread.mode.skas.switch_buf, + current->thread.mode.skas.fork_buf); + +#ifdef CONFIG_SMP + schedule_tail(NULL); +#endif + current->thread.prev_sched = NULL; + + n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); + if(n == 1) + userspace(¤t->thread.regs.regs); + else if(n == 2) + 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 exit_thread_skas(void) +{ +} + +void fork_handler(int sig) +{ + change_sig(SIGUSR1, 1); + thread_wait(¤t->thread.mode.skas.switch_buf, + current->thread.mode.skas.fork_buf); + + force_flush_all(); +#ifdef CONFIG_SMP + schedule_tail(current->thread.prev_sched); +#endif + current->thread.prev_sched = NULL; + unblock_signals(); + + userspace(¤t->thread.regs.regs); +} + +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); + + if(current->thread.forking){ + memcpy(&p->thread.regs.regs.mode.skas, + ¤t->thread.regs.regs.mode.skas, + sizeof(p->thread.regs.regs.mode.skas)); + REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.mode.skas.regs, 0); + if(sp != 0) REGS_SP(p->thread.regs.regs.mode.skas.regs) = sp; + + handler = fork_handler; + } + else { + memcpy(p->thread.regs.regs.mode.skas.regs, exec_regs, + sizeof(p->thread.regs.regs.mode.skas.regs)); + memcpy(p->thread.regs.regs.mode.skas.fp, exec_fp_regs, + sizeof(p->thread.regs.regs.mode.skas.fp)); + memcpy(p->thread.regs.regs.mode.skas.xfp, exec_fpx_regs, + sizeof(p->thread.regs.regs.mode.skas.xfp)); + p->thread.request.u.thread = current->thread.request.u.thread; + handler = new_thread_handler; + } + + new_thread((void *) p->thread.kernel_stack, + &p->thread.mode.skas.switch_buf, + &p->thread.mode.skas.fork_buf, handler); + return(0); +} + +void init_idle_skas(void) +{ + cpu_tasks[current->thread_info->cpu].pid = os_getpid(); +} + +extern void start_kernel(void); + +static int start_kernel_proc(void *unused) +{ + int pid; + + block_signals(); + pid = os_getpid(); + + cpu_tasks[0].pid = pid; + cpu_tasks[0].task = current; +#ifdef CONFIG_SMP + cpu_online_map = 1; +#endif + start_kernel(); + return(0); +} + +int start_uml_skas(void) +{ + start_userspace(); + capture_signal_stack(); + + init_new_thread_signals(1); + idle_timer(); + + init_task.thread.request.u.thread.proc = start_kernel_proc; + init_task.thread.request.u.thread.arg = NULL; + return(start_idle_thread((void *) init_task.thread.kernel_stack, + &init_task.thread.mode.skas.switch_buf, + &init_task.thread.mode.skas.fork_buf)); +} + +int external_pid_skas(struct task_struct *task) +{ + return(userspace_pid); +} + +int thread_pid_skas(struct thread_struct *thread) +{ + return(userspace_pid); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c new file mode 100644 index 000000000000..4f43f5492163 --- /dev/null +++ b/arch/um/kernel/skas/syscall_user.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include "kern_util.h" +#include "syscall_user.h" +#include "sysdep/ptrace.h" +#include "sysdep/sigcontext.h" + +/* XXX Bogus */ +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 +#define ERESTARTNOHAND 514 + +void handle_syscall(struct uml_pt_regs *regs) +{ + long result; + int index; + + host_to_regs(regs); + index = record_syscall_start(UPT_SYSCALL_NR(regs)); + + syscall_trace(); + result = execute_syscall(regs); + + REGS_SET_SYSCALL_RETURN(regs->mode.skas.regs, result); + if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || + (result == -ERESTARTNOINTR)) + do_signal(result); + + syscall_trace(); + record_syscall_end(index, result); +} + +/* + * 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/trap_user.c b/arch/um/kernel/skas/trap_user.c new file mode 100644 index 000000000000..b93e93a71e8e --- /dev/null +++ b/arch/um/kernel/skas/trap_user.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include "sysdep/ptrace.h" +#include "signal_user.h" +#include "user_util.h" +#include "kern_util.h" +#include "task.h" +#include "sigcontext.h" + +void sig_handler_common_skas(int sig, struct sigcontext *sc) +{ + struct uml_pt_regs save_regs, *r; + struct signal_info *info; + int save_errno = errno; + + r = (struct uml_pt_regs *) TASK_REGS(get_current()); + save_regs = *r; + r->is_user = 0; + r->mode.skas.fault_addr = SC_FAULT_ADDR(sc); + r->mode.skas.fault_type = SC_FAULT_TYPE(sc); + r->mode.skas.trap_type = SC_TRAP_TYPE(sc); + + change_sig(SIGUSR1, 1); + info = &sig_info[sig]; + if(!info->is_irq) unblock_signals(); + + (*info->handler)(sig, r); + + *r = save_regs; + errno = save_errno; +} + +extern int missed_ticks[]; + +void user_signal(int sig, struct uml_pt_regs *regs) +{ + struct signal_info *info; + + if(sig == SIGVTALRM) + missed_ticks[cpu()]++; + regs->is_user = 1; + regs->mode.skas.fault_addr = 0; + regs->mode.skas.fault_type = 0; + regs->mode.skas.trap_type = 0; + info = &sig_info[sig]; + (*info->handler)(sig, regs); +} + +/* + * 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/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h new file mode 100644 index 000000000000..3769d2aabc66 --- /dev/null +++ b/arch/um/kernel/tt/include/tt.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TT_H__ +#define __TT_H__ + +#include "sysdep/ptrace.h" + +extern int gdb_pid; +extern int debug; +extern int debug_stop; +extern int debug_trace; + +extern int honeypot; + +extern int fork_tramp(void *sig_stack); +extern int do_proc_op(void *t, int proc_id); +extern int tracer(int (*init_proc)(void *), void *sp); +extern void attach_process(int pid); +extern void tracer_panic(char *format, ...); +extern void set_init_pid(int pid); +extern int set_user_mode(void *task); +extern void set_tracing(void *t, int tracing); +extern int is_tracing(void *task); +extern int singlestepping_tt(void *t); +extern void clear_singlestep(void *t); +extern void syscall_handler(int sig, struct uml_pt_regs *regs); +extern void exit_kernel(int pid, void *task); +extern int do_syscall(void *task, int pid); +extern int is_valid_pid(int pid); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ -- cgit v1.2.3 From 60c1b7733b27267ed67d06a2f86a14e47aa9662b Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 04:48:11 -0500 Subject: Added a bunch of C files under arch/um/kernel/skas and arch/um/kernel/tt. --- arch/um/kernel/skas/include/proc_mm.h | 55 ++++ arch/um/kernel/tt/syscall_user.c | 90 +++++++ arch/um/kernel/tt/tracer.c | 465 ++++++++++++++++++++++++++++++++++ 3 files changed, 610 insertions(+) create mode 100644 arch/um/kernel/skas/include/proc_mm.h create mode 100644 arch/um/kernel/tt/syscall_user.c create mode 100644 arch/um/kernel/tt/tracer.c diff --git a/arch/um/kernel/skas/include/proc_mm.h b/arch/um/kernel/skas/include/proc_mm.h new file mode 100644 index 000000000000..cce61a679052 --- /dev/null +++ b/arch/um/kernel/skas/include/proc_mm.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_PROC_MM_H +#define __SKAS_PROC_MM_H + +#define MM_MMAP 54 +#define MM_MUNMAP 55 +#define MM_MPROTECT 56 +#define MM_COPY_SEGMENTS 57 + +struct mm_mmap { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +struct mm_munmap { + unsigned long addr; + unsigned long len; +}; + +struct mm_mprotect { + unsigned long addr; + unsigned long len; + unsigned int prot; +}; + +struct proc_mm_op { + int op; + union { + struct mm_mmap mmap; + struct mm_munmap munmap; + struct mm_mprotect mprotect; + int copy_segments; + } u; +}; + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c new file mode 100644 index 000000000000..699e91f09c92 --- /dev/null +++ b/arch/um/kernel/tt/syscall_user.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include "sysdep/ptrace.h" +#include "sigcontext.h" +#include "ptrace_user.h" +#include "task.h" +#include "user_util.h" +#include "kern_util.h" +#include "syscall_user.h" +#include "tt.h" + +/* XXX Bogus */ +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 +#define ERESTARTNOHAND 514 + +void syscall_handler_tt(int sig, struct uml_pt_regs *regs) +{ + void *sc; + long result; + int index, syscall; + + syscall = regs->syscall; + sc = regs->mode.tt; + sc_to_regs(regs, sc, syscall); + SC_START_SYSCALL(sc); + + index = record_syscall_start(syscall); + syscall_trace(); + result = execute_syscall(regs); + + /* regs->sc may have changed while the system call ran (there may + * have been an interrupt or segfault), so it needs to be refreshed. + */ + regs->mode.tt = sc; + + SC_SET_SYSCALL_RETURN(sc, result); + if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || + (result == -ERESTARTNOINTR)) + do_signal(result); + + syscall_trace(); + record_syscall_end(index, result); +} + +int do_syscall(void *task, int pid) +{ + unsigned long proc_regs[FRAME_SIZE]; + struct uml_pt_regs *regs; + int syscall; + + if(ptrace_getregs(pid, proc_regs) < 0) + tracer_panic("Couldn't read registers"); + syscall = PT_SYSCALL_NR(proc_regs); + + regs = TASK_REGS(task); + UPT_SYSCALL_NR(regs) = syscall; + + if(syscall < 1) return(0); + + if((syscall != __NR_sigreturn) && + ((unsigned long *) PT_IP(proc_regs) >= &_stext) && + ((unsigned long *) PT_IP(proc_regs) <= &_etext)) + tracer_panic("I'm tracing myself and I can't get out"); + + if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, + __NR_getpid) < 0) + tracer_panic("do_syscall : Nullifying syscall failed, " + "errno = %d", errno); + return(1); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c new file mode 100644 index 000000000000..5b06c48e45b7 --- /dev/null +++ b/arch/um/kernel/tt/tracer.c @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user.h" +#include "sysdep/ptrace.h" +#include "sigcontext.h" +#include "sysdep/sigcontext.h" +#include "os.h" +#include "signal_user.h" +#include "user_util.h" +#include "mem_user.h" +#include "process.h" +#include "kern_util.h" +#include "frame.h" +#include "chan_user.h" +#include "ptrace_user.h" +#include "mode.h" +#include "tt.h" + +static int tracer_winch[2]; + +int is_tracer_winch(int pid, int fd, void *data) +{ + if(pid != tracing_pid) + return(0); + + register_winch_irq(tracer_winch[0], fd, -1, data); + return(0); +} + +static void tracer_winch_handler(int sig) +{ + char c = 1; + + if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c)) + printk("tracer_winch_handler - write failed, errno = %d\n", + errno); +} + +/* Called only by the tracing thread during initialization */ + +static void setup_tracer_winch(void) +{ + int err; + + err = os_pipe(tracer_winch, 1, 1); + if(err){ + printk("setup_tracer_winch : os_pipe failed, errno = %d\n", + -err); + return; + } + signal(SIGWINCH, tracer_winch_handler); +} + +void attach_process(int pid) +{ + if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) || + (ptrace(PTRACE_CONT, pid, 0, 0) < 0)) + tracer_panic("OP_FORK failed to attach pid"); + wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); + if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) + tracer_panic("OP_FORK failed to continue process"); +} + +void tracer_panic(char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + printf("\n"); + while(1) pause(); +} + +static void tracer_segv(int sig, struct sigcontext sc) +{ + printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", + SC_FAULT_ADDR(&sc), SC_IP(&sc)); + while(1) + pause(); +} + +/* Changed early in boot, and then only read */ +int debug = 0; +int debug_stop = 1; +int debug_parent = 0; +int honeypot = 0; + +static int signal_tramp(void *arg) +{ + int (*proc)(void *); + + if(honeypot && munmap((void *) (host_task_size - 0x10000000), + 0x10000000)) + panic("Unmapping stack failed"); + if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) + panic("ptrace PTRACE_TRACEME failed"); + os_stop_process(os_getpid()); + change_sig(SIGWINCH, 0); + signal(SIGUSR1, SIG_IGN); + change_sig(SIGCHLD, 0); + signal(SIGSEGV, (__sighandler_t) sig_handler); + set_cmdline("(idle thread)"); + set_init_pid(os_getpid()); + proc = arg; + return((*proc)(NULL)); +} + +static void last_ditch_exit(int sig) +{ + kmalloc_ok = 0; + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + uml_cleanup(); + exit(1); +} + +static void sleeping_process_signal(int pid, int sig) +{ + switch(sig){ + /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is + * right because the process must be in the kernel already. + */ + case SIGCONT: + case SIGTSTP: + if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) + tracer_panic("sleeping_process_signal : Failed to " + "continue pid %d, errno = %d\n", pid, + sig); + break; + + /* This happens when the debugger (e.g. strace) is doing system call + * tracing on the kernel. During a context switch, the current task + * will be set to the incoming process and the outgoing process will + * hop into write and then read. Since it's not the current process + * any more, the trace of those will land here. So, we need to just + * PTRACE_SYSCALL it. + */ + case SIGTRAP: + if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) + tracer_panic("sleeping_process_signal : Failed to " + "PTRACE_SYSCALL pid %d, errno = %d\n", + pid, sig); + break; + case SIGSTOP: + break; + default: + tracer_panic("sleeping process %d got unexpected " + "signal : %d\n", pid, sig); + break; + } +} + +/* Accessed only by the tracing thread */ +int debugger_pid = -1; +int debugger_parent = -1; +int debugger_fd = -1; +int gdb_pid = -1; + +struct { + int pid; + int signal; + unsigned long addr; + struct timeval time; +} signal_record[1024][32]; + +int signal_index[32]; +int nsignals = 0; +int debug_trace = 0; +extern int io_nsignals, io_count, intr_count; + +extern void signal_usr1(int sig); + +int tracing_pid = -1; + +int tracer(int (*init_proc)(void *), void *sp) +{ + void *task = NULL; + unsigned long eip = 0; + int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; + int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0; + + capture_signal_stack(); + signal(SIGPIPE, SIG_IGN); + setup_tracer_winch(); + tracing_pid = os_getpid(); + printf("tracing thread pid = %d\n", tracing_pid); + + pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); + n = waitpid(pid, &status, WUNTRACED); + if(n < 0){ + printf("waitpid on idle thread failed, errno = %d\n", errno); + exit(1); + } + if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ + printf("Failed to continue idle thread, errno = %d\n", errno); + exit(1); + } + + signal(SIGSEGV, (sighandler_t) tracer_segv); + signal(SIGUSR1, signal_usr1); + 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); + if(debug_trace){ + printf("Tracing thread pausing to be attached\n"); + stop(); + } + if(debug){ + if(gdb_pid != -1) + debugger_pid = attach_debugger(pid, gdb_pid, 1); + else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); + if(debug_parent){ + debugger_parent = os_process_parent(debugger_pid); + init_parent_proxy(debugger_parent); + err = attach(debugger_parent); + if(err){ + printf("Failed to attach debugger parent %d, " + "errno = %d\n", debugger_parent, err); + debugger_parent = -1; + } + else { + if(ptrace(PTRACE_SYSCALL, debugger_parent, + 0, 0) < 0){ + printf("Failed to continue debugger " + "parent, errno = %d\n", errno); + debugger_parent = -1; + } + } + } + } + set_cmdline("(tracing thread)"); + while(1){ + if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){ + if(errno != ECHILD){ + printf("wait failed - errno = %d\n", errno); + } + continue; + } + if(pid == debugger_pid){ + int cont = 0; + + if(WIFEXITED(status) || WIFSIGNALED(status)) + debugger_pid = -1; + /* XXX Figure out how to deal with gdb and SMP */ + else cont = debugger_signal(status, cpu_tasks[0].pid); + if(cont == PTRACE_SYSCALL) strace = 1; + continue; + } + else if(pid == debugger_parent){ + debugger_parent_signal(status, pid); + continue; + } + nsignals++; + if(WIFEXITED(status)) ; +#ifdef notdef + { + printf("Child %d exited with status %d\n", pid, + WEXITSTATUS(status)); + } +#endif + else if(WIFSIGNALED(status)){ + sig = WTERMSIG(status); + if(sig != 9){ + printf("Child %d exited with signal %d\n", pid, + sig); + } + } + else if(WIFSTOPPED(status)){ + proc_id = pid_to_processor_id(pid); + sig = WSTOPSIG(status); + 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_PEEKUSER, 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; + + if(proc_id == -1){ + sleeping_process_signal(pid, sig); + continue; + } + + task = cpu_tasks[proc_id].task; + tracing = is_tracing(task); + old_tracing = tracing; + + switch(sig){ + case SIGUSR1: + sig = 0; + op = do_proc_op(task, proc_id); + switch(op){ + case OP_TRACE_ON: + arch_leave_kernel(task, pid); + tracing = 1; + break; + case OP_REBOOT: + case OP_HALT: + unmap_physmem(); + kmalloc_ok = 0; + ptrace(PTRACE_KILL, pid, 0, 0); + return(op == OP_REBOOT); + case OP_NONE: + printf("Detaching pid %d\n", pid); + detach(pid, SIGSTOP); + continue; + default: + break; + } + /* OP_EXEC switches host processes on us, + * we want to continue the new one. + */ + pid = cpu_tasks[proc_id].pid; + break; + case SIGTRAP: + if(!tracing && (debugger_pid != -1)){ + child_signal(pid, status); + continue; + } + tracing = 0; + if(do_syscall(task, pid)) sig = SIGUSR2; + else clear_singlestep(task); + break; + case SIGPROF: + if(tracing) sig = 0; + break; + case SIGCHLD: + case SIGHUP: + sig = 0; + break; + case SIGSEGV: + case SIGIO: + case SIGALRM: + case SIGVTALRM: + case SIGFPE: + case SIGBUS: + case SIGILL: + case SIGWINCH: + default: + tracing = 0; + break; + } + set_tracing(task, tracing); + + if(!tracing && old_tracing) + arch_enter_kernel(task, pid); + + if(!tracing && (debugger_pid != -1) && (sig != 0) && + (sig != SIGALRM) && (sig != SIGVTALRM) && + (sig != SIGSEGV) && (sig != SIGTRAP) && + (sig != SIGUSR2) && (sig != SIGIO)){ + child_signal(pid, status); + continue; + } + + if(tracing){ + if(singlestepping(task)) + cont_type = PTRACE_SINGLESTEP; + else cont_type = PTRACE_SYSCALL; + } + else cont_type = PTRACE_CONT; + + if((cont_type == PTRACE_CONT) && + (debugger_pid != -1) && strace) + cont_type = PTRACE_SYSCALL; + + if(ptrace(cont_type, pid, 0, sig) != 0){ + tracer_panic("ptrace failed to continue " + "process - errno = %d\n", + errno); + } + } + } + return(0); +} + +static int __init uml_debug_setup(char *line, int *add) +{ + char *next; + + debug = 1; + *add = 0; + if(*line != '=') return(0); + line++; + + while(line != NULL){ + next = strchr(line, ','); + if(next) *next++ = '\0'; + + if(!strcmp(line, "go")) debug_stop = 0; + else if(!strcmp(line, "parent")) debug_parent = 1; + else printk("Unknown debug option : '%s'\n", line); + + line = next; + } + return(0); +} + +__uml_setup("debug", uml_debug_setup, +"debug\n" +" Starts up the kernel under the control of gdb. See the \n" +" kernel debugging tutorial and the debugging session pages\n" +" at http://user-mode-linux.sourceforge.net/ for more information.\n\n" +); + +static int __init uml_debugtrace_setup(char *line, int *add) +{ + debug_trace = 1; + return 0; +} +__uml_setup("debugtrace", uml_debugtrace_setup, +"debugtrace\n" +" Causes the tracing thread to pause until it is attached by a\n" +" debugger and continued. This is mostly for debugging crashes\n" +" early during boot, and should be pretty much obsoleted by\n" +" the debug switch.\n\n" +); + +static int __init uml_honeypot_setup(char *line, int *add) +{ + jail_setup("", add); + honeypot = 1; + return 0; +} +__uml_setup("honeypot", uml_honeypot_setup, +"honeypot\n" +" This makes UML put process stacks in the same location as they are\n" +" on the host, allowing expoits such as stack smashes to work against\n" +" UML. This implies 'jail'.\n\n" +); + +/* + * 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: + */ -- cgit v1.2.3 From 38690b28ad7179dd6ea6b08623bded40cbdc0a3d Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 04:59:43 -0500 Subject: Added skas/mem_user.c and tt/gdb.c --- arch/um/kernel/skas/mem_user.c | 95 +++++++++++++++ arch/um/kernel/tt/gdb.c | 267 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 362 insertions(+) create mode 100644 arch/um/kernel/skas/mem_user.c create mode 100644 arch/um/kernel/tt/gdb.c diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c new file mode 100644 index 000000000000..7d12cdd621ae --- /dev/null +++ b/arch/um/kernel/skas/mem_user.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include "mem_user.h" +#include "user.h" +#include "os.h" +#include "proc_mm.h" + +void map(int fd, unsigned long virt, unsigned long phys, unsigned long len, + int r, int w, int x) +{ + struct proc_mm_op map; + struct mem_region *region; + int prot, n; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + region = phys_region(phys); + + map = ((struct proc_mm_op) { .op = MM_MMAP, + .u = + { .mmap = + { .addr = virt, + .len = len, + .prot = prot, + .flags = MAP_SHARED | + MAP_FIXED, + .fd = region->fd, + .offset = phys_offset(phys) + } } } ); + n = os_write_file(fd, (char *) &map, sizeof(map)); + if(n != sizeof(map)) + printk("map : /proc/mm map failed, errno = %d\n", errno); +} + +int unmap(int fd, void *addr, int len) +{ + struct proc_mm_op unmap; + int n; + + unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, + .u = + { .munmap = + { .addr = (unsigned long) addr, + .len = len } } } ); + n = os_write_file(fd, (char *) &unmap, sizeof(unmap)); + if((n != 0) && (n != sizeof(unmap))) + return(-errno); + return(0); +} + +int protect(int fd, unsigned long addr, unsigned long len, int r, int w, + int x, int must_succeed) +{ + struct proc_mm_op protect; + int prot, n; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + + protect = ((struct proc_mm_op) { .op = MM_MPROTECT, + .u = + { .mprotect = + { .addr = (unsigned long) addr, + .len = len, + .prot = prot } } } ); + + n = os_write_file(fd, (char *) &protect, sizeof(protect)); + if((n != 0) && (n != sizeof(protect))){ + if(must_succeed) + panic("protect failed, errno = %d", errno); + return(-errno); + } + return(0); +} + +void before_mem_skas(unsigned long unused) +{ +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c new file mode 100644 index 000000000000..1e819be2539b --- /dev/null +++ b/arch/um/kernel/tt/gdb.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include "uml-config.h" +#include "kern_constants.h" +#include "chan_user.h" +#include "init.h" +#include "user.h" +#include "debug.h" +#include "kern_util.h" +#include "user_util.h" +#include "tt.h" +#include "sysdep/thread.h" + +extern int debugger_pid; +extern int debugger_fd; +extern int debugger_parent; + +int detach(int pid, int sig) +{ + return(ptrace(PTRACE_DETACH, pid, 0, sig)); +} + +int attach(int pid) +{ + int err; + + err = ptrace(PTRACE_ATTACH, pid, 0, 0); + if(err < 0) return(-errno); + else return(err); +} + +int cont(int pid) +{ + return(ptrace(PTRACE_CONT, pid, 0, 0)); +} + +#ifdef CONFIG_PT_PROXY + +int debugger_signal(int status, pid_t pid) +{ + return(debugger_proxy(status, pid)); +} + +void child_signal(pid_t pid, int status) +{ + child_proxy(pid, status); +} + +static void gdb_announce(char *dev_name, int dev) +{ + printf("gdb assigned device '%s'\n", dev_name); +} + +static struct chan_opts opts = { + announce : gdb_announce, + xterm_title : "UML kernel debugger", + raw : 0, + tramp_stack : 0, + in_kernel : 0, +}; + +/* Accessed by the tracing thread, which automatically serializes access */ +static void *xterm_data; +static int xterm_fd; + +extern void *xterm_init(char *, int, struct chan_opts *); +extern int xterm_open(int, int, int, void *); +extern void xterm_close(int, void *); + +int open_gdb_chan(void) +{ + char stack[UM_KERN_PAGE_SIZE]; + + opts.tramp_stack = (unsigned long) stack; + xterm_data = xterm_init("", 0, &opts); + xterm_fd = xterm_open(1, 1, 1, xterm_data); + return(xterm_fd); +} + +static void exit_debugger_cb(void *unused) +{ + if(debugger_pid != -1){ + if(gdb_pid != -1){ + fake_child_exit(); + gdb_pid = -1; + } + else kill_child_dead(debugger_pid); + debugger_pid = -1; + if(debugger_parent != -1) + detach(debugger_parent, SIGINT); + } + if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data); +} + +static void exit_debugger(void) +{ + initial_thread_cb(exit_debugger_cb, NULL); +} + +__uml_exitcall(exit_debugger); + +struct gdb_data { + char *str; + int err; +}; + +static void config_gdb_cb(void *arg) +{ + struct gdb_data *data = arg; + struct task_struct *task; + int pid; + + data->err = -1; + if(debugger_pid != -1) exit_debugger_cb(NULL); + if(!strncmp(data->str, "pid,", strlen("pid,"))){ + data->str += strlen("pid,"); + pid = strtoul(data->str, NULL, 0); + task = cpu_tasks[0].task; + debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0); + if(debugger_pid != -1){ + data->err = 0; + gdb_pid = pid; + } + return; + } + data->err = 0; + debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); + init_proxy(debugger_pid, 0, 0); +} + +int gdb_config(char *str) +{ + struct gdb_data data; + + if(*str++ != '=') return(-1); + data.str = str; + initial_thread_cb(config_gdb_cb, &data); + return(data.err); +} + +void remove_gdb_cb(void *unused) +{ + exit_debugger_cb(NULL); +} + +int gdb_remove(char *unused) +{ + initial_thread_cb(remove_gdb_cb, NULL); + return(0); +} + +void signal_usr1(int sig) +{ + if(debugger_pid != -1){ + printk(UM_KERN_ERR "The debugger is already running\n"); + return; + } + debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); + init_proxy(debugger_pid, 0, 0); +} + +int init_ptrace_proxy(int idle_pid, int startup, int stop) +{ + int pid, status; + + pid = start_debugger(linux_prog, startup, stop, &debugger_fd); + status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); + if(pid < 0){ + cont(idle_pid); + return(-1); + } + init_proxy(pid, 1, status); + return(pid); +} + +int attach_debugger(int idle_pid, int pid, int stop) +{ + int status = 0, err; + + err = attach(pid); + if(err < 0){ + printf("Failed to attach pid %d, errno = %d\n", pid, -err); + return(-1); + } + if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); + init_proxy(pid, 1, status); + return(pid); +} + +#ifdef notdef /* Put this back in when it does something useful */ +static int __init uml_gdb_init_setup(char *line, int *add) +{ + gdb_init = uml_strdup(line); + return 0; +} + +__uml_setup("gdb=", uml_gdb_init_setup, +"gdb=\n\n" +); +#endif + +static int __init uml_gdb_pid_setup(char *line, int *add) +{ + gdb_pid = strtoul(line, NULL, 0); + *add = 0; + return 0; +} + +__uml_setup("gdb-pid=", uml_gdb_pid_setup, +"gdb-pid=\n" +" gdb-pid is used to attach an external debugger to UML. This may be\n" +" an already-running gdb or a debugger-like process like strace.\n\n" +); + +#else + +int debugger_signal(int status, pid_t pid){ return(0); } +void child_signal(pid_t pid, int status){ } +int init_ptrace_proxy(int idle_pid, int startup, int stop) +{ + printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); + kill_child_dead(idle_pid); + exit(1); +} + +void signal_usr1(int sig) +{ + printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); +} + +int attach_debugger(int idle_pid, int pid, int stop) +{ + printk(KERN_ERR "attach_debugger called when CONFIG_PT_PROXY " + "is off\n"); + return(-1); +} + +int config_gdb(char *str) +{ + return(-1); +} + +int remove_gdb(void) +{ + return(-1); +} + +int init_parent_proxy(int pid) +{ + return(-1); +} + +void debugger_parent_signal(int status, int pid) +{ +} + +#endif -- cgit v1.2.3 From 3817da1371de54bca1b8a3980647f3bfc6f4858b Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 08:54:16 -0500 Subject: Added the uaccess changes from the skas merge. --- arch/um/include/um_uaccess.h | 73 +++++++++++ arch/um/kernel/skas/include/uaccess.h | 239 ++++++++++++++++++++++++++++++++++ arch/um/kernel/tt/Makefile | 2 +- arch/um/kernel/tt/include/uaccess.h | 119 +++++++++++++++++ arch/um/kernel/tt/uaccess_user.c | 126 ++++++++++++++++++ arch/um/kernel/uaccess_user.c | 126 ------------------ include/asm-um/uaccess.h | 100 +------------- 7 files changed, 560 insertions(+), 225 deletions(-) create mode 100644 arch/um/include/um_uaccess.h create mode 100644 arch/um/kernel/skas/include/uaccess.h create mode 100644 arch/um/kernel/tt/include/uaccess.h create mode 100644 arch/um/kernel/tt/uaccess_user.c delete mode 100644 arch/um/kernel/uaccess_user.c diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h new file mode 100644 index 000000000000..b12802b8cde7 --- /dev/null +++ b/arch/um/include/um_uaccess.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __ARCH_UM_UACCESS_H +#define __ARCH_UM_UACCESS_H + +#include "linux/config.h" +#include "choose-mode.h" + +#ifdef CONFIG_MODE_TT +#include "../kernel/tt/include/uaccess.h" +#endif + +#ifdef CONFIG_MODE_SKAS +#include "../kernel/skas/include/uaccess.h" +#endif + +#define access_ok(type, addr, size) \ + CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size) + +static inline int verify_area(int type, const void * addr, unsigned long size) +{ + return(CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr, + size)); +} + +static inline int copy_from_user(void *to, const void *from, int n) +{ + return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to, + from, n)); +} + +static inline int copy_to_user(void *to, const void *from, int n) +{ + return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to, + from, n)); +} + +static inline int strncpy_from_user(char *dst, const char *src, int count) +{ + return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas, + dst, src, count)); +} + +static inline int __clear_user(void *mem, int len) +{ + return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len)); +} + +static inline int clear_user(void *mem, int len) +{ + return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len)); +} + +static inline int strnlen_user(void *str, int len) +{ + return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len)); +} + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h new file mode 100644 index 000000000000..7657c828f3c4 --- /dev/null +++ b/arch/um/kernel/skas/include/uaccess.h @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_UACCESS_H +#define __SKAS_UACCESS_H + +#include "linux/string.h" +#include "linux/sched.h" +#include "asm/processor.h" +#include "asm/pgtable.h" +#include "asm/errno.h" +#include "asm/current.h" +#include "asm/a.out.h" +#include "kern_util.h" + +#define access_ok_skas(type, addr, size) \ + ((segment_eq(get_fs(), KERNEL_DS)) || \ + (((unsigned long) (addr) < TASK_SIZE) && \ + ((unsigned long) (addr) + (size) < TASK_SIZE))) + +static inline int verify_area_skas(int type, const void * addr, + unsigned long size) +{ + return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); +} + +extern unsigned long handle_page_fault(unsigned long address, + unsigned long ip, int is_write, + int is_user, int *code_out); + +extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt, + pte_t *pte_out); + +static inline unsigned long maybe_map(unsigned long virt, int is_write) +{ + pte_t pte; + + void *phys = um_virt_to_phys(current, virt, &pte); + int dummy_code; + + if(IS_ERR(phys) || (is_write && !pte_write(pte))){ + if(!handle_page_fault(virt, 0, is_write, 0, &dummy_code)) + return(0); + phys = um_virt_to_phys(current, virt, NULL); + } + return((unsigned long) __va((unsigned long) phys)); +} + +static inline int buffer_op(unsigned long addr, int len, + int (*op)(unsigned long addr, int len, void *arg), + void *arg) +{ + int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); + int remain = len, n; + + n = (*op)(addr, size, arg); + if(n != 0) + return(n < 0 ? remain : 0); + + addr += size; + remain -= size; + if(remain == 0) + return(0); + + while(addr < ((addr + remain) & PAGE_MASK)){ + n = (*op)(addr, PAGE_SIZE, arg); + if(n != 0) + return(n < 0 ? remain : 0); + + addr += PAGE_SIZE; + remain -= PAGE_SIZE; + } + if(remain == 0) + return(0); + + n = (*op)(addr, remain, arg); + if(n != 0) + return(n < 0 ? remain : 0); + return(0); +} + +static inline int copy_chunk_from_user(unsigned long from, int len, void *arg) +{ + unsigned long *to_ptr = arg, to = *to_ptr; + + from = maybe_map(from, 0); + if(from == 0) + return(-1); + + memcpy((void *) to, (void *) from, len); + *to_ptr += len; + return(0); +} + +static inline int copy_from_user_skas(void *to, const void *from, int n) +{ + if(segment_eq(get_fs(), KERNEL_DS)){ + memcpy(to, from, n); + return(0); + } + + return(access_ok_skas(VERIFY_READ, from, n) ? + buffer_op((unsigned long) from, n, copy_chunk_from_user, &to) : + n); +} + +static inline int copy_chunk_to_user(unsigned long to, int len, void *arg) +{ + unsigned long *from_ptr = arg, from = *from_ptr; + + to = maybe_map(to, 1); + if(to == 0) + return(-1); + + memcpy((void *) to, (void *) from, len); + *from_ptr += len; + return(0); +} + +static inline int copy_to_user_skas(void *to, const void *from, int n) +{ + if(segment_eq(get_fs(), KERNEL_DS)){ + memcpy(to, from, n); + return(0); + } + + return(access_ok_skas(VERIFY_WRITE, to, n) ? + buffer_op((unsigned long) to, n, copy_chunk_to_user, &from) : + n); +} + +static inline int strncpy_chunk_from_user(unsigned long from, int len, + void *arg) +{ + char **to_ptr = arg, *to = *to_ptr; + int n; + + from = maybe_map(from, 0); + if(from == 0) + return(-1); + + strncpy(to, (void *) from, len); + n = strnlen(to, len); + *to_ptr += n; + + if(n < len) + return(1); + return(0); +} + +static inline int strncpy_from_user_skas(char *dst, const char *src, int count) +{ + int n; + char *ptr = dst; + + if(segment_eq(get_fs(), KERNEL_DS)){ + strncpy(dst, src, count); + return(strnlen(dst, count)); + } + + if(!access_ok_skas(VERIFY_READ, src, 1)) + return(-EFAULT); + + n = buffer_op((unsigned long) src, count, strncpy_chunk_from_user, + &ptr); + if(n != 0) + return(-EFAULT); + return(strnlen(dst, count)); +} + +static inline int clear_chunk(unsigned long addr, int len, void *unused) +{ + addr = maybe_map(addr, 1); + if(addr == 0) + return(-1); + + memset((void *) addr, 0, len); + return(0); +} + +static inline int __clear_user_skas(void *mem, int len) +{ + return(buffer_op((unsigned long) mem, len, clear_chunk, NULL)); +} + +static inline int clear_user_skas(void *mem, int len) +{ + if(segment_eq(get_fs(), KERNEL_DS)){ + memset(mem, 0, len); + return(0); + } + + return(access_ok_skas(VERIFY_WRITE, mem, len) ? + buffer_op((unsigned long) mem, len, clear_chunk, NULL) : len); +} + +static inline int strnlen_chunk(unsigned long str, int len, void *arg) +{ + int *len_ptr = arg, n; + + str = maybe_map(str, 0); + if(str == 0) + return(-1); + + n = strnlen((void *) str, len); + *len_ptr += n; + + if(n < len) + return(1); + return(0); +} + +static inline int strnlen_user_skas(void *str, int len) +{ + int count = 0, n; + + if(segment_eq(get_fs(), KERNEL_DS)) + return(strnlen(str, len) + 1); + + n = buffer_op((unsigned long) str, len, strnlen_chunk, &count); + if(n == 0) + return(count + 1); + return(-EFAULT); +} + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 8b0dd44a11c6..401ae1f4f59d 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -4,7 +4,7 @@ # obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o mem.o process_kern.o \ - syscall_user.o tracer.o + syscall_user.o tracer.o uaccess_user.o obj-$(CONFIG_PT_PROXY) += ptproxy/ diff --git a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h new file mode 100644 index 000000000000..7eae8c819d01 --- /dev/null +++ b/arch/um/kernel/tt/include/uaccess.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TT_UACCESS_H +#define __TT_UACCESS_H + +#include "linux/string.h" +#include "linux/sched.h" +#include "asm/processor.h" +#include "asm/errno.h" +#include "asm/current.h" +#include "asm/a.out.h" + +#define ABOVE_KMEM (16 * 1024 * 1024) + +extern unsigned long end_vm; +extern unsigned long uml_physmem; + +#define under_task_size(addr, size) \ + (((unsigned long) (addr) < TASK_SIZE) && \ + (((unsigned long) (addr) + (size)) < TASK_SIZE)) + +#define is_stack(addr, size) \ + (((unsigned long) (addr) < STACK_TOP) && \ + ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \ + (((unsigned long) (addr) + (size)) <= STACK_TOP)) + +#define access_ok_tt(type, addr, size) \ + ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \ + (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ + (under_task_size(addr, size) || is_stack(addr, size)))) + +static inline int verify_area_tt(int type, const void * addr, + unsigned long size) +{ + return(access_ok_tt(type, addr, size) ? 0 : -EFAULT); +} + +extern unsigned long get_fault_addr(void); + +extern int __do_copy_from_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher); + +static inline int copy_from_user_tt(void *to, const void *from, int n) +{ + return(access_ok_tt(VERIFY_READ, from, n) ? + __do_copy_from_user(to, from, n, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher) : n); +} + +extern int __do_copy_to_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher); + +static inline int copy_to_user_tt(void *to, const void *from, int n) +{ + return(access_ok_tt(VERIFY_WRITE, to, n) ? + __do_copy_to_user(to, from, n, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher) : n); +} + +extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, + void **fault_addr, void **fault_catcher); + +static inline int strncpy_from_user_tt(char *dst, const char *src, int count) +{ + int n; + + if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT); + n = __do_strncpy_from_user(dst, src, count, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher); + if(n < 0) return(-EFAULT); + return(n); +} + +extern int __do_clear_user(void *mem, size_t len, void **fault_addr, + void **fault_catcher); + +static inline int __clear_user_tt(void *mem, int len) +{ + return(__do_clear_user(mem, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +static inline int clear_user_tt(void *mem, int len) +{ + return(access_ok_tt(VERIFY_WRITE, mem, len) ? + __do_clear_user(mem, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher) : len); +} + +extern int __do_strnlen_user(const char *str, unsigned long n, + void **fault_addr, void **fault_catcher); + +static inline int strnlen_user_tt(void *str, int len) +{ + return(__do_strnlen_user(str, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +#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/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c new file mode 100644 index 000000000000..639ea1c4be37 --- /dev/null +++ b/arch/um/kernel/tt/uaccess_user.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) + * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include "user_util.h" + +static unsigned long __do_user_copy(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher, + void (*op)(void *to, const void *from, + int n), int *faulted_out) +{ + unsigned long *faddrp = (unsigned long *) fault_addr, ret; + + jmp_buf jbuf; + *fault_catcher = &jbuf; + if(setjmp(jbuf) == 0){ + (*op)(to, from, n); + ret = 0; + *faulted_out = 0; + } + else { + ret = *faddrp; + *faulted_out = 1; + } + *fault_addr = NULL; + *fault_catcher = NULL; + return ret; +} + +static void __do_copy(void *to, const void *from, int n) +{ + memcpy(to, from, n); +} + +int __do_copy_from_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + int faulted; + + fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, + __do_copy, &faulted); + if(!faulted) return(0); + else return(n - (fault - (unsigned long) from)); +} + + +int __do_copy_to_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + int faulted; + + fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, + __do_copy, &faulted); + if(!faulted) return(0); + else return(n - (fault - (unsigned long) to)); +} + +static void __do_strncpy(void *dst, const void *src, int count) +{ + strncpy(dst, src, count); +} + +int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + int faulted; + + fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, + __do_strncpy, &faulted); + if(!faulted) return(strlen(dst)); + else return(-1); +} + +static void __do_clear(void *to, const void *from, int n) +{ + memset(to, 0, n); +} + +int __do_clear_user(void *mem, unsigned long len, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + int faulted; + + fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, + __do_clear, &faulted); + if(!faulted) return(0); + else return(len - (fault - (unsigned long) mem)); +} + +int __do_strnlen_user(const char *str, unsigned long n, + void **fault_addr, void **fault_catcher) +{ + int ret; + unsigned long *faddrp = (unsigned long *)fault_addr; + jmp_buf jbuf; + + *fault_catcher = &jbuf; + if(setjmp(jbuf) == 0){ + ret = strlen(str) + 1; + } + else { + ret = *faddrp - (unsigned long) str; + } + *fault_addr = NULL; + *fault_catcher = NULL; + return ret; +} + +/* + * 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/uaccess_user.c b/arch/um/kernel/uaccess_user.c deleted file mode 100644 index 639ea1c4be37..000000000000 --- a/arch/um/kernel/uaccess_user.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include "user_util.h" - -static unsigned long __do_user_copy(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher, - void (*op)(void *to, const void *from, - int n), int *faulted_out) -{ - unsigned long *faddrp = (unsigned long *) fault_addr, ret; - - jmp_buf jbuf; - *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ - (*op)(to, from, n); - ret = 0; - *faulted_out = 0; - } - else { - ret = *faddrp; - *faulted_out = 1; - } - *fault_addr = NULL; - *fault_catcher = NULL; - return ret; -} - -static void __do_copy(void *to, const void *from, int n) -{ - memcpy(to, from, n); -} - -int __do_copy_from_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, - __do_copy, &faulted); - if(!faulted) return(0); - else return(n - (fault - (unsigned long) from)); -} - - -int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, - __do_copy, &faulted); - if(!faulted) return(0); - else return(n - (fault - (unsigned long) to)); -} - -static void __do_strncpy(void *dst, const void *src, int count) -{ - strncpy(dst, src, count); -} - -int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, - __do_strncpy, &faulted); - if(!faulted) return(strlen(dst)); - else return(-1); -} - -static void __do_clear(void *to, const void *from, int n) -{ - memset(to, 0, n); -} - -int __do_clear_user(void *mem, unsigned long len, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, - __do_clear, &faulted); - if(!faulted) return(0); - else return(len - (fault - (unsigned long) mem)); -} - -int __do_strnlen_user(const char *str, unsigned long n, - void **fault_addr, void **fault_catcher) -{ - int ret; - unsigned long *faddrp = (unsigned long *)fault_addr; - jmp_buf jbuf; - - *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ - ret = strlen(str) + 1; - } - else { - ret = *faddrp - (unsigned long) str; - } - *fault_addr = NULL; - *fault_catcher = NULL; - return ret; -} - -/* - * 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/include/asm-um/uaccess.h b/include/asm-um/uaccess.h index a8a7dfb7e4c8..e1dfea108857 100644 --- a/include/asm-um/uaccess.h +++ b/include/asm-um/uaccess.h @@ -1,18 +1,11 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ #ifndef __UM_UACCESS_H #define __UM_UACCESS_H -#include "linux/string.h" -#include "linux/sched.h" -#include "asm/processor.h" -#include "asm/errno.h" -#include "asm/current.h" -#include "asm/a.out.h" - #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -26,8 +19,6 @@ #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) -#define ABOVE_KMEM (16 * 1024 * 1024) - #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) #define USER_DS MAKE_MM_SEG(TASK_SIZE) @@ -35,56 +26,12 @@ #define get_fs() (current_thread_info()->addr_limit) #define set_fs(x) (current_thread_info()->addr_limit = (x)) -extern unsigned long end_vm; -extern unsigned long uml_physmem; - -#define under_task_size(addr, size) \ - (((unsigned long) (addr) < TASK_SIZE) && \ - (((unsigned long) (addr) + (size)) < TASK_SIZE)) - -#define is_stack(addr, size) \ - (((unsigned long) (addr) < STACK_TOP) && \ - ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \ - (((unsigned long) (addr) + (size)) <= STACK_TOP)) - #define segment_eq(a, b) ((a).seg == (b).seg) -#define access_ok(type, addr, size) \ - ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \ - (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ - (under_task_size(addr, size) || is_stack(addr, size)))) - -static inline int verify_area(int type, const void * addr, unsigned long size) -{ - return(access_ok(type, addr, size) ? 0 : -EFAULT); -} - -extern unsigned long get_fault_addr(void); - -extern int __do_copy_from_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher); - -static inline int copy_from_user(void *to, const void *from, int n) -{ - return(access_ok(VERIFY_READ, from, n) ? - __do_copy_from_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} +#include "um_uaccess.h" #define __copy_from_user(to, from, n) copy_from_user(to, from, n) -extern int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher); - -static inline int copy_to_user(void *to, const void *from, int n) -{ - return(access_ok(VERIFY_WRITE, to, n) ? - __do_copy_to_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} - #define __copy_to_user(to, from, n) copy_to_user(to, from, n) #define __get_user(x, ptr) \ @@ -128,49 +75,6 @@ static inline int copy_to_user(void *to, const void *from, int n) __put_user(x, private_ptr) : -EFAULT); \ }) -extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, - void **fault_addr, void **fault_catcher); - -static inline int strncpy_from_user(char *dst, const char *src, int count) -{ - int n; - - if(!access_ok(VERIFY_READ, src, 1)) return(-EFAULT); - n = __do_strncpy_from_user(dst, src, count, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher); - if(n < 0) return(-EFAULT); - return(n); -} - -extern int __do_clear_user(void *mem, size_t len, void **fault_addr, - void **fault_catcher); - -static inline int __clear_user(void *mem, int len) -{ - return(__do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -static inline int clear_user(void *mem, int len) -{ - return(access_ok(VERIFY_WRITE, mem, len) ? - __do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : len); -} - -extern int __do_strnlen_user(const char *str, unsigned long n, - void **fault_addr, void **fault_catcher); - -static inline int strnlen_user(void *str, int len) -{ - return(__do_strnlen_user(str, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - #define strlen_user(str) strnlen_user(str, ~0UL >> 1) struct exception_table_entry -- cgit v1.2.3 From 8133aaa196d963de7a2ff543cd35653cbb35d96b Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 11:38:56 -0500 Subject: A number of small fixes for the uaccess merge. --- arch/um/include/kern_util.h | 5 +- arch/um/include/um_uaccess.h | 2 +- arch/um/kernel/Makefile | 2 +- arch/um/kernel/process_kern.c | 22 ++++--- arch/um/kernel/skas/include/uaccess.h | 6 +- arch/um/kernel/trap_kern.c | 113 +++++++++++++++++++--------------- arch/um/kernel/tt/include/uaccess.h | 2 +- 7 files changed, 82 insertions(+), 70 deletions(-) diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 1567cb6a79dd..f94731350cd8 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -33,9 +33,8 @@ extern int do_signal(int error); extern int is_stack_fault(unsigned long sp); extern unsigned long segv(unsigned long address, unsigned long ip, int is_write, int is_user, void *sc); -extern unsigned long handle_page_fault(unsigned long address, unsigned long ip, - int is_write, int is_user, - int *code_out); +extern int handle_page_fault(unsigned long address, unsigned long ip, + int is_write, int is_user, int *code_out); extern void syscall_ready(void); extern void set_tracing(void *t, int tracing); extern int is_tracing(void *task); diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h index b12802b8cde7..41afa3a8f086 100644 --- a/arch/um/include/um_uaccess.h +++ b/arch/um/include/um_uaccess.h @@ -54,7 +54,7 @@ static inline int clear_user(void *mem, int len) return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len)); } -static inline int strnlen_user(void *str, int len) +static inline int strnlen_user(const void *str, int len) { return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len)); } diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 889fd82f1638..9fb50e9da6c6 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -10,7 +10,7 @@ obj-y = config.o exec_kern.o exitcode.o frame_kern.o frame.o helper.o \ process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \ syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \ - time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ + time_kern.o tlb.o trap_kern.o trap_user.o um_arch.o \ umid.o user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 991b2097dc9d..41a54e742a98 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -222,21 +222,25 @@ int page_mask(void) return(PAGE_MASK); } -unsigned long um_virt_to_phys(void *t, unsigned long addr) +void *um_virt_to_phys(struct task_struct *task, unsigned long addr, + pte_t *pte_out) { - struct task_struct *task; pgd_t *pgd; pmd_t *pmd; pte_t *pte; - task = t; - if(task->mm == NULL) return(0xffffffff); + if(task->mm == NULL) + return(ERR_PTR(-EINVAL)); pgd = pgd_offset(task->mm, addr); pmd = pmd_offset(pgd, addr); - if(!pmd_present(*pmd)) return(0xffffffff); + if(!pmd_present(*pmd)) + return(ERR_PTR(-EINVAL)); pte = pte_offset_kernel(pmd, addr); - if(!pte_present(*pte)) return(0xffffffff); - return((pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK)); + if(!pte_present(*pte)) + return(ERR_PTR(-EINVAL)); + if(pte_out != NULL) + *pte_out = *pte; + return((void *) (pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK)); } char *current_cmd(void) @@ -244,8 +248,8 @@ char *current_cmd(void) #if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM) return("(Unknown)"); #else - unsigned long addr = um_virt_to_phys(current, current->mm->arg_start); - return addr == 0xffffffff? "(Unknown)": __va(addr); + void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL); + return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr); #endif } diff --git a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h index 7657c828f3c4..2f266a26ee57 100644 --- a/arch/um/kernel/skas/include/uaccess.h +++ b/arch/um/kernel/skas/include/uaccess.h @@ -26,10 +26,6 @@ static inline int verify_area_skas(int type, const void * addr, return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); } -extern unsigned long handle_page_fault(unsigned long address, - unsigned long ip, int is_write, - int is_user, int *code_out); - extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt, pte_t *pte_out); @@ -212,7 +208,7 @@ static inline int strnlen_chunk(unsigned long str, int len, void *arg) return(0); } -static inline int strnlen_user_skas(void *str, int len) +static inline int strnlen_user_skas(const void *str, int len) { int count = 0, n; diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 5a9ed1c89478..b93c2b4eb9c7 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -4,6 +4,7 @@ */ #include "linux/kernel.h" +#include "asm/errno.h" #include "linux/sched.h" #include "linux/mm.h" #include "linux/spinlock.h" @@ -19,41 +20,36 @@ #include "kern_util.h" #include "kern.h" #include "chan_kern.h" -#include "debug.h" #include "mconsole_kern.h" #include "2_5compat.h" -extern int nsyscalls; - -unsigned long segv(unsigned long address, unsigned long ip, int is_write, - int is_user, void *sc) +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; struct vm_area_struct *vma; - struct siginfo si; - void *catcher; pgd_t *pgd; pmd_t *pmd; pte_t *pte; unsigned long page; + int err = -EFAULT; - if((address >= start_vm) && (address < end_vm)){ - flush_tlb_kernel_vm(); - return(0); - } - if(mm == NULL) panic("Segfault with no mm"); - catcher = current->thread.fault_catcher; - si.si_code = SEGV_MAPERR; + *code_out = SEGV_MAPERR; down_read(&mm->mmap_sem); vma = find_vma(mm, address); - if(!vma) goto bad; - else if(vma->vm_start <= address) goto good_area; - else if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad; - else if(expand_stack(vma, address)) goto bad; + if(!vma) + goto out; + else if(vma->vm_start <= address) + goto good_area; + else if(!(vma->vm_flags & VM_GROWSDOWN)) + goto out; + else if(expand_stack(vma, address)) + goto out; good_area: - si.si_code = SEGV_ACCERR; - if(is_write && !(vma->vm_flags & VM_WRITE)) goto bad; + *code_out = SEGV_ACCERR; + if(is_write && !(vma->vm_flags & VM_WRITE)) + goto out; page = address & PAGE_MASK; if(page == (unsigned long) current->thread_info + PAGE_SIZE) panic("Kernel stack overflow"); @@ -69,8 +65,10 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, current->maj_flt++; break; case VM_FAULT_SIGBUS: - goto do_sigbus; + err = -EACCES; + goto out; case VM_FAULT_OOM: + err = -ENOMEM; goto out_of_memory; default: BUG(); @@ -80,43 +78,45 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, *pte = pte_mkyoung(*pte); if(pte_write(*pte)) *pte = pte_mkdirty(*pte); flush_tlb_page(vma, page); + err = 0; + out: up_read(&mm->mmap_sem); - return(0); -do_sigbus: - up_read(&mm->mmap_sem); + return(err); - /* - * Send a sigbus, regardless of whether we were in kernel - * or user mode. - */ - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRERR; - si.si_addr = (void *)address; - force_sig_info(SIGBUS, &si, current); - if(!is_user) goto bad; - return(0); /* * We ran out of memory, or some other thing happened to us that made * us unable to handle the page fault gracefully. */ out_of_memory: - up_read(&mm->mmap_sem); if (current->pid == 1) { + up_read(&mm->mmap_sem); yield(); down_read(&mm->mmap_sem); goto survive; } - printk("VM: killing process %s\n", current->comm); - if(is_user) - do_exit(SIGKILL); + err = -ENOMEM; + goto out; +} + +unsigned long segv(unsigned long address, unsigned long ip, int is_write, + int is_user, void *sc) +{ + struct siginfo si; + void *catcher; + int err; - /* Fall through to bad */ + if(!is_user && (address >= start_vm) && (address < end_vm)){ + flush_tlb_kernel_vm(); + return(0); + } + if(current->mm == NULL) panic("Segfault with no mm"); + err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); - bad: - if(catcher != NULL){ + catcher = current->thread.fault_catcher; + if(!err) + return(0); + else if(catcher != NULL){ current->thread.fault_addr = (void *) address; - up_read(&mm->mmap_sem); do_longjmp(catcher, 1); } else if(current->thread.fault_addr != NULL){ @@ -125,15 +125,28 @@ out_of_memory: else if(arch_fixup(ip, sc)) return(0); - if(!is_user) + if(!is_user) panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", address, ip); - si.si_signo = SIGSEGV; - si.si_addr = (void *) address; - current->thread.cr2 = address; - current->thread.err = is_write; - force_sig_info(SIGSEGV, &si, current); - up_read(&mm->mmap_sem); + + if(err == -EACCES){ + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_code = BUS_ADRERR; + si.si_addr = (void *)address; + force_sig_info(SIGBUS, &si, current); + } + else if(err == -ENOMEM){ + printk("VM: killing process %s\n", current->comm); + do_exit(SIGKILL); + } + else { + si.si_signo = SIGSEGV; + si.si_addr = (void *) address; + current->thread.cr2 = address; + current->thread.err = is_write; + force_sig_info(SIGSEGV, &si, current); + } return(0); } diff --git a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h index 7eae8c819d01..902de9f3783c 100644 --- a/arch/um/kernel/tt/include/uaccess.h +++ b/arch/um/kernel/tt/include/uaccess.h @@ -98,7 +98,7 @@ static inline int clear_user_tt(void *mem, int len) extern int __do_strnlen_user(const char *str, unsigned long n, void **fault_addr, void **fault_catcher); -static inline int strnlen_user_tt(void *str, int len) +static inline int strnlen_user_tt(const void *str, int len) { return(__do_strnlen_user(str, len, ¤t->thread.fault_addr, -- cgit v1.2.3 From eccc45bfa711ddeae385ec29ca7228259bcd9f5c Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 12:00:31 -0500 Subject: Applied the sigcontext changes in the skas code. --- arch/um/include/sigcontext.h | 2 - arch/um/kernel/frame_kern.c | 17 +++-- arch/um/kernel/signal_kern.c | 19 +++-- arch/um/kernel/skas/Makefile | 6 +- arch/um/kernel/skas/sys-i386/Makefile | 17 +++++ arch/um/kernel/skas/sys-i386/sigcontext.c | 114 ++++++++++++++++++++++++++++++ arch/um/kernel/tt/Makefile | 7 +- arch/um/kernel/tt/sys-i386/Makefile | 17 +++++ arch/um/kernel/tt/sys-i386/sigcontext.c | 59 ++++++++++++++++ arch/um/sys-i386/sigcontext.c | 39 ---------- 10 files changed, 242 insertions(+), 55 deletions(-) create mode 100644 arch/um/kernel/skas/sys-i386/Makefile create mode 100644 arch/um/kernel/skas/sys-i386/sigcontext.c create mode 100644 arch/um/kernel/tt/sys-i386/Makefile create mode 100644 arch/um/kernel/tt/sys-i386/sigcontext.c diff --git a/arch/um/include/sigcontext.h b/arch/um/include/sigcontext.h index 1d2b195bc5f8..59816ca7a8df 100644 --- a/arch/um/include/sigcontext.h +++ b/arch/um/include/sigcontext.h @@ -9,8 +9,6 @@ #include "sysdep/sigcontext.h" extern int sc_size(void *data); -extern int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data); -extern int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data); extern void sc_to_sc(void *to_ptr, void *from_ptr); #endif diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c index 8726b2a1a439..b7abbf55498c 100644 --- a/arch/um/kernel/frame_kern.c +++ b/arch/um/kernel/frame_kern.c @@ -9,6 +9,8 @@ #include "frame_kern.h" #include "sigcontext.h" #include "sysdep/ptrace.h" +#include "choose-mode.h" +#include "mode.h" static int copy_restorer(void (*restorer)(void), unsigned long start, unsigned long sr_index, int sr_relative) @@ -25,6 +27,15 @@ static int copy_restorer(void (*restorer)(void), unsigned long start, sizeof(restorer))); } +static int copy_sc_to_user(void *to, struct pt_regs *from) +{ + return(CHOOSE_MODE(copy_sc_to_user_tt(to, from->regs.mode.tt, + &signal_frame_sc_sr.arch), + copy_sc_to_user_skas(to, &from->regs, + current->thread.cr2, + current->thread.err))); +} + int setup_signal_stack_si(unsigned long stack_top, int sig, unsigned long handler, void (*restorer)(void), struct pt_regs *regs, siginfo_t *info, @@ -43,8 +54,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, if(restorer == NULL) panic("setup_signal_stack_si - no restorer"); - if(copy_sc_to_user((void *) sc, regs->regs.mode.tt, - &signal_frame_sc.arch) || + if(copy_sc_to_user((void *) sc, regs) || copy_to_user((void *) start, signal_frame_si.common.data, signal_frame_si.common.len) || copy_to_user((void *) (start + signal_frame_si.common.sig_index), @@ -86,8 +96,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, if(copy_to_user((void *) start, frame->data, frame->len) || copy_to_user((void *) (start + frame->sig_index), &sig, sizeof(sig)) || - copy_sc_to_user(user_sc, regs->regs.mode.tt, - &signal_frame_sc.arch) || + copy_sc_to_user(user_sc, regs) || copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) || copy_to_user((void *) sigs, &mask->sig[1], sig_size) || copy_restorer(restorer, start, frame->sr_index, frame->sr_relative)) diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 83db897787ee..355810656aa0 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -23,6 +23,7 @@ #include "kern.h" #include "frame_kern.h" #include "sigcontext.h" +#include "mode.h" EXPORT_SYMBOL(block_signals); EXPORT_SYMBOL(unblock_signals); @@ -171,7 +172,7 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) */ if((current->ptrace & PT_DTRACE) && is_syscall(PT_REGS_IP(¤t->thread.regs))) - current->thread.mode.tt.singlestep_syscall = 1; + (void) CHOOSE_MODE(current->thread.mode.tt.singlestep_syscall = 1, 0); return(0); } @@ -228,6 +229,16 @@ int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) } } +static int copy_sc_from_user(struct pt_regs *to, void *from) +{ + int ret; + + ret = CHOOSE_MODE(copy_sc_from_user_tt(to->regs.mode.tt, from, + &signal_frame_sc.arch), + copy_sc_from_user_skas(&to->regs, from)); + return(ret); +} + int sys_sigreturn(struct pt_regs regs) { void *sc = sp_to_sc(PT_REGS_SP(®s)); @@ -241,8 +252,7 @@ int sys_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs.regs.mode.tt, sc, - &signal_frame_sc.arch); + copy_sc_from_user(current->thread.regs, sc); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } @@ -257,8 +267,7 @@ int sys_rt_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs.regs.mode.tt, sc, - &signal_frame_sc.arch); + copy_sc_from_user(current->thread.regs, sc); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index cb83a2255fa9..84d194b847a4 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -3,10 +3,10 @@ # Licensed under the GPL # -obj-y = exec_kern.o exec_user.o mem_user.o mmu.o process.o process_kern.o \ - syscall_user.o trap_user.o +subdir-y = sys-$(SUBARCH)/ -obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) +obj-y = exec_kern.o exec_user.o mem_user.o mmu.o process.o process_kern.o \ + syscall_user.o trap_user.o $(subdir-y) USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) diff --git a/arch/um/kernel/skas/sys-i386/Makefile b/arch/um/kernel/skas/sys-i386/Makefile new file mode 100644 index 000000000000..fb154b2f5686 --- /dev/null +++ b/arch/um/kernel/skas/sys-i386/Makefile @@ -0,0 +1,17 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +O_TARGET = sys-i386.o + +obj-y = sigcontext.o + +USER_OBJS = sigcontext.o + +include $(TOPDIR)/Rules.make + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + +clean : diff --git a/arch/um/kernel/skas/sys-i386/sigcontext.c b/arch/um/kernel/skas/sys-i386/sigcontext.c new file mode 100644 index 000000000000..07bb0ea0ed8a --- /dev/null +++ b/arch/um/kernel/skas/sys-i386/sigcontext.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include "sysdep/ptrace.h" +#include "sysdep/ptrace_user.h" +#include "kern_util.h" +#include "user.h" +#include "sigcontext.h" + +extern int userspace_pid; + +int copy_sc_from_user_skas(struct uml_pt_regs *regs, void *from_ptr) +{ + struct sigcontext sc, *from = from_ptr; + unsigned long fpregs[FP_FRAME_SIZE]; + int err; + + err = copy_from_user_proc(&sc, from, sizeof(sc)); + err |= copy_from_user_proc(fpregs, sc.fpstate, sizeof(fpregs)); + if(err) + return(err); + + regs->mode.skas.regs[GS] = sc.gs; + regs->mode.skas.regs[FS] = sc.fs; + regs->mode.skas.regs[ES] = sc.es; + regs->mode.skas.regs[DS] = sc.ds; + regs->mode.skas.regs[EDI] = sc.edi; + regs->mode.skas.regs[ESI] = sc.esi; + regs->mode.skas.regs[EBP] = sc.ebp; + regs->mode.skas.regs[UESP] = sc.esp; + regs->mode.skas.regs[EBX] = sc.ebx; + regs->mode.skas.regs[EDX] = sc.edx; + regs->mode.skas.regs[ECX] = sc.ecx; + regs->mode.skas.regs[EAX] = sc.eax; + regs->mode.skas.regs[EIP] = sc.eip; + regs->mode.skas.regs[CS] = sc.cs; + regs->mode.skas.regs[EFL] = sc.eflags; + regs->mode.skas.regs[UESP] = sc.esp_at_signal; + regs->mode.skas.regs[SS] = sc.ss; + regs->mode.skas.fault_addr = sc.cr2; + regs->mode.skas.fault_type = FAULT_WRITE(sc.err); + regs->mode.skas.trap_type = sc.trapno; + + err = ptrace(PTRACE_SETFPREGS, userspace_pid, 0, fpregs); + if(err < 0){ + printk("copy_sc_to_user - PTRACE_SETFPREGS failed, " + "errno = %d\n", errno); + return(1); + } + + return(0); +} + +int copy_sc_to_user_skas(void *to_ptr, struct uml_pt_regs *regs, + unsigned long fault_addr, int fault_type) +{ + struct sigcontext sc, *to = to_ptr; + struct _fpstate *to_fp; + unsigned long fpregs[FP_FRAME_SIZE]; + int err; + + sc.gs = regs->mode.skas.regs[GS]; + sc.fs = regs->mode.skas.regs[FS]; + sc.es = regs->mode.skas.regs[ES]; + sc.ds = regs->mode.skas.regs[DS]; + sc.edi = regs->mode.skas.regs[EDI]; + sc.esi = regs->mode.skas.regs[ESI]; + sc.ebp = regs->mode.skas.regs[EBP]; + sc.esp = regs->mode.skas.regs[UESP]; + sc.ebx = regs->mode.skas.regs[EBX]; + sc.edx = regs->mode.skas.regs[EDX]; + sc.ecx = regs->mode.skas.regs[ECX]; + sc.eax = regs->mode.skas.regs[EAX]; + sc.eip = regs->mode.skas.regs[EIP]; + sc.cs = regs->mode.skas.regs[CS]; + sc.eflags = regs->mode.skas.regs[EFL]; + sc.esp_at_signal = regs->mode.skas.regs[UESP]; + sc.ss = regs->mode.skas.regs[SS]; + sc.cr2 = fault_addr; + sc.err = TO_SC_ERR(fault_type); + sc.trapno = regs->mode.skas.trap_type; + + err = ptrace(PTRACE_GETFPREGS, userspace_pid, 0, fpregs); + if(err < 0){ + printk("copy_sc_to_user - PTRACE_GETFPREGS failed, " + "errno = %d\n", errno); + return(1); + } + to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to)); + sc.fpstate = to_fp; + + if(err) + return(err); + + return(copy_to_user_proc(to, &sc, sizeof(sc)) || + copy_to_user_proc(to_fp, fpregs, sizeof(fpregs))); +} + +/* + * 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/tt/Makefile b/arch/um/kernel/tt/Makefile index 401ae1f4f59d..76c46051c09e 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -3,10 +3,13 @@ # Licensed under the GPL # +subdir-y = sys-$(SUBARCH)/ + +subdir-$(CONFIG_PT_PROXY) += ptproxy/ + obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o mem.o process_kern.o \ - syscall_user.o tracer.o uaccess_user.o + syscall_user.o tracer.o uaccess_user.o $(subdir-y) -obj-$(CONFIG_PT_PROXY) += ptproxy/ USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o tracer.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) diff --git a/arch/um/kernel/tt/sys-i386/Makefile b/arch/um/kernel/tt/sys-i386/Makefile new file mode 100644 index 000000000000..fb154b2f5686 --- /dev/null +++ b/arch/um/kernel/tt/sys-i386/Makefile @@ -0,0 +1,17 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +O_TARGET = sys-i386.o + +obj-y = sigcontext.o + +USER_OBJS = sigcontext.o + +include $(TOPDIR)/Rules.make + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + +clean : diff --git a/arch/um/kernel/tt/sys-i386/sigcontext.c b/arch/um/kernel/tt/sys-i386/sigcontext.c new file mode 100644 index 000000000000..1701c0dfb030 --- /dev/null +++ b/arch/um/kernel/tt/sys-i386/sigcontext.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include "kern_util.h" +#include "sysdep/frame.h" + +int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data) +{ + struct arch_frame_data *arch = data; + struct sigcontext *to = to_ptr, *from = from_ptr; + struct _fpstate *to_fp, *from_fp; + unsigned long sigs; + int err; + + to_fp = to->fpstate; + from_fp = from->fpstate; + sigs = to->oldmask; + err = copy_from_user_proc(to, from, sizeof(*to)); + to->oldmask = sigs; + if(to_fp != NULL){ + err |= copy_from_user_proc(&to->fpstate, &to_fp, + sizeof(to->fpstate)); + err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size); + } + return(err); +} + +int copy_sc_to_user_tt(void *to_ptr, void *from_ptr, void *data) +{ + struct arch_frame_data *arch = data; + struct sigcontext *to = to_ptr, *from = from_ptr; + struct _fpstate *to_fp, *from_fp; + int err; + + to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to)); + from_fp = from->fpstate; + err = copy_to_user_proc(to, from, sizeof(*to)); + if(from_fp != NULL){ + err |= copy_to_user_proc(&to->fpstate, &to_fp, + sizeof(to->fpstate)); + err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size); + } + 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/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c index e61a94651371..6d33bedc07d7 100644 --- a/arch/um/sys-i386/sigcontext.c +++ b/arch/um/sys-i386/sigcontext.c @@ -18,45 +18,6 @@ int sc_size(void *data) return(sizeof(struct sigcontext) + arch->fpstate_size); } -int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data) -{ - struct arch_frame_data *arch = data; - struct sigcontext *to = to_ptr, *from = from_ptr; - struct _fpstate *to_fp, *from_fp; - int err; - - to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to)); - from_fp = from->fpstate; - err = copy_to_user_proc(to, from, sizeof(*to)); - if(from_fp != NULL){ - err |= copy_to_user_proc(&to->fpstate, &to_fp, - sizeof(to->fpstate)); - err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size); - } - return(err); -} - -int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data) -{ - struct arch_frame_data *arch = data; - struct sigcontext *to = to_ptr, *from = from_ptr; - struct _fpstate *to_fp, *from_fp; - unsigned long sigs; - int err; - - to_fp = to->fpstate; - from_fp = from->fpstate; - sigs = to->oldmask; - err = copy_from_user_proc(to, from, sizeof(*to)); - to->oldmask = sigs; - if(to_fp != NULL){ - err |= copy_from_user_proc(&to->fpstate, &to_fp, - sizeof(to->fpstate)); - err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size); - } - return(err); -} - void sc_to_sc(void *to_ptr, void *from_ptr) { struct sigcontext *to = to_ptr, *from = from_ptr; -- cgit v1.2.3 From ca7e435f06fbade800199046b315d202b3b39e36 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 12:26:06 -0500 Subject: Some minor build and compilation fixes to the copy_sc merge. --- arch/um/kernel/signal_kern.c | 4 ++-- arch/um/kernel/skas/Makefile | 4 +--- arch/um/kernel/skas/sys-i386/Makefile | 5 ++--- arch/um/kernel/tt/Makefile | 7 ++----- arch/um/kernel/tt/sys-i386/Makefile | 5 ++--- 5 files changed, 9 insertions(+), 16 deletions(-) diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 355810656aa0..4e016a44bba2 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -252,7 +252,7 @@ int sys_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs, sc); + copy_sc_from_user(¤t->thread.regs, sc); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } @@ -267,7 +267,7 @@ int sys_rt_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs, sc); + copy_sc_from_user(¤t->thread.regs, sc); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index 84d194b847a4..aa5257572407 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -3,10 +3,8 @@ # Licensed under the GPL # -subdir-y = sys-$(SUBARCH)/ - obj-y = exec_kern.o exec_user.o mem_user.o mmu.o process.o process_kern.o \ - syscall_user.o trap_user.o $(subdir-y) + syscall_user.o trap_user.o sys-$(SUBARCH)/ USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) diff --git a/arch/um/kernel/skas/sys-i386/Makefile b/arch/um/kernel/skas/sys-i386/Makefile index fb154b2f5686..fb6b22056f37 100644 --- a/arch/um/kernel/skas/sys-i386/Makefile +++ b/arch/um/kernel/skas/sys-i386/Makefile @@ -3,15 +3,14 @@ # Licensed under the GPL # -O_TARGET = sys-i386.o - obj-y = sigcontext.o USER_OBJS = sigcontext.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) include $(TOPDIR)/Rules.make $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< clean : diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 76c46051c09e..2b1c87271c6e 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -3,13 +3,10 @@ # Licensed under the GPL # -subdir-y = sys-$(SUBARCH)/ - -subdir-$(CONFIG_PT_PROXY) += ptproxy/ - obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o mem.o process_kern.o \ - syscall_user.o tracer.o uaccess_user.o $(subdir-y) + syscall_user.o tracer.o uaccess_user.o sys-$(SUBARCH)/ +obj-$(CONFIG_PT_PROXY) += ptproxy/ USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o tracer.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) diff --git a/arch/um/kernel/tt/sys-i386/Makefile b/arch/um/kernel/tt/sys-i386/Makefile index fb154b2f5686..fb6b22056f37 100644 --- a/arch/um/kernel/tt/sys-i386/Makefile +++ b/arch/um/kernel/tt/sys-i386/Makefile @@ -3,15 +3,14 @@ # Licensed under the GPL # -O_TARGET = sys-i386.o - obj-y = sigcontext.o USER_OBJS = sigcontext.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) include $(TOPDIR)/Rules.make $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< clean : -- cgit v1.2.3 From 7ee0eebf1138a64d9aac60ab93f9ec1e3494a247 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 12:30:24 -0500 Subject: Merged the IP checksum changes from the skas code. --- arch/um/include/sysdep-i386/checksum.h | 217 +++++++++++++++++++++++++++++++++ arch/um/kernel/checksum.c | 42 +++++++ arch/um/sys-i386/ksyms.c | 3 +- include/asm-um/checksum.h | 2 +- 4 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 arch/um/include/sysdep-i386/checksum.h create mode 100644 arch/um/kernel/checksum.c diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h new file mode 100644 index 000000000000..c77e434d61a9 --- /dev/null +++ b/arch/um/include/sysdep-i386/checksum.h @@ -0,0 +1,217 @@ +/* + * Licensed under the GPL + */ + +#ifndef __UM_SYSDEP_CHECKSUM_H +#define __UM_SYSDEP_CHECKSUM_H + +#include "linux/string.h" + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char * buff, int len, + unsigned int sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums, and handles user-space pointer exceptions correctly, when needed. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +unsigned int csum_partial_copy_to(const char *src, char *dst, int len, + int sum, int *err_ptr); +unsigned int csum_partial_copy_from(const char *src, char *dst, int len, + int sum, int *err_ptr); + +/* + * Note: when you get a NULL pointer exception here this means someone + * passed in an incorrect kernel address to one of these functions. + * + * If you use these functions directly please don't forget the + * verify_area(). + */ + +static __inline__ +unsigned int csum_partial_copy_nocheck(const char *src, char *dst, + int len, int sum) +{ + memcpy(dst, src, len); + return(csum_partial(dst, len, sum)); +} + +static __inline__ +unsigned int csum_partial_copy_from_user(const char *src, char *dst, + int len, int sum, int *err_ptr) +{ + return csum_partial_copy_from(src, dst, len, sum, err_ptr); +} + +/* + * These are the old (and unsafe) way of doing checksums, a warning message + * will be printed if they are used and an exeption occurs. + * + * these functions should go away after some time. + */ + +#define csum_partial_copy_fromuser csum_partial_copy_from_user +unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum); + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + * + * By Jorge Cwik , adapted for linux by + * Arnt Gulbrandsen. + */ +static inline unsigned short ip_fast_csum(unsigned char * iph, + unsigned int ihl) +{ + unsigned int sum; + + __asm__ __volatile__( + "movl (%1), %0 ;\n" + "subl $4, %2 ;\n" + "jbe 2f ;\n" + "addl 4(%1), %0 ;\n" + "adcl 8(%1), %0 ;\n" + "adcl 12(%1), %0 ;\n" +"1: adcl 16(%1), %0 ;\n" + "lea 4(%1), %1 ;\n" + "decl %2 ;\n" + "jne 1b ;\n" + "adcl $0, %0 ;\n" + "movl %0, %2 ;\n" + "shrl $16, %0 ;\n" + "addw %w2, %w0 ;\n" + "adcl $0, %0 ;\n" + "notl %0 ;\n" +"2: ;\n" + /* Since the input registers which are loaded with iph and ipl + are modified, we must also specify them as outputs, or gcc + will assume they contain their original values. */ + : "=r" (sum), "=r" (iph), "=r" (ihl) + : "1" (iph), "2" (ihl)); + return(sum); +} + +/* + * Fold a partial checksum + */ + +static inline unsigned int csum_fold(unsigned int sum) +{ + __asm__( + "addl %1, %0 ;\n" + "adcl $0xffff, %0 ;\n" + : "=r" (sum) + : "r" (sum << 16), "0" (sum & 0xffff0000) + ); + return (~sum) >> 16; +} + +static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + __asm__( + "addl %1, %0 ;\n" + "adcl %2, %0 ;\n" + "adcl %3, %0 ;\n" + "adcl $0, %0 ;\n" + : "=r" (sum) + : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum)); + return sum; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ + +static inline unsigned short ip_compute_csum(unsigned char * buff, int len) +{ + return csum_fold (csum_partial(buff, len, 0)); +} + +#define _HAVE_ARCH_IPV6_CSUM +static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, + struct in6_addr *daddr, + __u32 len, + unsigned short proto, + unsigned int sum) +{ + __asm__( + "addl 0(%1), %0 ;\n" + "adcl 4(%1), %0 ;\n" + "adcl 8(%1), %0 ;\n" + "adcl 12(%1), %0 ;\n" + "adcl 0(%2), %0 ;\n" + "adcl 4(%2), %0 ;\n" + "adcl 8(%2), %0 ;\n" + "adcl 12(%2), %0 ;\n" + "adcl %3, %0 ;\n" + "adcl %4, %0 ;\n" + "adcl $0, %0 ;\n" + : "=&r" (sum) + : "r" (saddr), "r" (daddr), + "r"(htonl(len)), "r"(htonl(proto)), "0"(sum)); + + return csum_fold(sum); +} + +/* + * Copy and checksum to user + */ +#define HAVE_CSUM_COPY_USER +static __inline__ unsigned int csum_and_copy_to_user(const char *src, + char *dst, int len, + int sum, int *err_ptr) +{ + if (access_ok(VERIFY_WRITE, dst, len)) + return(csum_partial_copy_to(src, dst, len, sum, err_ptr)); + + if (len) + *err_ptr = -EFAULT; + + return -1; /* invalid checksum */ +} + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c new file mode 100644 index 000000000000..6e27cb032258 --- /dev/null +++ b/arch/um/kernel/checksum.c @@ -0,0 +1,42 @@ +#include "asm/uaccess.h" +#include "linux/errno.h" + +extern unsigned int arch_csum_partial(const char *buff, int len, int sum); + +extern unsigned int csum_partial(char *buff, int len, int sum) +{ + return(arch_csum_partial(buff, len, sum)); +} + +unsigned int csum_partial_copy_to(const char *src, char *dst, int len, + int sum, int *err_ptr) +{ + if(copy_to_user(dst, src, len)){ + *err_ptr = -EFAULT; + return(-1); + } + + return(arch_csum_partial(src, len, sum)); +} + +unsigned int csum_partial_copy_from(const char *src, char *dst, int len, + int sum, int *err_ptr) +{ + if(copy_from_user(dst, src, len)){ + *err_ptr = -EFAULT; + return(-1); + } + + return(arch_csum_partial(dst, len, sum)); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c index bf57ac7e04e1..74f70a120458 100644 --- a/arch/um/sys-i386/ksyms.c +++ b/arch/um/sys-i386/ksyms.c @@ -13,4 +13,5 @@ EXPORT_SYMBOL(__down_failed_trylock); EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_generic); +EXPORT_SYMBOL(csum_partial_copy_from); +EXPORT_SYMBOL(csum_partial_copy_to); diff --git a/include/asm-um/checksum.h b/include/asm-um/checksum.h index 4b38f37c822e..5b501361e361 100644 --- a/include/asm-um/checksum.h +++ b/include/asm-um/checksum.h @@ -1,6 +1,6 @@ #ifndef __UM_CHECKSUM_H #define __UM_CHECKSUM_H -#include "asm/arch/checksum.h" +#include "sysdep/checksum.h" #endif -- cgit v1.2.3 From fc0ff28c30944fe0833fe5f7c9959ce9ee6fe54a Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 13:21:41 -0500 Subject: Removed the checksum.S symlink from arch/um/sys-i386/Makefile. --- arch/um/sys-i386/Makefile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index c96a75fe3fdb..b9d7e94d7827 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -6,11 +6,11 @@ obj-$(CONFIG_HIGHMEM) += highmem.o export-objs = ksyms.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -SYMLINKS = semaphore.c checksum.S extable.c highmem.c module.c +SYMLINKS = semaphore.c extable.c highmem.c module.c semaphore.c-dir = kernel -checksum.S-dir = lib extable.c-dir = mm highmem.c-dir = mm module.c-dir = kernel @@ -22,10 +22,8 @@ endef include $(TOPDIR)/Rules.make -USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) - $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< $(foreach f,$(SYMLINKS),$(src)/$f): $(call make_link,$@) -- cgit v1.2.3 From c86507d10d05f9b56338de8c2aae8e2b22694ef5 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 13:22:43 -0500 Subject: Some small build fixes to the IP checksum merge. --- arch/um/kernel/Makefile | 6 +++--- arch/um/os-Linux/Makefile | 6 +++--- arch/um/os-Linux/drivers/Makefile | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 9fb50e9da6c6..ba6c05749f04 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -5,9 +5,9 @@ EXTRA_TARGETS := unmap_fin.o -obj-y = config.o exec_kern.o exitcode.o frame_kern.o frame.o helper.o \ - init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o process.o \ - process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ +obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \ + helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \ + process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \ syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \ time_kern.o tlb.o trap_kern.o trap_user.o um_arch.o \ diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index d3235b6d3e85..a38b53f6961b 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,14 +3,14 @@ # Licensed under the GPL # -obj-y = file.o process.o tty.o +obj-y = file.o process.o tty.o drivers/ -USER_OBJS := $(foreach file,$(obj-y),arch/um/os-Linux/$(file)) +USER_OBJS := $(foreach file,file.o process.o tty.o,$(obj)/$(file)) include $(TOPDIR)/Rules.make $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< clean : diff --git a/arch/um/os-Linux/drivers/Makefile b/arch/um/os-Linux/drivers/Makefile index 28b15662dcac..922e22fc54e2 100644 --- a/arch/um/os-Linux/drivers/Makefile +++ b/arch/um/os-Linux/drivers/Makefile @@ -13,8 +13,9 @@ obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs)) USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS)) +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) include $(TOPDIR)/Rules.make $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< -- cgit v1.2.3 From 863468e5864fe11932f110b078b79f9c23749d3c Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 22 Nov 2002 02:53:13 -0500 Subject: Merged a number of small skas changes. --- arch/um/include/chan_user.h | 1 - arch/um/include/kern.h | 2 +- arch/um/include/mem.h | 1 + arch/um/include/time_user.h | 2 +- arch/um/kernel/mem.c | 24 +------ arch/um/kernel/process_kern.c | 8 +-- arch/um/kernel/ptrace.c | 61 +++++++++++++++- arch/um/kernel/sigio_user.c | 13 ++-- arch/um/kernel/skas/Makefile | 2 +- arch/um/kernel/skas/syscall_kern.c | 42 +++++++++++ arch/um/kernel/skas/time.c | 30 ++++++++ arch/um/kernel/smp.c | 12 ++-- arch/um/kernel/syscall_kern.c | 120 ++----------------------------- arch/um/kernel/time.c | 22 ++---- arch/um/kernel/time_kern.c | 3 +- arch/um/kernel/trap_user.c | 41 ++--------- arch/um/kernel/tt/Makefile | 9 ++- arch/um/kernel/tt/ksyms.c | 28 ++++++++ arch/um/kernel/tt/syscall_kern.c | 142 +++++++++++++++++++++++++++++++++++++ arch/um/kernel/tt/time.c | 28 ++++++++ arch/um/kernel/tt/trap_user.c | 58 +++++++++++++++ arch/um/kernel/umid.c | 6 +- arch/um/sys-i386/ldt.c | 69 +++++++++++++++++- arch/um/sys-i386/ptrace.c | 57 ++++++++++++--- 24 files changed, 552 insertions(+), 229 deletions(-) create mode 100644 arch/um/kernel/skas/syscall_kern.c create mode 100644 arch/um/kernel/skas/time.c create mode 100644 arch/um/kernel/tt/ksyms.c create mode 100644 arch/um/kernel/tt/syscall_kern.c create mode 100644 arch/um/kernel/tt/time.c create mode 100644 arch/um/kernel/tt/trap_user.c diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h index c016c2aab72e..9414c1a44c6d 100644 --- a/arch/um/include/chan_user.h +++ b/arch/um/include/chan_user.h @@ -44,7 +44,6 @@ extern void generic_free(void *data); extern void register_winch(int fd, void *device_data); extern void register_winch_irq(int fd, int tty_fd, int pid, void *line); -extern void setup_tracer_winch(void); #define __channel_help(fn, prefix) \ __uml_help(fn, prefix "[0-9]*=\n" \ diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h index 09eae635a15e..3e3aed19f54c 100644 --- a/arch/um/include/kern.h +++ b/arch/um/include/kern.h @@ -25,7 +25,6 @@ extern void *sbrk(int increment); extern void *malloc(int size); extern void perror(char *err); extern int kill(int pid, int sig); -extern int getpid(void); extern int getuid(void); extern int pause(void); extern int write(int, const void *, int); @@ -34,6 +33,7 @@ extern int close(int); extern int read(unsigned int, char *, int); extern int pipe(int *); extern int sched_yield(void); +extern int ptrace(int op, int pid, long addr, long data); #endif /* diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h index e7835b541196..bad6b30b8f7d 100644 --- a/arch/um/include/mem.h +++ b/arch/um/include/mem.h @@ -13,6 +13,7 @@ struct vm_reserved { }; extern void set_usable_vm(unsigned long start, unsigned long end); +extern void set_kmem_end(unsigned long new); #endif diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h index d49a34f0bee8..ec7dc1a65465 100644 --- a/arch/um/include/time_user.h +++ b/arch/um/include/time_user.h @@ -8,7 +8,7 @@ extern void timer(void); extern void switch_timers(int to_real); -extern void user_time_init(void); +extern void set_interval(int timer_type); extern void idle_sleep(int secs); extern void enable_timer(void); extern void time_lock(void); diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 3db5375ebe04..178223bf2bfa 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -414,28 +414,8 @@ __uml_setup("mem=", uml_mem_setup, struct page *arch_validate(struct page *page, int mask, int order) { - unsigned long addr, zero = 0; - int i; - - again: - if(page == NULL) return(page); - if(PageHighMem(page)) return(page); - - addr = (unsigned long) page_address(page); - for(i = 0; i < (1 << order); i++){ - current->thread.fault_addr = (void *) addr; - if(__do_copy_to_user((void *) addr, &zero, - sizeof(zero), - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)){ - if(!(mask & __GFP_WAIT)) return(NULL); - else break; - } - addr += PAGE_SIZE; - } - if(i == (1 << order)) return(page); - page = alloc_pages(mask, order); - goto again; + return(CHOOSE_MODE_PROC(arch_validate_tt, arch_validate_skas, page, + mask, order)); } DECLARE_MUTEX(vm_reserved_sem); diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 41a54e742a98..12ff8db4e053 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -71,7 +71,7 @@ int external_pid(void *t) { struct task_struct *task = t ? t : current; - return(task->thread.mode.tt.extern_pid); + return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task)); } int pid_to_processor_id(int pid) @@ -310,6 +310,7 @@ int user_context(unsigned long sp) } extern void remove_umid_dir(void); + __uml_exitcall(remove_umid_dir); extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; @@ -353,11 +354,6 @@ int clear_user_proc(void *buf, int size) return(clear_user(buf, size)); } -void set_thread_sc(void *sc) -{ - current->thread.regs.regs.mode.tt = sc; -} - int smp_sigio_handler(void) { #ifdef CONFIG_SMP diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index c47bc17fdecf..61bc79033231 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -9,6 +9,7 @@ #include "linux/smp_lock.h" #include "linux/security.h" #include "linux/ptrace.h" +#include "linux/proc_mm.h" #include "asm/ptrace.h" #include "asm/uaccess.h" #include "kern_util.h" @@ -21,6 +22,11 @@ void ptrace_disable(struct task_struct *child) { } +extern long do_mmap2(struct task_struct *task, unsigned long addr, + unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, + unsigned long pgoff); + int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -182,13 +188,13 @@ int sys_ptrace(long request, long pid, long addr, long data) #ifdef PTRACE_GETREGS case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - if (!access_ok(VERIFY_WRITE, (unsigned *)data, + if (!access_ok(VERIFY_WRITE, (unsigned long *)data, FRAME_SIZE_OFFSET)) { ret = -EIO; break; } for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) { - __put_user(getreg(child, i),(unsigned long *) data); + __put_user(getreg(child, i), (unsigned long *) data); data += sizeof(long); } ret = 0; @@ -231,6 +237,57 @@ int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SETFPXREGS: /* Set the child FPU state. */ ret = set_fpxregs(data, child); break; +#endif + case PTRACE_FAULTINFO: { + struct ptrace_faultinfo fault; + + fault = ((struct ptrace_faultinfo) + { .is_write = child->thread.err, + .addr = child->thread.cr2 }); + ret = copy_to_user((unsigned long *) data, &fault, + sizeof(fault)); + if(ret) + break; + break; + } + case PTRACE_SIGPENDING: + ret = copy_to_user((unsigned long *) data, + &child->pending.signal, + sizeof(child->pending.signal)); + break; + + case PTRACE_LDT: { + struct ptrace_ldt ldt; + + if(copy_from_user(&ldt, (unsigned long *) data, + sizeof(ldt))){ + ret = -EIO; + break; + } + + /* This one is confusing, so just punt and return -EIO for + * now + */ + ret = -EIO; + break; + } +#ifdef CONFIG_PROC_MM + case PTRACE_SWITCH_MM: { + struct mm_struct *old = child->mm; + struct mm_struct *new = proc_mm_get_mm(data); + + if(IS_ERR(new)){ + ret = PTR_ERR(new); + break; + } + + atomic_inc(&new->mm_users); + child->mm = new; + child->active_mm = new; + mmput(old); + ret = 0; + break; + } #endif default: ret = -EIO; diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index 740608075b7c..da00ed4feede 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -39,14 +39,13 @@ struct openpty_arg { int err; }; -static int openpty_cb(void *arg) +static void openpty_cb(void *arg) { struct openpty_arg *info = arg; info->err = 0; if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) info->err = errno; - return(0); } void __init check_one_sigio(void (*proc)(int, int)) @@ -54,13 +53,9 @@ void __init check_one_sigio(void (*proc)(int, int)) struct sigaction old, new; struct termios tt; struct openpty_arg pty = { master : -1, slave : -1 }; - int master, slave, flags, err; + int master, slave, flags; - err = run_helper_thread(openpty_cb, &pty, CLONE_FILES, NULL, 2); - if(err < 0){ - printk("run_helper_thread failed, errno = %d\n", -err); - return; - } + initial_thread_cb(openpty_cb, &pty); if(pty.err){ printk("openpty failed, errno = %d\n", pty.err); return; @@ -387,7 +382,7 @@ void write_sigio_workaround(void) goto out_close2; write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, - CLONE_FILES, &stack, 0); + CLONE_FILES | CLONE_VM, &stack, 0); if(write_sigio_pid < 0) goto out_close2; diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index aa5257572407..a58e13b91b6f 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -4,7 +4,7 @@ # obj-y = exec_kern.o exec_user.o mem_user.o mmu.o process.o process_kern.o \ - syscall_user.o trap_user.o sys-$(SUBARCH)/ + syscall_kern.o syscall_user.o time.o trap_user.o sys-$(SUBARCH)/ USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c new file mode 100644 index 000000000000..d870870db1ac --- /dev/null +++ b/arch/um/kernel/skas/syscall_kern.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sys.h" +#include "asm/errno.h" +#include "asm/unistd.h" +#include "asm/ptrace.h" +#include "asm/current.h" +#include "sysdep/syscalls.h" +#include "kern_util.h" + +extern syscall_handler_t *sys_call_table[]; + +long execute_syscall_skas(void *r) +{ + struct pt_regs *regs = r; + long res; + int syscall; + + current->thread.nsyscalls++; + nsyscalls++; + syscall = regs->regs.syscall; + + if((syscall >= NR_syscalls) || (syscall < 0)) + res = -ENOSYS; + else res = EXECUTE_SYSCALL(syscall, regs); + + return(res); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c new file mode 100644 index 000000000000..98091494b897 --- /dev/null +++ b/arch/um/kernel/skas/time.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include "time_user.h" +#include "process.h" +#include "user.h" + +void user_time_init_skas(void) +{ + if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR) + panic("Couldn't set SIGALRM handler"); + if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) + panic("Couldn't set SIGVTALRM handler"); + set_interval(ITIMER_VIRTUAL); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index c9d9b15789d1..3503ed13f59a 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -116,7 +116,8 @@ static int idle_proc(void *cpup) panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, -err); - activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.extern_pid); + activate_ipi(cpu_data[cpu].ipi_pipe[0], + current->thread.mode.tt.extern_pid); wmb(); if (test_and_set_bit(cpu, &smp_callin_map)) { @@ -143,10 +144,12 @@ static struct task_struct *idle_thread(int cpu) if(IS_ERR(new_task)) panic("do_fork failed in idle_thread"); cpu_tasks[cpu] = ((struct cpu_task) - { .pid = new_task->thread.extern_pid, + { .pid = new_task->thread.mode.tt.extern_pid, .task = new_task } ); idle_threads[cpu] = new_task; - write(new_task->thread.switch_pipe[1], &c, sizeof(c)); + CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c, + sizeof(c)), + ({ panic("skas mode doesn't support SMP"); })); return(new_task); } @@ -162,7 +165,8 @@ void smp_prepare_cpus(unsigned int maxcpus) err = os_pipe(cpu_data[0].ipi_pipe, 1, 1); if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); - activate_ipi(cpu_data[0].ipi_pipe[0], current->thread.extern_pid); + activate_ipi(cpu_data[0].ipi_pipe[0], + current->thread.mode.tt.extern_pid); for(cpu = 1; cpu < ncpus; cpu++){ printk("Booting processor %d...\n", cpu); diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index adc52d2dccf2..cdebe6776f78 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -20,6 +20,11 @@ #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 um_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void * data) @@ -298,122 +303,9 @@ int sys_sigaltstack(const stack_t *uss, stack_t *uoss) return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); } -static inline int check_area(void *ptr, int size) -{ - return(verify_area(VERIFY_WRITE, ptr, size)); -} - -static int check_readlink(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], regs->regs.args[2])); -} - -static int check_utime(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], - sizeof(struct utimbuf))); -} - -static int check_oldstat(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], - sizeof(struct __old_kernel_stat))); -} - -static int check_stat(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], sizeof(struct stat))); -} - -static int check_stat64(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], sizeof(struct stat64))); -} - -struct bogus { - int kernel_ds; - int (*check_params)(struct pt_regs *); -}; - -struct bogus this_is_bogus[256] = { - [ __NR_mknod ] = { 1, NULL }, - [ __NR_mkdir ] = { 1, NULL }, - [ __NR_rmdir ] = { 1, NULL }, - [ __NR_unlink ] = { 1, NULL }, - [ __NR_symlink ] = { 1, NULL }, - [ __NR_link ] = { 1, NULL }, - [ __NR_rename ] = { 1, NULL }, - [ __NR_umount ] = { 1, NULL }, - [ __NR_mount ] = { 1, NULL }, - [ __NR_pivot_root ] = { 1, NULL }, - [ __NR_chdir ] = { 1, NULL }, - [ __NR_chroot ] = { 1, NULL }, - [ __NR_open ] = { 1, NULL }, - [ __NR_quotactl ] = { 1, NULL }, - [ __NR_sysfs ] = { 1, NULL }, - [ __NR_readlink ] = { 1, check_readlink }, - [ __NR_acct ] = { 1, NULL }, - [ __NR_execve ] = { 1, NULL }, - [ __NR_uselib ] = { 1, NULL }, - [ __NR_statfs ] = { 1, NULL }, - [ __NR_truncate ] = { 1, NULL }, - [ __NR_access ] = { 1, NULL }, - [ __NR_chmod ] = { 1, NULL }, - [ __NR_chown ] = { 1, NULL }, - [ __NR_lchown ] = { 1, NULL }, - [ __NR_utime ] = { 1, check_utime }, - [ __NR_oldlstat ] = { 1, check_oldstat }, - [ __NR_oldstat ] = { 1, check_oldstat }, - [ __NR_stat ] = { 1, check_stat }, - [ __NR_lstat ] = { 1, check_stat }, - [ __NR_stat64 ] = { 1, check_stat64 }, - [ __NR_lstat64 ] = { 1, check_stat64 }, - [ __NR_chown32 ] = { 1, NULL }, -}; - -/* sys_utimes */ - -static int check_bogosity(struct pt_regs *regs) -{ - struct bogus *bogon = &this_is_bogus[regs->regs.syscall]; - - if(!bogon->kernel_ds) return(0); - if(bogon->check_params && (*bogon->check_params)(regs)) - return(-EFAULT); - set_fs(KERNEL_DS); - return(0); -} - -/* Unlocked, I don't care if this is a bit off */ -int nsyscalls = 0; - -extern syscall_handler_t *sys_call_table[]; - long execute_syscall(void *r) { - struct pt_regs *regs = r; - long res; - int syscall; - - current->thread.nsyscalls++; - nsyscalls++; - syscall = regs->regs.syscall; - - if((syscall >= NR_syscalls) || (syscall < 0)) - res = -ENOSYS; - else if(honeypot && check_bogosity(regs)) - res = -EFAULT; - else res = EXECUTE_SYSCALL(syscall, regs); - - set_fs(USER_DS); - - if(current->thread.mode.tt.singlestep_syscall){ - current->thread.mode.tt.singlestep_syscall = 0; - current->ptrace &= ~PT_DTRACE; - force_sig(SIGTRAP, current); - } - - return(res); + return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r)); } spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED; diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 2ab57626b43f..282756af3779 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -23,22 +23,21 @@ void timer(void) gettimeofday(&xtime, NULL); } -static void set_interval(int timer_type) +void set_interval(int timer_type) { - struct itimerval interval; + int usec = 1000000/hz(); + struct itimerval interval = ((struct itimerval) { { 0, usec }, + { 0, usec } }); - interval.it_interval.tv_sec = 0; - interval.it_interval.tv_usec = 1000000/hz(); - interval.it_value.tv_sec = 0; - interval.it_value.tv_usec = 1000000/hz(); if(setitimer(timer_type, &interval, NULL) == -1) panic("setitimer failed - errno = %d\n", errno); } void enable_timer(void) { - struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() }, - { 0, 1000000/hz() }}); + int usec = 1000000/hz(); + struct itimerval enable = ((struct itimerval) { { 0, usec }, + { 0, usec }}); if(setitimer(ITIMER_VIRTUAL, &enable, NULL)) printk("enable_timer - setitimer failed, errno = %d\n", errno); @@ -76,13 +75,6 @@ void idle_timer(void) set_interval(ITIMER_REAL); } -void user_time_init(void) -{ - if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) - panic("Couldn't set SIGVTALRM handler"); - set_interval(ITIMER_VIRTUAL); -} - void time_init(void) { if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 93199e99c6f8..713d7af4a696 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -17,6 +17,7 @@ #include "kern_util.h" #include "user_util.h" #include "time_user.h" +#include "mode.h" u64 jiffies_64; @@ -142,7 +143,7 @@ int __init timer_init(void) { int err; - user_time_init(); + CHOOSE_MODE(user_time_init_tt(), user_time_init_skas()); if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL)) != 0) printk(KERN_ERR "timer_init : request_irq failed - " diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 38872e7a288b..925aacf560f3 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -96,57 +96,24 @@ struct signal_info sig_info[] = { is_irq : 0 }, }; -void sig_handler_common(int sig, struct sigcontext *sc) -{ - struct uml_pt_regs save_regs, *r; - struct signal_info *info; - int save_errno = errno, is_user; - - unprotect_kernel_mem(); - - r = (struct uml_pt_regs *) TASK_REGS(get_current()); - save_regs = *r; - is_user = user_context(SC_SP(sc)); - r->is_user = is_user; - r->mode.tt = sc; - if(sig != SIGUSR2) r->syscall = -1; - - change_sig(SIGUSR1, 1); - info = &sig_info[sig]; - if(!info->is_irq) unblock_signals(); - - (*info->handler)(sig, r); - - if(is_user){ - interrupt_end(); - block_signals(); - change_sig(SIGUSR1, 0); - set_user_mode(NULL); - } - *r = save_regs; - errno = save_errno; - if(is_user) protect_kernel_mem(); -} - void sig_handler(int sig, struct sigcontext sc) { - sig_handler_common(sig, &sc); + CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, + sig, &sc); } extern int timer_irq_inited, missed_ticks[]; void alarm_handler(int sig, struct sigcontext sc) { - int user; - if(!timer_irq_inited) return; missed_ticks[cpu()]++; - user = user_context(SC_SP(&sc)); if(sig == SIGALRM) switch_timers(0); - sig_handler_common(sig, &sc); + CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, + sig, &sc); if(sig == SIGALRM) switch_timers(1); diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 2b1c87271c6e..00148879c32c 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -3,12 +3,15 @@ # Licensed under the GPL # -obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o mem.o process_kern.o \ - syscall_user.o tracer.o uaccess_user.o sys-$(SUBARCH)/ +obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o ksyms.o mem.o process_kern.o \ + syscall_kern.o syscall_user.o time.o tracer.o trap_user.o \ + uaccess_user.o sys-$(SUBARCH)/ obj-$(CONFIG_PT_PROXY) += ptproxy/ -USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o tracer.o +export-objs = ksyms.o + +USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o time.o tracer.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) include $(TOPDIR)/Rules.make diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c new file mode 100644 index 000000000000..92ec85d67c7c --- /dev/null +++ b/arch/um/kernel/tt/ksyms.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/module.h" +#include "asm/uaccess.h" +#include "mode.h" + +EXPORT_SYMBOL(__do_copy_from_user); +EXPORT_SYMBOL(__do_copy_to_user); +EXPORT_SYMBOL(__do_strncpy_from_user); +EXPORT_SYMBOL(__do_strnlen_user); +EXPORT_SYMBOL(__do_clear_user); + +EXPORT_SYMBOL(tracing_pid); +EXPORT_SYMBOL(honeypot); + +/* + * 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/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c new file mode 100644 index 000000000000..463955bde899 --- /dev/null +++ b/arch/um/kernel/tt/syscall_kern.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/types.h" +#include "linux/utime.h" +#include "linux/sys.h" +#include "asm/unistd.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" +#include "sysdep/syscalls.h" +#include "kern_util.h" + +static inline int check_area(void *ptr, int size) +{ + return(verify_area(VERIFY_WRITE, ptr, size)); +} + +static int check_readlink(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], regs->regs.args[2])); +} + +static int check_utime(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], + sizeof(struct utimbuf))); +} + +static int check_oldstat(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], + sizeof(struct __old_kernel_stat))); +} + +static int check_stat(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], sizeof(struct stat))); +} + +static int check_stat64(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], sizeof(struct stat64))); +} + +struct bogus { + int kernel_ds; + int (*check_params)(struct pt_regs *); +}; + +struct bogus this_is_bogus[256] = { + [ __NR_mknod ] = { 1, NULL }, + [ __NR_mkdir ] = { 1, NULL }, + [ __NR_rmdir ] = { 1, NULL }, + [ __NR_unlink ] = { 1, NULL }, + [ __NR_symlink ] = { 1, NULL }, + [ __NR_link ] = { 1, NULL }, + [ __NR_rename ] = { 1, NULL }, + [ __NR_umount ] = { 1, NULL }, + [ __NR_mount ] = { 1, NULL }, + [ __NR_pivot_root ] = { 1, NULL }, + [ __NR_chdir ] = { 1, NULL }, + [ __NR_chroot ] = { 1, NULL }, + [ __NR_open ] = { 1, NULL }, + [ __NR_quotactl ] = { 1, NULL }, + [ __NR_sysfs ] = { 1, NULL }, + [ __NR_readlink ] = { 1, check_readlink }, + [ __NR_acct ] = { 1, NULL }, + [ __NR_execve ] = { 1, NULL }, + [ __NR_uselib ] = { 1, NULL }, + [ __NR_statfs ] = { 1, NULL }, + [ __NR_truncate ] = { 1, NULL }, + [ __NR_access ] = { 1, NULL }, + [ __NR_chmod ] = { 1, NULL }, + [ __NR_chown ] = { 1, NULL }, + [ __NR_lchown ] = { 1, NULL }, + [ __NR_utime ] = { 1, check_utime }, + [ __NR_oldlstat ] = { 1, check_oldstat }, + [ __NR_oldstat ] = { 1, check_oldstat }, + [ __NR_stat ] = { 1, check_stat }, + [ __NR_lstat ] = { 1, check_stat }, + [ __NR_stat64 ] = { 1, check_stat64 }, + [ __NR_lstat64 ] = { 1, check_stat64 }, + [ __NR_chown32 ] = { 1, NULL }, +}; + +/* sys_utimes */ + +static int check_bogosity(struct pt_regs *regs) +{ + struct bogus *bogon = &this_is_bogus[regs->regs.syscall]; + + if(!bogon->kernel_ds) return(0); + if(bogon->check_params && (*bogon->check_params)(regs)) + return(-EFAULT); + set_fs(KERNEL_DS); + return(0); +} + +/* Unlocked, I don't care if this is a bit off */ +int nsyscalls = 0; + +extern syscall_handler_t *sys_call_table[]; + +long execute_syscall_tt(void *r) +{ + struct pt_regs *regs = r; + long res; + int syscall; + + current->thread.nsyscalls++; + nsyscalls++; + syscall = regs->regs.syscall; + + if((syscall >= NR_syscalls) || (syscall < 0)) + res = -ENOSYS; + else if(honeypot && check_bogosity(regs)) + res = -EFAULT; + else res = EXECUTE_SYSCALL(syscall, regs); + + set_fs(USER_DS); + + if(current->thread.mode.tt.singlestep_syscall){ + current->thread.mode.tt.singlestep_syscall = 0; + current->ptrace &= ~PT_DTRACE; + force_sig(SIGTRAP, current); + } + + return(res); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c new file mode 100644 index 000000000000..8565b71b07cd --- /dev/null +++ b/arch/um/kernel/tt/time.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include "process.h" +#include "user.h" + +void user_time_init_tt(void) +{ + if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) + panic("Couldn't set SIGVTALRM handler"); + set_interval(ITIMER_VIRTUAL); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c new file mode 100644 index 000000000000..37c8af88e39e --- /dev/null +++ b/arch/um/kernel/tt/trap_user.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include "sysdep/ptrace.h" +#include "signal_user.h" +#include "user_util.h" +#include "kern_util.h" +#include "task.h" +#include "tt.h" + +void sig_handler_common_tt(int sig, struct sigcontext *sc) +{ + struct uml_pt_regs save_regs, *r; + struct signal_info *info; + int save_errno = errno, is_user; + + unprotect_kernel_mem(); + + r = (struct uml_pt_regs *) TASK_REGS(get_current()); + save_regs = *r; + is_user = user_context(SC_SP(sc)); + r->is_user = is_user; + r->mode.tt = sc; + if(sig != SIGUSR2) r->syscall = -1; + + change_sig(SIGUSR1, 1); + info = &sig_info[sig]; + if(!info->is_irq) unblock_signals(); + + (*info->handler)(sig, r); + + if(is_user){ + interrupt_end(); + block_signals(); + change_sig(SIGUSR1, 0); + set_user_mode(NULL); + } + *r = save_regs; + errno = save_errno; + if(is_user) protect_kernel_mem(); +} + +/* + * 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/umid.c b/arch/um/kernel/umid.c index 2ba2049510b3..e08acf5d5354 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -17,6 +17,8 @@ #include "umid.h" #include "init.h" #include "os.h" +#include "user_util.h" +#include "choose-mode.h" #define UMID_LEN 64 #define UML_DIR "~/.uml/" @@ -91,7 +93,7 @@ static int __init create_pid_file(void) return 0; } - sprintf(pid, "%d\n", (tracing_pid == -1) ? os_getpid() : tracing_pid); + sprintf(pid, "%d\n", os_getpid()); if(write(fd, pid, strlen(pid)) != strlen(pid)) printk("Write of pid file failed - errno = %d\n", errno); close(fd); @@ -179,7 +181,7 @@ int not_dead_yet(char *dir) dead = 1; } if(((kill(p, 0) < 0) && (errno == ESRCH)) || - (p == tracing_pid)) + (p == CHOOSE_MODE(tracing_pid, os_getpid()))) dead = 1; } if(!dead) return(1); diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index 7af4ef3d5dfd..33e302160d7c 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -3,15 +3,82 @@ * Licensed under the GPL */ +#include "linux/config.h" +#include "linux/slab.h" #include "asm/uaccess.h" +#include "asm/ptrace.h" +#include "choose-mode.h" +#include "kern.h" +#ifdef CONFIG_MODE_TT extern int modify_ldt(int func, void *ptr, unsigned long bytecount); -int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) +int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) { if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT); return(modify_ldt(func, ptr, bytecount)); } +#endif + +#ifdef CONFIG_MODE_SKAS +extern int userspace_pid; + +int sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) +{ + struct ptrace_ldt ldt; + void *buf; + int res, n; + + buf = kmalloc(bytecount, GFP_KERNEL); + if(buf == NULL) + return(-ENOMEM); + + res = 0; + + switch(func){ + case 1: + case 0x11: + res = copy_from_user(buf, ptr, bytecount); + break; + } + + if(res != 0){ + res = -EFAULT; + goto out; + } + + ldt = ((struct ptrace_ldt) { .func = func, + .ptr = buf, + .bytecount = bytecount }); + res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt); + if(res < 0) + goto out; + + switch(func){ + case 0: + case 2: + n = res; + res = copy_to_user(ptr, buf, n); + if(res != 0) + res = -EFAULT; + else + res = n; + break; + } + + out: + kfree(buf); + return(res); +} +#endif + +int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) +{ + return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, + ptr, bytecount)); +} + + /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index cb47c4e86b1e..817ef7479d3f 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -169,11 +169,12 @@ static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave } /* -b * FXSR floating point environment conversions. + * FXSR floating point environment conversions. */ -static inline int convert_fxsr_to_user(struct _fpstate *buf, - struct pt_regs *regs) +#ifdef CONFIG_MODE_TT +static inline int convert_fxsr_to_user_tt(struct _fpstate *buf, + struct pt_regs *regs) { struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); unsigned long env[7]; @@ -200,9 +201,17 @@ static inline int convert_fxsr_to_user(struct _fpstate *buf, } return 0; } +#endif -static inline int convert_fxsr_from_user(struct pt_regs *regs, - struct _fpstate *buf) +static inline int convert_fxsr_to_user(struct _fpstate *buf, + struct pt_regs *regs) +{ + return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0)); +} + +#ifdef CONFIG_MODE_TT +static inline int convert_fxsr_from_user_tt(struct pt_regs *regs, + struct _fpstate *buf) { struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); unsigned long env[7]; @@ -230,6 +239,13 @@ static inline int convert_fxsr_from_user(struct pt_regs *regs, } return 0; } +#endif + +static inline int convert_fxsr_from_user(struct pt_regs *regs, + struct _fpstate *buf) +{ + return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0)); +} int get_fpregs(unsigned long buf, struct task_struct *child) { @@ -251,7 +267,8 @@ int set_fpregs(unsigned long buf, struct task_struct *child) else return(0); } -int get_fpxregs(unsigned long buf, struct task_struct *tsk) +#ifdef CONFIG_MODE_TT +int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk) { struct pt_regs *regs = &tsk->thread.regs; struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); @@ -262,8 +279,15 @@ int get_fpxregs(unsigned long buf, struct task_struct *tsk) if(err) return -EFAULT; else return 0; } +#endif -int set_fpxregs(unsigned long buf, struct task_struct *tsk) +int get_fpxregs(unsigned long buf, struct task_struct *tsk) +{ + return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0)); +} + +#ifdef CONFIG_MODE_TT +int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk) { struct pt_regs *regs = &tsk->thread.regs; struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); @@ -274,6 +298,12 @@ int set_fpxregs(unsigned long buf, struct task_struct *tsk) if(err) return -EFAULT; else return 0; } +#endif + +int set_fpxregs(unsigned long buf, struct task_struct *tsk) +{ + return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0)); +} #ifdef notdef int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) @@ -291,8 +321,10 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) return(1); } #endif -static inline void copy_fpu_fxsave(struct pt_regs *regs, - struct user_i387_struct *buf) + +#ifdef CONFIG_MODE_TT +static inline void copy_fpu_fxsave_tt(struct pt_regs *regs, + struct user_i387_struct *buf) { struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs)); unsigned short *to; @@ -307,6 +339,13 @@ static inline void copy_fpu_fxsave(struct pt_regs *regs, memcpy( to, from, 5 * sizeof(unsigned short) ); } } +#endif + +static inline void copy_fpu_fxsave(struct pt_regs *regs, + struct user_i387_struct *buf) +{ + (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0); +} int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) { -- cgit v1.2.3 From 30768623c1f7594feb5a4883ac8de792ce95a571 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 22 Nov 2002 04:27:24 -0500 Subject: Minor build fixes to the last batch of skas merges. --- arch/um/kernel/skas/Makefile | 5 +++-- arch/um/kernel/skas/mem.c | 35 +++++++++++++++++++++++++++++++++++ arch/um/kernel/tt/syscall_kern.c | 3 --- include/asm-um/ptrace-generic.h | 2 ++ 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 arch/um/kernel/skas/mem.c diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index a58e13b91b6f..97544aa29d1e 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -3,8 +3,9 @@ # Licensed under the GPL # -obj-y = exec_kern.o exec_user.o mem_user.o mmu.o process.o process_kern.o \ - syscall_kern.o syscall_user.o time.o trap_user.o sys-$(SUBARCH)/ +obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ + process_kern.o syscall_kern.o syscall_user.o time.o trap_user.o \ + sys-$(SUBARCH)/ USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c new file mode 100644 index 000000000000..0968b583473a --- /dev/null +++ b/arch/um/kernel/skas/mem.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/config.h" +#include "linux/mm.h" +#include "mem_user.h" + +unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, + unsigned long *task_size_out) +{ + /* Round up to the nearest 4M */ + unsigned long top = ROUND_4M((unsigned long) &arg); + + *host_size_out = top; + *task_size_out = top; + return(((unsigned long) set_task_sizes_skas) & ~0xffffff); +} + +struct page *arch_validate_skas(struct page *page, int mask, int order) +{ + return(page); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c index 463955bde899..dd087fb96ff6 100644 --- a/arch/um/kernel/tt/syscall_kern.c +++ b/arch/um/kernel/tt/syscall_kern.c @@ -98,9 +98,6 @@ static int check_bogosity(struct pt_regs *regs) return(0); } -/* Unlocked, I don't care if this is a bit off */ -int nsyscalls = 0; - extern syscall_handler_t *sys_call_table[]; long execute_syscall_tt(void *r) diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h index 18f6b5991856..0a5f77de79ba 100644 --- a/include/asm-um/ptrace-generic.h +++ b/include/asm-um/ptrace-generic.h @@ -8,6 +8,8 @@ #ifndef __ASSEMBLY__ +#include "linux/config.h" +#include "skas_ptrace.h" #include "asm/current.h" #define pt_regs pt_regs_subarch -- cgit v1.2.3 From f575fea5a2a3d1252cd04c0e1ea2d19d9ff93013 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 22 Nov 2002 10:39:33 -0500 Subject: Merged the tlb.c changes from the skas patch. --- arch/um/kernel/skas/Makefile | 2 +- arch/um/kernel/skas/tlb.c | 155 ++++++++++++++++++++++++++++++ arch/um/kernel/tlb.c | 219 ++++--------------------------------------- arch/um/kernel/tt/Makefile | 2 +- arch/um/kernel/tt/tlb.c | 219 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 395 insertions(+), 202 deletions(-) create mode 100644 arch/um/kernel/skas/tlb.c create mode 100644 arch/um/kernel/tt/tlb.c diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index 97544aa29d1e..d696b40d7e94 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -4,7 +4,7 @@ # obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ - process_kern.o syscall_kern.o syscall_user.o time.o trap_user.o \ + process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \ sys-$(SUBARCH)/ USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c new file mode 100644 index 000000000000..e3d60415c75e --- /dev/null +++ b/arch/um/kernel/skas/tlb.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/sched.h" +#include "asm/page.h" +#include "asm/pgtable.h" +#include "asm/mmu.h" +#include "user_util.h" +#include "mem_user.h" +#include "skas.h" +#include "os.h" + +static void fix_range(struct mm_struct *mm, unsigned long start_addr, + unsigned long end_addr, int force) +{ + pgd_t *npgd; + pmd_t *npmd; + pte_t *npte; + unsigned long addr; + int r, w, x, err, fd; + + if(mm == NULL) return; + fd = mm->context.skas.mm_fd; + for(addr = start_addr; addr < end_addr;){ + npgd = pgd_offset(mm, addr); + npmd = pmd_offset(npgd, addr); + if(pmd_present(*npmd)){ + npte = pte_offset(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); + if(!pte_dirty(*npte)) w = 0; + if(!pte_young(*npte)){ + r = 0; + w = 0; + } + if(force || pte_newpage(*npte)){ + err = unmap(fd, (void *) addr, PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + if(pte_present(*npte)) + map(fd, addr, + pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x); + } + else if(pte_newprot(*npte)){ + protect(fd, addr, PAGE_SIZE, r, w, x, 1); + } + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; + } + else { + if(force || pmd_newpage(*npmd)){ + err = unmap(fd, (void *) addr, PMD_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + pmd_mkuptodate(*npmd); + } + addr += PMD_SIZE; + } + } +} + +static void flush_kernel_vm_range(unsigned long start, unsigned long end) +{ + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long addr; + int updated = 0, err; + + mm = &init_mm; + for(addr = start_vm; addr < end_vm;){ + pgd = pgd_offset(mm, addr); + pmd = pmd_offset(pgd, addr); + if(pmd_present(*pmd)){ + pte = pte_offset(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; + protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + } + addr += PAGE_SIZE; + + } + else { + if(pmd_newpage(*pmd)){ + updated = 1; + err = os_unmap_memory((void *) addr, PMD_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr += PMD_SIZE; + } + } +} + +void flush_tlb_kernel_vm_skas(void) +{ + flush_kernel_vm_range(start_vm, end_vm); +} + +void __flush_tlb_one_skas(unsigned long addr) +{ + flush_kernel_vm_range(addr, addr + PAGE_SIZE); +} + +void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if(mm == NULL) + flush_kernel_vm_range(start, end); + else fix_range(mm, start, end, 0); +} + +void flush_tlb_mm_skas(struct mm_struct *mm) +{ + if(mm == NULL) + flush_tlb_kernel_vm_skas(); + else fix_range(mm, 0, host_task_size, 0); +} + +void force_flush_all_skas(void) +{ + fix_range(current->mm, 0, host_task_size, 1); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index 000a26862ec5..2b41b4f4de0c 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -1,236 +1,55 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -#include "linux/sched.h" -#include "linux/slab.h" -#include "linux/bootmem.h" +#include "linux/mm.h" +#include "asm/page.h" #include "asm/pgalloc.h" -#include "asm-generic/tlb.h" -#include "asm/pgtable.h" -#include "asm/a.out.h" -#include "asm/processor.h" -#include "asm/mmu_context.h" -#include "asm/uaccess.h" -#include "asm/atomic.h" -#include "mem_user.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "tlb.h" -#include "os.h" - -static void fix_range(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force) -{ - pgd_t *npgd; - pmd_t *npmd; - pte_t *npte; - unsigned long addr; - int r, w, x, err; - - if((current->thread.mode.tt.extern_pid != -1) && - (current->thread.mode.tt.extern_pid != os_getpid())) - panic("fix_range fixing wrong address space, current = 0x%p", - current); - if(mm == NULL) return; - for(addr=start_addr;addr TASK_SIZE, which is - * only true in the honeypot case. - */ - addr = STACK_TOP - ABOVE_KMEM; - continue; - } - npgd = pgd_offset(mm, addr); - npmd = pmd_offset(npgd, addr); - if(pmd_present(*npmd)){ - npte = pte_offset_kernel(npmd, addr); - r = pte_read(*npte); - w = pte_write(*npte); - x = pte_exec(*npte); - if(!pte_dirty(*npte)) w = 0; - if(!pte_young(*npte)){ - r = 0; - w = 0; - } - if(force || pte_newpage(*npte)){ - err = os_unmap_memory((void *) addr, - PAGE_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - if(pte_present(*npte)) - map_memory(addr, - pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x); - } - else if(pte_newprot(*npte)){ - protect_memory(addr, PAGE_SIZE, r, w, x, 1); - } - *npte = pte_mkuptodate(*npte); - addr += PAGE_SIZE; - } - else { - if(force || pmd_newpage(*npmd)){ - err = os_unmap_memory((void *) addr, PMD_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - pmd_mkuptodate(*npmd); - } - addr += PMD_SIZE; - } - } -} - -atomic_t vmchange_seq = ATOMIC_INIT(1); - -void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) -{ - struct mm_struct *mm; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long addr; - int updated = 0, err; - - mm = &init_mm; - for(addr = start; addr < end;){ - pgd = pgd_offset(mm, addr); - pmd = pmd_offset(pgd, addr); - if(pmd_present(*pmd)){ - 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; - protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); - } - addr += PAGE_SIZE; - } - else { - if(pmd_newpage(*pmd)){ - updated = 1; - err = os_unmap_memory((void *) addr, PMD_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr += PMD_SIZE; - } - } - if(updated && update_seq) atomic_inc(&vmchange_seq); -} +#include "choose-mode.h" +#include "mode_kern.h" void flush_tlb_kernel_range(unsigned long start, unsigned long end) { flush_kernel_range(start, end, 1); } -static void protect_vm_page(unsigned long addr, int w, int must_succeed) +void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) { - int err; - - err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed); - if(err == 0) return; - else if((err == -EFAULT) || (err == -ENOMEM)){ - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); - protect_vm_page(addr, w, 1); - } - else panic("protect_vm_page : protect failed, errno = %d\n", err); + address &= PAGE_MASK; + flush_tlb_range(vma->vm_mm, address, address + PAGE_SIZE); } -void mprotect_kernel_vm(int w) +void flush_tlb_all(void) { - struct mm_struct *mm; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long addr; - - mm = &init_mm; - for(addr = start_vm; addr < end_vm;){ - pgd = pgd_offset(mm, addr); - pmd = pmd_offset(pgd, addr); - if(pmd_present(*pmd)){ - pte = pte_offset_kernel(pmd, addr); - if(pte_present(*pte)) protect_vm_page(addr, w, 0); - addr += PAGE_SIZE; - } - else addr += PMD_SIZE; - } + flush_tlb_mm(current->mm); } - + void flush_tlb_kernel_vm(void) { - flush_tlb_kernel_range(start_vm, end_vm); + CHOOSE_MODE(flush_tlb_kernel_vm_tt(), flush_tlb_kernel_vm_skas()); } void __flush_tlb_one(unsigned long addr) { - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); } - -void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + +void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - if(vma->vm_mm != current->mm) - return; - - /* Assumes that the range start ... end is entirely within - * either process memory or kernel vm - */ - if((start >= start_vm) && (start < end_vm)) - flush_kernel_range(start, end, 1); - else fix_range(vma->vm_mm, start, end, 0); + CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, mm, start, + end); } void flush_tlb_mm(struct mm_struct *mm) { - unsigned long seq; - - if(mm != current->mm) - return; - - fix_range(mm, 0, STACK_TOP, 0); - - seq = atomic_read(&vmchange_seq); - if(current->thread.mode.tt.vm_seq == seq) return; - current->thread.mode.tt.vm_seq = seq; - flush_kernel_range(start_vm, end_vm, 0); -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) -{ - address &= PAGE_MASK; - flush_tlb_range(vma, address, address + PAGE_SIZE); -} - -void flush_tlb_all(void) -{ - flush_tlb_mm(current->mm); + CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); } void force_flush_all(void) { - fix_range(current->mm, 0, STACK_TOP, 1); - flush_kernel_range(start_vm, end_vm, 0); + CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); } pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 00148879c32c..00c3eea54715 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -4,7 +4,7 @@ # obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o ksyms.o mem.o process_kern.o \ - syscall_kern.o syscall_user.o time.o tracer.o trap_user.o \ + syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ uaccess_user.o sys-$(SUBARCH)/ obj-$(CONFIG_PT_PROXY) += ptproxy/ diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c new file mode 100644 index 000000000000..7b858b7e1023 --- /dev/null +++ b/arch/um/kernel/tt/tlb.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/kernel.h" +#include "linux/sched.h" +#include "asm/page.h" +#include "asm/pgtable.h" +#include "asm/uaccess.h" +#include "user_util.h" +#include "mem_user.h" +#include "os.h" + +static void fix_range(struct mm_struct *mm, unsigned long start_addr, + unsigned long end_addr, int force) +{ + pgd_t *npgd; + pmd_t *npmd; + pte_t *npte; + unsigned long addr; + int r, w, x, err; + + if((current->thread.mode.tt.extern_pid != -1) && + (current->thread.mode.tt.extern_pid != os_getpid())) + panic("fix_range fixing wrong address space, current = 0x%p", + current); + if(mm == NULL) return; + for(addr=start_addr;addr TASK_SIZE, which is + * only true in the honeypot case. + */ + addr = STACK_TOP - ABOVE_KMEM; + continue; + } + npgd = pgd_offset(mm, addr); + npmd = pmd_offset(npgd, addr); + if(pmd_present(*npmd)){ + npte = pte_offset_kernel(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); + if(!pte_dirty(*npte)) w = 0; + if(!pte_young(*npte)){ + r = 0; + w = 0; + } + if(force || pte_newpage(*npte)){ + err = os_unmap_memory((void *) addr, + PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + if(pte_present(*npte)) + map_memory(addr, + pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x); + } + else if(pte_newprot(*npte)){ + protect_memory(addr, PAGE_SIZE, r, w, x, 1); + } + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; + } + else { + if(force || pmd_newpage(*npmd)){ + err = os_unmap_memory((void *) addr, PMD_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + pmd_mkuptodate(*npmd); + } + addr += PMD_SIZE; + } + } +} + +atomic_t vmchange_seq = ATOMIC_INIT(1); + +void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) +{ + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long addr; + int updated = 0, err; + + mm = &init_mm; + for(addr = start; addr < end;){ + pgd = pgd_offset(mm, addr); + pmd = pmd_offset(pgd, addr); + if(pmd_present(*pmd)){ + 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; + protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + } + addr += PAGE_SIZE; + } + else { + if(pmd_newpage(*pmd)){ + updated = 1; + err = os_unmap_memory((void *) addr, PMD_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr += PMD_SIZE; + } + } + if(updated && update_seq) atomic_inc(&vmchange_seq); +} + +static void protect_vm_page(unsigned long addr, int w, int must_succeed) +{ + int err; + + err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed); + if(err == 0) return; + else if((err == -EFAULT) || (err == -ENOMEM)){ + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + protect_vm_page(addr, w, 1); + } + else panic("protect_vm_page : protect failed, errno = %d\n", err); +} + +void mprotect_kernel_vm(int w) +{ + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long addr; + + mm = &init_mm; + for(addr = start_vm; addr < end_vm;){ + pgd = pgd_offset(mm, addr); + pmd = pmd_offset(pgd, addr); + if(pmd_present(*pmd)){ + pte = pte_offset_kernel(pmd, addr); + if(pte_present(*pte)) protect_vm_page(addr, w, 0); + addr += PAGE_SIZE; + } + else addr += PMD_SIZE; + } +} + +void flush_tlb_kernel_vm_tt(void) +{ + flush_tlb_kernel_vm_range(start_vm, end_vm); +} + +void __flush_tlb_one_tt(unsigned long addr) +{ + flush_tlb_kernel_vm_range(addr, addr + PAGE_SIZE); +} + +void flush_tlb_range_tt(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if(mm != current->mm) return; + + /* Assumes that the range start ... end is entirely within + * either process memory or kernel vm + */ + if((start >= start_vm) && (start < end_vm)) + flush_kernel_vm_range(start, end, 1); + else fix_range(mm, start, end, 0); +} + +void flush_tlb_mm_tt(struct mm_struct *mm) +{ + unsigned long seq; + + if(mm != current->mm) return; + + fix_range(mm, 0, STACK_TOP, 0); + + seq = atomic_read(&vmchange_seq); + if(current->thread.mode.tt.vm_seq == seq) return; + current->thread.mode.tt.vm_seq = seq; + flush_kernel_vm_range(start_vm, end_vm, 0); +} + +void force_flush_all_tt(void) +{ + fix_range(current->mm, 0, STACK_TOP, 1); + flush_kernel_vm_range(start_vm, end_vm, 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: + */ -- cgit v1.2.3 From 3fc0447a70827dbcc57c2225c2fe61001d4285c7 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 22 Nov 2002 11:22:57 -0500 Subject: Fixed various build problems with the tlb.c merge. --- arch/um/kernel/skas/include/mode_kern.h | 4 ++-- arch/um/kernel/skas/tlb.c | 11 ++++++----- arch/um/kernel/tlb.c | 12 ++++-------- arch/um/kernel/tt/include/mode_kern.h | 4 ++-- arch/um/kernel/tt/tlb.c | 22 ++++++++++++++-------- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/arch/um/kernel/skas/include/mode_kern.h b/arch/um/kernel/skas/include/mode_kern.h index dcbc70345a56..acc73b0c30c5 100644 --- a/arch/um/kernel/skas/include/mode_kern.h +++ b/arch/um/kernel/skas/include/mode_kern.h @@ -23,8 +23,8 @@ extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); extern void init_idle_skas(void); extern void flush_tlb_kernel_vm_skas(void); extern void __flush_tlb_one_skas(unsigned long addr); -extern void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start, - unsigned long end); +extern void flush_tlb_range_skas(struct vm_area_struct *vma, + unsigned long start, unsigned long end); extern void flush_tlb_mm_skas(struct mm_struct *mm); extern void force_flush_all_skas(void); extern long execute_syscall_skas(void *r); diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c index e3d60415c75e..655d3cdee856 100644 --- a/arch/um/kernel/skas/tlb.c +++ b/arch/um/kernel/skas/tlb.c @@ -5,6 +5,7 @@ #include "linux/stddef.h" #include "linux/sched.h" +#include "linux/mm.h" #include "asm/page.h" #include "asm/pgtable.h" #include "asm/mmu.h" @@ -28,7 +29,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, npgd = pgd_offset(mm, addr); npmd = pmd_offset(npgd, addr); if(pmd_present(*npmd)){ - npte = pte_offset(npmd, addr); + npte = pte_offset_kernel(npmd, addr); r = pte_read(*npte); w = pte_write(*npte); x = pte_exec(*npte); @@ -80,7 +81,7 @@ static void flush_kernel_vm_range(unsigned long start, unsigned long end) pgd = pgd_offset(mm, addr); pmd = pmd_offset(pgd, addr); if(pmd_present(*pmd)){ - pte = pte_offset(pmd, addr); + pte = pte_offset_kernel(pmd, addr); if(!pte_present(*pte) || pte_newpage(*pte)){ updated = 1; err = os_unmap_memory((void *) addr, @@ -123,12 +124,12 @@ void __flush_tlb_one_skas(unsigned long addr) flush_kernel_vm_range(addr, addr + PAGE_SIZE); } -void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start, +void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - if(mm == NULL) + if(vma->vm_mm == NULL) flush_kernel_vm_range(start, end); - else fix_range(mm, start, end, 0); + else fix_range(vma->vm_mm, start, end, 0); } void flush_tlb_mm_skas(struct mm_struct *mm) diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index 2b41b4f4de0c..ea2ed5486881 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -6,18 +6,14 @@ #include "linux/mm.h" #include "asm/page.h" #include "asm/pgalloc.h" +#include "asm/tlbflush.h" #include "choose-mode.h" #include "mode_kern.h" -void flush_tlb_kernel_range(unsigned long start, unsigned long end) -{ - flush_kernel_range(start, end, 1); -} - void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) { address &= PAGE_MASK; - flush_tlb_range(vma->vm_mm, address, address + PAGE_SIZE); + flush_tlb_range(vma, address, address + PAGE_SIZE); } void flush_tlb_all(void) @@ -35,10 +31,10 @@ void __flush_tlb_one(unsigned long addr) CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); } -void flush_tlb_range(struct mm_struct *mm, unsigned long start, +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, mm, start, + CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, end); } diff --git a/arch/um/kernel/tt/include/mode_kern.h b/arch/um/kernel/tt/include/mode_kern.h index 7482e345f1c9..f8da37c07c55 100644 --- a/arch/um/kernel/tt/include/mode_kern.h +++ b/arch/um/kernel/tt/include/mode_kern.h @@ -24,8 +24,8 @@ extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); extern void init_idle_tt(void); extern void flush_tlb_kernel_vm_tt(void); extern void __flush_tlb_one_tt(unsigned long addr); -extern void flush_tlb_range_tt(struct mm_struct *mm, unsigned long start, - unsigned long end); +extern void flush_tlb_range_tt(struct vm_area_struct *vma, + unsigned long start, unsigned long end); extern void flush_tlb_mm_tt(struct mm_struct *mm); extern void force_flush_all_tt(void); extern long execute_syscall_tt(void *r); diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c index 7b858b7e1023..fbe0a4fd3915 100644 --- a/arch/um/kernel/tt/tlb.c +++ b/arch/um/kernel/tt/tlb.c @@ -6,6 +6,7 @@ #include "linux/stddef.h" #include "linux/kernel.h" #include "linux/sched.h" +#include "linux/mm.h" #include "asm/page.h" #include "asm/pgtable.h" #include "asm/uaccess.h" @@ -130,6 +131,11 @@ void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) if(updated && update_seq) atomic_inc(&vmchange_seq); } +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + flush_kernel_range(start, end, 1); +} + static void protect_vm_page(unsigned long addr, int w, int must_succeed) { int err; @@ -166,25 +172,25 @@ void mprotect_kernel_vm(int w) void flush_tlb_kernel_vm_tt(void) { - flush_tlb_kernel_vm_range(start_vm, end_vm); + flush_tlb_kernel_range(start_vm, end_vm); } void __flush_tlb_one_tt(unsigned long addr) { - flush_tlb_kernel_vm_range(addr, addr + PAGE_SIZE); + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); } -void flush_tlb_range_tt(struct mm_struct *mm, unsigned long start, +void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - if(mm != current->mm) return; + if(vma->vm_mm != current->mm) return; /* Assumes that the range start ... end is entirely within * either process memory or kernel vm */ if((start >= start_vm) && (start < end_vm)) - flush_kernel_vm_range(start, end, 1); - else fix_range(mm, start, end, 0); + flush_kernel_range(start, end, 1); + else fix_range(vma->vm_mm, start, end, 0); } void flush_tlb_mm_tt(struct mm_struct *mm) @@ -198,13 +204,13 @@ void flush_tlb_mm_tt(struct mm_struct *mm) seq = atomic_read(&vmchange_seq); if(current->thread.mode.tt.vm_seq == seq) return; current->thread.mode.tt.vm_seq = seq; - flush_kernel_vm_range(start_vm, end_vm, 0); + flush_kernel_range(start_vm, end_vm, 0); } void force_flush_all_tt(void) { fix_range(current->mm, 0, STACK_TOP, 1); - flush_kernel_vm_range(start_vm, end_vm, 0); + flush_kernel_range(start_vm, end_vm, 0); } /* -- cgit v1.2.3 From 41fb3bb0728d67c7646bc45296d3454e9af4aad2 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 22 Nov 2002 11:47:15 -0500 Subject: Merged the rest of the skas changes. --- arch/um/kernel/um_arch.c | 64 ++++++++++++++++++++++++++++++++++-------------- include/asm-um/page.h | 2 ++ 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index eb5a5e6eef42..50c3f6313e16 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -41,13 +41,14 @@ #define DEFAULT_COMMAND_LINE "root=6200" struct cpuinfo_um boot_cpu_data = { - .loops_per_jiffy = 0, - .ipi_pipe = { -1, -1 } + .loops_per_jiffy = 0, + .ipi_pipe = { -1, -1 } }; unsigned long thread_saved_pc(struct task_struct *task) { - return(os_process_pc(task->thread.mode.tt.extern_pid)); + return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, + thread))); } static int show_cpuinfo(struct seq_file *m, void *v) @@ -96,16 +97,7 @@ pte_t * __bad_pagetable(void) return(NULL); } -#ifdef CONFIG_HOST_2G_2G -#define TOP 0x80000000 -#else -#define TOP 0xc0000000 -#endif - -#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) -#define START (TOP - SIZE) - -/* Set in main */ +/* Set in linux_main */ unsigned long host_task_size; unsigned long task_size; @@ -192,11 +184,48 @@ static int __init uml_ncpus_setup(char *line, int *add) __uml_setup("ncpus=", uml_ncpus_setup, "ncpus=<# of desired CPUs>\n" -" This tells an SMP kernel how many virtual processors to start.\n" -" Currently, this has no effect because SMP isn't enabled.\n\n" +" This tells an SMP kernel how many virtual processors to start.\n\n" ); #endif +int force_tt = 0; + +if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) ++#define DEFAULT_TT 0 + +static int __init mode_tt_setup(char *line, int *add) +{ + force_tt = 1; + return(0); +} + +__uml_setup("mode=tt", mode_tt_setup, +"mode=tt\n" +" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n" +" forces UML to run in tt (tracing thread) mode. It is not the default\n" +" because it's slower and less secure than skas mode.\n\n" +); + +#else +#ifdef CONFIG_MODE_SKAS + +#define DEFAULT_TT 0 + +#else +#ifdef CONFIG_MODE_TT + +#define DEFAULT_TT 1 + +#else + +#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled + +#endif +#endif +#endif + +int mode_tt = DEFAULT_TT; + static int __init Usage(char *line, int *add) { const char **p; @@ -244,9 +273,6 @@ static void __init uml_postsetup(void) return; } -extern int debug_trace; -int mode_tt = 1; - /* Set during early boot */ unsigned long brk_start; static struct vm_reserved kernel_vm_reserved; @@ -267,7 +293,7 @@ int linux_main(int argc, char **argv) } if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE); - mode_tt = 1; + mode_tt = force_tt ? 1 : !can_do_skas(); uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, &host_task_size, &task_size); diff --git a/include/asm-um/page.h b/include/asm-um/page.h index e3279d1d0b31..f4c0f7eb0d05 100644 --- a/include/asm-um/page.h +++ b/include/asm-um/page.h @@ -18,6 +18,8 @@ struct page; #undef PAGE_OFFSET #undef KERNELBASE +extern unsigned long uml_physmem; + #define PAGE_OFFSET (uml_physmem) #define KERNELBASE PAGE_OFFSET -- cgit v1.2.3 From 16c80381fd641e99268f4f80ee6542afef212d66 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sat, 23 Nov 2002 06:49:59 -0500 Subject: Finished the skas merge by eliminating a syntax error, fixing the new compilation warnings, and fixing a call to handle_page_fault. --- arch/um/include/kern_util.h | 1 + arch/um/kernel/skas/include/mode_kern.h | 2 +- arch/um/kernel/skas/include/uaccess.h | 2 +- arch/um/kernel/skas/process.c | 5 ++++- arch/um/kernel/skas/process_kern.c | 3 ++- arch/um/kernel/tt/exec_kern.c | 1 + arch/um/kernel/tt/include/mode_kern.h | 2 +- arch/um/kernel/tt/process_kern.c | 5 +++-- arch/um/kernel/tt/ptproxy/ptrace.c | 1 + arch/um/kernel/um_arch.c | 6 +++--- 10 files changed, 18 insertions(+), 10 deletions(-) diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index f94731350cd8..8bef1a8a6153 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -75,6 +75,7 @@ extern void debugger_parent_signal(int status, int pid); extern void child_signal(int pid, int status); extern int init_ptrace_proxy(int idle_pid, int startup, int stop); extern int init_parent_proxy(int pid); +extern int singlestepping(void *t); extern void check_stack_overflow(void *ptr); extern void relay_signal(int sig, struct uml_pt_regs *regs); extern void not_implemented(void); diff --git a/arch/um/kernel/skas/include/mode_kern.h b/arch/um/kernel/skas/include/mode_kern.h index acc73b0c30c5..e4b472ac7d2d 100644 --- a/arch/um/kernel/skas/include/mode_kern.h +++ b/arch/um/kernel/skas/include/mode_kern.h @@ -34,7 +34,7 @@ extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, extern int start_uml_skas(void); extern struct page *arch_validate_skas(struct page *page, int mask, int order); extern int external_pid_skas(struct task_struct *task); -extern int thread_pid_skas(struct thread_struct *thread); +extern int thread_pid_skas(struct task_struct *task); #define kmem_end_skas (host_task_size) diff --git a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h index 2f266a26ee57..9e9f9c273009 100644 --- a/arch/um/kernel/skas/include/uaccess.h +++ b/arch/um/kernel/skas/include/uaccess.h @@ -37,7 +37,7 @@ static inline unsigned long maybe_map(unsigned long virt, int is_write) int dummy_code; if(IS_ERR(phys) || (is_write && !pte_write(pte))){ - if(!handle_page_fault(virt, 0, is_write, 0, &dummy_code)) + if(handle_page_fault(virt, 0, is_write, 0, &dummy_code)) return(0); phys = um_virt_to_phys(current, virt, NULL); } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index c3283a366cb8..5c72105d84dd 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -298,7 +298,10 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg) cb_back = &here; if(setjmp(here) == 0) longjmp(initial_jmpbuf, 2); - + + cb_proc = NULL; + cb_arg = NULL; + cb_back = NULL; } void halt_skas(void) diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index bc3394b04343..ed17599d2c56 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -137,6 +137,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, void init_idle_skas(void) { cpu_tasks[current->thread_info->cpu].pid = os_getpid(); + default_idle(); } extern void start_kernel(void); @@ -177,7 +178,7 @@ int external_pid_skas(struct task_struct *task) return(userspace_pid); } -int thread_pid_skas(struct thread_struct *thread) +int thread_pid_skas(struct task_struct *task) { return(userspace_pid); } diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index dd52d8751c5c..afd94713d742 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -9,6 +9,7 @@ #include "asm/ptrace.h" #include "asm/uaccess.h" #include "asm/pgalloc.h" +#include "asm/tlbflush.h" #include "user_util.h" #include "kern_util.h" #include "irq_user.h" diff --git a/arch/um/kernel/tt/include/mode_kern.h b/arch/um/kernel/tt/include/mode_kern.h index f8da37c07c55..3dbd434f1abe 100644 --- a/arch/um/kernel/tt/include/mode_kern.h +++ b/arch/um/kernel/tt/include/mode_kern.h @@ -35,7 +35,7 @@ extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, extern int start_uml_tt(void); extern struct page *arch_validate_tt(struct page *page, int mask, int order); extern int external_pid_tt(struct task_struct *task); -extern int thread_pid_tt(struct thread_struct *thread); +extern int thread_pid_tt(struct task_struct *task); #define kmem_end_tt (host_task_size - ABOVE_KMEM) diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index db9cfc294bb7..5b4b285f8cd4 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -9,6 +9,7 @@ #include "asm/system.h" #include "asm/pgalloc.h" #include "asm/ptrace.h" +#include "asm/tlbflush.h" #include "irq_user.h" #include "signal_user.h" #include "kern_util.h" @@ -480,9 +481,9 @@ int external_pid_tt(struct task_struct *task) return(task->thread.mode.tt.extern_pid); } -int thread_pid_tt(struct thread_struct *thread) +int thread_pid_tt(struct task_struct *task) { - return(thread->mode.tt.extern_pid); + return(task->thread.mode.tt.extern_pid); } int is_valid_pid(int pid) diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c index 910d026677ca..721d0a306fde 100644 --- a/arch/um/kernel/tt/ptproxy/ptrace.c +++ b/arch/um/kernel/tt/ptproxy/ptrace.c @@ -21,6 +21,7 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml #include "user_util.h" #include "kern_util.h" #include "ptrace_user.h" +#include "tt.h" long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, long arg3, long arg4, pid_t child, int *ret) diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 50c3f6313e16..aacf0ca51a63 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -48,7 +48,7 @@ struct cpuinfo_um boot_cpu_data = { unsigned long thread_saved_pc(struct task_struct *task) { return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, - thread))); + task))); } static int show_cpuinfo(struct seq_file *m, void *v) @@ -190,8 +190,8 @@ __uml_setup("ncpus=", uml_ncpus_setup, int force_tt = 0; -if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) -+#define DEFAULT_TT 0 +#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) +#define DEFAULT_TT 0 static int __init mode_tt_setup(char *line, int *add) { -- cgit v1.2.3 From 433553bd1f42c0515fe77d9c0a93b67c2ff66030 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sat, 23 Nov 2002 09:25:48 -0500 Subject: Updated to 2.5.49, which involved fixing the calls to do_fork. --- arch/um/kernel/process_kern.c | 2 +- arch/um/kernel/syscall_kern.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 1588e175b4db..0e247f1a20bf 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -190,7 +190,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) current->thread.request.u.thread.proc = fn; current->thread.request.u.thread.arg = arg; - p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL); + p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL); if(IS_ERR(p)) panic("do_fork failed in kernel_thread"); return(p->pid); } diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index b15340a6b837..ab42524562b1 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -33,7 +33,7 @@ long sys_fork(void) struct task_struct *p; current->thread.forking = 1; - p = do_fork(SIGCHLD, 0, NULL, 0, NULL); + p = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL); current->thread.forking = 0; return(IS_ERR(p) ? PTR_ERR(p) : p->pid); } @@ -43,7 +43,7 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp) struct task_struct *p; current->thread.forking = 1; - p = do_fork(clone_flags, newsp, NULL, 0, NULL); + p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL); current->thread.forking = 0; return(IS_ERR(p) ? PTR_ERR(p) : p->pid); } @@ -53,7 +53,7 @@ long sys_vfork(void) struct task_struct *p; current->thread.forking = 1; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL); + p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, NULL); current->thread.forking = 0; return(IS_ERR(p) ? PTR_ERR(p) : p->pid); } -- cgit v1.2.3 From 64d40969e2859bd6a3d051f1819043278dd82d20 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Nov 2002 03:41:02 -0500 Subject: A whole lot of small changes to sync up the 2.4 and 2.5 pools somewhat. Mostly whitespace changes, plus some code movement. Also added checksum.S to the repository, which I had somehow missed before. --- arch/um/sys-i386/checksum.S | 460 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 460 insertions(+) create mode 100644 arch/um/sys-i386/checksum.S diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S new file mode 100644 index 000000000000..a11171fb6223 --- /dev/null +++ b/arch/um/sys-i386/checksum.S @@ -0,0 +1,460 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Pentium Pro/II routines: + * Alexander Kjeldaas + * Finn Arne Gangstad + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception + * handling. + * Andi Kleen, add zeroing on error + * converted to pure assembler + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ + +/* +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) + */ + +.text +.align 4 +.globl arch_csum_partial + +#ifndef CONFIG_X86_USE_PPRO_CHECKSUM + + /* + * Experiments with Ethernet and SLIP connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. We get at + * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ +arch_csum_partial: + pushl %esi + pushl %ebx + movl 20(%esp),%eax # Function arg: unsigned int sum + movl 16(%esp),%ecx # Function arg: int len + movl 12(%esp),%esi # Function arg: unsigned char *buff + testl $2, %esi # Check alignment. + jz 2f # Jump if alignment is ok. + subl $2, %ecx # Alignment uses up two bytes. + jae 1f # Jump if we had at least two bytes. + addl $2, %ecx # ecx was < 2. Deal with it. + jmp 4f +1: movw (%esi), %bx + addl $2, %esi + addw %bx, %ax + adcl $0, %eax +2: + movl %ecx, %edx + shrl $5, %ecx + jz 2f + testl %esi, %esi +1: movl (%esi), %ebx + adcl %ebx, %eax + movl 4(%esi), %ebx + adcl %ebx, %eax + movl 8(%esi), %ebx + adcl %ebx, %eax + movl 12(%esi), %ebx + adcl %ebx, %eax + movl 16(%esi), %ebx + adcl %ebx, %eax + movl 20(%esi), %ebx + adcl %ebx, %eax + movl 24(%esi), %ebx + adcl %ebx, %eax + movl 28(%esi), %ebx + adcl %ebx, %eax + lea 32(%esi), %esi + dec %ecx + jne 1b + adcl $0, %eax +2: movl %edx, %ecx + andl $0x1c, %edx + je 4f + shrl $2, %edx # This clears CF +3: adcl (%esi), %eax + lea 4(%esi), %esi + dec %edx + jne 3b + adcl $0, %eax +4: andl $3, %ecx + jz 7f + cmpl $2, %ecx + jb 5f + movw (%esi),%cx + leal 2(%esi),%esi + je 6f + shll $16,%ecx +5: movb (%esi),%cl +6: addl %ecx,%eax + adcl $0, %eax +7: + popl %ebx + popl %esi + ret + +#else + +/* Version for PentiumII/PPro */ + +arch_csum_partial: + pushl %esi + pushl %ebx + movl 20(%esp),%eax # Function arg: unsigned int sum + movl 16(%esp),%ecx # Function arg: int len + movl 12(%esp),%esi # Function arg: const unsigned char *buf + + testl $2, %esi + jnz 30f +10: + movl %ecx, %edx + movl %ecx, %ebx + andl $0x7c, %ebx + shrl $7, %ecx + addl %ebx,%esi + shrl $2, %ebx + negl %ebx + lea 45f(%ebx,%ebx,2), %ebx + testl %esi, %esi + jmp *%ebx + + # Handle 2-byte-aligned regions +20: addw (%esi), %ax + lea 2(%esi), %esi + adcl $0, %eax + jmp 10b + +30: subl $2, %ecx + ja 20b + je 32f + movzbl (%esi),%ebx # csumming 1 byte, 2-aligned + addl %ebx, %eax + adcl $0, %eax + jmp 80f +32: + addw (%esi), %ax # csumming 2 bytes, 2-aligned + adcl $0, %eax + jmp 80f + +40: + addl -128(%esi), %eax + adcl -124(%esi), %eax + adcl -120(%esi), %eax + adcl -116(%esi), %eax + adcl -112(%esi), %eax + adcl -108(%esi), %eax + adcl -104(%esi), %eax + adcl -100(%esi), %eax + adcl -96(%esi), %eax + adcl -92(%esi), %eax + adcl -88(%esi), %eax + adcl -84(%esi), %eax + adcl -80(%esi), %eax + adcl -76(%esi), %eax + adcl -72(%esi), %eax + adcl -68(%esi), %eax + adcl -64(%esi), %eax + adcl -60(%esi), %eax + adcl -56(%esi), %eax + adcl -52(%esi), %eax + adcl -48(%esi), %eax + adcl -44(%esi), %eax + adcl -40(%esi), %eax + adcl -36(%esi), %eax + adcl -32(%esi), %eax + adcl -28(%esi), %eax + adcl -24(%esi), %eax + adcl -20(%esi), %eax + adcl -16(%esi), %eax + adcl -12(%esi), %eax + adcl -8(%esi), %eax + adcl -4(%esi), %eax +45: + lea 128(%esi), %esi + adcl $0, %eax + dec %ecx + jge 40b + movl %edx, %ecx +50: andl $3, %ecx + jz 80f + + # Handle the last 1-3 bytes without jumping + notl %ecx # 1->2, 2->1, 3->0, higher bits are masked + movl $0xffffff,%ebx # by the shll and shrl instructions + shll $3,%ecx + shrl %cl,%ebx + andl -128(%esi),%ebx # esi is 4-aligned so should be ok + addl %ebx,%eax + adcl $0,%eax +80: + popl %ebx + popl %esi + ret + +#endif + +/* +unsigned int csum_partial_copy_generic (const char *src, char *dst, + int len, int sum, int *src_err_ptr, int *dst_err_ptr) + */ + +/* + * Copy from ds while checksumming, otherwise like csum_partial + * + * The macros SRC and DST specify the type of access for the instruction. + * thus we can call a custom exception handler for all access types. + * + * FIXME: could someone double-check whether I haven't mixed up some SRC and + * DST definitions? It's damn hard to trigger all cases. I hope I got + * them all but there's no guarantee. + */ + +#define SRC(y...) \ + 9999: y; \ + .section __ex_table, "a"; \ + .long 9999b, 6001f ; \ + .previous + +#define DST(y...) \ + 9999: y; \ + .section __ex_table, "a"; \ + .long 9999b, 6002f ; \ + .previous + +.align 4 +.globl csum_partial_copy_generic_i386 + +#ifndef CONFIG_X86_USE_PPRO_CHECKSUM + +#define ARGBASE 16 +#define FP 12 + +csum_partial_copy_generic_i386: + subl $4,%esp + pushl %edi + pushl %esi + pushl %ebx + movl ARGBASE+16(%esp),%eax # sum + movl ARGBASE+12(%esp),%ecx # len + movl ARGBASE+4(%esp),%esi # src + movl ARGBASE+8(%esp),%edi # dst + + testl $2, %edi # Check alignment. + jz 2f # Jump if alignment is ok. + subl $2, %ecx # Alignment uses up two bytes. + jae 1f # Jump if we had at least two bytes. + addl $2, %ecx # ecx was < 2. Deal with it. + jmp 4f +SRC(1: movw (%esi), %bx ) + addl $2, %esi +DST( movw %bx, (%edi) ) + addl $2, %edi + addw %bx, %ax + adcl $0, %eax +2: + movl %ecx, FP(%esp) + shrl $5, %ecx + jz 2f + testl %esi, %esi +SRC(1: movl (%esi), %ebx ) +SRC( movl 4(%esi), %edx ) + adcl %ebx, %eax +DST( movl %ebx, (%edi) ) + adcl %edx, %eax +DST( movl %edx, 4(%edi) ) + +SRC( movl 8(%esi), %ebx ) +SRC( movl 12(%esi), %edx ) + adcl %ebx, %eax +DST( movl %ebx, 8(%edi) ) + adcl %edx, %eax +DST( movl %edx, 12(%edi) ) + +SRC( movl 16(%esi), %ebx ) +SRC( movl 20(%esi), %edx ) + adcl %ebx, %eax +DST( movl %ebx, 16(%edi) ) + adcl %edx, %eax +DST( movl %edx, 20(%edi) ) + +SRC( movl 24(%esi), %ebx ) +SRC( movl 28(%esi), %edx ) + adcl %ebx, %eax +DST( movl %ebx, 24(%edi) ) + adcl %edx, %eax +DST( movl %edx, 28(%edi) ) + + lea 32(%esi), %esi + lea 32(%edi), %edi + dec %ecx + jne 1b + adcl $0, %eax +2: movl FP(%esp), %edx + movl %edx, %ecx + andl $0x1c, %edx + je 4f + shrl $2, %edx # This clears CF +SRC(3: movl (%esi), %ebx ) + adcl %ebx, %eax +DST( movl %ebx, (%edi) ) + lea 4(%esi), %esi + lea 4(%edi), %edi + dec %edx + jne 3b + adcl $0, %eax +4: andl $3, %ecx + jz 7f + cmpl $2, %ecx + jb 5f +SRC( movw (%esi), %cx ) + leal 2(%esi), %esi +DST( movw %cx, (%edi) ) + leal 2(%edi), %edi + je 6f + shll $16,%ecx +SRC(5: movb (%esi), %cl ) +DST( movb %cl, (%edi) ) +6: addl %ecx, %eax + adcl $0, %eax +7: +5000: + +# Exception handler: +.section .fixup, "ax" + +6001: + movl ARGBASE+20(%esp), %ebx # src_err_ptr + movl $-EFAULT, (%ebx) + + # zero the complete destination - computing the rest + # is too much work + movl ARGBASE+8(%esp), %edi # dst + movl ARGBASE+12(%esp), %ecx # len + xorl %eax,%eax + rep ; stosb + + jmp 5000b + +6002: + movl ARGBASE+24(%esp), %ebx # dst_err_ptr + movl $-EFAULT,(%ebx) + jmp 5000b + +.previous + + popl %ebx + popl %esi + popl %edi + popl %ecx # equivalent to addl $4,%esp + ret + +#else + +/* Version for PentiumII/PPro */ + +#define ROUND1(x) \ + SRC(movl x(%esi), %ebx ) ; \ + addl %ebx, %eax ; \ + DST(movl %ebx, x(%edi) ) ; + +#define ROUND(x) \ + SRC(movl x(%esi), %ebx ) ; \ + adcl %ebx, %eax ; \ + DST(movl %ebx, x(%edi) ) ; + +#define ARGBASE 12 + +csum_partial_copy_generic_i386: + pushl %ebx + pushl %edi + pushl %esi + movl ARGBASE+4(%esp),%esi #src + movl ARGBASE+8(%esp),%edi #dst + movl ARGBASE+12(%esp),%ecx #len + movl ARGBASE+16(%esp),%eax #sum +# movl %ecx, %edx + movl %ecx, %ebx + movl %esi, %edx + shrl $6, %ecx + andl $0x3c, %ebx + negl %ebx + subl %ebx, %esi + subl %ebx, %edi + lea -1(%esi),%edx + andl $-32,%edx + lea 3f(%ebx,%ebx), %ebx + testl %esi, %esi + jmp *%ebx +1: addl $64,%esi + addl $64,%edi + SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl) + ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52) + ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36) + ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20) + ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4) +3: adcl $0,%eax + addl $64, %edx + dec %ecx + jge 1b +4: movl ARGBASE+12(%esp),%edx #len + andl $3, %edx + jz 7f + cmpl $2, %edx + jb 5f +SRC( movw (%esi), %dx ) + leal 2(%esi), %esi +DST( movw %dx, (%edi) ) + leal 2(%edi), %edi + je 6f + shll $16,%edx +5: +SRC( movb (%esi), %dl ) +DST( movb %dl, (%edi) ) +6: addl %edx, %eax + adcl $0, %eax +7: +.section .fixup, "ax" +6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr + movl $-EFAULT, (%ebx) + # zero the complete destination (computing the rest is too much work) + movl ARGBASE+8(%esp),%edi # dst + movl ARGBASE+12(%esp),%ecx # len + xorl %eax,%eax + rep; stosb + jmp 7b +6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr + movl $-EFAULT, (%ebx) + jmp 7b +.previous + + popl %esi + popl %edi + popl %ebx + ret + +#undef ROUND +#undef ROUND1 + +#endif -- cgit v1.2.3 From 0fc3a8cde0a53af12f9f9566b0304439b83e4d97 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Nov 2002 11:03:24 -0500 Subject: Small fixes to sync up the 2.4 and 2.5 pools. Also fixed a stupid signal handling bug. --- arch/um/drivers/chan_user.c | 2 +- arch/um/include/user_util.h | 1 - arch/um/kernel/frame_kern.c | 10 ++-- arch/um/kernel/process.c | 44 +++------------ arch/um/kernel/skas/include/skas.h | 1 + arch/um/kernel/skas/process.c | 23 ++++++++ arch/um/kernel/skas/trap_user.c | 2 + arch/um/kernel/syscall_user.c | 8 +-- arch/um/kernel/trap_user.c | 8 +-- arch/um/kernel/tt/gdb.c | 19 +++++-- arch/um/kernel/tt/include/debug.h | 3 ++ arch/um/kernel/tt/process_kern.c | 106 ++++++++++++++++++------------------- arch/um/kernel/tt/ptproxy/Makefile | 1 - arch/um/kernel/tt/tlb.c | 11 ++-- arch/um/kernel/tt/tracer.c | 5 +- arch/um/main.c | 6 +-- include/asm-um/processor-generic.h | 5 +- 17 files changed, 132 insertions(+), 123 deletions(-) diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 62d30a693f52..e06f20a14877 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -187,7 +187,7 @@ void register_winch(int fd, void *device_data) if(!isatty(fd)) return; - pid = tcgetpgrp(fd); + pid = tcgetpgrp(fd); if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && (pid == -1)){ thread = winch_tramp(fd, device_data, &thread_fd); diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index f1d3bca2bd27..a419cc9ccfff 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -73,7 +73,6 @@ extern void setup_hostinfo(void); extern void add_arg(char *cmd_line, char *arg); extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); extern void init_new_thread_signals(int altstack); -extern void attach_process(int pid); extern void do_exec(int old_pid, int new_pid); extern void tracer_panic(char *msg, ...); extern char *get_umid(int only_if_set); diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c index b7abbf55498c..cd2177629bec 100644 --- a/arch/um/kernel/frame_kern.c +++ b/arch/um/kernel/frame_kern.c @@ -29,11 +29,11 @@ static int copy_restorer(void (*restorer)(void), unsigned long start, static int copy_sc_to_user(void *to, struct pt_regs *from) { - return(CHOOSE_MODE(copy_sc_to_user_tt(to, from->regs.mode.tt, - &signal_frame_sc_sr.arch), - copy_sc_to_user_skas(to, &from->regs, - current->thread.cr2, - current->thread.err))); + return(CHOOSE_MODE(copy_sc_to_user_tt(to, from->regs.mode.tt, + &signal_frame_sc_sr.arch), + copy_sc_to_user_skas(to, &from->regs, + current->thread.cr2, + current->thread.err))); } int setup_signal_stack_si(unsigned long stack_top, int sig, diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 1119d6b2b922..44e9a980949f 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -39,6 +39,7 @@ #include "mode.h" #ifdef CONFIG_MODE_SKAS #include "skas_ptrace.h" +#include "skas.h" #endif void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) @@ -130,12 +131,6 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack, return(arg.pid); } -void trace_myself(void) -{ - if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) - panic("ptrace failed in trace_myself"); -} - void suspend_new_thread(int fd) { char c; @@ -227,19 +222,19 @@ void __init check_ptrace(void) break; } } - stop_ptraced_child(pid, stack, 0); + stop_ptraced_child(pid, stack, 0); printk("OK\n"); } int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) { jmp_buf buf; - int n; + int n; *jmp_ptr = &buf; - n = setjmp(buf); - if(n != 0) - return(n); + n = setjmp(buf); + if(n != 0) + return(n); (*fn)(arg); return(0); } @@ -254,31 +249,6 @@ void forward_pending_sigio(int target) kill(target, SIGIO); } -#ifdef CONFIG_MODE_SKAS -static void init_registers(int pid) -{ - int err; - - if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0) - panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", - errno); - - err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs); - if(!err) - return; - - have_fpx_regs = 0; - if(errno != EIO) - panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", - errno); - - err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs); - if(err) - panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", - errno); -} -#endif - int can_do_skas(void) { #ifdef CONFIG_MODE_SKAS @@ -311,7 +281,7 @@ int can_do_skas(void) return(ret); #else return(0); -#endif +#endif } /* diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index 6732307894d5..e733b0c87448 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h @@ -33,6 +33,7 @@ extern int new_mm(int from); extern void save_registers(struct uml_pt_regs *regs); extern void restore_registers(struct uml_pt_regs *regs); extern void start_userspace(void); +extern void init_registers(int pid); #endif diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 5c72105d84dd..15a1fd345178 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -351,6 +351,29 @@ void kill_off_processes_skas(void) os_kill_process(userspace_pid, 1); } +void init_registers(int pid) +{ + int err; + + if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0) + panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", + errno); + + err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs); + if(!err) + return; + + have_fpx_regs = 0; + if(errno != EIO) + panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", + errno); + + err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs); + if(err) + panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", + errno); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index b93e93a71e8e..e906e5a630cb 100644 --- a/arch/um/kernel/skas/trap_user.c +++ b/arch/um/kernel/skas/trap_user.c @@ -50,6 +50,8 @@ void user_signal(int sig, struct uml_pt_regs *regs) regs->mode.skas.trap_type = 0; info = &sig_info[sig]; (*info->handler)(sig, regs); + + unblock_signals(); } /* diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c index 00e8fcc10f27..3712286fe5cb 100644 --- a/arch/um/kernel/syscall_user.c +++ b/arch/um/kernel/syscall_user.c @@ -18,8 +18,8 @@ struct { int record_syscall_start(int syscall) { - int max, index; - + int max, index; + max = sizeof(syscall_record)/sizeof(syscall_record[0]); index = next_syscall_index(max); @@ -32,8 +32,8 @@ int record_syscall_start(int syscall) void record_syscall_end(int index, int result) { - syscall_record[index].result = result; - gettimeofday(&syscall_record[index].end, NULL); + syscall_record[index].result = result; + gettimeofday(&syscall_record[index].end, NULL); } /* diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 925aacf560f3..02e7b0eede15 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -74,7 +74,7 @@ void usr2_handler(int sig, struct uml_pt_regs *regs) { CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); } - + struct signal_info sig_info[] = { [ SIGTRAP ] { handler : relay_signal, is_irq : 0 }, @@ -119,11 +119,11 @@ void alarm_handler(int sig, struct sigcontext sc) switch_timers(1); } -void do_longjmp(void *p, int val) +void do_longjmp(void *b, int val) { - jmp_buf *jbuf = (jmp_buf *) p; + jmp_buf *buf = b; - longjmp(*jbuf, val); + longjmp(*buf, val); } /* diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c index 1e819be2539b..22753784178a 100644 --- a/arch/um/kernel/tt/gdb.c +++ b/arch/um/kernel/tt/gdb.c @@ -117,7 +117,7 @@ struct gdb_data { static void config_gdb_cb(void *arg) { struct gdb_data *data = arg; - struct task_struct *task; + void *task; int pid; data->err = -1; @@ -228,19 +228,19 @@ int debugger_signal(int status, pid_t pid){ return(0); } void child_signal(pid_t pid, int status){ } int init_ptrace_proxy(int idle_pid, int startup, int stop) { - printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); + printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); kill_child_dead(idle_pid); exit(1); } void signal_usr1(int sig) { - printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); + printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); } int attach_debugger(int idle_pid, int pid, int stop) { - printk(KERN_ERR "attach_debugger called when CONFIG_PT_PROXY " + printk(UM_KERN_ERR "attach_debugger called when CONFIG_PT_PROXY " "is off\n"); return(-1); } @@ -265,3 +265,14 @@ void debugger_parent_signal(int status, int pid) } #endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h index 1d8b0a2638a8..8eff674107ca 100644 --- a/arch/um/kernel/tt/include/debug.h +++ b/arch/um/kernel/tt/include/debug.h @@ -3,6 +3,7 @@ * Lars Brinkhoff. * Licensed under the GPL */ + #ifndef __DEBUG_H #define __DEBUG_H @@ -11,6 +12,8 @@ extern void child_proxy(pid_t pid, int status); extern void init_proxy (pid_t pid, int waiting, int status); extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); extern void fake_child_exit(void); +extern int gdb_config(char *str); +extern int gdb_remove(char *unused); #endif diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 5b4b285f8cd4..683e2d35cac5 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -24,30 +24,11 @@ #include "init.h" #include "tt.h" -extern void start_kernel(void); - -static int start_kernel_proc(void *unused) -{ - int pid; - - block_signals(); - pid = os_getpid(); - - cpu_tasks[0].pid = pid; - cpu_tasks[0].task = current; -#ifdef CONFIG_SMP - cpu_online_map = 1; -#endif - if(debug) os_stop_process(pid); - start_kernel(); - return(0); -} - void *switch_to_tt(void *prev, void *next, void *last) { struct task_struct *from, *to; unsigned long flags; - int vtalrm, alrm, prof, err, cpu; + int err, vtalrm, alrm, prof, cpu; char c; /* jailing and SMP are incompatible, so this doesn't need to be * made per-cpu @@ -60,7 +41,7 @@ void *switch_to_tt(void *prev, void *next, void *last) to->thread.prev_sched = from; cpu = from->thread_info->cpu; - if(cpu == 0) + if(cpu == 0) forward_interrupts(to->thread.mode.tt.extern_pid); #ifdef CONFIG_SMP forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid); @@ -130,18 +111,6 @@ void exit_thread_tt(void) close(current->thread.mode.tt.switch_pipe[1]); } -void reboot_tt(void) -{ - current->thread.request.op = OP_REBOOT; - os_usr1_process(os_getpid()); -} - -void halt_tt(void) -{ - current->thread.request.op = OP_HALT; - os_usr1_process(os_getpid()); -} - extern void schedule_tail(struct task_struct *prev); static void new_thread_handler(int sig) @@ -276,6 +245,32 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, return(0); } +void reboot_tt(void) +{ + current->thread.request.op = OP_REBOOT; + os_usr1_process(os_getpid()); +} + +void halt_tt(void) +{ + current->thread.request.op = OP_HALT; + os_usr1_process(os_getpid()); +} + +void kill_off_processes_tt(void) +{ + struct task_struct *p; + int me; + + me = os_getpid(); + for_each_process(p){ + if(p->thread.mode.tt.extern_pid != me) + os_kill_process(p->thread.mode.tt.extern_pid, 0); + } + if(init_task.thread.mode.tt.extern_pid != me) + os_kill_process(init_task.thread.mode.tt.extern_pid, 0); +} + void initial_thread_cb_tt(void (*proc)(void *), void *arg) { if(os_getpid() == tracing_pid){ @@ -395,7 +390,6 @@ static void mprotect_kernel_mem(int w) mprotect_kernel_vm(w); } -/* No SMP problems since jailing and SMP are incompatible */ void unprotect_kernel_mem(void) { mprotect_kernel_mem(1); @@ -406,18 +400,23 @@ void protect_kernel_mem(void) mprotect_kernel_mem(0); } -void kill_off_processes_tt(void) +extern void start_kernel(void); + +static int start_kernel_proc(void *unused) { - struct task_struct *p; - int me; + int pid; - me = os_getpid(); - for_each_process(p){ - if(p->thread.mode.tt.extern_pid != me) - os_kill_process(p->thread.mode.tt.extern_pid, 0); - } - if(init_task.thread.mode.tt.extern_pid != me) - os_kill_process(init_task.thread.mode.tt.extern_pid, 0); + block_signals(); + pid = os_getpid(); + + cpu_tasks[0].pid = pid; + cpu_tasks[0].task = current; +#ifdef CONFIG_SMP + cpu_online_map = 1; +#endif + if(debug) os_stop_process(pid); + start_kernel(); + return(0); } void set_tracing(void *task, int tracing) @@ -435,7 +434,8 @@ int set_user_mode(void *t) struct task_struct *task; task = t ? t : current; - if(task->thread.mode.tt.tracing) return(1); + if(task->thread.mode.tt.tracing) + return(1); task->thread.request.op = OP_TRACE_ON; os_usr1_process(os_getpid()); return(0); @@ -451,22 +451,22 @@ void set_init_pid(int pid) err); } -void clear_singlestep(void *t) -{ - struct task_struct *task = (struct task_struct *) t; - - task->ptrace &= ~PT_DTRACE; -} - int singlestepping(void *t) { - struct task_struct *task = (struct task_struct *) t; + struct task_struct *task = t; if(task->thread.mode.tt.singlestep_syscall) return(0); return(task->ptrace & PT_DTRACE); } +void clear_singlestep(void *t) +{ + struct task_struct *task = t; + + task->ptrace &= ~PT_DTRACE; +} + int start_uml_tt(void) { void *sp; diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile index cf94d8b61c88..10eb5b00f39a 100644 --- a/arch/um/kernel/tt/ptproxy/Makefile +++ b/arch/um/kernel/tt/ptproxy/Makefile @@ -13,4 +13,3 @@ $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< clean: - rm -f *.o core child ptproxy diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c index fbe0a4fd3915..e7e95a5c6ad2 100644 --- a/arch/um/kernel/tt/tlb.c +++ b/arch/um/kernel/tt/tlb.c @@ -84,7 +84,8 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, atomic_t vmchange_seq = ATOMIC_INIT(1); -void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) +static void flush_kernel_vm_range(unsigned long start, unsigned long end, + int update_seq) { struct mm_struct *mm; pgd_t *pgd; @@ -133,7 +134,7 @@ void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) void flush_tlb_kernel_range(unsigned long start, unsigned long end) { - flush_kernel_range(start, end, 1); + flush_kernel_vm_range(start, end, 1); } static void protect_vm_page(unsigned long addr, int w, int must_succeed) @@ -189,7 +190,7 @@ void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start, * either process memory or kernel vm */ if((start >= start_vm) && (start < end_vm)) - flush_kernel_range(start, end, 1); + flush_kernel_vm_range(start, end, 1); else fix_range(vma->vm_mm, start, end, 0); } @@ -204,13 +205,13 @@ void flush_tlb_mm_tt(struct mm_struct *mm) seq = atomic_read(&vmchange_seq); if(current->thread.mode.tt.vm_seq == seq) return; current->thread.mode.tt.vm_seq = seq; - flush_kernel_range(start_vm, end_vm, 0); + flush_kernel_vm_range(start_vm, end_vm, 0); } void force_flush_all_tt(void) { fix_range(current->mm, 0, STACK_TOP, 1); - flush_kernel_range(start_vm, end_vm, 0); + flush_kernel_vm_range(start_vm, end_vm, 0); } /* diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index 5b06c48e45b7..90e948c836bb 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c @@ -372,13 +372,14 @@ int tracer(int (*init_proc)(void *), void *sp) if(!tracing && (debugger_pid != -1) && (sig != 0) && (sig != SIGALRM) && (sig != SIGVTALRM) && (sig != SIGSEGV) && (sig != SIGTRAP) && - (sig != SIGUSR2) && (sig != SIGIO)){ + (sig != SIGUSR2) && (sig != SIGIO) && + (sig != SIGFPE)){ child_signal(pid, status); continue; } if(tracing){ - if(singlestepping(task)) + if(singlestepping_tt(task)) cont_type = PTRACE_SINGLESTEP; else cont_type = PTRACE_SYSCALL; } diff --git a/arch/um/main.c b/arch/um/main.c index ffe6ed6f6289..3addff95120c 100644 --- a/arch/um/main.c +++ b/arch/um/main.c @@ -135,13 +135,13 @@ int main(int argc, char **argv, char **envp) } #define CAN_KMALLOC() \ - (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1)) + (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1)) extern void *__real_malloc(int); void *__wrap_malloc(int size) { - if(CAN_KMALLOC()) return(um_kmalloc(size)); + if(CAN_KMALLOC()) return(um_kmalloc(size)); else return(__real_malloc(size)); } @@ -158,7 +158,7 @@ extern void __real_free(void *); void __wrap_free(void *ptr) { - if(CAN_KMALLOC()) kfree(ptr); + if(CAN_KMALLOC()) kfree(ptr); else __real_free(ptr); } diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index 596257f5bd15..435380cc08d7 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -24,8 +24,8 @@ struct mm_struct; #ifdef CONFIG_MODE_TT struct proc_tt_mode { - int extern_pid; - int tracing; + int extern_pid; + int tracing; int switch_pipe[2]; int singlestep_syscall; int vm_seq; @@ -40,7 +40,6 @@ struct proc_skas_mode { #endif struct thread_struct { - int tracing; int forking; unsigned long kernel_stack; int nsyscalls; -- cgit v1.2.3 From c66e8593ac3b5ad4c72dd2aea5a5b5036719e258 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Nov 2002 12:07:47 -0500 Subject: Fixed a stupid compile bug. --- arch/um/kernel/tt/process_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 683e2d35cac5..a9f6264d1fc9 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -451,7 +451,7 @@ void set_init_pid(int pid) err); } -int singlestepping(void *t) +int singlestepping_tt(void *t) { struct task_struct *task = t; -- cgit v1.2.3 From d3f34f89e958a8ca6cce54d5ba76a7c6b40b6d39 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 6 Dec 2002 11:23:55 -0500 Subject: Updated to 2.5.50. --- arch/um/kernel/ptrace.c | 3 +-- arch/um/kernel/sys_call_table.c | 1 + include/asm-um/pgtable.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index d6dacf475c33..8b5739a84ed3 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -33,8 +33,7 @@ int sys_ptrace(long request, long pid, long addr, long data) if (current->ptrace & PT_PTRACED) goto out; - ret = security_ptrace(current->parent, current); - if (ret) + if((ret = security_ptrace(current->parent, current))) goto out; /* set the ptrace bit in the process flags. */ diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c index 9418e8e329f6..14b4e4c066b6 100644 --- a/arch/um/kernel/sys_call_table.c +++ b/arch/um/kernel/sys_call_table.c @@ -8,6 +8,7 @@ #include "linux/version.h" #include "linux/sys.h" #include "linux/swap.h" +#include "linux/sysctl.h" #include "asm/signal.h" #include "sysdep/syscalls.h" #include "kern_util.h" diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h index a79a756c3989..8d607c87418d 100644 --- a/include/asm-um/pgtable.h +++ b/include/asm-um/pgtable.h @@ -373,15 +373,15 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) } /* Find an entry in the third-level page table.. */ -#define __pte_offset(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define __pte_offset(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define pte_offset_kernel(dir, address) \ ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address)) #define pte_offset_map(dir, address) \ ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + __pte_offset(address)) #define pte_offset_map_nested(dir, address) \ ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + __pte_offset(address)) -#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) -#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) +#define pte_unmap(pte) kunmap_atomic((pte), KM_PTE0) +#define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1) #if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM4G) typedef u32 pte_addr_t; -- cgit v1.2.3 From de5ef99a5255b3d3f54e9a69ed06c6f75939232d Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 6 Dec 2002 11:25:54 -0500 Subject: Added a couple of includes as part of the 2.5.50 update. --- arch/um/kernel/skas/include/uaccess.h | 1 + arch/um/kernel/tt/syscall_kern.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h index 9e9f9c273009..df408e12d933 100644 --- a/arch/um/kernel/skas/include/uaccess.h +++ b/arch/um/kernel/skas/include/uaccess.h @@ -8,6 +8,7 @@ #include "linux/string.h" #include "linux/sched.h" +#include "linux/err.h" #include "asm/processor.h" #include "asm/pgtable.h" #include "asm/errno.h" diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c index dd087fb96ff6..3fb449db2885 100644 --- a/arch/um/kernel/tt/syscall_kern.c +++ b/arch/um/kernel/tt/syscall_kern.c @@ -9,6 +9,7 @@ #include "asm/unistd.h" #include "asm/ptrace.h" #include "asm/uaccess.h" +#include "asm/stat.h" #include "sysdep/syscalls.h" #include "kern_util.h" -- cgit v1.2.3 From 2e7fa3fb6089f4c7f847d919cb9806f86836bc7f Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 16 Dec 2002 14:44:15 -0500 Subject: Applied updates from 2.5.51 and 2.5.52. --- arch/um/kernel/ptrace.c | 3 ++- arch/um/kernel/signal_kern.c | 7 +++++++ arch/um/kernel/sys_call_table.c | 2 +- arch/um/kernel/syscall_kern.c | 6 +++++- arch/um/uml.lds.S | 11 ++++++++++- include/asm-um/thread_info.h | 10 ++++------ 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 8b5739a84ed3..d6dacf475c33 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -33,7 +33,8 @@ int sys_ptrace(long request, long pid, long addr, long data) if (current->ptrace & PT_PTRACED) goto out; - if((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index be60440cf012..87768b9661aa 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -69,6 +69,9 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, ret = 0; switch(error){ + case -ERESTART_RESTARTBLOCK: + current_thread_info()->restart_block.fn = + do_no_restart_syscall; case -ERESTARTNOHAND: ret = -EINTR; break; @@ -160,6 +163,10 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); PT_REGS_RESTART_SYSCALL(regs); } + else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){ + PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall; + PT_REGS_RESTART_SYSCALL(regs); + } } /* This closes a way to execute a system call on the host. If diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c index 7b5a703a24c7..9a329a4938ab 100644 --- a/arch/um/kernel/sys_call_table.c +++ b/arch/um/kernel/sys_call_table.c @@ -254,7 +254,7 @@ extern syscall_handler_t um_stime; #endif syscall_handler_t *sys_call_table[] = { - [ 0 ] = sys_ni_syscall, + [ __NR_restart_syscall ] = sys_restart_syscall, [ __NR_exit ] = sys_exit, [ __NR_fork ] = sys_fork, [ __NR_read ] = (syscall_handler_t *) sys_read, diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index ab42524562b1..1cf0ed074e2a 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -182,7 +182,11 @@ int sys_ipc (uint call, int first, int second, switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + return sys_semtimedop(first, (struct sembuf *) ptr, second, + NULL); + case SEMTIMEDOP: + return sys_semtimedop(first, (struct sembuf *) ptr, second, + (const struct timespec *) fifth); case SEMGET: return sys_semget (first, second, third); case SEMCTL: { diff --git a/arch/um/uml.lds.S b/arch/um/uml.lds.S index cd4b487e0fa5..736df4695129 100644 --- a/arch/um/uml.lds.S +++ b/arch/um/uml.lds.S @@ -59,18 +59,27 @@ SECTIONS __uml_setup_start = .; .uml.setup.init : { *(.uml.setup.init) } __uml_setup_end = .; + __uml_help_start = .; .uml.help.init : { *(.uml.help.init) } __uml_help_end = .; + __uml_postsetup_start = .; .uml.postsetup.init : { *(.uml.postsetup.init) } __uml_postsetup_end = .; + __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; + + __start___param = .; + __param : { *(__param) } + __stop___param = .; + __per_cpu_start = . ; .data.percpu : { *(.data.percpu) } - __per_cpu_end = . ; + __per_cpu_end = . ; + __initcall_start = .; .initcall.init : { *(.initcall1.init) diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index 1cb0f45359f5..bd3f4fe40c6b 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h @@ -20,14 +20,9 @@ struct thread_info { mm_segment_t addr_limit; /* thread address space: 0-0xBFFFFFFF for user 0-0xFFFFFFFF for kernel */ + struct restart_block restart_block; }; -/* - * macros/functions for gaining access to the thread information structure - * - * preempt_count needs to be 1 initially, until the scheduler is functional. - */ - #define INIT_THREAD_INFO(tsk) \ { \ task: &tsk, \ @@ -36,6 +31,9 @@ struct thread_info { cpu: 0, \ preempt_count: 1, \ addr_limit: KERNEL_DS, \ + restart_block: { \ + fn: do_no_restart_syscall, \ + }, \ } #define init_thread_info (init_thread_union.thread_info) -- cgit v1.2.3 From fe8217c366bc44f933e07a5bab28ed513ca3734b Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 16 Dec 2002 16:21:56 -0500 Subject: Removed includes of Rules.mk. --- arch/um/kernel/skas/Makefile | 2 -- arch/um/kernel/skas/sys-i386/Makefile | 2 -- arch/um/kernel/tt/Makefile | 2 -- arch/um/kernel/tt/sys-i386/Makefile | 2 -- 4 files changed, 8 deletions(-) diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index d696b40d7e94..72c79956f6a6 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -10,8 +10,6 @@ obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -include $(TOPDIR)/Rules.make - include/skas_ptregs.h : util/mk_ptregs util/mk_ptregs > $@ diff --git a/arch/um/kernel/skas/sys-i386/Makefile b/arch/um/kernel/skas/sys-i386/Makefile index fb6b22056f37..2ad8271c604d 100644 --- a/arch/um/kernel/skas/sys-i386/Makefile +++ b/arch/um/kernel/skas/sys-i386/Makefile @@ -8,8 +8,6 @@ obj-y = sigcontext.o USER_OBJS = sigcontext.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -include $(TOPDIR)/Rules.make - $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 00c3eea54715..9b436c8ef1bb 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -14,8 +14,6 @@ export-objs = ksyms.o USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o time.o tracer.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -include $(TOPDIR)/Rules.make - $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< diff --git a/arch/um/kernel/tt/sys-i386/Makefile b/arch/um/kernel/tt/sys-i386/Makefile index fb6b22056f37..2ad8271c604d 100644 --- a/arch/um/kernel/tt/sys-i386/Makefile +++ b/arch/um/kernel/tt/sys-i386/Makefile @@ -8,8 +8,6 @@ obj-y = sigcontext.o USER_OBJS = sigcontext.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -include $(TOPDIR)/Rules.make - $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< -- cgit v1.2.3 From 10d91c8cd512c1d72a8ca85debb91a892ad66341 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 16 Dec 2002 16:22:54 -0500 Subject: Updated to 2.5.52. A couple of changes relating to system call restarting. --- arch/um/kernel/signal_kern.c | 1 + arch/um/kernel/sys_call_table.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 87768b9661aa..0a76cbb70e5f 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -16,6 +16,7 @@ #include "linux/binfmts.h" #include "asm/signal.h" #include "asm/uaccess.h" +#include "asm/unistd.h" #include "user_util.h" #include "kern_util.h" #include "signal_kern.h" diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c index 9a329a4938ab..f54c2ae723b5 100644 --- a/arch/um/kernel/sys_call_table.c +++ b/arch/um/kernel/sys_call_table.c @@ -13,6 +13,7 @@ #include "sysdep/syscalls.h" #include "kern_util.h" +extern syscall_handler_t sys_restart_syscall; extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_exit; extern syscall_handler_t sys_fork; -- cgit v1.2.3 From edf22f511a224d69ca0634dd72c1539a4948d453 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sun, 22 Dec 2002 19:20:30 -0800 Subject: [PATCH] USB Joypad quirk Orginally from Vojtech Pavlik (16th June 2002 via email), to fix my 'broken' USB joypad, Fully tested in both 2.4.x and 2.5.52 (and 2.5.52-bk). --- drivers/usb/input/hid-core.c | 4 ++++ drivers/usb/input/hid-input.c | 5 +++++ drivers/usb/input/hid.h | 1 + 3 files changed, 10 insertions(+) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 88523db2a603..0da1965b13d3 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1317,6 +1317,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 #define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205 +#define USB_VENDOR_ID_TOPMAX 0x0663 +#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 + #define USB_VENDOR_ID_MGE 0x0463 #define USB_DEVICE_ID_MGE_UPS 0xffff #define USB_DEVICE_ID_MGE_UPS1 0x0001 @@ -1355,6 +1358,7 @@ struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV }, + { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, { 0, 0 } }; diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 9090b577643f..1fae2bc757fc 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -357,6 +357,11 @@ static void hidinput_configure_usage(struct hid_device *device, struct hid_field int a = field->logical_minimum; int b = field->logical_maximum; + if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) { + a = field->logical_minimum = 0; + b = field->logical_maximum = 255; + } + input->absmin[usage->code] = a; input->absmax[usage->code] = b; input->absfuzz[usage->code] = (b - a) >> 8; diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 4f40b1b70d8f..2672f12ada5a 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -206,6 +206,7 @@ struct hid_item { #define HID_QUIRK_IGNORE 0x04 #define HID_QUIRK_NOGET 0x08 #define HID_QUIRK_HIDDEV 0x10 +#define HID_QUIRK_BADPAD 0x12 /* * This is the global enviroment of the parser. This information is -- cgit v1.2.3 From 3de01c0094239b242ff48383d932869346251954 Mon Sep 17 00:00:00 2001 From: Henning Meier-Geinitz Date: Sun, 22 Dec 2002 19:21:38 -0800 Subject: [PATCH] scanner.c: Accept scanners with more than one interface This patch allows the scanner driver to accept devices with more than one interface. That's needed by some multi-function periphals (e.g. scanner+printer). --- drivers/usb/image/scanner.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c index 27591a0898e0..2d78b2f0e6da 100644 --- a/drivers/usb/image/scanner.c +++ b/drivers/usb/image/scanner.c @@ -321,10 +321,12 @@ * "Jaeger, Gerhard" , Ira Childress * , Till Kamppeter , * Ed Hamrick , Oliver Schwartz - * and everyone else who sent ids. + * and everyone else who sent ids. * - Some Benq, Genius and Plustek ids are identified now. * - Accept scanners with only one bulk (in) endpoint (thanks to Sergey * Vlasov ). + * - Accept devices with more than one interface. Only use interfaces that + * look like belonging to scanners. * * TODO * - Remove the 2/3 endpoint limitation @@ -907,13 +909,15 @@ probe_scanner(struct usb_interface *intf, return -ENODEV; } - if (dev->config[0].desc.bNumInterfaces != 1) { - info("probe_scanner: Only one device interface is supported."); + interface = intf->altsetting; + + if (interface[0].desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC && + interface[0].desc.bInterfaceClass != USB_CLASS_PER_INTERFACE && + interface[0].desc.bInterfaceClass != 16) { + dbg("probe_scanner: This interface doesn't look like a scanner (class=0x%x).", interface[0].desc.bInterfaceClass); return -ENODEV; } - interface = intf->altsetting; - /* * Start checking for one or two bulk endpoints and an optional * interrupt endpoint. If we have an interrupt endpoint go ahead and -- cgit v1.2.3 From 65c67d3a63f2749ee9c686681bd1ec3777826459 Mon Sep 17 00:00:00 2001 From: Henning Meier-Geinitz Date: Sun, 22 Dec 2002 19:21:56 -0800 Subject: [PATCH] scanner.c: fix compilation error with debugging enabled This patch removes a now unnecessary debug line taht broke compilation when debugging was enabled. --- drivers/usb/image/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c index 2d78b2f0e6da..5fc2d7ef9037 100644 --- a/drivers/usb/image/scanner.c +++ b/drivers/usb/image/scanner.c @@ -327,6 +327,7 @@ * Vlasov ). * - Accept devices with more than one interface. Only use interfaces that * look like belonging to scanners. + * - Fix compilation error when debugging is enabled. * * TODO * - Remove the 2/3 endpoint limitation @@ -860,7 +861,6 @@ probe_scanner(struct usb_interface *intf, } dbg("probe_scanner: USB dev address:%p", dev); - dbg("probe_scanner: ifnum:%u", ifnum); /* * 1. Check Vendor/Product -- cgit v1.2.3 From 5a8e410f39f70678be3c59153c6cbffe890e1dce Mon Sep 17 00:00:00 2001 From: Ganesh Varadarajan Date: Mon, 23 Dec 2002 18:27:27 -0800 Subject: [PATCH] USB ipaq driver update The ActiveSync USB "protocol" seems to be the same for all WinCE devices seen so far. So it seems reasonable to pre-emptively support all devices which work with ActiveSync. --- Documentation/usb/usb-serial.txt | 36 +++++++++++++++++---------- drivers/usb/serial/Kconfig | 4 +-- drivers/usb/serial/ipaq.c | 38 +++++++++++++++++++++++++--- drivers/usb/serial/ipaq.h | 53 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 107 insertions(+), 24 deletions(-) diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index 7e6150c50088..82d73ba58392 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -91,27 +91,27 @@ HandSpring Visor, Palm USB, and Cli Kroah-Hartman at greg@kroah.com -Compaq iPAQ, HP Jornada and Casio EM500 driver +PocketPC PDA Driver - This driver can be used to connect to Compaq iPAQ, HP Jornada and Casio EM500 - PDAs running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. - It's very likely that every device supported by ActiveSync USB works with this - driver. The driver supports the Compaq iPAQ, Jornada 548/568 and the Casio - EM500 out of the box. For others, please use module parameters to specify - the product and vendor id. e.g. modprobe ipaq vendor=0x3f0 product=0x1125 + This driver can be used to connect to Compaq iPAQ, HP Jornada, Casio EM500 + and other PDAs running Windows CE 3.0 or PocketPC 2002 using a USB + cable/cradle. + Most devices supported by ActiveSync are supported out of the box. + For others, please use module parameters to specify the product and vendor + id. e.g. modprobe ipaq vendor=0x3f0 product=0x1125 The driver presents a serial interface (usually on /dev/ttyUSB0) over - which one may run ppp and establish a TCP/IP link to the iPAQ. Once this + which one may run ppp and establish a TCP/IP link to the PDA. Once this is done, you can transfer files, backup, download email etc. The most - significant advantage of using USB is speed - you can get 73 to 113 - kbytes/sec for download/upload to the iPAQ. + significant advantage of using USB is speed - I can get 73 to 113 + kbytes/sec for download/upload to my iPAQ. This driver is only one of a set of components required to utilize the USB connection. Please visit http://synce.sourceforge.net which contains the necessary packages and a simple step-by-step howto. Once connected, you can use Win CE programs like ftpView, Pocket Outlook - from the iPAQ and xcerdisp, synce utilities from the Linux side. + from the PDA and xcerdisp, synce utilities from the Linux side. To use Pocket IE, follow the instructions given at http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing @@ -126,8 +126,18 @@ Compaq iPAQ, HP Jornada and Casio EM500 driver If it doesn't work for some reason, load both the usbserial and ipaq module with the module parameter "debug" set to 1 and examine the system log. - You can also try soft-resetting your iPAQ before attempting a connection. - + You can also try soft-resetting your PDA before attempting a connection. + + Other functionality may be possible depending on your PDA. According to + Wes Cilldhaire , with the Toshiba E570, + ...if you boot into the bootloader (hold down the power when hitting the + reset button, continuing to hold onto the power until the bootloader screen + is displayed), then put it in the cradle with the ipaq driver loaded, open + a terminal on /dev/ttyUSB0, it gives you a "USB Reflash" terminal, which can + be used to flash the ROM, as well as the microP code.. so much for needing + Toshiba's $350 serial cable for flashing!! :D + NOTE: This has NOT been tested. Use at your own risk. + For any questions or problems with the driver, please contact Ganesh Varadarajan diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 1e0dfb0dd9e7..82f3db1ee634 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -150,11 +150,11 @@ config USB_SERIAL_VISOR module, say M here and read . config USB_SERIAL_IPAQ - tristate "USB Compaq iPAQ / HP Jornada / Casio EM500 Driver" + tristate "USB PocketPC PDA Driver" depends on USB_SERIAL help Say Y here if you want to connect to your Compaq iPAQ, HP Jornada - 548/568 or Casio EM500 running Windows CE 3.0 or PocketPC 2002 + or any other PDA running Windows CE 3.0 or PocketPC 2002 using a USB cradle/cable. For information on using the driver, read . diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index b9e23ac67023..fb04cc639145 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -9,6 +9,10 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * + * (12/12/2002) ganesh + * Added support for practically all devices supported by ActiveSync + * on Windows. Thanks to Wes Cilldhaire . + * * (26/11/2002) ganesh * Added insmod options to specify product and vendor id. * Use modprobe ipaq vendor=0xfoo product=0xbar @@ -68,9 +72,9 @@ * Version Information */ -#define DRIVER_VERSION "v0.4" +#define DRIVER_VERSION "v0.5" #define DRIVER_AUTHOR "Ganesh Varadarajan " -#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada, Casio EM500 driver" +#define DRIVER_DESC "USB PocketPC PDA driver" static int product, vendor; @@ -94,10 +98,36 @@ static void ipaq_destroy_lists(struct usb_serial_port *port); static struct usb_device_id ipaq_id_table [] = { /* The first entry is a placeholder for the insmod-specified device */ { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) }, + { USB_DEVICE(ASKEY_VENDOR_ID, ASKEY_PRODUCT_ID) }, + { USB_DEVICE(BCOM_VENDOR_ID, BCOM_0065_ID) }, + { USB_DEVICE(BCOM_VENDOR_ID, BCOM_0066_ID) }, + { USB_DEVICE(BCOM_VENDOR_ID, BCOM_0067_ID) }, + { USB_DEVICE(CASIO_VENDOR_ID, CASIO_2001_ID) }, + { USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) }, { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) }, + { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_0032_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) }, - { USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_2116_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_2216_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_3016_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_3116_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_3216_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_4016_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_4116_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_4216_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_5016_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_5116_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_5216_ID) }, + { USB_DEVICE(LINKUP_VENDOR_ID, LINKUP_PRODUCT_ID) }, + { USB_DEVICE(MICROSOFT_VENDOR_ID, MICROSOFT_00CE_ID) }, + { USB_DEVICE(PORTATEC_VENDOR_ID, PORTATEC_PRODUCT_ID) }, + { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_WIRELESS_ID) }, + { USB_DEVICE(SOCKET_VENDOR_ID, SOCKET_PRODUCT_ID) }, + { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_ID) }, + { USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) }, + { USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -114,7 +144,7 @@ static struct usb_driver ipaq_driver = { /* All of the device info needed for the Compaq iPAQ */ struct usb_serial_device_type ipaq_device = { .owner = THIS_MODULE, - .name = "Compaq iPAQ", + .name = "PocketPC PDA", .id_table = ipaq_id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h index 16469a60b65d..f3302b337ee0 100644 --- a/drivers/usb/serial/ipaq.h +++ b/drivers/usb/serial/ipaq.h @@ -9,22 +9,66 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * */ #ifndef __LINUX_USB_SERIAL_IPAQ_H #define __LINUX_USB_SERIAL_IPAQ_H +#define ASKEY_VENDOR_ID 0x1690 +#define ASKEY_PRODUCT_ID 0x0601 + +#define BCOM_VENDOR_ID 0x0960 +#define BCOM_0065_ID 0x0065 +#define BCOM_0066_ID 0x0066 +#define BCOM_0067_ID 0x0067 + +#define CASIO_VENDOR_ID 0x07cf +#define CASIO_2001_ID 0x2001 +#define CASIO_EM500_ID 0x2002 #define COMPAQ_VENDOR_ID 0x049f #define COMPAQ_IPAQ_ID 0x0003 +#define COMPAQ_0032_ID 0x0032 #define HP_VENDOR_ID 0x03f0 #define HP_JORNADA_548_ID 0x1016 #define HP_JORNADA_568_ID 0x1116 +#define HP_2016_ID 0x2016 +#define HP_2116_ID 0x2116 +#define HP_2216_ID 0x2216 +#define HP_3016_ID 0x3016 +#define HP_3116_ID 0x3116 +#define HP_3216_ID 0x3216 +#define HP_4016_ID 0x4016 +#define HP_4116_ID 0x4116 +#define HP_4216_ID 0x4216 +#define HP_5016_ID 0x5016 +#define HP_5116_ID 0x5116 +#define HP_5216_ID 0x5216 -#define CASIO_VENDOR_ID 0x07cf -#define CASIO_EM500_ID 0x2002 +#define LINKUP_VENDOR_ID 0x094b +#define LINKUP_PRODUCT_ID 0x0001 + +#define MICROSOFT_VENDOR_ID 0x045e +#define MICROSOFT_00CE_ID 0x00ce + +#define PORTATEC_VENDOR_ID 0x0961 +#define PORTATEC_PRODUCT_ID 0x0010 + +#define SAGEM_VENDOR_ID 0x5e04 +#define SAGEM_WIRELESS_ID 0xce00 + +#define SOCKET_VENDOR_ID 0x0104 +#define SOCKET_PRODUCT_ID 0x00be + +#define TOSHIBA_VENDOR_ID 0x0930 +#define TOSHIBA_PRODUCT_ID 0x0700 + +#define HTC_VENDOR_ID 0x0bb4 +#define HTC_PRODUCT_ID 0x00ce + +#define NEC_VENDOR_ID 0x0409 +#define NEC_PRODUCT_ID 0x00d5 /* * Since we can't queue our bulk write urbs (don't know why - it just @@ -41,8 +85,7 @@ * * The value of PACKET_SIZE was empirically determined by * checking the maximum write sizes sent down by the ppp ldisc. - * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size - * supported by the iPAQ. + * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size. */ struct ipaq_packet { -- cgit v1.2.3 From ac517c3f41ac2c4dd456e93365eae83d520eec61 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 25 Dec 2002 18:57:27 -0800 Subject: The fast poll code incorrectly assumed that "sizeof pp" was the same as "offsetof pp->entries". Which happens to be true on 32-bit platforms, but not on 64-bit ones. From Anton Blanchard. --- fs/select.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/select.c b/fs/select.c index 456465510c09..510e1defe964 100644 --- a/fs/select.c +++ b/fs/select.c @@ -471,7 +471,7 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout) walk->next = pp; walk = pp; - if (copy_from_user(pp+1, ufds + nfds-i, + if (copy_from_user(pp->entries, ufds + nfds-i, sizeof(struct pollfd)*pp->len)) { err = -EFAULT; goto out_fds; -- cgit v1.2.3 From 99a6e15b856ffd9a91f6d85dfaa09d3a38857d7f Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Wed, 25 Dec 2002 19:06:30 -0800 Subject: [PATCH] Make swsuspend restore DS/ES segments properly --- arch/i386/kernel/suspend_asm.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/i386/kernel/suspend_asm.S b/arch/i386/kernel/suspend_asm.S index e454ec55b824..6fe892675869 100644 --- a/arch/i386/kernel/suspend_asm.S +++ b/arch/i386/kernel/suspend_asm.S @@ -64,9 +64,10 @@ ENTRY(do_magic) jb .L1455 .p2align 4,,7 .L1453: - movl $104,%eax + movl $__USER_DS,%eax movw %ax, %ds + movw %ax, %es movl saved_context_esp, %esp movl saved_context_ebp, %ebp movl saved_context_eax, %eax -- cgit v1.2.3 From 1b2fe8205cfaf215150c8172d533ba2e5c466dae Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Dec 2002 20:13:04 -0800 Subject: [PATCH] USB: make the usbserial driver have the same name for the tty, usb, and module subsystems. --- drivers/usb/serial/usb-serial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 5098b5e63d31..40a1f81361c1 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -366,7 +366,7 @@ static struct usb_device_id generic_serial_ids[] = { /* Driver structure we register with the USB core */ static struct usb_driver usb_serial_driver = { - .name = "serial", + .name = "usbserial", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, #ifdef CONFIG_USB_SERIAL_GENERIC @@ -1259,7 +1259,7 @@ void usb_serial_disconnect(struct usb_interface *interface) struct tty_driver usb_serial_tty_driver = { .magic = TTY_DRIVER_MAGIC, - .driver_name = "usb-serial", + .driver_name = "usbserial", #ifndef CONFIG_DEVFS_FS .name = "ttyUSB", #else -- cgit v1.2.3 From 9bcac5a8407ec8e9b01c36ea9d8c8b64cd02b74e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Dec 2002 20:13:26 -0800 Subject: [PATCH] USB: convert visor driver to use dev_err() and dev_info() macros --- drivers/usb/serial/visor.c | 56 ++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index ce7fb050ad8d..6c7f25291c9a 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -303,7 +303,7 @@ static int visor_open (struct usb_serial_port *port, struct file *filp) if (!port->read_urb) { /* this is needed for some brain dead Sony devices */ - err ("Device lied about number of ports, please use a lower one."); + dev_err(port->dev, "Device lied about number of ports, please use a lower one.\n"); return -ENODEV; } @@ -327,8 +327,8 @@ static int visor_open (struct usb_serial_port *port, struct file *filp) visor_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) { - err("%s - failed submitting read urb, error %d", - __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting read urb, error %d\n", + __FUNCTION__, result); goto exit; } @@ -336,8 +336,8 @@ static int visor_open (struct usb_serial_port *port, struct file *filp) dbg("%s - adding interrupt input for treo", __FUNCTION__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) - err("%s - failed submitting interrupt urb, error %d", - __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting interrupt urb, error %d\n", + __FUNCTION__, result); } exit: return result; @@ -363,7 +363,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) * device is still here */ transfer_buffer = kmalloc (0x12, GFP_KERNEL); if (!transfer_buffer) { - err("%s - kmalloc(%d) failed.", __FUNCTION__, 0x12); + dev_err(port->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 0x12); } else { /* send a shutdown message to the device */ usb_control_msg (serial->dev, @@ -380,7 +380,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) usb_unlink_urb (port->interrupt_in_urb); } /* Uncomment the following line if you want to see some statistics in your syslog */ - /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ + /* dev_info (port->dev, "Bytes In = %d Bytes Out = %d\n", bytes_in, bytes_out); */ } @@ -395,13 +395,13 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig buffer = kmalloc (count, GFP_ATOMIC); if (!buffer) { - err ("out of memory"); + dev_err(port->dev, "out of memory\n"); return -ENOMEM; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { - err ("no more free urbs"); + dev_err(port->dev, "no more free urbs\n"); kfree (buffer); return -ENOMEM; } @@ -427,8 +427,8 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { - err("%s - usb_submit_urb(write bulk) failed with status = %d", - __FUNCTION__, status); + dev_err(port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", + __FUNCTION__, status); count = status; } else { bytes_out += count; @@ -539,7 +539,7 @@ static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs) visor_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); return; } @@ -577,8 +577,8 @@ static void visor_read_int_callback (struct urb *urb, struct pt_regs *regs) exit: result = usb_submit_urb (urb, GFP_ATOMIC); if (result) - err("%s - Error %d submitting interrupt urb", - __FUNCTION__, result); + dev_err(urb->dev->dev, "%s - Error %d submitting interrupt urb\n", + __FUNCTION__, result); } static void visor_throttle (struct usb_serial_port *port) @@ -597,18 +597,19 @@ static void visor_unthrottle (struct usb_serial_port *port) port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err("%s - failed submitting read urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); } static int visor_probe (struct usb_serial *serial) { + struct device *dev = &serial->dev->dev; int response; int i; int num_ports; unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL); if (!transfer_buffer) { - err("%s - kmalloc(%d) failed.", __FUNCTION__, 256); + dev_err(*dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 256); return -ENOMEM; } @@ -621,14 +622,14 @@ static int visor_probe (struct usb_serial *serial) response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION, 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); if (response < 0) { - err("%s - error getting connection information", __FUNCTION__); + dev_err(*dev, "%s - error getting connection information\n", __FUNCTION__); } else { struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer; char *string; le16_to_cpus(&connection_info->num_ports); num_ports = connection_info->num_ports; - info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports); + dev_info(*dev, "%s: Number of ports: %d\n", serial->type->name, connection_info->num_ports); for (i = 0; i < num_ports; ++i) { switch (connection_info->connections[i].port_function_id) { case VISOR_FUNCTION_GENERIC: @@ -650,8 +651,8 @@ static int visor_probe (struct usb_serial *serial) string = "unknown"; break; } - info("%s: port %d, is for %s use", serial->type->name, - connection_info->connections[i].port, string); + dev_info(*dev, "%s: port %d, is for %s use\n", serial->type->name, + connection_info->connections[i].port, string); /* save off our num_ports info so that we can use it in the calc_num_ports call */ serial->private = (void *)(long)num_ports; } @@ -666,7 +667,7 @@ static int visor_probe (struct usb_serial *serial) 0xc2, 0x0000, 0x0000, transfer_buffer, 0x14, 300); if (response < 0) { - err("%s - error getting first unknown palm command", __FUNCTION__); + dev_err(*dev, "%s - error getting first unknown palm command\n", __FUNCTION__); } else { usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer); } @@ -675,7 +676,7 @@ static int visor_probe (struct usb_serial *serial) 0xc2, 0x0000, 0x0000, transfer_buffer, 0x14, 300); if (response < 0) { - err("%s - error getting second unknown palm command", __FUNCTION__); + dev_err(*dev, "%s - error getting second unknown palm command\n", __FUNCTION__); } else { usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer); } @@ -685,7 +686,7 @@ static int visor_probe (struct usb_serial *serial) response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE, 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300); if (response < 0) { - err("%s - error getting bytes available request", __FUNCTION__); + dev_err(*dev, "%s - error getting bytes available request\n", __FUNCTION__); } kfree (transfer_buffer); @@ -707,6 +708,7 @@ static int visor_calc_num_ports (struct usb_serial *serial) static int clie_3_5_startup (struct usb_serial *serial) { + struct device *dev = &serial->dev->dev; int result; u8 data; @@ -721,11 +723,11 @@ static int clie_3_5_startup (struct usb_serial *serial) USB_REQ_GET_CONFIGURATION, USB_DIR_IN, 0, 0, &data, 1, HZ * 3); if (result < 0) { - err("%s: get config number failed: %d", __FUNCTION__, result); + dev_err(*dev, "%s: get config number failed: %d\n", __FUNCTION__, result); return result; } if (result != 1) { - err("%s: get config number bad return length: %d", __FUNCTION__, result); + dev_err(*dev, "%s: get config number bad return length: %d\n", __FUNCTION__, result); return -EIO; } @@ -735,11 +737,11 @@ static int clie_3_5_startup (struct usb_serial *serial) USB_DIR_IN | USB_RECIP_INTERFACE, 0, 0, &data, 1, HZ * 3); if (result < 0) { - err("%s: get interface number failed: %d", __FUNCTION__, result); + dev_err(*dev, "%s: get interface number failed: %d\n", __FUNCTION__, result); return result; } if (result != 1) { - err("%s: get interface number bad return length: %d", __FUNCTION__, result); + dev_err(*dev, "%s: get interface number bad return length: %d\n", __FUNCTION__, result); return -EIO; } -- cgit v1.2.3 From 31164daa452a170cd03a5b89bdf0e79b28bbb200 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Dec 2002 20:17:51 -0800 Subject: [PATCH] USB: convert usbserial core to use dev_err() and dev_info() macros --- drivers/usb/serial/bus.c | 12 ++++++------ drivers/usb/serial/ezusb.c | 4 ++-- drivers/usb/serial/generic.c | 6 +++--- drivers/usb/serial/usb-serial.c | 34 +++++++++++++++++----------------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 3d99da8441d5..fee75805b1c9 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -66,7 +66,7 @@ static int usb_serial_device_probe (struct device *dev) driver = port->serial->type; if (driver->port_probe) { if (!try_module_get(driver->owner)) { - err ("module get failed, exiting"); + dev_err(*dev, "module get failed, exiting\n"); retval = -EIO; goto exit; } @@ -79,8 +79,8 @@ static int usb_serial_device_probe (struct device *dev) minor = port->number; tty_register_devfs (&usb_serial_tty_driver, 0, minor); - info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", - driver->name, minor, minor); + dev_info(*dev, "%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)\n", + driver->name, minor, minor); exit: return retval; @@ -101,7 +101,7 @@ static int usb_serial_device_remove (struct device *dev) driver = port->serial->type; if (driver->port_remove) { if (!try_module_get(driver->owner)) { - err ("module get failed, exiting"); + dev_err(*dev, "module get failed, exiting\n"); retval = -EIO; goto exit; } @@ -111,8 +111,8 @@ static int usb_serial_device_remove (struct device *dev) exit: minor = port->number; tty_unregister_devfs (&usb_serial_tty_driver, minor); - info("%s converter now disconnected from ttyUSB%d", - driver->name, minor); + dev_info(*dev, "%s converter now disconnected from ttyUSB%d\n", + driver->name, minor); return retval; } diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c index 35616b5e23a0..ad567d566953 100644 --- a/drivers/usb/serial/ezusb.c +++ b/drivers/usb/serial/ezusb.c @@ -41,7 +41,7 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da transfer_buffer = kmalloc (length, GFP_KERNEL); if (!transfer_buffer) { - err("%s - kmalloc(%d) failed.", __FUNCTION__, length); + dev_err(serial->dev->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, length); return -ENOMEM; } memcpy (transfer_buffer, data, length); @@ -56,7 +56,7 @@ int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) dbg("%s - %d", __FUNCTION__, reset_bit); response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0); if (response < 0) { - err("%s- %d failed", __FUNCTION__, reset_bit); + dev_err(serial->dev->dev, "%s- %d failed\n", __FUNCTION__, reset_bit); } return response; } diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index d4dde44d06b5..ae5bdb865bdc 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -106,7 +106,7 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); } return result; @@ -176,7 +176,7 @@ int usb_serial_generic_write (struct usb_serial_port *port, int from_user, const /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) - err("%s - failed submitting write urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); else result = count; @@ -266,7 +266,7 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *reg usb_serial_generic_read_bulk_callback), port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); } void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 40a1f81361c1..4c43ef447488 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -841,7 +841,7 @@ static struct usb_serial * create_serial (struct usb_device *dev, serial = kmalloc (sizeof (*serial), GFP_KERNEL); if (!serial) { - err ("%s - out of memory", __FUNCTION__); + dev_err(dev->dev, "%s - out of memory\n", __FUNCTION__); return NULL; } memset (serial, 0, sizeof(*serial)); @@ -899,14 +899,14 @@ int usb_serial_probe(struct usb_interface *interface, serial = create_serial (dev, interface, type); if (!serial) { - err ("%s - out of memory", __FUNCTION__); + dev_err(interface->dev, "%s - out of memory\n", __FUNCTION__); return -ENODEV; } /* if this device type has a probe function, call it */ if (type->probe) { if (!try_module_get(type->owner)) { - err ("module get failed, exiting"); + dev_err(interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; } @@ -980,7 +980,7 @@ int usb_serial_probe(struct usb_interface *interface, * properly during a later invocation of usb_serial_probe */ if (num_bulk_in == 0 || num_bulk_out == 0) { - info("PL-2303 hack: descriptors matched but endpoints did not"); + dev_info(interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); kfree (serial); return -ENODEV; } @@ -989,13 +989,13 @@ int usb_serial_probe(struct usb_interface *interface, #endif /* found all that we need */ - info("%s converter detected", type->name); + dev_info(interface->dev, "%s converter detected\n", type->name); #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; if (num_ports == 0) { - err("Generic device with no bulk out, not allowed."); + dev_err(interface->dev, "Generic device with no bulk out, not allowed.\n"); kfree (serial); return -EIO; } @@ -1005,7 +1005,7 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has a calc_num_ports function, call it */ if (type->calc_num_ports) { if (!try_module_get(type->owner)) { - err ("module get failed, exiting"); + dev_err(interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; } @@ -1017,7 +1017,7 @@ int usb_serial_probe(struct usb_interface *interface, } if (get_free_serial (serial, num_ports, &minor) == NULL) { - err("No more free serial devices"); + dev_err(interface->dev, "No more free serial devices\n"); kfree (serial); return -ENOMEM; } @@ -1034,14 +1034,14 @@ int usb_serial_probe(struct usb_interface *interface, port = &serial->port[i]; port->read_urb = usb_alloc_urb (0, GFP_KERNEL); if (!port->read_urb) { - err("No free urbs available"); + dev_err(interface->dev, "No free urbs available\n"); goto probe_error; } buffer_size = endpoint->wMaxPacketSize; port->bulk_in_endpointAddress = endpoint->bEndpointAddress; port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); if (!port->bulk_in_buffer) { - err("Couldn't allocate bulk_in_buffer"); + dev_err(interface->dev, "Couldn't allocate bulk_in_buffer\n"); goto probe_error; } usb_fill_bulk_urb (port->read_urb, dev, @@ -1059,7 +1059,7 @@ int usb_serial_probe(struct usb_interface *interface, port = &serial->port[i]; port->write_urb = usb_alloc_urb(0, GFP_KERNEL); if (!port->write_urb) { - err("No free urbs available"); + dev_err(interface->dev, "No free urbs available\n"); goto probe_error; } buffer_size = endpoint->wMaxPacketSize; @@ -1067,7 +1067,7 @@ int usb_serial_probe(struct usb_interface *interface, port->bulk_out_endpointAddress = endpoint->bEndpointAddress; port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL); if (!port->bulk_out_buffer) { - err("Couldn't allocate bulk_out_buffer"); + dev_err(interface->dev, "Couldn't allocate bulk_out_buffer\n"); goto probe_error; } usb_fill_bulk_urb (port->write_urb, dev, @@ -1085,14 +1085,14 @@ int usb_serial_probe(struct usb_interface *interface, port = &serial->port[i]; port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!port->interrupt_in_urb) { - err("No free urbs available"); + dev_err(interface->dev, "No free urbs available\n"); goto probe_error; } buffer_size = endpoint->wMaxPacketSize; port->interrupt_in_endpointAddress = endpoint->bEndpointAddress; port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); if (!port->interrupt_in_buffer) { - err("Couldn't allocate interrupt_in_buffer"); + dev_err(interface->dev, "Couldn't allocate interrupt_in_buffer\n"); goto probe_error; } usb_fill_int_urb (port->interrupt_in_urb, dev, @@ -1121,7 +1121,7 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has an attach function, call it */ if (type->attach) { if (!try_module_get(type->owner)) { - err ("module get failed, exiting"); + dev_err(interface->dev, "module get failed, exiting\n"); goto probe_error; } retval = type->attach (serial); @@ -1190,6 +1190,7 @@ probe_error: void usb_serial_disconnect(struct usb_interface *interface) { struct usb_serial *serial = dev_get_drvdata (&interface->dev); + struct device *dev = &interface->dev; struct usb_serial_port *port; int i; @@ -1252,8 +1253,7 @@ void usb_serial_disconnect(struct usb_interface *interface) /* free up any memory that we allocated */ kfree (serial); } - info("device disconnected"); - + dev_info(*dev, "device disconnected\n"); } -- cgit v1.2.3 From 90b8e1ed39ed8018a2c1236084347eb4a1ec6776 Mon Sep 17 00:00:00 2001 From: Ivan Kokshaysky Date: Wed, 25 Dec 2002 21:54:58 -0800 Subject: [PATCH] fix PCI bridge handling in probe.c As Ben pointed out, disabling the PCI-to-PCI bridge before scanning its secondary bus is a serious bug. It can easily crash even on PCs when booting with "pci=assign-busses" option. For example, that code completely disconnects the AGP bridge (along with VGA behind it) from the bus and then calls pci_do_scan_bus() where printks are quite possible. --- drivers/pci/probe.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a9064b0ffea8..4363f2c188c3 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -285,13 +285,12 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max } else { /* * We need to assign a number to this bus which we always - * do in the second pass. We also keep all address decoders - * on the bridge disabled during scanning. FIXME: Why? + * do in the second pass. */ if (!pass) return max; - pci_read_config_word(dev, PCI_COMMAND, &cr); - pci_write_config_word(dev, PCI_COMMAND, 0x0000); + + /* Clear errors */ pci_write_config_word(dev, PCI_STATUS, 0xffff); child = pci_add_new_bus(bus, dev, ++max); @@ -319,7 +318,6 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max */ child->subordinate = max; pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); - pci_write_config_word(dev, PCI_COMMAND, cr); } sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number); -- cgit v1.2.3 From 6898c902b76b3d55022a44da95fbe38569458dd9 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Wed, 25 Dec 2002 21:55:05 -0800 Subject: [PATCH] amd756 and amd8111 sensors support Add support for amd756 and amd8111 sensors --- MAINTAINERS | 9 + drivers/Makefile | 2 + drivers/char/mem.c | 13 + drivers/i2c/Kconfig | 3 + drivers/i2c/busses/Kconfig | 56 +++ drivers/i2c/busses/Makefile | 7 + drivers/i2c/busses/i2c-amd756.c | 526 ++++++++++++++++++++++++++++ drivers/i2c/busses/i2c-amd8111.c | 425 +++++++++++++++++++++++ drivers/i2c/busses/i2c-mainboard.c | 34 ++ drivers/i2c/chips/Kconfig | 54 +++ drivers/i2c/chips/Makefile | 7 + drivers/i2c/chips/adm1021.c | 633 ++++++++++++++++++++++++++++++++++ drivers/i2c/chips/lm75.c | 403 ++++++++++++++++++++++ drivers/i2c/chips/sensors.c | 37 ++ drivers/i2c/i2c-core.c | 15 +- drivers/i2c/i2c-dev.c | 15 +- drivers/i2c/i2c-proc.c | 60 +++- include/linux/i2c-id.h | 1 + include/linux/i2c-proc.h | 25 ++ include/linux/sensors.h | 690 +++++++++++++++++++++++++++++++++++++ 20 files changed, 3003 insertions(+), 12 deletions(-) create mode 100644 drivers/i2c/busses/Kconfig create mode 100644 drivers/i2c/busses/Makefile create mode 100644 drivers/i2c/busses/i2c-amd756.c create mode 100644 drivers/i2c/busses/i2c-amd8111.c create mode 100644 drivers/i2c/busses/i2c-mainboard.c create mode 100644 drivers/i2c/chips/Kconfig create mode 100644 drivers/i2c/chips/Makefile create mode 100644 drivers/i2c/chips/adm1021.c create mode 100644 drivers/i2c/chips/lm75.c create mode 100644 drivers/i2c/chips/sensors.c create mode 100644 include/linux/sensors.h diff --git a/MAINTAINERS b/MAINTAINERS index 8e382197d494..e8b5a59b5353 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -762,6 +762,15 @@ L: linux-i2c@pelican.tk.uni-linz.ac.at W: http://www.tk.uni-linz.ac.at/~simon/private/i2c S: Maintained +SENSORS DRIVERS +P: Frodo Looijaard +M: frodol@dds.nl +P: Philip Edelbrock +M: phil@netroedge.com +L: sensors@stimpy.netroedge.com +W: http://www.lm-sensors.nu/ +S: Maintained + i386 BOOT CODE P: Riley H. Williams M: Riley@Williams.Name diff --git a/drivers/Makefile b/drivers/Makefile index a6ce89683e2c..07c756c046b8 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -38,6 +38,8 @@ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2C) += i2c/ +obj-$(CONFIG_I2C_MAINBOARD) += i2c/busses/ +obj-$(CONFIG_SENSORS) += i2c/chips/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 3df145966b6d..0e97b489d17b 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -27,6 +27,12 @@ #include #include +#ifdef CONFIG_I2C_MAINBOARD +extern void i2c_mainboard_init_all(void); +#endif +#ifdef CONFIG_SENSORS +extern void sensors_init_all(void); +#endif #ifdef CONFIG_I2C extern int i2c_init_all(void); #endif @@ -705,6 +711,9 @@ int __init chr_dev_init(void) #ifdef CONFIG_I2C i2c_init_all(); #endif +#ifdef CONFIG_I2C_MAINBOARD + i2c_mainboard_init_all(); +#endif #if defined (CONFIG_FB) fbmem_init(); #endif @@ -719,6 +728,10 @@ int __init chr_dev_init(void) #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) tapechar_init(); #endif +#ifdef CONFIG_SENSORS + sensors_init_all(); +#endif + return 0; } diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 131f4c901af5..206f7c5f2ed4 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -193,5 +193,8 @@ config I2C_PROC it as a module, say M here and read . The module will be called i2c-proc.o. + source drivers/i2c/busses/Kconfig + source drivers/i2c/chips/Kconfig + endmenu diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig new file mode 100644 index 000000000000..b6bf9ee09ff2 --- /dev/null +++ b/drivers/i2c/busses/Kconfig @@ -0,0 +1,56 @@ +# +# Sensor device configuration +# All depend on EXPERIMENTAL, I2C and I2C_PROC. +# + +menu "I2C Hardware Sensors Mainboard support" + +config I2C_MAINBOARD + bool "Hardware sensors mainboard support" + depends on EXPERIMENTAL && I2C && I2C_PROC + help + Many modern mainboards have some kind of I2C interface integrated. This + is often in the form of a SMBus, or System Management Bus, which is + basically the same as I2C but which uses only a subset of the I2C + protocol. + + You will also want the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config I2C_AMD756 + tristate " AMD 756/766" + depends on I2C_MAINBOARD + help + If you say yes to this option, support will be included for the AMD + 756/766/768 mainboard I2C interfaces. + + This can also be built as a module which can be inserted and removed + while the kernel is running. If you want to compile it as a module, + say M here and read . + + The module will be called i2c-amd756.o. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config I2C_AMD8111 + tristate " AMD 8111" + depends on I2C_MAINBOARD + help + If you say yes to this option, support will be included for the AMD + 8111 mainboard I2C interfaces. + + This can also be built as a module which can be inserted and removed + while the kernel is running. If you want to compile it as a module, + say M here and read . + + The module will be called i2c-amd8111.o. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +endmenu + diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile new file mode 100644 index 000000000000..75d4babc375c --- /dev/null +++ b/drivers/i2c/busses/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the kernel hardware sensors bus drivers. +# + +obj-$(CONFIG_I2C_MAINBOARD) += i2c-mainboard.o +obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o +obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c new file mode 100644 index 000000000000..db08bdc56430 --- /dev/null +++ b/drivers/i2c/busses/i2c-amd756.c @@ -0,0 +1,526 @@ +/* + amd756.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + + Copyright (c) 1999-2002 Merlin Hughes + + Shamelessly ripped from i2c-piix4.c: + + Copyright (c) 1998, 1999 Frodo Looijaard and + Philip Edelbrock + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + 2002-04-08: Added nForce support. (Csaba Halasz) + 2002-10-03: Fixed nForce PnP I/O port. (Michael Steil) +*/ + +/* + Supports AMD756, AMD766, AMD768 and nVidia nForce + Note: we assume there can only be one device, with one SMBus interface. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct sd { + const unsigned short vendor; + const unsigned short device; + const unsigned short function; + const char* name; + int amdsetup:1; +}; + +static struct sd supported[] = { + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B, 3, "AMD756", 1}, + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 3, "AMD766", 1}, + {PCI_VENDOR_ID_AMD, 0x7443, 3, "AMD768", 1}, + {PCI_VENDOR_ID_NVIDIA, 0x01B4, 1, "nVidia nForce", 0}, + {0, 0, 0} +}; + +/* AMD756 SMBus address offsets */ +#define SMB_ADDR_OFFSET 0xE0 +#define SMB_IOSIZE 16 +#define SMB_GLOBAL_STATUS (0x0 + amd756_smba) +#define SMB_GLOBAL_ENABLE (0x2 + amd756_smba) +#define SMB_HOST_ADDRESS (0x4 + amd756_smba) +#define SMB_HOST_DATA (0x6 + amd756_smba) +#define SMB_HOST_COMMAND (0x8 + amd756_smba) +#define SMB_HOST_BLOCK_DATA (0x9 + amd756_smba) +#define SMB_HAS_DATA (0xA + amd756_smba) +#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_smba) +#define SMB_HAS_HOST_ADDRESS (0xE + amd756_smba) +#define SMB_SNOOP_ADDRESS (0xF + amd756_smba) + +/* PCI Address Constants */ + +/* address of I/O space */ +#define SMBBA 0x058 /* mh */ +#define SMBBANFORCE 0x014 + +/* general configuration */ +#define SMBGCFG 0x041 /* mh */ + +/* silicon revision code */ +#define SMBREV 0x008 + +/* Other settings */ +#define MAX_TIMEOUT 500 + +/* AMD756 constants */ +#define AMD756_QUICK 0x00 +#define AMD756_BYTE 0x01 +#define AMD756_BYTE_DATA 0x02 +#define AMD756_WORD_DATA 0x03 +#define AMD756_PROCESS_CALL 0x04 +#define AMD756_BLOCK_DATA 0x05 + +/* insmod parameters */ + +int __init i2c_amd756_init(void); +void __exit i2c_amd756_exit(void); +static int amd756_cleanup(void); + +static int amd756_setup(void); +static s32 amd756_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data); +static void amd756_do_pause(unsigned int amount); +static void amd756_abort(void); +static int amd756_transaction(void); +static void amd756_inc(struct i2c_adapter *adapter); +static void amd756_dec(struct i2c_adapter *adapter); +static u32 amd756_func(struct i2c_adapter *adapter); + +static struct i2c_algorithm smbus_algorithm = { + /* name */ "Non-I2C SMBus adapter", + /* id */ I2C_ALGO_SMBUS, + /* master_xfer */ NULL, + /* smbus_access */ amd756_access, + /* slave;_send */ NULL, + /* slave_rcv */ NULL, + /* algo_control */ NULL, + /* functionality */ amd756_func, +}; + +static struct i2c_adapter amd756_adapter = { + "unset", + I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756, + &smbus_algorithm, + NULL, + amd756_inc, + amd756_dec, + NULL, + NULL, +}; + +static int __initdata amd756_initialized; +static struct sd *amd756_sd = NULL; +static unsigned short amd756_smba = 0; + +int amd756_setup(void) +{ + unsigned char temp; + struct sd *currdev; + struct pci_dev *AMD756_dev = NULL; + + if (pci_present() == 0) { + return -ENODEV; + } + + /* Look for a supported chip */ + for(currdev = supported; currdev->vendor; ) { + AMD756_dev = pci_find_device(currdev->vendor, + currdev->device, AMD756_dev); + if (AMD756_dev != NULL) { + if (PCI_FUNC(AMD756_dev->devfn) == currdev->function) + break; + } else { + currdev++; + } + } + + if (AMD756_dev == NULL) { + printk + ("i2c-amd756.o: Error: No AMD756 or compatible device detected!\n"); + return -ENODEV; + } + printk(KERN_INFO "i2c-amd756.o: Found %s SMBus controller.\n", currdev->name); + + if (currdev->amdsetup) + { + pci_read_config_byte(AMD756_dev, SMBGCFG, &temp); + if ((temp & 128) == 0) { + printk("i2c-amd756.o: Error: SMBus controller I/O not enabled!\n"); + return -ENODEV; + } + + /* Determine the address of the SMBus areas */ + /* Technically it is a dword but... */ + pci_read_config_word(AMD756_dev, SMBBA, &amd756_smba); + amd756_smba &= 0xff00; + amd756_smba += SMB_ADDR_OFFSET; + } else { + pci_read_config_word(AMD756_dev, SMBBANFORCE, &amd756_smba); + amd756_smba &= 0xfffc; + } + if(amd756_smba == 0) { + printk(KERN_ERR "i2c-amd756.o: Error: SMB base address uninitialized\n"); + return -ENODEV; + } + if (check_region(amd756_smba, SMB_IOSIZE)) { + printk + ("i2c-amd756.o: SMB region 0x%x already in use!\n", + amd756_smba); + return -ENODEV; + } + + /* Everything is happy, let's grab the memory and set things up. */ + request_region(amd756_smba, SMB_IOSIZE, "amd756-smbus"); + +#ifdef DEBUG + pci_read_config_byte(AMD756_dev, SMBREV, &temp); + printk("i2c-amd756.o: SMBREV = 0x%X\n", temp); + printk("i2c-amd756.o: AMD756_smba = 0x%X\n", amd756_smba); +#endif /* DEBUG */ + + /* store struct sd * for future reference */ + amd756_sd = currdev; + + return 0; +} + +/* + SMBUS event = I/O 28-29 bit 11 + see E0 for the status bits and enabled in E2 + +*/ + +/* Internally used pause function */ +void amd756_do_pause(unsigned int amount) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(amount); +} + +#define GS_ABRT_STS (1 << 0) +#define GS_COL_STS (1 << 1) +#define GS_PRERR_STS (1 << 2) +#define GS_HST_STS (1 << 3) +#define GS_HCYC_STS (1 << 4) +#define GS_TO_STS (1 << 5) +#define GS_SMB_STS (1 << 11) + +#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \ + GS_HCYC_STS | GS_TO_STS ) + +#define GE_CYC_TYPE_MASK (7) +#define GE_HOST_STC (1 << 3) +#define GE_ABORT (1 << 5) + +void amd756_abort(void) +{ + printk("i2c-amd756.o: Sending abort.\n"); + outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE); + amd756_do_pause(100); + outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); +} + +int amd756_transaction(void) +{ + int temp; + int result = 0; + int timeout = 0; + +#ifdef DEBUG + printk + ("i2c-amd756.o: Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", + inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), + inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); +#endif + + /* Make sure the SMBus host is ready to start transmitting */ + if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) { +#ifdef DEBUG + printk + ("i2c-amd756.o: SMBus busy (%04x). Waiting... \n", temp); +#endif + do { + amd756_do_pause(1); + temp = inw_p(SMB_GLOBAL_STATUS); + } while ((temp & (GS_HST_STS | GS_SMB_STS)) && + (timeout++ < MAX_TIMEOUT)); + /* If the SMBus is still busy, we give up */ + if (timeout >= MAX_TIMEOUT) { + printk("i2c-amd756.o: Busy wait timeout! (%04x)\n", temp); + amd756_abort(); + return -1; + } + timeout = 0; + } + + /* start the transaction by setting the start bit */ + outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE); + + /* We will always wait for a fraction of a second! */ + do { + amd756_do_pause(1); + temp = inw_p(SMB_GLOBAL_STATUS); + } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT)); + + /* If the SMBus is still busy, we give up */ + if (timeout >= MAX_TIMEOUT) { + printk("i2c-amd756.o: Completion timeout!\n"); + amd756_abort (); + return -1; + } + + if (temp & GS_PRERR_STS) { + result = -1; +#ifdef DEBUG + printk("i2c-amd756.o: SMBus Protocol error (no response)!\n"); +#endif + } + + if (temp & GS_COL_STS) { + result = -1; + printk("i2c-amd756.o: SMBus collision!\n"); + } + + if (temp & GS_TO_STS) { + result = -1; +#ifdef DEBUG + printk("i2c-amd756.o: SMBus protocol timeout!\n"); +#endif + } +#ifdef DEBUG + if (temp & GS_HCYC_STS) { + printk("i2c-amd756.o: SMBus protocol success!\n"); + } +#endif + + outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); + +#ifdef DEBUG + if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) { + printk + ("i2c-amd756.o: Failed reset at end of transaction (%04x)\n", + temp); + } + printk + ("i2c-amd756.o: Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", + inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), + inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); +#endif + + return result; +} + +/* Return -1 on error. */ +s32 amd756_access(struct i2c_adapter * adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data * data) +{ + int i, len; + + /** TODO: Should I supporte the 10-bit transfers? */ + switch (size) { + case I2C_SMBUS_PROC_CALL: + printk + ("i2c-amd756.o: I2C_SMBUS_PROC_CALL not supported!\n"); + /* TODO: Well... It is supported, I'm just not sure what to do here... */ + return -1; + case I2C_SMBUS_QUICK: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + size = AMD756_QUICK; + break; + case I2C_SMBUS_BYTE: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + /* TODO: Why only during write? */ + if (read_write == I2C_SMBUS_WRITE) + outb_p(command, SMB_HOST_COMMAND); + size = AMD756_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + outb_p(command, SMB_HOST_COMMAND); + if (read_write == I2C_SMBUS_WRITE) + outw_p(data->byte, SMB_HOST_DATA); + size = AMD756_BYTE_DATA; + break; + case I2C_SMBUS_WORD_DATA: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + outb_p(command, SMB_HOST_COMMAND); + if (read_write == I2C_SMBUS_WRITE) + outw_p(data->word, SMB_HOST_DATA); /* TODO: endian???? */ + size = AMD756_WORD_DATA; + break; + case I2C_SMBUS_BLOCK_DATA: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + outb_p(command, SMB_HOST_COMMAND); + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + if (len < 0) + len = 0; + if (len > 32) + len = 32; + outw_p(len, SMB_HOST_DATA); + /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */ + for (i = 1; i <= len; i++) + outb_p(data->block[i], + SMB_HOST_BLOCK_DATA); + } + size = AMD756_BLOCK_DATA; + break; + } + + /* How about enabling interrupts... */ + outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE); + + if (amd756_transaction()) /* Error in transaction */ + return -1; + + if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK)) + return 0; + + + switch (size) { + case AMD756_BYTE: + data->byte = inw_p(SMB_HOST_DATA); + break; + case AMD756_BYTE_DATA: + data->byte = inw_p(SMB_HOST_DATA); + break; + case AMD756_WORD_DATA: + data->word = inw_p(SMB_HOST_DATA); /* TODO: endian???? */ + break; + case AMD756_BLOCK_DATA: + data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f; + if(data->block[0] > 32) + data->block[0] = 32; + /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */ + for (i = 1; i <= data->block[0]; i++) + data->block[i] = inb_p(SMB_HOST_BLOCK_DATA); + break; + } + + return 0; +} + +void amd756_inc(struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +void amd756_dec(struct i2c_adapter *adapter) +{ + + MOD_DEC_USE_COUNT; +} + +u32 amd756_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL; +} + +int __init i2c_amd756_init(void) +{ + int res; +#ifdef DEBUG +/* PE- It might be good to make this a permanent part of the code! */ + if (amd756_initialized) { + printk + ("i2c-amd756.o: Oops, amd756_init called a second time!\n"); + return -EBUSY; + } +#endif + amd756_initialized = 0; + if ((res = amd756_setup())) { + printk + ("i2c-amd756.o: AMD756 or compatible device not detected, module not inserted.\n"); + amd756_cleanup(); + return res; + } + amd756_initialized++; + sprintf(amd756_adapter.name, "SMBus %s adapter at %04x", + amd756_sd->name, amd756_smba); + if ((res = i2c_add_adapter(&amd756_adapter))) { + printk + ("i2c-amd756.o: Adapter registration failed, module not inserted.\n"); + amd756_cleanup(); + return res; + } + amd756_initialized++; + printk("i2c-amd756.o: %s bus detected and initialized\n", + amd756_sd->name); + return 0; +} + +void __exit i2c_amd756_exit(void) +{ + amd756_cleanup(); +} + +static int amd756_cleanup(void) +{ + int res; + if (amd756_initialized >= 2) { + if ((res = i2c_del_adapter(&amd756_adapter))) { + printk + ("i2c-amd756.o: i2c_del_adapter failed, module not removed\n"); + return res; + } else + amd756_initialized--; + } + if (amd756_initialized >= 1) { + release_region(amd756_smba, SMB_IOSIZE); + amd756_initialized--; + } + return 0; +} + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE + +MODULE_AUTHOR("Merlin Hughes "); +MODULE_DESCRIPTION("AMD756/766/768/nVidia nForce SMBus driver"); + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#endif /* MODULE */ + +module_init(i2c_amd756_init) +module_exit(i2c_amd756_exit) diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c new file mode 100644 index 000000000000..ac2f741d3843 --- /dev/null +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -0,0 +1,425 @@ +/* + * SMBus 2.0 driver for AMD-8111 IO-Hub. + * + * Copyright (c) 2002 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("Vojtech Pavlik "); +MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver"); + +struct amd_smbus { + struct pci_dev *dev; + struct i2c_adapter adapter; + int base; + int size; +}; + +/* + * AMD PCI control registers definitions. + */ + +#define AMD_PCI_MISC 0x48 + +#define AMD_PCI_MISC_SCI 0x04 /* deliver SCI */ +#define AMD_PCI_MISC_INT 0x02 /* deliver PCI IRQ */ +#define AMD_PCI_MISC_SPEEDUP 0x01 /* 16x clock speedup */ + +/* + * ACPI 2.0 chapter 13 PCI interface definitions. + */ + +#define AMD_EC_DATA 0x00 /* data register */ +#define AMD_EC_SC 0x04 /* status of controller */ +#define AMD_EC_CMD 0x04 /* command register */ +#define AMD_EC_ICR 0x08 /* interrupt control register */ + +#define AMD_EC_SC_SMI 0x04 /* smi event pending */ +#define AMD_EC_SC_SCI 0x02 /* sci event pending */ +#define AMD_EC_SC_BURST 0x01 /* burst mode enabled */ +#define AMD_EC_SC_CMD 0x08 /* byte in data reg is command */ +#define AMD_EC_SC_IBF 0x02 /* data ready for embedded controller */ +#define AMD_EC_SC_OBF 0x01 /* data ready for host */ + +#define AMD_EC_CMD_RD 0x80 /* read EC */ +#define AMD_EC_CMD_WR 0x81 /* write EC */ +#define AMD_EC_CMD_BE 0x82 /* enable burst mode */ +#define AMD_EC_CMD_BD 0x83 /* disable burst mode */ +#define AMD_EC_CMD_QR 0x84 /* query EC */ + +/* + * ACPI 2.0 chapter 13 access of registers of the EC + */ + +unsigned int amd_ec_wait_write(struct amd_smbus *smbus) +{ + int timeout = 500; + + while (timeout-- && (inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF)) + udelay(1); + + if (!timeout) { + printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for IBF to clear\n"); + return -1; + } + + return 0; +} + +unsigned int amd_ec_wait_read(struct amd_smbus *smbus) +{ + int timeout = 500; + + while (timeout-- && (~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF)) + udelay(1); + + if (!timeout) { + printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for OBF to set\n"); + return -1; + } + + return 0; +} + +unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, unsigned char *data) +{ + if (amd_ec_wait_write(smbus)) + return -1; + outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD); + + if (amd_ec_wait_write(smbus)) + return -1; + outb(address, smbus->base + AMD_EC_DATA); + + if (amd_ec_wait_read(smbus)) + return -1; + *data = inb(smbus->base + AMD_EC_DATA); + + return 0; +} + +unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsigned char data) +{ + if (amd_ec_wait_write(smbus)) + return -1; + outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD); + + if (amd_ec_wait_write(smbus)) + return -1; + outb(address, smbus->base + AMD_EC_DATA); + + if (amd_ec_wait_write(smbus)) + return -1; + outb(data, smbus->base + AMD_EC_DATA); + + return 0; +} + +/* + * ACPI 2.0 chapter 13 SMBus 2.0 EC register model + */ + +#define AMD_SMB_PRTCL 0x00 /* protocol, PEC */ +#define AMD_SMB_STS 0x01 /* status */ +#define AMD_SMB_ADDR 0x02 /* address */ +#define AMD_SMB_CMD 0x03 /* command */ +#define AMD_SMB_DATA 0x04 /* 32 data registers */ +#define AMD_SMB_BCNT 0x24 /* number of data bytes */ +#define AMD_SMB_ALRM_A 0x25 /* alarm address */ +#define AMD_SMB_ALRM_D 0x26 /* 2 bytes alarm data */ + +#define AMD_SMB_STS_DONE 0x80 +#define AMD_SMB_STS_ALRM 0x40 +#define AMD_SMB_STS_RES 0x20 +#define AMD_SMB_STS_STATUS 0x1f + +#define AMD_SMB_STATUS_OK 0x00 +#define AMD_SMB_STATUS_FAIL 0x07 +#define AMD_SMB_STATUS_DNAK 0x10 +#define AMD_SMB_STATUS_DERR 0x11 +#define AMD_SMB_STATUS_CMD_DENY 0x12 +#define AMD_SMB_STATUS_UNKNOWN 0x13 +#define AMD_SMB_STATUS_ACC_DENY 0x17 +#define AMD_SMB_STATUS_TIMEOUT 0x18 +#define AMD_SMB_STATUS_NOTSUP 0x19 +#define AMD_SMB_STATUS_BUSY 0x1A +#define AMD_SMB_STATUS_PEC 0x1F + +#define AMD_SMB_PRTCL_WRITE 0x00 +#define AMD_SMB_PRTCL_READ 0x01 +#define AMD_SMB_PRTCL_QUICK 0x02 +#define AMD_SMB_PRTCL_BYTE 0x04 +#define AMD_SMB_PRTCL_BYTE_DATA 0x06 +#define AMD_SMB_PRTCL_WORD_DATA 0x08 +#define AMD_SMB_PRTCL_BLOCK_DATA 0x0a +#define AMD_SMB_PRTCL_PROC_CALL 0x0c +#define AMD_SMB_PRTCL_BLOCK_PROC_CALL 0x0d +#define AMD_SMB_PRTCL_I2C_BLOCK_DATA 0x4a +#define AMD_SMB_PRTCL_PEC 0x80 + + +s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, + char read_write, u8 command, int size, union i2c_smbus_data * data) +{ + struct amd_smbus *smbus = adap->algo_data; + unsigned char protocol, len, pec, temp[2]; + int i; + + protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE; + pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0; + + switch (size) { + + case I2C_SMBUS_QUICK: + protocol |= AMD_SMB_PRTCL_QUICK; + read_write = I2C_SMBUS_WRITE; + break; + + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) + amd_ec_write(smbus, AMD_SMB_DATA, data->byte); + protocol |= AMD_SMB_PRTCL_BYTE; + break; + + case I2C_SMBUS_BYTE_DATA: + amd_ec_write(smbus, AMD_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) + amd_ec_write(smbus, AMD_SMB_DATA, data->byte); + protocol |= AMD_SMB_PRTCL_BYTE_DATA; + break; + + case I2C_SMBUS_WORD_DATA_PEC: + protocol |= AMD_SMB_PRTCL_PEC; + case I2C_SMBUS_WORD_DATA: + amd_ec_write(smbus, AMD_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) { + amd_ec_write(smbus, AMD_SMB_DATA, data->word); + amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); + } + protocol |= AMD_SMB_PRTCL_WORD_DATA | pec; + break; + + case I2C_SMBUS_BLOCK_DATA_PEC: + protocol |= AMD_SMB_PRTCL_PEC; + case I2C_SMBUS_BLOCK_DATA: + amd_ec_write(smbus, AMD_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) { + len = min_t(u8, data->block[0], 32); + amd_ec_write(smbus, AMD_SMB_BCNT, len); + for (i = 0; i < len; i++) + amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + } + protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec; + break; + + case I2C_SMBUS_I2C_BLOCK_DATA: + len = min_t(u8, data->block[0], 32); + amd_ec_write(smbus, AMD_SMB_CMD, command); + amd_ec_write(smbus, AMD_SMB_BCNT, len); + if (read_write == I2C_SMBUS_WRITE) + for (i = 0; i < len; i++) + amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA; + break; + + case I2C_SMBUS_PROC_CALL_PEC: + protocol |= AMD_SMB_PRTCL_PEC; + case I2C_SMBUS_PROC_CALL: + amd_ec_write(smbus, AMD_SMB_CMD, command); + amd_ec_write(smbus, AMD_SMB_DATA, data->word); + amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); + protocol = AMD_SMB_PRTCL_PROC_CALL | pec; + read_write = I2C_SMBUS_READ; + break; + + case I2C_SMBUS_BLOCK_PROC_CALL_PEC: + protocol |= AMD_SMB_PRTCL_PEC; + case I2C_SMBUS_BLOCK_PROC_CALL: + protocol |= pec; + len = min_t(u8, data->block[0], 31); + amd_ec_write(smbus, AMD_SMB_CMD, command); + amd_ec_write(smbus, AMD_SMB_BCNT, len); + for (i = 0; i < len; i++) + amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec; + read_write = I2C_SMBUS_READ; + break; + + default: + printk(KERN_WARNING "i2c-amd8111.c: Unsupported transaction %d\n", size); + return -1; + } + + amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1); + amd_ec_write(smbus, AMD_SMB_PRTCL, protocol); + + amd_ec_read(smbus, AMD_SMB_STS, temp + 0); + + if (~temp[0] & AMD_SMB_STS_DONE) { + udelay(500); + amd_ec_read(smbus, AMD_SMB_STS, temp + 0); + } + + if (~temp[0] & AMD_SMB_STS_DONE) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/100); + amd_ec_read(smbus, AMD_SMB_STS, temp + 0); + } + + if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS)) + return -1; + + if (read_write == I2C_SMBUS_WRITE) + return 0; + + switch (size) { + + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + amd_ec_read(smbus, AMD_SMB_DATA, &data->byte); + break; + + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_WORD_DATA_PEC: + case I2C_SMBUS_PROC_CALL: + case I2C_SMBUS_PROC_CALL_PEC: + amd_ec_read(smbus, AMD_SMB_DATA, temp + 0); + amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1); + data->word = (temp[1] << 8) | temp[0]; + break; + + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_DATA_PEC: + case I2C_SMBUS_BLOCK_PROC_CALL: + case I2C_SMBUS_BLOCK_PROC_CALL_PEC: + amd_ec_read(smbus, AMD_SMB_BCNT, &len); + len = min_t(u8, len, 32); + case I2C_SMBUS_I2C_BLOCK_DATA: + for (i = 0; i < len; i++) + amd_ec_read(smbus, AMD_SMB_DATA + i, data->block + i + 1); + data->block[0] = len; + break; + } + + return 0; +} + +void amd8111_inc(struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +void amd8111_dec(struct i2c_adapter *adapter) +{ + MOD_DEC_USE_COUNT; +} + +u32 amd8111_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WORD_DATA_PEC | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA_PEC | + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PROC_CALL_PEC | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC | + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC; +} + +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus 2.0 adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = amd8111_access, + .functionality = amd8111_func, +}; + +static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct amd_smbus *smbus; + + if (~pci_resource_flags(dev, 0) & IORESOURCE_IO) + return -1; + + if (!(smbus = (void*)kmalloc(sizeof(struct amd_smbus), GFP_KERNEL))) + return -1; + memset(smbus, 0, sizeof(struct amd_smbus)); + + pci_set_drvdata(dev, smbus); + smbus->dev = dev; + smbus->base = pci_resource_start(dev, 0); + smbus->size = pci_resource_len(dev, 0); + + if (!request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0")) { + kfree(smbus); + return -1; + } + + sprintf(smbus->adapter.name, "SMBus2 AMD8111 adapter at %04x", smbus->base); + smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111; + smbus->adapter.algo = &smbus_algorithm; + smbus->adapter.algo_data = smbus; + smbus->adapter.inc_use = amd8111_inc; + smbus->adapter.dec_use = amd8111_dec; + + if (i2c_add_adapter(&smbus->adapter)) { + printk(KERN_WARNING "i2c-amd8111.c: Failed to register adapter.\n"); + release_region(smbus->base, smbus->size); + kfree(smbus); + return -1; + } + + pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0); + + printk(KERN_INFO "i2c-amd8111.c: AMD8111 SMBus 2.0 adapter at %#x\n", smbus->base); + return 0; +} + +static void __devexit amd8111_remove(struct pci_dev *dev) +{ + struct amd_smbus *smbus = (void*) pci_get_drvdata(dev); + if (i2c_del_adapter(&smbus->adapter)) { + printk(KERN_WARNING "i2c-amd8111.c: Failed to unregister adapter.\n"); + return; + } + release_region(smbus->base, smbus->size); + kfree(smbus); +} + +static struct pci_device_id amd8111_id_table[] __devinitdata = +{{ 0x1022, 0x746a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 }}; + + +static struct pci_driver amd8111_driver = { + .name = "amd8111 smbus 2.0", + .id_table = amd8111_id_table, + .probe = amd8111_probe, + .remove = __devexit_p(amd8111_remove), +}; + +int __init amd8111_init(void) +{ + return pci_module_init(&amd8111_driver); +} + +void __exit amd8111_exit(void) +{ + pci_unregister_driver(&amd8111_driver); +} + +module_init(amd8111_init); +module_exit(amd8111_exit); diff --git a/drivers/i2c/busses/i2c-mainboard.c b/drivers/i2c/busses/i2c-mainboard.c new file mode 100644 index 000000000000..5c58598bd399 --- /dev/null +++ b/drivers/i2c/busses/i2c-mainboard.c @@ -0,0 +1,34 @@ +/* + i2c-mainboard.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Not configurable as a module */ + +#include + +extern int i2c_amd756_init(void); + +int __init i2c_mainboard_init_all(void) +{ +#ifdef CONFIG_I2C_AMD756 + i2c_amd756_init(); +#endif + + return 0; +} diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig new file mode 100644 index 000000000000..19ade539d2ac --- /dev/null +++ b/drivers/i2c/chips/Kconfig @@ -0,0 +1,54 @@ +# +# Sensor device configuration +# All depend on EXPERIMENTAL, I2C and I2C_PROC. +# + +menu "I2C Hardware Sensors Chip support" + +config SENSORS + bool "Hardware sensors chip support" + depends on EXPERIMENTAL && I2C && I2C_PROC + help + Many modern mainboards have some kind of I2C interface integrated. + This is often in the form of a SMBus, or System Management Bus, which + is basically the same as I2C but which uses only a subset of the I2C + protocol. + + You will also want the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config SENSORS_ADM1021 + tristate " Analog Devices ADM1021 and compatibles" + depends on SENSORS + help + If you say yes here you get support for Analog Devices ADM1021 + and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, + Genesys Logic GL523SM, National Semi LM84, TI THMC10, + and the XEON processor built-in sensor. This can also + be built as a module which can be inserted and removed while the + kernel is running. + + The module will be called adm1021.o. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config SENSORS_LM75 + tristate " National Semiconductors LM75 and compatibles" + depends on SENSORS + help + If you say yes here you get support for National Semiconductor LM75 + sensor chips and clones: Dallas Semi DS75 and DS1775, TelCon + TCN75, and National Semi LM77. This can also be built as a module + which can be inserted and removed while the kernel is running. + + The module will be called lm75.o. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +endmenu + diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile new file mode 100644 index 000000000000..0bb64d68a61e --- /dev/null +++ b/drivers/i2c/chips/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the kernel hardware sensors chip drivers. +# + +obj-$(CONFIG_SENSORS) += sensors.o +obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o +obj-$(CONFIG_SENSORS_LM75) += lm75.o diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c new file mode 100644 index 000000000000..54a76b9a0309 --- /dev/null +++ b/drivers/i2c/chips/adm1021.c @@ -0,0 +1,633 @@ +/* + adm1021.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard and + Philip Edelbrock + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b, + 0x4c, 0x4e, SENSORS_I2C_END +}; +static unsigned int normal_isa[] = { SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); + +/* adm1021 constants specified below */ + +/* The adm1021 registers */ +/* Read-only */ +#define ADM1021_REG_TEMP 0x00 +#define ADM1021_REG_REMOTE_TEMP 0x01 +#define ADM1021_REG_STATUS 0x02 +#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ +#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ +#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ +/* These use different addresses for reading/writing */ +#define ADM1021_REG_CONFIG_R 0x03 +#define ADM1021_REG_CONFIG_W 0x09 +#define ADM1021_REG_CONV_RATE_R 0x04 +#define ADM1021_REG_CONV_RATE_W 0x0A +/* These are for the ADM1023's additional precision on the remote temp sensor */ +#define ADM1021_REG_REM_TEMP_PREC 0x010 +#define ADM1021_REG_REM_OFFSET 0x011 +#define ADM1021_REG_REM_OFFSET_PREC 0x012 +#define ADM1021_REG_REM_TOS_PREC 0x013 +#define ADM1021_REG_REM_THYST_PREC 0x014 +/* limits */ +#define ADM1021_REG_TOS_R 0x05 +#define ADM1021_REG_TOS_W 0x0B +#define ADM1021_REG_REMOTE_TOS_R 0x07 +#define ADM1021_REG_REMOTE_TOS_W 0x0D +#define ADM1021_REG_THYST_R 0x06 +#define ADM1021_REG_THYST_W 0x0C +#define ADM1021_REG_REMOTE_THYST_R 0x08 +#define ADM1021_REG_REMOTE_THYST_W 0x0E +/* write-only */ +#define ADM1021_REG_ONESHOT 0x0F + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +/* Conversions note: 1021 uses normal integer signed-byte format*/ +#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) + +/* Initial values */ + +/* Note: Eventhough I left the low and high limits named os and hyst, +they don't quite work like a thermostat the way the LM75 does. I.e., +a lower temp than THYST actuall triggers an alarm instead of +clearing it. Weird, ey? --Phil */ +#define adm1021_INIT_TOS 60 +#define adm1021_INIT_THYST 20 +#define adm1021_INIT_REMOTE_TOS 60 +#define adm1021_INIT_REMOTE_THYST 20 + +/* Each client has this additional data */ +struct adm1021_data { + int sysctl_id; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 temp, temp_os, temp_hyst; /* Register values */ + u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms, die_code; + /* Special values for ADM1023 only */ + u8 remote_temp_prec, remote_temp_os_prec, remote_temp_hyst_prec, + remote_temp_offset, remote_temp_offset_prec; +}; + +int __init sensors_adm1021_init(void); +void __exit sensors_adm1021_exit(void); +static int adm1021_cleanup(void); + +static int adm1021_attach_adapter(struct i2c_adapter *adapter); +static int adm1021_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind); +static void adm1021_init_client(struct i2c_client *client); +static int adm1021_detach_client(struct i2c_client *client); +static int adm1021_command(struct i2c_client *client, unsigned int cmd, + void *arg); +static void adm1021_inc_use(struct i2c_client *client); +static void adm1021_dec_use(struct i2c_client *client); +static int adm1021_read_value(struct i2c_client *client, u8 reg); +static int adm1021_write_value(struct i2c_client *client, u8 reg, + u16 value); +static void adm1021_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1021_remote_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, + long *results); +static void adm1021_alarms(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1021_die_code(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1021_update_client(struct i2c_client *client); + +/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ +static int read_only = 0; + + +/* This is the driver that will be inserted */ +static struct i2c_driver adm1021_driver = { + /* name */ "ADM1021, MAX1617 sensor driver", + /* id */ I2C_DRIVERID_ADM1021, + /* flags */ I2C_DF_NOTIFY, + /* attach_adapter */ &adm1021_attach_adapter, + /* detach_client */ &adm1021_detach_client, + /* command */ &adm1021_command, + /* inc_use */ &adm1021_inc_use, + /* dec_use */ &adm1021_dec_use +}; + +/* These files are created for each detected adm1021. This is just a template; + though at first sight, you might think we could use a statically + allocated list, we need some way to get back to the parent - which + is done through one of the 'extra' fields which are initialized + when a new copy is allocated. */ +static ctl_table adm1021_dir_table_template[] = { + {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_temp}, + {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_remote_temp}, + {ADM1021_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_die_code}, + {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_alarms}, + {0} +}; + +static ctl_table adm1021_max_dir_table_template[] = { + {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_temp}, + {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_remote_temp}, + {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_alarms}, + {0} +}; + +/* Used by init/cleanup */ +static int __initdata adm1021_initialized = 0; + +/* I choose here for semi-static allocation. Complete dynamic + allocation could also be used; the code needed for this would probably + take more memory than the datastructure takes now. */ +static int adm1021_id = 0; + +int adm1021_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, adm1021_detect); +} + +static int adm1021_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + int i; + struct i2c_client *new_client; + struct adm1021_data *data; + int err = 0; + const char *type_name = ""; + const char *client_name = ""; + + /* Make sure we aren't probing the ISA bus!! This is just a safety check + at this moment; i2c_detect really won't call us. */ +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + printk + ("adm1021.o: adm1021_detect called for an ISA bus adapter?!?\n"); + return 0; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto error0; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access adm1021_{read,write}_value. */ + + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct adm1021_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto error0; + } + + data = (struct adm1021_data *) (new_client + 1); + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &adm1021_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + if (kind < 0) { + if ( + (adm1021_read_value(new_client, ADM1021_REG_STATUS) & + 0x03) != 0x00) + goto error1; + } + + /* Determine the chip type. */ + + if (kind <= 0) { + i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); + if (i == 0x41) + if ((adm1021_read_value (new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) + kind = adm1023; + else + kind = adm1021; + else if (i == 0x49) + kind = thmc10; + else if (i == 0x23) + kind = gl523sm; + else if ((i == 0x4d) && + (adm1021_read_value + (new_client, ADM1021_REG_DEV_ID) == 0x01)) + kind = max1617a; + /* LM84 Mfr ID in a different place */ + else + if (adm1021_read_value + (new_client, ADM1021_REG_CONV_RATE_R) == 0x00) + kind = lm84; + else if (i == 0x54) + kind = mc1066; + else + kind = max1617; + } + + if (kind == max1617) { + type_name = "max1617"; + client_name = "MAX1617 chip"; + } else if (kind == max1617a) { + type_name = "max1617a"; + client_name = "MAX1617A chip"; + } else if (kind == adm1021) { + type_name = "adm1021"; + client_name = "ADM1021 chip"; + } else if (kind == adm1023) { + type_name = "adm1023"; + client_name = "ADM1023 chip"; + } else if (kind == thmc10) { + type_name = "thmc10"; + client_name = "THMC10 chip"; + } else if (kind == lm84) { + type_name = "lm84"; + client_name = "LM84 chip"; + } else if (kind == gl523sm) { + type_name = "gl523sm"; + client_name = "GL523SM chip"; + } else if (kind == mc1066) { + type_name = "mc1066"; + client_name = "MC1066 chip"; + } else { +#ifdef DEBUG + printk("adm1021.o: Internal error: unknown kind (%d)?!?", + kind); +#endif + goto error1; + } + + /* Fill in the remaining client fields and put it into the global list */ + strcpy(new_client->name, client_name); + data->type = kind; + + new_client->id = adm1021_id++; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto error3; + + /* Register a new directory entry with module sensors */ + if ((i = i2c_register_entry(new_client, + type_name, + data->type == + adm1021 ? + adm1021_dir_table_template : + adm1021_max_dir_table_template, + THIS_MODULE)) < 0) { + err = i; + goto error4; + } + data->sysctl_id = i; + + /* Initialize the ADM1021 chip */ + adm1021_init_client(new_client); + return 0; + + error4: + i2c_detach_client(new_client); + error3: + error1: + kfree(new_client); + error0: + return err; +} + +void adm1021_init_client(struct i2c_client *client) +{ + /* Initialize the adm1021 chip */ + adm1021_write_value(client, ADM1021_REG_TOS_W, + TEMP_TO_REG(adm1021_INIT_TOS)); + adm1021_write_value(client, ADM1021_REG_THYST_W, + TEMP_TO_REG(adm1021_INIT_THYST)); + adm1021_write_value(client, ADM1021_REG_REMOTE_TOS_W, + TEMP_TO_REG(adm1021_INIT_REMOTE_TOS)); + adm1021_write_value(client, ADM1021_REG_REMOTE_THYST_W, + TEMP_TO_REG(adm1021_INIT_REMOTE_THYST)); + /* Enable ADC and disable suspend mode */ + adm1021_write_value(client, ADM1021_REG_CONFIG_W, 0); + /* Set Conversion rate to 1/sec (this can be tinkered with) */ + adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); +} + +int adm1021_detach_client(struct i2c_client *client) +{ + + int err; + + i2c_deregister_entry(((struct adm1021_data *) (client->data))-> + sysctl_id); + + if ((err = i2c_detach_client(client))) { + printk + ("adm1021.o: Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + + return 0; + +} + + +/* No commands defined yet */ +int adm1021_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + return 0; +} + +void adm1021_inc_use(struct i2c_client *client) +{ + MOD_INC_USE_COUNT; +} + +void adm1021_dec_use(struct i2c_client *client) +{ + MOD_DEC_USE_COUNT; +} + +/* All registers are byte-sized */ +int adm1021_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (read_only > 0) + return 0; + + return i2c_smbus_write_byte_data(client, reg, value); +} + +void adm1021_update_client(struct i2c_client *client) +{ + struct adm1021_data *data = client->data; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { + +#ifdef DEBUG + printk("Starting adm1021 update\n"); +#endif + + data->temp = adm1021_read_value(client, ADM1021_REG_TEMP); + data->temp_os = + adm1021_read_value(client, ADM1021_REG_TOS_R); + data->temp_hyst = + adm1021_read_value(client, ADM1021_REG_THYST_R); + data->remote_temp = + adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); + data->remote_temp_os = + adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); + data->remote_temp_hyst = + adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); + data->alarms = + adm1021_read_value(client, ADM1021_REG_STATUS) & 0xec; + if (data->type == adm1021) + data->die_code = + adm1021_read_value(client, + ADM1021_REG_DIE_CODE); + if (data->type == adm1023) { + data->remote_temp_prec = + adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); + data->remote_temp_os_prec = + adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); + data->remote_temp_hyst_prec = + adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); + data->remote_temp_offset = + adm1021_read_value(client, ADM1021_REG_REM_OFFSET); + data->remote_temp_offset_prec = + adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); +} + + +void adm1021_temp(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1021_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1021_update_client(client); + results[0] = TEMP_FROM_REG(data->temp_os); + results[1] = TEMP_FROM_REG(data->temp_hyst); + results[2] = TEMP_FROM_REG(data->temp); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->temp_os = TEMP_TO_REG(results[0]); + adm1021_write_value(client, ADM1021_REG_TOS_W, + data->temp_os); + } + if (*nrels_mag >= 2) { + data->temp_hyst = TEMP_TO_REG(results[1]); + adm1021_write_value(client, ADM1021_REG_THYST_W, + data->temp_hyst); + } + } +} + +void adm1021_remote_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ +int prec=0; + struct adm1021_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + if (data->type == adm1023) { *nrels_mag = 3; } + else { *nrels_mag = 0; } + else if (operation == SENSORS_PROC_REAL_READ) { + adm1021_update_client(client); + results[0] = TEMP_FROM_REG(data->remote_temp_os); + results[1] = TEMP_FROM_REG(data->remote_temp_hyst); + results[2] = TEMP_FROM_REG(data->remote_temp); + if (data->type == adm1023) { + results[0]=results[0]*1000 + + ((data->remote_temp_os_prec >> 5) * 125); + results[1]=results[1]*1000 + + ((data->remote_temp_hyst_prec >> 5) * 125); + results[2]=(TEMP_FROM_REG(data->remote_temp_offset)*1000) + + ((data->remote_temp_offset_prec >> 5) * 125); + results[3]=TEMP_FROM_REG(data->remote_temp)*1000 + + ((data->remote_temp_prec >> 5) * 125); + *nrels_mag = 4; + } else { + *nrels_mag = 3; + } + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + if (data->type == adm1023) { + prec=((results[0]-((results[0]/1000)*1000))/125)<<5; + adm1021_write_value(client, + ADM1021_REG_REM_TOS_PREC, + prec); + results[0]=results[0]/1000; + data->remote_temp_os_prec=prec; + } + data->remote_temp_os = TEMP_TO_REG(results[0]); + adm1021_write_value(client, + ADM1021_REG_REMOTE_TOS_W, + data->remote_temp_os); + } + if (*nrels_mag >= 2) { + if (data->type == adm1023) { + prec=((results[1]-((results[1]/1000)*1000))/125)<<5; + adm1021_write_value(client, + ADM1021_REG_REM_THYST_PREC, + prec); + results[1]=results[1]/1000; + data->remote_temp_hyst_prec=prec; + } + data->remote_temp_hyst = TEMP_TO_REG(results[1]); + adm1021_write_value(client, + ADM1021_REG_REMOTE_THYST_W, + data->remote_temp_hyst); + } + if (*nrels_mag >= 3) { + if (data->type == adm1023) { + prec=((results[2]-((results[2]/1000)*1000))/125)<<5; + adm1021_write_value(client, + ADM1021_REG_REM_OFFSET_PREC, + prec); + results[2]=results[2]/1000; + data->remote_temp_offset_prec=prec; + data->remote_temp_offset=results[2]; + adm1021_write_value(client, + ADM1021_REG_REM_OFFSET, + data->remote_temp_offset); + } + } + } +} + +void adm1021_die_code(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct adm1021_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1021_update_client(client); + results[0] = data->die_code; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + /* Can't write to it */ + } +} + +void adm1021_alarms(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1021_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1021_update_client(client); + results[0] = data->alarms; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + /* Can't write to it */ + } +} + +int __init sensors_adm1021_init(void) +{ + int res; + + printk("adm1021.o version %s (%s)\n", LM_VERSION, LM_DATE); + adm1021_initialized = 0; + if ((res = i2c_add_driver(&adm1021_driver))) { + printk + ("adm1021.o: Driver registration failed, module not inserted.\n"); + adm1021_cleanup(); + return res; + } + adm1021_initialized++; + return 0; +} + +void __exit sensors_adm1021_exit(void) +{ + adm1021_cleanup(); +} + +static int adm1021_cleanup(void) +{ + int res; + + if (adm1021_initialized >= 1) { + if ((res = i2c_del_driver(&adm1021_driver))) { + printk + ("adm1021.o: Driver deregistration failed, module not removed.\n"); + return res; + } + adm1021_initialized--; + } + + return 0; +} + +MODULE_AUTHOR + ("Frodo Looijaard and Philip Edelbrock "); +MODULE_DESCRIPTION("adm1021 driver"); + +MODULE_PARM(read_only, "i"); +MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); + +module_init(sensors_adm1021_init) +module_exit(sensors_adm1021_exit) diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c new file mode 100644 index 000000000000..f7a516b82703 --- /dev/null +++ b/drivers/i2c/chips/lm75.c @@ -0,0 +1,403 @@ +/* + lm75.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; +static unsigned int normal_isa[] = { SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm75); + +/* Many LM75 constants specified below */ + +/* The LM75 registers */ +#define LM75_REG_TEMP 0x00 +#define LM75_REG_CONF 0x01 +#define LM75_REG_TEMP_HYST 0x02 +#define LM75_REG_TEMP_OS 0x03 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define TEMP_FROM_REG(val) ((((val & 0x7fff) >> 7) * 5) | ((val & 0x8000)?-256:0)) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val<0?(0x200+((val)/5))<<7:(((val) + 2) / 5) << 7),0,0xffff)) + +/* Initial values */ +#define LM75_INIT_TEMP_OS 600 +#define LM75_INIT_TEMP_HYST 500 + +/* Each client has this additional data */ +struct lm75_data { + int sysctl_id; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u16 temp, temp_os, temp_hyst; /* Register values */ +}; + +int __init sensors_lm75_init(void); +void __exit sensors_lm75_exit(void); +static int lm75_cleanup(void); + +static int lm75_attach_adapter(struct i2c_adapter *adapter); +static int lm75_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind); +static void lm75_init_client(struct i2c_client *client); +static int lm75_detach_client(struct i2c_client *client); +static int lm75_command(struct i2c_client *client, unsigned int cmd, + void *arg); +static void lm75_inc_use(struct i2c_client *client); +static void lm75_dec_use(struct i2c_client *client); +static u16 swap_bytes(u16 val); +static int lm75_read_value(struct i2c_client *client, u8 reg); +static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); +static void lm75_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm75_update_client(struct i2c_client *client); + + +/* This is the driver that will be inserted */ +static struct i2c_driver lm75_driver = { + /* name */ "LM75 sensor chip driver", + /* id */ I2C_DRIVERID_LM75, + /* flags */ I2C_DF_NOTIFY, + /* attach_adapter */ &lm75_attach_adapter, + /* detach_client */ &lm75_detach_client, + /* command */ &lm75_command, + /* inc_use */ &lm75_inc_use, + /* dec_use */ &lm75_dec_use +}; + +/* These files are created for each detected LM75. This is just a template; + though at first sight, you might think we could use a statically + allocated list, we need some way to get back to the parent - which + is done through one of the 'extra' fields which are initialized + when a new copy is allocated. */ +static ctl_table lm75_dir_table_template[] = { + {LM75_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm75_temp}, + {0} +}; + +/* Used by init/cleanup */ +static int __initdata lm75_initialized = 0; + +static int lm75_id = 0; + +int lm75_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, lm75_detect); +} + +/* This function is called by i2c_detect */ +int lm75_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + int i, cur, conf, hyst, os; + struct i2c_client *new_client; + struct lm75_data *data; + int err = 0; + const char *type_name, *client_name; + + /* Make sure we aren't probing the ISA bus!! This is just a safety check + at this moment; i2c_detect really won't call us. */ +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + printk + ("lm75.o: lm75_detect called for an ISA bus adapter?!?\n"); + return 0; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto error0; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm75_{read,write}_value. */ + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct lm75_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto error0; + } + + data = (struct lm75_data *) (new_client + 1); + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &lm75_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. It is lousy. */ + if (kind < 0) { + cur = i2c_smbus_read_word_data(new_client, 0); + conf = i2c_smbus_read_byte_data(new_client, 1); + hyst = i2c_smbus_read_word_data(new_client, 2); + os = i2c_smbus_read_word_data(new_client, 3); + for (i = 0; i <= 0x1f; i++) + if ( + (i2c_smbus_read_byte_data + (new_client, i * 8 + 1) != conf) + || + (i2c_smbus_read_word_data + (new_client, i * 8 + 2) != hyst) + || + (i2c_smbus_read_word_data + (new_client, i * 8 + 3) != os)) + goto error1; + } + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = lm75; + + if (kind == lm75) { + type_name = "lm75"; + client_name = "LM75 chip"; + } else { +#ifdef DEBUG + printk("lm75.o: Internal error: unknown kind (%d)?!?", + kind); +#endif + goto error1; + } + + /* Fill in the remaining client fields and put it into the global list */ + strcpy(new_client->name, client_name); + + new_client->id = lm75_id++; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto error3; + + /* Register a new directory entry with module sensors */ + if ((i = i2c_register_entry(new_client, type_name, + lm75_dir_table_template, + THIS_MODULE)) < 0) { + err = i; + goto error4; + } + data->sysctl_id = i; + + lm75_init_client(new_client); + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + + error4: + i2c_detach_client(new_client); + error3: + error1: + kfree(new_client); + error0: + return err; +} + +int lm75_detach_client(struct i2c_client *client) +{ + int err; + +#ifdef MODULE + if (MOD_IN_USE) + return -EBUSY; +#endif + + i2c_deregister_entry(((struct lm75_data *) (client->data))-> + sysctl_id); + + if ((err = i2c_detach_client(client))) { + printk + ("lm75.o: Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + + return 0; +} + +int lm75_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + return 0; +} + +void lm75_inc_use(struct i2c_client *client) +{ + MOD_INC_USE_COUNT; +} + +void lm75_dec_use(struct i2c_client *client) +{ + MOD_DEC_USE_COUNT; +} + +u16 swap_bytes(u16 val) +{ + return (val >> 8) | (val << 8); +} + +/* All registers are word-sized, except for the configuration register. + LM75 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +int lm75_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == LM75_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return swap_bytes(i2c_smbus_read_word_data(client, reg)); +} + +/* All registers are word-sized, except for the configuration register. + LM75 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == LM75_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_data(client, reg, + swap_bytes(value)); +} + +void lm75_init_client(struct i2c_client *client) +{ + /* Initialize the LM75 chip */ + lm75_write_value(client, LM75_REG_TEMP_OS, + TEMP_TO_REG(LM75_INIT_TEMP_OS)); + lm75_write_value(client, LM75_REG_TEMP_HYST, + TEMP_TO_REG(LM75_INIT_TEMP_HYST)); + lm75_write_value(client, LM75_REG_CONF, 0); +} + +void lm75_update_client(struct i2c_client *client) +{ + struct lm75_data *data = client->data; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { + +#ifdef DEBUG + printk("Starting lm75 update\n"); +#endif + + data->temp = lm75_read_value(client, LM75_REG_TEMP); + data->temp_os = lm75_read_value(client, LM75_REG_TEMP_OS); + data->temp_hyst = + lm75_read_value(client, LM75_REG_TEMP_HYST); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); +} + + +void lm75_temp(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm75_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + lm75_update_client(client); + results[0] = TEMP_FROM_REG(data->temp_os); + results[1] = TEMP_FROM_REG(data->temp_hyst); + results[2] = TEMP_FROM_REG(data->temp); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->temp_os = TEMP_TO_REG(results[0]); + lm75_write_value(client, LM75_REG_TEMP_OS, + data->temp_os); + } + if (*nrels_mag >= 2) { + data->temp_hyst = TEMP_TO_REG(results[1]); + lm75_write_value(client, LM75_REG_TEMP_HYST, + data->temp_hyst); + } + } +} + +int __init sensors_lm75_init(void) +{ + int res; + + printk("lm75.o version %s (%s)\n", LM_VERSION, LM_DATE); + lm75_initialized = 0; + if ((res = i2c_add_driver(&lm75_driver))) { + printk + ("lm75.o: Driver registration failed, module not inserted.\n"); + lm75_cleanup(); + return res; + } + lm75_initialized++; + return 0; +} + +void __exit sensors_lm75_exit(void) +{ + lm75_cleanup(); +} + +static int lm75_cleanup(void) +{ + int res; + + if (lm75_initialized >= 1) { + if ((res = i2c_del_driver(&lm75_driver))) { + printk + ("lm75.o: Driver deregistration failed, module not removed.\n"); + return res; + } + lm75_initialized--; + } + + return 0; +} + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("LM75 driver"); + +module_init(sensors_lm75_init); +module_exit(sensors_lm75_exit); diff --git a/drivers/i2c/chips/sensors.c b/drivers/i2c/chips/sensors.c new file mode 100644 index 000000000000..0733c474753b --- /dev/null +++ b/drivers/i2c/chips/sensors.c @@ -0,0 +1,37 @@ +/* + sensors.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Not configurable as a module */ + +#include + +extern int sensors_adm1021_init(void); +extern int sensors_lm75_init(void); + +int __init sensors_init_all(void) +{ +#ifdef CONFIG_SENSORS_ADM1021 + sensors_adm1021_init(); +#endif +#ifdef CONFIG_SENSORS_LM75 + sensors_lm75_init(); +#endif + return 0; +} diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 0716d42479f7..01af09b5120f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -21,7 +21,7 @@ All SMBus-related things are written by Frodo Looijaard SMBus 2.0 support by Mark Studebaker */ -/* $Id: i2c-core.c,v 1.86 2002/09/12 06:47:26 ac9410 Exp $ */ +/* $Id: i2c-core.c,v 1.89 2002/11/03 16:47:16 mds Exp $ */ #include #include @@ -77,7 +77,8 @@ static int i2c_debug; #ifdef CONFIG_PROC_FS -static int i2cproc_init(void); +int __init i2cproc_init(void); +void __exit i2cproc_exit(void); static int i2cproc_cleanup(void); static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, @@ -1332,15 +1333,15 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, if (read_write == I2C_SMBUS_READ) { msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; } else { - msg[0].len = data->block[0] + 2; - if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 2) { + msg[0].len = data->block[0] + 1; + if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) { printk("i2c-core.o: i2c_smbus_xfer_emulated called with " "invalid block write size (%d)\n", data->block[0]); return -1; } - for (i = 0; i < data->block[0]; i++) - msgbuf0[i] = data->block[i+1]; + for (i = 1; i <= data->block[0]; i++) + msgbuf0[i] = data->block[i]; } break; default: @@ -1456,7 +1457,7 @@ static int __init i2c_init(void) return 0; } -static void __exit i2c_exit(void) +void __exit i2c_exit(void) { i2cproc_cleanup(); } diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 73c20b3069be..a2c539a5d269 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -28,7 +28,7 @@ /* The devfs code is contributed by Philipp Matthias Hahn */ -/* $Id: i2c-dev.c,v 1.46 2002/07/06 02:07:39 mds Exp $ */ +/* $Id: i2c-dev.c,v 1.48 2002/10/01 14:10:04 ac9410 Exp $ */ #include #include @@ -48,6 +48,10 @@ #include #include +int __init i2c_dev_init(void); +void __exit i2c_dev_exit(void); +static int dev_cleanup(void); + /* struct file_operations changed too often in the 2.1 series for nice code */ static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, @@ -433,7 +437,7 @@ static int i2cdev_command(struct i2c_client *client, unsigned int cmd, return -1; } -static void i2cdev_cleanup(void) +static int dev_cleanup(void) { int res; @@ -467,6 +471,11 @@ int __init i2c_dev_init(void) return 0; } +void __exit i2c_dev_exit(void) +{ + dev_cleanup(); +} + EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Frodo Looijaard and Simon G. Vogl "); @@ -474,4 +483,4 @@ MODULE_DESCRIPTION("I2C /dev entries driver"); MODULE_LICENSE("GPL"); module_init(i2c_dev_init); -module_exit(i2cdev_cleanup); +module_exit(i2c_dev_exit); diff --git a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c index 6c6d4903a023..2f26eab8d882 100644 --- a/drivers/i2c/i2c-proc.c +++ b/drivers/i2c/i2c-proc.c @@ -40,6 +40,10 @@ #define THIS_MODULE NULL #endif +int __init sensors_init(void); +void __exit i2c_proc_exit(void); +static int proc_cleanup(void); + static int i2c_create_name(char **name, const char *prefix, struct i2c_adapter *adapter, int addr); static int i2c_parse_reals(int *nrels, void *buffer, int bufsize, @@ -56,6 +60,7 @@ static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, #define SENSORS_ENTRY_MAX 20 static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX]; +static unsigned short i2c_inodes[SENSORS_ENTRY_MAX]; static struct i2c_client *i2c_clients[SENSORS_ENTRY_MAX]; @@ -186,6 +191,8 @@ int i2c_register_entry(struct i2c_client *client, const char *prefix, return id; } #endif /* DEBUG */ + i2c_inodes[id - 256] = + new_header->ctl_table->child->child->de->low_ino; new_header->ctl_table->child->child->de->owner = controlling_mod; return id; @@ -208,6 +215,49 @@ void i2c_deregister_entry(int id) } } +/* Monitor access for /proc/sys/dev/sensors; make unloading i2c-proc.o + impossible if some process still uses it or some file in it */ +void i2c_fill_inode(struct inode *inode, int fill) +{ + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +/* Monitor access for /proc/sys/dev/sensors/ directories; make unloading + the corresponding module impossible if some process still uses it or + some file in it */ +void i2c_dir_fill_inode(struct inode *inode, int fill) +{ + int i; + struct i2c_client *client; + +#ifdef DEBUG + if (!inode) { + printk(KERN_ERR "i2c-proc.o: Warning: inode NULL in fill_inode()\n"); + return; + } +#endif /* def DEBUG */ + + for (i = 0; i < SENSORS_ENTRY_MAX; i++) + if (i2c_clients[i] + && (i2c_inodes[i] == inode->i_ino)) break; +#ifdef DEBUG + if (i == SENSORS_ENTRY_MAX) { + printk + (KERN_ERR "i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n", + inode->i_ino); + return; + } +#endif /* def DEBUG */ + client = i2c_clients[i]; + if (fill) + client->driver->inc_use(client); + else + client->driver->dec_use(client); +} + int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp, void *buffer, size_t * lenp) { @@ -813,12 +863,18 @@ int __init sensors_init(void) return 0; } -static void __exit i2c_cleanup(void) +void __exit i2c_proc_exit(void) +{ + proc_cleanup(); +} + +static int proc_cleanup(void) { if (i2c_initialized >= 1) { unregister_sysctl_table(i2c_proc_header); i2c_initialized--; } + return 0; } EXPORT_SYMBOL(i2c_deregister_entry); @@ -832,4 +888,4 @@ MODULE_DESCRIPTION("i2c-proc driver"); MODULE_LICENSE("GPL"); module_init(sensors_init); -module_exit(i2c_cleanup); +module_exit(i2c_proc_exit); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 8a52e78b89f0..2b6394004ea1 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -233,6 +233,7 @@ #define I2C_HW_SMBUS_ALI1535 0x07 #define I2C_HW_SMBUS_SIS630 0x08 #define I2C_HW_SMBUS_SIS645 0x09 +#define I2C_HW_SMBUS_AMD8111 0x0a /* --- ISA pseudo-adapter */ #define I2C_HW_ISA 0x00 diff --git a/include/linux/i2c-proc.h b/include/linux/i2c-proc.h index 4a4c33db48d5..ccdd2a95b1d1 100644 --- a/include/linux/i2c-proc.h +++ b/include/linux/i2c-proc.h @@ -348,6 +348,31 @@ struct i2c_address_data { {NULL}}; \ SENSORS_INSMOD +#define SENSORS_INSMOD_8(chip1,chip2,chip3,chip4,chip5,chip6,chip7,chip8) \ + enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8 }; \ + SENSORS_MODULE_PARM(force, \ + "List of adapter,address pairs to boldly assume " \ + "to be present"); \ + SENSORS_MODULE_PARM_FORCE(chip1); \ + SENSORS_MODULE_PARM_FORCE(chip2); \ + SENSORS_MODULE_PARM_FORCE(chip3); \ + SENSORS_MODULE_PARM_FORCE(chip4); \ + SENSORS_MODULE_PARM_FORCE(chip5); \ + SENSORS_MODULE_PARM_FORCE(chip6); \ + SENSORS_MODULE_PARM_FORCE(chip7); \ + SENSORS_MODULE_PARM_FORCE(chip8); \ + static struct i2c_force_data forces[] = {{force,any_chip}, \ + {force_ ## chip1,chip1}, \ + {force_ ## chip2,chip2}, \ + {force_ ## chip3,chip3}, \ + {force_ ## chip4,chip4}, \ + {force_ ## chip5,chip5}, \ + {force_ ## chip6,chip6}, \ + {force_ ## chip7,chip7}, \ + {force_ ## chip8,chip8}, \ + {NULL}}; \ + SENSORS_INSMOD + typedef int i2c_found_addr_proc(struct i2c_adapter *adapter, int addr, unsigned short flags, int kind); diff --git a/include/linux/sensors.h b/include/linux/sensors.h new file mode 100644 index 000000000000..31998faab1e6 --- /dev/null +++ b/include/linux/sensors.h @@ -0,0 +1,690 @@ +/* + sensors.h - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef SENSORS_NSENSORS_H +#define SENSORS_NSENSORS_H + +#define LM_DATE "20020915" +#define LM_VERSION "2.6.5" + +#include + +#define LM78_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM78_SYSCTL_IN1 1001 +#define LM78_SYSCTL_IN2 1002 +#define LM78_SYSCTL_IN3 1003 +#define LM78_SYSCTL_IN4 1004 +#define LM78_SYSCTL_IN5 1005 +#define LM78_SYSCTL_IN6 1006 +#define LM78_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM78_SYSCTL_FAN2 1102 +#define LM78_SYSCTL_FAN3 1103 +#define LM78_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define LM78_SYSCTL_VID 1300 /* Volts * 100 */ +#define LM78_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM78_SYSCTL_ALARMS 2001 /* bitvector */ + +#define LM78_ALARM_IN0 0x0001 +#define LM78_ALARM_IN1 0x0002 +#define LM78_ALARM_IN2 0x0004 +#define LM78_ALARM_IN3 0x0008 +#define LM78_ALARM_IN4 0x0100 +#define LM78_ALARM_IN5 0x0200 +#define LM78_ALARM_IN6 0x0400 +#define LM78_ALARM_FAN1 0x0040 +#define LM78_ALARM_FAN2 0x0080 +#define LM78_ALARM_FAN3 0x0800 +#define LM78_ALARM_TEMP 0x0010 +#define LM78_ALARM_BTI 0x0020 +#define LM78_ALARM_CHAS 0x1000 +#define LM78_ALARM_FIFO 0x2000 +#define LM78_ALARM_SMI_IN 0x4000 + +#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ +#define W83781D_SYSCTL_IN1 1001 +#define W83781D_SYSCTL_IN2 1002 +#define W83781D_SYSCTL_IN3 1003 +#define W83781D_SYSCTL_IN4 1004 +#define W83781D_SYSCTL_IN5 1005 +#define W83781D_SYSCTL_IN6 1006 +#define W83781D_SYSCTL_IN7 1007 +#define W83781D_SYSCTL_IN8 1008 +#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ +#define W83781D_SYSCTL_FAN2 1102 +#define W83781D_SYSCTL_FAN3 1103 +#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ +#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ +#define W83781D_SYSCTL_VRM 1301 +#define W83781D_SYSCTL_PWM1 1401 +#define W83781D_SYSCTL_PWM2 1402 +#define W83781D_SYSCTL_PWM3 1403 +#define W83781D_SYSCTL_PWM4 1404 +#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define W83781D_SYSCTL_SENS2 1502 +#define W83781D_SYSCTL_SENS3 1503 +#define W83781D_SYSCTL_RT1 1601 /* 32-entry table */ +#define W83781D_SYSCTL_RT2 1602 /* 32-entry table */ +#define W83781D_SYSCTL_RT3 1603 /* 32-entry table */ +#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ +#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ + +#define W83781D_ALARM_IN0 0x0001 +#define W83781D_ALARM_IN1 0x0002 +#define W83781D_ALARM_IN2 0x0004 +#define W83781D_ALARM_IN3 0x0008 +#define W83781D_ALARM_IN4 0x0100 +#define W83781D_ALARM_IN5 0x0200 +#define W83781D_ALARM_IN6 0x0400 +#define W83782D_ALARM_IN7 0x10000 +#define W83782D_ALARM_IN8 0x20000 +#define W83781D_ALARM_FAN1 0x0040 +#define W83781D_ALARM_FAN2 0x0080 +#define W83781D_ALARM_FAN3 0x0800 +#define W83781D_ALARM_TEMP1 0x0010 +#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ +#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S */ +#define W83781D_ALARM_TEMP3 0x2000 /* 782D only */ +#define W83781D_ALARM_CHAS 0x1000 + +#define LM75_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ + +#define ADM1021_SYSCTL_TEMP 1200 +#define ADM1021_SYSCTL_REMOTE_TEMP 1201 +#define ADM1021_SYSCTL_DIE_CODE 1202 +#define ADM1021_SYSCTL_ALARMS 1203 + +#define ADM1021_ALARM_TEMP_HIGH 0x40 +#define ADM1021_ALARM_TEMP_LOW 0x20 +#define ADM1021_ALARM_RTEMP_HIGH 0x10 +#define ADM1021_ALARM_RTEMP_LOW 0x08 +#define ADM1021_ALARM_RTEMP_NA 0x04 + +#define GL518_SYSCTL_VDD 1000 /* Volts * 100 */ +#define GL518_SYSCTL_VIN1 1001 +#define GL518_SYSCTL_VIN2 1002 +#define GL518_SYSCTL_VIN3 1003 +#define GL518_SYSCTL_FAN1 1101 /* RPM */ +#define GL518_SYSCTL_FAN2 1102 +#define GL518_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define GL518_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define GL518_SYSCTL_ALARMS 2001 /* bitvector */ +#define GL518_SYSCTL_BEEP 2002 /* bitvector */ +#define GL518_SYSCTL_FAN1OFF 2003 +#define GL518_SYSCTL_ITERATE 2004 + +#define GL518_ALARM_VDD 0x01 +#define GL518_ALARM_VIN1 0x02 +#define GL518_ALARM_VIN2 0x04 +#define GL518_ALARM_VIN3 0x08 +#define GL518_ALARM_TEMP 0x10 +#define GL518_ALARM_FAN1 0x20 +#define GL518_ALARM_FAN2 0x40 + +#define GL520_SYSCTL_VDD 1000 /* Volts * 100 */ +#define GL520_SYSCTL_VIN1 1001 +#define GL520_SYSCTL_VIN2 1002 +#define GL520_SYSCTL_VIN3 1003 +#define GL520_SYSCTL_VIN4 1004 +#define GL520_SYSCTL_FAN1 1101 /* RPM */ +#define GL520_SYSCTL_FAN2 1102 +#define GL520_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define GL520_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define GL520_SYSCTL_VID 1300 +#define GL520_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define GL520_SYSCTL_ALARMS 2001 /* bitvector */ +#define GL520_SYSCTL_BEEP 2002 /* bitvector */ +#define GL520_SYSCTL_FAN1OFF 2003 +#define GL520_SYSCTL_CONFIG 2004 + +#define GL520_ALARM_VDD 0x01 +#define GL520_ALARM_VIN1 0x02 +#define GL520_ALARM_VIN2 0x04 +#define GL520_ALARM_VIN3 0x08 +#define GL520_ALARM_TEMP1 0x10 +#define GL520_ALARM_FAN1 0x20 +#define GL520_ALARM_FAN2 0x40 +#define GL520_ALARM_TEMP2 0x80 +#define GL520_ALARM_VIN4 0x80 + +#define EEPROM_SYSCTL1 1000 +#define EEPROM_SYSCTL2 1001 +#define EEPROM_SYSCTL3 1002 +#define EEPROM_SYSCTL4 1003 +#define EEPROM_SYSCTL5 1004 +#define EEPROM_SYSCTL6 1005 +#define EEPROM_SYSCTL7 1006 +#define EEPROM_SYSCTL8 1007 +#define EEPROM_SYSCTL9 1008 +#define EEPROM_SYSCTL10 1009 +#define EEPROM_SYSCTL11 1010 +#define EEPROM_SYSCTL12 1011 +#define EEPROM_SYSCTL13 1012 +#define EEPROM_SYSCTL14 1013 +#define EEPROM_SYSCTL15 1014 +#define EEPROM_SYSCTL16 1015 + +#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM80_SYSCTL_IN1 1001 +#define LM80_SYSCTL_IN2 1002 +#define LM80_SYSCTL_IN3 1003 +#define LM80_SYSCTL_IN4 1004 +#define LM80_SYSCTL_IN5 1005 +#define LM80_SYSCTL_IN6 1006 +#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM80_SYSCTL_FAN2 1102 +#define LM80_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ + +#define ADM9240_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM9240_SYSCTL_IN1 1001 +#define ADM9240_SYSCTL_IN2 1002 +#define ADM9240_SYSCTL_IN3 1003 +#define ADM9240_SYSCTL_IN4 1004 +#define ADM9240_SYSCTL_IN5 1005 +#define ADM9240_SYSCTL_FAN1 1101 /* Rotations/min */ +#define ADM9240_SYSCTL_FAN2 1102 +#define ADM9240_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define ADM9240_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define ADM9240_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM9240_SYSCTL_ANALOG_OUT 2002 +#define ADM9240_SYSCTL_VID 2003 + +#define ADM9240_ALARM_IN0 0x0001 +#define ADM9240_ALARM_IN1 0x0002 +#define ADM9240_ALARM_IN2 0x0004 +#define ADM9240_ALARM_IN3 0x0008 +#define ADM9240_ALARM_IN4 0x0100 +#define ADM9240_ALARM_IN5 0x0200 +#define ADM9240_ALARM_FAN1 0x0040 +#define ADM9240_ALARM_FAN2 0x0080 +#define ADM9240_ALARM_TEMP 0x0010 +#define ADM9240_ALARM_CHAS 0x1000 + +#define ADM1024_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM1024_SYSCTL_IN1 1001 +#define ADM1024_SYSCTL_IN2 1002 +#define ADM1024_SYSCTL_IN3 1003 +#define ADM1024_SYSCTL_IN4 1004 +#define ADM1024_SYSCTL_IN5 1005 +#define ADM1024_SYSCTL_FAN1 1101 /* Rotations/min */ +#define ADM1024_SYSCTL_FAN2 1102 +#define ADM1024_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define ADM1024_SYSCTL_TEMP1 1290 /* Degrees Celcius */ +#define ADM1024_SYSCTL_TEMP2 1295 /* Degrees Celcius */ +#define ADM1024_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define ADM1024_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM1024_SYSCTL_ANALOG_OUT 2002 +#define ADM1024_SYSCTL_VID 2003 + +#define ADM1024_ALARM_IN0 0x0001 +#define ADM1024_ALARM_IN1 0x0002 +#define ADM1024_ALARM_IN2 0x0004 +#define ADM1024_ALARM_IN3 0x0008 +#define ADM1024_ALARM_IN4 0x0100 +#define ADM1024_ALARM_IN5 0x0200 +#define ADM1024_ALARM_FAN1 0x0040 +#define ADM1024_ALARM_FAN2 0x0080 +#define ADM1024_ALARM_TEMP 0x0010 +#define ADM1024_ALARM_TEMP1 0x0020 +#define ADM1024_ALARM_TEMP2 0x0001 +#define ADM1024_ALARM_CHAS 0x1000 + +#define ADM1025_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM1025_SYSCTL_IN1 1001 +#define ADM1025_SYSCTL_IN2 1002 +#define ADM1025_SYSCTL_IN3 1003 +#define ADM1025_SYSCTL_IN4 1004 +#define ADM1025_SYSCTL_IN5 1005 +#define ADM1025_SYSCTL_RTEMP 1251 +#define ADM1025_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define ADM1025_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM1025_SYSCTL_ANALOG_OUT 2002 +#define ADM1025_SYSCTL_VID 2003 +#define ADM1025_SYSCTL_VRM 2004 + +#define ADM1025_ALARM_IN0 0x0001 +#define ADM1025_ALARM_IN1 0x0002 +#define ADM1025_ALARM_IN2 0x0004 +#define ADM1025_ALARM_IN3 0x0008 +#define ADM1025_ALARM_IN4 0x0100 +#define ADM1025_ALARM_IN5 0x0200 +#define ADM1025_ALARM_RTEMP 0x0020 +#define ADM1025_ALARM_TEMP 0x0010 + +#define LTC1710_SYSCTL_SWITCH_1 1000 +#define LTC1710_SYSCTL_SWITCH_2 1001 + +#define LM80_ALARM_IN0 0x0001 +#define LM80_ALARM_IN1 0x0002 +#define LM80_ALARM_IN2 0x0004 +#define LM80_ALARM_IN3 0x0008 +#define LM80_ALARM_IN4 0x0010 +#define LM80_ALARM_IN5 0x0020 +#define LM80_ALARM_IN6 0x0040 +#define LM80_ALARM_FAN1 0x0400 +#define LM80_ALARM_FAN2 0x0800 +#define LM80_ALARM_TEMP_HOT 0x0100 +#define LM80_ALARM_TEMP_OS 0x2000 +#define LM80_ALARM_CHAS 0x1000 +#define LM80_ALARM_BTI 0x0200 +#define LM80_ALARM_INT_IN 0x0080 + +#define MAXI_SYSCTL_FAN1 1101 /* Rotations/min */ +#define MAXI_SYSCTL_FAN2 1102 /* Rotations/min */ +#define MAXI_SYSCTL_FAN3 1103 /* Rotations/min */ +#define MAXI_SYSCTL_FAN4 1104 /* Rotations/min */ +#define MAXI_SYSCTL_TEMP1 1201 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP2 1202 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP3 1203 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP4 1204 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP5 1205 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP6 1206 /* Degrees Celcius */ +#define MAXI_SYSCTL_PLL 1301 /* MHz */ +#define MAXI_SYSCTL_VID1 1401 /* Volts / 6.337, for nba just Volts */ +#define MAXI_SYSCTL_VID2 1402 /* Volts */ +#define MAXI_SYSCTL_VID3 1403 /* Volts */ +#define MAXI_SYSCTL_VID4 1404 /* Volts */ +#define MAXI_SYSCTL_VID5 1405 /* Volts */ +#define MAXI_SYSCTL_LCD1 1501 /* Line 1 of LCD */ +#define MAXI_SYSCTL_LCD2 1502 /* Line 2 of LCD */ +#define MAXI_SYSCTL_LCD3 1503 /* Line 3 of LCD */ +#define MAXI_SYSCTL_LCD4 1504 /* Line 4 of LCD */ +#define MAXI_SYSCTL_ALARMS 2001 /* Bitvector (see below) */ + +#define MAXI_ALARM_VID4 0x0001 +#define MAXI_ALARM_TEMP2 0x0002 +#define MAXI_ALARM_VID1 0x0004 +#define MAXI_ALARM_VID2 0x0008 +#define MAXI_ALARM_VID3 0x0010 +#define MAXI_ALARM_PLL 0x0080 +#define MAXI_ALARM_TEMP4 0x0100 +#define MAXI_ALARM_TEMP5 0x0200 +#define MAXI_ALARM_FAN1 0x1000 +#define MAXI_ALARM_FAN2 0x2000 +#define MAXI_ALARM_FAN3 0x4000 + +#define MAXI_ALARM_FAN 0x0100 /* To be used with MaxiLife'99 */ +#define MAXI_ALARM_VID 0x0200 /* The MSB specifies which sensor */ +#define MAXI_ALARM_TEMP 0x0400 /* in the alarm group failed, i.e.: */ +#define MAXI_ALARM_VADD 0x0800 /* 0x0402 = TEMP2 failed = CPU2 temp */ + +#define SIS5595_SYSCTL_IN0 1000 /* Volts * 100 */ +#define SIS5595_SYSCTL_IN1 1001 +#define SIS5595_SYSCTL_IN2 1002 +#define SIS5595_SYSCTL_IN3 1003 +#define SIS5595_SYSCTL_IN4 1004 +#define SIS5595_SYSCTL_FAN1 1101 /* Rotations/min */ +#define SIS5595_SYSCTL_FAN2 1102 +#define SIS5595_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define SIS5595_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define SIS5595_SYSCTL_ALARMS 2001 /* bitvector */ + +#define SIS5595_ALARM_IN0 0x01 +#define SIS5595_ALARM_IN1 0x02 +#define SIS5595_ALARM_IN2 0x04 +#define SIS5595_ALARM_IN3 0x08 +#define SIS5595_ALARM_BTI 0x20 +#define SIS5595_ALARM_FAN1 0x40 +#define SIS5595_ALARM_FAN2 0x80 +#define SIS5595_ALARM_IN4 0x8000 +#define SIS5595_ALARM_TEMP 0x8000 + +#define VIA686A_SYSCTL_IN0 1000 +#define VIA686A_SYSCTL_IN1 1001 +#define VIA686A_SYSCTL_IN2 1002 +#define VIA686A_SYSCTL_IN3 1003 +#define VIA686A_SYSCTL_IN4 1004 +#define VIA686A_SYSCTL_FAN1 1101 +#define VIA686A_SYSCTL_FAN2 1102 +#define VIA686A_SYSCTL_TEMP 1200 +#define VIA686A_SYSCTL_TEMP2 1201 +#define VIA686A_SYSCTL_TEMP3 1202 +#define VIA686A_SYSCTL_FAN_DIV 2000 +#define VIA686A_SYSCTL_ALARMS 2001 + +#define VIA686A_ALARM_IN0 0x01 +#define VIA686A_ALARM_IN1 0x02 +#define VIA686A_ALARM_IN2 0x04 +#define VIA686A_ALARM_IN3 0x08 +#define VIA686A_ALARM_TEMP 0x10 +#define VIA686A_ALARM_FAN1 0x40 +#define VIA686A_ALARM_FAN2 0x80 +#define VIA686A_ALARM_IN4 0x100 +#define VIA686A_ALARM_TEMP2 0x800 +#define VIA686A_ALARM_CHAS 0x1000 +#define VIA686A_ALARM_TEMP3 0x8000 + +#define ICSPLL_SYSCTL1 1000 + +#define BT869_SYSCTL_STATUS 1000 +#define BT869_SYSCTL_NTSC 1001 +#define BT869_SYSCTL_HALF 1002 +#define BT869_SYSCTL_RES 1003 +#define BT869_SYSCTL_COLORBARS 1004 +#define BT869_SYSCTL_DEPTH 1005 +#define BT869_SYSCTL_SVIDEO 1006 + +#define MATORB_SYSCTL_DISP 1000 + +#define THMC50_SYSCTL_TEMP 1200 /* Degrees Celcius */ +#define THMC50_SYSCTL_REMOTE_TEMP 1201 /* Degrees Celcius */ +#define THMC50_SYSCTL_INTER 1202 +#define THMC50_SYSCTL_INTER_MASK 1203 +#define THMC50_SYSCTL_DIE_CODE 1204 +#define THMC50_SYSCTL_ANALOG_OUT 1205 + +#define DDCMON_SYSCTL_ID 1010 +#define DDCMON_SYSCTL_SIZE 1011 +#define DDCMON_SYSCTL_SYNC 1012 +#define DDCMON_SYSCTL_TIMINGS 1013 +#define DDCMON_SYSCTL_SERIAL 1014 + +#define LM87_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM87_SYSCTL_IN1 1001 +#define LM87_SYSCTL_IN2 1002 +#define LM87_SYSCTL_IN3 1003 +#define LM87_SYSCTL_IN4 1004 +#define LM87_SYSCTL_IN5 1005 +#define LM87_SYSCTL_AIN1 1006 +#define LM87_SYSCTL_AIN2 1007 +#define LM87_SYSCTL_FAN1 1102 +#define LM87_SYSCTL_FAN2 1103 +#define LM87_SYSCTL_TEMP1 1250 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_TEMP2 1251 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_TEMP3 1252 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM87_SYSCTL_ALARMS 2001 /* bitvector */ +#define LM87_SYSCTL_ANALOG_OUT 2002 +#define LM87_SYSCTL_VID 2003 +#define LM87_SYSCTL_VRM 2004 + +#define LM87_ALARM_IN0 0x0001 +#define LM87_ALARM_IN1 0x0002 +#define LM87_ALARM_IN2 0x0004 +#define LM87_ALARM_IN3 0x0008 +#define LM87_ALARM_TEMP1 0x0010 +#define LM87_ALARM_TEMP2 0x0020 +#define LM87_ALARM_TEMP3 0x0020 /* same?? */ +#define LM87_ALARM_FAN1 0x0040 +#define LM87_ALARM_FAN2 0x0080 +#define LM87_ALARM_IN4 0x0100 +#define LM87_ALARM_IN5 0x0200 +#define LM87_ALARM_RESERVED1 0x0400 +#define LM87_ALARM_RESERVED2 0x0800 +#define LM87_ALARM_CHAS 0x1000 +#define LM87_ALARM_THERM_SIG 0x2000 +#define LM87_ALARM_TEMP2_FAULT 0x4000 +#define LM87_ALARM_TEMP3_FAULT 0x08000 + +#define PCF8574_SYSCTL_READ 1000 +#define PCF8574_SYSCTL_WRITE 1001 + +#define MTP008_SYSCTL_IN0 1000 /* Volts * 100 */ +#define MTP008_SYSCTL_IN1 1001 +#define MTP008_SYSCTL_IN2 1002 +#define MTP008_SYSCTL_IN3 1003 +#define MTP008_SYSCTL_IN4 1004 +#define MTP008_SYSCTL_IN5 1005 +#define MTP008_SYSCTL_IN6 1006 +#define MTP008_SYSCTL_FAN1 1101 /* Rotations/min */ +#define MTP008_SYSCTL_FAN2 1102 +#define MTP008_SYSCTL_FAN3 1103 +#define MTP008_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define MTP008_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define MTP008_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ +#define MTP008_SYSCTL_VID 1300 /* Volts * 100 */ +#define MTP008_SYSCTL_PWM1 1401 +#define MTP008_SYSCTL_PWM2 1402 +#define MTP008_SYSCTL_PWM3 1403 +#define MTP008_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define MTP008_SYSCTL_SENS2 1502 +#define MTP008_SYSCTL_SENS3 1503 +#define MTP008_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define MTP008_SYSCTL_ALARMS 2001 /* bitvector */ +#define MTP008_SYSCTL_BEEP 2002 /* bitvector */ + +#define MTP008_ALARM_IN0 0x0001 +#define MTP008_ALARM_IN1 0x0002 +#define MTP008_ALARM_IN2 0x0004 +#define MTP008_ALARM_IN3 0x0008 +#define MTP008_ALARM_IN4 0x0100 +#define MTP008_ALARM_IN5 0x0200 +#define MTP008_ALARM_IN6 0x0400 +#define MTP008_ALARM_FAN1 0x0040 +#define MTP008_ALARM_FAN2 0x0080 +#define MTP008_ALARM_FAN3 0x0800 +#define MTP008_ALARM_TEMP1 0x0010 +#define MTP008_ALARM_TEMP2 0x0100 +#define MTP008_ALARM_TEMP3 0x0200 + +#define DS1621_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define DS1621_SYSCTL_ALARMS 2001 /* bitvector */ +#define DS1621_ALARM_TEMP_HIGH 0x40 +#define DS1621_ALARM_TEMP_LOW 0x20 +#define DS1621_SYSCTL_ENABLE 2002 +#define DS1621_SYSCTL_CONTINUOUS 2003 +#define DS1621_SYSCTL_POLARITY 2004 + +#define IT87_SYSCTL_IN0 1000 /* Volts * 100 */ +#define IT87_SYSCTL_IN1 1001 +#define IT87_SYSCTL_IN2 1002 +#define IT87_SYSCTL_IN3 1003 +#define IT87_SYSCTL_IN4 1004 +#define IT87_SYSCTL_IN5 1005 +#define IT87_SYSCTL_IN6 1006 +#define IT87_SYSCTL_IN7 1007 +#define IT87_SYSCTL_IN8 1008 +#define IT87_SYSCTL_FAN1 1101 /* Rotations/min */ +#define IT87_SYSCTL_FAN2 1102 +#define IT87_SYSCTL_FAN3 1103 +#define IT87_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define IT87_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define IT87_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ +#define IT87_SYSCTL_VID 1300 /* Volts * 100 */ +#define IT87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define IT87_SYSCTL_ALARMS 2004 /* bitvector */ + +#define IT87_ALARM_IN0 0x000100 +#define IT87_ALARM_IN1 0x000200 +#define IT87_ALARM_IN2 0x000400 +#define IT87_ALARM_IN3 0x000800 +#define IT87_ALARM_IN4 0x001000 +#define IT87_ALARM_IN5 0x002000 +#define IT87_ALARM_IN6 0x004000 +#define IT87_ALARM_IN7 0x008000 +#define IT87_ALARM_FAN1 0x0001 +#define IT87_ALARM_FAN2 0x0002 +#define IT87_ALARM_FAN3 0x0004 +#define IT87_ALARM_TEMP1 0x00010000 +#define IT87_ALARM_TEMP2 0x00020000 +#define IT87_ALARM_TEMP3 0x00040000 + +#define FSCPOS_SYSCTL_VOLT0 1000 /* 12 volt supply */ +#define FSCPOS_SYSCTL_VOLT1 1001 /* 5 volt supply */ +#define FSCPOS_SYSCTL_VOLT2 1002 /* batterie voltage*/ +#define FSCPOS_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ +#define FSCPOS_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ +#define FSCPOS_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ +#define FSCPOS_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ +#define FSCPOS_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ +#define FSCPOS_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ +#define FSCPOS_SYSCTL_REV 2000 /* Revision */ +#define FSCPOS_SYSCTL_EVENT 2001 /* global event status */ +#define FSCPOS_SYSCTL_CONTROL 2002 /* global control byte */ +#define FSCPOS_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ + +#define FSCSCY_SYSCTL_VOLT0 1000 /* 12 volt supply */ +#define FSCSCY_SYSCTL_VOLT1 1001 /* 5 volt supply */ +#define FSCSCY_SYSCTL_VOLT2 1002 /* batterie voltage*/ +#define FSCSCY_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ +#define FSCSCY_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ +#define FSCSCY_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ +#define FSCSCY_SYSCTL_FAN3 1104 /* state, min, ripple, actual value fan 3 */ +#define FSCSCY_SYSCTL_FAN4 1105 /* state, min, ripple, actual value fan 4 */ +#define FSCSCY_SYSCTL_FAN5 1106 /* state, min, ripple, actual value fan 5 */ +#define FSCSCY_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ +#define FSCSCY_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ +#define FSCSCY_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ +#define FSCSCY_SYSCTL_TEMP3 1204 /* state and value of sensor 3, chassis */ +#define FSCSCY_SYSCTL_REV 2000 /* Revision */ +#define FSCSCY_SYSCTL_EVENT 2001 /* global event status */ +#define FSCSCY_SYSCTL_CONTROL 2002 /* global control byte */ +#define FSCSCY_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ +#define FSCSCY_SYSCTL_PCILOAD 2004 /* PCILoad value */ +#define FSCSCY_SYSCTL_INTRUSION 2005 /* state, control for intrusion sensor */ + +#define PCF8591_SYSCTL_AIN_CONF 1000 /* Analog input configuration */ +#define PCF8591_SYSCTL_CH0 1001 /* Input channel 1 */ +#define PCF8591_SYSCTL_CH1 1002 /* Input channel 2 */ +#define PCF8591_SYSCTL_CH2 1003 /* Input channel 3 */ +#define PCF8591_SYSCTL_CH3 1004 /* Input channel 4 */ +#define PCF8591_SYSCTL_AOUT_ENABLE 1005 /* Analog output enable flag */ +#define PCF8591_SYSCTL_AOUT 1006 /* Analog output */ + +#define ARP_SYSCTL1 1000 +#define ARP_SYSCTL2 1001 +#define ARP_SYSCTL3 1002 +#define ARP_SYSCTL4 1003 +#define ARP_SYSCTL5 1004 +#define ARP_SYSCTL6 1005 +#define ARP_SYSCTL7 1006 +#define ARP_SYSCTL8 1007 + +#define SMSC47M1_SYSCTL_FAN1 1101 /* Rotations/min */ +#define SMSC47M1_SYSCTL_FAN2 1102 +#define SMSC47M1_SYSCTL_PWM1 1401 +#define SMSC47M1_SYSCTL_PWM2 1402 +#define SMSC47M1_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define SMSC47M1_SYSCTL_ALARMS 2004 /* bitvector */ + +#define SMSC47M1_ALARM_FAN1 0x0001 +#define SMSC47M1_ALARM_FAN2 0x0002 + +#define VT1211_SYSCTL_IN0 1000 +#define VT1211_SYSCTL_IN1 1001 +#define VT1211_SYSCTL_IN2 1002 +#define VT1211_SYSCTL_IN3 1003 +#define VT1211_SYSCTL_IN4 1004 +#define VT1211_SYSCTL_IN5 1005 +#define VT1211_SYSCTL_IN6 1006 +#define VT1211_SYSCTL_FAN1 1101 +#define VT1211_SYSCTL_FAN2 1102 +#define VT1211_SYSCTL_TEMP 1200 +#define VT1211_SYSCTL_TEMP2 1201 +#define VT1211_SYSCTL_TEMP3 1202 +#define VT1211_SYSCTL_TEMP4 1203 +#define VT1211_SYSCTL_TEMP5 1204 +#define VT1211_SYSCTL_TEMP6 1205 +#define VT1211_SYSCTL_TEMP7 1206 +#define VT1211_SYSCTL_VID 1300 +#define VT1211_SYSCTL_PWM1 1401 +#define VT1211_SYSCTL_PWM2 1402 +#define VT1211_SYSCTL_VRM 1600 +#define VT1211_SYSCTL_UCH 1700 +#define VT1211_SYSCTL_FAN_DIV 2000 +#define VT1211_SYSCTL_ALARMS 2001 + +#define VT1211_ALARM_IN1 0x01 +#define VT1211_ALARM_IN2 0x02 +#define VT1211_ALARM_IN5 0x04 +#define VT1211_ALARM_IN3 0x08 +#define VT1211_ALARM_TEMP 0x10 +#define VT1211_ALARM_FAN1 0x40 +#define VT1211_ALARM_FAN2 0x80 +#define VT1211_ALARM_IN4 0x100 +#define VT1211_ALARM_IN6 0x200 +#define VT1211_ALARM_TEMP2 0x800 +#define VT1211_ALARM_CHAS 0x1000 +#define VT1211_ALARM_TEMP3 0x8000 +/* duplicates */ +#define VT1211_ALARM_IN0 VT1211_ALARM_TEMP +#define VT1211_ALARM_TEMP4 VT1211_ALARM_IN1 +#define VT1211_ALARM_TEMP5 VT1211_ALARM_IN2 +#define VT1211_ALARM_TEMP6 VT1211_ALARM_IN3 +#define VT1211_ALARM_TEMP7 VT1211_ALARM_IN4 + +#define LM92_SYSCTL_ALARMS 2001 /* high, low, critical */ +#define LM92_SYSCTL_TEMP 1200 /* high, low, critical, hysterisis, input */ + +#define LM92_ALARM_TEMP_HIGH 0x01 +#define LM92_ALARM_TEMP_LOW 0x02 +#define LM92_ALARM_TEMP_CRIT 0x04 +#define LM92_TEMP_HIGH 0x08 +#define LM92_TEMP_LOW 0x10 +#define LM92_TEMP_CRIT 0x20 +#define LM92_TEMP_HYST 0x40 +#define LM92_TEMP_INPUT 0x80 + +#define VT8231_SYSCTL_IN0 1000 +#define VT8231_SYSCTL_IN1 1001 +#define VT8231_SYSCTL_IN2 1002 +#define VT8231_SYSCTL_IN3 1003 +#define VT8231_SYSCTL_IN4 1004 +#define VT8231_SYSCTL_IN5 1005 +#define VT8231_SYSCTL_IN6 1006 +#define VT8231_SYSCTL_FAN1 1101 +#define VT8231_SYSCTL_FAN2 1102 +#define VT8231_SYSCTL_TEMP 1200 +#define VT8231_SYSCTL_TEMP2 1201 +#define VT8231_SYSCTL_TEMP3 1202 +#define VT8231_SYSCTL_TEMP4 1203 +#define VT8231_SYSCTL_TEMP5 1204 +#define VT8231_SYSCTL_TEMP6 1205 +#define VT8231_SYSCTL_TEMP7 1206 +#define VT8231_SYSCTL_VID 1300 +#define VT8231_SYSCTL_PWM1 1401 +#define VT8231_SYSCTL_PWM2 1402 +#define VT8231_SYSCTL_VRM 1600 +#define VT8231_SYSCTL_UCH 1700 +#define VT8231_SYSCTL_FAN_DIV 2000 +#define VT8231_SYSCTL_ALARMS 2001 + +#define VT8231_ALARM_IN1 0x01 +#define VT8231_ALARM_IN2 0x02 +#define VT8231_ALARM_IN5 0x04 +#define VT8231_ALARM_IN3 0x08 +#define VT8231_ALARM_TEMP 0x10 +#define VT8231_ALARM_FAN1 0x40 +#define VT8231_ALARM_FAN2 0x80 +#define VT8231_ALARM_IN4 0x100 +#define VT8231_ALARM_IN6 0x200 +#define VT8231_ALARM_TEMP2 0x800 +#define VT8231_ALARM_CHAS 0x1000 +#define VT8231_ALARM_TEMP3 0x8000 +/* duplicates */ +#define VT8231_ALARM_IN0 VT8231_ALARM_TEMP +#define VT8231_ALARM_TEMP4 VT8231_ALARM_IN1 +#define VT8231_ALARM_TEMP5 VT8231_ALARM_IN2 +#define VT8231_ALARM_TEMP6 VT8231_ALARM_IN3 +#define VT8231_ALARM_TEMP7 VT8231_ALARM_IN4 + +#define SMARTBATT_SYSCTL_I 1001 +#define SMARTBATT_SYSCTL_V 1002 +#define SMARTBATT_SYSCTL_TEMP 1003 +#define SMARTBATT_SYSCTL_TIME 1004 +#define SMARTBATT_SYSCTL_ALARMS 1005 +#define SMARTBATT_SYSCTL_CHARGE 1006 + + +#endif /* def SENSORS_SENSORS_H */ -- cgit v1.2.3 From 8becad9547d5bf26ec757dea21ff80766fd665f8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Dec 2002 21:57:20 -0800 Subject: [PATCH] USB: convert empeg driver to use dev_err() and dev_info() macros --- drivers/usb/serial/empeg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index a5e3b7795d7d..984f1708ef78 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -181,7 +181,7 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp) result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) - err("%s - failed submitting read urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); return result; } @@ -205,7 +205,7 @@ static void empeg_close (struct usb_serial_port *port, struct file * filp) usb_unlink_urb (port->read_urb); } /* Uncomment the following line if you want to see some statistics in your syslog */ - /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ + /* dev_info (port->dev, "Bytes In = %d Bytes Out = %d\n", bytes_in, bytes_out); */ } @@ -248,7 +248,7 @@ static int empeg_write (struct usb_serial_port *port, int from_user, const unsig if (urb->transfer_buffer == NULL) { urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); if (urb->transfer_buffer == NULL) { - err("%s no more kernel memory...", __FUNCTION__); + dev_err(port->dev, "%s no more kernel memory...\n", __FUNCTION__); goto exit; } } @@ -278,7 +278,7 @@ static int empeg_write (struct usb_serial_port *port, int from_user, const unsig /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { - err("%s - usb_submit_urb(write bulk) failed with status = %d", __FUNCTION__, status); + dev_err(port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __FUNCTION__, status); bytes_sent = status; break; } @@ -426,7 +426,7 @@ static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs) result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + dev_err(urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); return; @@ -451,7 +451,7 @@ static void empeg_unthrottle (struct usb_serial_port *port) result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err("%s - failed submitting read urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); return; } -- cgit v1.2.3 From d407f7f3a7d15118956409d26eb017b96a6b7101 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Dec 2002 21:57:41 -0800 Subject: [PATCH] USB: convert io_edgeport driver to use dev_err() and dev_info() macros --- drivers/usb/serial/io_edgeport.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index e0963b2ecf13..04818b27250f 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -572,7 +572,7 @@ static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial) record = (struct edge_firmware_image_record *)firmware; response = rom_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]); if (response < 0) { - err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len); + dev_err(edge_serial->serial->dev->dev, "sram_write failed (%x, %x, %d)\n", record->ExtAddr, record->Addr, record->Len); break; } firmware += sizeof (struct edge_firmware_image_record) + record->Len; @@ -840,7 +840,7 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs) exit: result = usb_submit_urb (urb, GFP_ATOMIC); if (result) { - err("%s - Error %d submitting control urb", __FUNCTION__, result); + dev_err(urb->dev->dev, "%s - Error %d submitting control urb\n", __FUNCTION__, result); } } @@ -889,7 +889,7 @@ static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs) edge_serial->read_urb->dev = edge_serial->serial->dev; status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (status) { - err("%s - usb_submit_urb(read bulk) failed, status = %d", __FUNCTION__, status); + dev_err(urb->dev->dev, "%s - usb_submit_urb(read bulk) failed, status = %d\n", __FUNCTION__, status); } } } @@ -1057,7 +1057,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) * this interrupt will continue as long as the edgeport is connected */ response = usb_submit_urb (edge_serial->interrupt_read_urb, GFP_KERNEL); if (response) { - err("%s - Error %d submitting control urb", __FUNCTION__, response); + dev_err(port->dev, "%s - Error %d submitting control urb\n", __FUNCTION__, response); } } @@ -1081,7 +1081,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0); if (response < 0) { - err("%s - error sending open port command", __FUNCTION__); + dev_err(port->dev, "%s - error sending open port command\n", __FUNCTION__); edge_port->openPending = FALSE; return -ENODEV; } @@ -1450,7 +1450,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge count = fifo->count; buffer = kmalloc (count+2, GFP_ATOMIC); if (buffer == NULL) { - err("%s - no more kernel memory...", __FUNCTION__); + dev_err(edge_serial->serial->dev->dev, "%s - no more kernel memory...\n", __FUNCTION__); edge_port->write_in_progress = FALSE; return; } @@ -2143,7 +2143,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2 } edge_port = (struct edgeport_port *)port->private; if (edge_port == NULL) { - err("%s - edge_port == NULL for port %d", __FUNCTION__, edge_serial->rxPort); + dev_err(edge_serial->serial->dev->dev, "%s - edge_port == NULL for port %d\n", __FUNCTION__, edge_serial->rxPort); return; } @@ -2330,7 +2330,7 @@ static int sram_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u transfer_buffer = kmalloc (64, GFP_KERNEL); if (!transfer_buffer) { - err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 64); + dev_err(serial->dev->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 64); return -ENOMEM; } @@ -2375,7 +2375,7 @@ static int rom_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u1 transfer_buffer = kmalloc (64, GFP_KERNEL); if (!transfer_buffer) { - err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 64); + dev_err(serial->dev->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 64); return -ENOMEM; } @@ -2420,7 +2420,7 @@ static int rom_read (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 transfer_buffer = kmalloc (64, GFP_KERNEL); if (!transfer_buffer) { - err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 64); + dev_err(serial->dev->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 64); return -ENOMEM; } @@ -2463,7 +2463,7 @@ static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u buffer = kmalloc (10, GFP_ATOMIC); if (!buffer) { - err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 10); + dev_err(edge_port->port->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 10); return -ENOMEM; } @@ -2554,14 +2554,14 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa status = calc_baud_rate_divisor (baudRate, &divisor); if (status) { - err("%s - bad baud rate", __FUNCTION__); + dev_err(edge_port->port->dev, "%s - bad baud rate\n", __FUNCTION__); return status; } // Alloc memory for the string of commands. cmdBuffer = kmalloc (0x100, GFP_ATOMIC); if (!cmdBuffer) { - err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 0x100); + dev_err(edge_port->port->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 0x100); return -ENOMEM; } currCmd = cmdBuffer; @@ -2838,7 +2838,7 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial) (__u8 *)(&edge_serial->manuf_descriptor)); if (response < 1) { - err("error in getting manufacturer descriptor"); + dev_err(edge_serial->serial->dev->dev, "error in getting manufacturer descriptor\n"); } else { char string[30]; dbg("**Manufacturer Descriptor"); @@ -2877,7 +2877,7 @@ static void get_boot_desc (struct edgeport_serial *edge_serial) (__u8 *)(&edge_serial->boot_descriptor)); if (response < 1) { - err("error in getting boot descriptor"); + dev_err(edge_serial->serial->dev->dev, "error in getting boot descriptor\n"); } else { dbg("**Boot Descriptor:"); dbg(" BootCodeLength: %d", edge_serial->boot_descriptor.BootCodeLength); @@ -2938,7 +2938,7 @@ static void load_application_firmware (struct edgeport_serial *edge_serial) record = (struct edge_firmware_image_record *)firmware; response = sram_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]); if (response < 0) { - err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len); + dev_err(edge_serial->serial->dev->dev, "sram_write failed (%x, %x, %d)\n", record->ExtAddr, record->Addr, record->Len); break; } firmware += sizeof (struct edge_firmware_image_record) + record->Len; @@ -2974,7 +2974,7 @@ static int edge_startup (struct usb_serial *serial) /* create our private serial structure */ edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL); if (edge_serial == NULL) { - err("%s - Out of memory", __FUNCTION__); + dev_err(serial->dev->dev, "%s - Out of memory", __FUNCTION__); return -ENOMEM; } memset (edge_serial, 0, sizeof(struct edgeport_serial)); @@ -2988,7 +2988,7 @@ static int edge_startup (struct usb_serial *serial) get_string(dev, dev->descriptor.iProduct, &edge_serial->name[i]); - info("%s detected", edge_serial->name); + dev_info(serial->dev->dev, "%s detected\n", edge_serial->name); /* get the manufacturing descriptor for this device */ get_manufacturing_desc (edge_serial); @@ -3030,7 +3030,9 @@ static int edge_startup (struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); if (edge_port == NULL) { - err("%s - Out of memory", __FUNCTION__); + dev_err(serial->dev->dev, "%s - Out of memory", __FUNCTION__); + serial->private = NULL; + kfree(edge_serial); return -ENOMEM; } memset (edge_port, 0, sizeof(struct edgeport_port)); -- cgit v1.2.3 From e090f79f97c593d04063c47cd1216246d4885ab5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Dec 2002 21:58:03 -0800 Subject: [PATCH] USB: convert io_ti driver to use dev_err() and dev_info() macros --- drivers/usb/serial/io_ti.c | 72 ++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index ba9e939667f1..0591c586f151 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -473,7 +473,7 @@ static int TIIsTxActive (struct edgeport_port *port) oedb = kmalloc (sizeof (* oedb), GFP_KERNEL); if (!oedb) { - err ("%s - out of memory", __FUNCTION__); + dev_err (port->port->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } @@ -592,7 +592,7 @@ static int TIChooseConfiguration (struct usb_device *dev) dbg ("%s - MAX Power = %d", __FUNCTION__, dev->config->desc.bMaxPower*2); if (dev->config->desc.bNumInterfaces != 1) { - err ("%s - bNumInterfaces is not 1, ERROR!", __FUNCTION__); + dev_err (dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", __FUNCTION__); return -ENODEV; } @@ -684,6 +684,7 @@ static int ValidChecksum(struct ti_i2c_desc *rom_desc, __u8 *buffer) /* Make sure that the I2C image is good */ static int TiValidateI2cImage (struct edgeport_serial *serial) { + struct device *dev = &serial->serial->dev->dev; int status = 0; struct ti_i2c_desc *rom_desc; int start_address = 2; @@ -691,12 +692,12 @@ static int TiValidateI2cImage (struct edgeport_serial *serial) rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL); if (!rom_desc) { - err ("%s - out of memory", __FUNCTION__); + dev_err (*dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } buffer = kmalloc (TI_MAX_I2C_SIZE, GFP_KERNEL); if (!buffer) { - err ("%s - out of memory when allocating buffer", __FUNCTION__); + dev_err (*dev, "%s - out of memory when allocating buffer\n", __FUNCTION__); kfree (rom_desc); return -ENOMEM; } @@ -707,7 +708,7 @@ static int TiValidateI2cImage (struct edgeport_serial *serial) goto ExitTiValidateI2cImage; if (*buffer != 0x52) { - err ("%s - invalid buffer signature", __FUNCTION__); + dev_err (*dev, "%s - invalid buffer signature\n", __FUNCTION__); status = -ENODEV; goto ExitTiValidateI2cImage; } @@ -765,7 +766,7 @@ static int TIReadManufDescriptor (struct edgeport_serial *serial, __u8 *buffer) rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL); if (!rom_desc) { - err ("%s - out of memory", __FUNCTION__); + dev_err (serial->serial->dev->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_ION, rom_desc); @@ -800,7 +801,7 @@ exit: } /* Build firmware header used for firmware update */ -static int BuildI2CFirmwareHeader (__u8 *header) +static int BuildI2CFirmwareHeader (__u8 *header, struct device *dev) { __u8 *buffer; int buffer_size; @@ -822,7 +823,7 @@ static int BuildI2CFirmwareHeader (__u8 *header) buffer = kmalloc (buffer_size, GFP_KERNEL); if (!buffer) { - err ("%s - out of memory", __FUNCTION__); + dev_err (*dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } @@ -960,6 +961,7 @@ static int TIConfigureBootDevice (struct usb_device *dev) */ static int TIDownloadFirmware (struct edgeport_serial *serial) { + struct device *dev = &serial->serial->dev->dev; int status = 0; int start_address; struct edge_ti_manuf_descriptor *ti_manuf_desc; @@ -982,7 +984,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) interface = &serial->serial->dev->config->interface->altsetting->desc; if (!interface) { - err ("%s - no interface set, error!", __FUNCTION__); + dev_err (serial->serial->dev->dev, "%s - no interface set, error!", __FUNCTION__); return -ENODEV; } @@ -1019,7 +1021,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) */ ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL); if (!ti_manuf_desc) { - err ("%s - out of memory.", __FUNCTION__); + dev_err (*dev, "%s - out of memory.\n", __FUNCTION__); return -ENOMEM; } status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc); @@ -1038,7 +1040,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL); if (!rom_desc) { - err ("%s - out of memory.", __FUNCTION__); + dev_err (*dev, "%s - out of memory.\n", __FUNCTION__); kfree (ti_manuf_desc); return -ENOMEM; } @@ -1052,7 +1054,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) firmware_version = kmalloc (sizeof (*firmware_version), GFP_KERNEL); if (!firmware_version) { - err ("%s - out of memory.", __FUNCTION__); + dev_err (*dev, "%s - out of memory.\n", __FUNCTION__); kfree (rom_desc); kfree (ti_manuf_desc); return -ENOMEM; @@ -1129,7 +1131,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) } if (record != I2C_DESC_TYPE_FIRMWARE_BLANK) { - err ("%s - error resetting device", __FUNCTION__); + dev_err (*dev, "%s - error resetting device\n", __FUNCTION__); kfree (firmware_version); kfree (rom_desc); kfree (ti_manuf_desc); @@ -1160,7 +1162,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) header = kmalloc (HEADER_SIZE, GFP_KERNEL); if (!header) { - err ("%s - out of memory.", __FUNCTION__); + dev_err (*dev, "%s - out of memory.\n", __FUNCTION__); kfree (rom_desc); kfree (ti_manuf_desc); return -ENOMEM; @@ -1168,7 +1170,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) vheader = kmalloc (HEADER_SIZE, GFP_KERNEL); if (!vheader) { - err ("%s - out of memory.", __FUNCTION__); + dev_err (*dev, "%s - out of memory.\n", __FUNCTION__); kfree (header); kfree (rom_desc); kfree (ti_manuf_desc); @@ -1183,7 +1185,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) // And finally when the device comes back up in download mode the driver will cause // the new firmware to be copied from the UMP Ram to I2C and the firmware will update // the record type from 0xf2 to 0x02. - status = BuildI2CFirmwareHeader(header); + status = BuildI2CFirmwareHeader(header, dev); if (status) { kfree (vheader); kfree (header); @@ -1300,7 +1302,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) */ ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL); if (!ti_manuf_desc) { - err ("%s - out of memory.", __FUNCTION__); + dev_err (*dev, "%s - out of memory.\n", __FUNCTION__); return -ENOMEM; } status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc); @@ -1335,7 +1337,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial) buffer_size = (((1024 * 16) - 512) + sizeof(struct ti_i2c_image_header)); buffer = kmalloc (buffer_size, GFP_KERNEL); if (!buffer) { - err ("%s - out of memory", __FUNCTION__); + dev_err (*dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } @@ -1616,7 +1618,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8 static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs) { - struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context; + struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context; struct usb_serial_port *port; struct edgeport_port *edge_port; unsigned char *data = urb->transfer_buffer; @@ -1700,8 +1702,8 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs) break; default: - err ("%s - Unknown Interrupt code from UMP %x\n", - __FUNCTION__, data[1]); + dev_err (urb->dev->dev, "%s - Unknown Interrupt code from UMP %x\n", + __FUNCTION__, data[1]); break; } @@ -1709,8 +1711,8 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs) exit: status = usb_submit_urb (urb, GFP_ATOMIC); if (status) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); + dev_err (urb->dev->dev, "%s - usb_submit_urb failed with result %d\n", + __FUNCTION__, status); } static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs) @@ -1777,8 +1779,8 @@ exit: /* continue always trying to read */ status = usb_submit_urb (urb, GFP_ATOMIC); if (status) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); + dev_err (urb->dev->dev, "%s - usb_submit_urb failed with result %d\n", + __FUNCTION__, status); } static void edge_bulk_out_callback (struct urb *urb, struct pt_regs *regs) @@ -1853,7 +1855,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) edge_port->dma_address = UMPD_OEDB2_ADDRESS; break; default: - err ("Unknown port number!!!"); + dev_err (port->dev, "Unknown port number!!!\n"); return -ENODEV; } @@ -1929,7 +1931,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) /* we are the first port to be opened, let's post the interrupt urb */ urb = edge_serial->serial->port[0].interrupt_in_urb; if (!urb) { - err ("%s - no interrupt urb present, exiting", __FUNCTION__); + dev_err (port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__); return -EINVAL; } urb->complete = edge_interrupt_callback; @@ -1937,7 +1939,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) urb->dev = dev; status = usb_submit_urb (urb, GFP_KERNEL); if (status) { - err ("%s - usb_submit_urb failed with value %d", __FUNCTION__, status); + dev_err (port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status); return status; } } @@ -1952,7 +1954,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) /* start up our bulk read urb */ urb = port->read_urb; if (!urb) { - err ("%s - no read urb present, exiting", __FUNCTION__); + dev_err (port->dev, "%s - no read urb present, exiting\n", __FUNCTION__); return -EINVAL; } urb->complete = edge_bulk_in_callback; @@ -1960,7 +1962,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) urb->dev = dev; status = usb_submit_urb (urb, GFP_KERNEL); if (status) { - err ("%s - read bulk usb_submit_urb failed with value %d", __FUNCTION__, status); + dev_err (port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __FUNCTION__, status); return status; } @@ -2070,7 +2072,7 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) - err("%s - failed submitting write urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); else result = count; @@ -2189,7 +2191,7 @@ static void edge_unthrottle (struct usb_serial_port *port) port->read_urb->dev = port->serial->dev; status = usb_submit_urb (port->read_urb, GFP_ATOMIC); if (status) { - err ("%s - usb_submit_urb failed with value %d", __FUNCTION__, status); + dev_err (port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status); } } @@ -2215,7 +2217,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { - err ("%s - out of memory", __FUNCTION__); + dev_err (edge_port->port->dev, "%s - out of memory\n", __FUNCTION__); return; } @@ -2588,7 +2590,7 @@ static int edge_startup (struct usb_serial *serial) /* create our private serial structure */ edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL); if (edge_serial == NULL) { - err("%s - Out of memory", __FUNCTION__); + dev_err(serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); return -ENOMEM; } memset (edge_serial, 0, sizeof(struct edgeport_serial)); @@ -2605,7 +2607,7 @@ static int edge_startup (struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); if (edge_port == NULL) { - err("%s - Out of memory", __FUNCTION__); + dev_err(serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); return -ENOMEM; } memset (edge_port, 0, sizeof(struct edgeport_port)); -- cgit v1.2.3 From c2d953cfdd512eff67c454ce8b1c3c8f018ba374 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Dec 2002 21:58:26 -0800 Subject: [PATCH] USB: convert ir-usb driver to use dev_err() and dev_info() macros --- drivers/usb/serial/ir-usb.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index d18801249d63..6d40da5bd9e7 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -243,7 +243,7 @@ static int ir_startup (struct usb_serial *serial) irda_desc = irda_usb_find_class_desc (serial->dev, 0); if (irda_desc == NULL) { - err ("IRDA class descriptor not found, device not bound"); + dev_err (serial->dev->dev, "IRDA class descriptor not found, device not bound\n"); return -ENODEV; } @@ -291,7 +291,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp) /* override the default buffer sizes */ buffer = kmalloc (buffer_size, GFP_KERNEL); if (!buffer) { - err ("%s - out of memory.", __FUNCTION__); + dev_err (port->dev, "%s - out of memory.\n", __FUNCTION__); return -ENOMEM; } kfree (port->read_urb->transfer_buffer); @@ -300,7 +300,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp) buffer = kmalloc (buffer_size, GFP_KERNEL); if (!buffer) { - err ("%s - out of memory.", __FUNCTION__); + dev_err (port->dev, "%s - out of memory.\n", __FUNCTION__); return -ENOMEM; } kfree (port->write_urb->transfer_buffer); @@ -320,7 +320,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp) port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) - err("%s - failed submitting read urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); return result; } @@ -353,7 +353,7 @@ static int ir_write (struct usb_serial_port *port, int from_user, const unsigned dbg("%s - port = %d, count = %d", __FUNCTION__, port->number, count); if (!port->tty) { - err ("%s - no tty???", __FUNCTION__); + dev_err (port->dev, "%s - no tty???\n", __FUNCTION__); return 0; } @@ -399,7 +399,7 @@ static int ir_write (struct usb_serial_port *port, int from_user, const unsigned result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) - err("%s - failed submitting write urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); else result = transfer_size; @@ -503,11 +503,9 @@ static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs) port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - err("%s - failed resubmitting read urb, error %d", - __FUNCTION__, - result); + dev_err(port->dev, "%s - failed resubmitting read urb, error %d\n", + __FUNCTION__, result); break ; @@ -601,7 +599,7 @@ static void ir_set_termios (struct usb_serial_port *port, struct termios *old_te result = usb_submit_urb (port->write_urb, GFP_KERNEL); if (result) - err("%s - failed submitting write urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); } return; } -- cgit v1.2.3 From 77d062a5f572597bbae1ae5f12b7bd22167bf1a7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Dec 2002 21:58:47 -0800 Subject: [PATCH] USB: convert keyspan driver to use dev_err() and dev_info() macros --- drivers/usb/serial/keyspan.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index e128949276bf..7f6bcea0dee9 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1037,7 +1037,7 @@ static int keyspan_fake_startup (struct usb_serial *serial) } if (record == NULL) { - err("Required keyspan firmware image (%s) unavailable.", fw_name); + dev_err(serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name); return(1); } @@ -1051,10 +1051,10 @@ static int keyspan_fake_startup (struct usb_serial *serial) (unsigned char *)record->data, record->data_size, 0xa0); if (response < 0) { - err("ezusb_writememory failed for Keyspan" - "firmware (%d %04X %p %d)", - response, - record->address, record->data, record->data_size); + dev_err(serial->dev->dev, "ezusb_writememory failed for Keyspan" + "firmware (%d %04X %p %d)\n", + response, + record->address, record->data, record->data_size); break; } record++; @@ -1849,7 +1849,7 @@ static int keyspan_startup (struct usb_serial *serial) if (d_details->product_id == serial->dev->descriptor.idProduct) break; if (d_details == NULL) { - err("%s - unknown product id %x", __FUNCTION__, serial->dev->descriptor.idProduct); + dev_err(serial->dev->dev, "%s - unknown product id %x\n", __FUNCTION__, serial->dev->descriptor.idProduct); return 1; } -- cgit v1.2.3 From da73843feb3c1f5373d98b0f5799117fdb46e67c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Dec 2002 21:59:10 -0800 Subject: [PATCH] USB: convert pl2303 driver to use dev_err() and dev_info() macros --- drivers/usb/serial/pl2303.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 1284892b0fb4..c1ff4e3ff3d5 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -204,7 +204,7 @@ static int pl2303_write (struct usb_serial_port *port, int from_user, const uns port->write_urb->dev = port->serial->dev; result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) - err("%s - failed submitting write urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); else result = count; @@ -247,7 +247,7 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol buf = kmalloc (7, GFP_KERNEL); if (!buf) { - err("%s - out of memory.", __FUNCTION__); + dev_err(port->dev, "%s - out of memory.\n", __FUNCTION__); return; } memset (buf, 0x00, 0x07); @@ -295,7 +295,7 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol case B230400: baud = 230400; break; case B460800: baud = 460800; break; default: - err ("pl2303 driver does not support the baudrate requested (fix it)"); + dev_err(port->dev, "pl2303 driver does not support the baudrate requested (fix it)\n"); break; } dbg("%s - baud = %d", __FUNCTION__, baud); @@ -413,7 +413,7 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) port->read_urb->dev = serial->dev; result = usb_submit_urb (port->read_urb, GFP_KERNEL); if (result) { - err("%s - failed submitting read urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); pl2303_close (port, NULL); return -EPROTO; } @@ -422,7 +422,7 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) port->interrupt_in_urb->dev = serial->dev; result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL); if (result) { - err("%s - failed submitting interrupt urb, error %d", __FUNCTION__, result); + dev_err(port->dev, "%s - failed submitting interrupt urb, error %d\n", __FUNCTION__, result); pl2303_close (port, NULL); return -EPROTO; } @@ -621,8 +621,8 @@ static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs) exit: status = usb_submit_urb (urb, GFP_ATOMIC); if (status) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); + dev_err(urb->dev->dev, "%s - usb_submit_urb failed with result %d\n", + __FUNCTION__, status); } @@ -658,7 +658,7 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs) urb->dev = serial->dev; result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + dev_err(urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); return; } dbg("%s - unable to handle the error, exiting.", __FUNCTION__); @@ -683,7 +683,7 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs) urb->dev = serial->dev; result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + dev_err(urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); } return; @@ -712,7 +712,7 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs) port->write_urb->dev = port->serial->dev; result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) - err("%s - failed resubmitting write urb, error %d", __FUNCTION__, result); + dev_err(urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result); return; } -- cgit v1.2.3 From a83c24f33622b86c3cb2a53f959a042d67ab7258 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 25 Dec 2002 23:27:03 -0800 Subject: [FB] Fix minor typos wrt readq/writeq support on 64-bit targets. --- drivers/video/cfbcopyarea.c | 2 +- include/linux/fb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index 43c030ff9ad7..f99a1692d5cb 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -38,7 +38,7 @@ #define BYTES_PER_LONG 4 #else #define FB_WRITEL fb_writeq -#define FB_READL fb_readq(x) +#define FB_READL fb_readq #define SHIFT_PER_LONG 6 #define BYTES_PER_LONG 8 #endif diff --git a/include/linux/fb.h b/include/linux/fb.h index 23dd4c02ddec..188da2f94589 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -424,9 +424,11 @@ struct fb_info { #define fb_readb __raw_readb #define fb_readw __raw_readw #define fb_readl __raw_readl +#define fb_readq __raw_readq #define fb_writeb __raw_writeb #define fb_writew __raw_writew #define fb_writel __raw_writel +#define fb_writeq __raw_writeq #define fb_memset memset_io #else -- cgit v1.2.3 From 1af3131d0c77394498c05b191267f9a7f8f8c225 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 25 Dec 2002 23:56:07 -0800 Subject: [FB] First cut at updating tgafb to 2.5 fb api. A large scale rewrite modeled off of skeletonfb.c. --- drivers/video/Makefile | 2 +- drivers/video/tgafb.c | 1499 ++++++++++++++++++++---------------------------- drivers/video/tgafb.h | 199 ------- include/video/tgafb.h | 210 +++++++ 4 files changed, 825 insertions(+), 1085 deletions(-) delete mode 100644 drivers/video/tgafb.h create mode 100644 include/video/tgafb.h diff --git a/drivers/video/Makefile b/drivers/video/Makefile index d9767337fe1f..96bf3caaebab 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -48,7 +48,7 @@ obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o obj-$(CONFIG_FB_CLGEN) += clgenfb.o obj-$(CONFIG_FB_TRIDENT) += tridentfb.o obj-$(CONFIG_FB_S3TRIO) += S3triofb.o -obj-$(CONFIG_FB_TGA) += tgafb.o +obj-$(CONFIG_FB_TGA) += tgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \ cfbimgblt.o vgastate.o diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 325f0ab1ae6c..2db3eced1d38 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -2,10 +2,10 @@ * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha - * + * * $Id: tgafb.c,v 1.12.2.3 2000/04/04 06:44:56 mato Exp $ * - * This driver is partly based on the original TGA framebuffer device, which + * This driver is partly based on the original TGA framebuffer device, which * was partly based on the original TGA console driver, which are * * Copyright (C) 1997 Geert Uytterhoeven @@ -28,982 +28,711 @@ * KNOWN PROBLEMS/TO DO ==================================================== */ #include -#include #include +#include #include #include #include #include #include -#include #include -#include -#include #include -#include +#include #include -#include +#include #include - -#include