Недавно решил приобщиться к современным технологиям и купить наконец-то умные часы. Точнее, не часы, а "фитнес-браслет". В общем, обо всём по порядку...
В первую очередь мне нужно было устройство, которое бы просто уведомляло меня о сообщениях и звонках на телефон, который зимой запрятан где-то в недрах пуховика и не слышен на фоне уличного шума. Ну и время ещё показывало, ага. Плюс не особо люблю vendor lock-in, и, например, у меня есть умная лампа, используемая в качестве будильника, но управляемая собственным инстансом Home Assistant, а не фирменными облачными сервисами, поэтому к часам тоже были определённые требования открытости.
Первым делом стал читать, а что же такое Android Wear (а точнее, теперь уже Wear OS) — наверняка же у неё более развитая экосистема в целом и открытых решений в частности. Впрочем, вскоре у меня сложилось ощущение, что это устройства в основном не из бюджетного сегмента, что выглядит неудивительно, учитывая "Kernel type: modified Linux kernel". Не уверен, что это мнение полноценно отражает действительность, но так или иначе от идеи покупать часы обязательно на известной "полноформатной" ОС я отказался.
Следующая мысль была поступить, как с роутером: заранее свериться со списком поддерживаемых устройств и купить под перепрошивку на свободную ОС. Конечно, часы — это не роутер с полноценным линуксом, 128 мегабайтами оперативки и т.д., но ведь существуют же сторонние прошивки для умных термометров (да, я сам в шоке). От этой идеи в итоге тоже отказался, поскольку обнаружил более перспективный вариант (хотя какие-то альтернативные прошивки существуют, как минимум, для более мощного железа "часов", а не "браслетов").
Решение, на котором я пока что остановился, это использование более бюджетного "умного браслета" на произвольной оригинальной прошивке, и управление этим браслетом из свободного софта. Похоже, что сторонний софт, работающий с часами/браслетами со стороны смартфона — это, в принципе, не редкость, но меня в первую очередь интересует что-нибудь из F-Droid, раз уж мне придётся выдать этому приложению права на чтение, например, уведомлений (авторизационные и не только эсэмэски, мессенджеры и чего только не).
В качестве смартфонного приложения я решил попробовать Gadgetbridge. Оно поддерживает большое количество устройств разных производителей (и даже есть рекомендации, что лучше из этого покупать), а в качестве устройства — Huawei Band 8. Стоит отметить, что для связывания с Gadgetbridge этого браслета даже не требуется приложение от производителя и пляски с извлечением ключа. Пляски требуются, чтобы можно было перепривязывать устройство без сброса между GB и фирменным приложением (которое пока что нужно, например, для перепрошивки), но это не столь критично и не очень сложно. Не сказал бы, что эта связка работает прямо, как мне хотелось (можно подумать, я знал, чего конкретно мне хотелось...), но посмотрим, как будет дальше. Как минимум, уведомления оно отображает, время тоже.
#android
В первую очередь мне нужно было устройство, которое бы просто уведомляло меня о сообщениях и звонках на телефон, который зимой запрятан где-то в недрах пуховика и не слышен на фоне уличного шума. Ну и время ещё показывало, ага. Плюс не особо люблю vendor lock-in, и, например, у меня есть умная лампа, используемая в качестве будильника, но управляемая собственным инстансом Home Assistant, а не фирменными облачными сервисами, поэтому к часам тоже были определённые требования открытости.
Первым делом стал читать, а что же такое Android Wear (а точнее, теперь уже Wear OS) — наверняка же у неё более развитая экосистема в целом и открытых решений в частности. Впрочем, вскоре у меня сложилось ощущение, что это устройства в основном не из бюджетного сегмента, что выглядит неудивительно, учитывая "Kernel type: modified Linux kernel". Не уверен, что это мнение полноценно отражает действительность, но так или иначе от идеи покупать часы обязательно на известной "полноформатной" ОС я отказался.
Следующая мысль была поступить, как с роутером: заранее свериться со списком поддерживаемых устройств и купить под перепрошивку на свободную ОС. Конечно, часы — это не роутер с полноценным линуксом, 128 мегабайтами оперативки и т.д., но ведь существуют же сторонние прошивки для умных термометров (да, я сам в шоке). От этой идеи в итоге тоже отказался, поскольку обнаружил более перспективный вариант (хотя какие-то альтернативные прошивки существуют, как минимум, для более мощного железа "часов", а не "браслетов").
Решение, на котором я пока что остановился, это использование более бюджетного "умного браслета" на произвольной оригинальной прошивке, и управление этим браслетом из свободного софта. Похоже, что сторонний софт, работающий с часами/браслетами со стороны смартфона — это, в принципе, не редкость, но меня в первую очередь интересует что-нибудь из F-Droid, раз уж мне придётся выдать этому приложению права на чтение, например, уведомлений (авторизационные и не только эсэмэски, мессенджеры и чего только не).
В качестве смартфонного приложения я решил попробовать Gadgetbridge. Оно поддерживает большое количество устройств разных производителей (и даже есть рекомендации, что лучше из этого покупать), а в качестве устройства — Huawei Band 8. Стоит отметить, что для связывания с Gadgetbridge этого браслета даже не требуется приложение от производителя и пляски с извлечением ключа. Пляски требуются, чтобы можно было перепривязывать устройство без сброса между GB и фирменным приложением (которое пока что нужно, например, для перепрошивки), но это не столь критично и не очень сложно. Не сказал бы, что эта связка работает прямо, как мне хотелось (можно подумать, я знал, чего конкретно мне хотелось...), но посмотрим, как будет дальше. Как минимум, уведомления оно отображает, время тоже.
#android
f-droid.org
Gadgetbridge | F-Droid - Free and Open Source Android App Repository
Use your smart watch and other bluetooth devices and keep your data private!
Столкнулся с веб-интерфейсной странностью, которая разрешилась весьма неожиданным образом.
Как я уже писал некоторое время назад, я решил настроить локальную коробочку с популярными линукс-дистрибутивами. Одним из таких дистрибутивов оказался Manjaro (мне, правда, пока им пользоваться не приходилось, но дистрибутив на слуху, а место есть). Поэтому я периодически заходил на страницу загрузок и скачивал свежие torrent-файлы. Но вот незадача: ссылки то работали, то нет: иногда кликаешь по кнопке Torrent и... ничего не происходит. Вообще. А иногда работает. В общем, пользоваться можно, но как-то некомфортно. Если хотите, можете тоже перейти по ссылке и попробовать отладить проблему самостоятельно :) У меня ошибка воспроизводилась на десктопных Firefox и Chromium.
Сначала я подумал, что раз уж на сайте такие причудливые динамические панельки с кнопками, то конкретные ссылки на актуальные версии iso-шников для KDE, Xfce и прочих могут загружаться отдельным файлом (я когда-то экспериментировал с одностраничным приложением, которое тянуло конфигурацию отдельным json-ом, хотя это вообще не показатель, поскольку я не веб-разработчик). Подобная проблема должна быть легко заметна в "инструментах разработчика" в браузере: в списке сетевых запросов и, скорее всего, ещё и в консоли JavaScript. Но в сетевых запросах всё зелено, а в консоли JS, как всегда, есть отдельные ворнинги, но их наличие не зависит от наличия основной проблемы.
После мне стало казаться, что не нужно прокликивать интерфейс слишком быстро — мало ли там какой-нибудь race condition, что-нибудь прогрузиться перед очередным кликом не успевает — стал подкрадываться к кнопкам осторожней, но проблема окончательно не исчезла.
И вот, наконец, я случайно заметил, в чём отличие между успешным и неуспешным скачиванием...
Оказалось, что дело не в сети и не в JS, а в стилях! Интуитивно же кажется, что если большая прямоугольная с закруглёнными краями "кнопка" подсветилась, значит должна реагировать на клик. Нифига! Цветной прямоугольник живёт своей жизнью, а сама ссылка — немногим больше слова "Torrent", "Image" и т.д. Есть у меня подозрение, что даже для одного и того же человека воспроизводимость бага может зависеть от удобности мыши или, например, от настроения :) А уж помогать с такой ошибкой кому-то должно быть ещё веселее...
Как я уже писал некоторое время назад, я решил настроить локальную коробочку с популярными линукс-дистрибутивами. Одним из таких дистрибутивов оказался Manjaro (мне, правда, пока им пользоваться не приходилось, но дистрибутив на слуху, а место есть). Поэтому я периодически заходил на страницу загрузок и скачивал свежие torrent-файлы. Но вот незадача: ссылки то работали, то нет: иногда кликаешь по кнопке Torrent и... ничего не происходит. Вообще. А иногда работает. В общем, пользоваться можно, но как-то некомфортно. Если хотите, можете тоже перейти по ссылке и попробовать отладить проблему самостоятельно :) У меня ошибка воспроизводилась на десктопных Firefox и Chromium.
Сначала я подумал, что раз уж на сайте такие причудливые динамические панельки с кнопками, то конкретные ссылки на актуальные версии iso-шников для KDE, Xfce и прочих могут загружаться отдельным файлом (я когда-то экспериментировал с одностраничным приложением, которое тянуло конфигурацию отдельным json-ом, хотя это вообще не показатель, поскольку я не веб-разработчик). Подобная проблема должна быть легко заметна в "инструментах разработчика" в браузере: в списке сетевых запросов и, скорее всего, ещё и в консоли JavaScript. Но в сетевых запросах всё зелено, а в консоли JS, как всегда, есть отдельные ворнинги, но их наличие не зависит от наличия основной проблемы.
После мне стало казаться, что не нужно прокликивать интерфейс слишком быстро — мало ли там какой-нибудь race condition, что-нибудь прогрузиться перед очередным кликом не успевает — стал подкрадываться к кнопкам осторожней, но проблема окончательно не исчезла.
И вот, наконец, я случайно заметил, в чём отличие между успешным и неуспешным скачиванием...
manjaro.org
Manjaro Image Downloads
Choose from major Linux Desktop environments to run Manjaro on your computer.
Лайфхак: перенаправления в- или из файла в bash не обязаны идти в самом конце команды. Допустим, я хочу отсортировать строки в таком файле:
при помощи команды sort. Забудем на минуточку, что конкретно команде sort файл(ы) также можно передавать как аргументы командной строки, и представим, что у нас есть только фильтр, преобразующий stdin в stdout:
... и тут мы вспоминаем, что сортировать нужно по второй колонке — той, что с буквой — для этого нужно просто указать опцию
3 B Some string
1 C Some other string
2 A One more test string
при помощи команды sort. Забудем на минуточку, что конкретно команде sort файл(ы) также можно передавать как аргументы командной строки, и представим, что у нас есть только фильтр, преобразующий stdin в stdout:
$ sort < /tmp/long-input-name
1 C Some other string
2 A One more test string
3 B Some string
... и тут мы вспоминаем, что сортировать нужно по второй колонке — той, что с буквой — для этого нужно просто указать опцию
-k 2. Так вот, оказывается, необязательно гнать курсор до начала всех перенаправлений, можно просто дописать опцию после:$ sort < /tmp/long-input-name -k 2
2 A One more test string
3 B Some string
1 C Some other string
С тех пор, как #маленький_но_гордый_сервер был проапгрейжен (да, я ещё не потерял надежду продолжить эту тему заметок), у меня остался лежать Orange Pi Zero 3. Захотелось сделать из него ютубосмотрелку, как-никак, TV boxes — это одно из предназначений его процессора — хотя правильнее, наверное, говорить System-on-Chip — Allwinner H618 (ссылка, если что, на фанатский сайт не на официальный сайт производителя).
Увы, поставив на него свежий OpenSUSE Tumbleweed (обычно я пользуюсь Убунтой, но раз уж для "сервера" настроил MicroOS, то и здесь решил использовать что-нибудь из OpenSUSE), я не обнаружил следов видеодрайверов, и в частности, модуля panfrost, который я так старательно банил в "серверном" варианте, потому что при его инициализации напрочь висла система. Думал, за прошедшее время модуль допилили, но оказалось, что теперь "модуль не виснет, он делает больно по-другому".
По запросу "opensuse panfrost" гугл выдал что-то вроде официальной документации дистрибутива, из которой следовало, что всё уже давно поддерживается, но мало в каких описаниях плат Mali GPU описан в device tree. Что же, идём в Armbian, там я когда-то видел сборку под Zero 3 с предположительно работающей графикой. Правда, сборка не особо официальная, и внутренний параноик как-то не особо хочет доверять ей свой пароль от гугла-ютуба. К счастью, из неё мне требуется только небольшой файлик
В общем, подложил я этот dtb вместо шедшего в комплекте с ядром, перезагрузился, и понял, что всё верно, теперь система знает про GPU... и вновь зависает при загрузке, блин. Похоже, тот патч для power domain driver (что бы это ни значило) всё ещё на вмержили. Некоторое количество времени я пытался нагуглить, как прямо на плате пропатчить и пересобрать один-единственный модуль, потом засомневался, а модуль ли это, или он намертво влинкован в ядро, плюнул и пошёл читать описание, а что же этот патч делает.
В описании патча, который я пытался применить, говорилось
Костыль получился простой: посмотрев в консоли U-Boot при помощи
... можно понять, что вклиниться в процесс загрузки можно, положив в корень FAT32-раздела файлпосле вместо скрипта пошёл бы загружаться efi), получился скрипт из двух строчек:
который нужно положить, например, в файл
Увы, поставив на него свежий OpenSUSE Tumbleweed (обычно я пользуюсь Убунтой, но раз уж для "сервера" настроил MicroOS, то и здесь решил использовать что-нибудь из OpenSUSE), я не обнаружил следов видеодрайверов, и в частности, модуля panfrost, который я так старательно банил в "серверном" варианте, потому что при его инициализации напрочь висла система. Думал, за прошедшее время модуль допилили, но оказалось, что теперь "модуль не виснет, он делает больно по-другому".
По запросу "opensuse panfrost" гугл выдал что-то вроде официальной документации дистрибутива, из которой следовало, что всё уже давно поддерживается, но мало в каких описаниях плат Mali GPU описан в device tree. Что же, идём в Armbian, там я когда-то видел сборку под Zero 3 с предположительно работающей графикой. Правда, сборка не особо официальная, и внутренний параноик как-то не особо хочет доверять ей свой пароль от гугла-ютуба. К счастью, из неё мне требуется только небольшой файлик
sun50i-h618-orangepi-zero3.dtb с описанием оборудования.В общем, подложил я этот dtb вместо шедшего в комплекте с ядром, перезагрузился, и понял, что всё верно, теперь система знает про GPU... и вновь зависает при загрузке, блин. Похоже, тот патч для power domain driver (что бы это ни значило) всё ещё на вмержили. Некоторое количество времени я пытался нагуглить, как прямо на плате пропатчить и пересобрать один-единственный модуль, потом засомневался, а модуль ли это, или он намертво влинкован в ядро, плюнул и пошёл читать описание, а что же этот патч делает.
В описании патча, который я пытался применить, говорилось
The Allwinner H616 features register 0x7010254 in the PRCM MMIO frame,
where bit 0 needs to be cleared to enable operation of the Mali GPU.
With this bit set (the reset default), any access to the Mali registers
hangs the bus and thus the whole system. The BSP code clears this bit
in U-Boot and their kernel never touches it again.
Костыль получился простой: посмотрев в консоли U-Boot при помощи
env print (вывод слегка переформатирован для читаемости), что происходит в окрестности момента загрузки EFI-бинарника GRUB 2...=> env print
...
boot_prefixes=/ /boot/
boot_scripts=boot.scr.uimg boot.scr
...
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; \
for prefix in ${boot_prefixes}; do \
run scan_dev_for_extlinux; \
run scan_dev_for_scripts; \
done; \
run scan_dev_for_efi;
scan_dev_for_scripts=for script in ${boot_scripts}; do \
if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then # ...
... можно понять, что вклиниться в процесс загрузки можно, положив в корень FAT32-раздела файл
boot.scr. Фактически, мне нужно командой mw.b 0x7010254 0x00 1 включить GPU (disclaimer: здесь я заранее посмотрел при помощи md, что похоже, что по этому адресу всегда лежит значение 0x01, значит, со сброшенным младшим битом это будет просто 0x00, в общем же случае пришлось бы как-нибудь вычислять, наверное...) и возобновить процесс загрузки с минимальными изменениями. Поскольку закостылить требуется лишь вполне конкретную ситуацию (т.е. я знаю, какое железо используется, знаю где лежат загрузчики, знаю, что сразу же mw.b 0x7010254 0x00 1
run scan_dev_for_efi
который нужно положить, например, в файл
boot.cmd и обернуть правильным бинарным заголовком, чтобы U-Boot его узнал, в линуксовой консоли выполнивmkimage -A arm64 -O u-boot -T script -d boot.cmd boot.scr
Теперь ядро благополучно загрузилось, и при этом
PS: Оказывается, 1) ограничение на размер поста бывает не только при наличие картинок, 2) десктопный клиент сам разбивает длинное сообщение на части.
lsmod показал, что модуль panfrost был автоматически загружен... а вот графический сеанс на мониторе, подключенном по HDMI, так и не отобразился: видимо, некоторые из других драйверов, перечисленных в списке недоделок на linux-sunxi, действительно ещё не влиты в основное ядро. Но это, как говорится, уже совсем другая история... Зато теперь приветственная строчка "Have a lot of fun", печатаемая при текстовом логине в OpenSUSE заиграла новыми красками.PS: Оказывается, 1) ограничение на размер поста бывает не только при наличие картинок, 2) десктопный клиент сам разбивает длинное сообщение на части.
Кстати о том, как извлечь файл из preinstalled-образа диска с несколькими разделами.
Обычно в линуксе образ диска вроде iso-файла можно просто примонтировать командой
Но это образ одной файловой системы. А что, если на вход у нас есть дамп диска с таблицей разделов MBR или GPT, и нам нужен какой-то из этих разделов? Тут нам поможет знание о существовании loop devices, просто придётся вручную сделать два отдельных шага: настроить loop device и подмонтировать его. Дело в том, что при настройке можно попросить ядро представить, будто у него появился ещё один обычный диск (ну, там, флешку подключили), и попробовать поискать на нём разделы:
Да, здесь получилось не столь "зрелищно", поскольку раздел всего один. Хотя, как знать: раздел-то один, а без парсинга таблицы разделов не открыть:
Кстати,
Ну и после завершения работы с образом можно этот образ отцепить от loop device:
Обычно в линуксе образ диска вроде iso-файла можно просто примонтировать командой
mount так же, как обычное блочное устройство: просто вместо mount /dev/sda1 /mnt пишешь mount file.iso /mnt, и всё работает. При этом где-то в глубине команда mount настроит loop-устройство, превратив файл в block device, а далее подмонтирует уже block device (методом чайника, ага), но для пользователя это не столь важно.Но это образ одной файловой системы. А что, если на вход у нас есть дамп диска с таблицей разделов MBR или GPT, и нам нужен какой-то из этих разделов? Тут нам поможет знание о существовании loop devices, просто придётся вручную сделать два отдельных шага: настроить loop device и подмонтировать его. Дело в том, что при настройке можно попросить ядро представить, будто у него появился ещё один обычный диск (ну, там, флешку подключили), и попробовать поискать на нём разделы:
$ losetup --find --show --partscan /tmp/armbian.img
/dev/loop26
$ ls /dev/loop26*
/dev/loop26 /dev/loop26p1
$ mount /dev/loop26p1 /mnt
$ ls /mnt
bin bin.usr-is-merged boot dev etc # ...
Да, здесь получилось не столь "зрелищно", поскольку раздел всего один. Хотя, как знать: раздел-то один, а без парсинга таблицы разделов не открыть:
$ mount /tmp/armbian.img /mnt
mount: /mnt: wrong fs type, bad option, bad superblock on /dev/loop26, missing codepage or helper program, or other error.
dmesg(1) may have more information after failed mount system call.
$ file /tmp/armbian.img
/tmp/armbian.img: DOS/MBR boot sector; partition 1 : ID=0x83, start-CHS (0x0,130,3), end-CHS (0x2e9,131,26), startsector 8192, 11968512 sectors, extended partition table (last)
Кстати,
file точно так же расскажет о содержимом блочного устройства, нужно только правильно попросить:$ file /dev/loop26*
/dev/loop26: block special (7/26)
/dev/loop26p1: block special (259/5)
$ file --special-files /dev/loop26*
/dev/loop26: DOS/MBR boot sector; partition 1 : ID=0x83, start-CHS (0x0,130,3), end-CHS (0x2e9,131,26), startsector 8192, 11968512 sectors, extended partition table (last)
/dev/loop26p1: Linux rev 1.0 ext4 filesystem data, UUID=3b40068e-537c-4a9a-a1fe-6bff7c29918c, volume name "armbi_root" (extents) (64bit) (large files) (huge files)
Ну и после завершения работы с образом можно этот образ отцепить от loop device:
$ losetup --detach /dev/loop26
При этом понятно, откуда строчка "nan" — это NaN (Not-a-Number), а вот почему именно он появился при переходе от
P.S.: JS не мой любимый язык программирования, репостнул из-за синтаксиса :)
'b' + 'a' к 'b' + 'a' + + 'a' — вопрос... И да, без пробелов между + + — синтаксическая ошибка, "ты что, дурак? причём здесь инкремент?!?". P.S.: JS не мой любимый язык программирования, репостнул из-за синтаксиса :)
Кстати о JavaScript, который хоть и не мой любимый язык, но с которым я когда-то много взаимодействовал с необычной стороны — как с машинным языком, в который компилируется что-нибудь высокоуровневое типа C :) Знаете ли вы, что в какой-то момент было сформулировано компилируемое ahead-of-time подмножество JS, которое браузеры могли распознавать и более эффективно выполнять: https://en.wikipedia.org/wiki/Asm.js При этом браузеры могли игнорировать существование Asm.js или банально не знать о нём, и тогда код был просто несколько причудливым джаваскриптом. А потом пришёл бинарный WebAssembly, и необходимость в Asm.js, вроде бы, отпала.
Кстати о правильном толковании стандартов языка, на Stack Overflow даже есть тег [language-lawyer] с аннотацией "For questions about the intricacies of formal or authoritative specifications of programming languages", например
* What does the C++ standard say about the size of int, long?
* A positive lambda: '+[]{}' - What sorcery is this?
* What does the C++ standard say about the size of int, long?
* A positive lambda: '+[]{}' - What sorcery is this?
Stack Overflow
Highest scored 'language-lawyer' questions
Stack Overflow | The World’s Largest Online Community for Developers
Помимо StackOverflow есть целое семейство вопросо-ответных сайтов на разные тематики, называется StackExchange. Одним из таких сайтов является worldbuilding.stackexchange.com — сайт, где авторы художественных произведений спрашивают советы по более логичному обоснованию деталей сюжета.
Одним из таких вопросов был: зачем может быть полезна письменность обществу с развитой телепатией? Чтоб вы понимали, этот вопрос (а точнее самый популярный ответ на него) я с лёгкостью нашёл в поиске сайта по запросу "cache druids". В общем, вот: обсуждение друидов L2-кэша, вопросов отказоустойчивости и т.д.
P.S.: Кто-то, безусловно, уже мог видеть у меня эту ссылку, но сюда я её ещё не кидал.
Одним из таких вопросов был: зачем может быть полезна письменность обществу с развитой телепатией? Чтоб вы понимали, этот вопрос (а точнее самый популярный ответ на него) я с лёгкостью нашёл в поиске сайта по запросу "cache druids". В общем, вот: обсуждение друидов L2-кэша, вопросов отказоустойчивости и т.д.
P.S.: Кто-то, безусловно, уже мог видеть у меня эту ссылку, но сюда я её ещё не кидал.
Worldbuilding Stack Exchange
Does a hive mind race need a written language?
Imagine that human beings in a parallel world evolved with hive mind, so that they can communicate telepathically almost instantly at infinite range. To put thoughts into writing requires effort an...
Понадобилось мне запустить Thunderbird без доступа в интернет, чтобы проверить самодостаточность экспортированного mbox-файла с письмами. Наверное, можно было бы соорудить какую-нибудь изоляцию при помощи network namespace, но я решил, что чем разбираться с нюансами linux namespaces, а потом ещё и думать, как надёжно разделить профили Thunderbird "для экспорта" и "для теста", проще сразу поднять виртуальную машину. При этом хотелось работать прямо с Live DVD, чтобы найдя потом эту ВМ через пол-года, не пытаться судорожно вспомнить, а можно ли её удалить, или там что-то важное лежит: раз нет HDD, значит и ничего важного нет :) Впрочем, поскольку QEMU можно запускать прямо из терминала, то нет не то что HDD, нет даже какой-то перманентной сущности "виртуальная машина", которую нужно (или не нужно) удалять.
QEMU был выбран потому, что не хотелось возиться с установкой драйверов VirtualBox ни на хост, ни в гостевую систему. Хост не хотелось трогать просто потому, чтобы потом при каждом обновлении ядра не запускалась сборка модулей через dkms, а установка "дополнений гостевой ОС" внутри Live DVD без перезагрузки в принципе не выглядит простой задачей.
В общем, небольшая памятка (возможно, даже для себя через пол-года). Строка запуска QEMU с каталогом, расшаренным между хостом и гостем, выглядит примерно так:
Первая строчка (
Вторая строка описывает каталог, расшаренный при помощи некоего древнего протокола из операционной системы Plan 9, который, если верить документации QEMU, поддерживается аж со времён ядра
Что неудивительно, расшаренный каталог сам по себе в гостевой системе не подключится (потому что куда конкретно он должен подключиться?) — его нужно подмонтировать:
Здесь
Кстати, если хочется, чтобы внутри ВМ шустрее работала графика, можно добавить при запуске QEMU опции
Опция
В завершение не лишним будет упомянуть, что речь идёт об изоляции доверенной гостевой ОС для предотвращения случайного обращения куда не надо. Если же в гостевой системе предполагается наличие malware, то тут нужно отдельно читать best practices по надёжной изоляции — я даже советовать не берусь.
UPD: Ах да, так увлёкся документированием расшаривания каталога и тестированием разных эмулируемых видеоадаптеров, что до, собственно, проверки бекапа дело не дошло, поэтому о самом главном забыл:
QEMU был выбран потому, что не хотелось возиться с установкой драйверов VirtualBox ни на хост, ни в гостевую систему. Хост не хотелось трогать просто потому, чтобы потом при каждом обновлении ядра не запускалась сборка модулей через dkms, а установка "дополнений гостевой ОС" внутри Live DVD без перезагрузки в принципе не выглядит простой задачей.
В общем, небольшая памятка (возможно, даже для себя через пол-года). Строка запуска QEMU с каталогом, расшаренным между хостом и гостем, выглядит примерно так:
qemu-system-x86_64 \
-m 4096 -accel kvm \
-virtfs local,path=/tmp/share,mount_tag=share,security_model=none \
-net none \
-cdrom kubuntu-24.10-desktop-amd64.iso
Первая строчка (
-m 4096 -accel kvm) указывает выделить виртуалке 4ГБ оперативной памяти и использовать аппаратное ускорение виртуализации (KVM — штука стандартная, поэтому на типичном "десктопном линуксе" на хосте сторонние модули не нужны, разве что своего пользователя может потребоваться добавить в какую-нибудь группу и перезайти в систему).Вторая строка описывает каталог, расшаренный при помощи некоего древнего протокола из операционной системы Plan 9, который, если верить документации QEMU, поддерживается аж со времён ядра
2.6.36.rc4, то есть очень давно. Подробности можно почитать во всё той же документации, я же просто уточню, что path=/tmp/share указывает каталог на хосте, mount_tag=share задаёт метку, по которой эта шара будет монтироваться гостем, а security_model=none указывает не заморачиваться по поводу прав доступа к файлам.Что неудивительно, расшаренный каталог сам по себе в гостевой системе не подключится (потому что куда конкретно он должен подключиться?) — его нужно подмонтировать:
mount -t 9p -o trans=virtio,version=9p2000.L share /mnt
Здесь
/mnt — точка монтирования в гостевой системе, а share — тот самый mount tag.Кстати, если хочется, чтобы внутри ВМ шустрее работала графика, можно добавить при запуске QEMU опции
...
-display gtk,gl=on -vga none -device virtio-gpu-gl \
...
Опция
-display gtk,gl=on указывает включить OpenGL в графическом интерфейсе ВМ на хосте (т.е. самом окошке с виртуальным экраном и меню "Reboot"/"Power off"/...), -device virtio-gpu-gl добавляет в эмулируемую систему продвинутую виртуальную видеокарту, а -vga none извлекает видеокарту обычную, чтобы система не путалась. Правда, с "продвинутой видеокартой" изображение не появится, пока не запустится графический сеанс (ну или вообще никогда, если "гость" упадёт до этого этапа). Бонусом — гостевая система будет с пониманием относиться к тому, что монитор вдруг поменял нативное разрешение, когда на хосте меняют размер окна.В завершение не лишним будет упомянуть, что речь идёт об изоляции доверенной гостевой ОС для предотвращения случайного обращения куда не надо. Если же в гостевой системе предполагается наличие malware, то тут нужно отдельно читать best practices по надёжной изоляции — я даже советовать не берусь.
UPD: Ах да, так увлёкся документированием расшаривания каталога и тестированием разных эмулируемых видеоадаптеров, что до, собственно, проверки бекапа дело не дошло, поэтому о самом главном забыл:
-net none отключает сеть :) Дописал в команду запуска.Кстати, о запуске QEMU из командной строки. Как известно, в *nix длинную команду запуска чего-нибудь можно положить в файл, исполняемый как shell-скрипт. Этот файл можно будет редактировать в текстовом редакторе вместо встроенного редактора bash или другой оболочки, а для читаемости разбить команду на несколько строк, завершаемых символом
Всё бы хорошо, но потом начинает хотеться временно отключить часть аргументов. Казалось бы, есть же символ
Называется этот приём array variables. Хотя в shell-скриптах примерно все переменные — строки, но в bash некоторые переменные могут содержать последовательность логически разделённых строк. В документации написано, что поддерживаются даже ассоциативные массивы, но сейчас не о них. Если при присваивании переменной вместо
\ (как было сделано постом выше).Всё бы хорошо, но потом начинает хотеться временно отключить часть аргументов. Казалось бы, есть же символ
#, комментирующий до конца строки. Но нет: \ не продолжит "виртуальную строку", будучи закомментированным. Можно, конечно, в какой-то точке файла написать exit 0, а следом устроить склад временно выведенных из эксплуатации наборов аргументов — когда-то я так и делал. Но есть способ лучше! Правда, непохоже, чтобы минимальный /bin/sh, гарантированный стандартом, это поддерживал, но в bash (и наверняка zsh) такой приём жизнь облегчит.Называется этот приём array variables. Хотя в shell-скриптах примерно все переменные — строки, но в bash некоторые переменные могут содержать последовательность логически разделённых строк. В документации написано, что поддерживаются даже ассоциативные массивы, но сейчас не о них. Если при присваивании переменной вместо
name="some value" написать name=("value a" "value b"), то в переменной окажется сохранена последовательность строк, которую можно потом передать далее с сохранением разбиения на аргументы при помощи синтаксиса ${name[@]} (на самом деле, ${string_var} — это то же самое, что $string_var, так что из нового добавляется только [@]). Например:args=(
file
"multi word file name"
other_file
)
gzip "${args[@]}"
Уже не первый год, как во многих графических интерфейсах есть ночной цветовой режим — в смысле не тёмная тема, а светлая, но с пониженной цветовой температурой. Есть такая функция и в KDE. А недавно я обнаружил, что свежая Kubuntu 24.10 при прокрутке на значке "ночной" цветовой гаммы умеет ещё и менять яркость монитора. То есть не просто программно домножать компоненты R, G, B на коэффициент, меньший единицы, а буквально регулировать яркость подсветки монитора. Да, именно отдельностоящего монитора, подключенного по HDMI.
Впрочем, самой по себе возможности подобного управления я уже успел удивиться пару лет назад, когда решил загуглить, что же это за пункт меню под названием "DDC/CI" со значениями Enabled и Disabled. До чего, оказывается, техника дошла: когда-то давно пользовался здоровенным ЭЛТ монитором, у которого было чудо техники — USB-вход для управления настройками через специальный виндовый софт, а теперь вот случайно обнаруживаешь, что уже есть независимый от производителя стандарт (и I²C-шина в HDMI-разъёме), а из репозитория можно просто поставить консольную или графическую утилиту.
Впрочем, самой по себе возможности подобного управления я уже успел удивиться пару лет назад, когда решил загуглить, что же это за пункт меню под названием "DDC/CI" со значениями Enabled и Disabled. До чего, оказывается, техника дошла: когда-то давно пользовался здоровенным ЭЛТ монитором, у которого было чудо техники — USB-вход для управления настройками через специальный виндовый софт, а теперь вот случайно обнаруживаешь, что уже есть независимый от производителя стандарт (и I²C-шина в HDMI-разъёме), а из репозитория можно просто поставить консольную или графическую утилиту.
Пару лет назад я заказал на Алиэкспрессе отладочную плату с STM32 с намерением "ну надо же когда-нибудь приобщиться к программированию микроконтроллеров, а то чё я как лох-то?..". И вот, наконец-то решился: буду моргать светодиодом! Впрочем, не спешите с раздражением пролистывать очередной гайд по установке Arduino IDE (или что там обычно в таких случаях ставят) — сегодня будет занимательное (надеюсь) чтение technical reference manual на микроконтроллер и документации по системе команд Armv7. Ну и практика, конечно: ассемблер, gdb, все дела...
Целью сегодняшней "лабораторки" будет написание минимального примера, который можно запустить на железе, без использования готовых библиотек и прочей "магии" — буквально, получаем управление с первых тактов работы CPU, хотя и с некоторым читерством: я воспользуюсь возможностью отладки с компьютера, чтобы загрузить код прямиком в SRAM и передать на него управление.
Сразу уточню, что я не являюсь профессиональным писателем "загрузочного кода", равно как и программистом микроконтроллеров — у меня больше "компиляторостроительная" специализация — поэтому приведённый код и подход ни в коем случае не best practices, это скорее заметки вида "итак, я почти ничего не знаю про этот микроконтроллер, и я примерно понимаю, куда читать — давайте попробуем сделать хоть что-то".
#моргаем_светодиодом
Целью сегодняшней "лабораторки" будет написание минимального примера, который можно запустить на железе, без использования готовых библиотек и прочей "магии" — буквально, получаем управление с первых тактов работы CPU, хотя и с некоторым читерством: я воспользуюсь возможностью отладки с компьютера, чтобы загрузить код прямиком в SRAM и передать на него управление.
Сразу уточню, что я не являюсь профессиональным писателем "загрузочного кода", равно как и программистом микроконтроллеров — у меня больше "компиляторостроительная" специализация — поэтому приведённый код и подход ни в коем случае не best practices, это скорее заметки вида "итак, я почти ничего не знаю про этот микроконтроллер, и я примерно понимаю, куда читать — давайте попробуем сделать хоть что-то".
#моргаем_светодиодом
Для начала, с чем будем работать. В качестве отладочной платы используется одна из Black pill, в моём случае WeAct v3.0 с микроконтроллером STM32F401CDU6. Кстати, вот этот сайт, похоже, будет очень полезен как справочник: stm32-base.org — например, вот страница, описывающая мою плату (там, правда, указана микросхема ...CEU6).
Для отладки я буду использовать open hardware адаптер NanoDAP, о котором, когда-нибудь, наверное, напишу подробнее, а пока просто скажу, что из него торчит с одной стороны USB, а с другой — пины JTAG, SWD и UART. В случае STM32 я буду использовать интерфейс SWD.
При подаче на плату питания по USB или через SWD (только не одновременно двумя способами — думаю, последствия будут не ахти...), изначально в ней запускается то, что в неё прошил производитель. В моём случае это код, который... мигает светодиодом.Эксперимент завершён, расходимся.
#моргаем_светодиодом
Для отладки я буду использовать open hardware адаптер NanoDAP, о котором, когда-нибудь, наверное, напишу подробнее, а пока просто скажу, что из него торчит с одной стороны USB, а с другой — пины JTAG, SWD и UART. В случае STM32 я буду использовать интерфейс SWD.
При подаче на плату питания по USB или через SWD (только не одновременно двумя способами — думаю, последствия будут не ахти...), изначально в ней запускается то, что в неё прошил производитель. В моём случае это код, который... мигает светодиодом.
#моргаем_светодиодом
После того, как SWD-интерфейс физически присоединён, нужно понять, как через него подключиться отладчиком к микроконтроллеру. Для работы с JTAG- и SWD-адаптерами можно использовать OpenOCD: будучи правильно сконфигурирована, эта программа подсоединится к аппаратному адаптеру и откроет сетевой порт, на котором будет ожидать подключения от GDB, реализуя протокол gdb extended-remote.
Чтобы объяснить OpenOCD, с чем ей нужно работать, создадим файл
и запустим openocd:
Теперь можно запустить gdb (а точнее, придётся установить gdb-multiarch, поскольку ваш компьютер, скорее всего, тоже использует систему команд x86_64, а не 32-битный ARM) и подключиться к OpenOCD:
В примере выше
На 32-битном ARM инструкции могут иметь длину как 2, так и 4 байта, и как можно догадаться по примеру выше, мимо начала "второй с конца" инструкции я промахнулся. Попробуем ещё раз:
Вот, теперь больше похоже на правду.
#моргаем_светодиодом
Чтобы объяснить OpenOCD, с чем ей нужно работать, создадим файл
nanodap.cfg с таким содержимым:# тип адаптера, с которым будем работать
adapter driver cmsis-dap
# имеющаяся у меня реализация cmsis-dap представляется компьютеру
# как USB-устройство с VendorID 0xc251, ProductID 0xf001
cmsis_dap_vid_pid 0xc251 0xf001
transport select swd
source [find target/stm32f4x.cfg]
и запустим openocd:
$ sudo openocd -f nanodap.cfg
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : CMSIS-DAP: SWD supported
Info : CMSIS-DAP: JTAG supported
Info : CMSIS-DAP: SWO-UART supported
Info : CMSIS-DAP: Atomic commands supported
Info : CMSIS-DAP: Test domain timer supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1
Info : CMSIS-DAP: Interface ready
Info : clock speed 2000 kHz
Info : SWD DPIDR 0x2ba01477
Info : [stm32f4x.cpu] Cortex-M4 r0p1 processor detected
Info : [stm32f4x.cpu] target has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f4x.cpu on 3333
Info : Listening on port 3333 for gdb connections
Теперь можно запустить gdb (а точнее, придётся установить gdb-multiarch, поскольку ваш компьютер, скорее всего, тоже использует систему команд x86_64, а не 32-битный ARM) и подключиться к OpenOCD:
>>> target extended :3333
Remote debugging using :3333
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x0800343e in ?? ()
>>> x/10i $pc-8
0x8003436: mcr2 7, 5, pc, cr10, cr13, {7} @ <UNPREDICTABLE>
0x800343a: @ <UNDEFINED> instruction: 0xfacc42b8
=> 0x800343e: beq.n 0x80034aa
0x8003440: uxtb.w r10, r9
0x8003444: bl 0x80009d4
0x8003448: mov r7, r0
0x800344a: cmp.w r10, #1
0x800344e: bne.n 0x80034aa
0x8003450: ldrb.w r1, [r8]
0x8003454: ldrh.w r0, [r8, #2]
В примере выше
>>> — это приглашение gdb, а $pc — обозначение регистра, указывающего на текущую инструкцию: program counter. x/10i $pc - 8 означает "отобрази мне содержимое памяти (x), начиная с адреса, заданного выражением $pc - 8, при этом интерпретируй содержимое как инструкции (i) в количестве 10 штук".На 32-битном ARM инструкции могут иметь длину как 2, так и 4 байта, и как можно догадаться по примеру выше, мимо начала "второй с конца" инструкции я промахнулся. Попробуем ещё раз:
>>> x/10i $pc-6
0x8003438: bl 0x80009d4
0x800343c: cmp r0, r7
=> 0x800343e: beq.n 0x80034aa
0x8003440: uxtb.w r10, r9
0x8003444: bl 0x80009d4
0x8003448: mov r7, r0
0x800344a: cmp.w r10, #1
0x800344e: bne.n 0x80034aa
0x8003450: ldrb.w r1, [r8]
0x8003454: ldrh.w r0, [r8, #2]
Вот, теперь больше похоже на правду.
#моргаем_светодиодом