Skip to content

Commit 2b50220

Browse files
authored
Merge pull request #790 from elicn/dev-uefi-imp
Misc. UEFI improvements and bugfixes
2 parents ecbac7f + ec36637 commit 2b50220

File tree

8 files changed

+128
-51
lines changed

8 files changed

+128
-51
lines changed

qiling/os/uefi/bs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ def hook_SetMem(ql: Qiling, address: int, params):
510510
def hook_CreateEventEx(ql: Qiling, address: int, params):
511511
return CreateEvent(ql, params)
512512

513-
def CreateEvent(ql, params):
513+
def CreateEvent(ql: Qiling, params):
514514
event_id = len(ql.loader.events)
515515
event_dic = {
516516
"NotifyFunction": params["NotifyFunction"],

qiling/os/uefi/hob.py

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
#
55

66
from qiling import Qiling
7-
from qiling.os.uefi.utils import GetEfiConfigurationTable
7+
from qiling.os.uefi.context import UefiContext
8+
from qiling.os.uefi.utils import GetEfiConfigurationTable, CompareGuid, str_to_guid
89
from qiling.os.uefi.UefiBaseType import STRUCT, EFI_GUID, UINT32, UINT16
910
from qiling.os.uefi.UefiSpec import EFI_CONFIGURATION_TABLE
1011

@@ -25,31 +26,25 @@ class EFI_HOB_GUID_TYPE(STRUCT):
2526
('Name', EFI_GUID)
2627
]
2728

28-
def GetHobList(ql: Qiling) -> int:
29+
def GetHobList(ql: Qiling, context: UefiContext) -> int:
2930
"""Get HOB list location in memory (ostensibly set by PEI).
3031
"""
3132

3233
conftable_guid = ql.os.profile['HOB_LIST']['Guid']
33-
conftable_ptr = GetEfiConfigurationTable(ql.loader.dxe_context, conftable_guid)
34+
conftable_ptr = GetEfiConfigurationTable(context, conftable_guid)
3435
conftable = EFI_CONFIGURATION_TABLE.loadFrom(ql, conftable_ptr)
3536

3637
return ql.unpack64(conftable.VendorTable)
3738

38-
def CreateHob(ql: Qiling, hob) -> int:
39+
def CreateHob(ql: Qiling, context: UefiContext, hob) -> int:
3940
"""Add a HOB to the end of the HOB list.
4041
"""
4142

42-
hoblist = GetHobList(ql)
43+
hoblist = GetHobList(ql, context)
4344

4445
# look for the list end marker; uefi codebase assumes there is
4546
# always one
46-
while True:
47-
header = EFI_HOB_GENERIC_HEADER.loadFrom(ql, hoblist)
48-
49-
if header.HobType == EFI_HOB_TYPE_END_OF_HOB_LIST:
50-
break
51-
52-
hoblist += header.HobLength
47+
hoblist = GetNextHob(ql, EFI_HOB_TYPE_END_OF_HOB_LIST, hoblist)
5348

5449
# overwrite end marker with the hob
5550
pHob = hoblist
@@ -65,3 +60,46 @@ def CreateHob(ql: Qiling, hob) -> int:
6560

6661
# return the address the hob was written to; it might be useful
6762
return pHob
63+
64+
def GetNextHob(ql: Qiling, hobtype: int, hoblist: int) -> int:
65+
"""Get next HOB on the list.
66+
"""
67+
68+
hobaddr = hoblist
69+
70+
while True:
71+
header = EFI_HOB_GENERIC_HEADER.loadFrom(ql, hobaddr)
72+
73+
# found the hob?
74+
if header.HobType == hobtype:
75+
break
76+
77+
# reached end of hob list?
78+
if header.HobType == EFI_HOB_TYPE_END_OF_HOB_LIST:
79+
return 0
80+
81+
hobaddr += header.HobLength
82+
83+
return hobaddr
84+
85+
def GetNextGuidHob(ql: Qiling, guid: str, hoblist: int):
86+
"""Find next HOB with the specified GUID.
87+
"""
88+
89+
hobguid = str_to_guid(guid)
90+
hobaddr = hoblist
91+
92+
while True:
93+
hobaddr = GetNextHob(ql, EFI_HOB_TYPE_GUID_EXTENSION, hobaddr)
94+
95+
if not hobaddr:
96+
return 0
97+
98+
hob = EFI_HOB_GUID_TYPE.loadFrom(ql, hobaddr)
99+
100+
if CompareGuid(hob.Name, hobguid):
101+
break
102+
103+
hobaddr += hob.Header.HobLength
104+
105+
return hobaddr

qiling/os/uefi/protocols/EfiSmmAccess2Protocol.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

6+
from qiling import Qiling
67
from qiling.os.const import *
78
from qiling.os.uefi.const import *
89
from ..fncc import *
910
from ..ProcessorBind import *
1011
from ..UefiBaseType import *
1112
from ..PiMultiPhase import *
12-
from ..utils import write_int64, read_int64
13+
from .. import utils
1314

1415
# @see: MdePkg\Include\Pi\PiMultiPhase.h
1516
class EFI_MMRAM_DESCRIPTOR(STRUCT):
@@ -37,23 +38,23 @@ class EFI_SMM_ACCESS2_PROTOCOL(STRUCT):
3738
@dxeapi(params = {
3839
"This" : POINTER
3940
})
40-
def hook_Open(ql, address, params):
41+
def hook_Open(ql: Qiling, address: int, params):
4142
ql.loader.smm_context.tseg_open = True
4243

4344
return EFI_SUCCESS
4445

4546
@dxeapi(params = {
4647
"This" : POINTER
4748
})
48-
def hook_Close(ql, address, params):
49+
def hook_Close(ql: Qiling, address: int, params):
4950
ql.loader.smm_context.tseg_open = False
5051

5152
return EFI_SUCCESS
5253

5354
@dxeapi(params = {
5455
"This" : POINTER
5556
})
56-
def hook_Lock(ql, address, params):
57+
def hook_Lock(ql: Qiling, address: int, params):
5758
ql.loader.smm_context.tseg_locked = True
5859

5960
return EFI_SUCCESS
@@ -84,7 +85,7 @@ def _coalesce(seq):
8485
"MmramMapSize" : POINTER, # IN OUT PTR(UINTN)
8586
"MmramMap" : POINTER # OUT PTR(EFI_MMRAM_DESCRIPTOR)
8687
})
87-
def hook_GetCapabilities(ql, address, params):
88+
def hook_GetCapabilities(ql: Qiling, address: int, params):
8889
heap = ql.loader.smm_context.heap
8990

9091
# get a copy of smm heap chunks list sorted by starting address
@@ -107,8 +108,23 @@ def hook_GetCapabilities(ql, address, params):
107108
size = len(chunks) * EFI_SMRAM_DESCRIPTOR.sizeof()
108109
MmramMapSize = params["MmramMapSize"]
109110

110-
if read_int64(ql, MmramMapSize) < size:
111-
write_int64(ql, MmramMapSize, size)
111+
if utils.read_int64(ql, MmramMapSize) < size:
112+
# since the caller cannot predict how much memory would be required for storing
113+
# the memory map, this method is normally called twice. the first one passes a
114+
# zero size only to determine the expected size, then the caller allocates the
115+
# required amount of memory and call it again.
116+
#
117+
# our memory map is managed differently from the real one, and memory allocations
118+
# are likely to generate an additional "map block" (or two, if allocated somewhere
119+
# in the last free heap chunk). because the caller allocates a new memory chunk
120+
# between the two calls, that would cause the second call to always complain the
121+
# buffer is too small.
122+
#
123+
# to work around that, we have the first call return a larger number than it should
124+
# have, to compensate on the coming allocation.
125+
extra = 2 * EFI_SMRAM_DESCRIPTOR.sizeof()
126+
127+
utils.write_int64(ql, MmramMapSize, size + extra)
112128
return EFI_BUFFER_TOO_SMALL
113129

114130
MmramMap = params["MmramMap"]

qiling/os/uefi/protocols/EfiSmmCpuProtocol.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,19 @@ class EFI_SMM_SAVE_STATE_REGISTER(ENUM_UC):
9898

9999
@dxeapi(params = {
100100
"This" : POINTER, # EFI_SMM_CPU_PROTOCOL
101-
"Width" : UINTN, # UINTN
101+
"Width" : ULONGLONG,# UINTN
102102
"Register" : INT, # EFI_SMM_SAVE_STATE_REGISTER
103-
"CpuIndex" : UINTN, # UINTN
103+
"CpuIndex" : ULONGLONG,# UINTN
104104
"Buffer" : POINTER # PTR(VOID))
105105
})
106106
def hook_SmmReadSaveState(ql, address, params):
107107
return EFI_SUCCESS
108108

109109
@dxeapi(params = {
110110
"This" : POINTER, # EFI_SMM_CPU_PROTOCOL
111-
"Width" : UINTN, # UINTN
111+
"Width" : ULONGLONG,# UINTN
112112
"Register" : INT, # EFI_SMM_SAVE_STATE_REGISTER
113-
"CpuIndex" : UINTN, # UINTN
113+
"CpuIndex" : ULONGLONG,# UINTN
114114
"Buffer" : POINTER # PTR(VOID))
115115
})
116116
def hook_SmmWriteSaveState(ql, address, params):

qiling/os/uefi/rt.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

6+
from qiling import Qiling
67
from qiling.os.const import *
78
from .const import *
89
from .utils import *
@@ -14,28 +15,28 @@
1415
"Time" : POINTER, # OUT PTR(EFI_TIME)
1516
"Capabilities" : POINTER # OUT PTR(EFI_TIME_CAPABILITIES)
1617
})
17-
def hook_GetTime(ql, address, params):
18+
def hook_GetTime(ql: Qiling, address: int, params):
1819
return EFI_SUCCESS
1920

2021
@dxeapi(params={
2122
"Time": POINTER # IN PTR(EFI_TIME)
2223
})
23-
def hook_SetTime(ql, address, params):
24+
def hook_SetTime(ql: Qiling, address: int, params):
2425
return EFI_SUCCESS
2526

2627
@dxeapi(params={
2728
"Enabled" : POINTER, # OUT PTR(BOOLEAN)
2829
"Pending" : POINTER, # OUT PTR(BOOLEAN)
2930
"Time" : POINTER # OUT PTR(EFI_TIME)
3031
})
31-
def hook_GetWakeupTime(ql, address, params):
32+
def hook_GetWakeupTime(ql: Qiling, address: int, params):
3233
return EFI_SUCCESS
3334

3435
@dxeapi(params={
3536
"Enable": BOOL, # BOOLEAN
3637
"Time" : POINTER # PTR(EFI_TIME)
3738
})
38-
def hook_SetWakeupTime(ql, address, params):
39+
def hook_SetWakeupTime(ql: Qiling, address: int, params):
3940
return EFI_SUCCESS
4041

4142
@dxeapi(params={
@@ -44,14 +45,14 @@ def hook_SetWakeupTime(ql, address, params):
4445
"DescriptorVersion" : UINT, # UINT32
4546
"VirtualMap" : POINTER # PTR(EFI_MEMORY_DESCRIPTOR)
4647
})
47-
def hook_SetVirtualAddressMap(ql, address, params):
48+
def hook_SetVirtualAddressMap(ql: Qiling, address: int, params):
4849
return EFI_SUCCESS
4950

5051
@dxeapi(params={
5152
"DebugDisposition" : UINT, # UINTN
5253
"Address" : POINTER # OUT PTR(PTR(VOID))
5354
})
54-
def hook_ConvertPointer(ql, address, params):
55+
def hook_ConvertPointer(ql: Qiling, address: int, params):
5556
return EFI_SUCCESS
5657

5758
@dxeapi(params={
@@ -61,28 +62,36 @@ def hook_ConvertPointer(ql, address, params):
6162
"DataSize" : POINTER, # IN OUT PTR(UINTN)
6263
"Data" : POINTER # OUT PTR(VOID)
6364
})
64-
def hook_GetVariable(ql, address, params):
65+
def hook_GetVariable(ql: Qiling, address: int, params):
6566
name = params['VariableName']
67+
6668
if name in ql.env:
6769
var = ql.env[name]
6870
read_len = read_int64(ql, params['DataSize'])
71+
6972
if params['Attributes'] != 0:
7073
write_int64(ql, params['Attributes'], 0)
74+
7175
write_int64(ql, params['DataSize'], len(var))
76+
7277
if read_len < len(var):
7378
return EFI_BUFFER_TOO_SMALL
79+
7480
if params['Data'] != 0:
7581
ql.mem.write(params['Data'], var)
82+
7683
return EFI_SUCCESS
84+
7785
ql.log.warning(f'variable with name {name} not found')
86+
7887
return EFI_NOT_FOUND
7988

8089
@dxeapi(params={
8190
"VariableNameSize" : POINTER, # IN OUT PTR(UINTN)
8291
"VariableName" : POINTER, # IN OUT PTR(CHAR16)
8392
"VendorGuid" : GUID # IN OUT PTR(EFI_GUID)
8493
})
85-
def hook_GetNextVariableName(ql, address, params):
94+
def hook_GetNextVariableName(ql: Qiling, address: int, params):
8695
var_name_size = params["VariableNameSize"]
8796
var_name = params["VariableName"]
8897

@@ -124,14 +133,14 @@ def hook_GetNextVariableName(ql, address, params):
124133
"DataSize" : UINT, # UINTN
125134
"Data" : POINTER # PTR(VOID)
126135
})
127-
def hook_SetVariable(ql, address, params):
136+
def hook_SetVariable(ql: Qiling, address: int, params):
128137
ql.env[params['VariableName']] = bytes(ql.mem.read(params['Data'], params['DataSize']))
129138
return EFI_SUCCESS
130139

131140
@dxeapi(params={
132141
"HighCount": POINTER # OUT PTR(UINT32)
133142
})
134-
def hook_GetNextHighMonotonicCount(ql, address, params):
143+
def hook_GetNextHighMonotonicCount(ql: Qiling, address: int, params):
135144
ql.os.monotonic_count += 0x0000000100000000
136145
hmc = ql.os.monotonic_count
137146
hmc = (hmc >> 32) & 0xffffffff
@@ -144,7 +153,7 @@ def hook_GetNextHighMonotonicCount(ql, address, params):
144153
"DataSize" : UINT, # UINTN
145154
"ResetData" : POINTER # PTR(VOID)
146155
})
147-
def hook_ResetSystem(ql, address, params):
156+
def hook_ResetSystem(ql: Qiling, address: int, params):
148157
ql.emu_stop()
149158

150159
return EFI_SUCCESS
@@ -154,7 +163,7 @@ def hook_ResetSystem(ql, address, params):
154163
"CapsuleCount" : UINT, # UINTN
155164
"ScatterGatherList" : ULONGLONG # EFI_PHYSICAL_ADDRESS
156165
})
157-
def hook_UpdateCapsule(ql, address, params):
166+
def hook_UpdateCapsule(ql: Qiling, address: int, params):
158167
return EFI_SUCCESS
159168

160169
@dxeapi(params={
@@ -163,7 +172,7 @@ def hook_UpdateCapsule(ql, address, params):
163172
"MaximumCapsuleSize": POINTER, # OUT PTR(UINT64)
164173
"ResetType" : POINTER # OUT PTR(EFI_RESET_TYPE)
165174
})
166-
def hook_QueryCapsuleCapabilities(ql, address, params):
175+
def hook_QueryCapsuleCapabilities(ql: Qiling, address: int, params):
167176
return EFI_SUCCESS
168177

169178
@dxeapi(params={
@@ -172,7 +181,7 @@ def hook_QueryCapsuleCapabilities(ql, address, params):
172181
"RemainingVariableStorageSize" : POINTER, # OUT PTR(UINT64)
173182
"MaximumVariableSize" : POINTER # OUT PTR(UINT64)
174183
})
175-
def hook_QueryVariableInfo(ql, address, params):
184+
def hook_QueryVariableInfo(ql: Qiling, address: int, params):
176185
return EFI_SUCCESS
177186

178187
def initialize(ql, gRT : int):

qiling/os/uefi/smst.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ def initialize(ql, gSmst : int):
287287
ql.loader.smm_context.conf_table_data_ptr = conf_data
288288
ql.loader.smm_context.conf_table_data_next_ptr = conf_data
289289

290+
install_configuration_table(ql.loader.smm_context, "HOB_LIST", None)
290291
install_configuration_table(ql.loader.smm_context, "SMM_RUNTIME_SERVICES_TABLE", gSmmRT)
291292

292293
__all__ = [

qiling/os/uefi/st.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

6+
from qiling import Qiling
67
from qiling.os.uefi import bs, rt, ds
78
from qiling.os.uefi.utils import install_configuration_table
89
from qiling.os.uefi.UefiSpec import EFI_SYSTEM_TABLE, EFI_BOOT_SERVICES, EFI_RUNTIME_SERVICES, EFI_CONFIGURATION_TABLE
@@ -46,7 +47,7 @@
4647
#
4748
# ... the remainder of the 256 KiB chunk may be used for more conf table data
4849

49-
def initialize(ql, gST : int):
50+
def initialize(ql: Qiling, gST: int):
5051
ql.loader.gST = gST
5152

5253
gBS = gST + EFI_SYSTEM_TABLE.sizeof() # boot services
@@ -90,8 +91,6 @@ def initialize(ql, gST : int):
9091
install_configuration_table(ql.loader.dxe_context, "HOB_LIST", None)
9192
install_configuration_table(ql.loader.dxe_context, "DXE_SERVICE_TABLE", gDS)
9293

93-
94-
9594
__all__ = [
9695
'initialize'
9796
]

0 commit comments

Comments
 (0)