UEFI Variable là gì?

UEFI Variable lưu cấu hình firmware theo dạng Name + VendorGuid + Attributes + Data. Hiểu variable giúp debug boot option mất, Secure Boot fail và NVRAM đầy.

Cập nhật 5 phút đọc
Đọc bằng Tiếng Việt English 日本語
BIOS Terms cover

UEFI Variable là cơ chế lưu trạng thái và cấu hình firmware theo dạng Name + VendorGuid + Attributes + Data. Một phần variable có attribute NV (non-volatile) nên vẫn còn sau khi tắt máy - boot option, Secure Boot key, setup policy đều đi qua cơ chế này.

Điểm quan trọng: variable không phải key-value đơn giản. Cùng tên nhưng khác VendorGuid là hai variable hoàn toàn khác nhau. Cùng data nhưng khác attribute thì quyền truy cập và lifetime cũng khác.

Cấu trúc một variable

Mục Giá trị Ghi chú
Name BootOrder, SecureBoot, ... Unicode string. Phân biệt hoa thường.
VendorGuid gEfiGlobalVariableGuid, ... Namespace. Cùng Name khác GUID = hai variable khác nhau.
Attributes NV | BS | RT | Auth Quy định lifetime và quyền truy cập. Xem chi tiết: Variable Attribute là gì?
Data Binary payload Format tùy variable - UINT16 array cho BootOrder, UINT8 cho SecureBoot, ...

GetVariable - đọc variable

Ví dụ dưới đây là boot-time pattern, nên còn dùng gBS để allocate buffer. Nếu gọi variable service trong runtime path sau ExitBootServices(), không được dùng gBS.

UINT32 Attributes;
UINTN  DataSize = 0;
VOID   *Buffer  = NULL;

// Lần 1: lấy size
Status = gRT->GetVariable(
                L"BootOrder",
                &gEfiGlobalVariableGuid,
                &Attributes,
                &DataSize,
                NULL
                );

if (Status == EFI_BUFFER_TOO_SMALL) {
  // Boot-time: còn được dùng gBS để allocate buffer
  Status = gBS->AllocatePool(EfiBootServicesData, DataSize, &Buffer);
  if (EFI_ERROR(Status)) {
    return Status;
  }

  // Lần 2: đọc thật sự
  Status = gRT->GetVariable(
                  L"BootOrder",
                  &gEfiGlobalVariableGuid,
                  &Attributes,
                  &DataSize,
                  Buffer
                  );
  // Sau khi dùng xong, nhớ gBS->FreePool(Buffer) trong boot-time code
}

if (Status == EFI_NOT_FOUND) {
  // Kiểm tra cả tên biến VÀ VendorGuid - sai một trong hai thì EFI_NOT_FOUND
}

SetVariable - ghi variable

UINT16 BootOrder[] = { 0x0001, 0x0000, 0x0002 };

Status = gRT->SetVariable(
                L"BootOrder",
                &gEfiGlobalVariableGuid,
                EFI_VARIABLE_NON_VOLATILE |
                EFI_VARIABLE_BOOTSERVICE_ACCESS |
                EFI_VARIABLE_RUNTIME_ACCESS,
                sizeof(BootOrder),
                BootOrder
                );

if (Status == EFI_OUT_OF_RESOURCES) {
  // Variable store đầy hoặc không reclaim được đủ space
  // Cần giảm size, xóa variable không cần, hoặc kiểm tra reclaim/GC của firmware
}

if (Status == EFI_SECURITY_VIOLATION) {
  // Payload/quyền ghi không thỏa yêu cầu bảo vệ của variable
}

// Với variable thông thường, DataSize = 0 thường dùng để delete variable.
// Protected/authenticated variable có thể yêu cầu rule riêng khi delete.
Status = gRT->SetVariable(L"MyVar", &MyGuid, Attributes, 0, NULL);

Namespace isolation

VendorGuid là cơ chế namespace - hai vendor có thể dùng cùng tên variable mà không conflict:

"CustomConfig" + {VENDOR-A-GUID}  ← variable của Vendor A
"CustomConfig" + {VENDOR-B-GUID}  ← variable hoàn toàn khác

Đây là lý do khi đọc variable của platform vendor, phải biết đúng GUID của họ - không có GUID thì không tìm được dù tên đúng.

Authenticated variable

Một số variable quan trọng - đặc biệt Secure Boot keys như PK, KEK, db, dbx - yêu cầu authenticated write. Vẫn ghi qua SetVariable(), nhưng Data payload phải có authenticated header/signature đúng theo rule của firmware và trạng thái Secure Boot hiện tại. Nếu ghi payload thường, firmware có thể trả EFI_SECURITY_VIOLATION.

QueryVariableInfo - kiểm tra variable store

Trước khi ghi variable lớn, có thể hỏi firmware còn bao nhiêu dung lượng:

UINT64 MaxVariableStorageSize;
UINT64 RemainingVariableStorageSize;
UINT64 MaxVariableSize;

Status = gRT->QueryVariableInfo(
               EFI_VARIABLE_NON_VOLATILE |
               EFI_VARIABLE_BOOTSERVICE_ACCESS |
               EFI_VARIABLE_RUNTIME_ACCESS,
               &MaxVariableStorageSize,
               &RemainingVariableStorageSize,
               &MaxVariableSize
               );

Nếu RemainingVariableStorageSize thấp, SetVariable() có thể fail với EFI_OUT_OF_RESOURCES dù data không quá lớn.

Checklist khi làm việc với UEFI Variable

Câu hỏi tự kiểm tra

  1. UEFI Variable được xác định bởi những thành phần nào?
  2. Vì sao cùng Name nhưng khác VendorGuid lại là hai variable khác nhau?
  3. GetVariable thường được gọi hai lần để làm gì?
  4. EFI_BUFFER_TOO_SMALL trong GetVariable có nghĩa là gì?
  5. EFI_NOT_FOUND khi đọc variable thường cần kiểm tra những gì?
  6. DataSize = 0 trong SetVariable thường dùng để làm gì?
  7. EFI_SECURITY_VIOLATION khi ghi Secure Boot variable thường gợi ý điều gì?
  8. QueryVariableInfo dùng để kiểm tra gì?

Bài liên quan

Nguồn tham khảo public

Thấy nội dung này hữu ích?

Lưu lại hoặc chia sẻ cho người cũng đang học firmware, BIOS/UEFI và embedded systems.

Nội dung liên quan

Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.

Biến note thành bài viết hoàn chỉnh

Notes là nơi ghi nhanh khái niệm.