The point you are missing is that "bare-metal code" is assembler, regardless of how much effort is involved.
I again have to point you to Linux or *BSD, these OSes have real time drivers in C. I don't recall seeing *any* peripheral driver in Linux that is not C. Practically all assembly code is under arch/ which means bootstrap, memory initialization and main timers. The rest is C.
Go ahead and write a real time driver in C, let me know how it works for you.
I'm doing this right now, and it is a very usual thing for me to do because I work on firmware for slower microcontrollers that run at clock speeds from 1.8 to 16 MHz. I have tons of peripherals in the MCU, and they must be serviced on time. A typical MCU project is a real time design. Sometimes I profile the code by connecting an oscilloscope to some spare pins and check that I have enough time in critical parts of the code. And *all* the code is C, compiled by avr-gcc 4.3.2. I have maybe 0.1% of the code that is in assembler, and that is stock macros that come with avr-gcc.
To illustrate, here you can see the lowest level of avr32 support, and you can observe how many LOCs are in .S and how many are in .c files. If still not convinced, visit mm/ and see what language the do_page_fault() is implemented in; that is one of most performance-critical pieces of code. C today is the "bare-metal" language of choice, and it works well in that role.