commit 0241a7fc9bbeab66b38dd65de218e221b91d7b28 from: Aleksey Ryndin date: Fri Mar 03 15:08:31 2023 UTC Report v0.0.1^ initial commit (incomplete) commit - 9472018638dac9837b3f82455425865d2f163729 commit + 0241a7fc9bbeab66b38dd65de218e221b91d7b28 blob - /dev/null blob + adbbd86e4d5b64c9799faab2bba7153ece053b19 (mode 644) --- /dev/null +++ reports/20230302-v0.0.1.md @@ -0,0 +1,141 @@ +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. +Для учета локальных особенностей системы, где происходит сборка, используется файл `config.mk`. + +Сборка и запуск протестированы в двух arm64-конфигурациях: +* Alpine Linux v3.17 + Из особенностей тут только то, что используется утилита `objcopy` из пакета + `llvm14`. +``` +$ cat config.mk +OBJCOPY = llvm14-objcopy +``` + +* OpenBSD 7.2 + Локальный конфиг нужен для явного использования инструментария LLVM из + пакетов, так как встроенный в базу не умеет кросс-компилировать. +``` +$ cat config.mk +(!) TBD +``` + +Сборка (команда `make`) последовательно вызовет следующие утилиты: +* `${AC}` (по умолчанию `clang`): обработка ассемблерного файла (`.S`) для + получения объектного (`.o`). +* `${CXX}` (по умолчанию `clang++`): обработка C++ файлов (`.cc`) для получения + объектных (`.o`). +* `${LD}` (по умолчанию `ld.lld`): компоновка исполняемого (`.elf`) файла из + полученных на предыдущих шагах объектных файлов. +* `${OBJCOPY}` (по умолчанию `llvm-objcopy`): дамп исполняемого файла в + _плоское_ представление его в памяти, как если бы этот файл был загружен на + исполнение. Результатом получает `.img` файл. + + +Просмотр содержимого собранных бинарных файлов +---------------------------------------------- + +Утилиту `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` + +UART Echo test + + +Запуск под отладкой +------------------- + +`make gdb-remote` + +