Колибри для встроенных систем?

Using Kolibri in embedded systems
  • Asper
    В строительстве Москвы участвовали зодчие.
    Galkov
    *протягивает красную пилюлю* Добро пожаловать в реальный мир стан разработчиков Колибри. Здесь практически не бывает конструктивных обсуждений, особенно насчёт ядра, в котором разбираются немногие.
    2) Что-то не видно шквала предложений решений проблем. И людей, желающих высказаться по существу проблем, тоже не видно. Можно, конечно, ждать и слушать, но не стоит ни надеяться на решение от других, ни обвинять других в отсутствии конструктивного диалога. Особенно если речь идёт о замене старого трухлявого бревна новым продвинутым (при перестройке угла дома шансы услышать ответ на предложение высказываться несколько выше).
    5) Всякие действия продиктованы какой-то целью, но не всякие действия достигают своей цели. Не всякой глобальной цели можно достигнуть, преследуя локальные.
    7) CURRENT_TASK - вполне себе говорящее имя переменной. Ну а по поводу мысленного эксперимента - если представить незнакомому человеку Ивана Иванова как Петра Петрова, то не стоит удивляться тому, что этому человеку будет несколько сложно потом соотнести фамилию Ивана Иванова с реальным Ивановым.
    8) Угу.
    9) Угу. Разумеется, при условии, что после изменений всё по-прежнему будет работать.
    10) Убивает, и это факт.

    V86 предназначен в первую очередь для работы с железом через BIOS. Когда BIOS запрещает прерывания, менеджер тоже глобально запрещает прерывания, считая, что BIOS знает, что делает. Теоретически V86 может подвесить систему, если это может BIOS; но если верить BIOSу, то управление всегда вернётся, это относится и к обработке прерываний в том числе. Вмешивание во внутренности переключателя задач нужно для того, чтобы немедленно обрабатывать прерывания от железа - обработать прерывания, инициированные BIOS, может только сама BIOS, и ей нужно вернуть управление. VIP не используется, ибо не нужен, когда cli в виртуальной машине сводится к cli в реальной (да и вообще ни при чём, если iopl=3).
    Ушёл к умным, знающим и культурным людям.
  • Насчет зодчих и проектирования, это хорошо. Пугает только лишь максимализм начинания разработки с нуля. Походит на анархию какую-то. С нуля начинать тяжело, потому как во всяком случае на первых порах прийдется работать над всем чуть ли не в одиночку. Если же речь идет лишь о генеральной перестройке ядра, то тут дела обстоят проще. В первую очередь необходимо сохранить API для прикладников, чтобы не потерять ту часть сообщества, что не вовлечена в процесс ядерного кодирования.
  • Я не считаю, что нужно сохранить API, многое можно перенести в библиотеки. Тем более разработка нового это не всегда с 0 разработка. Очень хороший пласт можно взять существующих решений, обкатанных и показавших свою функциональность. Еще такой вопрос, сейчас процессоры выпускаются с поддержкой режима AMD64/EMT64 (даже интел атом), т.к. разработка ведется достаточное время и имеет смысл ориентироваться на этот режим работы ЦП. Можно конечно вести 2 проекта для режима IA-32 и AMD64/EMT64, но это имхо распыление сил. Я считаю, что нужно проектировать ядро только для AMD64/EMT64 режимов ЦП.
  • Да бросьте, кто там говорило про упадческие настроения? Mario79 и diamond просто констатируют факты.
  • Galkov

    Имена в верхнем регистре - мои. Некоторые из них не совсем удачные (я опирался на memmap.inc) но на этот счёт есть отмазка
    Когда я использую слово, оно значит именно то, что я хочу, чтоб оно значило. — ни больше, ни меньше
    и ещё одна отмазка. Если интересно что было раньше - смотри svn rev 163.
  • 2Serge - да, я читал.
    Что тут можно сказать - снимаю шляпу.
    Та ситуация, в которой пребывали Вы... Да сегодняшнее мое "неудовольствие" - просто капризы избалованного ребенка, по сравнении с Вашей тогда :)

    Конечно привыкну, а сейчас я просто высказал мнение (пока еще помню) человека, у которого глаз не успел замылиться

    А все-таки, если я возьму и тупо, но глобально - поменяю эти имена :?:
    Мне кажется, что название как-то должно отражать и тип хранимых данных. Все ж таки Adr и Index (который у нас фактически байт) - это разные вещи даже по смыслу...
    А у нас ведь сегодня даже имена адресов начала массива структур TASKDATA и APPDATA - имеют разные суффиксы: CURRENT_TASK и SLOT_BASE. И что занимательно, TASK_BASE у нас тоже есть, но по смыслу - ничего общего с SLOT_BASE.
    Это сегодня занимательно, а по началу......... "мне нужны его глаза" :D

    Не, ну не совсем тупо, про двоякое назначение магического слова CURRENT_TASK - я помню.

    Блин, вот возьму, и поменяю :D
  • Любой русский программист, после пары минут чтения кода, обязательно вскочит и произнесет, обращаясь к себе: переписать это все нафиг. Потом в нем шевельнется сомнение в том, сколько времени это займет, и остаток дня русский программист потратит на то, что будет доказывать самому себе, что это только кажется, что переписать это много работы. А если взяться и посидеть немного, то все получится. Зато код будет красивый и правильный.

    API сохранять нельзя, потому что у них есть некоторые фундаментальные ограничения. В этом одна из проблем.
    Galkov
    Если тебе так удобнее - меняй. Смысла я в этом не вижу, но и вреда тоже не вижу.
    И может быть, если "это реализовано в корне неправильно" - было бы еще интереснее.
    Эту часть - пожалуйста. Из общих соображений - общая непродуманность, практически полное отсутствие проверок входных параметров из юзермодного кода ("ядро держится на честном слове прикладных программ") наряду с отсутствием средств что-то сделать против передачи некорректного юзермодного указателя, отсутствие многих необходимых вещей, например, синхронизирующих примитивов, отсутствие понятия привилегированных и ограниченных в правах приложениях, любое приложение может делать с системой всё, что хочет, общая непродуманность API (достаточно взглянуть на список по номерам, чтобы убедиться, что это дикая смесь всего чего попало в довольно произвольном порядке), полное отсутствие понятия процесса как такового (есть только потоки, и модификация, скажем, показателя занимаемой памяти, который на самом деле относится к процессу, превращается в запутанный цикл по всем потокам), при любом запросе к файлу каждый раз парсится имя файла, разбираются все вышележащие папки из-за полного отсутствия хэндлов и соответствующих управляющих структур, код FAT12 завязан на драйвер флопа, код ISO9660 - на драйвер CD... В частностях... Так, пройдём по исходникам в алфавитном порядке:
    blkdev/cd_drv.inc - все данные передаются в глобальных переменных, которые ещё и сидят внутри кода, а не данных, кое-где используется 16-битные регистры, что раздувает и тормозит код, ожидание готовности делается опросом и циклом с change_task, поиск в кэше - линейный перебор, насколько нужны присутствующие cli/sti и насколько не нужны закомментированные, не могу определить.
    blkdev/cdrom.inc - функция для проигрывания аудио-CD напрямую приводом, содержит ещё одну функцию посылки atapi-команды, независимую от предыдущего файла, снова кое-где 16-битную адресацию можно и убрать, повсюду понатыканы вызовы delay_ms, в которых мало того, что константы задержек взяты, скорее всего, с потолка, так ещё и процессорное время расходуют зазря (кое-где внутри блоков cli/sti)
    blkdev/fdc.inc - юзабельно, хотя данные драйверу флопика передаются опять же через глобальные переменные
    blkdev/flp_drv.inc - цикл с change_task, 16-битные регистры в отдельных местах
    blkdev/hd_drv.inc - линейный поиск в кэше
    blkdev/ide_cache.inc - юзабельно, хотя слишком много повторяющегося кода
    blkdev/rd.inc - жёстко прописаны фиксированный абсолютный адрес и размер рамдиска, полностью отсутствуют блокировки, всё ещё поддерживается устаревшее чтение функцией то ли 58, то ли ещё более древней
    blkdev/rdsave.inc - отсутствуют блокировки
    boot/ - юзабельно, за исключением boot/rdload.inc с передачей параметров через глобальные переменные, повторяющийся код и загрузка образа происходит через устаревшую функцию, понимающую только FAT
    bus/pci - юзабельно
    core/conf_lib.inc - использует старую версию libini
    core/debug.inc - юзабельно, но использует неработающую check_region
    core/dll.inc - использует цикл с change_task в get_notify, load_library совершенно не заботится о том, что библиотека, возможно, уже загружена и даже, возможно, в адресное пространство текущего процесса
    core/export.inc - юзабельно
    core/exports.inc - юзабельно
    core/ext_lib.inc - статический буфер без проверок переполнения, неработающая mem.ReAlloc, да и вообще идея подгружать юзермодную libini в пространство ядра и давать ей выполняться выглядит сомнительно
    core/fpu.inc - юзабельно
    core/heap.inc - отсутствуют блокировки при работе с кучей приложения
    core/malloc.inc - юзабельно, хотя следует помнить, что под всю кучу малых блоков выделяется ровно 256 Кб, не больше и не меньше, и никогда не расширяется и не сужается
    core/memory.inc - юзабельно
    core/peload.inc - юзабельно, если работает (в данный момент не используется)
    core/sched.inc - тупой планировщик, по циклу переключающий все имеющиеся задачи
    И так далее, и тому подобное.
    Ушёл к умным, знающим и культурным людям.
  • 2diamond

    2) Не, не обвиняю. Но призываю... Пытаясь аргументировать тем, что, в общем-то - ничего особо нового, существуют давно испытанные "схемы общения"

    5) Все правильно. Договоримся на том, что ни абсолютный "минус", ни абсолютный "плюс" - это не есть правда жизни. Мне кажется, что правда в том, что в какую сторону (плюс или минус) мы будем двигаться - от нас ТОЖЕ зависит.

    8,9) Ну держитесь :D что абсолютных гарантий не бывает, рассуждать неуместно, надо полагать.
    А вот отвечать (фиксить до победного конца) за свои коды - это само собой.
    Куда оно денется, с подводной лодки-то....

    10) Про то, что мы считаем, что BIOS "знает что делает" - это я уже успел вкурить. И про то, что из того, что "эти знания биоса" нам недоступны, следует необходимость нарушения "стройной" работы shed-а

    Вопрос в другом.
    Знания и ответственность (да, он молодец, и обработчик прерывания сделал быстрым и коротким) биоса кончаются после выхода из прерывания (iret внутри биоса). Дальше - это уже слот, и даже после выхода из vm86, и возврата в 3-е кольцо.
    Задача-то переключена безвозвратно.
    Ну предположим, еще несколько слотов на карусели загрузят проц по полной программе. Дальше - опять это прерывание, и опять те же несколько слотов.
    И так, предположим - всю жизнь.

    Это - следствие вмешательства в работу shed-а
    Ну я не просто так спросил про VIP - именно на выходе из прерывания (про IOPL я в курсе, что одно без другого не бывает) и кончается ответственность биоса, и начинается - приложения. А на самом деле - начинается безответственность.

    Собственно, тут два вопроса:
    а) Следует ли мне думать про локализацию в shed-е некой do_call_task (чтобы возвращать карусель на "старое место") наряду с do_change_task
    б) Следует ли также думать про активизацию VIP в vm86 - чтобы выполнить некий "do_ret_task", по окончании ответственности биоса....

    "Следует ли" в том смысле, что не получат ли последующие действия характеристику "это реализовано в корне неправильно"



    P.S. ну вот и хорошо.
    Та треть из перечисленного, которая мне понятна - полностью совпадает с моим пониманием.
    И это радует :)
  • Galkov

    Если заиматься переименованием, есть смысл разгрести всю свалку от OS_BASE до DONT_SWITCH. В Колибри РЕ получилось перетащить всё это в сегмент .data и первые 64 Кб не используются и след-но не копируются по BOOT_VAR.
  • 2) У любого метода есть границы применимости.
    5) Не понял, откуда внезапно появились абсолютный плюс, абсолютный минус и движение к ним, и какое отношение всё это имеет к предыдущему разговору.
    10) VIP - аббревиатура, конечно, красивая, но настоятельно рекомендую почитать мануалы, чтобы понять, что она означает. Не по существу тут флаги VIF и VIP. Если уж отбирать управление и передавать его назад по карусели, то в момент выхода из V86-режима. Настоящий статус работы через BIOS - заплатка, пока нет полноценной поддержки нативными драйверами, но очень живучая заплатка, так что ещё одна мелкая заплатка для переключения задач туда/сюда в связи с вызовами bios особой роли не играет.
    Ушёл к умным, знающим и культурным людям.
  • 2diamond

    2) Предположим. Отрицательные результаты НЕ соблюдения "давно известных принципов" - наблюдал. Отрицательные результаты ПРИ соблюдении - пока нет.

    5) Улучшение по частям никогда не приведет к качественным изменениям - это "абсолютный минус". Улучшение по частям всегда и обязательно приведет к качественным изменениям - это "абсолютный плюс"
    Говорили вроде про это.
    Про "взять и переписать все заново" - это точно не про меня. Хотя... Да нет, не про меня.

    10) Хм, опять :wink:
    Не побоюсь повториться, но я умею Читать, ВСЕ-ТАКИ.
    Чтобы перехватить исключением возврат из 16-битного прерывания, необходим взведенный флаг Virtual Interrupt Present, а сохраненный в 16-ном стеке регистр Flag должен открывать прерывания (а на самом деле - Virtual Interrupt Flag)
    Так ли надо делать, или по другому, но другого способа "поймать iret" мне в голову пока не пришло. И все термины использованы были правильно.

    НО, должен согласиться, поймать выход из vm86 - по-проще будет, пожалуй...
    И, если 16-битный код - это код системы, а не пользователя - то и вполне допустимо, наверное.
    Видимо, в этом направлении и следует думать.
  • 2Serge

    Слушай, я понял смысл, но морально не готов пока. Будем надеяться - ПОКА. Хотя и согласен - сие достойно трудов

    Надо же не просто перетащить переменные в uglobal, но и проанализировать их использование, убрать копирование BOOT_VAR, а его самого перетащить на их место...
    А v86 попросить делать свои "записи" куда-нибудь в другое место....
    До такой эрудиции я еще не дошел :(
    Судорожно заниматься изучением кодов в тот момент, когда надо фиксить багу - не дело, имхо. Дай бог ее оперативно найти, когда коды почти наизусть знаешь :)
    Нельзя же исключать того, что где-то просто затерялся артефакт абсолютных ссылок еще с Ваших времен.

    А "просто переименование" имеет очень простой критерий "безобидности" - бинарные коды не должны измениться. Вообще.
    Фактически там только одна нетривиальность. Коды типа

    Code: Select all

         mov  edi,[CURRENT_TASK]
         mov  edx,[ecx+CURRENT_TASK+TASKDATA.pid]
    Должны переименовываться к разным именам
    А все остальное - прошелестел в far-е групповыми заменами, и всего делов...
  • 2) Тогда всё ещё впереди. Отрицательных результатов не гарантирую (хотя и такое бывает), но нулевые будут точно. Что-то меня на цитаты тянет...
    О, сколько нам открытий чудных
    Готовят просвещенья дух,
    И опыт, сын ошибок трудных...

    5) Если так определять абсолютные плюс и минус, то не в нашей власти выбирать, к какому из них двигаться - локальные изменения либо приведут к глобальным качественным, либо не приведут. Я склонен считать, что в данном конкретном случае - нет.
    10) *включает лекторский тон и готовится к очередной простыне текста*
    Значит, так. Давным-давно был процессор 8086, был реальный режим и в этом режиме исполнялся различный код. Иногда этот код запрещал прерывания, иногда их разрешал. Прерывания запрещались по двум возможным причинам: во-первых, коду могло понадобиться, чтобы у него совершенно точно не отобрали управление на каком-то промежутке (например, опрашивает какое-то устройство, которое должно вот-вот ответить), а во-вторых, код мог просто не хотеть конкуренции с другим кодом (например, он переключает стек или выполняет нереентерабельную процедуру).
    Прошло некоторое время. Появился 80386. В нём уже был защищённый режим (на самом деле этот режим появился в 80286, но v86 там не было) и встал вопрос о совместимости со старым кодом, для решения которого был придуман специальный режим V86. Основная фича V86 заключается в том, что это подрежим защищённого, в котором адреса из сегментных в линейные преобразуются как в реальном режиме. Защищённый режим на то и защищённый, что в нём абы кто не имеет права обращаться напрямую к оборудованию, а доступ контролируется полем IOPL: если код не менее привилегирован, чем IOPL (численно это неравенство CPL<=IOPL), то ему разрешаются инструкции cli/sti/hlt, которые запрещают/разрешают прерывания, в противном случае эти инструкции генерируют #GP. Но cli/sti всего лишь очищают/устанавливают 9-й бит в регистре flags, а на этот регистр воздействуют ещё и команды pushf, popf, int и iret. Для нового кода просто постулируется, что при cpl>iopl popf и iret игнорируют соответствующие биты, и новый код должен быть к этому готов. Но что делать со старым кодом? Сделали так: при cpl<=iopl (что для V86-кода эквивалентно IOPL=3) cli/sti/hlt/pushf/popf/int/iret делают то, что они и раньше делали, а при cpl>iopl все эти инструкции вызывают #GP, и V86-менеджер (обработчик #GP из V86-машин) уже может сам решать, сделано ли это для того, чтобы прерывания от других устройств не мешали (и тогда глобально выключать/включать прерывания) или чтобы другой код не мешал (и тогда вне этой машины вполне себе могут выполняться прочие действия).
    Всё это разработчики стали обкатывать, и в конечном счёте выяснилось, что основной сценарий использования - использование этого режима для запуска старых программ в осях защищённого режима, которые с железом работают самостоятельно и программы к нему напрямую не допускают. Соответственно на практике всегда IOPL=0, нужен только второй вариант использования запрещения прерываний, для каждой V86-машины внутри системы есть флаг занятости, показывающий, что ничего другого внутри этой машины в данный момент выполнять нельзя (но можно переключаться на другие задачи). V86-менеджер при этом занят вполне фиксированными делами: распознаёт, какая инструкция вызвала исключение, эмулирует её, при cli/sti/popf/iret анализирует предлагаемое значение для IF и в соответствии с ним устанавливает/сбрасывает флаг занятости, при pushf и int подсовывает вместо "настоящего" флага IF его эмулируемое значение. Кроме того, полезно, скажем, при прерывании от таймера уведомлять об этом V86-машины, чтобы выполняющиеся там программы могли отсчитывать время, так что появляется необходимость в менеджере при разрешении прерываний доставлять какие-нибудь события внутрь V86. Наконец, довольно удобной оказалась возможность программные прерывания int N эмулировать прямо из менеджера. В результате всё это работает, но, во-первых, нужно писать некоторый обвязочный код, а во-вторых, при каждом чихе вызывать исключение - не самое быстрое решение.
    Опять прошло некоторое время. Инженеры из Intel на всё это посмотрели, подумали, и появился процессор Pentium, в котором в числе прочего есть расширения V86. Фактически они сводятся к тому, что то, что раньше делал менеджер V86, теперь делает сам процессор - при iopl=3 ничего не изменилось, а при iopl<3, если включена поддержка расширений, то вместо флага внутри системы появляется флаг VIF внутри регистра eflags, и cli/sti/popf/iret вместо того, чтобы вызывать #GP, обработчик которого сведётся к изменению флага занятости, сразу меняют флаг VIF. На реальный флаг IF они в полном соответствии с тем, что код непривилегированный, не влияют. Соответственно pushf на место IF подставляет VIF. С int ситуация несколько интересней, поскольку можно обеспечить и возможность вызова обработчиков [псевдо]реального режима, не выходя из V86, так и возможность перехватчиков защищённого режима, но это выходит за рамки настоящего разговора, а мануалы таки никто не отменял. Кроме того, для того, чтобы можно было доставлять уведомления о прерываниях типа таймера, sti/popf/iret, устанавливающие IF, проверяют ещё один флаг внутри регистра eflags под названием VIP, и если он установлен, то считают, что система хочет доставить прерывание, и генерируют #GP в качестве уведомления, что зажёгся зелёный свет; когда система хочет доставить прерывание, если флаг VIF в задаче сброшен, то, вообще говоря, сразу этого делать нельзя, но можно установить VIP, и процессор сам сообщит, когда появится возможность.
    Думаю, после всей этой лекции должно быть понятно, что к ситуации в Колибри, где V86 используется исключительно для работы с железом, VIF и VIP не имеют никакого отношения. Собственно, включать их обработку просто нельзя из-за того, что BIOSовские cli/sti должны быть реальными cli/sti. Ну а насчёт перехвата iret - при iopl<3 это происходит автоматически, ибо генерируется #GP, а в общем случае можно вспомнить, что доставкой прерывания в V86 занимается не процессор, а система, и записывать в V86-стек не настоящие cs:ip, а подложные, ведущие куда-нибудь на инструкцию, заведомо вызывающую исключение (это может быть специальный int или просто invalid opcode, главное, чтобы система помнила адрес) - тогда iret вернётся, куда ей скажут.
    Ушёл к умным, знающим и культурным людям.
  • Хм...
    В общем, главное, что я вынес из этого: ну его нафиг этот VME.
    Действительно, "не настоящие" манипуляции c IF требуют большого тестирования - как минимум. На которое у меня, к примеру - ни малейшего настроения.
    Ну и хорошо, пусть будут настоящие.
    Но эта же логика должна нас привести к необходимости полной остановки shed-а после "подвешивания прерывания" в 16-битном стеке.
    В принципе, так оно и будет, если обработчик прерывания биоса не открывает прерывания специально. Настоящие, зачем-то.
    А какие гарантии...
    Ну скажем такая схема:
    • а) вот оно vm86-прерывание
      б) переключаем задачу форсировано для его обработки
      в) ловим именно нужный iret - и возвращаемся в задачу, на которой все это и случилось
    Все вроде правильно, с точки зрения shed-а... как и обычное прерывание, просто сделанное шибко мудрено.
    Если не происходило переключения задач в середине этого процесса...

    А про то, что нет проблем с поймать iret при отключенном VME - я просто позабыл. Премудрости виртуала вытеснили из башки более простые вещи.
  • Who is online

    Users browsing this forum: No registered users and 6 guests