Q
Q
Qreen2022-02-16 05:40:52
C++ / C#
Qreen, 2022-02-16 05:40:52

Why doesn't inportb(0x60) work?

I am writing the simplest "driver", if you can call it that, for my kernel (x86_64 architecture), I need to somehow read its buffer. I do inportb(0x60), which should be similar to in al, 60h - this is how I once did it in an old 32-bit kernel, which was written with a bios bootloader, in which case everything worked fine. In the same case, the compiler gives a warning that

warning: implicit declaration of function 'inportb' is invalid in C99 [-Wimplicit-function-declaration]
char status = inportb(0x60);
, but does not produce an error. I quietly link the under-driver file with the main kernel (end result is .efi), turn it into .iso and run it on qemu. What happens is that the kernel prints my debug message, jumps to exitbootservices, exits quietly, and loads the keyboard driver - that's it. The kernel stalled, things didn’t go any further, qemu hangs with the inscription "Exitbootservices ...", which is a sign of a successful exit from UEFI services, so the problem is in the driver. I deliberately removed all the lines from there, except for inportb (0x60), but the problem remained. Without a driver, everything works out calmly and turns off the computer, as it should be

Answer the question

In order to leave comments, you need to log in

1 answer(s)
J
jcmvbkbc, 2022-02-20
@Qreen

first, the compiler gives a warning, ... , but does not produce an error. I quietly link the under-driver file with the main kernel, (the end result is .efi),

The fact is that EFI applications do not have dynamic linking, and an undefined symbol after copying from .so to .efi simply refers to nowhere. If you output undefined symbols for bootx64.so, then inportb will be among them:
objdump -t bootx64.so | grep UND
0000000000000000         *UND*  0000000000000000 inportb

In qemu, the result of calling this function looks like this:
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
…

On the other hand, if you provide a function like this:
unsigned char
inportb(unsigned short port)
{
        unsigned char v;
        asm volatile ("in {%1|%b0}, {%b0|%1}\n" : "=a"(v) : "d"(port));
        return v;
}

then it is beautifully called and returns a value.
You can add an option -zdefsto the link command to get a link error if there are references to undefined symbols.
To see exactly what code is running, I run qemu with a monitor in the console (additional switch -monitor stdio). I press ESC when tianocore starts up in QEMU and select Boot Manager -> EFI Internal Shell, and there I write fs0:efi\boot\bootx64.efi, after that I turn on logging in the monitor console (with the commands logfile log, log in_asm,exec), and then I press enter in the EFI console. After that, you can look at the log file and look for familiar bytes from objdump in it.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question