Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / bsd-user / freebsd / os-sys.c
blobdf317065587ccce14127a2771ec9c453fd985769
1 /*
2 * FreeBSD sysctl() and sysarch() system call emulation
4 * Copyright (c) 2013-15 Stacey D. Son
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "qemu.h"
22 #include "target_arch_sysarch.h"
24 #include <sys/sysctl.h>
27 * Length for the fixed length types.
28 * 0 means variable length for strings and structures
29 * Compare with sys/kern_sysctl.c ctl_size
30 * Note: Not all types appear to be used in-tree.
32 static const int guest_ctl_size[CTLTYPE + 1] = {
33 [CTLTYPE_INT] = sizeof(abi_int),
34 [CTLTYPE_UINT] = sizeof(abi_uint),
35 [CTLTYPE_LONG] = sizeof(abi_long),
36 [CTLTYPE_ULONG] = sizeof(abi_ulong),
37 [CTLTYPE_S8] = sizeof(int8_t),
38 [CTLTYPE_S16] = sizeof(int16_t),
39 [CTLTYPE_S32] = sizeof(int32_t),
40 [CTLTYPE_S64] = sizeof(int64_t),
41 [CTLTYPE_U8] = sizeof(uint8_t),
42 [CTLTYPE_U16] = sizeof(uint16_t),
43 [CTLTYPE_U32] = sizeof(uint32_t),
44 [CTLTYPE_U64] = sizeof(uint64_t),
47 static const int host_ctl_size[CTLTYPE + 1] = {
48 [CTLTYPE_INT] = sizeof(int),
49 [CTLTYPE_UINT] = sizeof(u_int),
50 [CTLTYPE_LONG] = sizeof(long),
51 [CTLTYPE_ULONG] = sizeof(u_long),
52 [CTLTYPE_S8] = sizeof(int8_t),
53 [CTLTYPE_S16] = sizeof(int16_t),
54 [CTLTYPE_S32] = sizeof(int32_t),
55 [CTLTYPE_S64] = sizeof(int64_t),
56 [CTLTYPE_U8] = sizeof(uint8_t),
57 [CTLTYPE_U16] = sizeof(uint16_t),
58 [CTLTYPE_U32] = sizeof(uint32_t),
59 [CTLTYPE_U64] = sizeof(uint64_t),
62 #ifdef TARGET_ABI32
64 * Limit the amount of available memory to be most of the 32-bit address
65 * space. 0x100c000 was arrived at through trial and error as a good
66 * definition of 'most'.
68 static const abi_ulong guest_max_mem = UINT32_MAX - 0x100c000 + 1;
70 static abi_ulong cap_memory(uint64_t mem)
72 return MIN(guest_max_mem, mem);
74 #endif
76 static abi_ulong scale_to_guest_pages(uint64_t pages)
78 /* Scale pages from host to guest */
79 pages = muldiv64(pages, qemu_real_host_page_size(), TARGET_PAGE_SIZE);
80 #ifdef TARGET_ABI32
81 /* cap pages if need be */
82 pages = MIN(pages, guest_max_mem / (abi_ulong)TARGET_PAGE_SIZE);
83 #endif
84 return pages;
87 #ifdef TARGET_ABI32
88 /* Used only for TARGET_ABI32 */
89 static abi_long h2g_long_sat(long l)
91 if (l > INT32_MAX) {
92 l = INT32_MAX;
93 } else if (l < INT32_MIN) {
94 l = INT32_MIN;
96 return l;
99 static abi_ulong h2g_ulong_sat(u_long ul)
101 return MIN(ul, UINT32_MAX);
103 #endif
106 * placeholder until bsd-user downstream upstreams this with its thread support
108 #define bsd_get_ncpu() 1
111 * This uses the undocumented oidfmt interface to find the kind of a requested
112 * sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt() (compare to
113 * src/sbin/sysctl/sysctl.c)
115 static int oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
117 int qoid[CTL_MAXNAME + 2];
118 uint8_t buf[BUFSIZ];
119 int i;
120 size_t j;
122 qoid[0] = CTL_SYSCTL;
123 qoid[1] = CTL_SYSCTL_OIDFMT;
124 memcpy(qoid + 2, oid, len * sizeof(int));
126 j = sizeof(buf);
127 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
128 if (i) {
129 return i;
132 if (kind) {
133 *kind = *(uint32_t *)buf;
136 if (fmt) {
137 strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
139 return 0;
143 * Convert the old value from host to guest.
145 * For LONG and ULONG on ABI32, we need to 'down convert' the 8 byte quantities
146 * to 4 bytes. The caller setup a buffer in host memory to get this data from
147 * the kernel and pass it to us. We do the down conversion and adjust the length
148 * so the caller knows what to write as the returned length into the target when
149 * it copies the down converted values into the target.
151 * For normal integral types, we just need to byte swap. No size changes.
153 * For strings and node data, there's no conversion needed.
155 * For opaque data, per sysctl OID converts take care of it.
157 static void h2g_old_sysctl(void *holdp, size_t *holdlen, uint32_t kind)
159 size_t len;
160 int hlen, glen;
161 uint8_t *hp, *gp;
164 * Although rare, we can have arrays of sysctl. Both sysctl_old_ddb in
165 * kern_sysctl.c and show_var in sbin/sysctl/sysctl.c have code that loops
166 * this way. *holdlen has been set by the kernel to the host's length.
167 * Only LONG and ULONG on ABI32 have different sizes: see below.
169 gp = hp = (uint8_t *)holdp;
170 len = 0;
171 hlen = host_ctl_size[kind & CTLTYPE];
172 glen = guest_ctl_size[kind & CTLTYPE];
175 * hlen == 0 for CTLTYPE_STRING and CTLTYPE_NODE, which need no conversion
176 * as well as CTLTYPE_OPAQUE, which needs special converters.
178 if (hlen == 0) {
179 return;
182 while (len < *holdlen) {
183 if (hlen == glen) {
184 switch (hlen) {
185 case 1:
186 /* Nothing needed: no byteswapping and assigning in place */
187 break;
188 case 2:
189 *(uint16_t *)gp = tswap16(*(uint16_t *)hp);
190 break;
191 case 4:
192 *(uint32_t *)gp = tswap32(*(uint32_t *)hp);
193 break;
194 case 8:
195 *(uint64_t *)gp = tswap64(*(uint64_t *)hp);
196 break;
197 default:
198 g_assert_not_reached();
200 } else {
201 #ifdef TARGET_ABI32
203 * Saturating assignment for the only two types that differ between
204 * 32-bit and 64-bit machines. All other integral types have the
205 * same, fixed size and will be converted w/o loss of precision
206 * in the above switch.
208 switch (kind & CTLTYPE) {
209 case CTLTYPE_LONG:
210 *(abi_long *)gp = tswap32(h2g_long_sat(*(long *)hp));
211 break;
212 case CTLTYPE_ULONG:
213 *(abi_ulong *)gp = tswap32(h2g_ulong_sat(*(u_long *)hp));
214 break;
215 default:
216 g_assert_not_reached();
218 #else
219 g_assert_not_reached();
220 #endif
222 gp += glen;
223 hp += hlen;
224 len += hlen;
226 #ifdef TARGET_ABI32
227 if (hlen != glen) {
228 *holdlen = (*holdlen / hlen) * glen;
230 #endif
234 * Convert the undocmented name2oid sysctl data for the target.
236 static inline void sysctl_name2oid(uint32_t *holdp, size_t holdlen)
238 size_t i, num = holdlen / sizeof(uint32_t);
240 for (i = 0; i < num; i++) {
241 holdp[i] = tswap32(holdp[i]);
245 static inline void sysctl_oidfmt(uint32_t *holdp)
247 /* byte swap the kind */
248 holdp[0] = tswap32(holdp[0]);
251 static abi_long do_freebsd_sysctl_oid(CPUArchState *env, int32_t *snamep,
252 int32_t namelen, void *holdp, size_t *holdlenp, void *hnewp,
253 size_t newlen)
255 uint32_t kind = 0;
256 abi_long ret;
257 size_t holdlen, oldlen;
258 #ifdef TARGET_ABI32
259 void *old_holdp;
260 #endif
262 holdlen = oldlen = *holdlenp;
263 oidfmt(snamep, namelen, NULL, &kind);
265 /* Handle some arch/emulator dependent sysctl()'s here. */
266 switch (snamep[0]) {
267 case CTL_KERN:
268 switch (snamep[1]) {
269 case KERN_USRSTACK:
270 if (oldlen) {
271 (*(abi_ulong *)holdp) = tswapal(TARGET_USRSTACK);
273 holdlen = sizeof(abi_ulong);
274 ret = 0;
275 goto out;
277 case KERN_PS_STRINGS:
278 if (oldlen) {
279 (*(abi_ulong *)holdp) = tswapal(TARGET_PS_STRINGS);
281 holdlen = sizeof(abi_ulong);
282 ret = 0;
283 goto out;
285 default:
286 break;
288 break;
290 case CTL_HW:
291 switch (snamep[1]) {
292 case HW_MACHINE:
293 holdlen = sizeof(TARGET_HW_MACHINE);
294 if (holdp) {
295 strlcpy(holdp, TARGET_HW_MACHINE, oldlen);
297 ret = 0;
298 goto out;
300 case HW_MACHINE_ARCH:
302 holdlen = sizeof(TARGET_HW_MACHINE_ARCH);
303 if (holdp) {
304 strlcpy(holdp, TARGET_HW_MACHINE_ARCH, oldlen);
306 ret = 0;
307 goto out;
309 case HW_NCPU:
310 if (oldlen) {
311 (*(abi_int *)holdp) = tswap32(bsd_get_ncpu());
313 holdlen = sizeof(int32_t);
314 ret = 0;
315 goto out;
316 #if defined(TARGET_ARM)
317 case HW_FLOATINGPT:
318 if (oldlen) {
319 ARMCPU *cpu = env_archcpu(env);
320 *(abi_int *)holdp = cpu_isar_feature(aa32_vfp, cpu);
322 holdlen = sizeof(abi_int);
323 ret = 0;
324 goto out;
325 #endif
328 #ifdef TARGET_ABI32
329 case HW_PHYSMEM:
330 case HW_USERMEM:
331 case HW_REALMEM:
332 holdlen = sizeof(abi_ulong);
333 ret = 0;
335 if (oldlen) {
336 int mib[2] = {snamep[0], snamep[1]};
337 unsigned long lvalue;
338 size_t len = sizeof(lvalue);
340 if (sysctl(mib, 2, &lvalue, &len, NULL, 0) == -1) {
341 ret = -1;
342 } else {
343 lvalue = cap_memory(lvalue);
344 (*(abi_ulong *)holdp) = tswapal((abi_ulong)lvalue);
347 goto out;
348 #endif
350 default:
352 static int oid_hw_availpages;
353 static int oid_hw_pagesizes;
355 if (!oid_hw_availpages) {
356 int real_oid[CTL_MAXNAME + 2];
357 size_t len = sizeof(real_oid) / sizeof(int);
359 if (sysctlnametomib("hw.availpages", real_oid, &len) >= 0) {
360 oid_hw_availpages = real_oid[1];
363 if (!oid_hw_pagesizes) {
364 int real_oid[CTL_MAXNAME + 2];
365 size_t len = sizeof(real_oid) / sizeof(int);
367 if (sysctlnametomib("hw.pagesizes", real_oid, &len) >= 0) {
368 oid_hw_pagesizes = real_oid[1];
372 if (oid_hw_availpages && snamep[1] == oid_hw_availpages) {
373 long lvalue;
374 size_t len = sizeof(lvalue);
376 if (sysctlbyname("hw.availpages", &lvalue, &len, NULL, 0) == -1) {
377 ret = -1;
378 } else {
379 if (oldlen) {
380 lvalue = scale_to_guest_pages(lvalue);
381 (*(abi_ulong *)holdp) = tswapal((abi_ulong)lvalue);
383 holdlen = sizeof(abi_ulong);
384 ret = 0;
386 goto out;
389 if (oid_hw_pagesizes && snamep[1] == oid_hw_pagesizes) {
390 if (oldlen) {
391 (*(abi_ulong *)holdp) = tswapal((abi_ulong)TARGET_PAGE_SIZE);
392 ((abi_ulong *)holdp)[1] = 0;
394 holdlen = sizeof(abi_ulong) * 2;
395 ret = 0;
396 goto out;
398 break;
401 break;
403 default:
404 break;
407 #ifdef TARGET_ABI32
409 * For long and ulong with a 64-bit host and a 32-bit target we have to do
410 * special things. holdlen here is the length provided by the target to the
411 * system call. So we allocate a buffer twice as large because longs are
412 * twice as big on the host which will be writing them. In h2g_old_sysctl
413 * we'll adjust them and adjust the length.
415 if (kind == CTLTYPE_LONG || kind == CTLTYPE_ULONG) {
416 old_holdp = holdp;
417 holdlen = holdlen * 2;
418 holdp = g_malloc(holdlen);
420 #endif
422 ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
423 if (!ret && (holdp != 0)) {
425 if (snamep[0] == CTL_SYSCTL) {
426 switch (snamep[1]) {
427 case CTL_SYSCTL_NEXT:
428 case CTL_SYSCTL_NAME2OID:
429 case CTL_SYSCTL_NEXTNOSKIP:
431 * All of these return an OID array, so we need to convert to
432 * target.
434 sysctl_name2oid(holdp, holdlen);
435 break;
437 case CTL_SYSCTL_OIDFMT:
438 /* Handle oidfmt */
439 sysctl_oidfmt(holdp);
440 break;
441 case CTL_SYSCTL_OIDDESCR:
442 case CTL_SYSCTL_OIDLABEL:
443 default:
444 /* Handle it based on the type */
445 h2g_old_sysctl(holdp, &holdlen, kind);
446 /* NB: None of these are LONG or ULONG */
447 break;
449 } else {
451 * Need to convert from host to target. All the weird special cases
452 * are handled above.
454 h2g_old_sysctl(holdp, &holdlen, kind);
455 #ifdef TARGET_ABI32
457 * For the 32-bit on 64-bit case, for longs we need to copy the
458 * now-converted buffer to the target and free the buffer.
460 if (kind == CTLTYPE_LONG || kind == CTLTYPE_ULONG) {
461 memcpy(old_holdp, holdp, holdlen);
462 g_free(holdp);
463 holdp = old_holdp;
465 #endif
469 out:
470 *holdlenp = holdlen;
471 return ret;
475 * This syscall was created to make sysctlbyname(3) more efficient, but we can't
476 * really provide it in bsd-user. Notably, we must always translate the names
477 * independently since some sysctl values have to be faked for the target
478 * environment, so it still has to break down to two syscalls for the underlying
479 * implementation.
481 abi_long do_freebsd_sysctlbyname(CPUArchState *env, abi_ulong namep,
482 int32_t namelen, abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp,
483 abi_ulong newlen)
485 abi_long ret = -TARGET_EFAULT;
486 void *holdp = NULL, *hnewp = NULL;
487 char *snamep = NULL;
488 int oid[CTL_MAXNAME + 2];
489 size_t holdlen, oidplen;
490 abi_ulong oldlen = 0;
492 /* oldlenp is read/write, pre-check here for write */
493 if (oldlenp) {
494 if (!access_ok(VERIFY_WRITE, oldlenp, sizeof(abi_ulong)) ||
495 get_user_ual(oldlen, oldlenp)) {
496 goto out;
499 snamep = lock_user_string(namep);
500 if (snamep == NULL) {
501 goto out;
503 if (newp) {
504 hnewp = lock_user(VERIFY_READ, newp, newlen, 1);
505 if (hnewp == NULL) {
506 goto out;
509 if (oldp) {
510 holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0);
511 if (holdp == NULL) {
512 goto out;
515 holdlen = oldlen;
517 oidplen = ARRAY_SIZE(oid);
518 if (sysctlnametomib(snamep, oid, &oidplen) != 0) {
519 ret = -TARGET_EINVAL;
520 goto out;
523 ret = do_freebsd_sysctl_oid(env, oid, oidplen, holdp, &holdlen, hnewp,
524 newlen);
527 * writeability pre-checked above. __sysctl(2) returns ENOMEM and updates
528 * oldlenp for the proper size to use.
530 if (oldlenp && (ret == 0 || ret == -TARGET_ENOMEM)) {
531 put_user_ual(holdlen, oldlenp);
533 out:
534 unlock_user(snamep, namep, 0);
535 unlock_user(holdp, oldp, ret == 0 ? holdlen : 0);
536 unlock_user(hnewp, newp, 0);
538 return ret;
541 abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
542 abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
544 abi_long ret = -TARGET_EFAULT;
545 void *hnamep, *holdp = NULL, *hnewp = NULL;
546 size_t holdlen;
547 abi_ulong oldlen = 0;
548 int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
550 /* oldlenp is read/write, pre-check here for write */
551 if (oldlenp) {
552 if (!access_ok(VERIFY_WRITE, oldlenp, sizeof(abi_ulong)) ||
553 get_user_ual(oldlen, oldlenp)) {
554 goto out;
557 hnamep = lock_user(VERIFY_READ, namep, namelen, 1);
558 if (hnamep == NULL) {
559 goto out;
561 if (newp) {
562 hnewp = lock_user(VERIFY_READ, newp, newlen, 1);
563 if (hnewp == NULL) {
564 goto out;
567 if (oldp) {
568 holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0);
569 if (holdp == NULL) {
570 goto out;
573 holdlen = oldlen;
574 for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++, q++) {
575 *q = tswap32(*p);
578 ret = do_freebsd_sysctl_oid(env, snamep, namelen, holdp, &holdlen, hnewp,
579 newlen);
582 * writeability pre-checked above. __sysctl(2) returns ENOMEM and updates
583 * oldlenp for the proper size to use.
585 if (oldlenp && (ret == 0 || ret == -TARGET_ENOMEM)) {
586 put_user_ual(holdlen, oldlenp);
588 unlock_user(hnamep, namep, 0);
589 unlock_user(holdp, oldp, ret == 0 ? holdlen : 0);
590 out:
591 g_free(snamep);
592 return ret;
595 /* sysarch() is architecture dependent. */
596 abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
598 return do_freebsd_arch_sysarch(cpu_env, arg1, arg2);