Приветствую! Пытаюсь сейчас запустить таймеры APIC всех процессоров в SMP, но не очень-то получается. В смысле, на qemu пашет, а в реальности всё намного плачевнее (виснет ap-проц, либо падает bsp). В Intel Manual только описание регистров и режимов. У кого-нибудь есть какой-нибудь материал/примеры по программированию APIC (в том числе, и таймеров)?
Покажи код, так трудно что-то сказать. Насколько я понимаю, ты это делаешь прямо в своей ОС, но проще сделать тестовый пример на ассемблере, который запустит таймеры, чтобы защититься от посторонних ошибок. И нам легче разбирать будет.
Так, с APIC BSP разобрался. Оказывается, ребутал у меня систему код, который работает с VESA (потому что грузилась IDT реального режима, а прерывания таймера APIC не маскировались. Как следствие - фолт по неизвестному адресу, тому, который прописан в IDT реального режима за вектором таймера). А вот с AP непонятно пока. После включения прерываний выпадает exception, при этом кода ошибки нет (выпадают, в основном, исключения 0x08, 0x0e и 0x0d). При чём, я не уверен, что это именно exception, а больше подозреваю, что какое-то аппаратное прерывание, приходящееся на векторы исключений. Очень похоже на векторы PIC. Вопросы: 1. если APIC эмулируется как PIC, нужно ли проводить инициализацию PIC на каждом процессоре? 2. какие прерывания после STI могут приходить на AP-процессор?
SadKo IDT/GDT для каждого AP инициализированы? 1. скорее PIC может эмулироваться через APIC 2. в PIC архитектуре, PIC связан только с BP, независимо от того, в контексте какого процессора идет его программирование 3. в APIC архитектуре, APIC может быть связан с любым AP и BP через таблицу перенаправлений прерываний программировать ее можно в контексте любого процессора как вывод, в любой архитектуре, инициализацию достаточно произвести единожды STI выполнен для AP? тогда любые внешние: SMI, NMI, маскируемые если размаскированы элементы LVT, тогда еще набор локальных
IDT и GDT у процессоров общие. Проблема не возникала, пока на AP-процессоре не сделал STI. Решил протрассировать код. После STI выполняется N инструкций и выпадает в исключение, при чём, не обязательно одно и то же. Да и вообще сдаётся мне, что это не исключение. Код на BSP выполняется нормально. Таблица перенаправлений прерываний - это I/O APIC?
да перед STI на AP просмотри ее (таблицу) из BSP на предмет наличия идентификаторов AP и соответствующих векторов в каждом элементе какой режим обработки прерываний активен после STI? (PIC, Virtual-Wire, Symmetric)
значит в любом случае дело либо в NMI, либо в маскируемых прерываниях можешь создать в IDT 256 дескрипторов с фиктивными обработчиками и посмотреть номер вектора при генерации прерывания
Я это собирался проделать. В ближайшее время возьмусь. Всё же интересно, что творится. А есть какие-нибудь хорошие доки по IO APIC?
Спасибо. Сейчас просто времени мало во всём этом разбираться, но тема очень интересная. Буду отписываться по мере продвижения.
Собрал статистику по прерываниям (сделал IDT для AP-проца, считаю количество сработавших прерываний). Получил следующие цифры: прерывание 0x08 - один раз. прерывание 0x0c - один раз. прерывание 0x20 - постоянно инкрементируется. прерывание 0x21 - два раза. прерывание 0x27 - постоянно инкрементируется. Повесил APIC Timer на 254 прерывание, таймер срабатывает регулярно, инкрементируя счётчик. "PIC Master" запрограммирован на базовый вектор 0x20, "Slave" - на вектор 0x28. На BSP проце используются прерывания от таймера, от клавиатуры, от ATA, от FDC и от мыши. Spurious Vector установил в 0x1f. Как можно объяснить выскакивание прерываний 0x08 и 0x0c?
Нет, не могут, поскольку поток, запущенный на AP-процессоре, крутится нормально. Единственное. я, похоже, перепутал прерывание 0x0c и 0x0e (да, почерк у меня корявый). У меня есть такое предположение: эти прерывания стояли в очереди у Local APIC до тех пор, пока я не разрешил прерывания (sti), при чём, произошли до того, как был перепрограммирован "PIC" (например, на этапе загрузки BIOS/чтении бутсектора и пр.). Есть ли какой-нибудь способ сбросить очередь прерываний в APIC? 0x08 - вполне закономерно, таймер, 0x0e - прерывание от дисковода. У меня уже была проблема, когда второй проц спонтанно вешал первый (приходило левое прерывание на второй проц). Лечилось это программированием APIC в VirtualWire Mode. Возможно, это и послужило причиной такого зависания. Вопрос теперь стоит в другом: как убрать из очереди эти запросы?
нет после выбора бита в IRR, он обнуляется, а соответстующий ему бит в ISR устанавливается т. е если не запрещать маскируемые прерывания, то биты в IRR будут обнулены APIC-ом в процессе вызова обработчиков можно попытаться 256 раз записать 0 в EOI регистр при запрещенных прерываниях хотя не факт, что таким образом IRR обнулится: в мануале написано неоднозначно
SadKo Перепроверь статистику, а то она у тебя кривая какая то до безобразия. Хотя вроде и закономерно. rei3er Вроде все описанно. В MP какраз таки и говориться что надо очистить и запретить в I/O APIC В I/O APIC написано что прерывание может не сразу доставляться. Как запретить понятно там бит есть, как очист ить хм надо почитать повнимательнее. Можно цикл запустить пока бит о доставке в 0 невыставиться.
Получилось очистить запросы на прерывание таким образом: 1. читаем Local APIC IRR 2. Пишем 0 в Local APIC EOI 3. повторяем с пункта 1 256 раз После чего все фейковые счётчики прерываний равны 0. Есть идея, как это сделать более красиво: 1. читаем IRR 2. читаем ISR 3. IRR == ISR == 0 ? Если нет, то посылаем EOI и возвращаемся к 1 4. повторяем 1-3 для всех частей IRR и ISR (256/32 = 8 раз)
вы о чем? причем здесь LVT? речь идет о том, как избежать вызова обработчиков прерываний по векторам 0xC, 0xE