commit 6b6a9b6f372bb83e8dee9a0b688c5f545ea4c0f1 from: Aleksey Ryndin date: Tue Sep 12 11:15:30 2023 UTC Move to gemini://any-key.press/squat/reports/0.0.1.gmi commit - 730f64c68a1b81e1ef81f6f87362e64e60ddefc9 commit + 6b6a9b6f372bb83e8dee9a0b688c5f545ea4c0f1 blob - fb90d1c31e85e2279c21f1997b0773837c0030e3 (mode 644) blob + /dev/null --- reports/20230302-v0.0.1.md +++ /dev/null @@ -1,159 +0,0 @@ -squⱯt v0.0.1 -============ - -С++11 код, запускаемый на aarch64 железе. - -Структура проекта ------------------ - -Код проекта расположен в следующих исходных файлах: -* `boot.S`: стартовый (загрузочный) код в виде ассемблерного листинга. - Код загоняет в бесконечный цикл все процессоры, кроме _первого_ (используя - для идентификации регистр [MPIDR\_EL1][s0]). А на первом - процессоре обнуляет секцию `BSS`, настраивает стек на адрес точки входа и - отдает управление в C++ функцию `kernel_entry_point`. Стек по мере наполнения - растет в сторону уменьшения адреса, поэтому стартовые код (точки входа) не - перетирается. -* `kernel.cc`: модуль _условного ядра_. - Вызывает необходимую инициализацию (на текущий момент это только UART) и - передает управление коду полезной нагрузки (на текущий момент это - `UART echo test mode`: получение из UART символов и их обратная отсылка). -* `uart_virt.cc`: реализация работы UART([PL011][s1]) для платформы [virt в QEMU][s2]. -* `linker.ld`: описание геометрии секций для компоновщика. - -Проект собирается и запускается с использованием простого `Makefile`. - -[s0]: https://developer.arm.com/documentation/ddi0595/2021-12/AArch64-Registers/MPIDR-EL1--Multiprocessor-Affinity-Register "MPIDR_EL1, Multiprocessor Affinity Register" -[s1]: https://developer.arm.com/documentation/ddi0183 "PrimeCell UART (PL011) Technical Reference Manual" -[s2]: https://qemu.readthedocs.io/en/latest/system/arm/virt.html "QEMU: ‘virt’ generic virtual platform" - - -Конфигурирование сборки ------------------------ - -Для сборки используются утилиты из состава [LLVM][c0]. -Для учета локальных особенностей системы, где происходит сборка, используется файл `config.mk`. - -Сборка и запуск протестированы в двух arm64-конфигурациях: -* Alpine Linux v3.17 - Из особенностей тут только то, что используется утилита `objcopy` из пакета - `llvm14`. -``` -$ cat config.mk -OBJCOPY = llvm14-objcopy -``` - -* OpenBSD 7.2 - Локальный конфиг нужен для явного использования инструментария LLVM из - пакетов, так как встроенный в базу не умеет кросс-компилировать. -``` -$ cat config.mk -AS = /usr/local/bin/clang -CXX = /usr/local/bin/clang++ -LD = /usr/local/bin/ld.lld -OBJCOPY = /usr/local/bin/llvm-objcopy -``` - -Сборка (команда `make`) последовательно вызовет следующие утилиты: -* `${AC}` (по умолчанию `clang`): обработка ассемблерного файла (`.S`) для - получения объектного (`.o`). -* `${CXX}` (по умолчанию `clang++`): обработка C++ файлов (`.cc`) для получения - объектных (`.o`). -* `${LD}` (по умолчанию `ld.lld`): компоновка исполняемого (`.elf`) файла из - полученных на предыдущих шагах объектных файлов. -* `${OBJCOPY}` (по умолчанию `llvm-objcopy`): дамп исполняемого файла в - _плоское_ представление, как если бы этот файл был загружен в память на - исполнение. Результатом получает `.img` файл. - -[c0]: https://llvm.org/ "The LLVM Compiler Infrastructure" - -Просмотр содержимого собранных бинарных файлов ----------------------------------------------- - -Утилиту `llvm-objdump` можно использовать для инспектирования содержимого -получившегося `.elf` файла: -``` -$ llvm-objdump -d squat.elf -squat.elf: file format elf64-littleaarch64 - -Disassembly of section .text.boot: - -0000000000000000 <_start>: - 0: a0 00 38 d5 mrs x0, MPIDR_EL1 - 4: 00 5c 40 92 and x0, x0, #0xffffff - 8: 60 00 00 b4 cbz x0, 0x14 <_first_processor> - -000000000000000c <_idle>: - c: 5f 20 03 d5 wfe - 10: ff ff ff 17 b 0xc <_idle> - -0000000000000014 <_first_processor>: - 14: 60 14 00 10 adr x0, #652 - 18: 41 14 00 10 adr x1, #648 - -000000000000001c <_zero_bss>: - 1c: 1f 84 00 f8 str xzr, [x0], #8 - 20: 1f 00 01 eb cmp x0, x1 - 24: cb ff ff 54 b.lt 0x1c <_zero_bss> - 28: c0 fe ff 10 adr x0, #-40 - 2c: 1f 00 00 91 mov sp, x0 - 30: 02 00 00 94 bl 0x38 - 34: f6 ff ff 17 b 0xc <_idle> - -Disassembly of section .text: - -0000000000000038 : - 38: fd 7b bf a9 stp x29, x30, [sp, #-16]! - 3c: fd 03 00 91 mov x29, sp - 40: 25 00 00 94 bl 0xd4 <_ZN5Board4Uart10initializeEv> - 44: 1f 20 03 d5 nop - 48: a0 10 00 10 adr x0, #532 - 4c: 04 00 00 94 bl 0x5c <_ZN12_GLOBAL__N_116uart_send_stringEPKc> - 50: 18 00 00 94 bl 0xb0 <_ZN12_GLOBAL__N_119uart_echo_test_modeEv> - 54: fd 7b c1 a8 ldp x29, x30, [sp], #16 - 58: c0 03 5f d6 ret -``` -Тут стоит запомнить, что первая инструкция, которая ожидается к исполнению -`mrs x0, MPIDR_EL1` имеет байт код `a0 00 38 d5`. - -А результирующий _плоский_ `.img` файл можно смотреть с использованием -классического `hexdump`: -``` -$ hexdump -C squat.img -00000000 a0 00 38 d5 00 5c 40 92 60 00 00 b4 5f 20 03 d5 |..8..\@.`..._ ..| -00000010 ff ff ff 17 60 14 00 10 41 14 00 10 1f 84 00 f8 |....`...A.......| -00000020 1f 00 01 eb cb ff ff 54 c0 fe ff 10 1f 00 00 91 |.......T........| -00000030 02 00 00 94 f6 ff ff 17 fd 7b bf a9 fd 03 00 91 |.........{......| -``` -Тут стоит снова заметить, что в начале дампа мы снова видим заветный байт код -`a0 00 38 d5`, то есть нашу инструкцию `mrs x0, MPIDR_EL1`. Это минимальный -признак того, что сборка прошла успешно. - -Запуск и текущая полезная нагрузка ----------------------------------- - -_Пощупать_ текущую полезную нагрузку можно выполнив команду `make qemu`: -``` -$ make qemu -qemu-system-aarch64 -M virt -cpu cortex-a53 -kernel squat.img -nographic -monitor none -serial stdio -Squat entry point -UART echo test mode -> -``` - -В таком режиме код ждет получения очередного символа через UART, а затем -отсылает его же обратно. - - -Запуск под отладкой -------------------- - -При необходимости можно запустить QEMU в режиме отладки командой -`make gdb-remote`. В отличии от обычного запуска (`make qemu`) при запуске qemu -добавляются аргументы `-s -S`, которые включают отладку и ждут подключения -отладчика. В нашем случае отладчиком будем выступать `lldb`, который локально -подключится к QEMU через порт `1234`: -``` -$ lldb -(lldb) gdb-remote 1234 -```