diff options
author | David Teigland <teigland@redhat.com> | 2006-01-20 03:59:41 -0500 |
---|---|---|
committer | Steven Whitehouse <steve@chygwyn.com> | 2006-01-20 03:59:41 -0500 |
commit | 044399b2cb6ad2d7f63cfca945268853d7443a4d (patch) | |
tree | 5f96eb307b0389ac0b919a4744a40862b615e9da /arch/um | |
parent | 901359256b2666f52a3a7d3f31927677e91b3a2a (diff) | |
parent | 18a4144028f056b77d6576d4eb284246e9c7ea97 (diff) |
Merge branch 'master'
Diffstat (limited to 'arch/um')
66 files changed, 1558 insertions, 778 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 8ff3bcbce5fc..5982fe2753e0 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig | |||
@@ -143,6 +143,7 @@ config HOSTFS | |||
143 | 143 | ||
144 | config HPPFS | 144 | config HPPFS |
145 | tristate "HoneyPot ProcFS (EXPERIMENTAL)" | 145 | tristate "HoneyPot ProcFS (EXPERIMENTAL)" |
146 | depends on EXPERIMENTAL | ||
146 | help | 147 | help |
147 | hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc | 148 | hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc |
148 | entries to be overridden, removed, or fabricated from the host. | 149 | entries to be overridden, removed, or fabricated from the host. |
@@ -155,10 +156,6 @@ config HPPFS | |||
155 | You only need this if you are setting up a UML honeypot. Otherwise, | 156 | You only need this if you are setting up a UML honeypot. Otherwise, |
156 | it is safe to say 'N' here. | 157 | it is safe to say 'N' here. |
157 | 158 | ||
158 | If you are actively using it, please report any problems, since it's | ||
159 | getting fixed. In this moment, it is experimental on 2.6 (it works on | ||
160 | 2.4). | ||
161 | |||
162 | config MCONSOLE | 159 | config MCONSOLE |
163 | bool "Management console" | 160 | bool "Management console" |
164 | default y | 161 | default y |
@@ -243,8 +240,16 @@ config NEST_LEVEL | |||
243 | Only change this if you are running nested UMLs. | 240 | Only change this if you are running nested UMLs. |
244 | 241 | ||
245 | config HIGHMEM | 242 | config HIGHMEM |
246 | bool "Highmem support" | 243 | bool "Highmem support (EXPERIMENTAL)" |
247 | depends on !64BIT | 244 | depends on !64BIT && EXPERIMENTAL |
245 | default n | ||
246 | help | ||
247 | This was used to allow UML to run with big amounts of memory. | ||
248 | Currently it is unstable, so if unsure say N. | ||
249 | |||
250 | To use big amounts of memory, it is recommended to disable TT mode (i.e. | ||
251 | CONFIG_MODE_TT) and enable static linking (i.e. CONFIG_STATIC_LINK) - | ||
252 | this should allow the guest to use up to 2.75G of memory. | ||
248 | 253 | ||
249 | config KERNEL_STACK_ORDER | 254 | config KERNEL_STACK_ORDER |
250 | int "Kernel stack size order" | 255 | int "Kernel stack size order" |
@@ -269,17 +274,13 @@ endmenu | |||
269 | 274 | ||
270 | source "init/Kconfig" | 275 | source "init/Kconfig" |
271 | 276 | ||
272 | source "net/Kconfig" | 277 | source "drivers/block/Kconfig" |
273 | |||
274 | source "drivers/base/Kconfig" | ||
275 | 278 | ||
276 | source "arch/um/Kconfig.char" | 279 | source "arch/um/Kconfig.char" |
277 | 280 | ||
278 | source "drivers/block/Kconfig" | 281 | source "drivers/base/Kconfig" |
279 | 282 | ||
280 | config NETDEVICES | 283 | source "net/Kconfig" |
281 | bool | ||
282 | default NET | ||
283 | 284 | ||
284 | source "arch/um/Kconfig.net" | 285 | source "arch/um/Kconfig.net" |
285 | 286 | ||
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386 index c71b39a677aa..ef79ed25aecd 100644 --- a/arch/um/Kconfig.i386 +++ b/arch/um/Kconfig.i386 | |||
@@ -22,13 +22,17 @@ config TOP_ADDR | |||
22 | default 0x80000000 if HOST_2G_2G | 22 | default 0x80000000 if HOST_2G_2G |
23 | 23 | ||
24 | config 3_LEVEL_PGTABLES | 24 | config 3_LEVEL_PGTABLES |
25 | bool "Three-level pagetables" | 25 | bool "Three-level pagetables (EXPERIMENTAL)" |
26 | default n | 26 | default n |
27 | depends on EXPERIMENTAL | ||
27 | help | 28 | help |
28 | Three-level pagetables will let UML have more than 4G of physical | 29 | Three-level pagetables will let UML have more than 4G of physical |
29 | memory. All the memory that can't be mapped directly will be treated | 30 | memory. All the memory that can't be mapped directly will be treated |
30 | as high memory. | 31 | as high memory. |
31 | 32 | ||
33 | However, this it experimental on 32-bit architectures, so if unsure say | ||
34 | N (on x86-64 it's automatically enabled, instead, as it's safe there). | ||
35 | |||
32 | config STUB_CODE | 36 | config STUB_CODE |
33 | hex | 37 | hex |
34 | default 0xbfffe000 | 38 | default 0xbfffe000 |
diff --git a/arch/um/Makefile b/arch/um/Makefile index 45435ff589c1..6430a6383853 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile | |||
@@ -32,7 +32,7 @@ um-modes-$(CONFIG_MODE_TT) += tt | |||
32 | um-modes-$(CONFIG_MODE_SKAS) += skas | 32 | um-modes-$(CONFIG_MODE_SKAS) += skas |
33 | 33 | ||
34 | MODE_INCLUDE += $(foreach mode,$(um-modes-y),\ | 34 | MODE_INCLUDE += $(foreach mode,$(um-modes-y),\ |
35 | -I$(srctree)/$(ARCH_DIR)/kernel/$(mode)/include) | 35 | -I$(srctree)/$(ARCH_DIR)/include/$(mode)) |
36 | 36 | ||
37 | MAKEFILES-INCL += $(foreach mode,$(um-modes-y),\ | 37 | MAKEFILES-INCL += $(foreach mode,$(um-modes-y),\ |
38 | $(srctree)/$(ARCH_DIR)/Makefile-$(mode)) | 38 | $(srctree)/$(ARCH_DIR)/Makefile-$(mode)) |
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index 30d285b266af..507e3cbac9d3 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c | |||
@@ -31,6 +31,10 @@ void daemon_init(struct net_device *dev, void *data) | |||
31 | dpri->fd = -1; | 31 | dpri->fd = -1; |
32 | dpri->control = -1; | 32 | dpri->control = -1; |
33 | dpri->dev = dev; | 33 | dpri->dev = dev; |
34 | /* We will free this pointer. If it contains crap we're burned. */ | ||
35 | dpri->ctl_addr = NULL; | ||
36 | dpri->data_addr = NULL; | ||
37 | dpri->local_addr = NULL; | ||
34 | 38 | ||
35 | printk("daemon backend (uml_switch version %d) - %s:%s", | 39 | printk("daemon backend (uml_switch version %d) - %s:%s", |
36 | SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock); | 40 | SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock); |
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c index 1bb085b2824d..c944265955e2 100644 --- a/arch/um/drivers/daemon_user.c +++ b/arch/um/drivers/daemon_user.c | |||
@@ -158,10 +158,16 @@ static void daemon_remove(void *data) | |||
158 | struct daemon_data *pri = data; | 158 | struct daemon_data *pri = data; |
159 | 159 | ||
160 | os_close_file(pri->fd); | 160 | os_close_file(pri->fd); |
161 | pri->fd = -1; | ||
161 | os_close_file(pri->control); | 162 | os_close_file(pri->control); |
163 | pri->control = -1; | ||
164 | |||
162 | kfree(pri->data_addr); | 165 | kfree(pri->data_addr); |
166 | pri->data_addr = NULL; | ||
163 | kfree(pri->ctl_addr); | 167 | kfree(pri->ctl_addr); |
168 | pri->ctl_addr = NULL; | ||
164 | kfree(pri->local_addr); | 169 | kfree(pri->local_addr); |
170 | pri->local_addr = NULL; | ||
165 | } | 171 | } |
166 | 172 | ||
167 | int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri) | 173 | int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri) |
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index 3296e86a03a5..c41f75e4acb5 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "user.h" | 11 | #include "user.h" |
12 | #include "user_util.h" | 12 | #include "user_util.h" |
13 | #include "chan_user.h" | 13 | #include "chan_user.h" |
14 | #include "os.h" | ||
14 | 15 | ||
15 | struct fd_chan { | 16 | struct fd_chan { |
16 | int fd; | 17 | int fd; |
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index fb1f9fb9b871..8ebb2241ad42 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c | |||
@@ -68,6 +68,11 @@ static int uml_net_rx(struct net_device *dev) | |||
68 | return pkt_len; | 68 | return pkt_len; |
69 | } | 69 | } |
70 | 70 | ||
71 | static void uml_dev_close(void* dev) | ||
72 | { | ||
73 | dev_close( (struct net_device *) dev); | ||
74 | } | ||
75 | |||
71 | irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 76 | irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
72 | { | 77 | { |
73 | struct net_device *dev = dev_id; | 78 | struct net_device *dev = dev_id; |
@@ -80,15 +85,21 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
80 | spin_lock(&lp->lock); | 85 | spin_lock(&lp->lock); |
81 | while((err = uml_net_rx(dev)) > 0) ; | 86 | while((err = uml_net_rx(dev)) > 0) ; |
82 | if(err < 0) { | 87 | if(err < 0) { |
88 | DECLARE_WORK(close_work, uml_dev_close, dev); | ||
83 | printk(KERN_ERR | 89 | printk(KERN_ERR |
84 | "Device '%s' read returned %d, shutting it down\n", | 90 | "Device '%s' read returned %d, shutting it down\n", |
85 | dev->name, err); | 91 | dev->name, err); |
86 | dev_close(dev); | 92 | /* dev_close can't be called in interrupt context, and takes |
93 | * again lp->lock. | ||
94 | * And dev_close() can be safely called multiple times on the | ||
95 | * same device, since it tests for (dev->flags & IFF_UP). So | ||
96 | * there's no harm in delaying the device shutdown. */ | ||
97 | schedule_work(&close_work); | ||
87 | goto out; | 98 | goto out; |
88 | } | 99 | } |
89 | reactivate_fd(lp->fd, UM_ETH_IRQ); | 100 | reactivate_fd(lp->fd, UM_ETH_IRQ); |
90 | 101 | ||
91 | out: | 102 | out: |
92 | spin_unlock(&lp->lock); | 103 | spin_unlock(&lp->lock); |
93 | return(IRQ_HANDLED); | 104 | return(IRQ_HANDLED); |
94 | } | 105 | } |
@@ -317,6 +328,11 @@ static int eth_configure(int n, void *init, char *mac, | |||
317 | return 1; | 328 | return 1; |
318 | } | 329 | } |
319 | 330 | ||
331 | lp = dev->priv; | ||
332 | /* This points to the transport private data. It's still clear, but we | ||
333 | * must memset it to 0 *now*. Let's help the drivers. */ | ||
334 | memset(lp, 0, size); | ||
335 | |||
320 | /* sysfs register */ | 336 | /* sysfs register */ |
321 | if (!driver_registered) { | 337 | if (!driver_registered) { |
322 | platform_driver_register(¨_net_driver); | 338 | platform_driver_register(¨_net_driver); |
@@ -358,7 +374,6 @@ static int eth_configure(int n, void *init, char *mac, | |||
358 | free_netdev(dev); | 374 | free_netdev(dev); |
359 | return 1; | 375 | return 1; |
360 | } | 376 | } |
361 | lp = dev->priv; | ||
362 | 377 | ||
363 | /* lp.user is the first four bytes of the transport data, which | 378 | /* lp.user is the first four bytes of the transport data, which |
364 | * has already been initialized. This structure assignment will | 379 | * has already been initialized. This structure assignment will |
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 7696f8d2d89c..101efd26d467 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -1103,31 +1103,33 @@ static int ubd_ioctl(struct inode * inode, struct file * file, | |||
1103 | return(-EINVAL); | 1103 | return(-EINVAL); |
1104 | } | 1104 | } |
1105 | 1105 | ||
1106 | static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) | 1106 | static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) |
1107 | { | 1107 | { |
1108 | struct uml_stat buf1, buf2; | 1108 | struct uml_stat buf1, buf2; |
1109 | int err; | 1109 | int err; |
1110 | 1110 | ||
1111 | if(from_cmdline == NULL) return(1); | 1111 | if(from_cmdline == NULL) |
1112 | if(!strcmp(from_cmdline, from_cow)) return(1); | 1112 | return 0; |
1113 | if(!strcmp(from_cmdline, from_cow)) | ||
1114 | return 0; | ||
1113 | 1115 | ||
1114 | err = os_stat_file(from_cmdline, &buf1); | 1116 | err = os_stat_file(from_cmdline, &buf1); |
1115 | if(err < 0){ | 1117 | if(err < 0){ |
1116 | printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err); | 1118 | printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err); |
1117 | return(1); | 1119 | return 0; |
1118 | } | 1120 | } |
1119 | err = os_stat_file(from_cow, &buf2); | 1121 | err = os_stat_file(from_cow, &buf2); |
1120 | if(err < 0){ | 1122 | if(err < 0){ |
1121 | printk("Couldn't stat '%s', err = %d\n", from_cow, -err); | 1123 | printk("Couldn't stat '%s', err = %d\n", from_cow, -err); |
1122 | return(1); | 1124 | return 1; |
1123 | } | 1125 | } |
1124 | if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) | 1126 | if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) |
1125 | return(1); | 1127 | return 0; |
1126 | 1128 | ||
1127 | printk("Backing file mismatch - \"%s\" requested,\n" | 1129 | printk("Backing file mismatch - \"%s\" requested,\n" |
1128 | "\"%s\" specified in COW header of \"%s\"\n", | 1130 | "\"%s\" specified in COW header of \"%s\"\n", |
1129 | from_cmdline, from_cow, cow); | 1131 | from_cmdline, from_cow, cow); |
1130 | return(0); | 1132 | return 1; |
1131 | } | 1133 | } |
1132 | 1134 | ||
1133 | static int backing_file_mismatch(char *file, __u64 size, time_t mtime) | 1135 | static int backing_file_mismatch(char *file, __u64 size, time_t mtime) |
@@ -1189,18 +1191,19 @@ int open_ubd_file(char *file, struct openflags *openflags, | |||
1189 | unsigned long long size; | 1191 | unsigned long long size; |
1190 | __u32 version, align; | 1192 | __u32 version, align; |
1191 | char *backing_file; | 1193 | char *backing_file; |
1192 | int fd, err, sectorsize, same, mode = 0644; | 1194 | int fd, err, sectorsize, asked_switch, mode = 0644; |
1193 | 1195 | ||
1194 | fd = os_open_file(file, *openflags, mode); | 1196 | fd = os_open_file(file, *openflags, mode); |
1195 | if(fd < 0){ | 1197 | if (fd < 0) { |
1196 | if((fd == -ENOENT) && (create_cow_out != NULL)) | 1198 | if ((fd == -ENOENT) && (create_cow_out != NULL)) |
1197 | *create_cow_out = 1; | 1199 | *create_cow_out = 1; |
1198 | if(!openflags->w || | 1200 | if (!openflags->w || |
1199 | ((fd != -EROFS) && (fd != -EACCES))) return(fd); | 1201 | ((fd != -EROFS) && (fd != -EACCES))) |
1202 | return fd; | ||
1200 | openflags->w = 0; | 1203 | openflags->w = 0; |
1201 | fd = os_open_file(file, *openflags, mode); | 1204 | fd = os_open_file(file, *openflags, mode); |
1202 | if(fd < 0) | 1205 | if (fd < 0) |
1203 | return(fd); | 1206 | return fd; |
1204 | } | 1207 | } |
1205 | 1208 | ||
1206 | err = os_lock_file(fd, openflags->w); | 1209 | err = os_lock_file(fd, openflags->w); |
@@ -1209,7 +1212,9 @@ int open_ubd_file(char *file, struct openflags *openflags, | |||
1209 | goto out_close; | 1212 | goto out_close; |
1210 | } | 1213 | } |
1211 | 1214 | ||
1212 | if(backing_file_out == NULL) return(fd); | 1215 | /* Succesful return case! */ |
1216 | if(backing_file_out == NULL) | ||
1217 | return(fd); | ||
1213 | 1218 | ||
1214 | err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, | 1219 | err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, |
1215 | &size, §orsize, &align, bitmap_offset_out); | 1220 | &size, §orsize, &align, bitmap_offset_out); |
@@ -1218,34 +1223,34 @@ int open_ubd_file(char *file, struct openflags *openflags, | |||
1218 | "errno = %d\n", file, -err); | 1223 | "errno = %d\n", file, -err); |
1219 | goto out_close; | 1224 | goto out_close; |
1220 | } | 1225 | } |
1221 | if(err) return(fd); | 1226 | if(err) |
1222 | 1227 | return(fd); | |
1223 | if(backing_file_out == NULL) return(fd); | ||
1224 | 1228 | ||
1225 | same = same_backing_files(*backing_file_out, backing_file, file); | 1229 | asked_switch = path_requires_switch(*backing_file_out, backing_file, file); |
1226 | 1230 | ||
1227 | if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){ | 1231 | /* Allow switching only if no mismatch. */ |
1232 | if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) { | ||
1228 | printk("Switching backing file to '%s'\n", *backing_file_out); | 1233 | printk("Switching backing file to '%s'\n", *backing_file_out); |
1229 | err = write_cow_header(file, fd, *backing_file_out, | 1234 | err = write_cow_header(file, fd, *backing_file_out, |
1230 | sectorsize, align, &size); | 1235 | sectorsize, align, &size); |
1231 | if(err){ | 1236 | if (err) { |
1232 | printk("Switch failed, errno = %d\n", -err); | 1237 | printk("Switch failed, errno = %d\n", -err); |
1233 | return(err); | 1238 | goto out_close; |
1234 | } | 1239 | } |
1235 | } | 1240 | } else { |
1236 | else { | ||
1237 | *backing_file_out = backing_file; | 1241 | *backing_file_out = backing_file; |
1238 | err = backing_file_mismatch(*backing_file_out, size, mtime); | 1242 | err = backing_file_mismatch(*backing_file_out, size, mtime); |
1239 | if(err) goto out_close; | 1243 | if (err) |
1244 | goto out_close; | ||
1240 | } | 1245 | } |
1241 | 1246 | ||
1242 | cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, | 1247 | cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, |
1243 | bitmap_len_out, data_offset_out); | 1248 | bitmap_len_out, data_offset_out); |
1244 | 1249 | ||
1245 | return(fd); | 1250 | return fd; |
1246 | out_close: | 1251 | out_close: |
1247 | os_close_file(fd); | 1252 | os_close_file(fd); |
1248 | return(err); | 1253 | return err; |
1249 | } | 1254 | } |
1250 | 1255 | ||
1251 | int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, | 1256 | int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, |
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 8f4e46d677ab..c649108a9e9f 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h | |||
@@ -120,8 +120,10 @@ extern void machine_halt(void); | |||
120 | extern int is_syscall(unsigned long addr); | 120 | extern int is_syscall(unsigned long addr); |
121 | extern void arch_switch(void); | 121 | extern void arch_switch(void); |
122 | extern void free_irq(unsigned int, void *); | 122 | extern void free_irq(unsigned int, void *); |
123 | extern int um_in_interrupt(void); | ||
124 | extern int cpu(void); | 123 | extern int cpu(void); |
124 | |||
125 | /* Are we disallowed to sleep? Used to choose between GFP_KERNEL and GFP_ATOMIC. */ | ||
126 | extern int __cant_sleep(void); | ||
125 | extern void segv_handler(int sig, union uml_pt_regs *regs); | 127 | extern void segv_handler(int sig, union uml_pt_regs *regs); |
126 | extern void sigio_handler(int sig, union uml_pt_regs *regs); | 128 | extern void sigio_handler(int sig, union uml_pt_regs *regs); |
127 | 129 | ||
diff --git a/arch/um/include/longjmp.h b/arch/um/include/longjmp.h new file mode 100644 index 000000000000..018b3819ab0b --- /dev/null +++ b/arch/um/include/longjmp.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef __UML_LONGJMP_H | ||
2 | #define __UML_LONGJMP_H | ||
3 | |||
4 | #include <setjmp.h> | ||
5 | #include "os.h" | ||
6 | |||
7 | #define UML_SIGLONGJMP(buf, val) do { \ | ||
8 | longjmp(*buf, val); \ | ||
9 | } while(0) | ||
10 | |||
11 | #define UML_SIGSETJMP(buf, enable) ({ \ | ||
12 | int n; \ | ||
13 | enable = get_signals(); \ | ||
14 | n = setjmp(*buf); \ | ||
15 | if(n != 0) \ | ||
16 | set_signals(enable); \ | ||
17 | n; }) | ||
18 | |||
19 | #endif | ||
diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h index 2d88afd0cf16..e7539a8451ef 100644 --- a/arch/um/include/mode_kern.h +++ b/arch/um/include/mode_kern.h | |||
@@ -9,22 +9,11 @@ | |||
9 | #include "linux/config.h" | 9 | #include "linux/config.h" |
10 | 10 | ||
11 | #ifdef CONFIG_MODE_TT | 11 | #ifdef CONFIG_MODE_TT |
12 | #include "mode_kern-tt.h" | 12 | #include "mode_kern_tt.h" |
13 | #endif | 13 | #endif |
14 | 14 | ||
15 | #ifdef CONFIG_MODE_SKAS | 15 | #ifdef CONFIG_MODE_SKAS |
16 | #include "mode_kern-skas.h" | 16 | #include "mode_kern_skas.h" |
17 | #endif | 17 | #endif |
18 | 18 | ||
19 | #endif | 19 | #endif |
20 | |||
21 | /* | ||
22 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
23 | * Emacs will notice this stuff at the end of the file and automatically | ||
24 | * adjust the settings for this buffer only. This must remain at the end | ||
25 | * of the file. | ||
26 | * --------------------------------------------------------------------------- | ||
27 | * Local variables: | ||
28 | * c-file-style: "linux" | ||
29 | * End: | ||
30 | */ | ||
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index dd72d66cf0ed..eb1710b81255 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "../os/include/file.h" | 11 | #include "../os/include/file.h" |
12 | #include "sysdep/ptrace.h" | 12 | #include "sysdep/ptrace.h" |
13 | #include "kern_util.h" | 13 | #include "kern_util.h" |
14 | #include "skas/mm_id.h" | ||
14 | 15 | ||
15 | #define OS_TYPE_FILE 1 | 16 | #define OS_TYPE_FILE 1 |
16 | #define OS_TYPE_DIR 2 | 17 | #define OS_TYPE_DIR 2 |
@@ -190,11 +191,12 @@ extern int os_protect_memory(void *addr, unsigned long len, | |||
190 | int r, int w, int x); | 191 | int r, int w, int x); |
191 | extern int os_unmap_memory(void *addr, int len); | 192 | extern int os_unmap_memory(void *addr, int len); |
192 | extern void os_flush_stdout(void); | 193 | extern void os_flush_stdout(void); |
193 | extern unsigned long long os_usecs(void); | ||
194 | 194 | ||
195 | /* tt.c | 195 | /* tt.c |
196 | * for tt mode only (will be deleted in future...) | 196 | * for tt mode only (will be deleted in future...) |
197 | */ | 197 | */ |
198 | extern void stop(void); | ||
199 | extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); | ||
198 | extern int protect_memory(unsigned long addr, unsigned long len, | 200 | extern int protect_memory(unsigned long addr, unsigned long len, |
199 | int r, int w, int x, int must_succeed); | 201 | int r, int w, int x, int must_succeed); |
200 | extern void forward_pending_sigio(int target); | 202 | extern void forward_pending_sigio(int target); |
@@ -230,9 +232,63 @@ extern void block_signals(void); | |||
230 | extern void unblock_signals(void); | 232 | extern void unblock_signals(void); |
231 | extern int get_signals(void); | 233 | extern int get_signals(void); |
232 | extern int set_signals(int enable); | 234 | extern int set_signals(int enable); |
235 | extern void os_usr1_signal(int on); | ||
233 | 236 | ||
234 | /* trap.c */ | 237 | /* trap.c */ |
235 | extern void os_fill_handlinfo(struct kern_handlers h); | 238 | extern void os_fill_handlinfo(struct kern_handlers h); |
236 | extern void do_longjmp(void *p, int val); | 239 | extern void do_longjmp(void *p, int val); |
237 | 240 | ||
241 | /* util.c */ | ||
242 | extern void stack_protections(unsigned long address); | ||
243 | extern void task_protections(unsigned long address); | ||
244 | extern int raw(int fd); | ||
245 | extern void setup_machinename(char *machine_out); | ||
246 | extern void setup_hostinfo(void); | ||
247 | extern int setjmp_wrapper(void (*proc)(void *, void *), ...); | ||
248 | |||
249 | /* time.c */ | ||
250 | #define BILLION (1000 * 1000 * 1000) | ||
251 | |||
252 | extern void switch_timers(int to_real); | ||
253 | extern void idle_sleep(int secs); | ||
254 | extern void enable_timer(void); | ||
255 | extern void disable_timer(void); | ||
256 | extern void user_time_init(void); | ||
257 | extern void uml_idle_timer(void); | ||
258 | extern unsigned long long os_nsecs(void); | ||
259 | |||
260 | /* skas/mem.c */ | ||
261 | extern long run_syscall_stub(struct mm_id * mm_idp, | ||
262 | int syscall, unsigned long *args, long expected, | ||
263 | void **addr, int done); | ||
264 | extern long syscall_stub_data(struct mm_id * mm_idp, | ||
265 | unsigned long *data, int data_count, | ||
266 | void **addr, void **stub_addr); | ||
267 | extern int map(struct mm_id * mm_idp, unsigned long virt, | ||
268 | unsigned long len, int r, int w, int x, int phys_fd, | ||
269 | unsigned long long offset, int done, void **data); | ||
270 | extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, | ||
271 | int done, void **data); | ||
272 | extern int protect(struct mm_id * mm_idp, unsigned long addr, | ||
273 | unsigned long len, int r, int w, int x, int done, | ||
274 | void **data); | ||
275 | |||
276 | /* skas/process.c */ | ||
277 | extern int is_skas_winch(int pid, int fd, void *data); | ||
278 | extern int start_userspace(unsigned long stub_stack); | ||
279 | extern int copy_context_skas0(unsigned long stack, int pid); | ||
280 | extern void userspace(union uml_pt_regs *regs); | ||
281 | extern void map_stub_pages(int fd, unsigned long code, | ||
282 | unsigned long data, unsigned long stack); | ||
283 | extern void new_thread(void *stack, void **switch_buf_ptr, | ||
284 | void **fork_buf_ptr, void (*handler)(int)); | ||
285 | extern void thread_wait(void *sw, void *fb); | ||
286 | extern void switch_threads(void *me, void *next); | ||
287 | extern int start_idle_thread(void *stack, void *switch_buf_ptr, | ||
288 | void **fork_buf_ptr); | ||
289 | extern void initial_thread_cb_skas(void (*proc)(void *), | ||
290 | void *arg); | ||
291 | extern void halt_skas(void); | ||
292 | extern void reboot_skas(void); | ||
293 | |||
238 | #endif | 294 | #endif |
diff --git a/arch/um/kernel/skas/include/mm_id.h b/arch/um/include/skas/mm_id.h index 48dd0989ddaa..48dd0989ddaa 100644 --- a/arch/um/kernel/skas/include/mm_id.h +++ b/arch/um/include/skas/mm_id.h | |||
diff --git a/arch/um/include/skas/mmu-skas.h b/arch/um/include/skas/mmu-skas.h new file mode 100644 index 000000000000..d8869a6ef1b4 --- /dev/null +++ b/arch/um/include/skas/mmu-skas.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SKAS_MMU_H | ||
7 | #define __SKAS_MMU_H | ||
8 | |||
9 | #include "linux/config.h" | ||
10 | #include "mm_id.h" | ||
11 | #include "asm/ldt.h" | ||
12 | |||
13 | struct mmu_context_skas { | ||
14 | struct mm_id id; | ||
15 | unsigned long last_page_table; | ||
16 | #ifdef CONFIG_3_LEVEL_PGTABLES | ||
17 | unsigned long last_pmd; | ||
18 | #endif | ||
19 | uml_ldt_t ldt; | ||
20 | }; | ||
21 | |||
22 | extern void switch_mm_skas(struct mm_id * mm_idp); | ||
23 | |||
24 | #endif | ||
diff --git a/arch/um/include/skas/mode-skas.h b/arch/um/include/skas/mode-skas.h new file mode 100644 index 000000000000..260065cfeef1 --- /dev/null +++ b/arch/um/include/skas/mode-skas.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __MODE_SKAS_H__ | ||
7 | #define __MODE_SKAS_H__ | ||
8 | |||
9 | #include <sysdep/ptrace.h> | ||
10 | |||
11 | extern unsigned long exec_regs[]; | ||
12 | extern unsigned long exec_fp_regs[]; | ||
13 | extern unsigned long exec_fpx_regs[]; | ||
14 | extern int have_fpx_regs; | ||
15 | |||
16 | extern void sig_handler_common_skas(int sig, void *sc_ptr); | ||
17 | extern void kill_off_processes_skas(void); | ||
18 | |||
19 | #endif | ||
diff --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/include/skas/mode_kern_skas.h index c97a80dfe370..63c58739bde0 100644 --- a/arch/um/kernel/skas/include/mode_kern-skas.h +++ b/arch/um/include/skas/mode_kern_skas.h | |||
@@ -18,7 +18,6 @@ extern int copy_thread_skas(int nr, unsigned long clone_flags, | |||
18 | unsigned long sp, unsigned long stack_top, | 18 | unsigned long sp, unsigned long stack_top, |
19 | struct task_struct *p, struct pt_regs *regs); | 19 | struct task_struct *p, struct pt_regs *regs); |
20 | extern void release_thread_skas(struct task_struct *task); | 20 | extern void release_thread_skas(struct task_struct *task); |
21 | extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); | ||
22 | extern void init_idle_skas(void); | 21 | extern void init_idle_skas(void); |
23 | extern void flush_tlb_kernel_range_skas(unsigned long start, | 22 | extern void flush_tlb_kernel_range_skas(unsigned long start, |
24 | unsigned long end); | 23 | unsigned long end); |
@@ -39,14 +38,3 @@ extern int thread_pid_skas(struct task_struct *task); | |||
39 | #define kmem_end_skas (host_task_size - 1024 * 1024) | 38 | #define kmem_end_skas (host_task_size - 1024 * 1024) |
40 | 39 | ||
41 | #endif | 40 | #endif |
42 | |||
43 | /* | ||
44 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
45 | * Emacs will notice this stuff at the end of the file and automatically | ||
46 | * adjust the settings for this buffer only. This must remain at the end | ||
47 | * of the file. | ||
48 | * --------------------------------------------------------------------------- | ||
49 | * Local variables: | ||
50 | * c-file-style: "linux" | ||
51 | * End: | ||
52 | */ | ||
diff --git a/arch/um/kernel/skas/include/proc_mm.h b/arch/um/include/skas/proc_mm.h index cce61a679052..902809209603 100644 --- a/arch/um/kernel/skas/include/proc_mm.h +++ b/arch/um/include/skas/proc_mm.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -22,13 +22,13 @@ struct mm_mmap { | |||
22 | 22 | ||
23 | struct mm_munmap { | 23 | struct mm_munmap { |
24 | unsigned long addr; | 24 | unsigned long addr; |
25 | unsigned long len; | 25 | unsigned long len; |
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct mm_mprotect { | 28 | struct mm_mprotect { |
29 | unsigned long addr; | 29 | unsigned long addr; |
30 | unsigned long len; | 30 | unsigned long len; |
31 | unsigned int prot; | 31 | unsigned int prot; |
32 | }; | 32 | }; |
33 | 33 | ||
34 | struct proc_mm_op { | 34 | struct proc_mm_op { |
@@ -42,14 +42,3 @@ struct proc_mm_op { | |||
42 | }; | 42 | }; |
43 | 43 | ||
44 | #endif | 44 | #endif |
45 | |||
46 | /* | ||
47 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
48 | * Emacs will notice this stuff at the end of the file and automatically | ||
49 | * adjust the settings for this buffer only. This must remain at the end | ||
50 | * of the file. | ||
51 | * --------------------------------------------------------------------------- | ||
52 | * Local variables: | ||
53 | * c-file-style: "linux" | ||
54 | * End: | ||
55 | */ | ||
diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h new file mode 100644 index 000000000000..86357282d681 --- /dev/null +++ b/arch/um/include/skas/skas.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SKAS_H | ||
7 | #define __SKAS_H | ||
8 | |||
9 | #include "mm_id.h" | ||
10 | #include "sysdep/ptrace.h" | ||
11 | |||
12 | extern int userspace_pid[]; | ||
13 | extern int proc_mm, ptrace_faultinfo, ptrace_ldt; | ||
14 | extern int skas_needs_stub; | ||
15 | |||
16 | extern int user_thread(unsigned long stack, int flags); | ||
17 | extern void new_thread_proc(void *stack, void (*handler)(int sig)); | ||
18 | extern void new_thread_handler(int sig); | ||
19 | extern void handle_syscall(union uml_pt_regs *regs); | ||
20 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); | ||
21 | extern int new_mm(unsigned long stack); | ||
22 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); | ||
23 | extern long execute_syscall_skas(void *r); | ||
24 | extern unsigned long current_stub_stack(void); | ||
25 | |||
26 | #endif | ||
diff --git a/arch/um/kernel/skas/include/stub-data.h b/arch/um/include/skas/stub-data.h index f6ed92c3727d..f6ed92c3727d 100644 --- a/arch/um/kernel/skas/include/stub-data.h +++ b/arch/um/include/skas/stub-data.h | |||
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/include/skas/uaccess-skas.h index 64516c556cdf..224a75f4c025 100644 --- a/arch/um/kernel/skas/include/uaccess-skas.h +++ b/arch/um/include/skas/uaccess-skas.h | |||
@@ -19,14 +19,3 @@ extern int clear_user_skas(void __user *mem, int len); | |||
19 | extern int strnlen_user_skas(const void __user *str, int len); | 19 | extern int strnlen_user_skas(const void __user *str, int len); |
20 | 20 | ||
21 | #endif | 21 | #endif |
22 | |||
23 | /* | ||
24 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
25 | * Emacs will notice this stuff at the end of the file and automatically | ||
26 | * adjust the settings for this buffer only. This must remain at the end | ||
27 | * of the file. | ||
28 | * --------------------------------------------------------------------------- | ||
29 | * Local variables: | ||
30 | * c-file-style: "linux" | ||
31 | * End: | ||
32 | */ | ||
diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h deleted file mode 100644 index 17d7ef2141f4..000000000000 --- a/arch/um/include/time_user.h +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __TIME_USER_H__ | ||
7 | #define __TIME_USER_H__ | ||
8 | |||
9 | extern void timer(void); | ||
10 | extern void switch_timers(int to_real); | ||
11 | extern void idle_sleep(int secs); | ||
12 | extern void enable_timer(void); | ||
13 | extern void prepare_timer(void * ptr); | ||
14 | extern void disable_timer(void); | ||
15 | extern unsigned long time_lock(void); | ||
16 | extern void time_unlock(unsigned long); | ||
17 | extern void user_time_init(void); | ||
18 | |||
19 | #endif | ||
diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/include/tt/debug.h index 738435461e13..9778fa838296 100644 --- a/arch/um/kernel/tt/include/debug.h +++ b/arch/um/include/tt/debug.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and | 2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and |
3 | * Lars Brinkhoff. | 3 | * Lars Brinkhoff. |
4 | * Licensed under the GPL | 4 | * Licensed under the GPL |
diff --git a/arch/um/include/tt/mmu-tt.h b/arch/um/include/tt/mmu-tt.h new file mode 100644 index 000000000000..572a78b22587 --- /dev/null +++ b/arch/um/include/tt/mmu-tt.h | |||
@@ -0,0 +1,12 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __TT_MMU_H | ||
7 | #define __TT_MMU_H | ||
8 | |||
9 | struct mmu_context_tt { | ||
10 | }; | ||
11 | |||
12 | #endif | ||
diff --git a/arch/um/include/tt/mode-tt.h b/arch/um/include/tt/mode-tt.h new file mode 100644 index 000000000000..2823cd56eea2 --- /dev/null +++ b/arch/um/include/tt/mode-tt.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __MODE_TT_H__ | ||
7 | #define __MODE_TT_H__ | ||
8 | |||
9 | #include "sysdep/ptrace.h" | ||
10 | |||
11 | enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; | ||
12 | |||
13 | extern int tracing_pid; | ||
14 | |||
15 | extern int tracer(int (*init_proc)(void *), void *sp); | ||
16 | extern void sig_handler_common_tt(int sig, void *sc); | ||
17 | extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); | ||
18 | extern void reboot_tt(void); | ||
19 | extern void halt_tt(void); | ||
20 | extern int is_tracer_winch(int pid, int fd, void *data); | ||
21 | extern void kill_off_processes_tt(void); | ||
22 | |||
23 | #endif | ||
diff --git a/arch/um/include/tt/mode_kern_tt.h b/arch/um/include/tt/mode_kern_tt.h new file mode 100644 index 000000000000..efa0012550d0 --- /dev/null +++ b/arch/um/include/tt/mode_kern_tt.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __TT_MODE_KERN_H__ | ||
7 | #define __TT_MODE_KERN_H__ | ||
8 | |||
9 | #include "linux/sched.h" | ||
10 | #include "asm/page.h" | ||
11 | #include "asm/ptrace.h" | ||
12 | #include "asm/uaccess.h" | ||
13 | |||
14 | extern void switch_to_tt(void *prev, void *next); | ||
15 | extern void flush_thread_tt(void); | ||
16 | extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, | ||
17 | unsigned long esp); | ||
18 | extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, | ||
19 | unsigned long stack_top, struct task_struct *p, | ||
20 | struct pt_regs *regs); | ||
21 | extern void release_thread_tt(struct task_struct *task); | ||
22 | extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); | ||
23 | extern void init_idle_tt(void); | ||
24 | extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end); | ||
25 | extern void flush_tlb_kernel_vm_tt(void); | ||
26 | extern void __flush_tlb_one_tt(unsigned long addr); | ||
27 | extern void flush_tlb_range_tt(struct vm_area_struct *vma, | ||
28 | unsigned long start, unsigned long end); | ||
29 | extern void flush_tlb_mm_tt(struct mm_struct *mm); | ||
30 | extern void force_flush_all_tt(void); | ||
31 | extern long execute_syscall_tt(void *r); | ||
32 | extern void before_mem_tt(unsigned long brk_start); | ||
33 | extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, | ||
34 | unsigned long *task_size_out); | ||
35 | extern int start_uml_tt(void); | ||
36 | extern int external_pid_tt(struct task_struct *task); | ||
37 | extern int thread_pid_tt(struct task_struct *task); | ||
38 | |||
39 | #define kmem_end_tt (host_task_size - ABOVE_KMEM) | ||
40 | |||
41 | #endif | ||
diff --git a/arch/um/kernel/tt/include/tt.h b/arch/um/include/tt/tt.h index c667b67af405..808521980186 100644 --- a/arch/um/kernel/tt/include/tt.h +++ b/arch/um/include/tt/tt.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -34,13 +34,3 @@ extern long execute_syscall_tt(void *r); | |||
34 | 34 | ||
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | /* | ||
38 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
39 | * Emacs will notice this stuff at the end of the file and automatically | ||
40 | * adjust the settings for this buffer only. This must remain at the end | ||
41 | * of the file. | ||
42 | * --------------------------------------------------------------------------- | ||
43 | * Local variables: | ||
44 | * c-file-style: "linux" | ||
45 | * End: | ||
46 | */ | ||
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/include/tt/uaccess-tt.h index b9bfe9c481c4..b19645f32f24 100644 --- a/arch/um/kernel/tt/include/uaccess-tt.h +++ b/arch/um/include/tt/uaccess-tt.h | |||
@@ -46,14 +46,3 @@ extern int clear_user_tt(void __user *mem, int len); | |||
46 | extern int strnlen_user_tt(const void __user *str, int len); | 46 | extern int strnlen_user_tt(const void __user *str, int len); |
47 | 47 | ||
48 | #endif | 48 | #endif |
49 | |||
50 | /* | ||
51 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
52 | * Emacs will notice this stuff at the end of the file and automatically | ||
53 | * adjust the settings for this buffer only. This must remain at the end | ||
54 | * of the file. | ||
55 | * --------------------------------------------------------------------------- | ||
56 | * Local variables: | ||
57 | * c-file-style: "linux" | ||
58 | * End: | ||
59 | */ | ||
diff --git a/arch/um/include/user.h b/arch/um/include/user.h index 0f865ef46918..91b0ac4ad88c 100644 --- a/arch/um/include/user.h +++ b/arch/um/include/user.h | |||
@@ -18,6 +18,7 @@ extern int open_gdb_chan(void); | |||
18 | extern unsigned long strlcpy(char *, const char *, unsigned long); | 18 | extern unsigned long strlcpy(char *, const char *, unsigned long); |
19 | extern unsigned long strlcat(char *, const char *, unsigned long); | 19 | extern unsigned long strlcat(char *, const char *, unsigned long); |
20 | extern void *um_vmalloc(int size); | 20 | extern void *um_vmalloc(int size); |
21 | extern void *um_vmalloc_atomic(int size); | ||
21 | extern void vfree(void *ptr); | 22 | extern void vfree(void *ptr); |
22 | 23 | ||
23 | #endif | 24 | #endif |
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index c1dbd77b073f..a6f1f176cf84 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h | |||
@@ -44,10 +44,6 @@ extern unsigned long brk_start; | |||
44 | extern int pty_output_sigio; | 44 | extern int pty_output_sigio; |
45 | extern int pty_close_sigio; | 45 | extern int pty_close_sigio; |
46 | 46 | ||
47 | extern void stop(void); | ||
48 | extern void stack_protections(unsigned long address); | ||
49 | extern void task_protections(unsigned long address); | ||
50 | extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); | ||
51 | extern void *add_signal_handler(int sig, void (*handler)(int)); | 47 | extern void *add_signal_handler(int sig, void (*handler)(int)); |
52 | extern int linux_main(int argc, char **argv); | 48 | extern int linux_main(int argc, char **argv); |
53 | extern void set_cmdline(char *cmd); | 49 | extern void set_cmdline(char *cmd); |
@@ -55,8 +51,6 @@ extern void input_cb(void (*proc)(void *), void *arg, int arg_len); | |||
55 | extern int get_pty(void); | 51 | extern int get_pty(void); |
56 | extern void *um_kmalloc(int size); | 52 | extern void *um_kmalloc(int size); |
57 | extern int switcheroo(int fd, int prot, void *from, void *to, int size); | 53 | extern int switcheroo(int fd, int prot, void *from, void *to, int size); |
58 | extern void setup_machinename(char *machine_out); | ||
59 | extern void setup_hostinfo(void); | ||
60 | extern void do_exec(int old_pid, int new_pid); | 54 | extern void do_exec(int old_pid, int new_pid); |
61 | extern void tracer_panic(char *msg, ...); | 55 | extern void tracer_panic(char *msg, ...); |
62 | extern int detach(int pid, int sig); | 56 | extern int detach(int pid, int sig); |
@@ -70,18 +64,6 @@ extern int cpu_feature(char *what, char *buf, int len); | |||
70 | extern int arch_handle_signal(int sig, union uml_pt_regs *regs); | 64 | extern int arch_handle_signal(int sig, union uml_pt_regs *regs); |
71 | extern int arch_fixup(unsigned long address, void *sc_ptr); | 65 | extern int arch_fixup(unsigned long address, void *sc_ptr); |
72 | extern void arch_init_thread(void); | 66 | extern void arch_init_thread(void); |
73 | extern int setjmp_wrapper(void (*proc)(void *, void *), ...); | ||
74 | extern int raw(int fd); | 67 | extern int raw(int fd); |
75 | 68 | ||
76 | #endif | 69 | #endif |
77 | |||
78 | /* | ||
79 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
80 | * Emacs will notice this stuff at the end of the file and automatically | ||
81 | * adjust the settings for this buffer only. This must remain at the end | ||
82 | * of the file. | ||
83 | * --------------------------------------------------------------------------- | ||
84 | * Local variables: | ||
85 | * c-file-style: "linux" | ||
86 | * End: | ||
87 | */ | ||
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 193cc2b7448d..693018ba80f1 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile | |||
@@ -9,9 +9,8 @@ clean-files := | |||
9 | obj-y = config.o exec_kern.o exitcode.o \ | 9 | obj-y = config.o exec_kern.o exitcode.o \ |
10 | init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \ | 10 | init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \ |
11 | process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ | 11 | process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ |
12 | signal_kern.o smp.o syscall_kern.o sysrq.o time.o \ | 12 | signal_kern.o smp.o syscall_kern.o sysrq.o \ |
13 | time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o \ | 13 | time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o |
14 | user_util.o | ||
15 | 14 | ||
16 | obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o | 15 | obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o |
17 | obj-$(CONFIG_GPROF) += gprof_syms.o | 16 | obj-$(CONFIG_GPROF) += gprof_syms.o |
@@ -24,7 +23,7 @@ obj-$(CONFIG_MODE_SKAS) += skas/ | |||
24 | 23 | ||
25 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o | 24 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o |
26 | 25 | ||
27 | USER_OBJS := $(user-objs-y) config.o time.o tty_log.o user_util.o | 26 | USER_OBJS := $(user-objs-y) config.o tty_log.o |
28 | 27 | ||
29 | include arch/um/scripts/Makefile.rules | 28 | include arch/um/scripts/Makefile.rules |
30 | 29 | ||
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index efd222ffe20e..569fe8b9b053 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include "irq_user.h" | 17 | #include "irq_user.h" |
18 | #include "tlb.h" | 18 | #include "tlb.h" |
19 | #include "os.h" | 19 | #include "os.h" |
20 | #include "time_user.h" | ||
21 | #include "choose-mode.h" | 20 | #include "choose-mode.h" |
22 | #include "mode_kern.h" | 21 | #include "mode_kern.h" |
23 | 22 | ||
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 7f13b85d2656..3113cab8675e 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include "init.h" | 39 | #include "init.h" |
40 | #include "irq_user.h" | 40 | #include "irq_user.h" |
41 | #include "mem_user.h" | 41 | #include "mem_user.h" |
42 | #include "time_user.h" | ||
43 | #include "tlb.h" | 42 | #include "tlb.h" |
44 | #include "frame_kern.h" | 43 | #include "frame_kern.h" |
45 | #include "sigcontext.h" | 44 | #include "sigcontext.h" |
@@ -288,17 +287,27 @@ EXPORT_SYMBOL(disable_hlt); | |||
288 | 287 | ||
289 | void *um_kmalloc(int size) | 288 | void *um_kmalloc(int size) |
290 | { | 289 | { |
291 | return(kmalloc(size, GFP_KERNEL)); | 290 | return kmalloc(size, GFP_KERNEL); |
292 | } | 291 | } |
293 | 292 | ||
294 | void *um_kmalloc_atomic(int size) | 293 | void *um_kmalloc_atomic(int size) |
295 | { | 294 | { |
296 | return(kmalloc(size, GFP_ATOMIC)); | 295 | return kmalloc(size, GFP_ATOMIC); |
297 | } | 296 | } |
298 | 297 | ||
299 | void *um_vmalloc(int size) | 298 | void *um_vmalloc(int size) |
300 | { | 299 | { |
301 | return(vmalloc(size)); | 300 | return vmalloc(size); |
301 | } | ||
302 | |||
303 | void *um_vmalloc_atomic(int size) | ||
304 | { | ||
305 | return __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, PAGE_KERNEL); | ||
306 | } | ||
307 | |||
308 | int __cant_sleep(void) { | ||
309 | return in_atomic() || irqs_disabled() || in_interrupt(); | ||
310 | /* Is in_interrupt() really needed? */ | ||
302 | } | 311 | } |
303 | 312 | ||
304 | unsigned long get_fault_addr(void) | 313 | unsigned long get_fault_addr(void) |
@@ -370,11 +379,6 @@ int smp_sigio_handler(void) | |||
370 | return(0); | 379 | return(0); |
371 | } | 380 | } |
372 | 381 | ||
373 | int um_in_interrupt(void) | ||
374 | { | ||
375 | return(in_interrupt()); | ||
376 | } | ||
377 | |||
378 | int cpu(void) | 382 | int cpu(void) |
379 | { | 383 | { |
380 | return(current_thread->cpu); | 384 | return(current_thread->cpu); |
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index 62e5cfdf2188..f7b18e157d35 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c | |||
@@ -337,70 +337,103 @@ int ignore_sigio_fd(int fd) | |||
337 | return(err); | 337 | return(err); |
338 | } | 338 | } |
339 | 339 | ||
340 | static int setup_initial_poll(int fd) | 340 | static struct pollfd* setup_initial_poll(int fd) |
341 | { | 341 | { |
342 | struct pollfd *p; | 342 | struct pollfd *p; |
343 | 343 | ||
344 | p = um_kmalloc_atomic(sizeof(struct pollfd)); | 344 | p = um_kmalloc(sizeof(struct pollfd)); |
345 | if(p == NULL){ | 345 | if (p == NULL) { |
346 | printk("setup_initial_poll : failed to allocate poll\n"); | 346 | printk("setup_initial_poll : failed to allocate poll\n"); |
347 | return(-1); | 347 | return NULL; |
348 | } | 348 | } |
349 | *p = ((struct pollfd) { .fd = fd, | 349 | *p = ((struct pollfd) { .fd = fd, |
350 | .events = POLLIN, | 350 | .events = POLLIN, |
351 | .revents = 0 }); | 351 | .revents = 0 }); |
352 | current_poll = ((struct pollfds) { .poll = p, | 352 | return p; |
353 | .used = 1, | ||
354 | .size = 1 }); | ||
355 | return(0); | ||
356 | } | 353 | } |
357 | 354 | ||
358 | void write_sigio_workaround(void) | 355 | void write_sigio_workaround(void) |
359 | { | 356 | { |
360 | unsigned long stack; | 357 | unsigned long stack; |
358 | struct pollfd *p; | ||
361 | int err; | 359 | int err; |
360 | int l_write_sigio_fds[2]; | ||
361 | int l_sigio_private[2]; | ||
362 | int l_write_sigio_pid; | ||
362 | 363 | ||
364 | /* We call this *tons* of times - and most ones we must just fail. */ | ||
363 | sigio_lock(); | 365 | sigio_lock(); |
364 | if(write_sigio_pid != -1) | 366 | l_write_sigio_pid = write_sigio_pid; |
365 | goto out; | 367 | sigio_unlock(); |
366 | 368 | ||
367 | err = os_pipe(write_sigio_fds, 1, 1); | 369 | if (l_write_sigio_pid != -1) |
370 | return; | ||
371 | |||
372 | err = os_pipe(l_write_sigio_fds, 1, 1); | ||
368 | if(err < 0){ | 373 | if(err < 0){ |
369 | printk("write_sigio_workaround - os_pipe 1 failed, " | 374 | printk("write_sigio_workaround - os_pipe 1 failed, " |
370 | "err = %d\n", -err); | 375 | "err = %d\n", -err); |
371 | goto out; | 376 | return; |
372 | } | 377 | } |
373 | err = os_pipe(sigio_private, 1, 1); | 378 | err = os_pipe(l_sigio_private, 1, 1); |
374 | if(err < 0){ | 379 | if(err < 0){ |
375 | printk("write_sigio_workaround - os_pipe 2 failed, " | 380 | printk("write_sigio_workaround - os_pipe 1 failed, " |
376 | "err = %d\n", -err); | 381 | "err = %d\n", -err); |
377 | goto out_close1; | 382 | goto out_close1; |
378 | } | 383 | } |
379 | if(setup_initial_poll(sigio_private[1])) | 384 | |
385 | p = setup_initial_poll(l_sigio_private[1]); | ||
386 | if(!p) | ||
380 | goto out_close2; | 387 | goto out_close2; |
381 | 388 | ||
382 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | 389 | sigio_lock(); |
390 | |||
391 | /* Did we race? Don't try to optimize this, please, it's not so likely | ||
392 | * to happen, and no more than once at the boot. */ | ||
393 | if(write_sigio_pid != -1) | ||
394 | goto out_unlock; | ||
395 | |||
396 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | ||
383 | CLONE_FILES | CLONE_VM, &stack, 0); | 397 | CLONE_FILES | CLONE_VM, &stack, 0); |
384 | 398 | ||
385 | if(write_sigio_pid < 0) goto out_close2; | 399 | if (write_sigio_pid < 0) |
400 | goto out_clear; | ||
386 | 401 | ||
387 | if(write_sigio_irq(write_sigio_fds[0])) | 402 | if (write_sigio_irq(l_write_sigio_fds[0])) |
388 | goto out_kill; | 403 | goto out_kill; |
389 | 404 | ||
390 | out: | 405 | /* Success, finally. */ |
406 | memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); | ||
407 | memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); | ||
408 | |||
409 | current_poll = ((struct pollfds) { .poll = p, | ||
410 | .used = 1, | ||
411 | .size = 1 }); | ||
412 | |||
391 | sigio_unlock(); | 413 | sigio_unlock(); |
392 | return; | 414 | return; |
393 | 415 | ||
394 | out_kill: | 416 | out_kill: |
395 | os_kill_process(write_sigio_pid, 1); | 417 | l_write_sigio_pid = write_sigio_pid; |
396 | write_sigio_pid = -1; | 418 | write_sigio_pid = -1; |
419 | sigio_unlock(); | ||
420 | /* Going to call waitpid, avoid holding the lock. */ | ||
421 | os_kill_process(l_write_sigio_pid, 1); | ||
422 | goto out_free; | ||
423 | |||
424 | out_clear: | ||
425 | write_sigio_pid = -1; | ||
426 | out_unlock: | ||
427 | sigio_unlock(); | ||
428 | out_free: | ||
429 | kfree(p); | ||
397 | out_close2: | 430 | out_close2: |
398 | os_close_file(sigio_private[0]); | 431 | os_close_file(l_sigio_private[0]); |
399 | os_close_file(sigio_private[1]); | 432 | os_close_file(l_sigio_private[1]); |
400 | out_close1: | 433 | out_close1: |
401 | os_close_file(write_sigio_fds[0]); | 434 | os_close_file(l_write_sigio_fds[0]); |
402 | os_close_file(write_sigio_fds[1]); | 435 | os_close_file(l_write_sigio_fds[1]); |
403 | sigio_unlock(); | 436 | return; |
404 | } | 437 | } |
405 | 438 | ||
406 | int read_sigio_fd(int fd) | 439 | int read_sigio_fd(int fd) |
diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 7b0e0e81c161..da17b7541e08 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c | |||
@@ -99,31 +99,46 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, | |||
99 | return err; | 99 | return err; |
100 | } | 100 | } |
101 | 101 | ||
102 | static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset) | 102 | static int kern_do_signal(struct pt_regs *regs) |
103 | { | 103 | { |
104 | struct k_sigaction ka_copy; | 104 | struct k_sigaction ka_copy; |
105 | siginfo_t info; | 105 | siginfo_t info; |
106 | sigset_t *oldset; | ||
106 | int sig, handled_sig = 0; | 107 | int sig, handled_sig = 0; |
107 | 108 | ||
109 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
110 | oldset = ¤t->saved_sigmask; | ||
111 | else | ||
112 | oldset = ¤t->blocked; | ||
113 | |||
108 | while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){ | 114 | while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){ |
109 | handled_sig = 1; | 115 | handled_sig = 1; |
110 | /* Whee! Actually deliver the signal. */ | 116 | /* Whee! Actually deliver the signal. */ |
111 | if(!handle_signal(regs, sig, &ka_copy, &info, oldset)) | 117 | if(!handle_signal(regs, sig, &ka_copy, &info, oldset)){ |
118 | /* a signal was successfully delivered; the saved | ||
119 | * sigmask will have been stored in the signal frame, | ||
120 | * and will be restored by sigreturn, so we can simply | ||
121 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
122 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
123 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
112 | break; | 124 | break; |
125 | } | ||
113 | } | 126 | } |
114 | 127 | ||
115 | /* Did we come from a system call? */ | 128 | /* Did we come from a system call? */ |
116 | if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){ | 129 | if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){ |
117 | /* Restart the system call - no handlers present */ | 130 | /* Restart the system call - no handlers present */ |
118 | if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND || | 131 | switch(PT_REGS_SYSCALL_RET(regs)){ |
119 | PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS || | 132 | case -ERESTARTNOHAND: |
120 | PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){ | 133 | case -ERESTARTSYS: |
134 | case -ERESTARTNOINTR: | ||
121 | PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); | 135 | PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); |
122 | PT_REGS_RESTART_SYSCALL(regs); | 136 | PT_REGS_RESTART_SYSCALL(regs); |
123 | } | 137 | break; |
124 | else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){ | 138 | case -ERESTART_RESTARTBLOCK: |
125 | PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall; | 139 | PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall; |
126 | PT_REGS_RESTART_SYSCALL(regs); | 140 | PT_REGS_RESTART_SYSCALL(regs); |
141 | break; | ||
127 | } | 142 | } |
128 | } | 143 | } |
129 | 144 | ||
@@ -137,12 +152,19 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
137 | if(current->ptrace & PT_DTRACE) | 152 | if(current->ptrace & PT_DTRACE) |
138 | current->thread.singlestep_syscall = | 153 | current->thread.singlestep_syscall = |
139 | is_syscall(PT_REGS_IP(¤t->thread.regs)); | 154 | is_syscall(PT_REGS_IP(¤t->thread.regs)); |
155 | |||
156 | /* if there's no signal to deliver, we just put the saved sigmask | ||
157 | * back */ | ||
158 | if (!handled_sig && test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
159 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
160 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
161 | } | ||
140 | return(handled_sig); | 162 | return(handled_sig); |
141 | } | 163 | } |
142 | 164 | ||
143 | int do_signal(void) | 165 | int do_signal(void) |
144 | { | 166 | { |
145 | return(kern_do_signal(¤t->thread.regs, ¤t->blocked)); | 167 | return(kern_do_signal(¤t->thread.regs)); |
146 | } | 168 | } |
147 | 169 | ||
148 | /* | 170 | /* |
@@ -150,63 +172,20 @@ int do_signal(void) | |||
150 | */ | 172 | */ |
151 | long sys_sigsuspend(int history0, int history1, old_sigset_t mask) | 173 | long sys_sigsuspend(int history0, int history1, old_sigset_t mask) |
152 | { | 174 | { |
153 | sigset_t saveset; | ||
154 | |||
155 | mask &= _BLOCKABLE; | 175 | mask &= _BLOCKABLE; |
156 | spin_lock_irq(¤t->sighand->siglock); | 176 | spin_lock_irq(¤t->sighand->siglock); |
157 | saveset = current->blocked; | 177 | current->saved_sigmask = current->blocked; |
158 | siginitset(¤t->blocked, mask); | 178 | siginitset(¤t->blocked, mask); |
159 | recalc_sigpending(); | 179 | recalc_sigpending(); |
160 | spin_unlock_irq(¤t->sighand->siglock); | 180 | spin_unlock_irq(¤t->sighand->siglock); |
161 | 181 | ||
162 | PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; | 182 | current->state = TASK_INTERRUPTIBLE; |
163 | while (1) { | 183 | schedule(); |
164 | current->state = TASK_INTERRUPTIBLE; | 184 | set_thread_flag(TIF_RESTORE_SIGMASK); |
165 | schedule(); | 185 | return -ERESTARTNOHAND; |
166 | if(kern_do_signal(¤t->thread.regs, &saveset)) | ||
167 | return(-EINTR); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) | ||
172 | { | ||
173 | sigset_t saveset, newset; | ||
174 | |||
175 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
176 | if (sigsetsize != sizeof(sigset_t)) | ||
177 | return -EINVAL; | ||
178 | |||
179 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
180 | return -EFAULT; | ||
181 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
182 | |||
183 | spin_lock_irq(¤t->sighand->siglock); | ||
184 | saveset = current->blocked; | ||
185 | current->blocked = newset; | ||
186 | recalc_sigpending(); | ||
187 | spin_unlock_irq(¤t->sighand->siglock); | ||
188 | |||
189 | PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; | ||
190 | while (1) { | ||
191 | current->state = TASK_INTERRUPTIBLE; | ||
192 | schedule(); | ||
193 | if (kern_do_signal(¤t->thread.regs, &saveset)) | ||
194 | return(-EINTR); | ||
195 | } | ||
196 | } | 186 | } |
197 | 187 | ||
198 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | 188 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) |
199 | { | 189 | { |
200 | return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); | 190 | return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); |
201 | } | 191 | } |
202 | |||
203 | /* | ||
204 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
205 | * Emacs will notice this stuff at the end of the file and automatically | ||
206 | * adjust the settings for this buffer only. This must remain at the end | ||
207 | * of the file. | ||
208 | * --------------------------------------------------------------------------- | ||
209 | * Local variables: | ||
210 | * c-file-style: "linux" | ||
211 | * End: | ||
212 | */ | ||
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index 7a9fc16d71d4..57181a920d48 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile | |||
@@ -1,12 +1,12 @@ | |||
1 | # | 1 | # |
2 | # Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) | 2 | # Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) |
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ | 6 | obj-y := clone.o exec_kern.o mem.o mmu.o process_kern.o \ |
7 | syscall.o tlb.o uaccess.o | 7 | syscall.o tlb.o uaccess.o |
8 | 8 | ||
9 | USER_OBJS := process.o clone.o | 9 | USER_OBJS := clone.o |
10 | 10 | ||
11 | include arch/um/scripts/Makefile.rules | 11 | include arch/um/scripts/Makefile.rules |
12 | 12 | ||
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h deleted file mode 100644 index 44110c521e49..000000000000 --- a/arch/um/kernel/skas/include/mmu-skas.h +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SKAS_MMU_H | ||
7 | #define __SKAS_MMU_H | ||
8 | |||
9 | #include "linux/config.h" | ||
10 | #include "mm_id.h" | ||
11 | #include "asm/ldt.h" | ||
12 | |||
13 | struct mmu_context_skas { | ||
14 | struct mm_id id; | ||
15 | unsigned long last_page_table; | ||
16 | #ifdef CONFIG_3_LEVEL_PGTABLES | ||
17 | unsigned long last_pmd; | ||
18 | #endif | ||
19 | uml_ldt_t ldt; | ||
20 | }; | ||
21 | |||
22 | extern void switch_mm_skas(struct mm_id * mm_idp); | ||
23 | |||
24 | #endif | ||
25 | |||
26 | /* | ||
27 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
28 | * Emacs will notice this stuff at the end of the file and automatically | ||
29 | * adjust the settings for this buffer only. This must remain at the end | ||
30 | * of the file. | ||
31 | * --------------------------------------------------------------------------- | ||
32 | * Local variables: | ||
33 | * c-file-style: "linux" | ||
34 | * End: | ||
35 | */ | ||
diff --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h deleted file mode 100644 index bcd26a6a3888..000000000000 --- a/arch/um/kernel/skas/include/mode-skas.h +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __MODE_SKAS_H__ | ||
7 | #define __MODE_SKAS_H__ | ||
8 | |||
9 | #include <sysdep/ptrace.h> | ||
10 | |||
11 | extern unsigned long exec_regs[]; | ||
12 | extern unsigned long exec_fp_regs[]; | ||
13 | extern unsigned long exec_fpx_regs[]; | ||
14 | extern int have_fpx_regs; | ||
15 | |||
16 | extern void sig_handler_common_skas(int sig, void *sc_ptr); | ||
17 | extern void halt_skas(void); | ||
18 | extern void reboot_skas(void); | ||
19 | extern void kill_off_processes_skas(void); | ||
20 | extern int is_skas_winch(int pid, int fd, void *data); | ||
21 | |||
22 | #endif | ||
23 | |||
24 | /* | ||
25 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
26 | * Emacs will notice this stuff at the end of the file and automatically | ||
27 | * adjust the settings for this buffer only. This must remain at the end | ||
28 | * of the file. | ||
29 | * --------------------------------------------------------------------------- | ||
30 | * Local variables: | ||
31 | * c-file-style: "linux" | ||
32 | * End: | ||
33 | */ | ||
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h deleted file mode 100644 index 01d489de3986..000000000000 --- a/arch/um/kernel/skas/include/skas.h +++ /dev/null | |||
@@ -1,49 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SKAS_H | ||
7 | #define __SKAS_H | ||
8 | |||
9 | #include "mm_id.h" | ||
10 | #include "sysdep/ptrace.h" | ||
11 | |||
12 | extern int userspace_pid[]; | ||
13 | extern int proc_mm, ptrace_faultinfo, ptrace_ldt; | ||
14 | extern int skas_needs_stub; | ||
15 | |||
16 | extern void switch_threads(void *me, void *next); | ||
17 | extern void thread_wait(void *sw, void *fb); | ||
18 | extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, | ||
19 | void (*handler)(int)); | ||
20 | extern int start_idle_thread(void *stack, void *switch_buf_ptr, | ||
21 | void **fork_buf_ptr); | ||
22 | extern int user_thread(unsigned long stack, int flags); | ||
23 | extern void userspace(union uml_pt_regs *regs); | ||
24 | extern void new_thread_proc(void *stack, void (*handler)(int sig)); | ||
25 | extern void new_thread_handler(int sig); | ||
26 | extern void handle_syscall(union uml_pt_regs *regs); | ||
27 | extern int map(struct mm_id * mm_idp, unsigned long virt, | ||
28 | unsigned long len, int r, int w, int x, int phys_fd, | ||
29 | unsigned long long offset, int done, void **data); | ||
30 | extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, | ||
31 | int done, void **data); | ||
32 | extern int protect(struct mm_id * mm_idp, unsigned long addr, | ||
33 | unsigned long len, int r, int w, int x, int done, | ||
34 | void **data); | ||
35 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); | ||
36 | extern int new_mm(int from, unsigned long stack); | ||
37 | extern int start_userspace(unsigned long stub_stack); | ||
38 | extern int copy_context_skas0(unsigned long stack, int pid); | ||
39 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); | ||
40 | extern long execute_syscall_skas(void *r); | ||
41 | extern unsigned long current_stub_stack(void); | ||
42 | extern long run_syscall_stub(struct mm_id * mm_idp, | ||
43 | int syscall, unsigned long *args, long expected, | ||
44 | void **addr, int done); | ||
45 | extern long syscall_stub_data(struct mm_id * mm_idp, | ||
46 | unsigned long *data, int data_count, | ||
47 | void **addr, void **stub_addr); | ||
48 | |||
49 | #endif | ||
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 677871f1b37c..c5c9885a8297 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c | |||
@@ -78,7 +78,7 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) | |||
78 | struct mmu_context_skas *from_mm = NULL; | 78 | struct mmu_context_skas *from_mm = NULL; |
79 | struct mmu_context_skas *to_mm = &mm->context.skas; | 79 | struct mmu_context_skas *to_mm = &mm->context.skas; |
80 | unsigned long stack = 0; | 80 | unsigned long stack = 0; |
81 | int from_fd, ret = -ENOMEM; | 81 | int ret = -ENOMEM; |
82 | 82 | ||
83 | if(skas_needs_stub){ | 83 | if(skas_needs_stub){ |
84 | stack = get_zeroed_page(GFP_KERNEL); | 84 | stack = get_zeroed_page(GFP_KERNEL); |
@@ -108,11 +108,7 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) | |||
108 | from_mm = ¤t->mm->context.skas; | 108 | from_mm = ¤t->mm->context.skas; |
109 | 109 | ||
110 | if(proc_mm){ | 110 | if(proc_mm){ |
111 | if(from_mm) | 111 | ret = new_mm(stack); |
112 | from_fd = from_mm->id.u.mm_fd; | ||
113 | else from_fd = -1; | ||
114 | |||
115 | ret = new_mm(from_fd, stack); | ||
116 | if(ret < 0){ | 112 | if(ret < 0){ |
117 | printk("init_new_context_skas - new_mm failed, " | 113 | printk("init_new_context_skas - new_mm failed, " |
118 | "errno = %d\n", ret); | 114 | "errno = %d\n", ret); |
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 3b3955d84407..eea1c9c4bb0f 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <asm/types.h> | 18 | #include <asm/types.h> |
19 | #include "user.h" | 19 | #include "user.h" |
20 | #include "ptrace_user.h" | 20 | #include "ptrace_user.h" |
21 | #include "time_user.h" | ||
22 | #include "sysdep/ptrace.h" | 21 | #include "sysdep/ptrace.h" |
23 | #include "user_util.h" | 22 | #include "user_util.h" |
24 | #include "kern_util.h" | 23 | #include "kern_util.h" |
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index dc41c6dc2f34..3f70a2e12f06 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -13,14 +13,12 @@ | |||
13 | #include "asm/uaccess.h" | 13 | #include "asm/uaccess.h" |
14 | #include "asm/atomic.h" | 14 | #include "asm/atomic.h" |
15 | #include "kern_util.h" | 15 | #include "kern_util.h" |
16 | #include "time_user.h" | ||
17 | #include "skas.h" | 16 | #include "skas.h" |
18 | #include "os.h" | 17 | #include "os.h" |
19 | #include "user_util.h" | 18 | #include "user_util.h" |
20 | #include "tlb.h" | 19 | #include "tlb.h" |
21 | #include "kern.h" | 20 | #include "kern.h" |
22 | #include "mode.h" | 21 | #include "mode.h" |
23 | #include "proc_mm.h" | ||
24 | #include "registers.h" | 22 | #include "registers.h" |
25 | 23 | ||
26 | void switch_to_skas(void *prev, void *next) | 24 | void switch_to_skas(void *prev, void *next) |
@@ -34,7 +32,7 @@ void switch_to_skas(void *prev, void *next) | |||
34 | if(current->pid == 0) | 32 | if(current->pid == 0) |
35 | switch_timers(0); | 33 | switch_timers(0); |
36 | 34 | ||
37 | switch_threads(&from->thread.mode.skas.switch_buf, | 35 | switch_threads(&from->thread.mode.skas.switch_buf, |
38 | to->thread.mode.skas.switch_buf); | 36 | to->thread.mode.skas.switch_buf); |
39 | 37 | ||
40 | if(current->pid == 0) | 38 | if(current->pid == 0) |
@@ -50,8 +48,8 @@ void new_thread_handler(int sig) | |||
50 | 48 | ||
51 | fn = current->thread.request.u.thread.proc; | 49 | fn = current->thread.request.u.thread.proc; |
52 | arg = current->thread.request.u.thread.arg; | 50 | arg = current->thread.request.u.thread.arg; |
53 | change_sig(SIGUSR1, 1); | 51 | os_usr1_signal(1); |
54 | thread_wait(¤t->thread.mode.skas.switch_buf, | 52 | thread_wait(¤t->thread.mode.skas.switch_buf, |
55 | current->thread.mode.skas.fork_buf); | 53 | current->thread.mode.skas.fork_buf); |
56 | 54 | ||
57 | if(current->thread.prev_sched != NULL) | 55 | if(current->thread.prev_sched != NULL) |
@@ -82,8 +80,8 @@ void release_thread_skas(struct task_struct *task) | |||
82 | 80 | ||
83 | void fork_handler(int sig) | 81 | void fork_handler(int sig) |
84 | { | 82 | { |
85 | change_sig(SIGUSR1, 1); | 83 | os_usr1_signal(1); |
86 | thread_wait(¤t->thread.mode.skas.switch_buf, | 84 | thread_wait(¤t->thread.mode.skas.switch_buf, |
87 | current->thread.mode.skas.fork_buf); | 85 | current->thread.mode.skas.fork_buf); |
88 | 86 | ||
89 | force_flush_all(); | 87 | force_flush_all(); |
@@ -93,13 +91,13 @@ void fork_handler(int sig) | |||
93 | schedule_tail(current->thread.prev_sched); | 91 | schedule_tail(current->thread.prev_sched); |
94 | current->thread.prev_sched = NULL; | 92 | current->thread.prev_sched = NULL; |
95 | 93 | ||
96 | /* Handle any immediate reschedules or signals */ | 94 | /* Handle any immediate reschedules or signals */ |
97 | interrupt_end(); | 95 | interrupt_end(); |
98 | userspace(¤t->thread.regs.regs); | 96 | userspace(¤t->thread.regs.regs); |
99 | } | 97 | } |
100 | 98 | ||
101 | int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, | 99 | int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, |
102 | unsigned long stack_top, struct task_struct * p, | 100 | unsigned long stack_top, struct task_struct * p, |
103 | struct pt_regs *regs) | 101 | struct pt_regs *regs) |
104 | { | 102 | { |
105 | void (*handler)(int); | 103 | void (*handler)(int); |
@@ -123,27 +121,14 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, | |||
123 | return(0); | 121 | return(0); |
124 | } | 122 | } |
125 | 123 | ||
126 | extern void map_stub_pages(int fd, unsigned long code, | 124 | int new_mm(unsigned long stack) |
127 | unsigned long data, unsigned long stack); | ||
128 | int new_mm(int from, unsigned long stack) | ||
129 | { | 125 | { |
130 | struct proc_mm_op copy; | 126 | int fd; |
131 | int n, fd; | ||
132 | 127 | ||
133 | fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); | 128 | fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); |
134 | if(fd < 0) | 129 | if(fd < 0) |
135 | return(fd); | 130 | return(fd); |
136 | 131 | ||
137 | if(from != -1){ | ||
138 | copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, | ||
139 | .u = | ||
140 | { .copy_segments = from } } ); | ||
141 | n = os_write_file(fd, ©, sizeof(copy)); | ||
142 | if(n != sizeof(copy)) | ||
143 | printk("new_mm : /proc/mm copy_segments failed, " | ||
144 | "err = %d\n", -n); | ||
145 | } | ||
146 | |||
147 | if(skas_needs_stub) | 132 | if(skas_needs_stub) |
148 | map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack); | 133 | map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack); |
149 | 134 | ||
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index a5a47528dec7..5992c3257167 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include "asm/pgtable.h" | 13 | #include "asm/pgtable.h" |
14 | #include "asm/uaccess.h" | 14 | #include "asm/uaccess.h" |
15 | #include "kern_util.h" | 15 | #include "kern_util.h" |
16 | #include "user_util.h" | 16 | #include "os.h" |
17 | 17 | ||
18 | extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, | 18 | extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, |
19 | pte_t *pte_out); | 19 | pte_t *pte_out); |
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 1429c131879d..1731d90e6850 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c | |||
@@ -25,12 +25,12 @@ int record_syscall_start(int syscall) | |||
25 | syscall_record[index].syscall = syscall; | 25 | syscall_record[index].syscall = syscall; |
26 | syscall_record[index].pid = current_pid(); | 26 | syscall_record[index].pid = current_pid(); |
27 | syscall_record[index].result = 0xdeadbeef; | 27 | syscall_record[index].result = 0xdeadbeef; |
28 | syscall_record[index].start = os_usecs(); | 28 | syscall_record[index].start = os_nsecs(); |
29 | return(index); | 29 | return(index); |
30 | } | 30 | } |
31 | 31 | ||
32 | void record_syscall_end(int index, long result) | 32 | void record_syscall_end(int index, long result) |
33 | { | 33 | { |
34 | syscall_record[index].result = result; | 34 | syscall_record[index].result = result; |
35 | syscall_record[index].end = os_usecs(); | 35 | syscall_record[index].end = os_nsecs(); |
36 | } | 36 | } |
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 020ca79b8d33..3c7626cdba4b 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -13,12 +13,12 @@ | |||
13 | #include "linux/interrupt.h" | 13 | #include "linux/interrupt.h" |
14 | #include "linux/init.h" | 14 | #include "linux/init.h" |
15 | #include "linux/delay.h" | 15 | #include "linux/delay.h" |
16 | #include "linux/hrtimer.h" | ||
16 | #include "asm/irq.h" | 17 | #include "asm/irq.h" |
17 | #include "asm/param.h" | 18 | #include "asm/param.h" |
18 | #include "asm/current.h" | 19 | #include "asm/current.h" |
19 | #include "kern_util.h" | 20 | #include "kern_util.h" |
20 | #include "user_util.h" | 21 | #include "user_util.h" |
21 | #include "time_user.h" | ||
22 | #include "mode.h" | 22 | #include "mode.h" |
23 | #include "os.h" | 23 | #include "os.h" |
24 | 24 | ||
@@ -39,7 +39,7 @@ unsigned long long sched_clock(void) | |||
39 | int timer_irq_inited = 0; | 39 | int timer_irq_inited = 0; |
40 | 40 | ||
41 | static int first_tick; | 41 | static int first_tick; |
42 | static unsigned long long prev_usecs; | 42 | static unsigned long long prev_nsecs; |
43 | #ifdef CONFIG_UML_REAL_TIME_CLOCK | 43 | #ifdef CONFIG_UML_REAL_TIME_CLOCK |
44 | static long long delta; /* Deviation per interval */ | 44 | static long long delta; /* Deviation per interval */ |
45 | #endif | 45 | #endif |
@@ -58,23 +58,23 @@ void timer_irq(union uml_pt_regs *regs) | |||
58 | if(first_tick){ | 58 | if(first_tick){ |
59 | #ifdef CONFIG_UML_REAL_TIME_CLOCK | 59 | #ifdef CONFIG_UML_REAL_TIME_CLOCK |
60 | /* We've had 1 tick */ | 60 | /* We've had 1 tick */ |
61 | unsigned long long usecs = os_usecs(); | 61 | unsigned long long nsecs = os_nsecs(); |
62 | 62 | ||
63 | delta += usecs - prev_usecs; | 63 | delta += nsecs - prev_nsecs; |
64 | prev_usecs = usecs; | 64 | prev_nsecs = nsecs; |
65 | 65 | ||
66 | /* Protect against the host clock being set backwards */ | 66 | /* Protect against the host clock being set backwards */ |
67 | if(delta < 0) | 67 | if(delta < 0) |
68 | delta = 0; | 68 | delta = 0; |
69 | 69 | ||
70 | ticks += (delta * HZ) / MILLION; | 70 | ticks += (delta * HZ) / BILLION; |
71 | delta -= (ticks * MILLION) / HZ; | 71 | delta -= (ticks * BILLION) / HZ; |
72 | #else | 72 | #else |
73 | ticks = 1; | 73 | ticks = 1; |
74 | #endif | 74 | #endif |
75 | } | 75 | } |
76 | else { | 76 | else { |
77 | prev_usecs = os_usecs(); | 77 | prev_nsecs = os_nsecs(); |
78 | first_tick = 1; | 78 | first_tick = 1; |
79 | } | 79 | } |
80 | 80 | ||
@@ -84,49 +84,102 @@ void timer_irq(union uml_pt_regs *regs) | |||
84 | } | 84 | } |
85 | } | 85 | } |
86 | 86 | ||
87 | void boot_timer_handler(int sig) | 87 | void do_boot_timer_handler(struct sigcontext * sc) |
88 | { | 88 | { |
89 | struct pt_regs regs; | 89 | struct pt_regs regs; |
90 | 90 | ||
91 | CHOOSE_MODE((void) | 91 | CHOOSE_MODE((void) (UPT_SC(®s.regs) = sc), |
92 | (UPT_SC(®s.regs) = (struct sigcontext *) (&sig + 1)), | ||
93 | (void) (regs.regs.skas.is_user = 0)); | 92 | (void) (regs.regs.skas.is_user = 0)); |
94 | do_timer(®s); | 93 | do_timer(®s); |
95 | } | 94 | } |
96 | 95 | ||
96 | static DEFINE_SPINLOCK(timer_spinlock); | ||
97 | |||
98 | static unsigned long long local_offset = 0; | ||
99 | |||
100 | static inline unsigned long long get_time(void) | ||
101 | { | ||
102 | unsigned long long nsecs; | ||
103 | unsigned long flags; | ||
104 | |||
105 | spin_lock_irqsave(&timer_spinlock, flags); | ||
106 | nsecs = os_nsecs(); | ||
107 | nsecs += local_offset; | ||
108 | spin_unlock_irqrestore(&timer_spinlock, flags); | ||
109 | |||
110 | return nsecs; | ||
111 | } | ||
112 | |||
97 | irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) | 113 | irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) |
98 | { | 114 | { |
115 | unsigned long long nsecs; | ||
99 | unsigned long flags; | 116 | unsigned long flags; |
100 | 117 | ||
101 | do_timer(regs); | 118 | do_timer(regs); |
119 | |||
102 | write_seqlock_irqsave(&xtime_lock, flags); | 120 | write_seqlock_irqsave(&xtime_lock, flags); |
103 | timer(); | 121 | nsecs = get_time() + local_offset; |
122 | xtime.tv_sec = nsecs / NSEC_PER_SEC; | ||
123 | xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC; | ||
104 | write_sequnlock_irqrestore(&xtime_lock, flags); | 124 | write_sequnlock_irqrestore(&xtime_lock, flags); |
125 | |||
105 | return(IRQ_HANDLED); | 126 | return(IRQ_HANDLED); |
106 | } | 127 | } |
107 | 128 | ||
108 | long um_time(int __user *tloc) | 129 | long um_time(int __user *tloc) |
109 | { | 130 | { |
110 | struct timeval now; | 131 | long ret = get_time() / NSEC_PER_SEC; |
111 | 132 | ||
112 | do_gettimeofday(&now); | 133 | if((tloc != NULL) && put_user(ret, tloc)) |
113 | if (tloc) { | 134 | return -EFAULT; |
114 | if (put_user(now.tv_sec, tloc)) | 135 | |
115 | now.tv_sec = -EFAULT; | 136 | return ret; |
116 | } | 137 | } |
117 | return now.tv_sec; | 138 | |
139 | void do_gettimeofday(struct timeval *tv) | ||
140 | { | ||
141 | unsigned long long nsecs = get_time(); | ||
142 | |||
143 | tv->tv_sec = nsecs / NSEC_PER_SEC; | ||
144 | /* Careful about calculations here - this was originally done as | ||
145 | * (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC | ||
146 | * which gave bogus (> 1000000) values. Dunno why, suspect gcc | ||
147 | * (4.0.0) miscompiled it, or there's a subtle 64/32-bit conversion | ||
148 | * problem that I missed. | ||
149 | */ | ||
150 | nsecs -= tv->tv_sec * NSEC_PER_SEC; | ||
151 | tv->tv_usec = (unsigned long) nsecs / NSEC_PER_USEC; | ||
152 | } | ||
153 | |||
154 | static inline void set_time(unsigned long long nsecs) | ||
155 | { | ||
156 | unsigned long long now; | ||
157 | unsigned long flags; | ||
158 | |||
159 | spin_lock_irqsave(&timer_spinlock, flags); | ||
160 | now = os_nsecs(); | ||
161 | local_offset = nsecs - now; | ||
162 | spin_unlock_irqrestore(&timer_spinlock, flags); | ||
163 | |||
164 | clock_was_set(); | ||
118 | } | 165 | } |
119 | 166 | ||
120 | long um_stime(int __user *tptr) | 167 | long um_stime(int __user *tptr) |
121 | { | 168 | { |
122 | int value; | 169 | int value; |
123 | struct timespec new; | ||
124 | 170 | ||
125 | if (get_user(value, tptr)) | 171 | if (get_user(value, tptr)) |
126 | return -EFAULT; | 172 | return -EFAULT; |
127 | new.tv_sec = value; | 173 | |
128 | new.tv_nsec = 0; | 174 | set_time((unsigned long long) value * NSEC_PER_SEC); |
129 | do_settimeofday(&new); | 175 | |
176 | return 0; | ||
177 | } | ||
178 | |||
179 | int do_settimeofday(struct timespec *tv) | ||
180 | { | ||
181 | set_time((unsigned long long) tv->tv_sec * NSEC_PER_SEC + tv->tv_nsec); | ||
182 | |||
130 | return 0; | 183 | return 0; |
131 | } | 184 | } |
132 | 185 | ||
@@ -134,29 +187,15 @@ void timer_handler(int sig, union uml_pt_regs *regs) | |||
134 | { | 187 | { |
135 | local_irq_disable(); | 188 | local_irq_disable(); |
136 | irq_enter(); | 189 | irq_enter(); |
137 | update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)), | 190 | update_process_times(CHOOSE_MODE( |
138 | (regs)->skas.is_user)); | 191 | (UPT_SC(regs) && user_context(UPT_SP(regs))), |
192 | (regs)->skas.is_user)); | ||
139 | irq_exit(); | 193 | irq_exit(); |
140 | local_irq_enable(); | 194 | local_irq_enable(); |
141 | if(current_thread->cpu == 0) | 195 | if(current_thread->cpu == 0) |
142 | timer_irq(regs); | 196 | timer_irq(regs); |
143 | } | 197 | } |
144 | 198 | ||
145 | static DEFINE_SPINLOCK(timer_spinlock); | ||
146 | |||
147 | unsigned long time_lock(void) | ||
148 | { | ||
149 | unsigned long flags; | ||
150 | |||
151 | spin_lock_irqsave(&timer_spinlock, flags); | ||
152 | return(flags); | ||
153 | } | ||
154 | |||
155 | void time_unlock(unsigned long flags) | ||
156 | { | ||
157 | spin_unlock_irqrestore(&timer_spinlock, flags); | ||
158 | } | ||
159 | |||
160 | int __init timer_init(void) | 199 | int __init timer_init(void) |
161 | { | 200 | { |
162 | int err; | 201 | int err; |
@@ -171,14 +210,3 @@ int __init timer_init(void) | |||
171 | } | 210 | } |
172 | 211 | ||
173 | __initcall(timer_init); | 212 | __initcall(timer_init); |
174 | |||
175 | /* | ||
176 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
177 | * Emacs will notice this stuff at the end of the file and automatically | ||
178 | * adjust the settings for this buffer only. This must remain at the end | ||
179 | * of the file. | ||
180 | * --------------------------------------------------------------------------- | ||
181 | * Local variables: | ||
182 | * c-file-style: "linux" | ||
183 | * End: | ||
184 | */ | ||
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index 8f40e4838736..5c1e4cc1c049 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include "user_util.h" | 13 | #include "user_util.h" |
14 | #include "kern_util.h" | 14 | #include "kern_util.h" |
15 | #include "irq_user.h" | 15 | #include "irq_user.h" |
16 | #include "time_user.h" | ||
17 | #include "mem_user.h" | 16 | #include "mem_user.h" |
18 | #include "os.h" | 17 | #include "os.h" |
19 | #include "tlb.h" | 18 | #include "tlb.h" |
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c index 37e22d71a0d9..786e4edd86c5 100644 --- a/arch/um/kernel/tt/gdb.c +++ b/arch/um/kernel/tt/gdb.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "user_util.h" | 20 | #include "user_util.h" |
21 | #include "tt.h" | 21 | #include "tt.h" |
22 | #include "sysdep/thread.h" | 22 | #include "sysdep/thread.h" |
23 | #include "os.h" | ||
23 | 24 | ||
24 | extern int debugger_pid; | 25 | extern int debugger_pid; |
25 | extern int debugger_fd; | 26 | extern int debugger_fd; |
diff --git a/arch/um/kernel/tt/include/mmu-tt.h b/arch/um/kernel/tt/include/mmu-tt.h deleted file mode 100644 index 0440510ab3fe..000000000000 --- a/arch/um/kernel/tt/include/mmu-tt.h +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __TT_MMU_H | ||
7 | #define __TT_MMU_H | ||
8 | |||
9 | struct mmu_context_tt { | ||
10 | }; | ||
11 | |||
12 | #endif | ||
13 | |||
14 | /* | ||
15 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
16 | * Emacs will notice this stuff at the end of the file and automatically | ||
17 | * adjust the settings for this buffer only. This must remain at the end | ||
18 | * of the file. | ||
19 | * --------------------------------------------------------------------------- | ||
20 | * Local variables: | ||
21 | * c-file-style: "linux" | ||
22 | * End: | ||
23 | */ | ||
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 62535303aa27..295c1ac817b3 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include "os.h" | 18 | #include "os.h" |
19 | #include "kern.h" | 19 | #include "kern.h" |
20 | #include "sigcontext.h" | 20 | #include "sigcontext.h" |
21 | #include "time_user.h" | ||
22 | #include "mem_user.h" | 21 | #include "mem_user.h" |
23 | #include "tlb.h" | 22 | #include "tlb.h" |
24 | #include "mode.h" | 23 | #include "mode.h" |
diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c index 528a5fc8d887..03774427d468 100644 --- a/arch/um/kernel/tt/ptproxy/ptrace.c +++ b/arch/um/kernel/tt/ptproxy/ptrace.c | |||
@@ -20,6 +20,7 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml | |||
20 | #include "kern_util.h" | 20 | #include "kern_util.h" |
21 | #include "ptrace_user.h" | 21 | #include "ptrace_user.h" |
22 | #include "tt.h" | 22 | #include "tt.h" |
23 | #include "os.h" | ||
23 | 24 | ||
24 | long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, | 25 | long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, |
25 | long arg3, long arg4, pid_t child, int *ret) | 26 | long arg3, long arg4, pid_t child, int *ret) |
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c index a5f0e01e214e..99f178319d03 100644 --- a/arch/um/kernel/tt/ptproxy/sysdep.c +++ b/arch/um/kernel/tt/ptproxy/sysdep.c | |||
@@ -15,6 +15,7 @@ terms and conditions. | |||
15 | #include "ptrace_user.h" | 15 | #include "ptrace_user.h" |
16 | #include "user_util.h" | 16 | #include "user_util.h" |
17 | #include "user.h" | 17 | #include "user.h" |
18 | #include "os.h" | ||
18 | 19 | ||
19 | int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, | 20 | int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, |
20 | long *arg5) | 21 | long *arg5) |
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c index a414c529fbcd..b5d9d64d91e4 100644 --- a/arch/um/kernel/tt/trap_user.c +++ b/arch/um/kernel/tt/trap_user.c | |||
@@ -18,7 +18,7 @@ void sig_handler_common_tt(int sig, void *sc_ptr) | |||
18 | { | 18 | { |
19 | struct sigcontext *sc = sc_ptr; | 19 | struct sigcontext *sc = sc_ptr; |
20 | struct tt_regs save_regs, *r; | 20 | struct tt_regs save_regs, *r; |
21 | int save_errno = errno, is_user; | 21 | int save_errno = errno, is_user = 0; |
22 | void (*handler)(int, union uml_pt_regs *); | 22 | void (*handler)(int, union uml_pt_regs *); |
23 | 23 | ||
24 | /* This is done because to allow SIGSEGV to be delivered inside a SEGV | 24 | /* This is done because to allow SIGSEGV to be delivered inside a SEGV |
@@ -35,7 +35,8 @@ void sig_handler_common_tt(int sig, void *sc_ptr) | |||
35 | GET_FAULTINFO_FROM_SC(r->faultinfo, sc); | 35 | GET_FAULTINFO_FROM_SC(r->faultinfo, sc); |
36 | } | 36 | } |
37 | save_regs = *r; | 37 | save_regs = *r; |
38 | is_user = user_context(SC_SP(sc)); | 38 | if (sc) |
39 | is_user = user_context(SC_SP(sc)); | ||
39 | r->sc = sc; | 40 | r->sc = sc; |
40 | if(sig != SIGUSR2) | 41 | if(sig != SIGUSR2) |
41 | r->syscall = -1; | 42 | r->syscall = -1; |
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 40c7d6b1df68..08a4e628b24c 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile | |||
@@ -5,12 +5,12 @@ | |||
5 | 5 | ||
6 | obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ | 6 | obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ |
7 | start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \ | 7 | start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \ |
8 | drivers/ sys-$(SUBARCH)/ | 8 | util.o drivers/ sys-$(SUBARCH)/ |
9 | 9 | ||
10 | obj-$(CONFIG_MODE_SKAS) += skas/ | 10 | obj-$(CONFIG_MODE_SKAS) += skas/ |
11 | 11 | ||
12 | USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ | 12 | USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ |
13 | start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o | 13 | start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o |
14 | 14 | ||
15 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h | 15 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h |
16 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um | 16 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um |
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 36cc8475bcda..6490a4ff40ac 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c | |||
@@ -60,7 +60,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, | |||
60 | 60 | ||
61 | if((stack_out != NULL) && (*stack_out != 0)) | 61 | if((stack_out != NULL) && (*stack_out != 0)) |
62 | stack = *stack_out; | 62 | stack = *stack_out; |
63 | else stack = alloc_stack(0, um_in_interrupt()); | 63 | else stack = alloc_stack(0, __cant_sleep()); |
64 | if(stack == 0) | 64 | if(stack == 0) |
65 | return(-ENOMEM); | 65 | return(-ENOMEM); |
66 | 66 | ||
@@ -124,7 +124,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, | |||
124 | unsigned long stack, sp; | 124 | unsigned long stack, sp; |
125 | int pid, status, err; | 125 | int pid, status, err; |
126 | 126 | ||
127 | stack = alloc_stack(stack_order, um_in_interrupt()); | 127 | stack = alloc_stack(stack_order, __cant_sleep()); |
128 | if(stack == 0) return(-ENOMEM); | 128 | if(stack == 0) return(-ENOMEM); |
129 | 129 | ||
130 | sp = stack + (page_size() << stack_order) - sizeof(void *); | 130 | sp = stack + (page_size() << stack_order) - sizeof(void *); |
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index 172c8474453c..2878e89a674f 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include "user_util.h" | 16 | #include "user_util.h" |
17 | #include "kern_util.h" | 17 | #include "kern_util.h" |
18 | #include "mem_user.h" | 18 | #include "mem_user.h" |
19 | #include "time_user.h" | ||
20 | #include "irq_user.h" | 19 | #include "irq_user.h" |
21 | #include "user.h" | 20 | #include "user.h" |
22 | #include "init.h" | 21 | #include "init.h" |
@@ -82,20 +81,8 @@ extern void scan_elf_aux( char **envp); | |||
82 | int main(int argc, char **argv, char **envp) | 81 | int main(int argc, char **argv, char **envp) |
83 | { | 82 | { |
84 | char **new_argv; | 83 | char **new_argv; |
85 | sigset_t mask; | ||
86 | int ret, i, err; | 84 | int ret, i, err; |
87 | 85 | ||
88 | /* Enable all signals except SIGIO - in some environments, we can | ||
89 | * enter with some signals blocked | ||
90 | */ | ||
91 | |||
92 | sigemptyset(&mask); | ||
93 | sigaddset(&mask, SIGIO); | ||
94 | if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){ | ||
95 | perror("sigprocmask"); | ||
96 | exit(1); | ||
97 | } | ||
98 | |||
99 | #ifdef UML_CONFIG_CMDLINE_ON_HOST | 86 | #ifdef UML_CONFIG_CMDLINE_ON_HOST |
100 | /* Allocate memory for thread command lines */ | 87 | /* Allocate memory for thread command lines */ |
101 | if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ | 88 | if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ |
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 39815c6b5e45..7f5e2dac2a35 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "process.h" | 18 | #include "process.h" |
19 | #include "irq_user.h" | 19 | #include "irq_user.h" |
20 | #include "kern_util.h" | 20 | #include "kern_util.h" |
21 | #include "longjmp.h" | ||
21 | 22 | ||
22 | #define ARBITRARY_ADDR -1 | 23 | #define ARBITRARY_ADDR -1 |
23 | #define FAILURE_PID -1 | 24 | #define FAILURE_PID -1 |
@@ -205,24 +206,13 @@ void init_new_thread_signals(int altstack) | |||
205 | 206 | ||
206 | int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) | 207 | int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) |
207 | { | 208 | { |
208 | sigjmp_buf buf; | 209 | sigjmp_buf buf; |
209 | int n; | 210 | int n, enable; |
210 | 211 | ||
211 | *jmp_ptr = &buf; | 212 | *jmp_ptr = &buf; |
212 | n = sigsetjmp(buf, 1); | 213 | n = UML_SIGSETJMP(&buf, enable); |
213 | if(n != 0) | 214 | if(n != 0) |
214 | return(n); | 215 | return(n); |
215 | (*fn)(arg); | 216 | (*fn)(arg); |
216 | return(0); | 217 | return(0); |
217 | } | 218 | } |
218 | |||
219 | /* | ||
220 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
221 | * Emacs will notice this stuff at the end of the file and automatically | ||
222 | * adjust the settings for this buffer only. This must remain at the end | ||
223 | * of the file. | ||
224 | * --------------------------------------------------------------------------- | ||
225 | * Local variables: | ||
226 | * c-file-style: "linux" | ||
227 | * End: | ||
228 | */ | ||
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index c1f46a0fef13..f11b3124a0c8 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c | |||
@@ -12,32 +12,66 @@ | |||
12 | #include <string.h> | 12 | #include <string.h> |
13 | #include <sys/mman.h> | 13 | #include <sys/mman.h> |
14 | #include "user_util.h" | 14 | #include "user_util.h" |
15 | #include "kern_util.h" | ||
16 | #include "user.h" | 15 | #include "user.h" |
17 | #include "signal_kern.h" | 16 | #include "signal_kern.h" |
18 | #include "sysdep/sigcontext.h" | 17 | #include "sysdep/sigcontext.h" |
19 | #include "sysdep/signal.h" | 18 | #include "sysdep/signal.h" |
20 | #include "sigcontext.h" | 19 | #include "sigcontext.h" |
21 | #include "time_user.h" | ||
22 | #include "mode.h" | 20 | #include "mode.h" |
21 | #include "os.h" | ||
22 | |||
23 | /* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled | ||
24 | * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to | ||
25 | * be able to profile all of UML, not just the non-critical sections. If | ||
26 | * profiling is not thread-safe, then that is not my problem. We can disable | ||
27 | * profiling when SMP is enabled in that case. | ||
28 | */ | ||
29 | #define SIGIO_BIT 0 | ||
30 | #define SIGIO_MASK (1 << SIGIO_BIT) | ||
31 | |||
32 | #define SIGVTALRM_BIT 1 | ||
33 | #define SIGVTALRM_MASK (1 << SIGVTALRM_BIT) | ||
34 | |||
35 | #define SIGALRM_BIT 2 | ||
36 | #define SIGALRM_MASK (1 << SIGALRM_BIT) | ||
37 | |||
38 | static int signals_enabled = 1; | ||
39 | static int pending = 0; | ||
23 | 40 | ||
24 | void sig_handler(ARCH_SIGHDLR_PARAM) | 41 | void sig_handler(ARCH_SIGHDLR_PARAM) |
25 | { | 42 | { |
26 | struct sigcontext *sc; | 43 | struct sigcontext *sc; |
44 | int enabled; | ||
45 | |||
46 | /* Must be the first thing that this handler does - x86_64 stores | ||
47 | * the sigcontext in %rdx, and we need to save it before it has a | ||
48 | * chance to get trashed. | ||
49 | */ | ||
27 | 50 | ||
28 | ARCH_GET_SIGCONTEXT(sc, sig); | 51 | ARCH_GET_SIGCONTEXT(sc, sig); |
52 | |||
53 | enabled = signals_enabled; | ||
54 | if(!enabled && (sig == SIGIO)){ | ||
55 | pending |= SIGIO_MASK; | ||
56 | return; | ||
57 | } | ||
58 | |||
59 | block_signals(); | ||
60 | |||
29 | CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, | 61 | CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, |
30 | sig, sc); | 62 | sig, sc); |
63 | |||
64 | set_signals(enabled); | ||
31 | } | 65 | } |
32 | 66 | ||
33 | extern int timer_irq_inited; | 67 | extern int timer_irq_inited; |
34 | 68 | ||
35 | void alarm_handler(ARCH_SIGHDLR_PARAM) | 69 | static void real_alarm_handler(int sig, struct sigcontext *sc) |
36 | { | 70 | { |
37 | struct sigcontext *sc; | 71 | if(!timer_irq_inited){ |
38 | 72 | signals_enabled = 1; | |
39 | ARCH_GET_SIGCONTEXT(sc, sig); | 73 | return; |
40 | if(!timer_irq_inited) return; | 74 | } |
41 | 75 | ||
42 | if(sig == SIGALRM) | 76 | if(sig == SIGALRM) |
43 | switch_timers(0); | 77 | switch_timers(0); |
@@ -47,6 +81,52 @@ void alarm_handler(ARCH_SIGHDLR_PARAM) | |||
47 | 81 | ||
48 | if(sig == SIGALRM) | 82 | if(sig == SIGALRM) |
49 | switch_timers(1); | 83 | switch_timers(1); |
84 | |||
85 | } | ||
86 | |||
87 | void alarm_handler(ARCH_SIGHDLR_PARAM) | ||
88 | { | ||
89 | struct sigcontext *sc; | ||
90 | int enabled; | ||
91 | |||
92 | ARCH_GET_SIGCONTEXT(sc, sig); | ||
93 | |||
94 | enabled = signals_enabled; | ||
95 | if(!signals_enabled){ | ||
96 | if(sig == SIGVTALRM) | ||
97 | pending |= SIGVTALRM_MASK; | ||
98 | else pending |= SIGALRM_MASK; | ||
99 | |||
100 | return; | ||
101 | } | ||
102 | |||
103 | block_signals(); | ||
104 | |||
105 | real_alarm_handler(sig, sc); | ||
106 | set_signals(enabled); | ||
107 | } | ||
108 | |||
109 | extern void do_boot_timer_handler(struct sigcontext * sc); | ||
110 | |||
111 | void boot_timer_handler(ARCH_SIGHDLR_PARAM) | ||
112 | { | ||
113 | struct sigcontext *sc; | ||
114 | int enabled; | ||
115 | |||
116 | ARCH_GET_SIGCONTEXT(sc, sig); | ||
117 | |||
118 | enabled = signals_enabled; | ||
119 | if(!enabled){ | ||
120 | if(sig == SIGVTALRM) | ||
121 | pending |= SIGVTALRM_MASK; | ||
122 | else pending |= SIGALRM_MASK; | ||
123 | return; | ||
124 | } | ||
125 | |||
126 | block_signals(); | ||
127 | |||
128 | do_boot_timer_handler(sc); | ||
129 | set_signals(enabled); | ||
50 | } | 130 | } |
51 | 131 | ||
52 | void set_sigstack(void *sig_stack, int size) | 132 | void set_sigstack(void *sig_stack, int size) |
@@ -73,6 +153,7 @@ void set_handler(int sig, void (*handler)(int), int flags, ...) | |||
73 | { | 153 | { |
74 | struct sigaction action; | 154 | struct sigaction action; |
75 | va_list ap; | 155 | va_list ap; |
156 | sigset_t sig_mask; | ||
76 | int mask; | 157 | int mask; |
77 | 158 | ||
78 | va_start(ap, flags); | 159 | va_start(ap, flags); |
@@ -85,7 +166,12 @@ void set_handler(int sig, void (*handler)(int), int flags, ...) | |||
85 | action.sa_flags = flags; | 166 | action.sa_flags = flags; |
86 | action.sa_restorer = NULL; | 167 | action.sa_restorer = NULL; |
87 | if(sigaction(sig, &action, NULL) < 0) | 168 | if(sigaction(sig, &action, NULL) < 0) |
88 | panic("sigaction failed"); | 169 | panic("sigaction failed - errno = %d\n", errno); |
170 | |||
171 | sigemptyset(&sig_mask); | ||
172 | sigaddset(&sig_mask, sig); | ||
173 | if(sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0) | ||
174 | panic("sigprocmask failed - errno = %d\n", errno); | ||
89 | } | 175 | } |
90 | 176 | ||
91 | int change_sig(int signal, int on) | 177 | int change_sig(int signal, int on) |
@@ -98,89 +184,77 @@ int change_sig(int signal, int on) | |||
98 | return(!sigismember(&old, signal)); | 184 | return(!sigismember(&old, signal)); |
99 | } | 185 | } |
100 | 186 | ||
101 | /* Both here and in set/get_signal we don't touch SIGPROF, because we must not | ||
102 | * disable profiling; it's safe because the profiling code does not interact | ||
103 | * with the kernel code at all.*/ | ||
104 | |||
105 | static void change_signals(int type) | ||
106 | { | ||
107 | sigset_t mask; | ||
108 | |||
109 | sigemptyset(&mask); | ||
110 | sigaddset(&mask, SIGVTALRM); | ||
111 | sigaddset(&mask, SIGALRM); | ||
112 | sigaddset(&mask, SIGIO); | ||
113 | if(sigprocmask(type, &mask, NULL) < 0) | ||
114 | panic("Failed to change signal mask - errno = %d", errno); | ||
115 | } | ||
116 | |||
117 | void block_signals(void) | 187 | void block_signals(void) |
118 | { | 188 | { |
119 | change_signals(SIG_BLOCK); | 189 | signals_enabled = 0; |
120 | } | 190 | } |
121 | 191 | ||
122 | void unblock_signals(void) | 192 | void unblock_signals(void) |
123 | { | 193 | { |
124 | change_signals(SIG_UNBLOCK); | 194 | int save_pending; |
125 | } | ||
126 | 195 | ||
127 | /* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled | 196 | if(signals_enabled == 1) |
128 | * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to | 197 | return; |
129 | * be able to profile all of UML, not just the non-critical sections. If | ||
130 | * profiling is not thread-safe, then that is not my problem. We can disable | ||
131 | * profiling when SMP is enabled in that case. | ||
132 | */ | ||
133 | #define SIGIO_BIT 0 | ||
134 | #define SIGVTALRM_BIT 1 | ||
135 | 198 | ||
136 | static int enable_mask(sigset_t *mask) | 199 | /* We loop because the IRQ handler returns with interrupts off. So, |
137 | { | 200 | * interrupts may have arrived and we need to re-enable them and |
138 | int sigs; | 201 | * recheck pending. |
202 | */ | ||
203 | while(1){ | ||
204 | /* Save and reset save_pending after enabling signals. This | ||
205 | * way, pending won't be changed while we're reading it. | ||
206 | */ | ||
207 | signals_enabled = 1; | ||
208 | |||
209 | save_pending = pending; | ||
210 | if(save_pending == 0) | ||
211 | return; | ||
212 | |||
213 | pending = 0; | ||
214 | |||
215 | /* We have pending interrupts, so disable signals, as the | ||
216 | * handlers expect them off when they are called. They will | ||
217 | * be enabled again above. | ||
218 | */ | ||
219 | |||
220 | signals_enabled = 0; | ||
139 | 221 | ||
140 | sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT; | 222 | /* Deal with SIGIO first because the alarm handler might |
141 | sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT; | 223 | * schedule, leaving the pending SIGIO stranded until we come |
142 | sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT; | 224 | * back here. |
143 | return(sigs); | 225 | */ |
226 | if(save_pending & SIGIO_MASK) | ||
227 | CHOOSE_MODE_PROC(sig_handler_common_tt, | ||
228 | sig_handler_common_skas, SIGIO, NULL); | ||
229 | |||
230 | if(save_pending & SIGALRM_MASK) | ||
231 | real_alarm_handler(SIGALRM, NULL); | ||
232 | |||
233 | if(save_pending & SIGVTALRM_MASK) | ||
234 | real_alarm_handler(SIGVTALRM, NULL); | ||
235 | } | ||
144 | } | 236 | } |
145 | 237 | ||
146 | int get_signals(void) | 238 | int get_signals(void) |
147 | { | 239 | { |
148 | sigset_t mask; | 240 | return signals_enabled; |
149 | |||
150 | if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0) | ||
151 | panic("Failed to get signal mask"); | ||
152 | return(enable_mask(&mask)); | ||
153 | } | 241 | } |
154 | 242 | ||
155 | int set_signals(int enable) | 243 | int set_signals(int enable) |
156 | { | 244 | { |
157 | sigset_t mask; | ||
158 | int ret; | 245 | int ret; |
246 | if(signals_enabled == enable) | ||
247 | return enable; | ||
159 | 248 | ||
160 | sigemptyset(&mask); | 249 | ret = signals_enabled; |
161 | if(enable & (1 << SIGIO_BIT)) | 250 | if(enable) |
162 | sigaddset(&mask, SIGIO); | 251 | unblock_signals(); |
163 | if(enable & (1 << SIGVTALRM_BIT)){ | 252 | else block_signals(); |
164 | sigaddset(&mask, SIGVTALRM); | ||
165 | sigaddset(&mask, SIGALRM); | ||
166 | } | ||
167 | 253 | ||
168 | /* This is safe - sigprocmask is guaranteed to copy locally the | 254 | return ret; |
169 | * value of new_set, do his work and then, at the end, write to | 255 | } |
170 | * old_set. | ||
171 | */ | ||
172 | if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) | ||
173 | panic("Failed to enable signals"); | ||
174 | ret = enable_mask(&mask); | ||
175 | sigemptyset(&mask); | ||
176 | if((enable & (1 << SIGIO_BIT)) == 0) | ||
177 | sigaddset(&mask, SIGIO); | ||
178 | if((enable & (1 << SIGVTALRM_BIT)) == 0){ | ||
179 | sigaddset(&mask, SIGVTALRM); | ||
180 | sigaddset(&mask, SIGALRM); | ||
181 | } | ||
182 | if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0) | ||
183 | panic("Failed to block signals"); | ||
184 | 256 | ||
185 | return(ret); | 257 | void os_usr1_signal(int on) |
258 | { | ||
259 | change_sig(SIGUSR1, on); | ||
186 | } | 260 | } |
diff --git a/arch/um/os-Linux/skas/Makefile b/arch/um/os-Linux/skas/Makefile index eab5386d60a7..5fd8d4dad66a 100644 --- a/arch/um/os-Linux/skas/Makefile +++ b/arch/um/os-Linux/skas/Makefile | |||
@@ -3,8 +3,8 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y := trap.o | 6 | obj-y := mem.o process.o trap.o |
7 | 7 | ||
8 | USER_OBJS := trap.o | 8 | USER_OBJS := mem.o process.o trap.o |
9 | 9 | ||
10 | include arch/um/scripts/Makefile.rules | 10 | include arch/um/scripts/Makefile.rules |
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/os-Linux/skas/mem.c index 1d89640bd502..9890e9090f58 100644 --- a/arch/um/kernel/skas/mem_user.c +++ b/arch/um/os-Linux/skas/mem.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -32,7 +32,7 @@ extern void wait_stub_done(int pid, int sig, char * fname); | |||
32 | static inline unsigned long *check_init_stack(struct mm_id * mm_idp, | 32 | static inline unsigned long *check_init_stack(struct mm_id * mm_idp, |
33 | unsigned long *stack) | 33 | unsigned long *stack) |
34 | { | 34 | { |
35 | if(stack == NULL){ | 35 | if(stack == NULL) { |
36 | stack = (unsigned long *) mm_idp->stack + 2; | 36 | stack = (unsigned long *) mm_idp->stack + 2; |
37 | *stack = 0; | 37 | *stack = 0; |
38 | } | 38 | } |
@@ -45,13 +45,14 @@ int single_count = 0; | |||
45 | int multi_count = 0; | 45 | int multi_count = 0; |
46 | int multi_op_count = 0; | 46 | int multi_op_count = 0; |
47 | 47 | ||
48 | static long do_syscall_stub(struct mm_id *mm_idp, void **addr) | 48 | static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) |
49 | { | 49 | { |
50 | unsigned long regs[MAX_REG_NR]; | 50 | unsigned long regs[MAX_REG_NR]; |
51 | unsigned long *data; | 51 | int n; |
52 | unsigned long *syscall; | ||
53 | long ret, offset; | 52 | long ret, offset; |
54 | int n, pid = mm_idp->u.pid; | 53 | unsigned long * data; |
54 | unsigned long * syscall; | ||
55 | int pid = mm_idp->u.pid; | ||
55 | 56 | ||
56 | if(proc_mm) | 57 | if(proc_mm) |
57 | #warning Need to look up userspace_pid by cpu | 58 | #warning Need to look up userspace_pid by cpu |
@@ -59,10 +60,11 @@ static long do_syscall_stub(struct mm_id *mm_idp, void **addr) | |||
59 | 60 | ||
60 | multi_count++; | 61 | multi_count++; |
61 | 62 | ||
62 | get_safe_registers(regs); | 63 | get_safe_registers(regs); |
63 | regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + | 64 | regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + |
64 | ((unsigned long) &batch_syscall_stub - | 65 | ((unsigned long) &batch_syscall_stub - |
65 | (unsigned long) &__syscall_stub_start); | 66 | (unsigned long) &__syscall_stub_start); |
67 | |||
66 | n = ptrace_setregs(pid, regs); | 68 | n = ptrace_setregs(pid, regs); |
67 | if(n < 0) | 69 | if(n < 0) |
68 | panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", | 70 | panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", |
@@ -80,6 +82,8 @@ static long do_syscall_stub(struct mm_id *mm_idp, void **addr) | |||
80 | if (offset) { | 82 | if (offset) { |
81 | data = (unsigned long *)(mm_idp->stack + | 83 | data = (unsigned long *)(mm_idp->stack + |
82 | offset - UML_CONFIG_STUB_DATA); | 84 | offset - UML_CONFIG_STUB_DATA); |
85 | printk("do_syscall_stub : ret = %d, offset = %d, " | ||
86 | "data = 0x%x\n", ret, offset, data); | ||
83 | syscall = (unsigned long *)((unsigned long)data + data[0]); | 87 | syscall = (unsigned long *)((unsigned long)data + data[0]); |
84 | printk("do_syscall_stub: syscall %ld failed, return value = " | 88 | printk("do_syscall_stub: syscall %ld failed, return value = " |
85 | "0x%lx, expected return value = 0x%lx\n", | 89 | "0x%lx, expected return value = 0x%lx\n", |
@@ -107,32 +111,32 @@ static long do_syscall_stub(struct mm_id *mm_idp, void **addr) | |||
107 | 111 | ||
108 | long run_syscall_stub(struct mm_id * mm_idp, int syscall, | 112 | long run_syscall_stub(struct mm_id * mm_idp, int syscall, |
109 | unsigned long *args, long expected, void **addr, | 113 | unsigned long *args, long expected, void **addr, |
110 | int done) | 114 | int done) |
111 | { | 115 | { |
112 | unsigned long *stack = check_init_stack(mm_idp, *addr); | 116 | unsigned long *stack = check_init_stack(mm_idp, *addr); |
113 | 117 | ||
114 | if(done && *addr == NULL) | 118 | if(done && *addr == NULL) |
115 | single_count++; | 119 | single_count++; |
116 | 120 | ||
117 | *stack += sizeof(long); | 121 | *stack += sizeof(long); |
118 | stack += *stack / sizeof(long); | 122 | stack += *stack / sizeof(long); |
119 | 123 | ||
120 | *stack++ = syscall; | 124 | *stack++ = syscall; |
121 | *stack++ = args[0]; | 125 | *stack++ = args[0]; |
122 | *stack++ = args[1]; | 126 | *stack++ = args[1]; |
123 | *stack++ = args[2]; | 127 | *stack++ = args[2]; |
124 | *stack++ = args[3]; | 128 | *stack++ = args[3]; |
125 | *stack++ = args[4]; | 129 | *stack++ = args[4]; |
126 | *stack++ = args[5]; | 130 | *stack++ = args[5]; |
127 | *stack++ = expected; | 131 | *stack++ = expected; |
128 | *stack = 0; | 132 | *stack = 0; |
129 | multi_op_count++; | 133 | multi_op_count++; |
130 | 134 | ||
131 | if(!done && ((((unsigned long) stack) & ~PAGE_MASK) < | 135 | if(!done && ((((unsigned long) stack) & ~PAGE_MASK) < |
132 | PAGE_SIZE - 10 * sizeof(long))){ | 136 | PAGE_SIZE - 10 * sizeof(long))){ |
133 | *addr = stack; | 137 | *addr = stack; |
134 | return 0; | 138 | return 0; |
135 | } | 139 | } |
136 | 140 | ||
137 | return do_syscall_stub(mm_idp, addr); | 141 | return do_syscall_stub(mm_idp, addr); |
138 | } | 142 | } |
@@ -150,7 +154,7 @@ long syscall_stub_data(struct mm_id * mm_idp, | |||
150 | if((((unsigned long) *addr) & ~PAGE_MASK) >= | 154 | if((((unsigned long) *addr) & ~PAGE_MASK) >= |
151 | PAGE_SIZE - (10 + data_count) * sizeof(long)) { | 155 | PAGE_SIZE - (10 + data_count) * sizeof(long)) { |
152 | ret = do_syscall_stub(mm_idp, addr); | 156 | ret = do_syscall_stub(mm_idp, addr); |
153 | /* in case of error, don't overwrite data on stack */ | 157 | /* in case of error, don't overwrite data on stack */ |
154 | if(ret) | 158 | if(ret) |
155 | return ret; | 159 | return ret; |
156 | } | 160 | } |
@@ -172,39 +176,39 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, | |||
172 | int r, int w, int x, int phys_fd, unsigned long long offset, | 176 | int r, int w, int x, int phys_fd, unsigned long long offset, |
173 | int done, void **data) | 177 | int done, void **data) |
174 | { | 178 | { |
175 | int prot, ret; | 179 | int prot, ret; |
176 | 180 | ||
177 | prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | | 181 | prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | |
178 | (x ? PROT_EXEC : 0); | 182 | (x ? PROT_EXEC : 0); |
179 | 183 | ||
180 | if(proc_mm){ | 184 | if(proc_mm){ |
181 | struct proc_mm_op map; | 185 | struct proc_mm_op map; |
182 | int fd = mm_idp->u.mm_fd; | 186 | int fd = mm_idp->u.mm_fd; |
183 | 187 | ||
184 | map = ((struct proc_mm_op) { .op = MM_MMAP, | 188 | map = ((struct proc_mm_op) { .op = MM_MMAP, |
185 | .u = | 189 | .u = |
186 | { .mmap = | 190 | { .mmap = |
187 | { .addr = virt, | 191 | { .addr = virt, |
188 | .len = len, | 192 | .len = len, |
189 | .prot = prot, | 193 | .prot = prot, |
190 | .flags = MAP_SHARED | | 194 | .flags = MAP_SHARED | |
191 | MAP_FIXED, | 195 | MAP_FIXED, |
192 | .fd = phys_fd, | 196 | .fd = phys_fd, |
193 | .offset= offset | 197 | .offset= offset |
194 | } } } ); | 198 | } } } ); |
195 | ret = os_write_file(fd, &map, sizeof(map)); | 199 | ret = os_write_file(fd, &map, sizeof(map)); |
196 | if(ret != sizeof(map)) | 200 | if(ret != sizeof(map)) |
197 | printk("map : /proc/mm map failed, err = %d\n", -ret); | 201 | printk("map : /proc/mm map failed, err = %d\n", -ret); |
198 | else ret = 0; | 202 | else ret = 0; |
199 | } | 203 | } |
200 | else { | 204 | else { |
201 | unsigned long args[] = { virt, len, prot, | 205 | unsigned long args[] = { virt, len, prot, |
202 | MAP_SHARED | MAP_FIXED, phys_fd, | 206 | MAP_SHARED | MAP_FIXED, phys_fd, |
203 | MMAP_OFFSET(offset) }; | 207 | MMAP_OFFSET(offset) }; |
204 | 208 | ||
205 | ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, | 209 | ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, |
206 | data, done); | 210 | data, done); |
207 | } | 211 | } |
208 | 212 | ||
209 | return ret; | 213 | return ret; |
210 | } | 214 | } |
@@ -212,68 +216,66 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, | |||
212 | int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, | 216 | int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, |
213 | void **data) | 217 | void **data) |
214 | { | 218 | { |
215 | int ret; | 219 | int ret; |
216 | 220 | ||
217 | if(proc_mm){ | 221 | if(proc_mm){ |
218 | struct proc_mm_op unmap; | 222 | struct proc_mm_op unmap; |
219 | int fd = mm_idp->u.mm_fd; | 223 | int fd = mm_idp->u.mm_fd; |
220 | 224 | ||
221 | unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, | 225 | unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, |
222 | .u = | 226 | .u = |
223 | { .munmap = | 227 | { .munmap = |
224 | { .addr = | 228 | { .addr = |
225 | (unsigned long) addr, | 229 | (unsigned long) addr, |
226 | .len = len } } } ); | 230 | .len = len } } } ); |
227 | ret = os_write_file(fd, &unmap, sizeof(unmap)); | 231 | ret = os_write_file(fd, &unmap, sizeof(unmap)); |
228 | if(ret != sizeof(unmap)) | 232 | if(ret != sizeof(unmap)) |
229 | printk("unmap - proc_mm write returned %d\n", ret); | 233 | printk("unmap - proc_mm write returned %d\n", ret); |
230 | else ret = 0; | 234 | else ret = 0; |
231 | } | 235 | } |
232 | else { | 236 | else { |
233 | unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, | 237 | unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, |
234 | 0 }; | 238 | 0 }; |
235 | 239 | ||
236 | ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, | 240 | ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, |
237 | data, done); | 241 | data, done); |
238 | if(ret < 0) | 242 | } |
239 | printk("munmap stub failed, errno = %d\n", ret); | ||
240 | } | ||
241 | 243 | ||
242 | return ret; | 244 | return ret; |
243 | } | 245 | } |
244 | 246 | ||
245 | int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, | 247 | int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, |
246 | int r, int w, int x, int done, void **data) | 248 | int r, int w, int x, int done, void **data) |
247 | { | 249 | { |
248 | struct proc_mm_op protect; | 250 | struct proc_mm_op protect; |
249 | int prot, ret; | 251 | int prot, ret; |
250 | 252 | ||
251 | prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | | 253 | prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | |
252 | (x ? PROT_EXEC : 0); | 254 | (x ? PROT_EXEC : 0); |
253 | 255 | if(proc_mm){ | |
254 | if(proc_mm){ | 256 | int fd = mm_idp->u.mm_fd; |
255 | int fd = mm_idp->u.mm_fd; | 257 | |
256 | protect = ((struct proc_mm_op) { .op = MM_MPROTECT, | 258 | protect = ((struct proc_mm_op) { .op = MM_MPROTECT, |
257 | .u = | 259 | .u = |
258 | { .mprotect = | 260 | { .mprotect = |
259 | { .addr = | 261 | { .addr = |
260 | (unsigned long) addr, | 262 | (unsigned long) addr, |
261 | .len = len, | 263 | .len = len, |
262 | .prot = prot } } } ); | 264 | .prot = prot } } } ); |
263 | 265 | ||
264 | ret = os_write_file(fd, &protect, sizeof(protect)); | 266 | ret = os_write_file(fd, &protect, sizeof(protect)); |
265 | if(ret != sizeof(protect)) | 267 | if(ret != sizeof(protect)) |
266 | printk("protect failed, err = %d", -ret); | 268 | printk("protect failed, err = %d", -ret); |
267 | else ret = 0; | 269 | else ret = 0; |
268 | } | 270 | } |
269 | else { | 271 | else { |
270 | unsigned long args[] = { addr, len, prot, 0, 0, 0 }; | 272 | unsigned long args[] = { addr, len, prot, 0, 0, 0 }; |
271 | 273 | ||
272 | ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, | 274 | ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, |
273 | data, done); | 275 | data, done); |
274 | } | 276 | } |
275 | 277 | ||
276 | return ret; | 278 | return ret; |
277 | } | 279 | } |
278 | 280 | ||
279 | void before_mem_skas(unsigned long unused) | 281 | void before_mem_skas(unsigned long unused) |
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c new file mode 100644 index 000000000000..120a21c5883f --- /dev/null +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -0,0 +1,566 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | #include <unistd.h> | ||
9 | #include <errno.h> | ||
10 | #include <signal.h> | ||
11 | #include <setjmp.h> | ||
12 | #include <sched.h> | ||
13 | #include "ptrace_user.h" | ||
14 | #include <sys/wait.h> | ||
15 | #include <sys/mman.h> | ||
16 | #include <sys/user.h> | ||
17 | #include <sys/time.h> | ||
18 | #include <asm/unistd.h> | ||
19 | #include <asm/types.h> | ||
20 | #include "user.h" | ||
21 | #include "sysdep/ptrace.h" | ||
22 | #include "user_util.h" | ||
23 | #include "kern_util.h" | ||
24 | #include "skas.h" | ||
25 | #include "stub-data.h" | ||
26 | #include "mm_id.h" | ||
27 | #include "sysdep/sigcontext.h" | ||
28 | #include "sysdep/stub.h" | ||
29 | #include "os.h" | ||
30 | #include "proc_mm.h" | ||
31 | #include "skas_ptrace.h" | ||
32 | #include "chan_user.h" | ||
33 | #include "registers.h" | ||
34 | #include "mem.h" | ||
35 | #include "uml-config.h" | ||
36 | #include "process.h" | ||
37 | #include "longjmp.h" | ||
38 | |||
39 | int is_skas_winch(int pid, int fd, void *data) | ||
40 | { | ||
41 | if(pid != os_getpgrp()) | ||
42 | return(0); | ||
43 | |||
44 | register_winch_irq(-1, fd, -1, data); | ||
45 | return(1); | ||
46 | } | ||
47 | |||
48 | void wait_stub_done(int pid, int sig, char * fname) | ||
49 | { | ||
50 | int n, status, err; | ||
51 | |||
52 | do { | ||
53 | if ( sig != -1 ) { | ||
54 | err = ptrace(PTRACE_CONT, pid, 0, sig); | ||
55 | if(err) | ||
56 | panic("%s : continue failed, errno = %d\n", | ||
57 | fname, errno); | ||
58 | } | ||
59 | sig = 0; | ||
60 | |||
61 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | ||
62 | } while((n >= 0) && WIFSTOPPED(status) && | ||
63 | ((WSTOPSIG(status) == SIGVTALRM) || | ||
64 | /* running UML inside a detached screen can cause | ||
65 | * SIGWINCHes | ||
66 | */ | ||
67 | (WSTOPSIG(status) == SIGWINCH))); | ||
68 | |||
69 | if((n < 0) || !WIFSTOPPED(status) || | ||
70 | (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){ | ||
71 | unsigned long regs[HOST_FRAME_SIZE]; | ||
72 | |||
73 | if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) | ||
74 | printk("Failed to get registers from stub, " | ||
75 | "errno = %d\n", errno); | ||
76 | else { | ||
77 | int i; | ||
78 | |||
79 | printk("Stub registers -\n"); | ||
80 | for(i = 0; i < HOST_FRAME_SIZE; i++) | ||
81 | printk("\t%d - %lx\n", i, regs[i]); | ||
82 | } | ||
83 | panic("%s : failed to wait for SIGUSR1/SIGTRAP, " | ||
84 | "pid = %d, n = %d, errno = %d, status = 0x%x\n", | ||
85 | fname, pid, n, errno, status); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | extern unsigned long current_stub_stack(void); | ||
90 | |||
91 | void get_skas_faultinfo(int pid, struct faultinfo * fi) | ||
92 | { | ||
93 | int err; | ||
94 | |||
95 | if(ptrace_faultinfo){ | ||
96 | err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); | ||
97 | if(err) | ||
98 | panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " | ||
99 | "errno = %d\n", errno); | ||
100 | |||
101 | /* Special handling for i386, which has different structs */ | ||
102 | if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) | ||
103 | memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, | ||
104 | sizeof(struct faultinfo) - | ||
105 | sizeof(struct ptrace_faultinfo)); | ||
106 | } | ||
107 | else { | ||
108 | wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo"); | ||
109 | |||
110 | /* faultinfo is prepared by the stub-segv-handler at start of | ||
111 | * the stub stack page. We just have to copy it. | ||
112 | */ | ||
113 | memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | static void handle_segv(int pid, union uml_pt_regs * regs) | ||
118 | { | ||
119 | get_skas_faultinfo(pid, ®s->skas.faultinfo); | ||
120 | segv(regs->skas.faultinfo, 0, 1, NULL); | ||
121 | } | ||
122 | |||
123 | /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ | ||
124 | static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu) | ||
125 | { | ||
126 | int err, status; | ||
127 | |||
128 | /* Mark this as a syscall */ | ||
129 | UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs); | ||
130 | |||
131 | if (!local_using_sysemu) | ||
132 | { | ||
133 | err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, | ||
134 | __NR_getpid); | ||
135 | if(err < 0) | ||
136 | panic("handle_trap - nullifying syscall failed errno = %d\n", | ||
137 | errno); | ||
138 | |||
139 | err = ptrace(PTRACE_SYSCALL, pid, 0, 0); | ||
140 | if(err < 0) | ||
141 | panic("handle_trap - continuing to end of syscall failed, " | ||
142 | "errno = %d\n", errno); | ||
143 | |||
144 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); | ||
145 | if((err < 0) || !WIFSTOPPED(status) || | ||
146 | (WSTOPSIG(status) != SIGTRAP + 0x80)) | ||
147 | panic("handle_trap - failed to wait at end of syscall, " | ||
148 | "errno = %d, status = %d\n", errno, status); | ||
149 | } | ||
150 | |||
151 | handle_syscall(regs); | ||
152 | } | ||
153 | |||
154 | extern int __syscall_stub_start; | ||
155 | |||
156 | static int userspace_tramp(void *stack) | ||
157 | { | ||
158 | void *addr; | ||
159 | |||
160 | ptrace(PTRACE_TRACEME, 0, 0, 0); | ||
161 | |||
162 | init_new_thread_signals(1); | ||
163 | enable_timer(); | ||
164 | |||
165 | if(!proc_mm){ | ||
166 | /* This has a pte, but it can't be mapped in with the usual | ||
167 | * tlb_flush mechanism because this is part of that mechanism | ||
168 | */ | ||
169 | int fd; | ||
170 | __u64 offset; | ||
171 | fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); | ||
172 | addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(), | ||
173 | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); | ||
174 | if(addr == MAP_FAILED){ | ||
175 | printk("mapping mmap stub failed, errno = %d\n", | ||
176 | errno); | ||
177 | exit(1); | ||
178 | } | ||
179 | |||
180 | if(stack != NULL){ | ||
181 | fd = phys_mapping(to_phys(stack), &offset); | ||
182 | addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(), | ||
183 | PROT_READ | PROT_WRITE, | ||
184 | MAP_FIXED | MAP_SHARED, fd, offset); | ||
185 | if(addr == MAP_FAILED){ | ||
186 | printk("mapping segfault stack failed, " | ||
187 | "errno = %d\n", errno); | ||
188 | exit(1); | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | if(!ptrace_faultinfo && (stack != NULL)){ | ||
193 | unsigned long v = UML_CONFIG_STUB_CODE + | ||
194 | (unsigned long) stub_segv_handler - | ||
195 | (unsigned long) &__syscall_stub_start; | ||
196 | |||
197 | set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size()); | ||
198 | set_handler(SIGSEGV, (void *) v, SA_ONSTACK, | ||
199 | SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, | ||
200 | SIGUSR1, -1); | ||
201 | } | ||
202 | |||
203 | os_stop_process(os_getpid()); | ||
204 | return(0); | ||
205 | } | ||
206 | |||
207 | /* Each element set once, and only accessed by a single processor anyway */ | ||
208 | #undef NR_CPUS | ||
209 | #define NR_CPUS 1 | ||
210 | int userspace_pid[NR_CPUS]; | ||
211 | |||
212 | int start_userspace(unsigned long stub_stack) | ||
213 | { | ||
214 | void *stack; | ||
215 | unsigned long sp; | ||
216 | int pid, status, n, flags; | ||
217 | |||
218 | stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, | ||
219 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
220 | if(stack == MAP_FAILED) | ||
221 | panic("start_userspace : mmap failed, errno = %d", errno); | ||
222 | sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); | ||
223 | |||
224 | flags = CLONE_FILES | SIGCHLD; | ||
225 | if(proc_mm) flags |= CLONE_VM; | ||
226 | pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); | ||
227 | if(pid < 0) | ||
228 | panic("start_userspace : clone failed, errno = %d", errno); | ||
229 | |||
230 | do { | ||
231 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | ||
232 | if(n < 0) | ||
233 | panic("start_userspace : wait failed, errno = %d", | ||
234 | errno); | ||
235 | } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); | ||
236 | |||
237 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) | ||
238 | panic("start_userspace : expected SIGSTOP, got status = %d", | ||
239 | status); | ||
240 | |||
241 | if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0) | ||
242 | panic("start_userspace : PTRACE_OLDSETOPTIONS failed, errno=%d\n", | ||
243 | errno); | ||
244 | |||
245 | if(munmap(stack, PAGE_SIZE) < 0) | ||
246 | panic("start_userspace : munmap failed, errno = %d\n", errno); | ||
247 | |||
248 | return(pid); | ||
249 | } | ||
250 | |||
251 | void userspace(union uml_pt_regs *regs) | ||
252 | { | ||
253 | int err, status, op, pid = userspace_pid[0]; | ||
254 | int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ | ||
255 | |||
256 | while(1){ | ||
257 | restore_registers(pid, regs); | ||
258 | |||
259 | /* Now we set local_using_sysemu to be used for one loop */ | ||
260 | local_using_sysemu = get_using_sysemu(); | ||
261 | |||
262 | op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL)); | ||
263 | |||
264 | err = ptrace(op, pid, 0, 0); | ||
265 | if(err) | ||
266 | panic("userspace - could not resume userspace process, " | ||
267 | "pid=%d, ptrace operation = %d, errno = %d\n", | ||
268 | op, errno); | ||
269 | |||
270 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); | ||
271 | if(err < 0) | ||
272 | panic("userspace - waitpid failed, errno = %d\n", | ||
273 | errno); | ||
274 | |||
275 | regs->skas.is_user = 1; | ||
276 | save_registers(pid, regs); | ||
277 | UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ | ||
278 | |||
279 | if(WIFSTOPPED(status)){ | ||
280 | switch(WSTOPSIG(status)){ | ||
281 | case SIGSEGV: | ||
282 | if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) | ||
283 | user_signal(SIGSEGV, regs, pid); | ||
284 | else handle_segv(pid, regs); | ||
285 | break; | ||
286 | case SIGTRAP + 0x80: | ||
287 | handle_trap(pid, regs, local_using_sysemu); | ||
288 | break; | ||
289 | case SIGTRAP: | ||
290 | relay_signal(SIGTRAP, regs); | ||
291 | break; | ||
292 | case SIGIO: | ||
293 | case SIGVTALRM: | ||
294 | case SIGILL: | ||
295 | case SIGBUS: | ||
296 | case SIGFPE: | ||
297 | case SIGWINCH: | ||
298 | user_signal(WSTOPSIG(status), regs, pid); | ||
299 | break; | ||
300 | default: | ||
301 | printk("userspace - child stopped with signal " | ||
302 | "%d\n", WSTOPSIG(status)); | ||
303 | } | ||
304 | pid = userspace_pid[0]; | ||
305 | interrupt_end(); | ||
306 | |||
307 | /* Avoid -ERESTARTSYS handling in host */ | ||
308 | if(PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET) | ||
309 | PT_SYSCALL_NR(regs->skas.regs) = -1; | ||
310 | } | ||
311 | } | ||
312 | } | ||
313 | #define INIT_JMP_NEW_THREAD 0 | ||
314 | #define INIT_JMP_REMOVE_SIGSTACK 1 | ||
315 | #define INIT_JMP_CALLBACK 2 | ||
316 | #define INIT_JMP_HALT 3 | ||
317 | #define INIT_JMP_REBOOT 4 | ||
318 | |||
319 | int copy_context_skas0(unsigned long new_stack, int pid) | ||
320 | { | ||
321 | int err; | ||
322 | unsigned long regs[MAX_REG_NR]; | ||
323 | unsigned long current_stack = current_stub_stack(); | ||
324 | struct stub_data *data = (struct stub_data *) current_stack; | ||
325 | struct stub_data *child_data = (struct stub_data *) new_stack; | ||
326 | __u64 new_offset; | ||
327 | int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset); | ||
328 | |||
329 | /* prepare offset and fd of child's stack as argument for parent's | ||
330 | * and child's mmap2 calls | ||
331 | */ | ||
332 | *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), | ||
333 | .fd = new_fd, | ||
334 | .timer = ((struct itimerval) | ||
335 | { { 0, 1000000 / hz() }, | ||
336 | { 0, 1000000 / hz() }})}); | ||
337 | get_safe_registers(regs); | ||
338 | |||
339 | /* Set parent's instruction pointer to start of clone-stub */ | ||
340 | regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + | ||
341 | (unsigned long) stub_clone_handler - | ||
342 | (unsigned long) &__syscall_stub_start; | ||
343 | regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE - | ||
344 | sizeof(void *); | ||
345 | #ifdef __SIGNAL_FRAMESIZE | ||
346 | regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; | ||
347 | #endif | ||
348 | err = ptrace_setregs(pid, regs); | ||
349 | if(err < 0) | ||
350 | panic("copy_context_skas0 : PTRACE_SETREGS failed, " | ||
351 | "pid = %d, errno = %d\n", pid, errno); | ||
352 | |||
353 | /* set a well known return code for detection of child write failure */ | ||
354 | child_data->err = 12345678; | ||
355 | |||
356 | /* Wait, until parent has finished its work: read child's pid from | ||
357 | * parent's stack, and check, if bad result. | ||
358 | */ | ||
359 | wait_stub_done(pid, 0, "copy_context_skas0"); | ||
360 | |||
361 | pid = data->err; | ||
362 | if(pid < 0) | ||
363 | panic("copy_context_skas0 - stub-parent reports error %d\n", | ||
364 | pid); | ||
365 | |||
366 | /* Wait, until child has finished too: read child's result from | ||
367 | * child's stack and check it. | ||
368 | */ | ||
369 | wait_stub_done(pid, -1, "copy_context_skas0"); | ||
370 | if (child_data->err != UML_CONFIG_STUB_DATA) | ||
371 | panic("copy_context_skas0 - stub-child reports error %d\n", | ||
372 | child_data->err); | ||
373 | |||
374 | if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, | ||
375 | (void *)PTRACE_O_TRACESYSGOOD) < 0) | ||
376 | panic("copy_context_skas0 : PTRACE_OLDSETOPTIONS failed, " | ||
377 | "errno = %d\n", errno); | ||
378 | |||
379 | return pid; | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * This is used only, if stub pages are needed, while proc_mm is | ||
384 | * availabl. Opening /proc/mm creates a new mm_context, which lacks | ||
385 | * the stub-pages. Thus, we map them using /proc/mm-fd | ||
386 | */ | ||
387 | void map_stub_pages(int fd, unsigned long code, | ||
388 | unsigned long data, unsigned long stack) | ||
389 | { | ||
390 | struct proc_mm_op mmop; | ||
391 | int n; | ||
392 | __u64 code_offset; | ||
393 | int code_fd = phys_mapping(to_phys((void *) &__syscall_stub_start), | ||
394 | &code_offset); | ||
395 | |||
396 | mmop = ((struct proc_mm_op) { .op = MM_MMAP, | ||
397 | .u = | ||
398 | { .mmap = | ||
399 | { .addr = code, | ||
400 | .len = PAGE_SIZE, | ||
401 | .prot = PROT_EXEC, | ||
402 | .flags = MAP_FIXED | MAP_PRIVATE, | ||
403 | .fd = code_fd, | ||
404 | .offset = code_offset | ||
405 | } } }); | ||
406 | n = os_write_file(fd, &mmop, sizeof(mmop)); | ||
407 | if(n != sizeof(mmop)) | ||
408 | panic("map_stub_pages : /proc/mm map for code failed, " | ||
409 | "err = %d\n", -n); | ||
410 | |||
411 | if ( stack ) { | ||
412 | __u64 map_offset; | ||
413 | int map_fd = phys_mapping(to_phys((void *)stack), &map_offset); | ||
414 | mmop = ((struct proc_mm_op) | ||
415 | { .op = MM_MMAP, | ||
416 | .u = | ||
417 | { .mmap = | ||
418 | { .addr = data, | ||
419 | .len = PAGE_SIZE, | ||
420 | .prot = PROT_READ | PROT_WRITE, | ||
421 | .flags = MAP_FIXED | MAP_SHARED, | ||
422 | .fd = map_fd, | ||
423 | .offset = map_offset | ||
424 | } } }); | ||
425 | n = os_write_file(fd, &mmop, sizeof(mmop)); | ||
426 | if(n != sizeof(mmop)) | ||
427 | panic("map_stub_pages : /proc/mm map for data failed, " | ||
428 | "err = %d\n", -n); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, | ||
433 | void (*handler)(int)) | ||
434 | { | ||
435 | unsigned long flags; | ||
436 | sigjmp_buf switch_buf, fork_buf; | ||
437 | int enable; | ||
438 | |||
439 | *switch_buf_ptr = &switch_buf; | ||
440 | *fork_buf_ptr = &fork_buf; | ||
441 | |||
442 | /* Somewhat subtle - siglongjmp restores the signal mask before doing | ||
443 | * the longjmp. This means that when jumping from one stack to another | ||
444 | * when the target stack has interrupts enabled, an interrupt may occur | ||
445 | * on the source stack. This is bad when starting up a process because | ||
446 | * it's not supposed to get timer ticks until it has been scheduled. | ||
447 | * So, we disable interrupts around the sigsetjmp to ensure that | ||
448 | * they can't happen until we get back here where they are safe. | ||
449 | */ | ||
450 | flags = get_signals(); | ||
451 | block_signals(); | ||
452 | if(UML_SIGSETJMP(&fork_buf, enable) == 0) | ||
453 | new_thread_proc(stack, handler); | ||
454 | |||
455 | remove_sigstack(); | ||
456 | |||
457 | set_signals(flags); | ||
458 | } | ||
459 | |||
460 | void thread_wait(void *sw, void *fb) | ||
461 | { | ||
462 | sigjmp_buf buf, **switch_buf = sw, *fork_buf; | ||
463 | int enable; | ||
464 | |||
465 | *switch_buf = &buf; | ||
466 | fork_buf = fb; | ||
467 | if(UML_SIGSETJMP(&buf, enable) == 0) | ||
468 | siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK); | ||
469 | } | ||
470 | |||
471 | void switch_threads(void *me, void *next) | ||
472 | { | ||
473 | sigjmp_buf my_buf, **me_ptr = me, *next_buf = next; | ||
474 | int enable; | ||
475 | |||
476 | *me_ptr = &my_buf; | ||
477 | if(UML_SIGSETJMP(&my_buf, enable) == 0) | ||
478 | UML_SIGLONGJMP(next_buf, 1); | ||
479 | } | ||
480 | |||
481 | static sigjmp_buf initial_jmpbuf; | ||
482 | |||
483 | /* XXX Make these percpu */ | ||
484 | static void (*cb_proc)(void *arg); | ||
485 | static void *cb_arg; | ||
486 | static sigjmp_buf *cb_back; | ||
487 | |||
488 | int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) | ||
489 | { | ||
490 | sigjmp_buf **switch_buf = switch_buf_ptr; | ||
491 | int n, enable; | ||
492 | |||
493 | set_handler(SIGWINCH, (__sighandler_t) sig_handler, | ||
494 | SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, | ||
495 | SIGVTALRM, -1); | ||
496 | |||
497 | *fork_buf_ptr = &initial_jmpbuf; | ||
498 | n = UML_SIGSETJMP(&initial_jmpbuf, enable); | ||
499 | switch(n){ | ||
500 | case INIT_JMP_NEW_THREAD: | ||
501 | new_thread_proc((void *) stack, new_thread_handler); | ||
502 | break; | ||
503 | case INIT_JMP_REMOVE_SIGSTACK: | ||
504 | remove_sigstack(); | ||
505 | break; | ||
506 | case INIT_JMP_CALLBACK: | ||
507 | (*cb_proc)(cb_arg); | ||
508 | UML_SIGLONGJMP(cb_back, 1); | ||
509 | break; | ||
510 | case INIT_JMP_HALT: | ||
511 | kmalloc_ok = 0; | ||
512 | return(0); | ||
513 | case INIT_JMP_REBOOT: | ||
514 | kmalloc_ok = 0; | ||
515 | return(1); | ||
516 | default: | ||
517 | panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); | ||
518 | } | ||
519 | UML_SIGLONGJMP(*switch_buf, 1); | ||
520 | } | ||
521 | |||
522 | void initial_thread_cb_skas(void (*proc)(void *), void *arg) | ||
523 | { | ||
524 | sigjmp_buf here; | ||
525 | int enable; | ||
526 | |||
527 | cb_proc = proc; | ||
528 | cb_arg = arg; | ||
529 | cb_back = &here; | ||
530 | |||
531 | block_signals(); | ||
532 | if(UML_SIGSETJMP(&here, enable) == 0) | ||
533 | UML_SIGLONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK); | ||
534 | unblock_signals(); | ||
535 | |||
536 | cb_proc = NULL; | ||
537 | cb_arg = NULL; | ||
538 | cb_back = NULL; | ||
539 | } | ||
540 | |||
541 | void halt_skas(void) | ||
542 | { | ||
543 | block_signals(); | ||
544 | UML_SIGLONGJMP(&initial_jmpbuf, INIT_JMP_HALT); | ||
545 | } | ||
546 | |||
547 | void reboot_skas(void) | ||
548 | { | ||
549 | block_signals(); | ||
550 | UML_SIGLONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT); | ||
551 | } | ||
552 | |||
553 | void switch_mm_skas(struct mm_id *mm_idp) | ||
554 | { | ||
555 | int err; | ||
556 | |||
557 | #warning need cpu pid in switch_mm_skas | ||
558 | if(proc_mm){ | ||
559 | err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, | ||
560 | mm_idp->u.mm_fd); | ||
561 | if(err) | ||
562 | panic("switch_mm_skas - PTRACE_SWITCH_MM failed, " | ||
563 | "errno = %d\n", errno); | ||
564 | } | ||
565 | else userspace_pid[0] = mm_idp->u.pid; | ||
566 | } | ||
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index b47e5e71d1a5..6c5b17ed59e1 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include "irq_user.h" | 29 | #include "irq_user.h" |
30 | #include "ptrace_user.h" | 30 | #include "ptrace_user.h" |
31 | #include "mem_user.h" | 31 | #include "mem_user.h" |
32 | #include "time_user.h" | ||
33 | #include "init.h" | 32 | #include "init.h" |
34 | #include "os.h" | 33 | #include "os.h" |
35 | #include "uml-config.h" | 34 | #include "uml-config.h" |
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index cf30a39bc484..6f7626775acb 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c | |||
@@ -1,21 +1,128 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <stdio.h> | ||
1 | #include <stdlib.h> | 7 | #include <stdlib.h> |
8 | #include <unistd.h> | ||
9 | #include <time.h> | ||
2 | #include <sys/time.h> | 10 | #include <sys/time.h> |
11 | #include <signal.h> | ||
12 | #include <errno.h> | ||
13 | #include "user_util.h" | ||
14 | #include "kern_util.h" | ||
15 | #include "user.h" | ||
16 | #include "process.h" | ||
17 | #include "kern_constants.h" | ||
18 | #include "os.h" | ||
19 | |||
20 | /* XXX This really needs to be declared and initialized in a kernel file since | ||
21 | * it's in <linux/time.h> | ||
22 | */ | ||
23 | extern struct timespec wall_to_monotonic; | ||
24 | |||
25 | static void set_interval(int timer_type) | ||
26 | { | ||
27 | int usec = 1000000/hz(); | ||
28 | struct itimerval interval = ((struct itimerval) { { 0, usec }, | ||
29 | { 0, usec } }); | ||
30 | |||
31 | if(setitimer(timer_type, &interval, NULL) == -1) | ||
32 | panic("setitimer failed - errno = %d\n", errno); | ||
33 | } | ||
34 | |||
35 | void enable_timer(void) | ||
36 | { | ||
37 | set_interval(ITIMER_VIRTUAL); | ||
38 | } | ||
39 | |||
40 | void disable_timer(void) | ||
41 | { | ||
42 | struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); | ||
43 | if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) || | ||
44 | (setitimer(ITIMER_REAL, &disable, NULL) < 0)) | ||
45 | printk("disnable_timer - setitimer failed, errno = %d\n", | ||
46 | errno); | ||
47 | /* If there are signals already queued, after unblocking ignore them */ | ||
48 | set_handler(SIGALRM, SIG_IGN, 0, -1); | ||
49 | set_handler(SIGVTALRM, SIG_IGN, 0, -1); | ||
50 | } | ||
51 | |||
52 | void switch_timers(int to_real) | ||
53 | { | ||
54 | struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); | ||
55 | struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() }, | ||
56 | { 0, 1000000/hz() }}); | ||
57 | int old, new; | ||
58 | |||
59 | if(to_real){ | ||
60 | old = ITIMER_VIRTUAL; | ||
61 | new = ITIMER_REAL; | ||
62 | } | ||
63 | else { | ||
64 | old = ITIMER_REAL; | ||
65 | new = ITIMER_VIRTUAL; | ||
66 | } | ||
67 | |||
68 | if((setitimer(old, &disable, NULL) < 0) || | ||
69 | (setitimer(new, &enable, NULL))) | ||
70 | printk("switch_timers - setitimer failed, errno = %d\n", | ||
71 | errno); | ||
72 | } | ||
3 | 73 | ||
4 | unsigned long long os_usecs(void) | 74 | void uml_idle_timer(void) |
75 | { | ||
76 | if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) | ||
77 | panic("Couldn't unset SIGVTALRM handler"); | ||
78 | |||
79 | set_handler(SIGALRM, (__sighandler_t) alarm_handler, | ||
80 | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); | ||
81 | set_interval(ITIMER_REAL); | ||
82 | } | ||
83 | |||
84 | extern void ktime_get_ts(struct timespec *ts); | ||
85 | #define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts) | ||
86 | |||
87 | void time_init(void) | ||
88 | { | ||
89 | struct timespec now; | ||
90 | |||
91 | if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) | ||
92 | panic("Couldn't set SIGVTALRM handler"); | ||
93 | set_interval(ITIMER_VIRTUAL); | ||
94 | |||
95 | do_posix_clock_monotonic_gettime(&now); | ||
96 | wall_to_monotonic.tv_sec = -now.tv_sec; | ||
97 | wall_to_monotonic.tv_nsec = -now.tv_nsec; | ||
98 | } | ||
99 | |||
100 | unsigned long long os_nsecs(void) | ||
5 | { | 101 | { |
6 | struct timeval tv; | 102 | struct timeval tv; |
7 | 103 | ||
8 | gettimeofday(&tv, NULL); | 104 | gettimeofday(&tv, NULL); |
9 | return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec); | 105 | return((unsigned long long) tv.tv_sec * BILLION + tv.tv_usec * 1000); |
10 | } | 106 | } |
11 | 107 | ||
12 | /* | 108 | void idle_sleep(int secs) |
13 | * Overrides for Emacs so that we follow Linus's tabbing style. | 109 | { |
14 | * Emacs will notice this stuff at the end of the file and automatically | 110 | struct timespec ts; |
15 | * adjust the settings for this buffer only. This must remain at the end | 111 | |
16 | * of the file. | 112 | ts.tv_sec = secs; |
17 | * --------------------------------------------------------------------------- | 113 | ts.tv_nsec = 0; |
18 | * Local variables: | 114 | nanosleep(&ts, NULL); |
19 | * c-file-style: "linux" | 115 | } |
20 | * End: | 116 | |
21 | */ | 117 | /* XXX This partly duplicates init_irq_signals */ |
118 | |||
119 | void user_time_init(void) | ||
120 | { | ||
121 | set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, | ||
122 | SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, | ||
123 | SIGALRM, SIGUSR2, -1); | ||
124 | set_handler(SIGALRM, (__sighandler_t) alarm_handler, | ||
125 | SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, | ||
126 | SIGVTALRM, SIGUSR2, -1); | ||
127 | set_interval(ITIMER_VIRTUAL); | ||
128 | } | ||
diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c index 321e1c8e227d..a9f6b26f9828 100644 --- a/arch/um/os-Linux/trap.c +++ b/arch/um/os-Linux/trap.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "user_util.h" | 10 | #include "user_util.h" |
11 | #include "os.h" | 11 | #include "os.h" |
12 | #include "mode.h" | 12 | #include "mode.h" |
13 | #include "longjmp.h" | ||
13 | 14 | ||
14 | void usr2_handler(int sig, union uml_pt_regs *regs) | 15 | void usr2_handler(int sig, union uml_pt_regs *regs) |
15 | { | 16 | { |
@@ -36,5 +37,5 @@ void do_longjmp(void *b, int val) | |||
36 | { | 37 | { |
37 | sigjmp_buf *buf = b; | 38 | sigjmp_buf *buf = b; |
38 | 39 | ||
39 | siglongjmp(*buf, val); | 40 | UML_SIGLONGJMP(buf, val); |
40 | } | 41 | } |
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c index cb2648b79d0f..919d19f11537 100644 --- a/arch/um/os-Linux/tt.c +++ b/arch/um/os-Linux/tt.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include "sysdep/sigcontext.h" | 27 | #include "sysdep/sigcontext.h" |
28 | #include "irq_user.h" | 28 | #include "irq_user.h" |
29 | #include "ptrace_user.h" | 29 | #include "ptrace_user.h" |
30 | #include "time_user.h" | ||
31 | #include "init.h" | 30 | #include "init.h" |
32 | #include "os.h" | 31 | #include "os.h" |
33 | #include "uml-config.h" | 32 | #include "uml-config.h" |
@@ -63,6 +62,54 @@ void kill_child_dead(int pid) | |||
63 | } while(1); | 62 | } while(1); |
64 | } | 63 | } |
65 | 64 | ||
65 | void stop(void) | ||
66 | { | ||
67 | while(1) sleep(1000000); | ||
68 | } | ||
69 | |||
70 | int wait_for_stop(int pid, int sig, int cont_type, void *relay) | ||
71 | { | ||
72 | sigset_t *relay_signals = relay; | ||
73 | int status, ret; | ||
74 | |||
75 | while(1){ | ||
76 | CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED)); | ||
77 | if((ret < 0) || | ||
78 | !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ | ||
79 | if(ret < 0){ | ||
80 | printk("wait failed, errno = %d\n", | ||
81 | errno); | ||
82 | } | ||
83 | else if(WIFEXITED(status)) | ||
84 | printk("process %d exited with status %d\n", | ||
85 | pid, WEXITSTATUS(status)); | ||
86 | else if(WIFSIGNALED(status)) | ||
87 | printk("process %d exited with signal %d\n", | ||
88 | pid, WTERMSIG(status)); | ||
89 | else if((WSTOPSIG(status) == SIGVTALRM) || | ||
90 | (WSTOPSIG(status) == SIGALRM) || | ||
91 | (WSTOPSIG(status) == SIGIO) || | ||
92 | (WSTOPSIG(status) == SIGPROF) || | ||
93 | (WSTOPSIG(status) == SIGCHLD) || | ||
94 | (WSTOPSIG(status) == SIGWINCH) || | ||
95 | (WSTOPSIG(status) == SIGINT)){ | ||
96 | ptrace(cont_type, pid, 0, WSTOPSIG(status)); | ||
97 | continue; | ||
98 | } | ||
99 | else if((relay_signals != NULL) && | ||
100 | sigismember(relay_signals, WSTOPSIG(status))){ | ||
101 | ptrace(cont_type, pid, 0, WSTOPSIG(status)); | ||
102 | continue; | ||
103 | } | ||
104 | else printk("process %d stopped with signal %d\n", | ||
105 | pid, WSTOPSIG(status)); | ||
106 | panic("wait_for_stop failed to wait for %d to stop " | ||
107 | "with %d\n", pid, sig); | ||
108 | } | ||
109 | return(status); | ||
110 | } | ||
111 | } | ||
112 | |||
66 | /* | 113 | /* |
67 | *------------------------- | 114 | *------------------------- |
68 | * only for tt mode (will be deleted in future...) | 115 | * only for tt mode (will be deleted in future...) |
diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c index 38d710158c3d..166fb66995df 100644 --- a/arch/um/os-Linux/uaccess.c +++ b/arch/um/os-Linux/uaccess.c | |||
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | #include <setjmp.h> | 7 | #include <setjmp.h> |
8 | #include <string.h> | 8 | #include <string.h> |
9 | #include "longjmp.h" | ||
9 | 10 | ||
10 | unsigned long __do_user_copy(void *to, const void *from, int n, | 11 | unsigned long __do_user_copy(void *to, const void *from, int n, |
11 | void **fault_addr, void **fault_catcher, | 12 | void **fault_addr, void **fault_catcher, |
@@ -13,10 +14,11 @@ unsigned long __do_user_copy(void *to, const void *from, int n, | |||
13 | int n), int *faulted_out) | 14 | int n), int *faulted_out) |
14 | { | 15 | { |
15 | unsigned long *faddrp = (unsigned long *) fault_addr, ret; | 16 | unsigned long *faddrp = (unsigned long *) fault_addr, ret; |
17 | int enable; | ||
16 | 18 | ||
17 | sigjmp_buf jbuf; | 19 | sigjmp_buf jbuf; |
18 | *fault_catcher = &jbuf; | 20 | *fault_catcher = &jbuf; |
19 | if(sigsetjmp(jbuf, 1) == 0){ | 21 | if(UML_SIGSETJMP(&jbuf, enable) == 0){ |
20 | (*op)(to, from, n); | 22 | (*op)(to, from, n); |
21 | ret = 0; | 23 | ret = 0; |
22 | *faulted_out = 0; | 24 | *faulted_out = 0; |
diff --git a/arch/um/kernel/user_util.c b/arch/um/os-Linux/util.c index 4c231161f257..e32065e2fdc8 100644 --- a/arch/um/kernel/user_util.c +++ b/arch/um/os-Linux/util.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -29,17 +29,14 @@ | |||
29 | #include "init.h" | 29 | #include "init.h" |
30 | #include "ptrace_user.h" | 30 | #include "ptrace_user.h" |
31 | #include "uml-config.h" | 31 | #include "uml-config.h" |
32 | 32 | #include "os.h" | |
33 | void stop(void) | 33 | #include "longjmp.h" |
34 | { | ||
35 | while(1) sleep(1000000); | ||
36 | } | ||
37 | 34 | ||
38 | void stack_protections(unsigned long address) | 35 | void stack_protections(unsigned long address) |
39 | { | 36 | { |
40 | int prot = PROT_READ | PROT_WRITE | PROT_EXEC; | 37 | int prot = PROT_READ | PROT_WRITE | PROT_EXEC; |
41 | 38 | ||
42 | if(mprotect((void *) address, page_size(), prot) < 0) | 39 | if(mprotect((void *) address, page_size(), prot) < 0) |
43 | panic("protecting stack failed, errno = %d", errno); | 40 | panic("protecting stack failed, errno = %d", errno); |
44 | } | 41 | } |
45 | 42 | ||
@@ -59,49 +56,6 @@ void task_protections(unsigned long address) | |||
59 | panic("protecting stack failed, errno = %d", errno); | 56 | panic("protecting stack failed, errno = %d", errno); |
60 | } | 57 | } |
61 | 58 | ||
62 | int wait_for_stop(int pid, int sig, int cont_type, void *relay) | ||
63 | { | ||
64 | sigset_t *relay_signals = relay; | ||
65 | int status, ret; | ||
66 | |||
67 | while(1){ | ||
68 | CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED)); | ||
69 | if((ret < 0) || | ||
70 | !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ | ||
71 | if(ret < 0){ | ||
72 | printk("wait failed, errno = %d\n", | ||
73 | errno); | ||
74 | } | ||
75 | else if(WIFEXITED(status)) | ||
76 | printk("process %d exited with status %d\n", | ||
77 | pid, WEXITSTATUS(status)); | ||
78 | else if(WIFSIGNALED(status)) | ||
79 | printk("process %d exited with signal %d\n", | ||
80 | pid, WTERMSIG(status)); | ||
81 | else if((WSTOPSIG(status) == SIGVTALRM) || | ||
82 | (WSTOPSIG(status) == SIGALRM) || | ||
83 | (WSTOPSIG(status) == SIGIO) || | ||
84 | (WSTOPSIG(status) == SIGPROF) || | ||
85 | (WSTOPSIG(status) == SIGCHLD) || | ||
86 | (WSTOPSIG(status) == SIGWINCH) || | ||
87 | (WSTOPSIG(status) == SIGINT)){ | ||
88 | ptrace(cont_type, pid, 0, WSTOPSIG(status)); | ||
89 | continue; | ||
90 | } | ||
91 | else if((relay_signals != NULL) && | ||
92 | sigismember(relay_signals, WSTOPSIG(status))){ | ||
93 | ptrace(cont_type, pid, 0, WSTOPSIG(status)); | ||
94 | continue; | ||
95 | } | ||
96 | else printk("process %d stopped with signal %d\n", | ||
97 | pid, WSTOPSIG(status)); | ||
98 | panic("wait_for_stop failed to wait for %d to stop " | ||
99 | "with %d\n", pid, sig); | ||
100 | } | ||
101 | return(status); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | int raw(int fd) | 59 | int raw(int fd) |
106 | { | 60 | { |
107 | struct termios tt; | 61 | struct termios tt; |
@@ -113,7 +67,7 @@ int raw(int fd) | |||
113 | 67 | ||
114 | cfmakeraw(&tt); | 68 | cfmakeraw(&tt); |
115 | 69 | ||
116 | CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); | 70 | CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); |
117 | if(err < 0) | 71 | if(err < 0) |
118 | return -errno; | 72 | return -errno; |
119 | 73 | ||
@@ -149,7 +103,7 @@ void setup_hostinfo(void) | |||
149 | 103 | ||
150 | int setjmp_wrapper(void (*proc)(void *, void *), ...) | 104 | int setjmp_wrapper(void (*proc)(void *, void *), ...) |
151 | { | 105 | { |
152 | va_list args; | 106 | va_list args; |
153 | sigjmp_buf buf; | 107 | sigjmp_buf buf; |
154 | int n; | 108 | int n; |
155 | 109 | ||
@@ -161,14 +115,3 @@ int setjmp_wrapper(void (*proc)(void *, void *), ...) | |||
161 | va_end(args); | 115 | va_end(args); |
162 | return(n); | 116 | return(n); |
163 | } | 117 | } |
164 | |||
165 | /* | ||
166 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
167 | * Emacs will notice this stuff at the end of the file and automatically | ||
168 | * adjust the settings for this buffer only. This must remain at the end | ||
169 | * of the file. | ||
170 | * --------------------------------------------------------------------------- | ||
171 | * Local variables: | ||
172 | * c-file-style: "linux" | ||
173 | * End: | ||
174 | */ | ||
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index 17746b4c08ff..0cdfd4481d5e 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include "choose-mode.h" | 16 | #include "choose-mode.h" |
17 | #include "kern.h" | 17 | #include "kern.h" |
18 | #include "mode_kern.h" | 18 | #include "mode_kern.h" |
19 | #include "proc_mm.h" | ||
20 | #include "os.h" | ||
19 | 21 | ||
20 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); | 22 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); |
21 | 23 | ||
@@ -456,13 +458,14 @@ long init_new_ldt(struct mmu_context_skas * new_mm, | |||
456 | int i; | 458 | int i; |
457 | long page, err=0; | 459 | long page, err=0; |
458 | void *addr = NULL; | 460 | void *addr = NULL; |
461 | struct proc_mm_op copy; | ||
459 | 462 | ||
460 | memset(&desc, 0, sizeof(desc)); | ||
461 | 463 | ||
462 | if(!ptrace_ldt) | 464 | if(!ptrace_ldt) |
463 | init_MUTEX(&new_mm->ldt.semaphore); | 465 | init_MUTEX(&new_mm->ldt.semaphore); |
464 | 466 | ||
465 | if(!from_mm){ | 467 | if(!from_mm){ |
468 | memset(&desc, 0, sizeof(desc)); | ||
466 | /* | 469 | /* |
467 | * We have to initialize a clean ldt. | 470 | * We have to initialize a clean ldt. |
468 | */ | 471 | */ |
@@ -494,8 +497,26 @@ long init_new_ldt(struct mmu_context_skas * new_mm, | |||
494 | } | 497 | } |
495 | } | 498 | } |
496 | new_mm->ldt.entry_count = 0; | 499 | new_mm->ldt.entry_count = 0; |
500 | |||
501 | goto out; | ||
497 | } | 502 | } |
498 | else if (!ptrace_ldt) { | 503 | |
504 | if(proc_mm){ | ||
505 | /* We have a valid from_mm, so we now have to copy the LDT of | ||
506 | * from_mm to new_mm, because using proc_mm an new mm with | ||
507 | * an empty/default LDT was created in new_mm() | ||
508 | */ | ||
509 | copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, | ||
510 | .u = | ||
511 | { .copy_segments = | ||
512 | from_mm->id.u.mm_fd } } ); | ||
513 | i = os_write_file(new_mm->id.u.mm_fd, ©, sizeof(copy)); | ||
514 | if(i != sizeof(copy)) | ||
515 | printk("new_mm : /proc/mm copy_segments failed, " | ||
516 | "err = %d\n", -i); | ||
517 | } | ||
518 | |||
519 | if(!ptrace_ldt) { | ||
499 | /* Our local LDT is used to supply the data for | 520 | /* Our local LDT is used to supply the data for |
500 | * modify_ldt(READLDT), if PTRACE_LDT isn't available, | 521 | * modify_ldt(READLDT), if PTRACE_LDT isn't available, |
501 | * i.e., we have to use the stub for modify_ldt, which | 522 | * i.e., we have to use the stub for modify_ldt, which |
@@ -524,6 +545,7 @@ long init_new_ldt(struct mmu_context_skas * new_mm, | |||
524 | up(&from_mm->ldt.semaphore); | 545 | up(&from_mm->ldt.semaphore); |
525 | } | 546 | } |
526 | 547 | ||
548 | out: | ||
527 | return err; | 549 | return err; |
528 | } | 550 | } |
529 | 551 | ||