]> git.proxmox.com Git - mirror_qemu.git/blame - bsd-user/freebsd/os-sys.c
bsd-user: sysctl helper funtions: sysctl_name2oid and sysctl_oidfmt
[mirror_qemu.git] / bsd-user / freebsd / os-sys.c
CommitLineData
da07e694
WL
1/*
2 * FreeBSD sysctl() and sysarch() system call emulation
3 *
4 * Copyright (c) 2013-15 Stacey D. Son
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
48e438a3 20#include "qemu/osdep.h"
da07e694
WL
21#include "qemu.h"
22#include "target_arch_sysarch.h"
23
08675078
WL
24#include <sys/sysctl.h>
25
26/*
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.
31 */
efba70de 32static const int guest_ctl_size[CTLTYPE + 1] = {
08675078
WL
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),
45};
46
efba70de 47static const int host_ctl_size[CTLTYPE + 1] = {
08675078
WL
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),
60};
61
62#ifdef TARGET_ABI32
63/*
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'.
67 */
68static const abi_ulong guest_max_mem = UINT32_MAX - 0x100c000 + 1;
69
70static abi_ulong G_GNUC_UNUSED cap_memory(uint64_t mem)
71{
72 return MIN(guest_max_mem, mem);
73}
74#endif
75
76static abi_ulong G_GNUC_UNUSED scale_to_guest_pages(uint64_t pages)
77{
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;
85}
86
87#ifdef TARGET_ABI32
88/* Used only for TARGET_ABI32 */
efba70de 89static abi_long h2g_long_sat(long l)
08675078
WL
90{
91 if (l > INT32_MAX) {
92 l = INT32_MAX;
93 } else if (l < INT32_MIN) {
94 l = INT32_MIN;
95 }
96 return l;
97}
98
efba70de 99static abi_ulong h2g_ulong_sat(u_long ul)
08675078
WL
100{
101 return MIN(ul, UINT32_MAX);
102}
103#endif
104
105/*
106 * placeholder until bsd-user downstream upstreams this with its thread support
107 */
108#define bsd_get_ncpu() 1
109
efba70de
SS
110/*
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)
114 */
115static int G_GNUC_UNUSED oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
116{
117 int qoid[CTL_MAXNAME + 2];
118 uint8_t buf[BUFSIZ];
119 int i;
120 size_t j;
121
122 qoid[0] = CTL_SYSCTL;
123 qoid[1] = CTL_SYSCTL_OIDFMT;
124 memcpy(qoid + 2, oid, len * sizeof(int));
125
126 j = sizeof(buf);
127 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
128 if (i) {
129 return i;
130 }
131
132 if (kind) {
133 *kind = *(uint32_t *)buf;
134 }
135
136 if (fmt) {
137 strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
138 }
139 return 0;
140}
141
142/*
143 * Convert the old value from host to guest.
144 *
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.
150 *
151 * For normal integral types, we just need to byte swap. No size changes.
152 *
153 * For strings and node data, there's no conversion needed.
154 *
155 * For opaque data, per sysctl OID converts take care of it.
156 */
157static void G_GNUC_UNUSED h2g_old_sysctl(void *holdp, size_t *holdlen, uint32_t kind)
158{
159 size_t len;
160 int hlen, glen;
161 uint8_t *hp, *gp;
162
163 /*
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.
168 */
169 gp = hp = (uint8_t *)holdp;
170 len = 0;
171 hlen = host_ctl_size[kind & CTLTYPE];
172 glen = guest_ctl_size[kind & CTLTYPE];
173
174 /*
175 * hlen == 0 for CTLTYPE_STRING and CTLTYPE_NODE, which need no conversion
176 * as well as CTLTYPE_OPAQUE, which needs special converters.
177 */
178 if (hlen == 0) {
179 return;
180 }
181
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();
199 }
200 } else {
201#ifdef TARGET_ABI32
202 /*
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.
207 */
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();
217 }
218#else
219 g_assert_not_reached();
220#endif
221 }
222 gp += glen;
223 hp += hlen;
224 len += hlen;
225 }
226#ifdef TARGET_ABI32
227 if (hlen != glen) {
228 *holdlen = (*holdlen / hlen) * glen;
229 }
230#endif
231}
232
0394968a
JL
233/*
234 * Convert the undocmented name2oid sysctl data for the target.
235 */
236static inline void G_GNUC_UNUSED sysctl_name2oid(uint32_t *holdp, size_t holdlen)
237{
238 size_t i, num = holdlen / sizeof(uint32_t);
239
240 for (i = 0; i < num; i++) {
241 holdp[i] = tswap32(holdp[i]);
242 }
243}
244
245static inline void G_GNUC_UNUSED sysctl_oidfmt(uint32_t *holdp)
246{
247 /* byte swap the kind */
248 holdp[0] = tswap32(holdp[0]);
249}
250
da07e694
WL
251/* sysarch() is architecture dependent. */
252abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
253{
254 return do_freebsd_arch_sysarch(cpu_env, arg1, arg2);
255}