mirror of
https://github.com/qilingframework/qiling.git
synced 2026-10-12 02:21:40 +00:00
Align UEFI structures with all other OS
This commit is contained in:
@@ -161,7 +161,7 @@ class QlLoaderPE_UEFI(QlLoader):
|
||||
|
||||
for handle in context.loaded_image_protocol_modules:
|
||||
struct_addr = context.protocols[handle][self.loaded_image_protocol_guid]
|
||||
loaded_image_protocol = EfiLoadedImageProtocol.EFI_LOADED_IMAGE_PROTOCOL.loadFrom(self.ql, struct_addr)
|
||||
loaded_image_protocol = EfiLoadedImageProtocol.EFI_LOADED_IMAGE_PROTOCOL.load_from(self.ql.mem, struct_addr)
|
||||
|
||||
unload_ptr = loaded_image_protocol.Unload.value
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ from contextlib import contextmanager
|
||||
from functools import lru_cache
|
||||
from typing import TYPE_CHECKING, Mapping, Sequence, Union, Optional
|
||||
|
||||
from qiling.os.struct import BaseStructEL
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from qiling import Qiling
|
||||
|
||||
@@ -51,72 +53,13 @@ BOOLEAN = UINT8
|
||||
CHAR8 = UINT8
|
||||
CHAR16 = UINT16
|
||||
|
||||
STRUCT = BaseStructEL
|
||||
UNION = ctypes.Union
|
||||
|
||||
CPU_STACK_ALIGNMENT = 16
|
||||
PAGE_SIZE = 0x1000
|
||||
|
||||
|
||||
class STRUCT(ctypes.LittleEndianStructure):
|
||||
"""An abstract class for C structures.
|
||||
"""
|
||||
|
||||
# Structures are packed by default; when needed, padding should be added
|
||||
# manually through placeholder fields
|
||||
_pack_ = 1
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def saveTo(self, ql: Qiling, address: int) -> None:
|
||||
"""Store self contents to a specified memory address.
|
||||
"""
|
||||
|
||||
data = bytes(self)
|
||||
|
||||
ql.mem.write(address, data)
|
||||
|
||||
@classmethod
|
||||
def loadFrom(cls, ql: Qiling, address: int) -> 'STRUCT':
|
||||
"""Construct an instance of the structure from saved contents.
|
||||
"""
|
||||
|
||||
data = bytes(ql.mem.read(address, cls.sizeof()))
|
||||
|
||||
return cls.from_buffer_copy(data)
|
||||
|
||||
@classmethod
|
||||
@contextmanager
|
||||
def bindTo(cls, ql: Qiling, address: int):
|
||||
instance = cls.loadFrom(ql, address)
|
||||
|
||||
try:
|
||||
yield instance
|
||||
finally:
|
||||
instance.saveTo(ql, address)
|
||||
|
||||
@classmethod
|
||||
def sizeof(cls) -> int:
|
||||
"""Get the C structure size in bytes.
|
||||
"""
|
||||
|
||||
return ctypes.sizeof(cls)
|
||||
|
||||
@classmethod
|
||||
def offsetof(cls, fname: str) -> int:
|
||||
"""Get the offset of a field in the C structure.
|
||||
"""
|
||||
|
||||
return getattr(cls, fname).offset
|
||||
|
||||
@classmethod
|
||||
def memberat(cls, offset: int) -> Optional[str]:
|
||||
"""Get the member name at a given offset.
|
||||
"""
|
||||
|
||||
return next((fname for fname, *_ in cls._fields_ if cls.offsetof(fname) == offset), None)
|
||||
|
||||
|
||||
class EnumMeta(type(ctypes.c_int)):
|
||||
def __getattr__(self, key):
|
||||
return self._members_.index(key)
|
||||
|
||||
@@ -594,8 +594,8 @@ def initialize(ql: Qiling, gBS: int):
|
||||
ql.os.monotonic_count = 0
|
||||
|
||||
instance = init_struct(ql, gBS, descriptor)
|
||||
instance.saveTo(ql, gBS)
|
||||
instance.save_to(ql.mem, gBS)
|
||||
|
||||
__all__ = [
|
||||
'initialize'
|
||||
]
|
||||
]
|
||||
|
||||
@@ -53,7 +53,7 @@ class UefiContext(ABC):
|
||||
address = self.heap.alloc(struct_class.sizeof())
|
||||
|
||||
instance = utils.init_struct(self.ql, address, proto_desc)
|
||||
instance.saveTo(self.ql, address)
|
||||
instance.save_to(self.ql.mem, address)
|
||||
|
||||
self.protocols[handle][guid] = address
|
||||
return self.notify_protocol(handle, guid, address, from_hook)
|
||||
@@ -66,7 +66,7 @@ class UefiContext(ABC):
|
||||
# and update it here.
|
||||
guid = utils.str_to_guid(protocol)
|
||||
guid_ptr = self.heap.alloc(guid.sizeof())
|
||||
guid.saveTo(self.ql, guid_ptr)
|
||||
guid.save_to(self.ql.mem, guid_ptr)
|
||||
|
||||
event_dic['CallbackArgs'] = [guid_ptr, interface, handle]
|
||||
|
||||
@@ -135,10 +135,10 @@ class UefiConfTable:
|
||||
ptr = self.baseptr + self.nitems * EFI_CONFIGURATION_TABLE.sizeof()
|
||||
append = True
|
||||
|
||||
instance = EFI_CONFIGURATION_TABLE()
|
||||
instance.VendorGuid = utils.str_to_guid(guid)
|
||||
instance.VendorTable = table
|
||||
instance.saveTo(self.ql, ptr)
|
||||
EFI_CONFIGURATION_TABLE(
|
||||
VendorGuid = utils.str_to_guid(guid),
|
||||
VendorTable = table
|
||||
).save_to(self.ql.mem, ptr)
|
||||
|
||||
if append:
|
||||
self.nitems += 1
|
||||
@@ -149,7 +149,7 @@ class UefiConfTable:
|
||||
efi_guid = utils.str_to_guid(guid)
|
||||
|
||||
for _ in range(nitems):
|
||||
entry = EFI_CONFIGURATION_TABLE.loadFrom(self.ql, ptr)
|
||||
entry = EFI_CONFIGURATION_TABLE.load_from(self.ql.mem, ptr)
|
||||
|
||||
if utils.CompareGuid(entry.VendorGuid, efi_guid):
|
||||
return ptr
|
||||
@@ -162,7 +162,7 @@ class UefiConfTable:
|
||||
ptr = self.find(guid)
|
||||
|
||||
if ptr is not None:
|
||||
entry = EFI_CONFIGURATION_TABLE.loadFrom(self.ql, ptr)
|
||||
entry = EFI_CONFIGURATION_TABLE.load_from(self.ql.mem, ptr)
|
||||
|
||||
return entry.VendorTable.value
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@ def initialize(ql: Qiling, gDS: int):
|
||||
}
|
||||
|
||||
instance = init_struct(ql, gDS, descriptor)
|
||||
instance.saveTo(ql, gDS)
|
||||
instance.save_to(ql.mem, gDS)
|
||||
|
||||
__all__ = [
|
||||
'EFI_DXE_SERVICES',
|
||||
|
||||
@@ -36,7 +36,7 @@ def GetHobList(ql: Qiling, context: UefiContext) -> int:
|
||||
|
||||
return hoblist_vend
|
||||
|
||||
def CreateHob(ql: Qiling, context: UefiContext, hob) -> int:
|
||||
def CreateHob(ql: Qiling, context: UefiContext, hob: STRUCT) -> int:
|
||||
"""Add a HOB to the end of the HOB list.
|
||||
"""
|
||||
|
||||
@@ -48,15 +48,15 @@ def CreateHob(ql: Qiling, context: UefiContext, hob) -> int:
|
||||
|
||||
# overwrite end marker with the hob
|
||||
pHob = hoblist
|
||||
hob.saveTo(ql, pHob)
|
||||
hob.save_to(ql.mem, pHob)
|
||||
hoblist += hob.sizeof()
|
||||
|
||||
# create a new end marker istead, following the hob
|
||||
marker = EFI_HOB_GENERIC_HEADER()
|
||||
marker.HobType = EFI_HOB_TYPE_END_OF_HOB_LIST
|
||||
marker.HobLength = 0x0000
|
||||
marker.Reserved = 0x00000000
|
||||
marker.saveTo(ql, hoblist)
|
||||
EFI_HOB_GENERIC_HEADER(
|
||||
HobType = EFI_HOB_TYPE_END_OF_HOB_LIST,
|
||||
HobLength = 0x0000,
|
||||
Reserved = 0x00000000
|
||||
).save_to(ql.mem, hoblist)
|
||||
|
||||
# return the address the hob was written to; it might be useful
|
||||
return pHob
|
||||
@@ -68,7 +68,7 @@ def GetNextHob(ql: Qiling, hobtype: int, hoblist: int) -> int:
|
||||
hobaddr = hoblist
|
||||
|
||||
while True:
|
||||
header = EFI_HOB_GENERIC_HEADER.loadFrom(ql, hobaddr)
|
||||
header = EFI_HOB_GENERIC_HEADER.load_from(ql.mem, hobaddr)
|
||||
|
||||
# found the hob?
|
||||
if header.HobType == hobtype:
|
||||
@@ -95,7 +95,7 @@ def GetNextGuidHob(ql: Qiling, guid: str, hoblist: int) -> int:
|
||||
if not hobaddr:
|
||||
return 0
|
||||
|
||||
hob = EFI_HOB_GUID_TYPE.loadFrom(ql, hobaddr)
|
||||
hob = EFI_HOB_GUID_TYPE.load_from(ql.mem, hobaddr)
|
||||
|
||||
if CompareGuid(hob.Name, hobguid):
|
||||
break
|
||||
|
||||
@@ -47,7 +47,7 @@ class EFI_SMM_ACCESS2_PROTOCOL(STRUCT):
|
||||
def hook_Open(ql: Qiling, address: int, params):
|
||||
this = params["This"]
|
||||
|
||||
with EFI_SMM_ACCESS2_PROTOCOL.bindTo(ql, this) as struct:
|
||||
with EFI_SMM_ACCESS2_PROTOCOL.ref(ql.mem, this) as struct:
|
||||
struct.OpenState = True
|
||||
|
||||
return EFI_SUCCESS
|
||||
@@ -58,7 +58,7 @@ def hook_Open(ql: Qiling, address: int, params):
|
||||
def hook_Close(ql: Qiling, address: int, params):
|
||||
this = params["This"]
|
||||
|
||||
with EFI_SMM_ACCESS2_PROTOCOL.bindTo(ql, this) as struct:
|
||||
with EFI_SMM_ACCESS2_PROTOCOL.ref(ql.mem, this) as struct:
|
||||
struct.OpenState = False
|
||||
|
||||
return EFI_SUCCESS
|
||||
@@ -69,7 +69,7 @@ def hook_Close(ql: Qiling, address: int, params):
|
||||
def hook_Lock(ql: Qiling, address: int, params):
|
||||
this = params["This"]
|
||||
|
||||
with EFI_SMM_ACCESS2_PROTOCOL.bindTo(ql, this) as struct:
|
||||
with EFI_SMM_ACCESS2_PROTOCOL.ref(ql.mem, this) as struct:
|
||||
struct.LockState = True
|
||||
|
||||
return EFI_SUCCESS
|
||||
@@ -143,7 +143,7 @@ def hook_GetCapabilities(ql: Qiling, address: int, params):
|
||||
return EFI_BUFFER_TOO_SMALL
|
||||
|
||||
this = params["This"]
|
||||
struct = EFI_SMM_ACCESS2_PROTOCOL.loadFrom(ql, this)
|
||||
struct = EFI_SMM_ACCESS2_PROTOCOL.load_from(ql.mem, this)
|
||||
|
||||
state = EFI_CACHEABLE
|
||||
state |= EFI_SMRAM_OPEN if struct.OpenState else EFI_SMRAM_CLOSED
|
||||
@@ -152,13 +152,12 @@ def hook_GetCapabilities(ql: Qiling, address: int, params):
|
||||
MmramMap = params["MmramMap"]
|
||||
|
||||
for i, ch in enumerate(chunks):
|
||||
desc = EFI_SMRAM_DESCRIPTOR()
|
||||
desc.PhysicalStart = ch[0]
|
||||
desc.CpuStart = ch[0]
|
||||
desc.PhysicalSize = ch[1] - ch[0]
|
||||
desc.RegionState = state | (EFI_ALLOCATED if ch[2] else 0)
|
||||
|
||||
desc.saveTo(ql, MmramMap + (i * desc.sizeof()))
|
||||
EFI_SMRAM_DESCRIPTOR(
|
||||
PhysicalStart = ch[0],
|
||||
CpuStart = ch[0],
|
||||
PhysicalSize = ch[1] - ch[0],
|
||||
RegionState = state | (EFI_ALLOCATED if ch[2] else 0)
|
||||
).save_to(ql.mem, MmramMap + (i * EFI_SMRAM_DESCRIPTOR.sizeof()))
|
||||
|
||||
return EFI_SUCCESS
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ def hook_Register(ql: Qiling, address: int, params):
|
||||
|
||||
handlers = ql.loader.smm_context.swsmi_handlers
|
||||
|
||||
SwRegisterContext = EFI_SMM_SW_REGISTER_CONTEXT.loadFrom(ql, RegisterContext)
|
||||
SwRegisterContext = EFI_SMM_SW_REGISTER_CONTEXT.load_from(ql.mem, RegisterContext)
|
||||
idx = SwRegisterContext.SwSmiInputValue
|
||||
|
||||
# a value of -1 indicates that the swsmi index for this handler is flexible and
|
||||
@@ -67,10 +67,10 @@ def hook_Register(ql: Qiling, address: int, params):
|
||||
return EFI_OUT_OF_RESOURCES
|
||||
|
||||
SwRegisterContext.SwSmiInputValue = idx
|
||||
SwRegisterContext.saveTo(ql, RegisterContext)
|
||||
SwRegisterContext.save_to(ql.mem, RegisterContext)
|
||||
|
||||
else:
|
||||
This = EFI_SMM_SW_DISPATCH2_PROTOCOL.loadFrom(ql, params['This'])
|
||||
This = EFI_SMM_SW_DISPATCH2_PROTOCOL.load_from(ql.mem, params['This'])
|
||||
|
||||
if idx in handlers:
|
||||
return EFI_INVALID_PARAMETER
|
||||
|
||||
+14
-15
@@ -34,21 +34,20 @@ def hook_GetTime(ql: Qiling, address: int, params):
|
||||
|
||||
localtime = time.localtime()
|
||||
|
||||
efitime = EFI_TIME()
|
||||
efitime.Year = localtime.tm_year
|
||||
efitime.Month = localtime.tm_mon
|
||||
efitime.Day = localtime.tm_mday
|
||||
efitime.Hour = localtime.tm_hour
|
||||
efitime.Minute = localtime.tm_min
|
||||
efitime.Second = localtime.tm_sec
|
||||
efitime.Nanosecond = 0
|
||||
EFI_TIME(
|
||||
Year = localtime.tm_year,
|
||||
Month = localtime.tm_mon,
|
||||
Day = localtime.tm_mday,
|
||||
Hour = localtime.tm_hour,
|
||||
Minute = localtime.tm_min,
|
||||
Second = localtime.tm_sec,
|
||||
Nanosecond = 0,
|
||||
|
||||
# tz and dst settings are stored in the "RtcTimeSettings" nvram variable.
|
||||
# we just use the default settings instead
|
||||
efitime.TimeZone = EFI_UNSPECIFIED_TIMEZONE
|
||||
efitime.Daylight = 0
|
||||
|
||||
efitime.saveTo(ql, Time)
|
||||
# tz and dst settings are stored in the "RtcTimeSettings" nvram variable.
|
||||
# we just use the default settings instead
|
||||
TimeZone = EFI_UNSPECIFIED_TIMEZONE,
|
||||
Daylight = 0
|
||||
).save_to(ql.mem, Time)
|
||||
|
||||
return EFI_SUCCESS
|
||||
|
||||
@@ -296,7 +295,7 @@ def initialize(ql: Qiling, gRT: int):
|
||||
}
|
||||
|
||||
instance = init_struct(ql, gRT, descriptor)
|
||||
instance.saveTo(ql, gRT)
|
||||
instance.save_to(ql.mem, gRT)
|
||||
|
||||
__all__ = [
|
||||
'initialize'
|
||||
|
||||
@@ -219,17 +219,17 @@ class SmmEnv:
|
||||
CommBufferSize = heap.alloc(ql.arch.pointersize)
|
||||
|
||||
# setup Context
|
||||
args['RegisterContext'].saveTo(ql, Context)
|
||||
args['RegisterContext'].save_to(ql.mem, Context)
|
||||
|
||||
# setup CommBuffer
|
||||
SmmSwContext = EFI_SMM_SW_CONTEXT()
|
||||
SmmSwContext.SwSmiCpuIndex = cpu
|
||||
SmmSwContext.CommandPort = idx
|
||||
SmmSwContext.DataPort = 0
|
||||
SmmSwContext.saveTo(ql, CommBuffer)
|
||||
EFI_SMM_SW_CONTEXT(
|
||||
SwSmiCpuIndex = cpu,
|
||||
CommandPort = idx,
|
||||
DataPort = 0
|
||||
).save_to(ql.mem, CommBuffer)
|
||||
|
||||
# setup CommBufferSize
|
||||
ql.mem.write_ptr(CommBufferSize, SmmSwContext.sizeof(), 8)
|
||||
ql.mem.write_ptr(CommBufferSize, EFI_SMM_SW_CONTEXT.sizeof(), 8)
|
||||
|
||||
# clean up handler resources
|
||||
def __cleanup(ql: Qiling):
|
||||
|
||||
@@ -278,7 +278,7 @@ def initialize(ql: Qiling, context, gSmst: int):
|
||||
}
|
||||
|
||||
instance = init_struct(ql, gSmst, descriptor)
|
||||
instance.saveTo(ql, gSmst)
|
||||
instance.save_to(ql.mem, gSmst)
|
||||
|
||||
install_configuration_table(context, "HOB_LIST", None)
|
||||
install_configuration_table(context, "SMM_RUNTIME_SERVICES_TABLE", gSmmRT)
|
||||
|
||||
@@ -67,13 +67,12 @@ def initialize(ql: Qiling, context: UefiContext, gST: int):
|
||||
rt.initialize(ql, gRT)
|
||||
ds.initialize(ql, gDS)
|
||||
|
||||
instance = EFI_SYSTEM_TABLE()
|
||||
instance.RuntimeServices = gRT
|
||||
instance.BootServices = gBS
|
||||
instance.NumberOfTableEntries = 0
|
||||
instance.ConfigurationTable = cfg
|
||||
|
||||
instance.saveTo(ql, gST)
|
||||
EFI_SYSTEM_TABLE(
|
||||
RuntimeServices = gRT,
|
||||
BootServices = gBS,
|
||||
NumberOfTableEntries = 0,
|
||||
ConfigurationTable = cfg
|
||||
).save_to(ql.mem, gST)
|
||||
|
||||
install_configuration_table(context, "HOB_LIST", None)
|
||||
install_configuration_table(context, "DXE_SERVICE_TABLE", gDS)
|
||||
|
||||
Reference in New Issue
Block a user