You need to enable JavaScript to run this app. UEFI下C语言获取EDID信息:如何读取AL、AH及ES:DI寄存器的值
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 14:54:07