xref: /linux/arch/um/os-Linux/skas/mem.c (revision ba6e8564f459211117ce300eae2c7fdd23befe34)
1 /*
2  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5 
6 #include <signal.h>
7 #include <errno.h>
8 #include <string.h>
9 #include <sys/mman.h>
10 #include <sys/wait.h>
11 #include <asm/page.h>
12 #include <asm/unistd.h>
13 #include "mem_user.h"
14 #include "mem.h"
15 #include "skas.h"
16 #include "user.h"
17 #include "os.h"
18 #include "proc_mm.h"
19 #include "ptrace_user.h"
20 #include "user_util.h"
21 #include "kern_util.h"
22 #include "task.h"
23 #include "registers.h"
24 #include "uml-config.h"
25 #include "sysdep/ptrace.h"
26 #include "sysdep/stub.h"
27 
28 extern unsigned long batch_syscall_stub, __syscall_stub_start;
29 
30 extern void wait_stub_done(int pid, int sig, char * fname);
31 
32 static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
33 					      unsigned long *stack)
34 {
35 	if(stack == NULL) {
36 		stack = (unsigned long *) mm_idp->stack + 2;
37 		*stack = 0;
38 	}
39 	return stack;
40 }
41 
42 extern int proc_mm;
43 
44 int single_count = 0;
45 int multi_count = 0;
46 int multi_op_count = 0;
47 
48 static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
49 {
50 	unsigned long regs[MAX_REG_NR];
51 	int n, i;
52 	long ret, offset;
53 	unsigned long * data;
54 	unsigned long * syscall;
55 	int pid = mm_idp->u.pid;
56 
57 	if(proc_mm)
58 #warning Need to look up userspace_pid by cpu
59 		pid = userspace_pid[0];
60 
61 	multi_count++;
62 
63 	get_safe_registers(regs, NULL);
64 	regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
65 		((unsigned long) &batch_syscall_stub -
66 		 (unsigned long) &__syscall_stub_start);
67 
68 	n = ptrace_setregs(pid, regs);
69 	if(n < 0){
70 		printk("Registers - \n");
71 		for(i = 0; i < MAX_REG_NR; i++)
72 			printk("\t%d\t0x%lx\n", i, regs[i]);
73 		panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
74 		      -n);
75 	}
76 
77 	wait_stub_done(pid, 0, "do_syscall_stub");
78 
79 	/* When the stub stops, we find the following values on the
80 	 * beginning of the stack:
81 	 * (long )return_value
82 	 * (long )offset to failed sycall-data (0, if no error)
83 	 */
84 	ret = *((unsigned long *) mm_idp->stack);
85 	offset = *((unsigned long *) mm_idp->stack + 1);
86 	if (offset) {
87 		data = (unsigned long *)(mm_idp->stack +
88 					 offset - UML_CONFIG_STUB_DATA);
89 		printk("do_syscall_stub : ret = %ld, offset = %ld, "
90 		       "data = %p\n", ret, offset, data);
91 		syscall = (unsigned long *)((unsigned long)data + data[0]);
92 		printk("do_syscall_stub: syscall %ld failed, return value = "
93 		       "0x%lx, expected return value = 0x%lx\n",
94 		       syscall[0], ret, syscall[7]);
95 		printk("    syscall parameters: "
96 		       "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
97 		       syscall[1], syscall[2], syscall[3],
98 		       syscall[4], syscall[5], syscall[6]);
99 		for(n = 1; n < data[0]/sizeof(long); n++) {
100 			if(n == 1)
101 				printk("    additional syscall data:");
102 			if(n % 4 == 1)
103 				printk("\n      ");
104 			printk("  0x%lx", data[n]);
105 		}
106 		if(n > 1)
107 			printk("\n");
108 	}
109 	else ret = 0;
110 
111 	*addr = check_init_stack(mm_idp, NULL);
112 
113 	return ret;
114 }
115 
116 long run_syscall_stub(struct mm_id * mm_idp, int syscall,
117 		      unsigned long *args, long expected, void **addr,
118 		      int done)
119 {
120 	unsigned long *stack = check_init_stack(mm_idp, *addr);
121 
122 	if(done && *addr == NULL)
123 		single_count++;
124 
125 	*stack += sizeof(long);
126 	stack += *stack / sizeof(long);
127 
128 	*stack++ = syscall;
129 	*stack++ = args[0];
130 	*stack++ = args[1];
131 	*stack++ = args[2];
132 	*stack++ = args[3];
133 	*stack++ = args[4];
134 	*stack++ = args[5];
135 	*stack++ = expected;
136 	*stack = 0;
137 	multi_op_count++;
138 
139 	if(!done && ((((unsigned long) stack) & ~PAGE_MASK) <
140 		     PAGE_SIZE - 10 * sizeof(long))){
141 		*addr = stack;
142 		return 0;
143 	}
144 
145 	return do_syscall_stub(mm_idp, addr);
146 }
147 
148 long syscall_stub_data(struct mm_id * mm_idp,
149 		       unsigned long *data, int data_count,
150 		       void **addr, void **stub_addr)
151 {
152 	unsigned long *stack;
153 	int ret = 0;
154 
155 	/* If *addr still is uninitialized, it *must* contain NULL.
156 	 * Thus in this case do_syscall_stub correctly won't be called.
157 	 */
158 	if((((unsigned long) *addr) & ~PAGE_MASK) >=
159 	   PAGE_SIZE - (10 + data_count) * sizeof(long)) {
160 		ret = do_syscall_stub(mm_idp, addr);
161 		/* in case of error, don't overwrite data on stack */
162 		if(ret)
163 			return ret;
164 	}
165 
166 	stack = check_init_stack(mm_idp, *addr);
167 	*addr = stack;
168 
169 	*stack = data_count * sizeof(long);
170 
171 	memcpy(stack + 1, data, data_count * sizeof(long));
172 
173 	*stub_addr = (void *)(((unsigned long)(stack + 1) & ~PAGE_MASK) +
174 			      UML_CONFIG_STUB_DATA);
175 
176 	return 0;
177 }
178 
179 int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
180 	int r, int w, int x, int phys_fd, unsigned long long offset,
181 	int done, void **data)
182 {
183 	int prot, ret;
184 
185 	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
186 		(x ? PROT_EXEC : 0);
187 
188 	if(proc_mm){
189 		struct proc_mm_op map;
190 		int fd = mm_idp->u.mm_fd;
191 
192 		map = ((struct proc_mm_op) { .op	= MM_MMAP,
193 				       .u		=
194 				       { .mmap	=
195 					 { .addr	= virt,
196 					   .len	= len,
197 					   .prot	= prot,
198 					   .flags	= MAP_SHARED |
199 					   MAP_FIXED,
200 					   .fd	= phys_fd,
201 					   .offset= offset
202 					 } } } );
203 		ret = os_write_file(fd, &map, sizeof(map));
204 		if(ret != sizeof(map))
205 			printk("map : /proc/mm map failed, err = %d\n", -ret);
206 		else ret = 0;
207 	}
208 	else {
209 		unsigned long args[] = { virt, len, prot,
210 					 MAP_SHARED | MAP_FIXED, phys_fd,
211 					 MMAP_OFFSET(offset) };
212 
213 		ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt,
214 				       data, done);
215 	}
216 
217 	return ret;
218 }
219 
220 int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
221 	  void **data)
222 {
223 	int ret;
224 
225 	if(proc_mm){
226 		struct proc_mm_op unmap;
227 		int fd = mm_idp->u.mm_fd;
228 
229 		unmap = ((struct proc_mm_op) { .op	= MM_MUNMAP,
230 					 .u	=
231 					 { .munmap	=
232 					   { .addr	=
233 					     (unsigned long) addr,
234 					     .len		= len } } } );
235 		ret = os_write_file(fd, &unmap, sizeof(unmap));
236 		if(ret != sizeof(unmap))
237 			printk("unmap - proc_mm write returned %d\n", ret);
238 		else ret = 0;
239 	}
240 	else {
241 		unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
242 					 0 };
243 
244 		ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0,
245 				       data, done);
246 	}
247 
248 	return ret;
249 }
250 
251 int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
252 	    int r, int w, int x, int done, void **data)
253 {
254 	struct proc_mm_op protect;
255 	int prot, ret;
256 
257 	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
258 		(x ? PROT_EXEC : 0);
259 	if(proc_mm){
260 		int fd = mm_idp->u.mm_fd;
261 
262 		protect = ((struct proc_mm_op) { .op	= MM_MPROTECT,
263 					   .u	=
264 					   { .mprotect	=
265 					     { .addr	=
266 					       (unsigned long) addr,
267 					       .len	= len,
268 					       .prot	= prot } } } );
269 
270 		ret = os_write_file(fd, &protect, sizeof(protect));
271 		if(ret != sizeof(protect))
272 			printk("protect failed, err = %d", -ret);
273 		else ret = 0;
274 	}
275 	else {
276 		unsigned long args[] = { addr, len, prot, 0, 0, 0 };
277 
278 		ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
279 				       data, done);
280 	}
281 
282 	return ret;
283 }
284 
285 void before_mem_skas(unsigned long unused)
286 {
287 }
288