Операционные системы с нуля; Уровень 0

https://web.stanford.edu/class/cs140e/assignments/0-blinky/
  • Перевод
  • Tutorial

Добрый день/вечер/ночь/утро! Есть один экспериментальный курс по операционным системам. Есть он в Стэнфордском университете. Но часть материалов доступно всем желающим. Помимо слайдов доступны полные описания практических занятий.


Чем этот курс отличается от прочих других? Большая часть кода пишется самостоятельно и выполняется на вполне реальном современном железе. В качестве целевой платформы выбран Raspberry Pi 3 model B. Т.е. достаточно актуальная архитектура AArch64. ARMv8 Cortex-A53, четыре ядра, 64-бита и вот это всё. В качестве основного языка программирования выбран Rust. Который безопасный, быстрый, без GC и так далее. Его, Rust, предполагается изучать во время курса.


Тут есть про диски, файловые системы, операции ввода-вывода, потоки /процессы, планирование, виртуальную память, защиту и безопасность, прерывания, параллелизм и синхронизацию. Как и в любом другом, уважающем себя курсе. Разница в актуальности материала и в количестве практики. Коддить придётся много.


Примечание переводчика


Если вы хотели увидеть дословный перевод, то его не будет. Вместо этого я буду стараться сделать текст полезным и понятным. Например в тех местах, которые актуальны только для студентов Стэнфорда, я помещу информацию полезную остальным. Тут может быть немного сленга, чуточку несвязанных с оригиналом иллюстраций и небольшое количество дополнительных комментариев. В угоду читабельности тут не будет явных Примечаний Переводчика™. Текст можно считать художественным переводом или статьёй по мотивам. Я не сварщик — не обижусь.


Откуда я узнал про этот курс? Некто выложил ссылочку на Hacker News. Я случайно увидел и проникся. Немного сам тыкал материалы курса и в итоге решился это дело переводить.


Обзор


В этой части будем настраивать малинку и необходимые инструменты. По итогам у нас будет малинка, мигающая светодиодом. Тут есть четыре основных этапа. Для начала нам требуется убедиться, что связь Pi с компьютером вполне себе работает. Запустим предварительно подготовленную программу. Во втором этапе разберёмся, как светодиодики подключать. Про макетную плату и проводки. На третьем этапе соберём няшный сишный код и запустим его на Pi. Установим кросскомпилятор aarch64-none-elf и попробуем его в деле. И на четвёртом этапе перепишем это всё дело на Rust.


Парочка полезных ссылок:



Фаза 0: Начало работы


Перед выполнением курса следует достать себе в непосредственное пользование unix-подобную операционную систему. Это может быть Linux, BSD или macOS с установленными git, wget, tar, screen и make. Теоретически может заработать в Windows 10 с подсистемой linux, но никто не проверял наверняка. По крайней мере такая конфигурация не поддерживается. Т.е. для виндузятников нет готовых рецептов и рекомендуется установить Ubuntu LST или Fedora.



Из железа нам потребуются:


  • Raspberry Pi 3 model B (обязательно с процем BCM2837)
  • Макетная плата, она же доска для прототипирования
  • microSD карточка (плюс адаптер/переходник)
  • USB-UART переходник (CP2102 USB TTL)
  • Десяток многоцветных светодиодов
  • Резисторы на 100 Ом и на 1 кОм по четыре штуки
  • проводки

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


Внимание: малинка чувствительна к электростатике. Старайтесь не трогать голыми руками контакты. Вас током не убьёт и даже не поцарапает, а вот саму малинку вполне себе может вывести из строя. Заземляйтесь.


Когда это всё есть в наличии можно стянуть код задания:


git clone https://web.stanford.edu/class/cs140e/assignments/0-blinky/skeleton.git 0-blinky
cd assignment0
make fetch

Не стесняйтесь исследовать содержимое самостоятельно.


Фаза 1: Готовим малинку



Первое, что нам требуется сделать — это настройка CP2102-переходника. Он нужен для общения между компьютером и Pi. По мимо этого малинка получает через него жизненно необходимые 5 вольт. С одной стороны USB, с другой штук пять штырьков, посередине платка.


Настройка драйверов


На линуксе всё должно заработать сразу из коробки. На маках потребуется установить драйвер. Скачиваем этот архив и распаковываем. Запускаем SiLabsUSBDriverDisk.dmg и соглашаемся с пунктами о продаже души по лицензии. После этого на подмонтированном томе запускаем Silicon Labs VPC Driver.pkg. Устанавливаем и перезагружаемся.


Попробуйте вставить CP2102 в свободный USB-слот. Если всё работает, то должны появится соответствующие файлы в /dev. В случае мака /dev/tty.SLAB_USBtoUART. В случае линукса что-то вроде /dev/ttyUSB0. Запишите — пригодится. Вынимаем переходник.


Подключение малинки


Теперь подключаем Raspberry Pi к CP2102. Вот таблица соответствия разъёмов:


Разъёмы на CP2102 Разъёмы на Raspberry Pi
+5v 4
GND 6
RXD 8
TXD 10

Нумерация пинов на малинке (ещё есть интерактивная версия):



Всё вместе будет выглядеть так (цвета проводов можно выбирать произвольно):




Важно: проверьте и перепроверьте соединения перед подключением этого всего к компьютеру. Нам нужна свежая малинка, а не подгоревшее варенье.


Если есть уверенность в правильности сопряжения малинки и переходника — можно таки подключить CP2102 к компу.


Запуск


Raspberry Pi подгружает программки с microSD-карточки во время включения. Прямо сейчас мы разберёмся, как это готовить.


Для начала нам нужно скинуть на microSD-шку файлики из склонированного репозитория. А именно те, которые лежат в папке files/firmware. Т.е. bootcode.bin, config.txt и start.elf. Скопировать их следует в корень флеш-карты. Если вдруг в склонированном репозитории нет этих файликов — вы забыли про make fetch.


Зачем нужны bootcode.bin, config.txt и start.elf?
Это всё является загрузчиком для малинки. bootcode.bin — первый загрузчик. Его задача — загрузить start.elf. Который настраивает процессор в соответствии с содержимым файла config.txt. После этого он загружает kernel8.img и передаёт ему управление. Кстати где он?

Теперь копируем files/activity-led-blink.bin из репо в корень флеш-карты и даём этому файлику имя kernel8.img. Размонтируем карту и вытаскиваем. Убеждаемся, что малинка отключена. Затем вставляем карточку в малинку и подключаем малинку к питанию. Мы должны увидеть мигающий светодиод на малинке и на CP2102-переходнике. Мигание последнего означает, что там передаются некие данные.


Данные? Какие данные? Для того, чтоб посмотреть их нам нужно подключить эмулятор последовательного терминала к CP2102 и прочитать, что там происходит. Будем использовать screen ибо он установлен и на Linux, и на macOS. Вспомните путь к устройству из папки /dev и запустите


screen /dev/<имя> 115200

В Linux может потребоваться использовать sudo для запуска этой команды. Впрочем можно добавить своего пользователя в группу dialout и не писать перед этой командой sudo постоянно:


sudo gpasswd --add <имя-пользователя> dialout

Так или иначе, но мы должны увидеть приветствия от малинки. Для выхода из screen следует нажать <ctrl-a> k, а затем ответить y на предложение о выходе.


Фаза 2: Мигаем светодиодом


На этом этапе мы подключим 16-й вывод GPIO (физический контакт №36) малинки к светодиодику на макетке. Проверим его работу используя предварительно подготовленный бинарник с прошивкой. Убедитесь что малинка отключена.


GPIO: General Purpose I/O (Ввод-вывод общего назначения)


Как следует из названия, GPIO является общим механизмом передачи данных/сигналов между какими либо двумя устройствами через электрические контакты.


GPIO-выводы на малинке могут работать как входы или как выходы. Когда контакт является выходным, его можно включить или выключить. Под включением контакта подразумевается, что с него можно взять 3.3 вольта. Под выключением подразумевается, что через этот контакт ток не идёт. Когда же GPIO-контакт является входным, то малинка проверяет, есть ли на оном 3.3 вольта, либо же нет.


Эти контакты невероятно, умопомрачительно универсальны и их можно использовать для реализации огромного спектра различных функций. Подробности можно узнать в документации. Документация не просто так прилагается. Её можно, а иногда необходимо, читать по ходу курса.


Подключение светодиода.


Начнём с построения вот такой схемки:


Светодиод, включённый на постоянку


Если никогда не пользовали макетку, то рекомендуется почитать (или хотяб посмотреть картинки) вот в этом руководсве. На нашей схеме мы подсоединяем светодиодик к контакту 3.3 вольта (вывод №1) и к контакту с нулевым потенциалом (за номером 14). Обратите внимание на правильность подключения светодиода. Более короткая его ножка должна быть подключена через резистор к пину 14 (нулевой потенциал, или земля (ground) по другому). После этого можно подключить малинку к питанию. Светодиод будет гореть (если всё подключено правильно). Если светодиод перевернуть, то он просто не будет гореть. Он в конце концов такой же диод, как и любые его друзья.


Если всё заработало с равномерно горящим светодиодом, то можно попробовать оным помигать. Отрубаем малинку от питания. Теперь переподключаем светодиод от пина 1 к пину 36 (GPIO 16) вот таким образом:


Схема с мигающим светодиодом


Опять вынимаем карту памяти. Копируем на неё files/gpio16-blink.bin под именем kernel8.img вместо старого с тем же именем. Ставим карточку обратно и подключаем малинку к питанию. Теперь светодиод должен безудержно мигать.


Фаза 3: Няшный Си


На этот раз мы будем писать на сях прогу, которая будет делать тоже, что и gpio16-blink.bin. Для того, чтоб иметь возможность компилировать няшную сишечку под малинку нам нужен кросс-компилятор под aarch64-none-elf.


Установка кросс-компилятора


Нам нужно установить GNU-тулчейн для под архитектуру aarch64-none-elf (компилятор gcc и его компанию вроде objcopy).


Под macOS


Для начала стоит установить менеджер пакетов homebrew. Если уже установлен, то эту часть можно пропустить.


  1. Установите инструменты Xcode для командной строки. Появится диалоговое окно. Когда появится — нажмите "Установить", "Продолжить" или что там обычно.
    xcode-select --install
  2. Запустите скрипт установки Homebrew. Оный проведет вас через остальную часть процесса установки.
    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Теперь установим тулчейн aarch64-none-elf используя homebrew.


brew tap SergioBenitez/osxct
brew install aarch64-none-elf

Проверим, всё ли правильно установлено:


$ aarch64-none-elf-gcc --version
aarch64-none-elf-gcc (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Под Linux


  1. Загрузим и распакуем aarch64-none-elf-linux-x64.tar.gz. После этого переместим arch64-none-elf в /usr/local/bin:
    wget https://web.stanford.edu/class/cs140e/files/aarch64-none-elf-linux-x64.tar.gz
    tar -xzvf aarch64-none-elf-linux-x64.tar.gz
    sudo mv aarch64-none-elf /usr/local/bin
  2. Добавим /usr/local/bin/aarch64-none-elf/bin к переменной окружения PATH. Как именно — это зависит от вашего конкретного диструбутива Linux. В большинстве случаев следует добавить в ~/.profile следующее:
    PATH="/usr/local/bin/aarch64-none-elf/bin:$PATH"
  3. Проверяем, всё ли нормально. В качетве вывода мы должны получить версию gcc и всё такое.
    aarch64-none-elf-gcc --version

Можно собрать самому из исходников, если такое желание возникнет. Подробнее вот тут.


Теперь немного о железе


Взаимодействие подавляющего большинства современных аппаратных устройств с ПО осуществляется через отображение его в память Memory-mapped I/O. Суть такова: с устройствами можно общаться так, будто это просто некая часть памяти. При этом предоставляется спецификация о том, что будет происходить при записи или чтении определённых адресов в памяти. Адреса обычно разделяются на кусочки по 32 или 64 бита, которые называют регистрами. Регистры могут быть доступны только для чтения из них, для записи или для того и другого сразу.


Как мы узнаем, какие регистры и для чего использовать, и где в памяти они находятся? Производители различных устройств пишут документацию на эти самые устройства. Обычно их зовут даташитами (data sheet), мануалами (device manual), ну или просто документацией. Нет какого либо общего широко распространённого формата для документирования устройств. Иногда документация может быть недостаточной или её может не быть вообще. Умение читать и понимать аппаратную документацию это вполне себе полезный скилл и в некотором роде даже искусство.


Интерфейс GPIO в памяти


Документацию на многие периферийные устройства, которые есть у Rasbperry Pi, можно найти в документе BCM2837 ARM Peripherals Manual. Про GPIO можно почитать на 89 странице.


Падажжи, там же местами про BCM2835, а у нас BCM2837. Это норм?

Если открыть руководство, то там можно увидеть во многих местах упоминание BCM2835. Мы просто взяли руководство к нему и исправили некоторые ошибки. Ну и заголовок поменяли на BCM2837. BCM2837 и BCM2835 имеют одинаковые периферийные устройства с теми же относительными адресами в памяти. Основное отличие в общей конфигурации физической памяти. Базовый физический адрес периферийных устройств на BCM2837 — 0x3F000000, в отличии от 0x20000000 в BCM2835. Однако оба чипа отображают эти адреса на 0x7E000000. Вкратце на BCM2837 "периферийный" адрес 0x7EXXXXXX будет находится на физическом адресе 0x3FXXXXXX. Приведённая документация изменена с учётом этого.

Для нашей задачи нам достаточно следующих регистров:


имя адрес описание размер чтение/запись
GPFSEL1 0x7E200004 GPIO Function Select 1 32 бита и то и другое
GPSET0 0x7E20001C GPIO Pin Output Set 0 32 бита только запись
GPCLR0 0x7E200028 GPIO Pin Output Clear 0 32 бита только запись

Тащемто это непосредственно скопировано прямо из документации со страницы 90.


Теперь почитайте документацию для регистра GPFSELn на страницах 91 и 92. Мы записываем в этот регистр для настройки пинов в качестве выходных или входных. Какое должно быть значение в каждом поле регистра GPFSEL1 для настройки вывода №16 GPIO, чтоб он стал выходом?


Теперь опять читаем документацию на странице 95. Про регистры GPSET0 и GPCLR0. Мы записываем в регистр GPSET0 для включения контакта. А в GPCLR0 для выключения. Какое значение нам требуется записать в эти регистры для включения/выключения вывода 16?


Написание кода


В каталоге phase3/ репы есть заготовка кода для построения двоичного файла для малинки. Пока обойдёмся без объяснения того, зачем нужны crt0.S, layout.ld и Makefile. Вместо этого сосредоточимся на blinky.c. В нём вы обнаружите, что уже указаны адреса всех трёх необходимых нам регистров в верхней части. Кроме этого там есть парочка функций, которыми можно создать временную задержку. Задача состоит в том, чтоб дополнить функцию main так, чтобы вывод №16 GPIO был настроен как выход, а затем то включался, то выключался для мигания светодиодом.


Когда код будет готов — его следует протестировать. Для начала скомпилируйте его, запустив make, находясь в директории phase3/. Если всё хорошо и нет ошибок, то создастся файлик blinky.bin. Переименовываем его в kernel8.img, копируем на microSD-карточку и запускаем это всё на малинке. Если уже есть работающий kernel8.img — можно переходить к следующей фазе.


Подсказки:

Настройка/включение/выключение пинов могут быть реализованы за одну строку кода.

Тут пригодятся операторы <<, |, & и ~.

В сишечке можно использовать шестнадцатеричную и двоичную формы. Для числа три что-то вроде 0x03 и 0b011 соответственно.

Фаза 4: Ржавчина


В этот раз мы будем писать программу, подобную gpio16-blink.bin, но уже на Rust. Код пишем в phase4/src/lib.rs.


Установка Rust и Xargo


Для того, чтоб компилять программы на Rust, нам следует этот самый компейлятор установить. Помимо этого мы установим xargo, который является обёрткой, связанной с менеджером пакетов cargo. Xargo позволяет нам компейлировать наш код для Rasbperry Pi и всего такого.


  1. Идём на https://rustup.rs/ и следуем инструкциям для установки rustup. Убедитесь, что Rust был установлен корректно, запустив rustc --version.
  2. Теперь используем rustup и cargo (который установился вместе с rustc на прошлом шаге) для установки ночной сборки Rust. Заодно и исходники стандартной библиотеки установим. И xargo разумеется.
    rustup default nightly-2018-01-09
    rustup component add rust-src
    cargo install xargo
  3. Проверяем установленные команды и убеждаемся, что версии всего этого соответствуют тому, чего мы от них хотим:
    $ rustc --version
    rustc 1.25.0-nightly (b5392f545 2018-01-08)
    $ xargo --version
    xargo 0.3.10
    cargo 0.25.0-nightly (a88fbace4 2017-12-29)

Теперь у нас есть вполне себе рабочий компилятор Rust.


Написание кода


Для написания кода в файле phase4/src/lib.rs нужно знать по крайней мере следующие конструкции:


1) Вы можете читать из и писать в то, что находится за голыми указателями (*mut T) при помощи методов read_volatile() и write_volatile(). Например у нас объявлено такое:


const A: *mut u32 = 0x12 as *mut u32;
const B: *mut u32 = 0x34 as *mut u32;

Мы можем записать 32-разрядное целое число без знака с адресом 0x12 в ячейку с адресом 0x34 примерно вот так:


B.write_volatile(A.read_volatile());

2) Локальные переменные обявляются при помощи конструкции let имя_переменной = некое_выражение;.
Можно прочитать A из предыдущего примера (т.е. значение, расположенное по адресу 0x12) в переменную вот таким образом:


let value = A.read_volatile();

3) Вызвать функцию fn f(param: usize); можно вот так: f(123);.
4) Блок loop можно использовать для бесконечного повторения чего либо:


loop {
    do_this_again_and_again();
}

5) В Rust есть следующие побитовые операторы:


  • ! — инверсия
  • << — сдвиг влево
  • >> — сдвиг вправо
  • | — битовое ИЛИ
  • & — битовый И.

Теперь вы готовы помигать светодиодом из кода на Rust. Код пишем в phase4/src/lib.rs. Переведите сишный код в аналогичный rust-код (в функции kmain). Тут уже объявлены необходимые регистры и функция "сна", которая создаёт задержку на некоторое время. Используйте это всё.


Когда будете готовы проверить свою прогу, скомпилируйте её, запустив make в каталоге phase4. Если всё нормально, то создастся файл build/blinky.bin, который переименовываем в kernel8.img и кладём на microSD-карточку, которую затем вставляем в малинку. Когда светодиодик снова замигает — можно считать, что данная часть туториала завершена.


UPD Следующая серия

Поделиться публикацией
Комментарии 55
    +1
    Годно. в мемориз
      +2
      Большое спасибо за труд!
        +4
        Столько магии: все сделал, почему работает не понятно.
          +5

          Спрашивайте, что не понятно. Это как раз тот случай, когда "глупые" вопросы только приветствуются.

            0
            Используя доку по BCM2835, возможно повторить это на Raspberry Pi Model B? На новенькой третьей не хочется экспериментировать пока.
            //Спасибо за актуальную, интересную статью.
          +3
          Надо-бы пояснить как с помощью rust & xargo собирается кросс-платформенный бинарник.
          • НЛО прилетело и опубликовало эту надпись здесь
              +2

              Основную работу делает rustc. cargo и xargo — обёртки для управления зависимостями. Конкретно xargo — временный костыль для управления кросскомпиляцией стандартной библиотеки Rust. Вполне возможно, что всё, что делает xargo будет делать cargo. По крайней мере работы по этой части ведутся.


              cargo и xargo читают свои конфигурационные файлы, строят древа зависимостей одних компонентов от других. Потом они вызывают rustc для каждого элемента этого древа в правильном порядке.


              Если добавить флаг --verbose
                 Compiling core v0.0.0 (file:///home/lain/.rustup/toolchains/nightly-2018-01-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore)
                   Running `rustc --crate-name core /home/lain/.rustup/toolchains/nightly-2018-01-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/lib.rs --crate-type lib --emit=dep-info,link -C opt-level=3 -C panic=abort -C debuginfo=2 -C metadata=a801d90a8ede2cec -C extra-filename=-a801d90a8ede2cec --out-dir /tmp/xargo.QYpehsg9dGcf/target/aarch64-elf/release/deps --target aarch64-elf -L dependency=/tmp/xargo.QYpehsg9dGcf/target/aarch64-elf/release/deps -L dependency=/tmp/xargo.QYpehsg9dGcf/target/release/deps --sysroot /home/lain/.xargo -Z force-unstable-if-unmarked`
                  Finished release [optimized + debuginfo] target(s) in 33.14 secs
              + RUSTFLAGS="--sysroot /home/lain/.xargo -Z force-unstable-if-unmarked"
              + "cargo" "build" "--release" "--manifest-path" "/tmp/xargo.DNOId6dEQEQf/Cargo.toml" "--target" "aarch64-elf" "-v" "-p" "compiler_builtins"
                 Compiling compiler_builtins v0.1.0 (file:///home/lain/.rustup/toolchains/nightly-2018-01-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcompiler_builtins)
                   Running `rustc --crate-name build_script_build /home/lain/.rustup/toolchains/nightly-2018-01-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcompiler_builtins/build.rs --crate-type bin --emit=dep-info,link -C opt-level=3 -C debuginfo=2 --cfg 'feature="compiler-builtins"' --cfg 'feature="default"' -C metadata=52e30c5973f6dcea -C extra-filename=-52e30c5973f6dcea --out-dir /tmp/xargo.DNOId6dEQEQf/target/release/build/compiler_builtins-52e30c5973f6dcea -L dependency=/tmp/xargo.DNOId6dEQEQf/target/release/deps`
                   Running `/tmp/xargo.DNOId6dEQEQf/target/release/build/compiler_builtins-52e30c5973f6dcea/build-script-build`
                   Running `rustc --crate-name compiler_builtins /home/lain/.rustup/toolchains/nightly-2018-01-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcompiler_builtins/src/lib.rs --crate-type lib --emit=dep-info,link -C opt-level=3 -C panic=abort -C debuginfo=2 --cfg 'feature="compiler-builtins"' --cfg 'feature="default"' -C metadata=bb86bee2bebfce0f -C extra-filename=-bb86bee2bebfce0f --out-dir /tmp/xargo.DNOId6dEQEQf/target/aarch64-elf/release/deps --target aarch64-elf -L dependency=/tmp/xargo.DNOId6dEQEQf/target/aarch64-elf/release/deps -L dependency=/tmp/xargo.DNOId6dEQEQf/target/release/deps --sysroot /home/lain/.xargo -Z force-unstable-if-unmarked`
                  Finished release [optimized + debuginfo] target(s) in 10.7 secs
              + RUSTFLAGS="--sysroot /home/lain/.xargo"
              + "cargo" "build" "--verbose" "--release" "--target=aarch64-elf"
                 Compiling blinky v0.1.0 (file:///home/lain/WORK/0-blinky/phase4)
                   Running `rustc --crate-name build_script_build build.rs --crate-type bin --emit=dep-info,link -C opt-level=3 -C debuginfo=2 -C metadata=38baa0b289c5375d -C extra-filename=-38baa0b289c5375d --out-dir /home/lain/WORK/0-blinky/phase4/target/release/build/blinky-38baa0b289c5375d -L dependency=/home/lain/WORK/0-blinky/phase4/target/release/deps`
                 Compiling rlibc v1.0.0
                   Running `rustc --crate-name rlibc /home/lain/.cargo/registry/src/github.com-1ecc6299db9ec823/rlibc-1.0.0/src/lib.rs --crate-type lib --emit=dep-info,link -C opt-level=3 -C panic=abort -C debuginfo=2 -C metadata=87e53cf10f387acb -C extra-filename=-87e53cf10f387acb --out-dir /home/lain/WORK/0-blinky/phase4/target/aarch64-elf/release/deps --target aarch64-elf -L dependency=/home/lain/WORK/0-blinky/phase4/target/aarch64-elf/release/deps -L dependency=/home/lain/WORK/0-blinky/phase4/target/release/deps --cap-lints allow --sysroot /home/lain/.xargo`
                   Running `/home/lain/WORK/0-blinky/phase4/target/release/build/blinky-38baa0b289c5375d/build-script-build`
                   Running `rustc --crate-name blinky src/lib.rs --crate-type staticlib --emit=dep-info,link -C opt-level=3 -C panic=abort -C lto -C debuginfo=2 -C metadata=5fdf374864fe84b4 -C extra-filename=-5fdf374864fe84b4 --out-dir /home/lain/WORK/0-blinky/phase4/target/aarch64-elf/release/deps --target aarch64-elf -L dependency=/home/lain/WORK/0-blinky/phase4/target/aarch64-elf/release/deps -L dependency=/home/lain/WORK/0-blinky/phase4/target/release/deps --extern rlibc=/home/lain/WORK/0-blinky/phase4/target/aarch64-elf/release/deps/librlibc-87e53cf10f387acb.rlib --sysroot /home/lain/.xargo`
                  Finished release [optimized + debuginfo] target(s) in 3.31 secs

              Можно заметить, что опции из Cargo.toml передаются ключами в rustc.


              Немного о внутренностях rustc можно почитать например это https://rust-lang-nursery.github.io/rustc-guide/


              rustc в свою очередь берёт исходные файлы и преобразует их в тот вид, который его попросят. В нашем случае нам требуется статический файлик target/aarch64-elf/release/libblinky.a. В нём содержится бинарный код и некоторая информация о том, как его можно будет потом использовать.


              А использовать мы его будем самым гнустным образом. При помощи линкёра мы стыкуем его с crt0.o (который получился из crt0.S) и получаем build/blinky.elf. Этого эльфа мы преобразуем в тот, формат, который будет потом читать загрузчик (по сути просто отрежем все заголовки elf-файла)


              Я не всё детально расписал конечно, но самое основное.

            • НЛО прилетело и опубликовало эту надпись здесь
                +11

                Целиком и полностью согласен с вами. После того, как кто-то придумал фортран, ничего более годного человечеством придумано не было. Лисп не в счёт, он для любителей смайликов.

                +1
                Это называется по-другому: лабораторные или практические работы…
                  0
                  Большое вам спасибо!
                    0

                    Минуточку, если билдится blinky.elf, то кто со стороны малинки этот самый ELF парсит и грузит? Программировать под существующее линуксовое ядро — это не совсем "с нуля".

                      0
                      А кто тут elf собирает? Я вижу bin, который загружают bootcode.bin, config.txt и start.elf.
                        0

                        blinky.elf: $(BLINKY_OBJS) layout.ld
                        $(CROSS)-ld $(BLINKY_OBJS) -o $@ -Tlayout.ld


                        И crt0.S, который неявно подлинковывается к этому elf-у, как бы говорит нам о том, что это все будет запущено на малинке. Кто это там запускает?

                          +3

                          Загрузчик. Точнее их целых два. bootcode.bin и start.elf.
                          В следующей части мы свой загрузчик напишем. Наш загрузчик будет подгружать ядро по UART.


                          А кто подгружает наши загрузчики? Хороший вопрос. Этим занимается прошивка, до которой нам будет сложновато добраться (там закрыто и опечатано всё). По сути эта прошивка занимается примерно тем же, чем такая же штука в ардуинке — даёт нам возможность не использовать всякую тяжелую обвязку с программаторами и прочим.


                          Тут стоит немного упомянуть о том, что предоставляет нам процессор по части защиты одних частей от других.



                          Взято отсюда


                          Есть обычный мир и защищённый мир. В рамках курса мы будем воплощать наши хитрые планы в обычном мире.


                          Код, который мы выполняем по ходу курса будет выполняться на уровне Гипервизора. Чуть позже будет рассказано, как перемещаться с EL2 до EL1 и до EL0. И обратно. Понадобится нам это не раньше, чем будем работать с программами/потоками/процессами. Хотя может я напишу что-то про ассемблер и вот такое всё, применительно к этой архитектуре. Я не буду ограничиваться просто переводом оригинального курса. Иначе это было бы слишком скучно. (Тут стоит заметить, что я сам всё это потихоньку изучаю).

                            0

                            Выполнять свой код на EL3 возможно или все так же анально огорожено, как у Интела?

                      +1

                      Неясен смысл установки nightly-версии Rust. Что такого в ней появилось, чего ещё нет в stable? Не помешала бы об этом пара слов. Поскольку ночные сборки у каждого (скорее всего) будут свои, то не мешало бы понимать, для чего они вообще (может, скоро необходимые возможности в stable переберутся и ночные сборки станут не нужны).


                      Аналогичный вопрос про xargo. Зачем он нужен? Можно ли всё сделать силами одного лишь cargo или это невозможно и xargo делает некую магию? Это тоже хотелось бы понимать.

                        0

                        Нам нужно компилировать стандартные библиотеки, а не использовать свои готовые. Их можно скомпилировать только ночной сборкой компилятора.

                          0

                          Почему готовые нельзя использовать? Rasperry Pi недостаточно популярная архитектура и под неё нет готовых собранных пакетов или причина в чём-то другом?

                            +1

                            Проще предоставить возможность скомпилировать это всё для страждущих, чем предоставить хотелки на каждый чих. Кроме того можно собственную модифицированную версию туда влепить. Скажем использовать штуки из стандартной библиотеки (из std::io например) там, где у нас не заработают другие части (например std::net). Мы можем просто скопировать код стандартной библиотеки и вырезать то, что работать не будет.


                            Собственно основное назначение стандартной библиотеки — взаимодействие с операционной системой.


                            Помимо стандартной библиотеки там есть чуть более мелкие библиотеки вроде core и прочих. Зачем нам может понадобиться их компилять? Мы можем использовать разные опции компилятора для наших нужд. Например нужно ли нам использовать SIMD (на арме это NEON) или нинужно. Или ещё что-то. На все комбинации всех опций бинарники не предоставишь (технически можно, но ненужно ибо их будет очень много).


                            Собственно это всё есть в готовом виде для самых самых распространённых платформ. Под платформой будет подразумеваться Target Triplet. Т.е. сочетание процессора/окружения/операционной системы/чего там ещё. В нашем конкретном случае это что-то вроде aarch64-none-elf или что-то похожее. Т.е. проц с архитектурой aarch64, отсутствие ОСи и немного сочного мяса эльфов.

                        –3
                        «без GC» — что ?)))))))))))))
                        0
                        Да и к этому нужно упорно приложить руку тогда и все работает…
                          0
                          А какими учебными материалами лучше эти лабораторные работы сопроводить для человека, у которого тот самый уровень 0?
                            0

                            Если касательно программирования, то начинать стоит с книжечки по Rust. На русском последняя версия всё ещё не опубликована, но можно потыкать прямо вот тут: https://github.com/ruRust/rust_book_2ed/tree/ru_version/second-edition/src


                            По линуксу и вообще командной стоке можно много чего почитать. https://ryanstutorials.net/linuxtutorial/ https://ru.hexlet.io/courses/bash в качестве первых попавшихся примеров. Даже списком https://proglib.io/p/10-linux-resources/ Гугл по запросу "linux туториал" выдаст достаточно интересного на любой вкус. В том числе и в виде видях на ютубчике.


                            А так — спрашивайте конкретные вопросы. Каждый подразумевает под нулевым уровнем что-то своё.

                              0
                              В моем понимании (применительно ко мне), нулевой уровень — отсутствие опыта работы с компилируемыми языками, за исключением ВУЗовской начальной программы по C. Отсутствие опыта работы с электроникой, схемами, понимания их устройства. Мизерные навыки работы с командной строкой. Почти полное отсутствие представлений об устройстве операционной системы.
                              Язык проблем не представляет при этом, могу изучать английские материалы.
                                0
                                отсутствие опыта работы с компилируемыми языками, за исключением ВУЗовской начальной программы по C.

                                И этого опыта должно быть в целом достаточно. Предполагается, что Rust изучается по ходу курса.


                                Отсутствие опыта работы с электроникой, схемами, понимания их устройства.

                                В рамках этого курса достаточно самых самых минимальных знаний. По железной части кроме светодиодиков чего-то особого не будет (как работает UART, будет объяснено). Если есть желание фундаментально углубиться в эту тему, то есть лютейшая годнота под названием The Art of Electronics. Раз нет проблем с изучением англоязычных материалов — берите третье издание на английском (на русском совершенно другая нумерация и 3, 4, 5 и т.д. будут относится ко второму изданию на самом деле).


                                Почти полное отсутствие представлений об устройстве операционной системы.

                                В рамках курса исправим. С точки зрения практики, а не теории. После некоторой практики в рамках курса теорию будет гораздо интереснее и понятнее изучать кстати. Из самого близкого к оригиналу есть лекции https://web.stanford.edu/~ouster/cgi-bin/cs140-spring14/lectures.php которые в свою очередь рекомендуют читать книжечку Operating Systems: Principles and Practice.

                            –1

                            У меня приятель в школьные годы на ASM трехзадачную ОС написал… вот это даже "-3" этаж.

                              +4

                              Продолжая аналогию, цель курса не в умении работать лопатой ниже уровня моря, а в умении построить дом от подвала до верхнего этажа. И да, мы будем пользоваться лифтом.

                                –1

                                Меня никогда не тянуло на низкоуровневый кодинг. Что до лифта, то "с нуля" надо в кавычках тогда писать, с "нуля".

                                  0
                                  Только это больше похоже не на «Операционные системы с нуля», а «Спортивный ардуининг на Малинке-3 с нуля». Или в плане программы курса предусмотрено демонстрационное простейшее ядро с планировщиком, где каждый отдельный процесс моргает собственным светодиодом?

                                  У меня есть такое ИМХО, что для обучения студентов или увлечённых старшешкольников основам ОС в настоящее время требуется не только демонстрационная-учебная ОС типа «Minix» и подобных, но и учебное «железо» с минимальным набором устройств и интерфейсов (в пределах разумного). Потому что для учёбы даже нынешние одноплатники уже слишком сложны и перегружены всякими расширениями. Минимальным джентельменским набором я считаю такой список: SPI, SDIO, 2xUART, 2xUSB (можно только хост), GPIO (физически отдельно от обоих UART), JTAG. Вместо SPI Flash с u-boot — слот под microSD-карту. SDIO — на слот под полноразмерную SD. И дисплей 800x480 на борту, также работающий по SPI.
                                    0
                                    Или в плане программы курса предусмотрено демонстрационное простейшее ядро с планировщиком, где каждый отдельный процесс моргает собственным светодиодом?

                                    Предусмотрено. Правда ближе к концу оригинального курса. Не хочется сразу пугать размером мануала на ARMv8.


                                    Про фреймбуфер (и ускорение видео!) и usb я попробую отдельно рассказать. Может быть и про SDIO, но мне бы самому во всём этом разобраться. Про отдельный экранчик тоже расскажу, когда руки дойдут.

                                      0
                                      Если кто-то заинтересовался такой вещью как написание своей ОС, то предполагается, что с ассемблером он(а) уже достаточно хорошо знаком(а), и этот мануал уже как минимум прочитан «по диагонали». А вообще, перед тем, как программировать драйверы шин и прочие бэкенды, надо бы сделать акцент на базовых деталях — взаимодействие ядра и планировщика, что такое системные вызовы и для чего нужны, какие примитивы реализует libc, взаимодействие процесса пользователя с планировщиком и ядром, запуск и завершение процесса.
                                        0

                                        Суть такова:


                                        Уровень 0: Hello World
                                        Уровень 1: Uart, чуть более удобный бутлоадер
                                        Уровень 2: Работа с памятью и немного с файловой системой
                                        Уровень 3: Асм и процессы


                                        При этом на уровне 0 предполагается, что человек уже умеет на чём-то прогать из Си-подобного и в состоянии установить линупс при помощи гугла. Всё остальное явно или неявно познаётся в процессе.


                                        После основного курса можно будет пилить различные дополнения. Благо периферии там много разной.

                                0
                                Классный курс, спасибо за информацию.
                                  0
                                  Статья очень понравилась, и суть и изложение, спасибо.
                                  Вообще лихо они запитали RPi 3 от USB компа по ардуиновски. По спеку USB 500mA, малина
                                  Boot Max 0.75A
                                  Idle Avg 0.30A
                                  хотя если периферия не подключена то может и потянуть.
                                  Ну и соответственно внешнего блока питания подключать ка малине не надо если делать как описано, а если подключать, то тогда не подключать +5V с CP2102 — питание все же должно быть одно по правилам. Хотя… малинщики сами признают что бывает poweer backfeed из активных USV хабов и не всегда все сгорает.

                                    0
                                    Статья класс! А клоны малины пойдут для этого дела? И где их лучше заказывать по вашему опыту?
                                      0
                                      А клоны малины пойдут для этого дела?

                                      Там обязателен проц BCM2837. Соответственно это должен быть точный клон определённой версии малинки. Что на али, что на амазоне — малинка стоит примерно $38 (около 2200 рублей). Не то, чтоб дорого с учётом бесплатной доставки. Лично я с амазона заказал. Дополнительные плюшки мне вдвое дороже вышли, лол.

                                        0
                                        Спасибо! Какие дополнительные плюшки?
                                          0
                                          Набор компонентов в няшной удобной коробочке плюс экранчик

                                            0
                                            Спасибо! А как его искать напишите пожалуйста, посмотрю что он из себя представляет
                                              0

                                              Кого? Набор? electronics kit raspberry pi в поиске по магазину. Выбрать можно по вкусу. Светодиоды и резисторы есть практически в любом. Удобные коробочки может и не во всех есть, но там по фотографиям будет понятно. У меня конкретно этот, но я таки рекомендую повыбирать что-то самостоятельно.

                                                0
                                                Да, спасибо, выбирать конечно буду сам
                                        0
                                        В принципе, stage4 я собрал под Orange PI PC (код мигания светодиодами из stage4/src/lib.rs пришлось переписать полностью, т.к. другая SoC). Имею ввиду, что код rust без особых проблем можно скомпилировать и под orange pi. Другое дело, что архитектурно-зависимый код курса придется переписывать под свою платформу.

                                        Если кому-то интересно, могу описать процесс сборки.
                                          0
                                          Другое дело, что архитектурно-зависимый код курса придется переписывать под свою платформу.

                                          Собственно это решает. В уровне 3 это будет на столько критично, что чуть ли не с нуля придётся переписывать. Асм-часть точно будет другой.

                                      0

                                      [quote]Затем вставляем карточку в малинку и подключаем малинку к питанию. [/quote]
                                      Наверное, стоило бы отметить, что подключаем питание желательно не к usb компьютера, а так же подключаем usb-uart конвертор в usb?

                                        0
                                        А в чём прикол изучения именно на основе ARM и Raspberri Pi? Проще архитектура?
                                        Серьёзные настольные ОС пишутся под несколько другие архитектуры. Потом, не очень понятен упор на аппаратную часть:
                                        В уровне 3 это будет на столько критично, что чуть ли не с нуля придётся переписывать. Асм-часть точно будет другой.

                                        Разве в ОС главное не общие принципы (планировщик, файловая система, всё что выше вы писали)? Эти вещи вроде обычно на C реализуют, а не на ассемблере.
                                        Если суть использования Малины в том, что это единственное железо, с которым реально поэкспериментировать руками каждому — тогда у меня вопрос, почему под Intel x86/x64 таких штук не выпускают.
                                          +1
                                          Серьёзные настольные ОС пишутся под несколько другие архитектуры.

                                          Есть мнение, что таких архитектур примерно три. У нас одна из них. ARM — это по меньшей мере все современные смартфоны. И я не знаю, считаете ли вы Android (например) серьёзной операционной системой. Есть правда забавная деталь. ARMv8 (с нашим AArch64 в нашем проце) вышел в 2011 году, а первый чип в 2012. По меркам популярных архитектур это совсем недавно. Буквально утром за завтраком было.


                                          Проще архитектура?

                                          Сложность amd64 и этого всего в большом количестве легаси (см. x86). У арма сложность не в нём самом (не то, чтоб там было всё совсем просто), а в том, что с периферией от чипа к чипу та же беда, что и в вебе с фреймворками. Это если обобщать.


                                          Разве в ОС главное не общие принципы (планировщик, файловая система, всё что выше вы писали)? Эти вещи вроде обычно на C реализуют, а не на ассемблере.

                                          Есть буквально парочка штук, которые можно реализовать ТОЛЬКО на ассемблере. 150-200 строк на асме это немного (примерно такой размер для третьей части у init.S). Но достаточно для того, чтоб об этом стоило бы поговорить. Если уж мы вскрываем эту тему, то стоит углубиться дальше, чем комментирование этого самого init.S. Кроме того есть ещё парочка штук, которые без знания грязных подробностей работы современных процессоров сложновато объяснить.


                                          тогда у меня вопрос, почему под Intel x86/x64 таких штук не выпускают

                                          Выпускают. У вас на столе лежит одна такая. Можете попробовать. Благо инфы на эту тему огромное количество. Даже на русском языке. Если хочется прям всенепременно одноплатник, то что-то вроде есть в этом маленьком списке. Буквально десяток таких платок или около того.


                                          А вообще может вам немного не совсем понятна цель курса? Цель стоит не научиться взаимодействовать с существующими ОС (через понимание их устройства), а именно то самое. Драйвера допустим писать. Может быть под чуть более экзотическую архитектуру что-то настрочить.


                                          Это спойлер

                                          Одна такая экзотическая примочка поставляется вместе с малинкой. Про это будет в моём сочинении на тему "как я провёл лето".


                                          Только я этого не говорил. Сообщаю это исключительно на случай ежели лето будет достаточно тёплым для сочетания гавайской рубашки и характерного головного убора в красно-белых тонах. Мне самому ещё предстоит разобраться в этом.


                                          Курс одной ногой в OSdev, а другой в embedded. Утрируя: чуть влево — Таненбаум с косой стоит, чуть в право — Свидетели Arduino с мигающими светодиодами вместо глаз. По центру камень. Гранитный. Можно погрызть чуток. Или лизнуть хотяб.

                                            0
                                            И я не знаю, считаете ли вы Android (например) серьёзной операционной системой.

                                            Серьёзной, да, настольной — сорри, но нет (моё мнение).

                                            Сложность amd64 и этого всего в большом количестве легаси (см. x86)

                                            Что плохого в легаси? В том, что его много, и долго про него писать?

                                            Кроме того есть ещё парочка штук, которые без знания грязных подробностей работы современных процессоров сложновато объяснить.

                                            Я не против знать «грязные» подробности работы процов, это интересно и полезно. Но изучать весь ASM во всём объёме, да ещё и с практикой? Это тяжко слегка) Или там и не будет такого?

                                            У вас на столе лежит одна такая.

                                            Вы сейчас про что? Про клаву с её прошивкой?)

                                            … а именно то самое. Драйвера допустим писать. Может быть под чуть более экзотическую архитектуру что-то настрочить.


                                            Так мелко? :D Я-то думал, написать свою ОС. Шутка. А если серьёзно — то иметь для работы над такой ОС хотя бы начальную теоретическую базу (и кстати да, несколько неплохих примеров систем, созданных небольшими коллективами, есть на слуху, одна даже чуть ли не на модифицированном NT ядре сделана).
                                              0
                                              Серьёзной, да, настольной — сорри, но нет (моё мнение).

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


                                              Что плохого в легаси? В том, что его много, и долго про него писать?

                                              Там дофига всяких неприятных штук вроде странных режимов работы процессора. Проблема в том, что эти режимы реально приходится использовать. Например если нам нужна графика.


                                              Да и набор команд выглядит достаточно непродуманным. Это же просто наслоение костылей из разных эпох. Я не говорю, что это прям плохо. Но рассказывать про это будет гораздо дольше.


                                              Но изучать весь ASM во всём объёме, да ещё и с практикой?

                                              А в чём проблема? Там нет многотонного легаси. Оно спроектировано достаточно лёгким и понятным. Там будет всё, что можно назвать основами. Т.е. все основные команды над основными регистрами. Чуточку специальных штук. Ну и прерывания. Т.к. это RISC — основных команд там не то, чтоб много. Можно даже запомнить их. В отличии от.


                                              Вы сейчас про что? Про клаву с её прошивкой?)

                                              Про ту коробочку, которая PC. Вполне себе коробочка с процем, поддерживающем amd64.


                                              А если серьёзно — то иметь для работы над такой ОС хотя бы начальную теоретическую базу

                                              А как на счёт познавания этой самой базы в процессе или после этого всего, но по горячим следам? Всмысле сначала разбираемся с минимумом. Ну чтоб работало. А потом нам приходит светлая мысль: а как это можно улучшить, чем дополнить и т.д.?


                                              и кстати да, несколько неплохих примеров систем, созданных небольшими коллективами, есть на слуху, одна даже чуть ли не на модифицированном NT ядре сделана

                                              Не знаю такой. Если вы про ReactOS, то никакого отношения к NT она не имеет. Там полностью свободное ядро. Алсо этот проект не является хорошим годным примером, как проектировать ОС с нуля во имя учебных целей. Там задачи немного другие.

                                                0
                                                Если вы про ReactOS, то никакого отношения к NT она не имеет. Там полностью свободное ядро.

                                                Ядро свободное, но клон NT, так что называть его не имеющим отношения весьма странно.
                                                Я тоже не совсем понял, о чём писал предыдущий оратор, но парочка студенческих проектов на основе ядра WRK вполне существует. Правда проектов, зашедших дальше замены алгоритма деревьев на RB-Tree в дальнем уголке ядра от наших китайских друзей, я не встречал.
                                                  0
                                                  Если вы про ReactOS, то никакого отношения к NT она не имеет. Там полностью свободное ядро.

                                                  Ну я где-то читал, что там до кучи от NT 5.x, если ничего не путаю. Или реализовано по мотивам (код того ядра уже открыт), или прямо взято оттуда. А какие там задачи?

                                                  Вполне себе коробочка с процем, поддерживающем amd64.

                                                  amd64 — это то же самое, что x64? Сорри за глупый вопрос.
                                                  И если про PC — то не на столе, а под столом, у меня не ноут :)

                                                  А в чём проблема? Там нет многотонного легаси. Оно спроектировано достаточно лёгким и понятным.

                                                  Стоп, я начинаю путаться. Значит, про странные режимы работы и костыли рассказывать долго, а про ASM — быстро? Но ведь ASM — это те же машинные коды, только в буквенном, человекочитаемом виде. Смысл операций (во всяком случае простых) там совершенно аналогичен. И мне ассемблер простым не кажется… Пытался уже изучать немного, когда надо было в IDA Pro с отладкой одной софтины возиться :)
                                                    +1
                                                    Ну я где-то читал, что там до кучи от NT 5.x, если ничего не путаю.

                                                    Только идеи и интерфейсы.
                                                    Или реализовано по мотивам (код того ядра уже открыт), или прямо взято оттуда.

                                                    Не взято ни строчки. Ну или по крайней мере уличить их в краже нельзя.
                                                    Код ядра не открыт, там такая лицензия, что разработчикам ReactOS дышать в их сторону нельзя.
                                                    amd64 — это то же самое, что x64? Сорри за глупый вопрос.

                                                    Естественно. Спасибо AMD за ещё один слой костылей поверх x86.
                                                      0
                                                      Ну я где-то читал, что там до кучи от NT 5.x, если ничего не путаю.

                                                      Нет. Это полностью свободное ядро. Оно скорее по мотивам. Точнее даже по слухам. Но точно не на основе. Там нет и не может быть несвободного кода.


                                                      amd64 — это то же самое, что x64?

                                                      Абсолютно то же самое. Его ещё x86_64 называют. И все эти названия взаимозаменяемые.


                                                      Значит, про странные режимы работы и костыли рассказывать долго, а про ASM — быстро?

                                                      В рамках курса нам достаточно подмножества асма. Количество команд, сравнимое с количеством пальцев. Этих команд нам уже будет достаточно для понимания сути этого всего. Доступ к памяти, простая арифметика, перемещение данных в регистры (mov) и ветвление. Всё остальное — суть вариации над этим (и парочка спец-команд для сильного колдунства, которые будут объяснены тогда, когда реально потребуются). Если эти концепции усвоить, то остальные команды можно изучить самостоятельно (по мере потребности в них). Там документация такая, что по ней можно свой процессор собрать (точнее ей действительно так пользуются). В плане структурированности — настоящее гикпорно.

                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                            Самое читаемое