]>
git.proxmox.com Git - mirror_qemu.git/blob - bsd-user/freebsd/os-sys.c
625018b185b784f48fee2e6ced398c69c14b2a48
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 G_GNUC_UNUSED
cap_memory(uint64_t mem
)
72 return MIN(guest_max_mem
, mem
);
76 static abi_ulong G_GNUC_UNUSED
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 G_GNUC_UNUSED
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. */
269 * For long and ulong with a 64-bit host and a 32-bit target we have to do
270 * special things. holdlen here is the length provided by the target to the
271 * system call. So we allocate a buffer twice as large because longs are
272 * twice as big on the host which will be writing them. In h2g_old_sysctl
273 * we'll adjust them and adjust the length.
275 if (kind
== CTLTYPE_LONG
|| kind
== CTLTYPE_ULONG
) {
277 holdlen
= holdlen
* 2;
278 holdp
= g_malloc(holdlen
);
282 ret
= get_errno(sysctl(snamep
, namelen
, holdp
, &holdlen
, hnewp
, newlen
));
283 if (!ret
&& (holdp
!= 0)) {
285 if (snamep
[0] == CTL_SYSCTL
) {
287 case CTL_SYSCTL_NEXT
:
288 case CTL_SYSCTL_NAME2OID
:
289 case CTL_SYSCTL_NEXTNOSKIP
:
291 * All of these return an OID array, so we need to convert to
294 sysctl_name2oid(holdp
, holdlen
);
297 case CTL_SYSCTL_OIDFMT
:
299 sysctl_oidfmt(holdp
);
301 case CTL_SYSCTL_OIDDESCR
:
302 case CTL_SYSCTL_OIDLABEL
:
304 /* Handle it based on the type */
305 h2g_old_sysctl(holdp
, &holdlen
, kind
);
306 /* NB: None of these are LONG or ULONG */
311 * Need to convert from host to target. All the weird special cases
314 h2g_old_sysctl(holdp
, &holdlen
, kind
);
317 * For the 32-bit on 64-bit case, for longs we need to copy the
318 * now-converted buffer to the target and free the buffer.
320 if (kind
== CTLTYPE_LONG
|| kind
== CTLTYPE_ULONG
) {
321 memcpy(old_holdp
, holdp
, holdlen
);
333 /* sysarch() is architecture dependent. */
334 abi_long
do_freebsd_sysarch(void *cpu_env
, abi_long arg1
, abi_long arg2
)
336 return do_freebsd_arch_sysarch(cpu_env
, arg1
, arg2
);