Как в написании операционной системы используют C?
Не важно, на чём пишутся драйвера/ось/программы, в результате исполняется процессором машинный код - бинарные данные определённого формата, по которым процессор понимает, что ему делать в данный момент. На ассемблере приходится программировать, когда нужно реализовать очень "близкие к железу" вещи - трансляция памяти, регистры ввода-вывода. Каждая ассемблерная инструкция соответствует одному машинному слову, короче самый близкий к машине человекочитаемый код. 
Куда проще писать на высокоуровневых языках - части ОС и драйвера часто пишут на Си. Этот язык более прост для человека. Естественно этот код тоже сначала переводится компилятором в ассемблер, а затем и в машинный код. Другого процессор "не понимает". Этот набор данных подсовывается компьютеру в каком-либо виде. Например, самая первая инструкция в х86 ПК исполняется по адресу 0xFFFFFFF0 в адресном пространтсве. Этому адресу в современных ПК соответствуют самые последние 16 байт флеш-памяти BIOS. С этого кусочка запускается компьютер (это если кратко, на самом деле нифига не так). 
Раньше BIOS загружал операционку со специального загрузочного сектора на диске. Там в сыром виде лежал машинный код, который дальше обеспечивал загрузку ОСи. Сейчас всё более просто - место BIOS занял UEFI, по соглашению, система теперь стартует с файла в папке /efi/boot/bootx64.efi на загрузочном диске. То есть уже не просто сырые сектора, а сразу файлы. Обработка файловой системы и дисковых устройств запрограммирована в самом UEFI.
https://en.wikipedia.org/wiki/History_of_Linux
Как  то так
Или  то что мы в универе учили
https://homes.cs.washington.edu/~tom/nachos/