Уважаемые господа, прошу помощи. Итак, я стал счастливым обладателем SK-AT91SAM9G45.
Плата очень понравилась - её можно использовать даже не обладая навыками системного программирования. Разработчики обо всём позаботились, поэтому достаточно просто собирать в кросс-компиляции приложения, заливать их по FTP и чувствовать себя замечательно.
Но мы не ищем лёгких путей, поэтому плата была приобретена с одной целью - запуском на ней микроядра L4 и перенос системы Xameleon. А теперь я расскажу о проблемах, которые встретились на этом пути и попрошу помочь.
Исходный код микроядра был взят на этой странице: http://wiki.ok-labs.com/Microkernel файл okl4_3.0.tar.gz
Перед закачкой спрашивают некоторую информацию.
Поскольку средства разработки, которые поставляются вместе с платой, оказались несовместимы с okl4_3.0, пришлось скачать средства разработки:
После окончания сборки, в директории okl4_3.0/build появляются загрузочные образы. Бинарный файл, готовый для обработки командой mkimage, находится в okl4_3.0/build/images/image.boot.bin
Далее, формируется загрузочный файл для u-boot
mkimage -A arm -O linux -T kernel -C none -n "OKL4:Pistachio" \
-a 0x70008000 -e 0x70008000 \
-d okl4_3.0/build/images/image.boot.bin \
at91_sd.bin
Ответ помог, но проблему до конца не решил. Собственно говоря, привожу фрагмент сборочного скрипта, в котором задаются параметры платы (okl4_3.0/platform/vrsatile/tools/machines.py):
Это уже правленый по моему разумению код. memory['physical'] подсмотрел в образа ядра Linux, который поставляется вместе в SK-AT91SAM9G45.
Ну и собственно вопрос-мольба-о-помощи. Как запустить OKL4 на AT91SAM9G45?
Подозрений несколько:
1. Не разобрался с memory map и гружу не туда. (неужели?)
2. Неправильно заданы прерывания/адреса портов в okl4_3.0/platform/vrsatile/tools/machines.py (очень может быть)
3. OKL4 не поддерживает UART AT91SAM9G45 (маловероятно).
4. Микоядром используется другая скорость и/или параметры порта (flow control), нежели u-boot утилита, соответственно, терминал просто "не видит" данные, идущие от платы. (как проверить?)
Вы похоже полностью проигнорировали то что я вам писал о портировании микроядра - versatile и at91sam9g45 это абсолютно разные платформы, простым изменением адресов io memory и векторов прерываний не обойтись, нужно переписывать минимальный BSP но по второму кругу объяснять нет желания.
Там же по вашему вопросу написали ответ
Да, пожалуй, Вы правы. Сначала я кинулся писать длинный ответ на Ваше замечание, но, перечитав Ваши ответы и просмотрев код, пришёл к выводу, что "допиливать" OKL4 особого смысла нет - как выяснилось, трудозатраты на портирование L4Ka:Pistachio и OKL4 соизмеримы. При этом лицензия OKL4 похуже, чем у Pistachio, к тому же разработчики OKL4 потянули в ядро свои user space библиотеки, что тоже не очень хорошо.
Я бы на вашем месте присмотрелся к fiasco.OC - это текущий вариант L4 Дрезденского университета , насколько я начитал - это далеко не то же l4:fiasco API v2 про которое вы говорили что оно устаревшее. http://os.inf.tu-dresden.de/pipermail/l4-hackers/2011/004636.html
Прсто закрыть исходники не получится - но это же только плюс :)
Ого! Встроенный debugger заработал! А с терминалом он через polling работает или по прерываниям?
Прерывания от таймера подтверждаются? Если да, то вроде и всё. Остальные прерывания подтверждаются посылкой ответного IPC потоку, от которого пришло прерывания.
Покопался в сырцах микроядра - не совсем понятно, как "внутри" подтверждаются прерывания для ARM, для x86 всё просто и прозрачно.
А на уровне пользователя вообще элементарно, вне зависимости от платформы:
L4_StoreMR(0, &mr);
if( mr == 0xfff00000 )
{
// вызываем обработчик прерывания
// на основе TID можно определить номер прерывания, если драйвер обслуживает несколько устройств
interrupt_handler( TID );
// -- подтверждаем прерывание --
L4_LoadMR(0, 0);
L4_Send( TID );
}
else
{
// здесь может быть обработчик системных вызовов - read, write, ioctl и так далее
}
Во всяком случае в Pistachio прерывания на уровне драйверов обслуживаются именно так.
Странно как-то. Для платформ x86 подтверждение прерываний реализовано в intctrl-pic.h и intctrl-apic.h.
class intctrl_t : public generic_intctrl_t {
private:
i8259_pic_t<0x20> master;
i8259_pic_t<0xa0> slave;
...
void ack(word_t irq) {
if (irq >= 8)
{
slave.ack(irq-8);
master.ack(2);
}
else
master.ack(irq);
};
...
}
а вот что касается платформы arm, то, похоже, метод ack не переопределён и, соответсвенно, вместо него вызывается "заглушка", которая ничего не делает.
Если я правильно понял проблему, то в используемом intctrl.h необходимо реализовать этот метод.
Удивляет лишь одно - почему он нигде не определён для архитектуры arm? Как работает l4ka, если прерывания не подтверждаются? Странно это.
UPDATE:
Пошукал в сырцах и что-то мне не очень нравится то что нашёл:
drivers/sp804_timer/src/sp804_timer.c:
...
/* ack the interrupt */
tintclr_write(0x0);
...
drivers/imx31_timer/src/imx31_timer.c:
здесь вообще непонятно что происходит
static int
device_interrupt_impl (struct device_interface *di, struct imx31_timer *device, int irq)
drivers/pxa250_timer/src/main.c:
...
/* Ack the interrupt. */
sr_write(0x2);
...
Жуть. Бедный Pistachio! OKL вдоволь поиздевалась над ним.
Да ничего страшного :) Вы немного не поняли - подтвердить прерывания в контроллере прерываний это одно (это нужно делать в микроядре) а в контроллерах периферийных устроств (это делают в обработчиках прерываний этих устройств) это другое. Не для всех контроллеров прерываний нужно подтверждение. У atmel нужно, при этом порядок такой
1 The read of AIC_IVR is the entry point of the interrupt handling which allows the AIC to consider that the interrupt has been taken into account by the software.
2 The nIRQ line can be asserted only if an interrupt condition occurs on an interrupt source with a higher priority. If an interrupt condition happens (or is pending) during the interrupt treatment in progress, it is delayed until the software indicates to the AIC the end of the current service by writing the AIC_EOICR (End of Interrupt Command Register). The write of AIC_EOICR is the exit point of the interrupt handling.
В данном случае естественно переводить задачу по управлению AIC в юзерспейс чревато, если хотя бы раз не подтвердить прерывание - ни одно из них болше не появится на лини nIRQ проессора. Я посмотрел как сделано в фисташке для csb337 (плата на at91rm9200 - почти тоже самое что у нас но ядро старое 920t) и сделал так же - думаю это оптимальный вариант
static inline void mask(word_t irq)
{
ASSERT(irq < IRQS);
AIC(AIC_IDCR) = (1ul << irq);
AIC(AIC_EOICR) = 0; /* Signal that we have handled this interrupt */
}
т.е. после входа в обработчик маскируем сработавшее прерывание и "разрешаем" всем остальным появиться :) они все равно не сработают пока линия irq процессора не будет разблокирована - а об этом уже само ядро позаботится, когда сочтет нужным разрешить прерывания. Потом в фиаско отдельно ack тоже не используется хоть и реализована - там всегда используется mask+ack