Skip to content

Instantly share code, notes, and snippets.

@koxt
Created January 22, 2019 10:19
Show Gist options
  • Save koxt/de0c20a18f6d12c44918d4de90851275 to your computer and use it in GitHub Desktop.
Save koxt/de0c20a18f6d12c44918d4de90851275 to your computer and use it in GitHub Desktop.
Linux kernel
POSIX - Portable Operating System Interface
API - Application Programming Interface
VM - Virtual Memory
US - user space
KS - kernel space
IP - instruction pointer
CPU - central processing unit
DMA - direct memory access
dev - устройство
NUMA - Non-Uniform Memory Access
MMU - memory management unit
SMP - Symmetric Multiprocessing
IPI - inter processors interrupt
APIC - Advanced Programmable Interrupt Controller
LAPIC - local APIC
IOAPIC - input/output APIC
VT-x - Аппаратная виртуализация
ОС - операционная система
ASM - assembly language
Block I/O - block input/output
IPC - interprocess communication
всё касается x86
------------------------------------
Основа
ядро ОС:
1. API к аппаратуре
Linux API соответствует большей части POSIX, но не полностью
системный вызов
отличается от обычного вызова
передача управления из US в KS
с переключением привелегий - в привелигированный режим (от 3 к 0)
с точки зрения ASM
раньше - программное прерывание (инструкция int)
сейчас - инструкция sysenter
является интерфейсом к ядру
2. Управлять ресурсы:
делить доступ между процессами
ресурсы
CPU
Memory
Перифирия (жёсткие диски, мыши, клавы, моники и пр.)
I. Ядро, 2.5 типа
- монолитное
подсистемы
- отдельные части одной большой программы
- в одном адресном простанстве
- вызывают функции других подсистем
- модульное
подсистемы можно подключать/отключать на лету
- это Linux (можно собрать с разными модулями)
++ легче разрабатывать (всё в одном месте)
++ быстрее работает
- микро
ядро - подсистема взаимодействия подсистем
+ подсистема управления памятью (для ускорения)
++ безопаснее (можно восстановить подсисетему)
++ легче разрабатывать (декомпозировано, легче отладить так как мало)
II. Разбор печати "Hello World"
printf() - функция библиотеки (*написал разрботчик*)
write() - функцию (*его вызывает printf*) - не системный вызов
в библиотеке glibc есть имена дублирующие имена системных вызовов, но ими не являются
отличается от системного вызова, ожидаем что glibc кто-то пристегнёт (но может не быть)
отличается от системного вызова - может переставить аргументы, ядро может использовать свои внутренние структуры (таймеры - свои идентификаторы)
sys_write() - системный вызов (*его вызывает write*)
III. Дополнение к API между ядром и US кроме системных вызовов
procfs
- псевдо файловая, для отображения информации о выполняющихся в ядре процессах (нет системного вызова для получения этой информации)
sysctl
- оформлена как файловая система
для конфигурирования констант ядра (куча их в TCP/IP стеке) из US
netlink
- хитрый тип сокета, получателем данных является ядро, после обработки отвечает
- 99.9 написано API к Network подсистеме
IV.
Рекомендации к изучению
https://kernelnewbies.org/ - как точка входа для начинающих
исходники ядра
Что можно ещё изучить, возможные лекции:
Как ядро выглядить с точки зрения программиста
Что происходит на загрузке
Контекст исполнения кода
Синхронизация. MM:управление памятью в ядре, управление памятью программ
Планировщик. Управление процессами
Файловые системы (VFS)
Сетевой код
Особенности работы с дисками
Бонус: kernel developers community
------------------------------------
Отступления
1*.
в VM адреса среди [0:2^разрядность)
в VM разделены
US
IP бегает только в US
KS начиная с адреса вверх
IP бегает только в KS
1**.
выполнение кода в VM (вызов функции)
передача управления (jmp, call) из US в KS
меняются регистры процессора (IP, ...)
call меняет значения регистров процессора
jmp - в регистрах указывается куда вернуться после RETURN
2*.
в аппаратуры для ядра должны быть (мин. требования для работы ядра Linux):
защищённый режим - разделение привилегий кода
страничная адресация - режим
таймер/прерывания - генерация в предсказуемой манере
* ещё в ядре бывает:
DMA
- данные ядро пишет в память; говорит dev-у записать к себе; dev фоново читает; dev по завершение присылает прерывание
- до этого от CPU к dev через порты по 8 байт (инструкции in, out)
NUMA
на многопроцессорной системе CPU ходят к физ. памяти через несколько MMU, которые поровну делят память. MMU общаются между собой
++ для ускорения работы программа где много памяти
- доступ CPU к своей памяти быстрее (памяти меньше) через MMU_1, к чужой (MMU_1 - MMU - 2)- медленнее
-- ядру нужно разбаласировать процессы с учётом NUMA-зон (пришить процесс к CPU)
-- ядру нужно согласовывать выделение объектов в NUMA-зоне и использовать только с принадлежащих CPU
SMP - одинаковые CPU
IPI - прерывание не только от dev но и соседнего CPU (например. планировщик CPU_1 вытесняет процесс (шлёт IPI) на соседнем CPU_2 съевший много CPU_2-time)
APIC - CPU получает прерывания не от железа, а от APIC. APIC получает прерывания от железа
LAPIC - пришит к одному CPU
IOAPIC - принимает от железа прерывания, передаёт LAPIC
VT-x - запуск виртуальных машин эффиктивно на CPU
2**
Уровни привелегий
0 - самый высокий
только здесь настройка страничной адресации (2*)
здесь ядро
1,2
раньше до VT-x для выполнения кода гостевой ОС (чуть больше полномочий кода)
3 - самый низкий
нельзя запрещать прерывания
...
здесь US
нельзя ни на каком обратится к физической памяти
I*. Подсистемы ядра:
File sysem
Memory managment
Network
Block I/O - огромная
блочное dev
- ввод вывод блоками производится фиксированного размера в произвольное место у
- доступ к dev должен производится по произвольному адресу
(подсистема управление подсистемами - не Linux)
Управление процессами
IPC
У сетевой карты - доступ не произвольный
Прерывание - вызывается если dev что-то говорит CPU
В Linux нет ICMP сокетов, используются сырые сокеты (SOCK_RAW)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment