Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Giving Rust a chance for in-kernel codecs

Giving Rust a chance for in-kernel codecs

This talk will show how it is possible to write Rust code in the kernel without a binding layer, and how this drastically reduces the number of Rust abstractions needed, with a focus on V4L2 codec drivers and libraries. It will present a strategy wherein only a few critical functions are converted to Rust while accounting for the role of the “cbindgen” tool in keeping ABI compatibility. The source code of a previously submitted proof-of-concept will be used to provide examples.

Daniel ALMEIDA

Kernel Recipes

October 09, 2024
Tweet

More Decks by Kernel Recipes

Other Decks in Technology

Transcript

  1. 1 Giving Rust a chance for in-kernel codecs Daniel Almeida

    Consultant Software Engineer Collabora
  2. 4 Hardware codec accelerators • Specialized hardware to speed up

    decoding / encoding • They are usually faster and generate less heat • Their use frees up the main CPU, but.. • We now need drivers and an API to communicate with userland
  3. 5 Hardware codec accelerators • With a CPU implementation, everything

    is in userspace • With a hardware accelerator, there’s a userspace component • And also a kernel component, which means a highly privileged execution context
  4. 7

  5. 8 Bitstream metadata • Controls the decoding process, • A

    change in one parameter changes how the hardware interprets the rest of the bitstream • Is parsed from untrusted input • Interpreted and fed to the device by the kernel
  6. 9 Current validation process • Userspace programs may introduce their

    own checks • Kernel has an extremely ad-hoc validation strategy • If something breaks, we hope it’s before the kernel gets involved • Otherwise, we hope that the device simply hangs
  7. 11

  8. 12

  9. 13

  10. 16 Why Rust? • Sized arrays • Runtime bound checks

    using get() • Iterators instead of dangerous for-loops • References (which are always valid) instead of pointers • Ownership, lifetimes, destructors, etc...
  11. 17 Brief recap • A driver would need a layer

    of bindings, i.e.: abstractions • This layer of bindings did not please the maintainers • Therefore, this approach was abandoned
  12. 18 Feedback from last year • Who maintains what? •

    This will slow down development in C • This may break C code • The community is overwhelmed
  13. 22 • Generate machine code that can be called from

    C • Make it so the linker can find it • Can be used as an entry point to call other Rust code
  14. 23 • We don’t want this: _RNvNtCs1234_7mycrate3foo3bar – So no

    generics, – No closures – No namespacing – No methods, etc.
  15. 24 • We need this to be callable from C,

    hence “extern C” • Rustc will give us the machine code for the symbol. • That’s it really, the linker will happily comply.
  16. 25 • The public API is then rewritten as per

    above • But we need a way to expose the new API to C somehow. • Because...
  17. 26 • This works. • But it is not a

    good idea. • It can quickly get out of sync. • Nasty bugs can creep if we are not careful.
  18. 28 Cbindgen • Cbindgen can automatically generate a C header

    – Keeps things in sync – Ensure proper type layout and ABI • Avoids link errors and/or subtle bugs • Maintained by Mozilla
  19. 29 Cbindgen • If a function takes arguments, cbindgen will

    generate equivalent C structs • This works because of #[repr(C)]
  20. 30 Summary • Convert self-contained components into Rust • Ask

    rustc to generate the machine code • Annotate the public API so that it’s callable from C • Automatically generate a header file using cbindgen • #include the header in C code
  21. 32 Potential targets • This type of conversion works best

    when: – There is a self-contained component – That exposes a small public API • For video4linux, this means: – Codec libraries – Codec parsers
  22. 33 Codec libraries • Codec algorithms that run on the

    CPU • Results are fed back to the hardware • Abstracted so drivers can rely on a single implementation • Very self-contained
  23. 34 Rewriting the VP9 library • Two drivers were converted

    • There is a testing tool • We got the exact same score when running the tool • Relatively pain-free process
  24. 36 Proposals • Merge the code • Gate it behind

    a KCONFIG • Users get the C implementation by default • Run the Rust implementation on a CI • Eventually deprecate the C implementation
  25. 37 Compared to last year • Overall, a less ambitious

    approach • Less inconvenience to maintainers • The Rust code can be used by future Rust drivers, if any
  26. 39 Feedback • Provide examples of actual crashes that are

    fixed by Rust • Measure any performance impacts • Enable the Rust support in media-ci • Use media-ci to continuously test the Rust code • Merge the code in staging/media
  27. 40 Performance • There should be no overhead in using

    this approach • This means that the #[no_mangle], extern “C” stuff is free • The added checks are not free, of course • Programming the HW is *by far* not the bottleneck