Вопросы о прерывании APIC

Я следую книге, чтобы написать Linux-подобное ядро, однако столкнулся с проблемами с главой APIC.

Прежде всего, я перечислю свою платформу. Я использую Windows 10, использую Virtual Box для запуска Ubuntu 18.04 и запускаю в нем тестовые коды на bochs.

В настоящее время мое понимание APIC следующее:

1. На каждом ядре встроен локальный APIC, а на материнской плате — I/O APIC.

2. Доступ к локальному APIC можно получить с помощью сопоставления памяти или ссылки на MSR.

3, I/O APIC доступны через 3 регистра IOREGSEL, IOWIN, EOI. Основная идея состоит в том, чтобы установить значение для IOREGSEL и получить доступ к соответствующему регистру с помощью IOWIN.

4, есть 3 режима, интересующий режим симметричного ввода-вывода

5, I/O APIC имеют 24 контакта, контакт 1 связан с клавиатурой

6. Чтобы включить APIC и I/O APIC, необходимо выполнить ряд работ:

а) Прерывание по маске 8529A

б) Включите xAPIC и 2xAPIC, чтобы был возможен доступ к MSR

c) Маскировать все LVT (если локальные прерывания не нужны)

d) Настройка записей RTE для I/O APIC

д) Установка регистра IMCR в 0x01h, принудительно передает сигнал прерывания 8529A на I/O APIC.

f) Найдите другой регистр управления прерываниями (OIC) через корневой комплексный базовый регистр адреса (RCBA) и установите OIC[8]=1b, чтобы включить I/O APIC.

Теперь я представлю свои вопросы:

1. Как на bochs, так и на Virtual Box максимальное число записей LVT определяется как 6 (согласно руководству, существует 6 + 1 = 7 записей LVT), а запись LVT_CMCI недоступна (ошибка gp).

2. Говорят, что разные чипы на материнской плате будут отображать RCBA на разные порты, и мне придется искать это в руководствах. Но был бы способ обнаружить это самим программным обеспечением, иначе как коммерческая ОС подходила для другой платформы.

3. Поскольку я на виртуальной машине, как я могу определить доступность RCBA?

Спасибо всем, кто может ответить на мои вопросы или помочь мне лучше понять эту главу.


Я представлю часть своего кода по настройке APIC для простого прерывания клавиатуры.

Сначала будет функция обработки прерываний

void IRQ0x21_interrupt(Int_Info_No_Err STK)
{
    Ent_Int;
    color_printk(RED,BLACK,"do_IRQ: 0x21\t");

    unsigned char x;
    x = io_in8(0x60);
    color_printk(RED,BLACK,"key code:%#08x\n",x);
    wrmsr(0x80b, 0UL);
    //io_out8(0x20,0x20);
    Ret_Int;
}

Ret_Int и Ent_Int — это макросы, определенные для обработки стека прерываний, функция wrmsr() записывает 0 в адрес MSR 0x80b(EOI)

Далее будет функция настройки для LAPIC и I/O APIC, предполагая, что физический адрес 0xFEC00000 уже отображен в таблице страниц.

void APIC_init(void)
{
    int i;
    int virtual_index_address;
    int virtual_data_address;
    int virtual_EOI_address;
    unsigned long tmp;

    //Set interrupt, note No.33 link to IRQ0x21_interrupt() function
    for(i = 32;i < 56;i++)
    {
        _Set_INT(IDT_PTR.Offset + i, ATTR_INTR_GATE, 2, interrupt[i - 32]);
    }
    //Mask 8529A
    io_out8(0x21,0xff);
    io_out8(0xa1,0xff);
    //enable IMCR
    io_out8(0x22,0x70);
    io_out8(0x23,0x01);

    #pragma region Init_LAPIC
    //Enabling xAPIC(IA32_APIC_BASE[10]) and 2xAPIC(IA32_APIC_BASE[11])
    tmp = rdmsr(0x1b);
    tmp |= ((1UL << 10) | (1UL << 11));
    wrmsr(0x1b,tmp);
    //Enabling LAPIC(SVR[8])
    tmp = rdmsr(0x80f);
    tmp |= (1UL << 8); //No support for EOI broadcast, no need to set bit SVR[12]
    wrmsr(0x80f,tmp);
    //Mask all LVT
    tmp = 0x10000;
    //wrmsr(0x82F, tmp); Virtual machine do not support
    wrmsr(0x832, tmp);
    wrmsr(0x833, tmp);
    wrmsr(0x834, tmp);
    wrmsr(0x835, tmp);
    wrmsr(0x836, tmp);
    wrmsr(0x837, tmp);
    #pragma endregion

    #pragma region Init_IOAPIC
    virtual_index_address = (unsigned char*)(0xFEC00000 + PAGE_OFFSET);
    virtual_data_address = (unsigned int*)(0xFEC00000 + PAGE_OFFSET + 0x10);
    virtual_EOI_address = (unsigned int*)(0xFEC00000 + PAGE_OFFSET + 0x40);
    //Setting RTEs, mask all but 0x01 RTE table for keyboard
    for(i = 0x10;i < 0x40;i += 2){
        *virtual_index_address = i;
        io_mfence;
        *IOAPIC_MAP.virtual_data_address = 0x10020 + ((i - 0x10) >> 1) & 0xffffffff;
        io_mfence;
        *IOAPIC_MAP.virtual_index_address = i + 1;
        io_mfence;
        *IOAPIC_MAP.virtual_data_address = ((0x10020 + ((i - 0x10) >> 1)) >> 32) & 0xffffffff;
        io_mfence;
    }

    *virtual_index_address = 0x12;
    io_mfence;
    *IOAPIC_MAP.virtual_data_address = 0x10020 + (2 >> 1) & 0xffffffff;
    io_mfence;
    *IOAPIC_MAP.virtual_index_address = i + 1;
    io_mfence;
    *IOAPIC_MAP.virtual_data_address = ((0x10020 + (2 >> 1)) >> 32) & 0xffffffff;
    io_mfence;
    #pragma endregion
}

Итак, согласно ответам, I/O APIC настроен на открытие после завершения инициализации для RTE. Если кто-нибудь может быть так любезен, скажите мне, будет ли приведенный выше код работать или нет (для простого прерывания клавиатуры). Большое спасибо.


person Shore    schedule 06.08.2019    source источник


Ответы (1)


1. Как на bochs, так и на Virtual Box максимальное число записей LVT определяется как 6 (согласно руководству, существует 6 + 1 = 7 записей LVT), а запись LVT_CMCI недоступна (ошибка gp).

Intel документирует семь записей LVT в своем Руководстве для разработчиков программного обеспечения (раздел 10.5.1), но это текущее состояние оборудования.

Регистр счетчика производительности LVT и связанное с ним прерывание были представлены в процессорах P6, а также присутствуют в процессорах Pentium 4 и Intel Xeon.
Регистр температурного монитора LVT и связанное с ним прерывание были представлены в процессорах Pentium 4 и Intel Xeon. .
Регистр LVT CMCI и связанное с ним прерывание появились в процессорах Intel Xeon 5500.

Если вы считаете процессоры P6 и Pentium 4 устаревшими, вы всегда можете предположить, что существует как минимум шесть записей LVT.
Серия Xeon 5000 основана на Nehalem, предке современных поколений процессоров, и датируется 2008 годом. .

При доступе к недействительному регистру LAPIC в режиме x2APIC (т. е. при доступе к MSR) генерируется ошибка #GP, поскольку это происходит при доступе к несуществующим MSR.
При использовании устаревшего интерфейса и нахождении в освобожденной области LAPIC (до смещения 0x3f0) бит 7 будет установлен в Регистр СОЭ LAPIC.

Boch не обрабатывает регистр LVT_CMCI, буквально нет поддержки для этого в исходном коде.
Возможно, этот репозиторий не синхронизирован с текущим исходным кодом, но моя сборка bochs (довольно недавняя) по-прежнему не поддерживает его.
Переключатель против смещения регистра присутствовал еще в 2007 году, до Xeon 5500, поэтому либо автор забыл его обновить, либо решил, что MCE не стоит поддерживать.

Я не проверял VirtualBox, но, учитывая, что MCE и более общий механизм MCA довольно сложны, вероятно, он не поддерживается.

Проще говоря, LVT_CMCI не является обязательным. Проверить его наличие можно с помощью обычного интерфейса MMIO и регистра ESR.


2. Говорят, что разные чипы на материнской плате будут отображать RCBA на разные порты, и мне придется искать это в руководствах. Но был бы способ обнаружить это самим программным обеспечением, иначе как коммерческая ОС подходила для другой платформы.

О IOAPIC сообщает ОС через таблицы ACPI, в частности, раздел 5.2.12 Таблица описания нескольких APIC (MADT) в Спецификация ACPI содержит MMIO APIC IO.
В качестве альтернативы, если имеется, Таблица Intel MP.

Программному обеспечению не нужно знать об оборудовании, чтобы получить доступ к IO APIC. На самом деле вещи RCBA довольно противоречивы на аппаратном уровне.

В текущей системе x86 всегда есть IO APIC в PCH (концентраторе контроллера платформы), а также есть IO APIC в неядре некоторых серверных процессоров с несколькими сокетами (серии E5 и E7, а также Xeon 5500 имеют его - Xeon Scalable может /should, но подробное техническое описание отсутствует).
Наконец, APIC ввода-вывода может предоставляться другими способами, например, в концентраторе PCI (например, Intel PXH).

IO APIC в PCH Series 7, использовавшийся в то время с процессорами Ivy Bridge (около 2012 г.), следует шаблону RCBA:

OIC расположен по смещению 0x31FE в RCBA, а RCBA — по смещению 0xF0 в пространстве конфигурации PCI моста PCI-to-LPC (устройство 1f.0).
Между RCBA и LPC, очевидно, Intel использовала это устройство по внутренним причинам.
Поскольку все это задокументировано, ОС может получить RCBA и адрес OIC; при условии, что он распознает чипсет.
То же самое относится и к серии 8 (Haswell).

Начиная с серии 100 PCH (в сочетании со Skylake) IO APIC в PCH управляется контроллером P2SB (Primary to Sideband), это устройство 1f.1 (действительно до серии C620, последняя на момент написания ).
P2SB можно скрыть от программного обеспечения, записав бит 8 регистра 0xE0 в пространство конфигурации PCI, это приведет к тому, что все чтения конфигурации PCI будут возвращать единицы.
Запись, по крайней мере, в 0xE0, по-прежнему принимается; На самом деле, я «раскрыл» P2SB в своей системе и проверил его конфигурацию.
Регистр 0x64 в его конфигурационном пространстве PCI работает как регистр OIC (хотя он называется IOAC).

На стороне сервера некоторые (большинство?) процессоров Intel имеют APIC ввода-вывода, встроенный в неядро.
Это выглядит как устройство PCI (в отличие от APIC на стороне клиента, также существует класс PCI для IOAPIC).
Он может использовать стандартный механизм PCI BAR (регистр называется MBAR), поэтому его можно отображать в любом месте 4GiB и не только на 0xFECx xxxx.
У него также есть регистр ABAR, работа которого аналогична регистру IOAC.
Этот шаблон кажется верным для всех IO APIC, отображаемых как устройства PCI (например, в концентраторах PXH) .

На сервере PCH также имеет IO APIC, однако требуется дополнительная настройка, чтобы система могла правильно направлять запросы на IO APIC за DMI.

Все эти детали раскрываются для программистов BIOS в большей степени, чем для программистов ОС, надежный способ - использовать таблицу ACPI или таблицу MP (если обе не существуют, система не является SMP и IO APIC не требуется).


3. Поскольку я на виртуальной машине, как я могу определить доступность RCBA?

Это было частично или полностью рассмотрено в ответе на пункт 2 (то есть либо RCBA отсутствует, либо он находится в пространстве конфигурации PCI-to-LPC по адресу 0xf0).
Если вы используете VirtualBox, вы можете выбрать < href="http://www.datasheetcatalog.com/datasheets_pdf/8/2/3/7/82371SB_(PIIX3).shtml" rel="nofollow noreferrer">PIIX3 или набор микросхем ICH9.

Для PIIX3 нет RCBA (слишком старый), а база APIC имеет форму FEC0_xy00h, где xy можно настроить по адресу 0x80 конфигурационного пространства устройства 00.0. APIC является внешним компонентом, и этот параметр определяет, когда следует утверждать конкретные контакты IO APIC.

Для ICH9 RCBA находится в мосту PCI-to-LPC. Таким образом, простой способ прочитать его под Linux — sudo setpci -s 1f.0 F0.D (но проверьте синтаксис).

Обратите внимание, что оба компонента относятся к эпохе до PCH.

person Margaret Bloom    schedule 06.08.2019
comment
Привет большое спасибо. Я новичок, поэтому не понимаю всех ваших ответов. Итак, что делает большинство программистов ОС, чтобы включить I/O APIC, используя таблицу ACPI, что означает, что я должен включить I/O APIC во всей таблице ACPI? В виртуалке будет так же? И как мне это обнаружить?? - person Shore; 06.08.2019
comment
Кстати, если возможно, могу ли я спросить процедуру включения I/O APIC?? - person Shore; 06.08.2019
comment
@Shore Включение IO APIC — это просто вопрос программирования соответствующих RTE. Современные системы не поддерживают режим PIC, есть двойной PIC 8259A, но он всегда подключается к IRQ0 IOAPIC (LAPIC интегрированы в ЦП, а контакты LINT0/1 используются даже тогда, когда они отключены). Так что просто замаскируйте IRQ на уровне PIC и запрограммируйте IO APIC RTE. Это работает, потому что первые 15 IRQ такие же, как и для PIC, если нет переопределения, следующие IRQ-16-23 отображаются на каналы PCI A-H. Таблица MADT содержит подробную информацию: базы IO APIC, переопределения, необходимость использования старого порта... - person Margaret Bloom; 06.08.2019
comment
... 22h/23h для отключения PIC (описано в спецификации MP, это регистр IMCR). Включение IO APIC не является сложной частью, в отличие от получения топологии IRQ. На самом деле линии IRQ де-факто устарели в пользу MSI. Анализ таблицы ACPI представляет собой длинный шаблон кода, если у меня будет время, я посмотрю, могу ли я опубликовать пример. Но если вы новичок, вы должны быть уверены, что понимаете, как разбудить другие процессоры и как маршрутизируются IRQ, иначе все это будет бессмысленным. Могу я спросить, почему вы хотите включить IO APIC? - person Margaret Bloom; 06.08.2019
comment
Большое спасибо за то, что вы так терпеливы! Причина в том, что я пишу Linux-подобное ядро, следуя книге. Я готов к тому, что мне нужно настроить прерывание для клавиатуры с помощью APIC. У меня есть вопросы, так как в книге говорится, что мне нужно каким-то образом включить I/O APIC. Таким образом, краткое резюме будет заключаться в том, чтобы включить APIC, мне нужно только сделать: 1) включить LAPIC, 2) настроить RTE (замаскировать все остальные, кроме контакта 0x01), 3) записать относительное значение в IMCU ??? В настоящее время я использую Bochs с моделью процессора corei7_haswell_4770, и я проверю, работает ли она с описанными выше шагами. Спасибо еще раз! - person Shore; 07.08.2019
comment
Привет, я тестировал их на Bochs и Virtualbox, они оба работали!!! Так что мне действительно не нужно включать I/O APIC, он готов, как только я настрою RTE. Большое спасибо!! - person Shore; 07.08.2019