@Qreen
Разъяренный питонист

Почему не работает inportb(0x60)?

Я пишу простейший "драйвер", если его так можно назвать, для своего ядра (x86_64 архитектура), мне нужно каким то образом прочесть её буффер. Я делаю inportb(0x60), что должно быть аналогично in al, 60h - так я когда-то делал в стареньком 32-битном ядре, которое писалось ещё с загрузчиком для биоса, в таком случае все прекрасно работало. В этом же случае во-первых компилятор даёт предупреждение, что
warning: implicit declaration of function 'inportb' is invalid in C99 [-Wimplicit-function-declaration]
char status = inportb(0x60);
, но ошибки не производит. Я спокойно линкую файл недо-драйвера с основным ядром, (конечный результат - .efi), превращаю в .iso и запускаю на qemu. Происходит следующее: ядро печатает мое сообщение отладки, переходит к exitbootservices, спокойно завершает его и загружает драйвер клавы - все. Ядро застопилось, дальше дело не идёт, qemu висит с надписью "Exitbootservices...", что является признаком успешного выхода с сервисов UEFI, так что проблема именно в драйвере. Я специально удалил оттуда все строчки, кроме inportb(0x60), но проблема осталась. Без драйвера все отрабатывает спокойно и выключает компьютер, как и должно было быть
  • Вопрос задан
  • 204 просмотра
Решения вопроса 1
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
во-первых компилятор даёт предупреждение, … , но ошибки не производит. Я спокойно линкую файл недо-драйвера с основным ядром, (конечный результат - .efi),

Дело в том, что у EFI-приложений нет динамической линковки, а неопределённый символ после копирования из .so в .efi просто ссылается в никуда. Если вывести неопределённые символы для bootx64.so, то inportb будет среди них:
objdump -t bootx64.so | grep UND
0000000000000000         *UND*  0000000000000000 inportb


В qemu результат вызова этой функции выглядит так:
Trace 0: 0x7fb15d338e80 [0000000000000000/000000007e6e22de/0x40c2b0]
----------------                      
IN: 
0x7e6e2081:  bf 60 00 00 00           movl     $0x60, %edi
0x7e6e2086:  b8 00 00 00 00           movl     $0, %eax
0x7e6e208b:  e8 90 57 00 00           callq    0x7e6e7820

Trace 0: 0x7fb15d3390c0 [0000000000000000/000000007e6e2081/0x40c2b0]
----------------                      
IN: 
0x7e6e7820:  af                       scasl    (%rdi), %eax
0x7e6e7821:  af                       scasl    (%rdi), %eax
0x7e6e7822:  af                       scasl    (%rdi), %eax
0x7e6e7823:  af                       scasl    (%rdi), %eax
0x7e6e7824:  af                       scasl    (%rdi), %eax
0x7e6e7825:  af                       scasl    (%rdi), %eax
0x7e6e7826:  af                       scasl    (%rdi), %eax
0x7e6e7827:  af                       scasl    (%rdi), %eax
0x7e6e7828:  af                       scasl    (%rdi), %eax
0x7e6e7829:  af                       scasl    (%rdi), %eax
0x7e6e782a:  af                       scasl    (%rdi), %eax
0x7e6e782b:  af                       scasl    (%rdi), %eax
…


С другой стороны, если предоставить такую функцию:
unsigned char
inportb(unsigned short port)
{
        unsigned char v;
        asm volatile ("in {%1|%b0}, {%b0|%1}\n" : "=a"(v) : "d"(port));
        return v;
}

то она прекрасно вызывается и возвращает значение.

Можно добавить опцию -zdefs в команду линковки чтобы получать ошибку линковки при наличии ссылок на неопределённые символы.

Чтобы посмотреть, какой именно код выполняется, я запускаю qemu с монитором в консоли (дополнительным ключом -monitor stdio). Я нажимаю ESC когда в QEMU запускается tianocore и выбираю Boot Manager -> EFI Internal Shell, а там пишу fs0:efi\boot\bootx64.efi, после этого в мониторной консоли включаю логгирование (командами logfile log, log in_asm,exec), после чего нажимаю enter в консоли EFI. После этого можно смотреть в файл log и искать в нём знакомые байты из objdump.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы