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
+}