Все зависит от архитектуры, но в принципе все механизмы известны. У меня обращение к драйверам режима ядра выполняется точно так же, как к самому ядру, только с использованием абстракции "виртуальное устройство" (я это называю обращением к функциям вирт. устройства). Например:
Код:
mov esi,SI_DEVICEIO0
mov edi,[dev]
... ; другие параметры
int 60h
Также у драйверов есть возможность цеплять обработчики ко входам IDT 61h-0FFh, но это рекомендуется использовать только для очень специфических целей (эмуляция ABI других систем и т.п.) - ядро не занимается диспетчеризацией обращений к таким обработчикам.
Что касается обращения к службам со стороны прикладных программ, то здесь используются абсолютно такие же механизмы, что и между прикладными программами (в их основе лежит разделение памяти и синхронизация между процессами).