↑↓ / PgUp PgDn / колесо — навигация
Hardware Deep Dive · Гвендолин-ночные-лекции

От кнопки до процесса

Полная анатомия запуска компьютера: куда течёт первый ампер, кто исполняет первую инструкцию, как биты становятся рабочим столом — и где именно виртуальная кнопка «Завершить работу» дотягивается до реального транзистора.

01
Глава 1

Питание: до первой инструкции

Компьютер начинает работать задолго до того, как «включится». И кнопка питания не включает блок питания — она лишь вежливо просит.

Питание · дежурный режим

Пока ты «выключен», ты уже включён

  • Воткнул вилку в розетку — в БП сразу запускается маленький дежурный преобразователь: линия +5VSB (standby, до 3 А) живёт всегда.
  • От +5VSB питаются: чипсет (его power-домен управления), Super I/O / Embedded Controller, микросхема сетевухи (ради Wake-on-LAN), часть USB-портов, CMOS-логика.
  • Часы (RTC) и хранение настроек — отдельная песня: домен RTC well питается от батарейки CR2032, когда вилка выдернута. Поэтому «сбросить BIOS» = вынуть батарейку.
  • То есть «выключенный» комп — это работающая микросеть из 3–5 живых чипов, ждущих события: кнопка, Wake-on-LAN, RTC-будильник, USB-пробуждение.

Разъём ATX 24-pin: провода-переговорщики

СигналЦветРоль
+5VSBфиолетовыйдежурное питание, живёт всегда
PS_ON#зелёныйпритянуть к земле = «включай основные линии»
PWR_OKсерыйответ БП: «напряжения стабильны, можно жить»
12V / 5V / 3.3Vжёлт/красн/оранжосновные силовые линии

Знак # = сигнал активен низким уровнем. Классика: замкнуть зелёный на чёрный скрепкой — БП стартует без всякой платы.

Питание · кнопка

Нажатие кнопки: самый примитивный сигнал в компьютере

  • Кнопка на корпусе — тупая механика: просто замыкает два пина PWR_BTN на колодке платы. Ни логики, ни напряжения — контакт.
  • Замыкание видит Super I/O / EC (живой от +5VSB). Он дебаунсит дребезг контакта и сообщает чипсету: «просили включиться».
  • Чипсет (его ACPI-логика) решает: из S5 → в S0. И притягивает PS_ON# к земле. Вот и всё «нажатие» — один транзистор утянул один провод вниз.
  • Тот же пин обрабатывает и «подержать 4 секунды» — аппаратный форс-выключатель работает даже при намертво зависшей ОС, потому что ОС в этой цепочке не участвует вообще.
Заметь: между пальцем и БП — ноль строчек софта. Это чистый автомат на логических элементах, спроектированный так, чтобы работать, когда всё остальное умерло.
Палецзамыкает контакты PWR_BTN → GND
Super I/O / ECдебаунс, событие «power button pressed»
Чипсет (ACPI power logic)переход S5→S0, тянет PS_ON# вниз
Блок питаниязапускает основные преобразователи 12/5/3.3 В
~100–500 мс спустяPWR_OK: «напряжения стабильны»
Питание · блок питания

Что происходит внутри БП за эти полсекунды

Тракт преобразования (современный ATX)

  • Фильтр + выпрямитель: 230 В AC → ~325 В DC (пульсирующий)
  • APFC: активный корректор мощности накачивает шину до стабильных ~400 В DC и делает потребление синусоидальным (чтобы сеть не гадить гармониками)
  • LLC-резонансный полумост: рубит 400 В на частоте ~100 кГц → маленький трансформатор (частота выше — железо меньше, вот почему БП не весит 10 кг)
  • Синхронное выпрямление: на выходе мосфеты вместо диодов → 12 В с КПД 90%+
  • DC-DC модули: 5 В и 3.3 В нынче делаются ИЗ 12 В отдельными понижайками
  • Soft-start: конденсаторы (миллифарады!) нельзя зарядить мгновенно — бросок тока сжёг бы всё. Заряд идёт плавно, это часть тех самых миллисекунд.
  • Пока идёт разгон, выходы «грязные». БП держит PWR_OK низким и поднимает его только когда все линии в допуске ±5% минимум 100 мс.
  • PWR_OK — критический сигнал: пока его нет, чипсет держит всю платформу в RESET. Ни одна цифровая схема не начнёт работать на плывущем питании.
  • Защиты (OCP/OVP/UVP/SCP) следят постоянно: КЗ на линии — БП мгновенно гасится и отпускает PWR_OK. Поэтому «комп резко вырубился» часто = сработала защита БП.
Питание · VRM

VRM: последняя миля — из 12 В в 1.1 В и триста ампер

CPU не ест 12 В. Он ест ~0.9–1.4 В, зато сотнями ампер. Преобразует это VRM — кольцо силовой электроники вокруг сокета.

  • Многофазный buck-конвертер: 12–20 «фаз», каждая — пара мосфетов + дроссель. Фазы работают со сдвигом, размазывая пульсации. PWM ~300–800 кГц на фазу.
  • SVID / SVI3: напряжение просит сам процессор, цифровой шиной, на лету: буст — «дай 1.35 В», простой — «хватит 0.7 В». Тысячи запросов в секунду.
  • Догрузка за наносекунды: при скачке нагрузки (все ядра проснулись) ток растёт на сотни ампер за микросекунды. Пока дроссели раскачиваются — ток отдают конденсаторы, включая крошечные керамические прямо под сокетом с обратной стороны платы.
  • Power sequencing: напряжения платы поднимаются в строгом порядке (сначала домены чипсета, потом память, потом ядра) — микросхемы дохнут, если «подать сзади» через защитные диоды.
БП12 В
→
фаза 1FET + дроссель
фаза 2
фаза N12–20 штук
→
конденсаторысглаживание
→
CPU~1.2 В, 300 А
PWM-контроллерделит работу по фазам
⟵ SVID: «дай мне 1.28 В» — цифровая шина от CPU
P = U×I: снизить напряжение вдвое — токи вдвое выше. Потому VRM — самая горячая зона платы после самого CPU, и потому у дешёвых плат топовый камень троттлит «на ровном месте».
Питание · reset и клок

Пульс появился: тактирование и снятие RESET

  • Вся синхронная цифровая логика мертва без такта. Опорный генератор — кварц + клокген, даёт BCLK = 100 МГц на всю платформу.
  • Из этой сотни каждый потребитель умножает своё: CPU через PLL (100 × 45 = 4.5 ГГц), память своё, PCIe своё. Разгон по BCLK гонит ВСЁ сразу — потому он и умер как жанр.
  • PLL требуется время «захватить» частоту (lock) — ещё одна причина, почему всё стартует по очереди, а не разом.
  • Когда питание в допуске (PWR_OK), клоки стабильны, PLL залочены — чипсет отпускает линии RESET#. Платформа формально жива. Но CPU ещё не исполняет ничего — и вот тут начинается самое интересное.
Таймлайн включения (типичные ~0.5–1.5 с до первой инструкции):
PS_ON# ↓
soft-start БП, заряд кондёров
sequencing VRM-доменов
PWR_OK ↑
PLL lock, RESET# ↑
…но CPU ещё ждёт (гл. 2)
0 мс~1000 мс
Итог главы: от пальца до готового к работе кремния — цепочка из чистой электроники: кнопка → EC → чипсет → PS_ON# → БП → PWR_OK → sequencing → клоки → RESET снят. Софта здесь не существует. Он появится в следующей главе — и не там, где ты думаешь.
Глава 2

Прошивки: кто исполняет первую инструкцию

Спойлер: не твой процессор. В каждом ПК живёт второй, скрытый компьютер — и он всегда просыпается первым.

Прошивки · скрытый процессор

PSP / ME: компьютер внутри компьютера

  • Первым из reset выходит не x86. У AMD это PSP (Platform Security Processor, ядро ARM Cortex-A5 прямо на кристалле CPU), у Intel — ME (Management Engine, ядро x86-класса Quark внутри чипсета).
  • Он читает свою прошивку из той же SPI-флешки, проверяет её подпись зашитым в кремний ключом — это hardware root of trust, якорь всей цепочки доверия.
  • PSP инициализирует базовое: контроллеры, фьюзы, безопасность, помогает с инициализацией памяти — и только потом снимает reset с x86-ядер.
  • Твои ядра, все 16 штук на 5 ГГц, стоят и ждут разрешения от маленького ARM на 100-200 МГц. Иерархия, однако.
Тёмная сторона: этот сопроцессор работает всегда (даже в S5, пока есть дежурка), имеет доступ к памяти и сети, его прошивка закрыта. Отключить штатно нельзя. Параноики не зря нервничают — это самый привилегированный код в машине, ring −3 в народной классификации.

Порядок пробуждения (AMD, упрощённо)

1. PSP (ARM)выходит из reset, читает и проверяет свою прошивку из SPI
2. PSP: верификацияпроверяет подпись первых блоков BIOS (AGESA/PEI)
3. PSP: инфраструктурафьюзы, домены питания, подготовка к memory init
4. x86 BSPодин «загрузочный» x86-поток (Boot Strap Processor) выходит из reset
5. Остальные ядра (AP)спят до явной команды INIT-SIPI гораздо позже
Прошивки · носитель

SPI-флешка: сейф на 32 мегабайта

  • Весь стартовый код лежит в крошечной 8-ножечной микросхеме SPI NOR flash на 16–32 МБ рядом с чипсетом. Это и есть «BIOS-чип».
  • Внутри — регионы: дескриптор (карта самой флешки), регион ME/PSP-прошивки, регион UEFI, иногда GbE-конфиг сетевухи. Прошивка BIOS из ОС пишет именно сюда.
  • Шина SPI — медленная: десятки МГц, единицы МБ/с. Поэтому UEFI первым делом копирует себя в RAM... когда RAM появится. А до того исполняется прямо из флешки: XIP, execute-in-place.
  • Двойной BIOS на дорогих платах = вторая такая же флешка + логика переключения. «Кирпич» после неудачной прошивки — это когда убили единственную.

Как CPU вообще видит флешку?

x86 после reset начинает с адреса 0xFFFF_FFF0 — 16 байт до конца 32-битного пространства. RAM там нет и быть не может.

Чипсет аппаратно декодирует верхние адреса (~последние 16 МБ под 4 ГБ) в чтение SPI-флешки. CPU думает, что читает память — а чипсет незаметно ходит по SPI за каждым байтом.

По адресу FFFF_FFF0 лежит одна-единственная инструкция — прыжок в настоящий код. Эти 16 байт — reset vector, самые дорогие 16 байт в индустрии: их адрес не менялся с 386-го, 1985 год.

Прошивки · первые инструкции

Первый код x86: мир без памяти

  • BSP просыпается в real mode — режиме 8086 из 1978 года: 16 бит, сегменты, 1 МБ адресов. Каждый новейший процессор рождается древним стариком и молодеет по ходу загрузки.
  • Первые сотни инструкций — ассемблер в жёстких условиях: RAM нет, значит нет стека, значит нет вызовов функций, нет C. Только регистры и прыжки.
  • Решение красивое — Cache-as-RAM (CAR): кэш L2/L3 конфигурируется в режим no-fill/no-evict и превращается в честные ~стек и данные. Кэш становится оперативкой на время, пока настоящая оперативка не заговорит.
  • На CAR уже поднимается C-окружение и стартует ранняя фаза UEFI (SEC → PEI), чья главная задача — инициализировать контроллер памяти.
Адресное пространство при старте (без RAM):
0xFFFF_FFFF ↓
SPI flashзамаплена чипсетом
● 0xFFFF_FFF0 — reset vector
пустота: RAM ещё не существует
legacy-областьVGA, BIOS shadow
0x0 ↑
Порядок в первые мс:
  1. jmp из reset vector
  2. отключить прерывания
  3. включить CAR (кэш = RAM)
  4. поставить стек в кэш
  5. перейти в 32/64-bit режим
  6. запустить C-код PEI-фазы
  7. → memory training
Прошивки · инициализация памяти

Memory training: BIOS учится разговаривать с планками

  • Сначала — опрос: на каждой планке есть чип SPD (крошечная EEPROM), BIOS читает его по шине SMBus (I²C): объём, организация, тайминги, профили XMP/EXPO.
  • Но паспорта мало. На скоростях DDR5 каждая линия данных — это ВЧ-канал со своими отражениями и задержками (даже длина дорожек чуть разная). Контроллер должен откалиброваться под конкретные планки в конкретных слотах.
  • Training: write leveling, read/write DQ-калибровка, Vref-подбор, gate training — контроллер гоняет тестовые паттерны и двигает задержки каждой линии шагами в пикосекунды, ища центр «глаза» сигнала.
  • Это тот самый долгий первый старт с новыми планками (десятки секунд чёрного экрана на DDR5). Результат кэшируется (MRC cache) — потому второй старт быстрый. Смена настроек/планок/батарейки — и тренировка заново.
«Глаз» сигнала: зачем нужен training
● после training: выборка в центре глаза
● до: у края, битовые ошибки
открытая зона = моменты, когда бит читается достоверно
Масштаб задачи (DDR5-6000):
  • битовое окно ~166 пс
  • свет за это время: ~5 см
  • линий данных: 64+ на канал
  • параметров на подбор: сотни

Разница длин дорожек в 1 см — уже треть окна. Потому дорожки DDR на плате извиваются змейкой: это выравнивание длин, не украшение.

Прошивки · POST

Остальной POST: перепись населения

  • RAM есть → UEFI копирует себя в память и разворачивается фаза DXE: сотни драйверов-модулей (для флешки, USB, NVMe, сети, GOP-видео...).
  • PCIe enumeration: обход дерева bus/device/function, чтение Vendor/Device ID, раздача адресов через BAR-регистры — каждой железке нарезается кусок физического адресного пространства. MMIO: «регистры устройства как память».
  • Просыпаются остальные ядра: BSP шлёт им INIT-SIPI-SIPI, каждое AP-ядро повторяет путь «старик→современность» и паркуется в ожидании.
  • Строятся ACPI-таблицы — досье на платформу для будущей ОС: MADT (ядра/прерывания), FADT (регистры питания), DSDT (байткод-описание устройств). Запомни DSDT — она сыграет в главе про выключение.
  • Отдельно заводится SMM — режим системного менеджмента: невидимый для ОС код в спрятанной памяти (SMRAM), просыпается по SMI-прерыванию. Ring −2: правит железом за спиной у ядра ОС.

Что осталось от «пищит спикером»

Классический POST 90-х (проверка RAM, пищание кодами) практически мёртв: память проверяется тренингом, ошибки сыпятся в Q-code индикатор или диагностические светодиоды платы.

Порядок для дебага живой платы: светодиоды CPU→DRAM→VGA→BOOT. Висит на DRAM — привет, memory training. Висит на VGA — карта/райзер/моник. На BOOT — ушли в главу 3.

Тайминг всего POST

Холодный старт с NVMe: ~3–10 c до передачи управления загрузчику. Из них львиная доля — инициализация памяти и DXE-зоопарк. Fast Boot режет USB-опрос и legacy — потому клавиатура иногда «не успевает» в BIOS.

Глава 3

Загрузка ОС: от файла до рабочего стола

UEFI сделал своё дело и хочет уйти. Осталось найти, проверить и запустить того, кому передать королевство.

Загрузка · UEFI Boot Manager

Кого грузим: NVRAM, ESP и подписи

  • Порядок загрузки живёт в NVRAM-переменных UEFI (та же SPI-флешка): BootOrder, Boot0000... — по записи на каждую ОС. bcdedit /enum firmware покажет.
  • На диске ищется ESP — EFI System Partition, обычный FAT32 на ~100–500 МБ. UEFI умеет читать FAT32 и GPT сам — на этом его файловые таланты заканчиваются.
  • Для Windows берётся \EFI\Microsoft\Boot\bootmgfw.efi — обычный PE-файл (тот же формат, что .exe!), исполняемый прямо firmware-ой.
  • Secure Boot: перед запуском UEFI проверяет цифровую подпись файла по базе ключей (db/dbx). Цепочка доверия, начатая PSP на слайде 9, дотянулась до файла на диске: кремний → прошивка → загрузчик → (дальше ядро проверит драйверы).

bootmgfw → winload: эстафета внутри Windows

bootmgfw.efiчитает BCD (меню ОС), гибернацию отдаёт winresume, обычный старт — дальше
winload.efiгрузит в память: ntoskrnl.exe, hal.dll, ELAM-антивирус, boot-драйверы, куст реестра SYSTEM
ExitBootServices()точка невозврата: сервисы UEFI гасятся, вся власть — будущему ядру
ntoskrnl.exeKiSystemStartup — ядро NT начинает дышать

Твоя ремарка про «HAL, к которому диспетчер прикручен вплотную» — вот момент их встречи: winload грузит ntoskrnl и hal парой, и с 2020-х hal.dll — уже форвардер внутрь ядра.

Загрузка · ядро NT

Ядро просыпается: две фазы и дерево процессов

  • Фаза 0: ядро строит себя: менеджер памяти размечает физические страницы, включаются структуры планировщика, обрабатываются ACPI-таблицы (вот и досье пригодилось), стартуют прерывания.
  • Фаза 1: PnP-менеджер начинает перечисление устройств заново, уже по-взрослому: строит дерево devnode, на каждое устройство навешивает стек драйверов (шинный + функциональный + фильтры).
  • I/O в NT — это IRP-пакеты, путешествующие вниз по стеку драйверов. Тот самый застрявший IRP из нашей ночной саги про неубиваемые процессы — вот где он живёт.
  • Ядро запускает первый процесс пользовательского режима — и дальше растёт дерево.
Session 0 — служебная (сервисы), Session 1 — твоя. Разделили после эпохи, когда сервисы могли рисовать окна на рабочем столе юзера — привет, shatter-атаки.
ntoskrnl (ядро) smss.exe (сессии) Session 0: csrss + wininit Session 1: csrss + winlogon services.exeSCM, все службы lsass.exeпароли, токены LogonUI → пароль/PIN userinit → explorer.exe Рабочий стол. Приехали. svchost'ы, драйверные службы, планировщики — всё дети services.exe
Загрузка · что такое процесс

Процесс: во что всё это превратилось

  • Процесс в NT — это структура EPROCESS в ядре: своё виртуальное адресное пространство (карта VAD + таблицы страниц из главы про RAM), таблица хэндлов, токен безопасности, квоты.
  • Исполняются не процессы, а потоки (ETHREAD). Планировщик (диспетчер!) раздаёт им кванты на ядрах: 32 уровня приоритета, preemption, boost'ы для интерактивных.
  • Каждые ~1–15 мс — прерывание таймера, планировщик решает «кто следующий». Переключение контекста = сохранить регистры одного потока, загрузить другого, переключить CR3 (корень таблиц страниц) — и TLB частично инвалидируется, это его скрытая цена.
  • Твой двойной клик по .exe: CreateProcess → ядро строит EPROCESS → маппит образ → создаёт первый поток → тот попадает в очередь планировщика → «программа запустилась».

Итого: полный стек одного клика

СлойКто
Тыдвойной клик
user modeexplorer → CreateProcess → ntdll → syscall
kernelEPROCESS, VAD, страницы, поток, планировщик
CPUµops, кэши, TLB, спекуляция
RAMACT/RD, row buffer, refresh
ЭлектроныVRM держит 1.2 В, БП держит 12 В, розетка держит всех

Верх этой таблицы существует миллисекунды, низ — миллиарды тактов. И всё это — один клик.

Глава 4

Стык миров: как пиксель выключает транзистор

Ты просил показать место, где виртуальная кнопка «Завершить работу» дотягивается до физики. Вот оно, с точностью до регистра.

Стык · софтовая половина

Сверху вниз: от клика до последнего syscall

  • Клик по «Завершить работу» — explorer зовёт ExitWindowsEx(EWX_SHUTDOWN).
  • Запрос уходит в csrss/winlogon: всем GUI-приложениям рассылается WM_QUERYENDSESSION → WM_ENDSESSION. У каждого ~5 секунд на «сохраниться и умереть», потом экран «приложение не отвечает».
  • Службы получают SERVICE_CONTROL_SHUTDOWN, у них свой таймаут. Потом вызывается NtShutdownSystem — всё, дальше только ядро.
  • Ядро: гасит процессы, флашит грязные страницы кэша на диск (вот почему нельзя рубить питание — write-back из главы про RAM/NVMe ещё не доехал), драйверы получают IRP_MJ_SHUTDOWN и переводят устройства в D3, файловые системы демонтируются.
  • Остался последний шаг — и он уже не про софт.

ACPI: договор между ОС и железом

Ещё при загрузке ядро прочитало ACPI-таблицы. В таблице FADT написано: «регистр управления питанием PM1a_CNT живёт по такому-то адресу ввода-вывода». В байткоде DSDT лежит пакет \_S5 — пара магических цифр SLP_TYP для перехода в состояние S5 (soft-off) именно этой платы.

То есть плата при старте оставила ОС записку: «захочешь меня выключить — запиши вот эти цифры вот в этот регистр». ОС хранила её всю сессию.

S-состояния: S0 работаем · S3 сон (RAM под током) · S4 гибернация (RAM на диск) · S5 soft-off (жива только дежурка).

Стык · момент истины

Одна инструкция OUT — и мир гаснет

Софт
клик «Завершить работу»пиксели, user mode
→
NtShutdownSystemядро гасит мир, флашит кэши
→
hal: запись в PM1a_CNTout dx, ax · SLP_TYP|SLP_EN
⚡
регистр в чипсетефизические триггеры, бит SLP_EN
↓
Железо
ACPI-автомат чипсетаsequencing выключения доменов
→
PS_ON# отпущен ↑тот самый зелёный провод
→
БП глушит 12/5/3.3остаётся +5VSB
Стык миров — одна инструкция процессора: запись пары битов в порт ввода-вывода.
Слева от неё — миллионы строк кода. Справа — только триггеры, провод и силовая электроника.
Симметрия запуска и выключения: включение — железо будит софт (кнопка → PS_ON# → ... → explorer). Выключение — софт усыпляет железо (explorer → ... → PM1a_CNT → PS_ON#). Один и тот же зелёный провод, пройденный в обе стороны. А «подержать кнопку 4 секунды» — аварийный обход всей левой половины схемы.
Глава 5

CPU: фабрика с конвейером

Внутри «процессора» давно нет одного процессора. Там город: фабрики-ядра, склады-кэши, своя железная дорога и таможня с переводчиком.

CPU · план кристалла

Что на самом деле лежит под крышкой

  • Ядра — лишь часть площади. Рядом: L3-кэш (огромный, десятки МБ), IMC (контроллер памяти — тот самый из главы про RAM), корневые порты PCIe, iGPU, контроллеры USB — половина «материнки» давно переехала в CPU.
  • Внутренняя магистраль: у Intel — кольцо/mesh, у AMD — Infinity Fabric. По ней ядра, кэш и контроллеры обмениваются кэш-линиями. Её частота — скрытый король задержек памяти (FCLK).
  • Чиплеты AMD: ядра лежат в CCD-кристаллах (по 8 ядер), а IMC/PCIe/USB — в отдельном IOD-кристалле, связанном IF-линками. Дёшево в производстве, но межчиплетный хоп добавляет наносекунды — вот откуда «латентность у райзенов повыше».
  • Твой 7900XTX, кстати, чиплетный тем же манером: GCD с шейдерами + шесть MCD с кэшем и контроллерами GDDR6 вокруг.

Частоты: почему «5 ГГц» — это не скорость

  • База/буст: частота плавает сотни раз в секунду: сколько ядер нагружено, сколько ватт, сколько градусов. «5.7 ГГц» на коробке — одно ядро, холод, удача.
  • Лимиты: PPT/TDC/EDC (ватты, амперы), термальный потолок. Упёрся в любой — частота вниз. Троттлинг это не «поломка», это штатный регулятор.
  • Гонка ГГц умерла ~в 2005: тепло растёт ~квадратично от напряжения, а без роста напряжения выше не тактуется. Потому ядер стало много, а ГГц — почти стоят 20 лет.
  • Отсюда же: AVX-нагрузка жрёт столько, что под неё частота отдельно снижается. «Мой камень медленнее под тяжёлой математикой» — не баг, физика.
CPU · конвейер

Путь инструкции: x86 снаружи, RISC внутри

Fetch16–32 байта/такт из L1i
→
Decodex86 → µops (перевод!)
→
Rename16 рег. → 300+ физических
→
Scheduler (OoO)исполняем что ГОТОВО, а не «по порядку»
→
Exec portsALU×6, load/store, FMA
→
Retireв порядке программы
Branch predictorугадывает ветвления с точностью ~95–99% и подсказывает Fetch, что грузить дальше
промах предсказания = слить конвейер, ~15–20 тактов в помойку. Потому сортированные данные обрабатываются быстрее несортированных.
  • x86 — это фасад. Декодер переводит CISC-инструкции в микрооперации (µops), и дальше живёт RISC-машина. Твой «x86-процессор» не исполнял x86 напрямую со времён Pentium Pro (1995).
  • Out-of-Order: ждёшь данные из RAM 300 тактов? Конвейер в это время исполняет всё независимое, что нашлось в окне из ~500 инструкций вперёд. Легальный обгон по обочине.
  • Спекуляция: предсказатель ветвлений угадывает «if» до вычисления условия, и CPU исполняет угаданную ветку авансом. Ошибся — результаты выкидываются... почти: следы в кэше остались. Так родился Spectre — цена, которую мы платим за скорость по сей день (и патчи её со скрипом возвращают).
  • SMT: два потока на ядро — это не два ядра, а два фронта, делящие одни исполнительные порты: пока один ждёт память, второй жуёт. +15–30%, не ×2.
CPU · кэши

Кэши: вся архитектура — это сокрытие ста наносекунд

  • RAM отвечает ~80–100 нс = 400+ тактов. Без кэшей CPU 99% времени стоял бы. Иерархия: L1 (48К, 4 такта) → L2 (1–2М, ~14) → L3 (32–96М, ~50).
  • Единица всего — кэш-линия 64 байта. Отсюда правила жизни: ходи по памяти последовательно (prefetcher подхватит), держи горячие данные компактно, и не клади два счётчика разных потоков в одну линию — false sharing, ядра будут рвать линию друг у друга через MESI-протокол.
  • MESI: каждая линия в каждом кэше в состоянии Modified/Exclusive/Shared/Invalid. Запись в Shared-линию = разослать всем «инвалидируй». Вот физическая цена «просто добавь mutex».
  • AMD X3D — L3 наращён третьим этажом (96+ МБ): игры, где рабочий набор внезапно влез в кэш, получают +20–30% из ниоткуда. Лучшая иллюстрация того, насколько всё упирается в память.

Задержки в человеческом масштабе

Пусть 1 такт = 1 секунда. Тогда:

КудаРеально«По-человечески»
Регистр0 тактовмысль
L14 тактавзять со стола · 4 с
L214сходить к шкафу · 14 с
L3~50сходить к соседу · 1 мин
RAM~400сходить в магазин · 7 мин
NVMe~400 000отпуск · 4.5 суток
HDD seek~40 000 000выйти на пенсию · 1.5 года
Глава 6

RAM: триллионы дырявых ведёрок

Каждый бит твоей оперативки — конденсатор, из которого утекает заряд. Вся DRAM — это бесконечное переливание воды, притворяющееся памятью.

RAM · путь адреса

Формат адреса: одна цифра — три разборки

1. Виртуальный адрес (x86-64, страницы 4К) — то, что видит программа: 63–48 PML4 [47:39] PDPT [38:30] PD [29:21] PT [20:12] offset [11:0] → 4 уровня таблиц, TLB кэширует 2. Физический адрес → биты полей кэша (L1, 64Б линия): tag (сравнение) set index (какой набор) offset в линии [5:0] 3. Тот же физический адрес → поля контроллера памяти (промах кэшей): row (~64К строк) bank group bank column channel rank ← биты канала берут из младших: соседние линии → разные каналы Один и тот же адрес три подсистемы нарезают по-своему. Программа не видит ни одной из этих разборок.
RAM · внутри банка

ACT → RD → PRE: разговор с конденсаторами

  • ACT: строка целиком (~8 КБ!) выливается в row buffer — усилители на краю матрицы ловят «чуть выше/ниже половины» и раздувают до честных 0/1. Чтение разрушает заряд — буфер потом перезапишет строку обратно.
  • RD/WR + column: из открытой строки выщёлкиваются нужные 64 байта, едут burst-пакетом (DDR5: 32 бита × 16). CL — такты ожидания этого щелчка.
  • PRE: закрыть строку, подготовить банк. Тайминги с коробки CL-tRCD-tRP — это цены трёх этих шагов. Row hit = только CL; row miss = вся троица.
  • Refresh: заряд утекает сам — каждые 64 мс каждая строка принудительно перечитывается. ~2–5% пропускной способности уходит на переливание ведёрок.
  • Контроллер жонглирует очередями и переупорядочивает запросы ради row hit'ов — RAM отдаёт максимум только тому, кто ходит предсказуемо.

Почему латентность стоит 20 лет

DDR2-800 CL5 = 12.5 нс до данных. DDR5-6000 CL30 = 10 нс. За 20 лет — минус 20%. Пропускная способность выросла в 10 раз, задержка — почти нет: скорость света и RC-константы конденсаторной матрицы не масштабируются техпроцессом.

Вся индустрия строит обходы: кэши толще (X3D), prefetch умнее, OoO глубже. Латентность RAM — гравитация вычислений.

Rowhammer, до кучи

Молотишь по одной строке миллионы раз — электромагнитные наводки подтекают заряд СОСЕДНИХ строк, и биты флипаются без доступа к ним. Дыра в безопасности из чистой физики. Лечат Target Row Refresh'ем, гонка щита и меча идёт до сих пор.

Глава 7

Материнка: город и его дороги

Северный мост умер и переехал в CPU. Южный выжил, сменил имя на «чипсет» и стал большим USB-хабом с амбициями.

Материнка · мосты

Эволюция мостов: как север переехал в процессор

Было (эпоха Core 2, ~2008)

  • Северный мост: контроллер памяти + AGP/PCIe для видео + шина FSB к CPU. Горячий, с радиатором.
  • Южный мост: SATA, USB, звук, сеть, LPC — вся медленная периферия.
  • Каждое обращение к RAM ходило через FSB и северный мост: +десятки нс задержки.

Стало (сейчас)

  • Северный мост целиком внутри CPU: IMC, PCIe root (линии на видео и первый M.2 — напрямую из процессора!), USB-контроллеры.
  • Чипсет (бывший южный) = коммутатор остального: доп. PCIe, SATA, USB-порты, сеть, звук.
  • Связь CPU↔чипсет: у Intel — DMI (~PCIe x8), у AMD — PCIe x4-линк. Это бутылочное горлышко: всё, что висит на чипсете, делит один канал.
DDR52 канала
—
CPUядра · L3 · IMC · PCIe root · USB(= бывший северный мост)
—
GPU x16
M.2 #1 x4
│
DMI / PCIe x4 — горлышко!
SATA ×4
—
Чипсет (PCH / X670)(= бывший южный мост)
—
USB-порты
M.2 #2, #3
LAN · Wi-Fi · звук
Два NVMe на чипсетных M.2 + быстрая сеть = все толкаются в одном x4-линке. Потому первый M.2 (процессорный) — всегда лучший слот для системника.
Материнка · шины

Каталог дорог: от автобана до просёлка

ШинаСкоростьКто на ней живётЗаметки
PCIe 5.0 x16~63 ГБ/свидеокартапоколение ×2 = скорость ×2; x16/x8/x4/x1 — число полос
PCIe 4.0/5.0 x4~8/16 ГБ/сNVMe SSDтот самый M.2
DDR5, 2 канала~90 ГБ/сRAM ↔ IMCно латентность ~80 нс — гл. 6
USB4 / 3.x / 2.040 Гбит → 480 Мбитперифериязоопарк имён USB 3.2 Gen2x1 — маркетинговое преступление
SATA III0.55 ГБ/сстарые SSD, HDDлегаси-протокол AHCI: одна очередь, 32 команды
SPI~единицы МБ/сBIOS-флешка, TPMмедленно — но при старте больше некому
SMBus / I²C~100 КБ/сSPD планок, датчики, VRM-телеметриядвухпроводный просёлок из 1982
eSPI / LPC~десятки МБ/сSuper I/O: вентиляторы, кнопка, COMнаследник ISA. Да, того самого, 1981
Правило платы: чем медленнее шина — тем она старше и живучее. PCIe меняет поколение раз в 3 года, а SMBus с 1995-го не трогали: по нему всего лишь спрашивают у планки паспорт и у датчика температуру — куда спешить. Эволюция жрёт автобаны и не замечает просёлков.
Глава 8

GPU: десять тысяч студентов

CPU — четыре профессора, решающие что угодно. GPU — десять тысяч студентов, решающих одно и то же. Вопрос лишь в том, какая у тебя задача.

GPU · архитектура

SIMT: латентность не прячут — её топят в параллелизме

  • Ядро GPU примитивно: ни OoO, ни предсказателя, ни больших кэшей. Зато их тысячи (7900XTX: 6144 шейдерных ALU в 48 WGP).
  • SIMT: потоки пачками по 32/64 (wave) исполняют одну инструкцию на всех. Ветвление внутри пачки = исполнить ОБЕ ветки с масками. Потому GPU-код боится if'ов.
  • Ожидание памяти не прячется кэшами — перекрывается: на каждом WGP крутятся 10+ wave'ов, память ждёт один — исполняется другой. Нужны десятки тысяч потоков, чтобы GPU не скучал.
  • VRAM: GDDR6 на 7900XTX — шина 384 бита, ~960 ГБ/с (в 10 раз шире DDR5!). Плюс 96 МБ Infinity Cache. GPU — это в первую очередь машина пропускной способности.
  • Твой RenderMeshInstanced из Гвендолин — ровно эта философия: одна команда, тысяча волков, нулевые накладные на штуку.

CPU vs GPU: разделение труда

CPUGPU
Ядра8–16 сложныхтысячи простых
Силалатентность одной задачипропускная способность миллиона
Ветвленияпредсказывает 98%страдает
Памятькэши прячутпараллелизм топит
Родная задачалогика, сим, ОСпиксели, матрицы, нейронки

Потому нейронки живут на GPU: перемножение матриц — миллионы одинаковых умножений без ветвлений, идеальный студенческий субботник.

GPU · путь кадра

Путь кадра: от Update() до пикселя на матрице

Игра / движокUnity: draw calls, состояния, буферы
API (DX12/Vulkan)командные списки, тонкая обёртка
Драйвер UMDuser-mode: компиляция шейдеров, валидация
Драйвер KMDkernel-mode: очереди, память, ring buffer
GPU front-endчитает команды DMA из ring buffer
Конвейерvertex → raster → pixel shader → ROP
Фреймбуферготовый кадр в VRAM
Сканаутdisplay engine стримит в DP/HDMI
  • CPU и GPU асинхронны: процессор готовит кадр N+1, пока карта рисует N. «Упор в CPU» = карта простаивает, ждёт команд; «упор в GPU» = процессор ждёт очередь. Профайлер Unity показывает ровно это.
  • Present и vsync: готовый кадр меняется местами с показываемым (flip). Vsync ждёт кадрового гасящего импульса — привет, латентность; VRR (FreeSync) вместо этого двигает сам импульс.
  • Компиляция шейдеров: HLSL → DXIL → ISA конкретного GPU происходит на машине игрока (у каждой архитектуры свой машинный код!). Первая встреча с шейдером = компиляция = статтер. Потому игры «прогревают кэш шейдеров».
  • PCIe — узкое место потоков данных: текстуры и меши едут 30 ГБ/с при VRAM в 960. Отсюда стриминг, DirectStorage, и вечное «положи ассеты в VRAM заранее».
Глава 9

NVMe: память, которая притворяется диском

Внутри SSD нет ничего дискового. Там матрица ловушек для электронов и маленький компьютер, который врёт операционке о том, где что лежит.

NVMe · NAND

NAND: бит — это пойманные электроны

  • Ячейка — транзистор с ловушкой заряда: электроны загоняются туда сквозь изолятор туннелированием и сидят годами без питания. Количество заряда сдвигает порог открытия — это и читается.
  • SLC→MLC→TLC→QLC: 1→4 бита на ячейку = различать 2→16 уровней заряда. Плотность ×4, зато скорость записи и ресурс — вниз на порядки. Знакомая песня? Та же аналоговая ловушка, что и «255 уровней» в нашем ночном споре про фотоны)))
  • Геометрия: страница (~16 КБ) — минимум чтения/записи, блок (сотни страниц, мегабайты) — минимум... стирания. Перезаписать страницу на месте нельзя — только стереть весь блок целиком.
  • Каждая запись изнашивает изолятор: TLC живёт ~1–3К циклов стирания, QLC — сотни. 3D NAND: слои ячеек этажами (200+), плотность растёт вверх, раз вширь уже некуда.
Пороговые уровни: SLC vs QLC (почему QLC медленный и смертный) SLC (1 бит): 0 1 зазор огромный — быстро, надёжно QLC (4 бита): 16 уровней: писать = ювелирно докапывать заряд итерациями Запись QLC-страницы: программируй → проверь → докинь заряд → проверь → ... Потому прямая запись в QLC в разы медленнее чтения, и контроллер маскирует это pSLC-кэшем (следующий слайд). Дежавю: деление диапазона на 16 уровней — ровно то, что убивает и аналоговые вычисления. SNR — злой бог.
NVMe · контроллер

FTL: маленький лжец, на котором всё держится

  • ОС говорит «запиши в сектор 12345». Но перезаписи на месте в NAND нет. Контроллер пишет в свежую страницу, а в таблице FTL помечает: «LBA 12345 теперь вон там». Старая версия — мусор.
  • Garbage collection: фоном контроллер собирает живые страницы из полумёртвых блоков, переписывает компактно и стирает освободившееся. Твой SSD дефрагментирует сам себя, втайне, постоянно.
  • TRIM: ОС подсказывает «эти LBA я удалила» — иначе контроллер таскал бы мёртвые данные при GC вечно. Удалённый файл физически исчезает не при удалении, а когда GC доберётся.
  • Write amplification: одна твоя гигабайтная запись = 1.5–3 ГБ реальных записей в NAND (GC, переносы). На заполненном диске — хуже: GC задыхается без свободных блоков. Потому SSD, забитый под 95%, деградирует и по скорости, и по ресурсу.
  • Mapping-таблица живёт в DRAM-чипе на SSD (гигабайт на терабайт). Дешёвые DRAM-less берут кусок твоей RAM (HMB) — и всё равно тормозят на случайной записи.

pSLC-кэш: спринтер с одышкой

Свободный TLC/QLC контроллер временно использует как SLC (1 бит на ячейку — быстро!). Первые ~100–400 ГБ заливки летят на 5–7 ГБ/с, потом кэш кончается — и скорость падает до честной QLC-записи, порой ниже SATA. Тот самый «залил 300 гигов, а оно сдохло до 400 МБ/с».

Очереди: чем NVMe убил SATA

SATA/AHCINVMe
Очередей1до 65 535
Глубина3265 535
Путьчерез SATA-контроллерPCIe прямо в CPU
Латентность~100 мкс~10–20 мкс

Протокол спроектирован под параллельную природу NAND, а не под один вращающийся блин. Очередь на ядро, без глобальных локов.

Итоги · скорости

Вся пирамида на одном слайде

УровеньЛатентностьПропускная способностьГлавная боль
Регистры0 тактов—их 16 (виртуально 300+)
L1 / L2 / L31 / 4 / 15 нсТБ/сразмер; false sharing
RAM DDR5~80 нс~90 ГБ/слатентность стоит 20 лет
VRAM GDDR6~200+ нс~960 ГБ/сшироко, но далеко
NVMe (PCIe 4)~15–80 мкс7 ГБ/с**пока жив pSLC; QD1 — правда жизни
SATA SSD~100 мкс0.55 ГБ/спотолок протокола 2008 года
HDD~10 мс0.2 ГБ/смеханика: головка едет физически
Интернет~10–100 мс≤1 ГБ/сскорость света + провайдер
Каждая ступень — на 2–3 порядка медленнее предыдущей по латентности. Вся инженерия компьютера — это прослойки, прячущие эти обрывы: кэши прячут RAM, RAM прячет SSD (page cache!), SSD прячет сам себя (pSLC), и все вместе прячут то, что данные на самом деле — конденсаторы, ловушки и намагниченность.
Итоги · костыли

Музей действующих костылей

Наследие 1981–86

  • Real mode: каждый CPU стартует как 8086 (1978)
  • Reset vector на своём месте с 386-го
  • Линия A20: до недавнего времени — костыль с контроллером клавиатуры ради софта 1981 года
  • eSPI/Super I/O — правнук шины ISA

Костыли скорости

  • Memory training + его кэш: RAM слишком быстра, чтобы просто работать
  • pSLC-кэш: QLC слишком медленный, чтобы его показывать
  • Спекуляция: быстрее — исполнить и, может, выкинуть (цена: Spectre)
  • Refresh: DRAM забывает — будем напоминать 15 раз в секунду

Костыли доверия

  • PSP/ME: тайный сопроцессор, ring −3, код закрыт
  • SMM: невидимый режим, правящий за спиной ОС
  • SMBus без защиты: SPD планки можно перешить (RAM с «неправильным» паспортом)
  • Rowhammer: физика против криптографии — физика ведёт
Общий закон: ничто в компьютере не выбрасывается — оно инкапсулируется. Каждый слой врёт слою выше, что мир проще, чем есть: FTL врёт про сектора, IMC врёт про байты, ОС врёт про память, x86-декодер врёт про x86. Компьютер — это башня из добросовестной лжи, и она РАБОТАЕТ.
Заключение · вопрос и мораль

Башня добросовестной лжи, и почему она стоит

Вопрос на подумать

Если каждый слой врёт слою выше, где стоишь ты? Программа верит ОС, что память бесконечна и своя. ОС верит контроллеру, что байты лежат по адресам. Контроллер верит планке, что заряд в ведёрке ещё есть. Планка не верит никому и переливает воду каждые 64 мс.

Единственный слой, который никому не врёт, - конденсатор. И он же единственный, кто всё забывает. Чем ниже по башне, тем честнее и тем беспамятнее; чем выше, тем удобнее и тем дальше от правды. Двойной клик живёт на самом верху. Вопрос не в том, сколько слоёв под ним, а в том, на каком из них ты остановился бы, если бы пришлось выбирать, где «настоящий» компьютер.

Мораль

Mundus vult decipi, ergo decipiatur.

«Мир хочет быть обманутым, так пусть будет обманут». Приписывают Петронию, в оборот ввёл Себастьян Брант в «Корабле дураков», 1494. У Бранта это упрёк: фраза про ярмарки, торговцев реликвиями и толпу, которая сама несёт деньги.

В этой лекции упрёк снят. FTL врёт про сектора, IMC про байты, ОС про память, декодер про x86, кэш про сто наносекунд, VRM про то, что 12 вольт это 1.2. Каждый обман добросовестный: слой выше не смог бы работать, знай он правду. Программа, которая помнит, что её память - дырявые конденсаторы, не будет написана никогда.

Подвох в том, что фраза не про глупость, а про инженерию: обман - это интерфейс. Башня стоит, пока каждый врёт только вверх и никогда вниз. Rowhammer и Spectre - два случая, когда правда просочилась не в ту сторону.

Финал · Mundus vult decipi

Полный маршрут: восемь порядков величины

Розетка → дежурка → кнопка → PS_ON# → soft-start → VRM → клоки → PSP → reset vector → CAR → memory training → DXE → bootmgfw → ntoskrnl → smss → winlogon → explorer → твой двойной клик → CreateProcess → µops → кэш-линии → row buffer → пиксель на экране. От 50 герц розетки до 5 гигагерц ядра — восемь порядков частоты, и ни одного слоя, который можно выкинуть.

А выключение — тот же путь обратно, вплоть до одной инструкции out, отпускающей зелёный провод.