Архив за ‘XSystem’ категория

xskernel.org жив!

Август 30th, 2008

Домен xskernel.org после долгого пребывания в небытии снова вернулся ко мне!
Ура ура ура!

Новый релиз

Июнь 15th, 2008

Выпущен июньский релиз ядра под названием 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.
- Исправлены ошибки в хранении данных текстового режима.

Linux RPM

Июнь 13th, 2008

Научился создавать RPM-ки. Занятная вещь :) .
Теперь существует OpenWatcom 1.7.1 в RPM-пакете для openSUSE Linux.

Также Дрон собирался сделать ebuild ваткома. И что-то даже получается ;) .

А вот, кажется, и решение…

Июнь 9th, 2008

Как был такой анекдот:
Когда-то студент подумал. Ему понравилось, и он подумал ещё раз.

В общем, тут удалось пару часиков прикорнуть, и, о чудо, я, кажется додумался, как можно организовать блокировку прерываний для общего ресурса.

Итак, хочется иметь механизм, аналогичный Mutex, но при этом использовать этот механизм в прерываниях. Как говорится, здоровый сон всегда на пользу, и вот какая идея у меня родилась: почему бы не привести ситуацию, когда к ресурсу обращаются задача и прерывание, к ситуации с двумя прерываниями.

В чём суть? Да в том, что прерывание, вызываемое через 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. Блокиовать прерывания от устройства-инициатора прерываний на время его программирования. Также чревато тем, что, возможно, ответ от устройства приходит именно с прерыванием.

Таким образом, все виды блокировок являются недопустимыми из-за их неполноценности. Обдумываю возможные другие варианты…

Внимательность прежде всего.

Март 25th, 2008

Что-то сдаётся мне, я стал терять внимательность. Багу искал очень долго и, наконец, мегазавихляцким методом нашёл её. А ошибка была такая дурная, что аж обидно. Итак, вопрос на засыпку: какая ошибка в этом коде:

bool TATADirectory::ReadPIO(void *buffer, size_t count)
{
    if (WaitInterrupt(ATA_PIO_TIMEOUT))
    {
        if (WaitDevice(ATA_PIO_TIMEOUT, ATA_SR_DRQ))
        {
            TIntHandler::ClearInterrupts();
            inportwv(FPort.GetAddress()+ATA_REG_DR, buffer, count);
            TIntHandler::SetupInterrupts();
            return true;
        }
    }
    return false;
}

А вот и правильный ответ:
inportwv(FPort.GetAddress()+ATA_REG_DR, buffer, count>>1); // It is a word register!!!
Регистр ATA — двухбайтовый, и читать из него следует по два байта (что и отражено в имени функции — inportwv, которая читает массив слов из порта (rep insw)). Однако, передаётся в качестве счётчика число байт, а не слов. Поэтому происходит переполнение буфера и, как следствие, порча данных в ядре.

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, 2007

VESA

Всё-таки, упирался-не упирался, а прикрутил к ядру возможность вызывать 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, склепаю простые системные вызовы и запущу первые приложения.