LINUX.ORG.RU

Tk


12

1

Всего сообщений: 4

Написал эмулятор своего мобильника

Более чем два месяца назад заказал отладочные платы для своего хоббийного проекта, но они так и не пришли и хз, придут ли вообще. Разработка прошивки для него из-за этого застопорилась: писать «на воздух» я не особо люблю, а текущая клавиатура уже не отвечает моим требованиям - банально не хватает кнопок.

И тогда в голову начала приходить мысль - а не организовать ли мне эмулятор по типу того, который используется в Android Studio? Идея показалась мне классной, но останавливало отсутствие внятной документации по qemu, поэтому для реализации задумки предлагалось соснуть сурца. В какой-то момент я понял, что без полноценной клавиатуры я не смогу продолжить проект - банально нет всех нужных кнопок - было принято решение засучить рукава и попробовать.

В штатной поставке esp-idf есть qemu, но в ней особо не развернёшься, поэтому начал с простого - используя простое i2c устройство в качестве шаблона, создал заглушки для клавиатуры, контроллера модема и контроллера питания. Подключить их тоже не составило труда - код как раз на скриншоте. Обмен данными по шине i2c оказался очень простым: на эмулируемом устройстве есть всего 2 функции обратного вызова - для чтения и для записи. Таким образом, когда мастер пишет и читает, то просто подсовываем ему то, что он просит. Таким образом реализовать эмуляцию i2c устройств оказалось легче лёгкого.

Далее прерывания. Для эмуляции линий gpio в qemu используются линии прерываний. Тут вроде всё просто: на эмулируемом устройстве создаются выходные линии qemu_irq и далее они подключаются… куда? Вот тут меня ждала первая, пусть и лёгкая, задача. В самом начале я подключил линию irq клавиатуры на матрицу прерываний. Обработчик прерываний вызывался, но понять, на каком gpio оно произошло он не мог. Немного пораскинув мозгами и пососав сурца покопав исходники, я нашёл правильное место для подключения - матрица gpio. Как видите, в функциях read и write ничего нет, поэтому реализовать матрицу предлагается самостоятельно. Ожидаемо :) Реализовывается она очень просто. Сначала в матрице gpio создаются 40 входных и 40 выходных лини qemu_irq, которые будут отвечать за все gpio, которые есть у esp32. Далее создаются ещё 2 выходные линии qemu_irq, которые отвечают за обычные и non-maskable прерывания. Их я подключил к матрице прерываний на специально предусмотренные для этого каналы.

Теперь возвращаемся к функцуиям read и write. Вы когда-нибудь работали с расширителями портов, которые подключаются по шинам spi и i2c? Вся суть сводится к тому, что вы просто пишете и читаете нужные регистры по шинам, верно? Вот тут всё тоже самое, только с одним маленьким отличием - сами регистры нахадятся в самом микроконтроллере и процессор имеет к ним прямой доступ. То есть матрица gpio - это просто расширитель портов, который встроен в процессор и подключен напрямую к нему. Таким образом, вы теперь выступаете в качестве микросхемы :) В ваши регистры будут что-то писать и читать, а вы будете управлять линиями gpio. Когда процессор хочет выставить нужный gpio в нужный уровень - он просто пишет нужный бит в нужный регистр. Вы это видите и переключаете нужную линию qemu_irq в нужный уровень. Если же входная линия изменяет свой уровень, то вы просто отмечаете это у себя в структуре и при чтении сможете вернуть процессору текущие уровни gpio. Если процессор настроил прерывание на каком-либо gpio, то его можно уведомить об этом с помощью линий irq и nmi-irq. Далее процессор прочитает регистр прерываний и попросит вас сбросить их и вы это сделаете :) (иначе он будет постоянно опрашивать регистры прерываний, думая, что они всё ещё активны). Таким образом, реализовать матрицу gpio не составило особого труда. После этого я подключил свои устройства к нужным линиям матрицы gpio и смог эмулировать работу gpio без проблем.

Итак, я уже потирал руки и думал: «Сейчас я кабанчиком организую эмуляцию дисплея на шине spi и можно будет браться за гуй.». Ок, по аналогии с устройством i2c, беру в качестве шаблона какое-нибудь spi-устройство и начинаю реализовывать дисплей. Общение происходит как по i2c, только вместо обратных вызовов read и write, у вас есть обратный вызов transfer, в котором одновременно происходит и приём и передача данных. Сделал я дисплей, запускаю и… тишина! То есть по шине мне передаются сплошные нули! Всмысле? 0_0 В этот раз пососать сурца покопаться в исходниках пришлось гораздо более основательно. В итоге, понатыкав везде и всюду спасительный printf(), я нашёл чёрную дыру, в которой терялись данные по дороге от гостя до эмулируемого дисплея. На первый взгляд кажется, что тут всё ок, но когда я расставил printf() для распечатки адресов регистров, которые пишет и читает процессор, то всё встало на свои места - этот код никаким образом не обрабатывает регистры DMA! То есть вообще. Получается, что гость пытается слать данные через DMA буфер, а ванильный эмулятор spi туда даже не смотрит. В итоге, я сделал его копию и написал свою реализацию, которая позволяет отправлять данные по spi с использованием dma (полную реализацию пилить не стал, ибо влом). И для этого пришлось решить задачу со звёздочкой - доступ к памяти гостя.

Пару слов о том, как работает DMA на esp32. Прошивка организовывает где-нибудь в памяти специальные структуры с указателями на сами данные и входной буфер. Далее в специальнные DMA-регистры записываются адреса (указатели) этих структур. Далее подаётся команда на запуск передачи и данные передаются/принимаются без участия процессора. Теперь передо мной встала задача - как получить доступ по указателям, которые мне передаёт гость? Ведь гость даёт адрес внутри адресного пространства виртуальной машины. Сначала я нашёл решение с помощью функций cpu_physical_memory_read() и cpu_physical_memory_write(), которые работают с указателями из адресного пространства гостя. Но лишнее копирование не давало мне покоя и я нашёл решение получше.

При создании виртуальной машины qemu создаются различные области памяти. Одна из них - оперативка. Создаётся с помощью memory_region_init_ram(). В esp32 создаётся несколько различных областей такого типа. Фишка в том, что все эти области выделены как обычная память на хосте. Идея заключается в том, чтоб использовать memory_region_get_ram_ptr(), чтоб получить указатель на каждую область. Затем, зная начальный и конечный адрес каждого региона, можно вычислить расположение данных в оперативке хоста и работать с ними напрямую.

Последняя задача - как передать эти указатели, которые возвращают вызовы memory_region_get_ram_ptr(), в сам эмулятор spi? Он выполнен как отдельное устройство. В этот раз сосание сурца ковыряние в исходниках и чтение крох документации ничего не дали, поэтому решил действовать в лоб - передавать через свойства устройства. В эмуляторе spi я сделал несколько свойств с помощью object_property_add(), при создании машины при инициализации spi просто передал указатели как uint64_t с помощью qdev_prop_set_uint64(). Не уверен, что поступал правильно, но других решений не нашёл. Возможно, в таких случаях следует создавать отдельное устройство - эмулятор DMA, не знаю. Тем не менее, это сработало - я смог получить доступ к памяти гостя, высчитав смещение и прибавив его к одному из указателей на область памяти.

Гуй сделал на Tcl/Tk. Общение в машиной идёт через fifo. Просто и понятно. Уверен, что у qemu есть свой api для построения гуя, но я, честно говоря, к этому моменту уже окончательно устал искать информацию раз, и хотелось немного попрактиковаться в тикле два. До этого в тикле не работал с цветными изображениями и это был неплохой повод попробовать. Оказалось, что всё делается элементарно через image. Благо по тиклю информация есть, в отличие от.

К чему я вообще пишу обо всё об этом? Похвастаться? Да, не без этого, но ещё больше хочется поделиться вот чем. До того, как я полез писать эмулятор, я многое знал, но не понимал как именно работают те или иные вещи в микроконтроллерах. После того, как я написал эмулятор, я многое понял. Например, как именно процессор управляет своей перефирией. Как работают прерывания. Как работает DMA. Да и вообще, получил опыт в работе с «сырыми» регистрами. Я это к тому, что если у вас есть какая-нибудь идея и вам хочется её осуществить, то всегда пробуйте! Даже если задача изначально кажется сложной и неподъёмной. Запросто может оказаться так, что вы, как и я, не просто реализуете задуманное, но ещё получите ценные знания и/или опыт в процессе.

Такие дела \ё/

 , ,

u5er
()

Борьба с ботнетами на почтовиках

Решил тряхнуть стариной и разместить картиночку =). Процесс доработки (одной из частей) эдакого распределенного файрвола для почтовой системы. Справа в редакторе код, слева консоли на серверах где этот код запущен.

Железка ноут HP, Debian 11 и Cinnamon. Редактор самописанный на Tcl/Tk.

 , , ,

svk28
()

RedFlux - интерфейс к Redshift в духе f.lux

Периодически пользуюсь то виндой, то линуксом и был удивлён отсутствию на Linux фильтра синего с вменяемым интерфейсом и возможностями. А без него глазам уже неприятно, к хорошему привыкаешь.

Версия f.lux на Linux не имеет графического интерфейса и вообще намертво привязана к геолокации. Для меня эта привязка вообще неактуальна, так как в моей комнате обычно закрыты шторы и в итоге темно (если я вообще дома днём), а вечером включается лампа и оказывается светлее. Redshift также по дефолту привязан к геолокации, но температуру выставлять позволил, хоть и не слишком удобно. Так что...

Сделал вот враппер для редшифта, чтобы его удобно было использовать, выставляя температуру вручную с пресетами как в f.lux.

Точнее, тут даже два скрипта - redflux консольный, который позволяет ставить кастомную температуру и на который удобно биндить хоткеи в WM, и redflux-gui в виде интерфейса со скриншота. redflux-gui писался сильно позже и сам является враппером над redflux. Написано всё целиком на Bash, в том числе графический интерфейс. Для GUI используется обёртка над tk под названием tkbash (https://github.com/phil294/tkbash). По итогу не особо нативный, но для утилитки пойдёт. Для иконки в трее используется yad. Сначала думал всё на нём писать, но быстро понял, что он в основном для диалогов.

В какой-то момент наткнулся на RedShiftGUI (http://maoserr.com/projects/redshiftgui/), увидев его в Puppy Linux. Попадись он мне раньше, ничего бы не стал писать. Однако так и пришось бы жить без пресетов, а, возможно, и ещё каких фич - прямое сравнение не проводил. А пресеты у f.lux очень вкусные, взял в итоге их.

По самому скрину смотреть особо нечего - юзаемый мной уже в течение лет восьми LXDE, в качестве дистрибутива Arch Linux. Визуализатор звука - glava, красивый миниплеер это из гугломузыки, по возможности превращённый в виджет через конфигу Openbox.

Для новости довольно мелко, а для скринов поди пойдёт.

Ссылка на GitHub: https://github.com/Nebula-Mechanica/RedFlux

 , f.lux, , ,

nebularia
()

Прикладная некромания

На скриншоте взрыв из прошлого - программа Arb для молекулярной филогенетики. Всего-то 2004го года выпуска. На скриншоте подбор видо-специфических праймеров к генам 16s РНК. Tk жил, Tk жив, Tk будет жить!

 

DNA_Seq
()