UEFI下C语言获取EDID信息:如何读取AL、AH及ES:DI寄存器的值
解决方案
核心前提说明
你找到的int 0x10是实模式BIOS中断,仅能在16位实模式下执行,而64位UEFI默认运行在长模式下,直接调用该中断会触发处理器异常。你有两种可选方案实现需求:
- 方案一:使用UEFI原生协议获取EDID,无需处理模式切换,兼容性更强,是UEFI环境下的标准实现
- 方案二:开启UEFI的CSM兼容模块,手动实现长模式到16位实模式的切换,调用中断后再切回长模式返回结果给C代码
方案一:UEFI原生获取EDID(推荐)
UEFI规范定义了专门的EFI_EDID_DISCOVERED_PROTOCOL用于直接读取显示器EDID信息,无需调用BIOS中断,适配所有支持UEFI的设备,不需要开启CSM兼容。
C代码示例
#include <Uefi.h> #include <Protocol/EdidDiscovered.h> // 定义返回结果结构体 typedef struct { UINT8 edid_data[128]; EFI_STATUS status; } EdidResult; EdidResult get_edid(void) { EdidResult res = {0}; EFI_EDID_DISCOVERED_PROTOCOL* edid_protocol = NULL; EFI_HANDLE* handles = NULL; UINTN handle_cnt = 0; // 枚举所有EDID discovered协议实例 res.status = gBS->LocateHandleBuffer( ByProtocol, &gEfiEdidDiscoveredProtocolGuid, NULL, &handle_cnt, &handles ); if (EFI_ERROR(res.status)) return res; // 遍历找到有效EDID for (UINTN i = 0; i < handle_cnt; i++) { res.status = gBS->HandleProtocol( handles[i], &gEfiEdidDiscoveredProtocolGuid, (VOID**)&edid_protocol ); if (!EFI_ERROR(res.status) && edid_protocol->SizeOfEdid >= 128) { // 拷贝128字节标准EDID到返回结构体 gBS->CopyMem(res.edid_data, edid_protocol->Edid, 128); break; } } gBS->FreePool(handles); return res; }
方案二:封装int 0x10中断调用
如果你确实需要使用BIOS中断方案,需要先实现长模式和实模式的切换逻辑,再按照System V AMD64调用约定封装汇编函数给C调用。
步骤1:定义C侧数据结构与函数声明
#include <stdint.h> typedef struct { uint8_t al; // 中断返回AL值:0x4F表示功能支持 uint8_t ah; // 中断返回AH值:0表示成功,1表示失败 uint8_t edid[128]; // 存储读取到的EDID数据 } EdidInt10Result; // 声明汇编函数 extern void read_edid_int10(EdidInt10Result* result);
步骤2:汇编函数实现
注意:以下代码省略了64位长模式与16位实模式的切换逻辑,你需要自行补充模式切换代码,否则无法正常执行中断。
global read_edid_int10 read_edid_int10: ; 此处补充:从64位长模式切换到16位实模式的逻辑 ; ============================================= ; 执行int 0x10中断读取EDID mov ax, 0x4f15 mov bl, 0x01 xor cx, cx xor dx, dx int 0x10 ; ============================================= ; 此处补充:从16位实模式切回64位长模式的逻辑,切回前备份好AX、ES、DI寄存器的值 ; 填写返回结构体(第一个参数存在rdi寄存器) mov byte [rdi], al ; 保存AL到结构体al字段 mov byte [rdi + 1], ah ; 保存AH到结构体ah字段 ; 将ES:DI的实模式地址转换为线性地址,拷贝128字节EDID到结构体 mov rcx, rdx ; 假设你切回长模式后ES的值存在rdx的低16位 shl rcx, 4 add rcx, rsi ; 假设你切回长模式后DI的值存在rsi的低16位 lea rdi, [rdi + 2] ; 结构体edid字段的偏移 mov r8, 128 copy_edid: mov al, byte [rcx] mov byte [rdi], al inc rcx inc rdi dec r8 jnz copy_edid ret
步骤3:C侧调用
EdidInt10Result res = {0}; read_edid_int10(&res); if (res.al == 0x4F && res.ah == 0) { // 读取成功,res.edid中为有效EDID数据 } else { // 读取失败 }
内容的提问来源于stack exchange,提问作者Vapour Dev
相关产品推荐
相关产品推荐

