29863d1eff
Currently, to support 64-byte contexts, xhci_ctx_[gs]et_le(32|64) take a pointer to the field within a 32-byte context and, if 64-byte contexts are in use, compute where the 64-byte context field is and use that instead by deriving a pointer from the 32-byte field pointer. This is done by exploiting a combination of 64-byte contexts being the same layout as their 32-byte counterparts, just with 32 bytes of padding at the end, and that all individual contexts are either in a device context or an input context which itself is page-aligned. By masking out the low 4 bits (which is the offset of the field within the 32-byte contxt) of the offset within the page, the offset of the invididual context within the containing device/input context can be determined, which is itself 32 times the number of preceding contexts. Thus, adding this value to the pointer again gets 64 times the number of preceding contexts plus the field offset, which gives the offset of the 64-byte context plus the field offset, which is the address of the field in the 64-byte context. However, this involves a fair amount of lying to the compiler when constructing these intermediate pointers, and is rather difficult to reason about. In particular, this is problematic for CHERI, where we compile the kernel with subobject bounds enabled; that is, unless annotated to opt out (e.g. for C struct inheritance reasons where you need to be able to downcast, or containerof idioms), a pointer to a member of a struct is a capability whose bounds only cover that field, and any attempt to dereference outside those bounds will fault, protecting against intra-object buffer overflows. Thus the pointer given to xhci_ctx_[gs]et_le(32|64) is a capability whose bounds only cover the field in the 32-byte context, and computing the pointer to the 64-byte context field takes the address out of bounds, resulting in a fault when later dereferenced. This can be cleaned up by using a different abstraction. Instead of doing the 32-byte to 64-byte conversion on access to the field, we can do the conversion when getting a pointer to the context itself, and define proper 64-byte versions of contexts in order to let the compiler do all the necessary arithmetic rather than do it manually ourselves. This provides a cleaner implementation, works for CHERI and may even be slightly more performant as it avoids the need to mess with masking pointers (which cannot in the general case be optimised by compilers to be reused across accesses to different fields within the same context, since it does not know that the contexts are over-aligned compared with the C ABI requirements). Reviewed by: hselasky Differential Revision: https://reviews.freebsd.org/D32554 |
||
---|---|---|
.. | ||
controller | ||
gadget | ||
input | ||
misc | ||
net | ||
quirk | ||
serial | ||
storage | ||
template | ||
video | ||
wlan | ||
ufm_ioctl.h | ||
uftdiio.h | ||
uled_ioctl.h | ||
usb_bus.h | ||
usb_busdma.c | ||
usb_busdma.h | ||
usb_cdc.h | ||
usb_controller.h | ||
usb_core.c | ||
usb_core.h | ||
usb_debug.c | ||
usb_debug.h | ||
usb_dev.c | ||
usb_dev.h | ||
usb_device.c | ||
usb_device.h | ||
usb_dynamic.c | ||
usb_dynamic.h | ||
usb_endian.h | ||
usb_error.c | ||
usb_fdt_support.c | ||
usb_fdt_support.h | ||
usb_freebsd_loader.h | ||
usb_freebsd.h | ||
usb_generic.c | ||
usb_generic.h | ||
usb_handle_request.c | ||
usb_hid.c | ||
usb_hub_acpi.c | ||
usb_hub_private.h | ||
usb_hub.c | ||
usb_hub.h | ||
usb_if.m | ||
usb_ioctl.h | ||
usb_lookup.c | ||
usb_mbuf.c | ||
usb_mbuf.h | ||
usb_msctest.c | ||
usb_msctest.h | ||
usb_parse.c | ||
usb_pci.h | ||
usb_pf.c | ||
usb_pf.h | ||
usb_process.c | ||
usb_process.h | ||
usb_request.c | ||
usb_request.h | ||
usb_transfer.c | ||
usb_transfer.h | ||
usb_util.c | ||
usb_util.h | ||
usb.h | ||
usbdevs | ||
usbdi_util.h | ||
usbdi.h | ||
usbhid.h |