@samitouri / QOSamiQemu / commits / 40fc417f11

bsd-user: Add do_bsd_ioctl main function

Add main ioctl emulation dispatcher that handles table-driven ioctl translation with thunk-based structure conversion. Supports TYPE_NULL, TYPE_INT, and TYPE_PTR argument types with read, write, and read-write access modes. Signed-off-by: Stacey Son <sson@FreeBSD.org> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> Signed-off-by: Warner Losh <imp@bsdimp.com>

Stacey Son committed Mar 14, 2026 at 11:49 UTC 40fc417f11cf197ac81595290fccb3fa967361b0
1 file changed +100
bsd-user/bsd-ioctl.c
+100
@@ -292,3 +292,103 @@ static abi_long do_ioctl_in6_ifreq_sockaddr_int(const IOCTLEntry *ie,
292
293 return ret;
294 }
295 +
296 +abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg)
297 +{
298 + const IOCTLEntry *ie;
299 + const argtype *arg_type;
300 + abi_long ret;
301 + uint8_t buf_temp[MAX_STRUCT_SIZE];
302 + int target_size;
303 + void *argptr;
304 +
305 + ie = ioctl_entries;
306 + for (;;) {
307 + if (ie->target_cmd == 0) {
308 + gemu_log("QEMU unsupported ioctl: ");
309 + log_unsupported_ioctl(cmd);
310 + return -TARGET_ENOSYS;
311 + }
312 + if (ie->target_cmd == cmd) {
313 + break;
314 + }
315 + ie++;
316 + }
317 + arg_type = ie->arg_type;
318 +#if defined(DEBUG)
319 + gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
320 +#endif
321 + if (ie->do_ioctl) {
322 + return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
323 + }
324 +
325 + switch (arg_type[0]) {
326 + case TYPE_NULL:
327 + /* no argument */
328 + ret = get_errno(safe_ioctl(fd, ie->host_cmd));
329 + break;
330 +
331 + case TYPE_PTRVOID:
332 + case TYPE_INT:
333 + /* int argument */
334 + ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
335 + break;
336 +
337 + case TYPE_PTR:
338 + arg_type++;
339 + target_size = thunk_type_size(arg_type, 0);
340 + switch (ie->access) {
341 + case IOC_R:
342 + ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
343 + if (!is_error(ret)) {
344 + argptr = lock_user(VERIFY_WRITE, arg,
345 + target_size, 0);
346 + if (!argptr) {
347 + return -TARGET_EFAULT;
348 + }
349 + thunk_convert(argptr, buf_temp, arg_type,
350 + THUNK_TARGET);
351 + unlock_user(argptr, arg, target_size);
352 + }
353 + break;
354 +
355 + case IOC_W:
356 + argptr = lock_user(VERIFY_READ, arg, target_size, 1);
357 + if (!argptr) {
358 + return -TARGET_EFAULT;
359 + }
360 + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
361 + unlock_user(argptr, arg, 0);
362 + ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
363 + break;
364 +
365 + case IOC_RW:
366 + /* fallthrough */
367 + default:
368 + argptr = lock_user(VERIFY_READ, arg, target_size, 1);
369 + if (!argptr) {
370 + return -TARGET_EFAULT;
371 + }
372 + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
373 + unlock_user(argptr, arg, 0);
374 + ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
375 + if (!is_error(ret)) {
376 + argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
377 + if (!argptr) {
378 + return -TARGET_EFAULT;
379 + }
380 + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
381 + unlock_user(argptr, arg, target_size);
382 + }
383 + break;
384 + }
385 + break;
386 +
387 + default:
388 + gemu_log("QEMU unknown ioctl: type=%d ", arg_type[0]);
389 + log_unsupported_ioctl(cmd);
390 + ret = -TARGET_ENOSYS;
391 + break;
392 + }
393 + return ret;
394 +}