Выпущен июньский релиз ядра под названием jun.2008 Fishes: Pike.
Основные нововведения релиза:
- Добавлена информация о лицензиях.
- Добавлена поддержка PS/2 мыши (экспериментальное).
- Добавлено обнаружение и чтение ATA-устройств в режиме PIO.
- Добавлено устройство /dev/apic/local, ссылающееся на Local APIC.
- Добавлено устройство /dev/apic/timer, ссылающееся на Local APIC Timer.
- Добавлено устройство чтения шины PCI /dev/pci (экспериментальное).
- Добавлены функции sys_* для будущей защиты функций k_* от хаков из user-space.
- Добавлена возможность классом TConsole выводить данные в порт COM1.
- Добавлен класс трассировки ввода-вывода в аппаратные порты для возможности получения лога протокола обмена с устройством.
- Добавлен шлюз 0×07:0×00000000 для организации системных вызовов.
- Добавлены макроопределения для вывода отладки непосредственно в порт COM1.
- Добавлен класс быстрых мьютексов (фьютексов) для возможного исключения взаимоблокировок при разделении ресурса между задачей и обработчиком прерывания.
- Добавлено простое разделение нагрузки между процессорами в SMP.
Изменения:
- Исправлены ошибки в первичном загрузчике, связанные с неправильным кэшированием таблицы FAT.
- Все существующие до этого функции sys_* были переименованы в функции k_*.
- Заменён планировщик на планировщики, ориентированные на SMP.
- Исправлены ошибки в драйвере floppy.
- Исправлены ошибки в хранении данных текстового режима.
Статьи по меткам ‘xsystem’
Новый релиз
Июнь 15th, 2008А вот, кажется, и решение…
Июнь 9th, 2008Как был такой анекдот:
Когда-то студент подумал. Ему понравилось, и он подумал ещё раз.
В общем, тут удалось пару часиков прикорнуть, и, о чудо, я, кажется додумался, как можно организовать блокировку прерываний для общего ресурса.
В чём суть? Да в том, что прерывание, вызываемое через interrupt gate, обладает свойством атомарности на процессоре. То есть, не произойдёт никаких других прерываний от внешних устройств, пока сброшен флаг IF (ситуации с исключениями в расчёт не берём).
Ситуацию с прерываниями мы научились решать. Если вектор прерывания доставляется всем процессорам, то чтобы заставить его обработать только один процессор, необходимо воспользоваться Try-Lock конструкцией:
в обработчике прерываний:
TMutex Mutex;
interrupt_handler:
if (Mutex.TryLock()) // Защита от запуска обработчика на других процессорах
{
// Обработчик прерывания
Mutex.Unlock(); // Разблокировка мьютекса
}
Таким образом, код обработчика выполняется тем процессором, который первым смог захватить объект Mutex (напомню, метод TryLock() — это блокировка без ожидания. То есть, если не удалось заблокировать мьютекс, то сразу же функция возвращает false, удалось — true).
Хорошо. Теперь необходимо решить обратную задачу. Необходимо параллельный код превратить в последовательный. Для этого достаточно воспользоваться некоторой модификацией приведённой ранее схемы.
В данном случае надо уже использовать не попытку блокировки ресурса, а уже полноценную блокировку с ожиданием, но при этом гарантировать, что обработчик и задача будут вызываться на разных процессорах. Осуществить это можно, как я уже говорил, сведя задачу к обработчику прерывания. А отличие между ними очень небольшое: в обработчике флаг IF сброшен, а в задаче — установлен. Поэтому код блокировки ресурса задачей надо обернуть в CLI + STI блок.
Итого получим асимметричную схему блокировки объекта Mutex1:
в обработчике прерывания:
if (Mutex.TryLock()) // Защита от запуска обработчика на других процессорах
{
// Обработчик прерывания
Mutex1.Lock();
// Код, использующий общие данные, требующие блокировки
Mutex1.Unlock(); // Разблокировка мьютекса блокировки данных
Mutex.Unlock(); // Разблокировка мьютекса прерываний
}
в задаче:
_asm cli; // Запрещение прерываний, мы как бы в обработчике
Mutex1.Lock();
// Код, использующий общие данные, требующие блокировки
Mutex1.Unlock(); // Разблокировка мьютекса блокировки данных
_asm sti; // Разрешение прерываний, мы как бы вышли из обработчика
Вот, в принципе, и всё решение, которое гарантирует, что:
1. Обработчик прерывания и задача будут выполняться одновременно на разных процессорах.
2. Код доступа к общим данным будет выполняться последовательно в зависимости от того, кто первым захватил ресурс.
UPD:
Соответственно, всё это выполняется в Kernel Mode (ring 0), а для асимметричной блокировки можно написать отдельный специальный класс блокировки.
Вот так всегда…
Июнь 9th, 2008То, что работает на одном процессоре, может гарантированно не работать на нескольких.
Стоило мне только разделить нагрузку между процессорами, и драйвер клавиатуры+мыши стал глючить.
В чём же прикол? А вот в следующем:
1. на одном проце задачи пытается модифицировать содержимое портов.
2. на другом проце в это время срабатывает прерывание, которому тоже нужны порты.
Следствие: оба проца пытаются биться за один и тот же порт.
Как разрешить данную ситуацию?
1. Ввести мьютекс и блокировать его при попытке обращения к портам. Данный метод очень опасен. Например, в случае, если обращение к портам со стороны задачи и прерывание происходят на одном и том же процессоре. В таком случае Dead Lock обеспечен.
2. Разрешить прерывания в обработчике. Опасна эта вещь повторной входимостью а также Dead Lock’ом, так как в случае однопроцессорной системы не будет приходить прерывание от таймера, пока не будет послан EOI в PIC. Если же слать EOI при входе в обработчик, Dead Lock так же обеспечен (повторная попытка заблокировать мьютекс).
3. Блокиовать прерывания от устройства-инициатора прерываний на время его программирования. Также чревато тем, что, возможно, ответ от устройства приходит именно с прерыванием.
Таким образом, все виды блокировок являются недопустимыми из-за их неполноценности. Обдумываю возможные другие варианты…
VBE и VESA.
Декабрь 20th, 2007Господа! Я в ауте! Если выставлять бит исользования LFB при включении режима, то всё прекрасно! Если не выставлять, то отваливаются прерывания
. В принципе, ну его нафиг
. Всё равно без LFB никакого кайфа нет
. Так что, кажися, проблема решена
.
Итак, подытожим: из защищённого режима можно спокойно вызывать функции 0x4f00, 0x4f01, 0x4f02 прерывания 0×10. Но не рекомендуется указывать режимы без использования LFB, иначе может случиться нечто, что приведёт к системному сбою.
UPD:
1. Обязательно надо включить обработчики прерываний в реальном режиме перед вызовом int 10h.
2. Если перепрограммирован контроллер — скопировать векторы прерываний реального режима на новые.
3. Использовать только LFB-режимы.
Real Mode
Декабрь 8th, 2007Продолжаю колдовство с VESA.
Поменял модель организации вызова 16-разрядного кода. Теперь Код располагается в специальном сегменте, который начинается с адреса 0×90000. В этом же сегменте создаётся аллокатор страниц и аллокатор блоков. Их можно использовать для выделения памяти в пределах этого сегмента (что весьма удобно). Например, можно выделить 512 байт под общую информацию VBE или под буфер для получения информации о режиме.
Проблема в другом: после вызова 10h почему-то отваливаются IRQ-прерывания, хотя процессор возвращается обратно в защищённый режим и продолжает цикл. Возможно, надо будет попробовать переинициализировать контроллер.
int 10h
Ноябрь 22nd, 2007VESA
Всё-таки, упирался-не упирался, а прикрутил к ядру возможность вызывать int 10h. При чём, параметры можно передавать вот в такой вот структурке:
#pragma pack(push, 1)
typedef struct TRealmodeRegState
{
WORD FLAGS;
WORD DI;
WORD SI;
WORD DX;
WORD CX;
WORD BX;
WORD AX;
} TRealmodeRegState;
#pragma pack(pop)
Теперь оська умеет вваливаться в графический режим по f11 и вываливаться из него (тоже по f11). В качестве тестового режима было решено взять 0×114 (800x600x16).
Пора писать драйвер VBE (/dev/vbe).
Multiprocessing
Процессоры научились входить в main. Мало того, в качестве аргумента в main теперь передаётся номер процессора, который определяется специальным атомарным семафором. Теперь надо задуматься о шедулере, ибо тот шедулер, что имеется на данный момент, совсем не годится для мультипроцессорных систем. Уже есть идеи по организации шедулинга, но их надо воплотить в жизнь.
Ещё хотелось бы, чтобы на время иницализации /dev каждый процессор прописал себя в /dev/cpuid. Для этого надо как-то придумать, чтобы нужные нити запускались на нужных процессорах. Будем думать.
Known bugs
На AMD Athlon x2 упорно не хотят читаться секторы FDD. Скорее, проблема в том, что надо дёргать MTRR. Но надо проверить.
Опять же, на двухъядернике при нажатии нескольких клавиш одновременно виснет клава. Очень неприятно. Скорее, виноват второй CPU, который, возможно, отлавливает прерывание от клавиатуры. Наверное, проблема решится отрубанием APIC или программированием его в Virtual Wire Mode.
Multiprocessing.
Ноябрь 6th, 2007Оказывается, запустить все Application Processors не так уж и сложно. Для этого в ОС нужна минимальная поддержка APIC, чтобы появилась возможность послать IPI-SIPI-SIPI.
Проблема в другом — все процы стартуют в реальном режиме, и их надо переводить в защищёнку
. Продолжаем ковыряться. Надеюсь, к сессии допилю поддержку SMP, VESA, склепаю простые системные вызовы и запущу первые приложения.
День убит, но с пользой.
Октябрь 28th, 2007НЕЛЬЗЯ ВЕРИТЬ BIOS, ЧТО APIC РАБОТАЕТ В РЕЖИМЕ СОВМЕСТИМОСТИ.
После программирования APIC в Virtual Wire Mode комп перестал виснуть.
Учимся вырубать APIC
Октябрь 25th, 2007Для корректной работы ОС на многопроцессорных системах очень важно (АРХИВАЖНО) для первоначальной инициализации вырубить APIC. В моей ОС это делается следующим способом:
// Disable APIC
int cpuid = sys_open("/cpuid", O_RDONLY);
if (cpuid != 0)
{
TCPUIDInfo info;
if (sys_read(cpuid, &info, sizeof(TCPUIDInfo))==sizeof(TCPUIDInfo))
{
if ((info.Extensions&CPUID_EXT_APIC)!=0) // Disable APIC if presented
{
QWORD apic = ReadMSR(IA32_APIC_BASE);
apic &= (~(1<<11)); // Clear global enable/disable flag
WriteMSR(IA32_APIC_BASE, apic);
}
}
sys_close(cpuid);
}
После чего можно инициализировать обычный PIC (на самом деле, тот же APIC, но в legacy-mode
).
Жосткий дебагer
Октябрь 22nd, 2007Иногда приходится вот так вот отлаживать ОСь.
Комп превращается в мега-тормоза. А результата 0.
Но за бегущими циферками иногда интересно понаблюдать.