Commit Diff


commit - 6b7a76042d9a4ea05defa90868034259a49a3313
commit + 7c3169833fb1850f0e601734a771e81fe42b14f3
blob - 158547f4cc6099f0ec5a59cf6de05974745d686d
blob + 5f253db376e12e4a91df69b8deb3cfee5032ec9f
--- .gitignore
+++ .gitignore
@@ -1,2 +1,4 @@
 **/*.swp
 **/*.mp3
+capsule/squat/reports/DDI0183G_uart_pl011_r1p5_trm.pdf
+capsule/squat/reports/SysReg_xml_v88A-2021-12.pdf
blob - 15433943e06dc9bd6ff3f46e6516971541062385
blob + 5eda73bcb9c0e534e1285a7c6de3fa60585eacf7
--- capsule/index.gmi
+++ capsule/index.gmi
@@ -10,6 +10,10 @@
 Материалы на русском языке распосложены здесь:
 => vostok/ Простой Gemini сервер vostok (Восток), написанный на C++11
 
+## squⱯt: С++11 код, запускаемый на aarch64 железе.
+
+=> squat/ squⱯt: С++11 код, запускаемый на aarch64 железе
+
 ## Архив аудио лекции
 
 В своей капсуле я храню архив интересных (по моему мнению) аудиолекции. 
blob - /dev/null
blob + 46e2a40e8f0275303e9d5bcfdd84c3b38ff3e684 (mode 644)
--- /dev/null
+++ capsule/squat/index.gmi
@@ -0,0 +1,11 @@
+# squⱯt: С++11 код, запускаемый на aarch64 железе.
+
+Git репозиторий с исходным кодом сервера (C++11):
+```
+ssh://anonymous@got.any-key.press/squat
+```
+=> https://got.any-key.press/?action=summary&path=squat.git Web интерфейс к git репозиторию
+
+## Блог разработки проекта squⱯt
+
+=> reports/
blob - /dev/null
blob + 7a70f14793e7705200ca4149d7058c103cd0ee10 (mode 644)
--- /dev/null
+++ capsule/squat/reports/0.0.1.gmi
@@ -0,0 +1,128 @@
+# squⱯt v0.0.1
+
+С++11 код, запускаемый на aarch64 железе.
+
+## Структура проекта
+
+Код проекта расположен в следующих исходных файлах:
+* `boot.S`: стартовый (загрузочный) код в виде ассемблерного листинга. Код загоняет в бесконечный цикл все процессоры, кроме _первого_ (используя для идентификации регистр MPIDR_EL1). А на первом процессоре обнуляет секцию `BSS`, настраивает стек на адрес точки входа и отдает управление в C++ функцию `kernel_entry_point`. Стек по мере наполнения растет в сторону уменьшения адреса, поэтому стартовые код (точки входа) не перетирается.
+* `kernel.cc`: модуль условного ядра. Вызывает необходимую инициализацию (на текущий момент это только UART) и передает управление коду полезной нагрузки (на текущий момент это `UART echo test mode`: получение из UART символов и их обратная отсылка).
+* `uart_virt.cc`: реализация работы UART(PL011) для платформы virt в QEMU.
+* `linker.ld`: описание геометрии секций для компоновщика.
+
+Проект собирается и запускается с использованием простого `Makefile`.
+
+=> https://developer.arm.com/documentation/ddi0595/2021-12/AArch64-Registers/MPIDR-EL1--Multiprocessor-Affinity-Register MPIDR_EL1, Multiprocessor Affinity Register
+=> https://developer.arm.com/documentation/ddi0183 PrimeCell UART (PL011) Technical Reference Manual
+=> https://qemu.readthedocs.io/en/latest/system/arm/virt.html QEMU: ‘virt’ generic virtual platform
+
+UPD(2023-09-12): Связи с тем, что ARM блокирует запросы к своей документации для пользователей из РФ, ниже добавлены ссылки на локально сохранённые документы.
+=> SysReg_xml_v88A-2021-12.pdf Arm Architecture Registers
+=> DDI0183G_uart_pl011_r1p5_trm.pdf PrimeCell UART (PL011)
+
+## Конфигурирование сборки
+
+Для сборки используются утилиты из состава LLVM. Для учета локальных особенностей системы, где происходит сборка, используется файл `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` файл.
+
+=> 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 <kernel_entry_point>
+      34: f6 ff ff 17   b       0xc <_idle>
+
+Disassembly of section .text:
+
+0000000000000038 <kernel_entry_point>:
+      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
+```
blob - /dev/null
blob + e096ad7fadcef7ee97a35632dcbb6378dc48d12f (mode 644)
--- /dev/null
+++ capsule/squat/reports/index.gmi
@@ -0,0 +1,3 @@
+# Блог проекта squⱯt
+
+=> 0.0.1.gmi v0.0.1 (2023-03-02)