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"
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),
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
);
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
);
81 /* cap pages if need be */
82 pages
= MIN(pages
, guest_max_mem
/ (abi_ulong
)TARGET_PAGE_SIZE
);
88 /* Used only for TARGET_ABI32 */
89 static abi_long
h2g_long_sat(long l
)
93 } else if (l
< INT32_MIN
) {
99 static abi_ulong
h2g_ulong_sat(u_long ul
)
101 return MIN(ul
, UINT32_MAX
);
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];
122 qoid
[0] = CTL_SYSCTL
;
123 qoid
[1] = CTL_SYSCTL_OIDFMT
;
124 memcpy(qoid
+ 2, oid
, len
* sizeof(int));
127 i
= sysctl(qoid
, len
+ 2, buf
, &j
, 0, 0);
133 *kind
= *(uint32_t *)buf
;
137 strcpy(fmt
, (char *)(buf
+ sizeof(uint32_t)));
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
)
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
;
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.
182 while (len
< *holdlen
) {
186 /* Nothing needed: no byteswapping and assigning in place */
189 *(uint16_t *)gp
= tswap16(*(uint16_t *)hp
);
192 *(uint32_t *)gp
= tswap32(*(uint32_t *)hp
);
195 *(uint64_t *)gp
= tswap64(*(uint64_t *)hp
);
198 g_assert_not_reached();
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
) {
210 *(abi_long
*)gp
= tswap32(h2g_long_sat(*(long *)hp
));
213 *(abi_ulong
*)gp
= tswap32(h2g_ulong_sat(*(u_long
*)hp
));
216 g_assert_not_reached();
219 g_assert_not_reached();
228 *holdlen
= (*holdlen
/ hlen
) * glen
;
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
,
257 size_t holdlen
, oldlen
;
262 holdlen
= oldlen
= *holdlenp
;
263 oidfmt(snamep
, namelen
, NULL
, &kind
);
265 /* Handle some arch/emulator dependent sysctl()'s here. */
271 (*(abi_ulong
*)holdp
) = tswapal(TARGET_USRSTACK
);
273 holdlen
= sizeof(abi_ulong
);
277 case KERN_PS_STRINGS
:
279 (*(abi_ulong
*)holdp
) = tswapal(TARGET_PS_STRINGS
);
281 holdlen
= sizeof(abi_ulong
);
293 holdlen
= sizeof(TARGET_HW_MACHINE
);
295 strlcpy(holdp
, TARGET_HW_MACHINE
, oldlen
);
300 case HW_MACHINE_ARCH
:
302 holdlen
= sizeof(TARGET_HW_MACHINE_ARCH
);
304 strlcpy(holdp
, TARGET_HW_MACHINE_ARCH
, oldlen
);
311 (*(abi_int
*)holdp
) = tswap32(bsd_get_ncpu());
313 holdlen
= sizeof(int32_t);
316 #if defined(TARGET_ARM)
319 ARMCPU
*cpu
= env_archcpu(env
);
320 *(abi_int
*)holdp
= cpu_isar_feature(aa32_vfp
, cpu
);
322 holdlen
= sizeof(abi_int
);
332 holdlen
= sizeof(abi_ulong
);
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) {
343 lvalue
= cap_memory(lvalue
);
344 (*(abi_ulong
*)holdp
) = tswapal((abi_ulong
)lvalue
);
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
) {
374 size_t len
= sizeof(lvalue
);
376 if (sysctlbyname("hw.availpages", &lvalue
, &len
, NULL
, 0) == -1) {
380 lvalue
= scale_to_guest_pages(lvalue
);
381 (*(abi_ulong
*)holdp
) = tswapal((abi_ulong
)lvalue
);
383 holdlen
= sizeof(abi_ulong
);
389 if (oid_hw_pagesizes
&& snamep
[1] == oid_hw_pagesizes
) {
391 (*(abi_ulong
*)holdp
) = tswapal((abi_ulong
)TARGET_PAGE_SIZE
);
392 ((abi_ulong
*)holdp
)[1] = 0;
394 holdlen
= sizeof(abi_ulong
) * 2;
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
) {
417 holdlen
= holdlen
* 2;
418 holdp
= g_malloc(holdlen
);
422 ret
= get_errno(sysctl(snamep
, namelen
, holdp
, &holdlen
, hnewp
, newlen
));
423 if (!ret
&& (holdp
!= 0)) {
425 if (snamep
[0] == CTL_SYSCTL
) {
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
434 sysctl_name2oid(holdp
, holdlen
);
437 case CTL_SYSCTL_OIDFMT
:
439 sysctl_oidfmt(holdp
);
441 case CTL_SYSCTL_OIDDESCR
:
442 case CTL_SYSCTL_OIDLABEL
:
444 /* Handle it based on the type */
445 h2g_old_sysctl(holdp
, &holdlen
, kind
);
446 /* NB: None of these are LONG or ULONG */
451 * Need to convert from host to target. All the weird special cases
454 h2g_old_sysctl(holdp
, &holdlen
, kind
);
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
);
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
481 abi_long
do_freebsd_sysctlbyname(CPUArchState
*env
, abi_ulong namep
,
482 int32_t namelen
, abi_ulong oldp
, abi_ulong oldlenp
, abi_ulong newp
,
485 abi_long ret
= -TARGET_EFAULT
;
486 void *holdp
= NULL
, *hnewp
= 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 */
494 if (!access_ok(VERIFY_WRITE
, oldlenp
, sizeof(abi_ulong
)) ||
495 get_user_ual(oldlen
, oldlenp
)) {
499 snamep
= lock_user_string(namep
);
500 if (snamep
== NULL
) {
504 hnewp
= lock_user(VERIFY_READ
, newp
, newlen
, 1);
510 holdp
= lock_user(VERIFY_WRITE
, oldp
, oldlen
, 0);
517 oidplen
= ARRAY_SIZE(oid
);
518 if (sysctlnametomib(snamep
, oid
, &oidplen
) != 0) {
519 ret
= -TARGET_EINVAL
;
523 ret
= do_freebsd_sysctl_oid(env
, oid
, oidplen
, holdp
, &holdlen
, hnewp
,
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
);
534 unlock_user(snamep
, namep
, 0);
535 unlock_user(holdp
, oldp
, ret
== 0 ? holdlen
: 0);
536 unlock_user(hnewp
, newp
, 0);
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
;
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 */
552 if (!access_ok(VERIFY_WRITE
, oldlenp
, sizeof(abi_ulong
)) ||
553 get_user_ual(oldlen
, oldlenp
)) {
557 hnamep
= lock_user(VERIFY_READ
, namep
, namelen
, 1);
558 if (hnamep
== NULL
) {
562 hnewp
= lock_user(VERIFY_READ
, newp
, newlen
, 1);
568 holdp
= lock_user(VERIFY_WRITE
, oldp
, oldlen
, 0);
574 for (p
= hnamep
, q
= snamep
, i
= 0; i
< namelen
; p
++, i
++, q
++) {
578 ret
= do_freebsd_sysctl_oid(env
, snamep
, namelen
, holdp
, &holdlen
, hnewp
,
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);
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
);