Запись в порт 0cf8h завершается с ошибкой segfault

У меня процессор AMD модели e2-2000. Это семейство 0fh. Согласно семейству 0fh BKDG, у меня есть этот код для чтения идентификатора устройства и поставщика:

ReadPCIConfiguration:
movq    $0x80000100, %rax
movq    $0x0cf8, %rdx
outl    %eax, %dx          # sigsegv caught here
movq    $0x0cfc, %rdx
inl     %dx, %eax
ret

Насколько я знаю, алгоритм чтения/записи конфигурации PCI выглядит следующим образом:

  • записать номер целевой шины, номер функции номера устройства и смещение или номер регистра в адрес порта конфигурации
  • выполнять 1-, 2- или 4-байтовую операцию чтения/записи из/в порт данных конфигурации

Порты 0xcf8..0xcfb - адрес порта конфигурации (двойное слово)

Значение битов:

  • 31 - EnReg - включить транзакцию (R/W)
  • 24..31 - зарезервировано (Р/О)
  • 16..23 - BusNum (R/W)
  • 11..15 - DevNum (R/W)
  • 8..10 - FuncNum (R/W)
  • 2..7 - RegNum (R/W)
  • 0..1 - Зарезервировано (R/O)

Итак, пишу в шину - 0, dev - 0, func - 1, reg - 00

Я делаю что-то неправильно?

(Я запускаю скомпилированное и связанное приложение из пользовательского пространства, GNU/Debian "Wheezy" Linux 3.11.6)


person Sergey Kanaev    schedule 30.11.2013    source источник
comment
Я не аппаратный парень, но, вероятно, ОС не позволяет вам писать напрямую в порты? Для этого определенно существует системный вызов, чтобы гарантировать, что это делают только процессы с нужными привилегиями.   -  person Guido    schedule 01.12.2013
comment
Может быть ты прав. Но дело в том, что в дальнейшем код должен запускаться при старте ОС (для перенастройки карты системной памяти) и хотелось бы протестировать код хотя бы на доступ для чтения и корректность чтения.   -  person Sergey Kanaev    schedule 01.12.2013
comment
Виртуализировать? Запустите его перед ОС внутри виртуального бокса. Это, черт возьми, не приведет к segfault, поскольку нет ОС, но я понятия не имею, что делает ваш код!   -  person Guido    schedule 01.12.2013
comment
Я понял. Я нашел решение - это вызов с именами ioperm и iopl. Может стоит удалить вопрос?   -  person Sergey Kanaev    schedule 01.12.2013


Ответы (1)


Linux по умолчанию не позволяет пользовательскому коду записывать в порты ввода/вывода. (Это может быть довольно опасно с точки зрения безопасности.) Если вы хотите, чтобы Linux предоставил вашему процессу доступ к портам ввода-вывода, у вас есть два варианта:

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

  2. Вы можете читать и писать в /dev/port. См. mem(4). Очевидно, что вашему процессу потребуются права на чтение и запись для /dev/mem; на Wheezy это означает, что он должен работать от имени пользователя root, если вы не измените разрешения на устройстве.

person Benjamin Barenblat    schedule 30.11.2013
comment
Итак, вы говорите, что ioperm теперь устарело. Как насчет системного вызова iopl? - person Sergey Kanaev; 01.12.2013
comment
Взгляните на электронную почту Джоша Триплетта. Патч, который он выдвинул, позволяет пользователям компилировать как iopl, так и ioperm. - person Benjamin Barenblat; 01.12.2013
comment
Ага. Похоже, я буду использовать iopl для своих собственных тестов и использовать /dev/port в будущем. Но почему они должны отключать ioperm и iopl? Может это из соображений безопасности? В любом случае, спасибо за ваш быстрый ответ. - person Sergey Kanaev; 01.12.2013