[UEFI] Trying to understand "RegisterExceptionCallback"

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Sturm
Posts: 3
Joined: Fri Apr 05, 2019 11:04 pm

[UEFI] Trying to understand "RegisterExceptionCallback"

Post by Sturm »

Hello OSdev-people :)

I am new to OS developing and I wanted to go directly with UEFI and x64, trying to avoid BIOS-boot and mode switching. It works good so far, however I can't really get CPU-exception interrupts working. First I tried to do it manually with "lidt" and a lot of inline assembler, but I found the UEFI-function "RegisterExceptionCallback" in the official documentation here:
https://uefi.org/sites/default/files/re ... 21.1036676
This looked promising, so I went with that. However it doesn't really work. Qemu doesn't double/triple fault anymore, when an exception occurs, but my exception handling function isn't called.

This is my code:

Code: Select all

void exceptionDiv() {			  // The function I want to be called when the exception occurs
	kprintf("Exception 0x0!\n"); // This never happens
	asm volatile("iretq");
}
// ...
EFI_DEBUG_SUPPORT_PROTOCOL *dsp;
EFI_GUID dspGUID = EFI_DEBUG_SUPPORT_PROTOCOL_GUID;
status = ST->BootServices->LocateProtocol(&dspGUID, NULL, (void**) &dsp);
dsp->RegisterExceptionCallback(dsp, 0, exceptionDiv, EXCEPT_EBC_DIVIDE_ERROR);
kprintf("Test1\n"); 			// This works
uint32 test1 = 42, test2 = 0;
test1 /= test2; 				 // The exception occurs here
kprintf("Test2\n"); 			// This never happens
It seems like there is no more code executed as soon as the exception occurs.
nullplan
Member
Member
Posts: 1801
Joined: Wed Aug 30, 2017 8:24 am

Re: [UEFI] Trying to understand "RegisterExceptionCallback"

Post by nullplan »

You should have just turned the page.

Code: Select all

typedef
VOID (*EFI_EXCEPTION_CALLBACK) (
  IN EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT    SystemContext
  );
So already the type of your callback is wrong. Reading on a bit further:
The implementation must handle saving and restoring the processor context to/from the system context record around calls to the registered callback function.
So the "iret" is also wrong and must go, UEFI will handle it for you. That might have been the problem as it would crash so fast you couldn't see the output of the kprintf before it happens. But if that isn't it, are you sure you set the calling conventions correctly?

I find myself repeating the same message, but what does happen? You told us neither the code after the divide error nor the callback is executed, so what does happen instead? QEMU has a monitor window in which you can ask it to print the current RIP, for instance.
Carpe diem!
Sturm
Posts: 3
Joined: Fri Apr 05, 2019 11:04 pm

Re: [UEFI] Trying to understand "RegisterExceptionCallback"

Post by Sturm »

nullplan wrote:You told us neither the code after the divide error nor the callback is executed, so what does happen instead?
RIP is exactly 1519 bytes after my exception handler. This is Qemu's output:
Qemu wrote:check_exception old: 0xffffffff new 0x0
327: v=00 e=0000 i=0 cpl=0 IP=0038:0000000006b469c7 pc=0000000006b469c7 SP=0030:0000000007f0eaa0 env->regs[R_EAX]=000000000000002a
RAX=000000000000002a RBX=0000000007333f98 RCX=0000000006b52004 RDX=0000000000000000
RSI=0000000000000009 RDI=0000000007336018 RBP=0000000007f0eb20 RSP=0000000007f0eaa0
R8 =000000000000023e R9 =000000000000001b R10=0000000007e72080 R11=00000000ffbf826d
R12=0000000007337640 R13=0000000007337648 R14=0000000007f24b60 R15=0000000007336018
RIP=0000000006b469c7 RFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
exceptionDiv() is at 0x6b463cf.

I did change my code a little bit, no change though. :(

Code: Select all

VOID EFIAPI exceptionDiv (IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_SYSTEM_CONTEXT SystemContext) {
	printf("Exception!\n");
	while (1==1);
	return;
}

EFI_DEBUG_SUPPORT_PROTOCOL *dsp;
EFI_GUID dspGUID = EFI_DEBUG_SUPPORT_PROTOCOL_GUID;
ST->BootServices->LocateProtocol(&dspGUID, NULL, (void**) &dsp);
dsp->Isa = IsaX64;	// Setting the instruction set to x64
dsp->RegisterExceptionCallback(dsp, 0, NULL, EXCEPT_EBC_DIVIDE_ERROR);			// Unregister old callback
dsp->RegisterExceptionCallback(dsp, 0, exceptionDiv, EXCEPT_EBC_DIVIDE_ERROR); 	// Register new callback
dsp->RegisterExceptionCallback(dsp, 0, NULL, EXCEPT_X64_DIVIDE_ERROR);
dsp->RegisterExceptionCallback(dsp, 0, exceptionDiv, EXCEPT_X64_DIVIDE_ERROR);
dsp->RegisterExceptionCallback(dsp, 0, NULL, EXCEPT_IA32_DIVIDE_ERROR);
dsp->RegisterExceptionCallback(dsp, 0, exceptionDiv, EXCEPT_IA32_DIVIDE_ERROR);
RegisterExeptionCallback() returns "EFI_SUCCESS" in all cases.
Post Reply