xref: /linux/arch/um/os-Linux/skas/mem.c (revision f3d9478b2ce468c3115b02ecae7e975990697f15)
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;
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 		panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
71 		      n);
72 
73 	wait_stub_done(pid, 0, "do_syscall_stub");
74 
75 	/* When the stub stops, we find the following values on the
76 	 * beginning of the stack:
77 	 * (long )return_value
78 	 * (long )offset to failed sycall-data (0, if no error)
79 	 */
80 	ret = *((unsigned long *) mm_idp->stack);
81 	offset = *((unsigned long *) mm_idp->stack + 1);
82 	if (offset) {
83 		data = (unsigned long *)(mm_idp->stack +
84 					 offset - UML_CONFIG_STUB_DATA);
85 		printk("do_syscall_stub : ret = %ld, offset = %ld, "
86 		       "data = %p\n", ret, offset, data);
87 		syscall = (unsigned long *)((unsigned long)data + data[0]);
88 		printk("do_syscall_stub: syscall %ld failed, return value = "
89 		       "0x%lx, expected return value = 0x%lx\n",
90 		       syscall[0], ret, syscall[7]);
91 		printk("    syscall parameters: "
92 		       "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
93 		       syscall[1], syscall[2], syscall[3],
94 		       syscall[4], syscall[5], syscall[6]);
95 		for(n = 1; n < data[0]/sizeof(long); n++) {
96 			if(n == 1)
97 				printk("    additional syscall data:");
98 			if(n % 4 == 1)
99 				printk("\n      ");
100 			printk("  0x%lx", data[n]);
101 		}
102 		if(n > 1)
103 			printk("\n");
104 	}
105 	else ret = 0;
106 
107 	*addr = check_init_stack(mm_idp, NULL);
108 
109 	return ret;
110 }
111 
112 long run_syscall_stub(struct mm_id * mm_idp, int syscall,
113 		      unsigned long *args, long expected, void **addr,
114 		      int done)
115 {
116 	unsigned long *stack = check_init_stack(mm_idp, *addr);
117 
118 	if(done && *addr == NULL)
119 		single_count++;
120 
121 	*stack += sizeof(long);
122 	stack += *stack / sizeof(long);
123 
124 	*stack++ = syscall;
125 	*stack++ = args[0];
126 	*stack++ = args[1];
127 	*stack++ = args[2];
128 	*stack++ = args[3];
129 	*stack++ = args[4];
130 	*stack++ = args[5];
131 	*stack++ = expected;
132 	*stack = 0;
133 	multi_op_count++;
134 
135 	if(!done && ((((unsigned long) stack) & ~PAGE_MASK) <
136 		     PAGE_SIZE - 10 * sizeof(long))){
137 		*addr = stack;
138 		return 0;
139 	}
140 
141 	return do_syscall_stub(mm_idp, addr);
142 }
143 
144 long syscall_stub_data(struct mm_id * mm_idp,
145 		       unsigned long *data, int data_count,
146 		       void **addr, void **stub_addr)
147 {
148 	unsigned long *stack;
149 	int ret = 0;
150 
151 	/* If *addr still is uninitialized, it *must* contain NULL.
152 	 * Thus in this case do_syscall_stub correctly won't be called.
153 	 */
154 	if((((unsigned long) *addr) & ~PAGE_MASK) >=
155 	   PAGE_SIZE - (10 + data_count) * sizeof(long)) {
156 		ret = do_syscall_stub(mm_idp, addr);
157 		/* in case of error, don't overwrite data on stack */
158 		if(ret)
159 			return ret;
160 	}
161 
162 	stack = check_init_stack(mm_idp, *addr);
163 	*addr = stack;
164 
165 	*stack = data_count * sizeof(long);
166 
167 	memcpy(stack + 1, data, data_count * sizeof(long));
168 
169 	*stub_addr = (void *)(((unsigned long)(stack + 1) & ~PAGE_MASK) +
170 			      UML_CONFIG_STUB_DATA);
171 
172 	return 0;
173 }
174 
175 int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
176 	int r, int w, int x, int phys_fd, unsigned long long offset,
177 	int done, void **data)
178 {
179 	int prot, ret;
180 
181 	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
182 		(x ? PROT_EXEC : 0);
183 
184 	if(proc_mm){
185 		struct proc_mm_op map;
186 		int fd = mm_idp->u.mm_fd;
187 
188 		map = ((struct proc_mm_op) { .op	= MM_MMAP,
189 				       .u		=
190 				       { .mmap	=
191 					 { .addr	= virt,
192 					   .len	= len,
193 					   .prot	= prot,
194 					   .flags	= MAP_SHARED |
195 					   MAP_FIXED,
196 					   .fd	= phys_fd,
197 					   .offset= offset
198 					 } } } );
199 		ret = os_write_file(fd, &map, sizeof(map));
200 		if(ret != sizeof(map))
201 			printk("map : /proc/mm map failed, err = %d\n", -ret);
202 		else ret = 0;
203 	}
204 	else {
205 		unsigned long args[] = { virt, len, prot,
206 					 MAP_SHARED | MAP_FIXED, phys_fd,
207 					 MMAP_OFFSET(offset) };
208 
209 		ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt,
210 				       data, done);
211 	}
212 
213 	return ret;
214 }
215 
216 int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
217 	  void **data)
218 {
219 	int ret;
220 
221 	if(proc_mm){
222 		struct proc_mm_op unmap;
223 		int fd = mm_idp->u.mm_fd;
224 
225 		unmap = ((struct proc_mm_op) { .op	= MM_MUNMAP,
226 					 .u	=
227 					 { .munmap	=
228 					   { .addr	=
229 					     (unsigned long) addr,
230 					     .len		= len } } } );
231 		ret = os_write_file(fd, &unmap, sizeof(unmap));
232 		if(ret != sizeof(unmap))
233 			printk("unmap - proc_mm write returned %d\n", ret);
234 		else ret = 0;
235 	}
236 	else {
237 		unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
238 					 0 };
239 
240 		ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0,
241 				       data, done);
242 	}
243 
244 	return ret;
245 }
246 
247 int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
248 	    int r, int w, int x, int done, void **data)
249 {
250 	struct proc_mm_op protect;
251 	int prot, ret;
252 
253 	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
254 		(x ? PROT_EXEC : 0);
255 	if(proc_mm){
256 		int fd = mm_idp->u.mm_fd;
257 
258 		protect = ((struct proc_mm_op) { .op	= MM_MPROTECT,
259 					   .u	=
260 					   { .mprotect	=
261 					     { .addr	=
262 					       (unsigned long) addr,
263 					       .len	= len,
264 					       .prot	= prot } } } );
265 
266 		ret = os_write_file(fd, &protect, sizeof(protect));
267 		if(ret != sizeof(protect))
268 			printk("protect failed, err = %d", -ret);
269 		else ret = 0;
270 	}
271 	else {
272 		unsigned long args[] = { addr, len, prot, 0, 0, 0 };
273 
274 		ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
275 				       data, done);
276 	}
277 
278 	return ret;
279 }
280 
281 void before_mem_skas(unsigned long unused)
282 {
283 }
284