diff options
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/Kconfig.debug | 16 | ||||
-rw-r--r-- | arch/um/Kconfig.x86 | 5 | ||||
-rw-r--r-- | arch/um/drivers/Makefile | 4 | ||||
-rw-r--r-- | arch/um/drivers/mcast.h | 24 | ||||
-rw-r--r-- | arch/um/drivers/mcast_kern.c | 120 | ||||
-rw-r--r-- | arch/um/drivers/mcast_user.c | 165 | ||||
-rw-r--r-- | arch/um/drivers/umcast.h | 27 | ||||
-rw-r--r-- | arch/um/drivers/umcast_kern.c | 188 | ||||
-rw-r--r-- | arch/um/drivers/umcast_user.c | 186 | ||||
-rw-r--r-- | arch/um/drivers/xterm.c | 2 | ||||
-rw-r--r-- | arch/um/include/asm/common.lds.S | 2 | ||||
-rw-r--r-- | arch/um/include/asm/processor-generic.h | 2 | ||||
-rw-r--r-- | arch/um/include/asm/smp.h | 1 | ||||
-rw-r--r-- | arch/um/include/asm/tlb.h | 29 | ||||
-rw-r--r-- | arch/um/include/shared/os.h | 7 | ||||
-rw-r--r-- | arch/um/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/um/kernel/early_printk.c | 33 | ||||
-rw-r--r-- | arch/um/kernel/smp.c | 3 | ||||
-rw-r--r-- | arch/um/kernel/trap.c | 24 | ||||
-rw-r--r-- | arch/um/os-Linux/main.c | 3 | ||||
-rw-r--r-- | arch/um/os-Linux/process.c | 1 | ||||
-rw-r--r-- | arch/um/os-Linux/util.c | 5 |
22 files changed, 500 insertions, 348 deletions
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index 8fce5e536b0f..68205fd3b08c 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug | |||
@@ -28,13 +28,13 @@ config GCOV | |||
28 | If you're involved in UML kernel development and want to use gcov, | 28 | If you're involved in UML kernel development and want to use gcov, |
29 | say Y. If you're unsure, say N. | 29 | say Y. If you're unsure, say N. |
30 | 30 | ||
31 | config DEBUG_STACK_USAGE | 31 | config EARLY_PRINTK |
32 | bool "Stack utilization instrumentation" | 32 | bool "Early printk" |
33 | default N | 33 | default y |
34 | help | 34 | ---help--- |
35 | Track the maximum kernel stack usage - this will look at each | 35 | Write kernel log output directly to stdout. |
36 | kernel stack at process exit and log it if it's the deepest | 36 | |
37 | stack seen so far. | 37 | This is useful for kernel debugging when your machine crashes very |
38 | early before the console code is initialized. | ||
38 | 39 | ||
39 | This option will slow down process creation and destruction somewhat. | ||
40 | endmenu | 40 | endmenu |
diff --git a/arch/um/Kconfig.x86 b/arch/um/Kconfig.x86 index a9da516a5274..8aae429a56e2 100644 --- a/arch/um/Kconfig.x86 +++ b/arch/um/Kconfig.x86 | |||
@@ -15,7 +15,6 @@ endmenu | |||
15 | config UML_X86 | 15 | config UML_X86 |
16 | def_bool y | 16 | def_bool y |
17 | select GENERIC_FIND_FIRST_BIT | 17 | select GENERIC_FIND_FIRST_BIT |
18 | select GENERIC_FIND_NEXT_BIT | ||
19 | 18 | ||
20 | config 64BIT | 19 | config 64BIT |
21 | bool | 20 | bool |
@@ -29,10 +28,10 @@ config X86_64 | |||
29 | def_bool 64BIT | 28 | def_bool 64BIT |
30 | 29 | ||
31 | config RWSEM_XCHGADD_ALGORITHM | 30 | config RWSEM_XCHGADD_ALGORITHM |
32 | def_bool X86_XADD | 31 | def_bool X86_XADD && 64BIT |
33 | 32 | ||
34 | config RWSEM_GENERIC_SPINLOCK | 33 | config RWSEM_GENERIC_SPINLOCK |
35 | def_bool !X86_XADD | 34 | def_bool !RWSEM_XCHGADD_ALGORITHM |
36 | 35 | ||
37 | config 3_LEVEL_PGTABLES | 36 | config 3_LEVEL_PGTABLES |
38 | bool "Three-level pagetables (EXPERIMENTAL)" if !64BIT | 37 | bool "Three-level pagetables (EXPERIMENTAL)" if !64BIT |
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index 1d9b6ae967b0..e7582e1d248c 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile | |||
@@ -9,7 +9,7 @@ | |||
9 | slip-objs := slip_kern.o slip_user.o | 9 | slip-objs := slip_kern.o slip_user.o |
10 | slirp-objs := slirp_kern.o slirp_user.o | 10 | slirp-objs := slirp_kern.o slirp_user.o |
11 | daemon-objs := daemon_kern.o daemon_user.o | 11 | daemon-objs := daemon_kern.o daemon_user.o |
12 | mcast-objs := mcast_kern.o mcast_user.o | 12 | umcast-objs := umcast_kern.o umcast_user.o |
13 | net-objs := net_kern.o net_user.o | 13 | net-objs := net_kern.o net_user.o |
14 | mconsole-objs := mconsole_kern.o mconsole_user.o | 14 | mconsole-objs := mconsole_kern.o mconsole_user.o |
15 | hostaudio-objs := hostaudio_kern.o | 15 | hostaudio-objs := hostaudio_kern.o |
@@ -44,7 +44,7 @@ obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o | |||
44 | obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o | 44 | obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o |
45 | obj-$(CONFIG_UML_NET_DAEMON) += daemon.o | 45 | obj-$(CONFIG_UML_NET_DAEMON) += daemon.o |
46 | obj-$(CONFIG_UML_NET_VDE) += vde.o | 46 | obj-$(CONFIG_UML_NET_VDE) += vde.o |
47 | obj-$(CONFIG_UML_NET_MCAST) += mcast.o | 47 | obj-$(CONFIG_UML_NET_MCAST) += umcast.o |
48 | obj-$(CONFIG_UML_NET_PCAP) += pcap.o | 48 | obj-$(CONFIG_UML_NET_PCAP) += pcap.o |
49 | obj-$(CONFIG_UML_NET) += net.o | 49 | obj-$(CONFIG_UML_NET) += net.o |
50 | obj-$(CONFIG_MCONSOLE) += mconsole.o | 50 | obj-$(CONFIG_MCONSOLE) += mconsole.o |
diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h deleted file mode 100644 index 6fa282e896be..000000000000 --- a/arch/um/drivers/mcast.h +++ /dev/null | |||
@@ -1,24 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __DRIVERS_MCAST_H | ||
7 | #define __DRIVERS_MCAST_H | ||
8 | |||
9 | #include "net_user.h" | ||
10 | |||
11 | struct mcast_data { | ||
12 | char *addr; | ||
13 | unsigned short port; | ||
14 | void *mcast_addr; | ||
15 | int ttl; | ||
16 | void *dev; | ||
17 | }; | ||
18 | |||
19 | extern const struct net_user_info mcast_user_info; | ||
20 | |||
21 | extern int mcast_user_write(int fd, void *buf, int len, | ||
22 | struct mcast_data *pri); | ||
23 | |||
24 | #endif | ||
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c deleted file mode 100644 index ffc6416d5ed7..000000000000 --- a/arch/um/drivers/mcast_kern.c +++ /dev/null | |||
@@ -1,120 +0,0 @@ | |||
1 | /* | ||
2 | * user-mode-linux networking multicast transport | ||
3 | * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> | ||
4 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
5 | * | ||
6 | * based on the existing uml-networking code, which is | ||
7 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and | ||
8 | * James Leu (jleu@mindspring.net). | ||
9 | * Copyright (C) 2001 by various other people who didn't put their name here. | ||
10 | * | ||
11 | * Licensed under the GPL. | ||
12 | */ | ||
13 | |||
14 | #include "linux/init.h" | ||
15 | #include <linux/netdevice.h> | ||
16 | #include "mcast.h" | ||
17 | #include "net_kern.h" | ||
18 | |||
19 | struct mcast_init { | ||
20 | char *addr; | ||
21 | int port; | ||
22 | int ttl; | ||
23 | }; | ||
24 | |||
25 | static void mcast_init(struct net_device *dev, void *data) | ||
26 | { | ||
27 | struct uml_net_private *pri; | ||
28 | struct mcast_data *dpri; | ||
29 | struct mcast_init *init = data; | ||
30 | |||
31 | pri = netdev_priv(dev); | ||
32 | dpri = (struct mcast_data *) pri->user; | ||
33 | dpri->addr = init->addr; | ||
34 | dpri->port = init->port; | ||
35 | dpri->ttl = init->ttl; | ||
36 | dpri->dev = dev; | ||
37 | |||
38 | printk("mcast backend multicast address: %s:%u, TTL:%u\n", | ||
39 | dpri->addr, dpri->port, dpri->ttl); | ||
40 | } | ||
41 | |||
42 | static int mcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) | ||
43 | { | ||
44 | return net_recvfrom(fd, skb_mac_header(skb), | ||
45 | skb->dev->mtu + ETH_HEADER_OTHER); | ||
46 | } | ||
47 | |||
48 | static int mcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) | ||
49 | { | ||
50 | return mcast_user_write(fd, skb->data, skb->len, | ||
51 | (struct mcast_data *) &lp->user); | ||
52 | } | ||
53 | |||
54 | static const struct net_kern_info mcast_kern_info = { | ||
55 | .init = mcast_init, | ||
56 | .protocol = eth_protocol, | ||
57 | .read = mcast_read, | ||
58 | .write = mcast_write, | ||
59 | }; | ||
60 | |||
61 | static int mcast_setup(char *str, char **mac_out, void *data) | ||
62 | { | ||
63 | struct mcast_init *init = data; | ||
64 | char *port_str = NULL, *ttl_str = NULL, *remain; | ||
65 | char *last; | ||
66 | |||
67 | *init = ((struct mcast_init) | ||
68 | { .addr = "239.192.168.1", | ||
69 | .port = 1102, | ||
70 | .ttl = 1 }); | ||
71 | |||
72 | remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str, | ||
73 | NULL); | ||
74 | if (remain != NULL) { | ||
75 | printk(KERN_ERR "mcast_setup - Extra garbage on " | ||
76 | "specification : '%s'\n", remain); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | if (port_str != NULL) { | ||
81 | init->port = simple_strtoul(port_str, &last, 10); | ||
82 | if ((*last != '\0') || (last == port_str)) { | ||
83 | printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", | ||
84 | port_str); | ||
85 | return 0; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | if (ttl_str != NULL) { | ||
90 | init->ttl = simple_strtoul(ttl_str, &last, 10); | ||
91 | if ((*last != '\0') || (last == ttl_str)) { | ||
92 | printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", | ||
93 | ttl_str); | ||
94 | return 0; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr, | ||
99 | init->port, init->ttl); | ||
100 | |||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | static struct transport mcast_transport = { | ||
105 | .list = LIST_HEAD_INIT(mcast_transport.list), | ||
106 | .name = "mcast", | ||
107 | .setup = mcast_setup, | ||
108 | .user = &mcast_user_info, | ||
109 | .kern = &mcast_kern_info, | ||
110 | .private_size = sizeof(struct mcast_data), | ||
111 | .setup_size = sizeof(struct mcast_init), | ||
112 | }; | ||
113 | |||
114 | static int register_mcast(void) | ||
115 | { | ||
116 | register_transport(&mcast_transport); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | late_initcall(register_mcast); | ||
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c deleted file mode 100644 index ee19e91568a2..000000000000 --- a/arch/um/drivers/mcast_user.c +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /* | ||
2 | * user-mode-linux networking multicast transport | ||
3 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
4 | * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> | ||
5 | * | ||
6 | * based on the existing uml-networking code, which is | ||
7 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and | ||
8 | * James Leu (jleu@mindspring.net). | ||
9 | * Copyright (C) 2001 by various other people who didn't put their name here. | ||
10 | * | ||
11 | * Licensed under the GPL. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <unistd.h> | ||
16 | #include <errno.h> | ||
17 | #include <netinet/in.h> | ||
18 | #include "kern_constants.h" | ||
19 | #include "mcast.h" | ||
20 | #include "net_user.h" | ||
21 | #include "um_malloc.h" | ||
22 | #include "user.h" | ||
23 | |||
24 | static struct sockaddr_in *new_addr(char *addr, unsigned short port) | ||
25 | { | ||
26 | struct sockaddr_in *sin; | ||
27 | |||
28 | sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL); | ||
29 | if (sin == NULL) { | ||
30 | printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in " | ||
31 | "failed\n"); | ||
32 | return NULL; | ||
33 | } | ||
34 | sin->sin_family = AF_INET; | ||
35 | sin->sin_addr.s_addr = in_aton(addr); | ||
36 | sin->sin_port = htons(port); | ||
37 | return sin; | ||
38 | } | ||
39 | |||
40 | static int mcast_user_init(void *data, void *dev) | ||
41 | { | ||
42 | struct mcast_data *pri = data; | ||
43 | |||
44 | pri->mcast_addr = new_addr(pri->addr, pri->port); | ||
45 | pri->dev = dev; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static void mcast_remove(void *data) | ||
50 | { | ||
51 | struct mcast_data *pri = data; | ||
52 | |||
53 | kfree(pri->mcast_addr); | ||
54 | pri->mcast_addr = NULL; | ||
55 | } | ||
56 | |||
57 | static int mcast_open(void *data) | ||
58 | { | ||
59 | struct mcast_data *pri = data; | ||
60 | struct sockaddr_in *sin = pri->mcast_addr; | ||
61 | struct ip_mreq mreq; | ||
62 | int fd, yes = 1, err = -EINVAL; | ||
63 | |||
64 | |||
65 | if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) | ||
66 | goto out; | ||
67 | |||
68 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
69 | |||
70 | if (fd < 0) { | ||
71 | err = -errno; | ||
72 | printk(UM_KERN_ERR "mcast_open : data socket failed, " | ||
73 | "errno = %d\n", errno); | ||
74 | goto out; | ||
75 | } | ||
76 | |||
77 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { | ||
78 | err = -errno; | ||
79 | printk(UM_KERN_ERR "mcast_open: SO_REUSEADDR failed, " | ||
80 | "errno = %d\n", errno); | ||
81 | goto out_close; | ||
82 | } | ||
83 | |||
84 | /* set ttl according to config */ | ||
85 | if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl, | ||
86 | sizeof(pri->ttl)) < 0) { | ||
87 | err = -errno; | ||
88 | printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_TTL failed, " | ||
89 | "error = %d\n", errno); | ||
90 | goto out_close; | ||
91 | } | ||
92 | |||
93 | /* set LOOP, so data does get fed back to local sockets */ | ||
94 | if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { | ||
95 | err = -errno; | ||
96 | printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_LOOP failed, " | ||
97 | "error = %d\n", errno); | ||
98 | goto out_close; | ||
99 | } | ||
100 | |||
101 | /* bind socket to mcast address */ | ||
102 | if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { | ||
103 | err = -errno; | ||
104 | printk(UM_KERN_ERR "mcast_open : data bind failed, " | ||
105 | "errno = %d\n", errno); | ||
106 | goto out_close; | ||
107 | } | ||
108 | |||
109 | /* subscribe to the multicast group */ | ||
110 | mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr; | ||
111 | mreq.imr_interface.s_addr = 0; | ||
112 | if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, | ||
113 | &mreq, sizeof(mreq)) < 0) { | ||
114 | err = -errno; | ||
115 | printk(UM_KERN_ERR "mcast_open: IP_ADD_MEMBERSHIP failed, " | ||
116 | "error = %d\n", errno); | ||
117 | printk(UM_KERN_ERR "There appears not to be a multicast-" | ||
118 | "capable network interface on the host.\n"); | ||
119 | printk(UM_KERN_ERR "eth0 should be configured in order to use " | ||
120 | "the multicast transport.\n"); | ||
121 | goto out_close; | ||
122 | } | ||
123 | |||
124 | return fd; | ||
125 | |||
126 | out_close: | ||
127 | close(fd); | ||
128 | out: | ||
129 | return err; | ||
130 | } | ||
131 | |||
132 | static void mcast_close(int fd, void *data) | ||
133 | { | ||
134 | struct ip_mreq mreq; | ||
135 | struct mcast_data *pri = data; | ||
136 | struct sockaddr_in *sin = pri->mcast_addr; | ||
137 | |||
138 | mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr; | ||
139 | mreq.imr_interface.s_addr = 0; | ||
140 | if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, | ||
141 | &mreq, sizeof(mreq)) < 0) { | ||
142 | printk(UM_KERN_ERR "mcast_open: IP_DROP_MEMBERSHIP failed, " | ||
143 | "error = %d\n", errno); | ||
144 | } | ||
145 | |||
146 | close(fd); | ||
147 | } | ||
148 | |||
149 | int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri) | ||
150 | { | ||
151 | struct sockaddr_in *data_addr = pri->mcast_addr; | ||
152 | |||
153 | return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); | ||
154 | } | ||
155 | |||
156 | const struct net_user_info mcast_user_info = { | ||
157 | .init = mcast_user_init, | ||
158 | .open = mcast_open, | ||
159 | .close = mcast_close, | ||
160 | .remove = mcast_remove, | ||
161 | .add_address = NULL, | ||
162 | .delete_address = NULL, | ||
163 | .mtu = ETH_MAX_PACKET, | ||
164 | .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, | ||
165 | }; | ||
diff --git a/arch/um/drivers/umcast.h b/arch/um/drivers/umcast.h new file mode 100644 index 000000000000..6f8c0fe890fb --- /dev/null +++ b/arch/um/drivers/umcast.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __DRIVERS_UMCAST_H | ||
7 | #define __DRIVERS_UMCAST_H | ||
8 | |||
9 | #include "net_user.h" | ||
10 | |||
11 | struct umcast_data { | ||
12 | char *addr; | ||
13 | unsigned short lport; | ||
14 | unsigned short rport; | ||
15 | void *listen_addr; | ||
16 | void *remote_addr; | ||
17 | int ttl; | ||
18 | int unicast; | ||
19 | void *dev; | ||
20 | }; | ||
21 | |||
22 | extern const struct net_user_info umcast_user_info; | ||
23 | |||
24 | extern int umcast_user_write(int fd, void *buf, int len, | ||
25 | struct umcast_data *pri); | ||
26 | |||
27 | #endif | ||
diff --git a/arch/um/drivers/umcast_kern.c b/arch/um/drivers/umcast_kern.c new file mode 100644 index 000000000000..42dab11d2ecf --- /dev/null +++ b/arch/um/drivers/umcast_kern.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * user-mode-linux networking multicast transport | ||
3 | * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> | ||
4 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
5 | * | ||
6 | * based on the existing uml-networking code, which is | ||
7 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and | ||
8 | * James Leu (jleu@mindspring.net). | ||
9 | * Copyright (C) 2001 by various other people who didn't put their name here. | ||
10 | * | ||
11 | * Licensed under the GPL. | ||
12 | */ | ||
13 | |||
14 | #include "linux/init.h" | ||
15 | #include <linux/netdevice.h> | ||
16 | #include "umcast.h" | ||
17 | #include "net_kern.h" | ||
18 | |||
19 | struct umcast_init { | ||
20 | char *addr; | ||
21 | int lport; | ||
22 | int rport; | ||
23 | int ttl; | ||
24 | bool unicast; | ||
25 | }; | ||
26 | |||
27 | static void umcast_init(struct net_device *dev, void *data) | ||
28 | { | ||
29 | struct uml_net_private *pri; | ||
30 | struct umcast_data *dpri; | ||
31 | struct umcast_init *init = data; | ||
32 | |||
33 | pri = netdev_priv(dev); | ||
34 | dpri = (struct umcast_data *) pri->user; | ||
35 | dpri->addr = init->addr; | ||
36 | dpri->lport = init->lport; | ||
37 | dpri->rport = init->rport; | ||
38 | dpri->unicast = init->unicast; | ||
39 | dpri->ttl = init->ttl; | ||
40 | dpri->dev = dev; | ||
41 | |||
42 | if (dpri->unicast) { | ||
43 | printk(KERN_INFO "ucast backend address: %s:%u listen port: " | ||
44 | "%u\n", dpri->addr, dpri->rport, dpri->lport); | ||
45 | } else { | ||
46 | printk(KERN_INFO "mcast backend multicast address: %s:%u, " | ||
47 | "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) | ||
52 | { | ||
53 | return net_recvfrom(fd, skb_mac_header(skb), | ||
54 | skb->dev->mtu + ETH_HEADER_OTHER); | ||
55 | } | ||
56 | |||
57 | static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) | ||
58 | { | ||
59 | return umcast_user_write(fd, skb->data, skb->len, | ||
60 | (struct umcast_data *) &lp->user); | ||
61 | } | ||
62 | |||
63 | static const struct net_kern_info umcast_kern_info = { | ||
64 | .init = umcast_init, | ||
65 | .protocol = eth_protocol, | ||
66 | .read = umcast_read, | ||
67 | .write = umcast_write, | ||
68 | }; | ||
69 | |||
70 | static int mcast_setup(char *str, char **mac_out, void *data) | ||
71 | { | ||
72 | struct umcast_init *init = data; | ||
73 | char *port_str = NULL, *ttl_str = NULL, *remain; | ||
74 | char *last; | ||
75 | |||
76 | *init = ((struct umcast_init) | ||
77 | { .addr = "239.192.168.1", | ||
78 | .lport = 1102, | ||
79 | .ttl = 1 }); | ||
80 | |||
81 | remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str, | ||
82 | NULL); | ||
83 | if (remain != NULL) { | ||
84 | printk(KERN_ERR "mcast_setup - Extra garbage on " | ||
85 | "specification : '%s'\n", remain); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | if (port_str != NULL) { | ||
90 | init->lport = simple_strtoul(port_str, &last, 10); | ||
91 | if ((*last != '\0') || (last == port_str)) { | ||
92 | printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", | ||
93 | port_str); | ||
94 | return 0; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | if (ttl_str != NULL) { | ||
99 | init->ttl = simple_strtoul(ttl_str, &last, 10); | ||
100 | if ((*last != '\0') || (last == ttl_str)) { | ||
101 | printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", | ||
102 | ttl_str); | ||
103 | return 0; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | init->unicast = false; | ||
108 | init->rport = init->lport; | ||
109 | |||
110 | printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr, | ||
111 | init->lport, init->ttl); | ||
112 | |||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | static int ucast_setup(char *str, char **mac_out, void *data) | ||
117 | { | ||
118 | struct umcast_init *init = data; | ||
119 | char *lport_str = NULL, *rport_str = NULL, *remain; | ||
120 | char *last; | ||
121 | |||
122 | *init = ((struct umcast_init) | ||
123 | { .addr = "", | ||
124 | .lport = 1102, | ||
125 | .rport = 1102 }); | ||
126 | |||
127 | remain = split_if_spec(str, mac_out, &init->addr, | ||
128 | &lport_str, &rport_str, NULL); | ||
129 | if (remain != NULL) { | ||
130 | printk(KERN_ERR "ucast_setup - Extra garbage on " | ||
131 | "specification : '%s'\n", remain); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | if (lport_str != NULL) { | ||
136 | init->lport = simple_strtoul(lport_str, &last, 10); | ||
137 | if ((*last != '\0') || (last == lport_str)) { | ||
138 | printk(KERN_ERR "ucast_setup - Bad listen port : " | ||
139 | "'%s'\n", lport_str); | ||
140 | return 0; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | if (rport_str != NULL) { | ||
145 | init->rport = simple_strtoul(rport_str, &last, 10); | ||
146 | if ((*last != '\0') || (last == rport_str)) { | ||
147 | printk(KERN_ERR "ucast_setup - Bad remote port : " | ||
148 | "'%s'\n", rport_str); | ||
149 | return 0; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | init->unicast = true; | ||
154 | |||
155 | printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n", | ||
156 | init->lport, init->addr, init->rport); | ||
157 | |||
158 | return 1; | ||
159 | } | ||
160 | |||
161 | static struct transport mcast_transport = { | ||
162 | .list = LIST_HEAD_INIT(mcast_transport.list), | ||
163 | .name = "mcast", | ||
164 | .setup = mcast_setup, | ||
165 | .user = &umcast_user_info, | ||
166 | .kern = &umcast_kern_info, | ||
167 | .private_size = sizeof(struct umcast_data), | ||
168 | .setup_size = sizeof(struct umcast_init), | ||
169 | }; | ||
170 | |||
171 | static struct transport ucast_transport = { | ||
172 | .list = LIST_HEAD_INIT(ucast_transport.list), | ||
173 | .name = "ucast", | ||
174 | .setup = ucast_setup, | ||
175 | .user = &umcast_user_info, | ||
176 | .kern = &umcast_kern_info, | ||
177 | .private_size = sizeof(struct umcast_data), | ||
178 | .setup_size = sizeof(struct umcast_init), | ||
179 | }; | ||
180 | |||
181 | static int register_umcast(void) | ||
182 | { | ||
183 | register_transport(&mcast_transport); | ||
184 | register_transport(&ucast_transport); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | late_initcall(register_umcast); | ||
diff --git a/arch/um/drivers/umcast_user.c b/arch/um/drivers/umcast_user.c new file mode 100644 index 000000000000..59c56fd6f52a --- /dev/null +++ b/arch/um/drivers/umcast_user.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * user-mode-linux networking multicast transport | ||
3 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
4 | * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> | ||
5 | * | ||
6 | * based on the existing uml-networking code, which is | ||
7 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and | ||
8 | * James Leu (jleu@mindspring.net). | ||
9 | * Copyright (C) 2001 by various other people who didn't put their name here. | ||
10 | * | ||
11 | * Licensed under the GPL. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <unistd.h> | ||
16 | #include <errno.h> | ||
17 | #include <netinet/in.h> | ||
18 | #include "kern_constants.h" | ||
19 | #include "umcast.h" | ||
20 | #include "net_user.h" | ||
21 | #include "um_malloc.h" | ||
22 | #include "user.h" | ||
23 | |||
24 | static struct sockaddr_in *new_addr(char *addr, unsigned short port) | ||
25 | { | ||
26 | struct sockaddr_in *sin; | ||
27 | |||
28 | sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL); | ||
29 | if (sin == NULL) { | ||
30 | printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in " | ||
31 | "failed\n"); | ||
32 | return NULL; | ||
33 | } | ||
34 | sin->sin_family = AF_INET; | ||
35 | if (addr) | ||
36 | sin->sin_addr.s_addr = in_aton(addr); | ||
37 | else | ||
38 | sin->sin_addr.s_addr = INADDR_ANY; | ||
39 | sin->sin_port = htons(port); | ||
40 | return sin; | ||
41 | } | ||
42 | |||
43 | static int umcast_user_init(void *data, void *dev) | ||
44 | { | ||
45 | struct umcast_data *pri = data; | ||
46 | |||
47 | pri->remote_addr = new_addr(pri->addr, pri->rport); | ||
48 | if (pri->unicast) | ||
49 | pri->listen_addr = new_addr(NULL, pri->lport); | ||
50 | else | ||
51 | pri->listen_addr = pri->remote_addr; | ||
52 | pri->dev = dev; | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static void umcast_remove(void *data) | ||
57 | { | ||
58 | struct umcast_data *pri = data; | ||
59 | |||
60 | kfree(pri->listen_addr); | ||
61 | if (pri->unicast) | ||
62 | kfree(pri->remote_addr); | ||
63 | pri->listen_addr = pri->remote_addr = NULL; | ||
64 | } | ||
65 | |||
66 | static int umcast_open(void *data) | ||
67 | { | ||
68 | struct umcast_data *pri = data; | ||
69 | struct sockaddr_in *lsin = pri->listen_addr; | ||
70 | struct sockaddr_in *rsin = pri->remote_addr; | ||
71 | struct ip_mreq mreq; | ||
72 | int fd, yes = 1, err = -EINVAL; | ||
73 | |||
74 | |||
75 | if ((!pri->unicast && lsin->sin_addr.s_addr == 0) || | ||
76 | (rsin->sin_addr.s_addr == 0) || | ||
77 | (lsin->sin_port == 0) || (rsin->sin_port == 0)) | ||
78 | goto out; | ||
79 | |||
80 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
81 | |||
82 | if (fd < 0) { | ||
83 | err = -errno; | ||
84 | printk(UM_KERN_ERR "umcast_open : data socket failed, " | ||
85 | "errno = %d\n", errno); | ||
86 | goto out; | ||
87 | } | ||
88 | |||
89 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { | ||
90 | err = -errno; | ||
91 | printk(UM_KERN_ERR "umcast_open: SO_REUSEADDR failed, " | ||
92 | "errno = %d\n", errno); | ||
93 | goto out_close; | ||
94 | } | ||
95 | |||
96 | if (!pri->unicast) { | ||
97 | /* set ttl according to config */ | ||
98 | if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl, | ||
99 | sizeof(pri->ttl)) < 0) { | ||
100 | err = -errno; | ||
101 | printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_TTL " | ||
102 | "failed, error = %d\n", errno); | ||
103 | goto out_close; | ||
104 | } | ||
105 | |||
106 | /* set LOOP, so data does get fed back to local sockets */ | ||
107 | if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, | ||
108 | &yes, sizeof(yes)) < 0) { | ||
109 | err = -errno; | ||
110 | printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_LOOP " | ||
111 | "failed, error = %d\n", errno); | ||
112 | goto out_close; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /* bind socket to the address */ | ||
117 | if (bind(fd, (struct sockaddr *) lsin, sizeof(*lsin)) < 0) { | ||
118 | err = -errno; | ||
119 | printk(UM_KERN_ERR "umcast_open : data bind failed, " | ||
120 | "errno = %d\n", errno); | ||
121 | goto out_close; | ||
122 | } | ||
123 | |||
124 | if (!pri->unicast) { | ||
125 | /* subscribe to the multicast group */ | ||
126 | mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr; | ||
127 | mreq.imr_interface.s_addr = 0; | ||
128 | if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, | ||
129 | &mreq, sizeof(mreq)) < 0) { | ||
130 | err = -errno; | ||
131 | printk(UM_KERN_ERR "umcast_open: IP_ADD_MEMBERSHIP " | ||
132 | "failed, error = %d\n", errno); | ||
133 | printk(UM_KERN_ERR "There appears not to be a " | ||
134 | "multicast-capable network interface on the " | ||
135 | "host.\n"); | ||
136 | printk(UM_KERN_ERR "eth0 should be configured in order " | ||
137 | "to use the multicast transport.\n"); | ||
138 | goto out_close; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | return fd; | ||
143 | |||
144 | out_close: | ||
145 | close(fd); | ||
146 | out: | ||
147 | return err; | ||
148 | } | ||
149 | |||
150 | static void umcast_close(int fd, void *data) | ||
151 | { | ||
152 | struct umcast_data *pri = data; | ||
153 | |||
154 | if (!pri->unicast) { | ||
155 | struct ip_mreq mreq; | ||
156 | struct sockaddr_in *lsin = pri->listen_addr; | ||
157 | |||
158 | mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr; | ||
159 | mreq.imr_interface.s_addr = 0; | ||
160 | if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, | ||
161 | &mreq, sizeof(mreq)) < 0) { | ||
162 | printk(UM_KERN_ERR "umcast_close: IP_DROP_MEMBERSHIP " | ||
163 | "failed, error = %d\n", errno); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | close(fd); | ||
168 | } | ||
169 | |||
170 | int umcast_user_write(int fd, void *buf, int len, struct umcast_data *pri) | ||
171 | { | ||
172 | struct sockaddr_in *data_addr = pri->remote_addr; | ||
173 | |||
174 | return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); | ||
175 | } | ||
176 | |||
177 | const struct net_user_info umcast_user_info = { | ||
178 | .init = umcast_user_init, | ||
179 | .open = umcast_open, | ||
180 | .close = umcast_close, | ||
181 | .remove = umcast_remove, | ||
182 | .add_address = NULL, | ||
183 | .delete_address = NULL, | ||
184 | .mtu = ETH_MAX_PACKET, | ||
185 | .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, | ||
186 | }; | ||
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index da2caa5a21ef..8ac7146c237f 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c | |||
@@ -90,7 +90,7 @@ static int xterm_open(int input, int output, int primary, void *d, | |||
90 | int pid, fd, new, err; | 90 | int pid, fd, new, err; |
91 | char title[256], file[] = "/tmp/xterm-pipeXXXXXX"; | 91 | char title[256], file[] = "/tmp/xterm-pipeXXXXXX"; |
92 | char *argv[] = { terminal_emulator, title_switch, title, exec_switch, | 92 | char *argv[] = { terminal_emulator, title_switch, title, exec_switch, |
93 | "/usr/lib/uml/port-helper", "-uml-socket", | 93 | OS_LIB_PATH "/uml/port-helper", "-uml-socket", |
94 | file, NULL }; | 94 | file, NULL }; |
95 | 95 | ||
96 | if (access(argv[4], X_OK) < 0) | 96 | if (access(argv[4], X_OK) < 0) |
diff --git a/arch/um/include/asm/common.lds.S b/arch/um/include/asm/common.lds.S index 34bede8aad4a..4938de5512d2 100644 --- a/arch/um/include/asm/common.lds.S +++ b/arch/um/include/asm/common.lds.S | |||
@@ -42,7 +42,7 @@ | |||
42 | INIT_SETUP(0) | 42 | INIT_SETUP(0) |
43 | } | 43 | } |
44 | 44 | ||
45 | PERCPU(32, 32) | 45 | PERCPU_SECTION(32) |
46 | 46 | ||
47 | .initcall.init : { | 47 | .initcall.init : { |
48 | INIT_CALLS | 48 | INIT_CALLS |
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index d1d1b0d8a0cd..98d01bc4fa92 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h | |||
@@ -14,6 +14,8 @@ struct task_struct; | |||
14 | #include "registers.h" | 14 | #include "registers.h" |
15 | #include "sysdep/archsetjmp.h" | 15 | #include "sysdep/archsetjmp.h" |
16 | 16 | ||
17 | #include <linux/prefetch.h> | ||
18 | |||
17 | struct mm_struct; | 19 | struct mm_struct; |
18 | 20 | ||
19 | struct thread_struct { | 21 | struct thread_struct { |
diff --git a/arch/um/include/asm/smp.h b/arch/um/include/asm/smp.h index f27a96313174..4a4b09d4f366 100644 --- a/arch/um/include/asm/smp.h +++ b/arch/um/include/asm/smp.h | |||
@@ -11,7 +11,6 @@ | |||
11 | 11 | ||
12 | #define cpu_logical_map(n) (n) | 12 | #define cpu_logical_map(n) (n) |
13 | #define cpu_number_map(n) (n) | 13 | #define cpu_number_map(n) (n) |
14 | #define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */ | ||
15 | extern int hard_smp_processor_id(void); | 14 | extern int hard_smp_processor_id(void); |
16 | #define NO_PROC_ID -1 | 15 | #define NO_PROC_ID -1 |
17 | 16 | ||
diff --git a/arch/um/include/asm/tlb.h b/arch/um/include/asm/tlb.h index 660caedac9eb..4febacd1a8a1 100644 --- a/arch/um/include/asm/tlb.h +++ b/arch/um/include/asm/tlb.h | |||
@@ -22,9 +22,6 @@ struct mmu_gather { | |||
22 | unsigned int fullmm; /* non-zero means full mm flush */ | 22 | unsigned int fullmm; /* non-zero means full mm flush */ |
23 | }; | 23 | }; |
24 | 24 | ||
25 | /* Users of the generic TLB shootdown code must declare this storage space. */ | ||
26 | DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); | ||
27 | |||
28 | static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, | 25 | static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, |
29 | unsigned long address) | 26 | unsigned long address) |
30 | { | 27 | { |
@@ -47,27 +44,20 @@ static inline void init_tlb_gather(struct mmu_gather *tlb) | |||
47 | } | 44 | } |
48 | } | 45 | } |
49 | 46 | ||
50 | /* tlb_gather_mmu | 47 | static inline void |
51 | * Return a pointer to an initialized struct mmu_gather. | 48 | tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush) |
52 | */ | ||
53 | static inline struct mmu_gather * | ||
54 | tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) | ||
55 | { | 49 | { |
56 | struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); | ||
57 | |||
58 | tlb->mm = mm; | 50 | tlb->mm = mm; |
59 | tlb->fullmm = full_mm_flush; | 51 | tlb->fullmm = full_mm_flush; |
60 | 52 | ||
61 | init_tlb_gather(tlb); | 53 | init_tlb_gather(tlb); |
62 | |||
63 | return tlb; | ||
64 | } | 54 | } |
65 | 55 | ||
66 | extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, | 56 | extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, |
67 | unsigned long end); | 57 | unsigned long end); |
68 | 58 | ||
69 | static inline void | 59 | static inline void |
70 | tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) | 60 | tlb_flush_mmu(struct mmu_gather *tlb) |
71 | { | 61 | { |
72 | if (!tlb->need_flush) | 62 | if (!tlb->need_flush) |
73 | return; | 63 | return; |
@@ -83,12 +73,10 @@ tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) | |||
83 | static inline void | 73 | static inline void |
84 | tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) | 74 | tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) |
85 | { | 75 | { |
86 | tlb_flush_mmu(tlb, start, end); | 76 | tlb_flush_mmu(tlb); |
87 | 77 | ||
88 | /* keep the page table cache within bounds */ | 78 | /* keep the page table cache within bounds */ |
89 | check_pgt_cache(); | 79 | check_pgt_cache(); |
90 | |||
91 | put_cpu_var(mmu_gathers); | ||
92 | } | 80 | } |
93 | 81 | ||
94 | /* tlb_remove_page | 82 | /* tlb_remove_page |
@@ -96,11 +84,16 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) | |||
96 | * while handling the additional races in SMP caused by other CPUs | 84 | * while handling the additional races in SMP caused by other CPUs |
97 | * caching valid mappings in their TLBs. | 85 | * caching valid mappings in their TLBs. |
98 | */ | 86 | */ |
99 | static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) | 87 | static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) |
100 | { | 88 | { |
101 | tlb->need_flush = 1; | 89 | tlb->need_flush = 1; |
102 | free_page_and_swap_cache(page); | 90 | free_page_and_swap_cache(page); |
103 | return; | 91 | return 1; /* avoid calling tlb_flush_mmu */ |
92 | } | ||
93 | |||
94 | static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) | ||
95 | { | ||
96 | __tlb_remove_page(tlb, page); | ||
104 | } | 97 | } |
105 | 98 | ||
106 | /** | 99 | /** |
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index c4617baaa4f2..83c7c2ecd614 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h | |||
@@ -29,6 +29,12 @@ | |||
29 | #define OS_ACC_R_OK 4 /* Test for read permission. */ | 29 | #define OS_ACC_R_OK 4 /* Test for read permission. */ |
30 | #define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ | 30 | #define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ |
31 | 31 | ||
32 | #ifdef CONFIG_64BIT | ||
33 | #define OS_LIB_PATH "/usr/lib64/" | ||
34 | #else | ||
35 | #define OS_LIB_PATH "/usr/lib/" | ||
36 | #endif | ||
37 | |||
32 | /* | 38 | /* |
33 | * types taken from stat_file() in hostfs_user.c | 39 | * types taken from stat_file() in hostfs_user.c |
34 | * (if they are wrong here, they are wrong there...). | 40 | * (if they are wrong here, they are wrong there...). |
@@ -238,6 +244,7 @@ extern int raw(int fd); | |||
238 | extern void setup_machinename(char *machine_out); | 244 | extern void setup_machinename(char *machine_out); |
239 | extern void setup_hostinfo(char *buf, int len); | 245 | extern void setup_hostinfo(char *buf, int len); |
240 | extern void os_dump_core(void) __attribute__ ((noreturn)); | 246 | extern void os_dump_core(void) __attribute__ ((noreturn)); |
247 | extern void um_early_printk(const char *s, unsigned int n); | ||
241 | 248 | ||
242 | /* time.c */ | 249 | /* time.c */ |
243 | extern void idle_sleep(unsigned long long nsecs); | 250 | extern void idle_sleep(unsigned long long nsecs); |
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 1119233597a1..c4491c15afb2 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile | |||
@@ -17,6 +17,7 @@ obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \ | |||
17 | obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o | 17 | obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o |
18 | obj-$(CONFIG_GPROF) += gprof_syms.o | 18 | obj-$(CONFIG_GPROF) += gprof_syms.o |
19 | obj-$(CONFIG_GCOV) += gmon_syms.o | 19 | obj-$(CONFIG_GCOV) += gmon_syms.o |
20 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||
20 | 21 | ||
21 | USER_OBJS := config.o | 22 | USER_OBJS := config.o |
22 | 23 | ||
diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c new file mode 100644 index 000000000000..ec649bf72f68 --- /dev/null +++ b/arch/um/kernel/early_printk.c | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/console.h> | ||
11 | #include <linux/init.h> | ||
12 | #include "os.h" | ||
13 | |||
14 | static void early_console_write(struct console *con, const char *s, unsigned int n) | ||
15 | { | ||
16 | um_early_printk(s, n); | ||
17 | } | ||
18 | |||
19 | static struct console early_console = { | ||
20 | .name = "earlycon", | ||
21 | .write = early_console_write, | ||
22 | .flags = CON_BOOT, | ||
23 | .index = -1, | ||
24 | }; | ||
25 | |||
26 | static int __init setup_early_printk(char *buf) | ||
27 | { | ||
28 | register_console(&early_console); | ||
29 | |||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | early_param("earlyprintk", setup_early_printk); | ||
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index eefb107d2d73..155206a66908 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c | |||
@@ -7,9 +7,6 @@ | |||
7 | #include "asm/pgalloc.h" | 7 | #include "asm/pgalloc.h" |
8 | #include "asm/tlb.h" | 8 | #include "asm/tlb.h" |
9 | 9 | ||
10 | /* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */ | ||
11 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | ||
12 | |||
13 | #ifdef CONFIG_SMP | 10 | #ifdef CONFIG_SMP |
14 | 11 | ||
15 | #include "linux/sched.h" | 12 | #include "linux/sched.h" |
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 637c6505dc00..8c7b8823d1f0 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c | |||
@@ -113,6 +113,27 @@ out_of_memory: | |||
113 | return 0; | 113 | return 0; |
114 | } | 114 | } |
115 | 115 | ||
116 | static void show_segv_info(struct uml_pt_regs *regs) | ||
117 | { | ||
118 | struct task_struct *tsk = current; | ||
119 | struct faultinfo *fi = UPT_FAULTINFO(regs); | ||
120 | |||
121 | if (!unhandled_signal(tsk, SIGSEGV)) | ||
122 | return; | ||
123 | |||
124 | if (!printk_ratelimit()) | ||
125 | return; | ||
126 | |||
127 | printk("%s%s[%d]: segfault at %lx ip %p sp %p error %x", | ||
128 | task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, | ||
129 | tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi), | ||
130 | (void *)UPT_IP(regs), (void *)UPT_SP(regs), | ||
131 | fi->error_code); | ||
132 | |||
133 | print_vma_addr(KERN_CONT " in ", UPT_IP(regs)); | ||
134 | printk(KERN_CONT "\n"); | ||
135 | } | ||
136 | |||
116 | static void bad_segv(struct faultinfo fi, unsigned long ip) | 137 | static void bad_segv(struct faultinfo fi, unsigned long ip) |
117 | { | 138 | { |
118 | struct siginfo si; | 139 | struct siginfo si; |
@@ -141,6 +162,7 @@ void segv_handler(int sig, struct uml_pt_regs *regs) | |||
141 | struct faultinfo * fi = UPT_FAULTINFO(regs); | 162 | struct faultinfo * fi = UPT_FAULTINFO(regs); |
142 | 163 | ||
143 | if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) { | 164 | if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) { |
165 | show_segv_info(regs); | ||
144 | bad_segv(*fi, UPT_IP(regs)); | 166 | bad_segv(*fi, UPT_IP(regs)); |
145 | return; | 167 | return; |
146 | } | 168 | } |
@@ -202,6 +224,8 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, | |||
202 | address, ip); | 224 | address, ip); |
203 | } | 225 | } |
204 | 226 | ||
227 | show_segv_info(regs); | ||
228 | |||
205 | if (err == -EACCES) { | 229 | if (err == -EACCES) { |
206 | si.si_signo = SIGBUS; | 230 | si.si_signo = SIGBUS; |
207 | si.si_errno = 0; | 231 | si.si_errno = 0; |
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index eee69b9f52c9..fb2a97a75fb1 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c | |||
@@ -78,7 +78,7 @@ static void install_fatal_handler(int sig) | |||
78 | } | 78 | } |
79 | } | 79 | } |
80 | 80 | ||
81 | #define UML_LIB_PATH ":/usr/lib/uml" | 81 | #define UML_LIB_PATH ":" OS_LIB_PATH "/uml" |
82 | 82 | ||
83 | static void setup_env_path(void) | 83 | static void setup_env_path(void) |
84 | { | 84 | { |
@@ -142,7 +142,6 @@ int __init main(int argc, char **argv, char **envp) | |||
142 | */ | 142 | */ |
143 | install_fatal_handler(SIGINT); | 143 | install_fatal_handler(SIGINT); |
144 | install_fatal_handler(SIGTERM); | 144 | install_fatal_handler(SIGTERM); |
145 | install_fatal_handler(SIGHUP); | ||
146 | 145 | ||
147 | scan_elf_aux(envp); | 146 | scan_elf_aux(envp); |
148 | 147 | ||
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index e0477c3ee894..0c45dc8efb05 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c | |||
@@ -253,6 +253,7 @@ void init_new_thread_signals(void) | |||
253 | SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, | 253 | SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, |
254 | SIGVTALRM, -1); | 254 | SIGVTALRM, -1); |
255 | signal(SIGWINCH, SIG_IGN); | 255 | signal(SIGWINCH, SIG_IGN); |
256 | signal(SIGTERM, SIG_DFL); | ||
256 | } | 257 | } |
257 | 258 | ||
258 | int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr) | 259 | int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr) |
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index 42827cafa6af..5803b1887672 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c | |||
@@ -139,3 +139,8 @@ void os_dump_core(void) | |||
139 | 139 | ||
140 | uml_abort(); | 140 | uml_abort(); |
141 | } | 141 | } |
142 | |||
143 | void um_early_printk(const char *s, unsigned int n) | ||
144 | { | ||
145 | printf("%.*s", n, s); | ||
146 | } | ||