This is a common misconception that if the kernel needs direct hardware access and such, then it all becomes unsafe.
Rust programming style is building safe (zero-cost) abstractions on top of unsafe primitives, turning all other code into safe "glue" code. If you design for it, you can have a lot of "boring" code even in a kernel.
A kernel will have more unsafe primitives to implement, but the safe/unsafe division still helps testing the unsafe parts, and still prevents bugs caused by misuse of these APIs.
The type system that gives safety in userspace still exists in the kernel space. So even if the allocators and threads are different, you still have the type system tools to write safer APIs for them.
Yes. Because it's popular and large the Linux kernel has problems where abstractions leak and a subtle implementation detail causes problems because you were supposed to just know that certain APIs don't do quite what it seems like they'd do from the name.
Rust's culture says you must mark abstractions that leak safety as unsafe. If this Rust function named "make_doodad" is labelled safe, it is not OK that I could run it without a doodad_manager, and yet in this case it blows up. Either somehow require me to prove I have a doodad_manager, or, mark it unsafe and document the requirement, or re-design the function so that it checks for a doodad_manager and fails cleanly when one is not present. In some cases you might decide all three are needed: make_doodad_with_manager(&manager) -> Doodad, unsafe make_doodad_unchecked() -> Doodad and make_doodad() -> Result<Doodad,Problem>
In kernel space ordinary operations like writing to a [u32] you own can have unexpected results. For example the page may not exist or the memory could point to some hardware component or be aliased. See also pornel's comment.
There are some ideas around Rust code patterns and structure for bare metal, see for example the RTFM work (now renamed). But they all do have some drawbacks such as redeuced readability and IMO too much abstraction.
Anyway, my point was that since of the guarantees Rust provides build upon certain assumptions about the environment that generally don't exist in kernel space.
That not quite correct. Sure, you will have some unsafe primitives that interact with hardware. But nothing stops you from creating abstractions on top of those.
Also, `unsafe` doesn't disable all language features or the type system, it just provides an escape hatch to use raw pointers. Which, yes is quite a big step away from "normal Rust", but that's why we abstract around them.
It sure is extra and boring work, but it's entirely possible to create ergonomic APIs around unsafe low level primitives. I mean, that's how a lot of stuff gets implemented in stdlib or even in some crates. We just don't interact with it frequently, though.
Not kernel developer myself, but I've done some embedded Rust and written drivers