Skip to content

Commit 18d812e

Browse files
committed
Add SimpleText protocols to UEFI
1 parent e14ccf1 commit 18d812e

File tree

4 files changed

+254
-48
lines changed

4 files changed

+254
-48
lines changed

qiling/os/uefi/UefiSpec.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
from .UefiBaseType import *
1111
from .UefiMultiPhase import *
1212

13+
from .protocols.EfiSimpleTextInProtocol import EFI_SIMPLE_TEXT_INPUT_PROTOCOL
14+
from .protocols.EfiSimpleTextOutProtocol import EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
15+
16+
1317
# definitions for EFI_TIME.Daylight
1418
EFI_TIME_ADJUST_DAYLIGHT = (1 << 1)
1519
EFI_TIME_IN_DAYLIGHT = (1 << 2)
@@ -223,14 +227,6 @@ class EFI_CONFIGURATION_TABLE(STRUCT):
223227
('VendorTable', PTR(VOID)),
224228
]
225229

226-
# TODO: to be implemented
227-
# @see: MdePkg\Include\Protocol\SimpleTextIn.h
228-
EFI_SIMPLE_TEXT_INPUT_PROTOCOL = STRUCT
229-
230-
# TODO: to be implemented
231-
# @see: MdePkg\Include\Protocol\SimpleTextOut.h
232-
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL = STRUCT
233-
234230
class EFI_SYSTEM_TABLE(STRUCT):
235231
_pack_ = 8
236232

@@ -264,4 +260,4 @@ class EFI_SYSTEM_TABLE(STRUCT):
264260
'EFI_DEVICE_PATH_PROTOCOL',
265261
'EFI_OPEN_PROTOCOL_INFORMATION_ENTRY',
266262
'EFI_IMAGE_UNLOAD'
267-
]
263+
]
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
4+
#
5+
6+
from qiling.os.const import *
7+
from qiling.os.uefi.fncc import dxeapi
8+
from qiling.os.uefi.utils import *
9+
from qiling.os.uefi.ProcessorBind import *
10+
from qiling.os.uefi.UefiBaseType import EFI_STATUS, EFI_EVENT
11+
12+
13+
# @see: MdePkg/Include/Protocol/SimpleTextIn.h
14+
class EFI_INPUT_KEY(STRUCT):
15+
_fields_ = [
16+
('ScanCode', UINT16),
17+
('UnicodeChar', CHAR16)
18+
]
19+
20+
class EFI_SIMPLE_TEXT_INPUT_PROTOCOL(STRUCT):
21+
EFI_SIMPLE_TEXT_INPUT_PROTOCOL = STRUCT
22+
23+
_fields_ = [
24+
('Reset', FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_INPUT_PROTOCOL), BOOLEAN)),
25+
('ReadKeyStroke', FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_INPUT_PROTOCOL), PTR(EFI_INPUT_KEY))),
26+
('WaitForKey', EFI_EVENT)
27+
]
28+
29+
30+
@dxeapi(params={
31+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
32+
"ExtendedVerification": BOOL # IN BOOLEAN
33+
})
34+
def hook_Input_Reset(ql: Qiling, address: int, params):
35+
pass
36+
37+
@dxeapi(params={
38+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
39+
"Key": POINTER # OUT PTR(EFI_INPUT_KEY)
40+
})
41+
def hook_Read_Key_Stroke(ql: Qiling, address: int, params):
42+
pass
43+
44+
45+
def initialize(ql: Qiling, gIP: int):
46+
descriptor = {
47+
'struct': EFI_SIMPLE_TEXT_INPUT_PROTOCOL,
48+
'fields': (
49+
('Reset', hook_Input_Reset),
50+
('ReadKeyStroke', hook_Read_Key_Stroke),
51+
('WaitForKey', None)
52+
)
53+
}
54+
55+
instance = init_struct(ql, gIP, descriptor)
56+
instance.save_to(ql.mem, gIP)
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
4+
#
5+
6+
from qiling.os.const import *
7+
from qiling.os.uefi.fncc import dxeapi
8+
from qiling.os.uefi.utils import *
9+
from qiling.os.uefi.ProcessorBind import *
10+
from qiling.os.uefi.UefiBaseType import EFI_STATUS
11+
12+
13+
# @see: MdePkg/Include/Protocol/SimpleTextOut.h
14+
class SIMPLE_TEXT_OUTPUT_MODE(STRUCT):
15+
_fields_ = [
16+
("MaxMode", INT32),
17+
("Mode", INT32),
18+
("Attribute", INT32),
19+
("CursorColumn", INT32),
20+
("CursorRow", INT32),
21+
("CursorVisible", BOOLEAN),
22+
]
23+
24+
25+
class EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL(STRUCT):
26+
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL = STRUCT
27+
28+
_fields_ = [
29+
("Reset", FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL), BOOLEAN)),
30+
("OutputString", FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL), PTR(CHAR16))),
31+
("TestString", FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL), PTR(CHAR16))),
32+
("QueryMode", FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL), UINTN, PTR(UINTN), PTR(UINTN))),
33+
("SetMode", FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL), UINTN)),
34+
("SetAttribute", FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL), UINTN)),
35+
("ClearScreen", FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL))),
36+
("SetCursorPosition", FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL), UINTN, UINTN)),
37+
("EnableCursor", FUNCPTR(EFI_STATUS, PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL), BOOLEAN)),
38+
("Mode", PTR(SIMPLE_TEXT_OUTPUT_MODE))
39+
]
40+
41+
42+
@dxeapi(params={
43+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
44+
"ExtendedVerification": BOOL # IN BOOLEAN
45+
})
46+
def hook_TextReset(ql: Qiling, address: int, params):
47+
pass
48+
49+
@dxeapi(params={
50+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
51+
"String": WSTRING # IN PTR(CHAR16)
52+
})
53+
def hook_OutputString(ql: Qiling, address: int, params):
54+
print(params['String'])
55+
56+
return EFI_SUCCESS
57+
58+
@dxeapi(params={
59+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
60+
"String": WSTRING # IN PTR(CHAR16)
61+
})
62+
def hook_TestString(ql: Qiling, address: int, params):
63+
pass
64+
65+
@dxeapi(params={
66+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
67+
"ModeNumber": ULONGLONG, # IN UINTN
68+
"Columns": POINTER, # OUT PTR(UINTN)
69+
"Rows": POINTER # OUT PTR(UINTN)
70+
})
71+
def hook_QueryMode(ql: Qiling, address: int, params):
72+
pass
73+
74+
@dxeapi(params={
75+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
76+
"ModeNumber": ULONGLONG # IN UINTN
77+
})
78+
def hook_SetMode(ql: Qiling, address: int, params):
79+
pass
80+
81+
@dxeapi(params={
82+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
83+
"Attribute": ULONGLONG # IN UINTN
84+
})
85+
def hook_SetAttribute(ql: Qiling, address: int, params):
86+
pass
87+
88+
@dxeapi(params={
89+
"This": POINTER # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
90+
})
91+
def hook_ClearScreen(ql: Qiling, address: int, params):
92+
pass
93+
94+
@dxeapi(params={
95+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
96+
"Column": ULONGLONG, # IN UINTN
97+
"Row": ULONGLONG # IN UINTN
98+
})
99+
def hook_SetCursorPosition(ql: Qiling, address: int, params):
100+
pass
101+
102+
@dxeapi(params={
103+
"This": POINTER, # IN PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
104+
"Visible": BOOL # IN BOOLEAN
105+
})
106+
def hook_EnableCursor(ql: Qiling, address: int, params):
107+
pass
108+
109+
110+
def initialize(ql: Qiling, base: int):
111+
descriptor = {
112+
'struct': EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL,
113+
'fields': (
114+
('Reset', hook_TextReset),
115+
('OutputString', hook_OutputString),
116+
('TestString', hook_TestString),
117+
('QueryMode', hook_QueryMode),
118+
('SetMode', hook_SetMode),
119+
('SetAttribute', hook_SetAttribute),
120+
('ClearScreen', hook_ClearScreen),
121+
('SetCursorPosition', hook_SetCursorPosition),
122+
('EnableCursor', hook_EnableCursor),
123+
('Mode', None)
124+
)
125+
}
126+
127+
instance = init_struct(ql, base, descriptor)
128+
instance.save_to(ql.mem, base)

qiling/os/uefi/st.py

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

6-
from qiling import Qiling
6+
from typing import TYPE_CHECKING
7+
78
from qiling.os.uefi import bs, rt, ds
89
from qiling.os.uefi.context import UefiContext
910
from qiling.os.uefi.utils import install_configuration_table
10-
from qiling.os.uefi.UefiSpec import EFI_SYSTEM_TABLE, EFI_BOOT_SERVICES, EFI_RUNTIME_SERVICES
11+
from qiling.os.uefi.UefiSpec import EFI_SYSTEM_TABLE, EFI_SIMPLE_TEXT_INPUT_PROTOCOL, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL, EFI_BOOT_SERVICES, EFI_RUNTIME_SERVICES
12+
13+
import qiling.os.uefi.protocols.EfiSimpleTextInProtocol as txt_in
14+
import qiling.os.uefi.protocols.EfiSimpleTextOutProtocol as txt_out
15+
16+
17+
if TYPE_CHECKING:
18+
from qiling import Qiling
1119

1220
# static mem layout:
1321
#
14-
# +-- EFI_SYSTEM_TABLE ---------+
15-
# | |
16-
# | ... |
17-
# | RuntimeServices* -> (1) |
18-
# | BootServices* -> (2) |
19-
# | NumberOfTableEntries |
20-
# | ConfigurationTable* -> (4) |
21-
# +-----------------------------+
22-
# (1) +-- EFI_RUNTIME_SERVICES -----+
23-
# | |
24-
# | ... |
25-
# +-----------------------------+
26-
# (2) +-- EFI_BOOT_SERVICES --------+
27-
# | |
28-
# | ... |
29-
# +-----------------------------+
30-
# (3) +-- EFI_DXE_SERVICES ---------+
31-
# | |
32-
# | ... |
33-
# +-----------------------------+
34-
# (4) +-- EFI_CONFIGURATION_TABLE --+ of HOB_LIST
35-
# | VendorGuid |
36-
# | VendorTable* -> (5) |
37-
# +-----------------------------+
38-
# +-- EFI_CONFIGURATION_TABLE --+ of DXE_SERVICE_TABLE
39-
# | VendorGuid |
40-
# | VendorTable* -> (3) |
41-
# +-----------------------------+
22+
# +-- EFI_SYSTEM_TABLE -----------------+
23+
# | |
24+
# | ... |
25+
# | ConIn* -> (1) |
26+
# | ConOut* -> (2) |
27+
# | RuntimeServices* -> (3) |
28+
# | BootServices* -> (4) |
29+
# | NumberOfTableEntries |
30+
# | ConfigurationTable* -> (6) |
31+
# +-------------------------------------+
32+
# (1) +-- EFI_SIMPLE_TEXT_INPUT_PROTOCOL ---+
33+
# | |
34+
# | ... |
35+
# +-------------------------------------+
36+
# (2) +-- EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL --+
37+
# | |
38+
# | ... |
39+
# +-------------------------------------+
40+
# (3) +-- EFI_RUNTIME_SERVICES -------------+
41+
# | |
42+
# | ... |
43+
# +-------------------------------------+
44+
# (4) +-- EFI_BOOT_SERVICES ----------------+
45+
# | |
46+
# | ... |
47+
# +-------------------------------------+
48+
# (5) +-- EFI_DXE_SERVICES -----------------+
49+
# | |
50+
# | ... |
51+
# +-------------------------------------+
52+
# (6) +-- EFI_CONFIGURATION_TABLE ----------+ of HOB_LIST
53+
# | VendorGuid |
54+
# | VendorTable* -> (7) |
55+
# +-------------------------------------+
56+
# +-- EFI_CONFIGURATION_TABLE ----------+ of DXE_SERVICE_TABLE
57+
# | VendorGuid |
58+
# | VendorTable* -> (5) |
59+
# +-------------------------------------+
4260
#
4361
# ... the remainder of the chunk may be used for additional EFI_CONFIGURATION_TABLE entries
44-
62+
#
4563
# dynamically allocated (context.conf_table_data_ptr):
4664
#
47-
# (5) +-- VOID* --------------------+
48-
# | ... |
49-
# +-----------------------------+
65+
# (7) +-- VOID* ----------------------------+
66+
# | ... |
67+
# +-------------------------------------+
68+
5069

5170
def initialize(ql: Qiling, context: UefiContext, gST: int):
5271
ql.loader.gST = gST
5372

54-
gBS = gST + EFI_SYSTEM_TABLE.sizeof() # boot services
55-
gRT = gBS + EFI_BOOT_SERVICES.sizeof() # runtime services
56-
gDS = gRT + EFI_RUNTIME_SERVICES.sizeof() # dxe services
57-
cfg = gDS + ds.EFI_DXE_SERVICES.sizeof() # configuration tables array
73+
sti = gST + EFI_SYSTEM_TABLE.sizeof() # input protocols
74+
sto = sti + EFI_SIMPLE_TEXT_INPUT_PROTOCOL.sizeof() # output protocols
75+
gRT = sto + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.sizeof() # runtime services
76+
gBS = gRT + EFI_RUNTIME_SERVICES.sizeof() # boot services
77+
gDS = gBS + EFI_BOOT_SERVICES.sizeof() # dxe services
78+
cfg = gDS + ds.EFI_DXE_SERVICES.sizeof() # configuration tables array
5879

5980
ql.log.info(f'Global tables:')
6081
ql.log.info(f' | gST {gST:#010x}')
@@ -63,11 +84,16 @@ def initialize(ql: Qiling, context: UefiContext, gST: int):
6384
ql.log.info(f' | gDS {gDS:#010x}')
6485
ql.log.info(f'')
6586

87+
txt_in.initialize(ql, sti)
88+
txt_out.initialize(ql, sto)
89+
6690
bs.initialize(ql, gBS)
6791
rt.initialize(ql, gRT)
6892
ds.initialize(ql, gDS)
6993

7094
EFI_SYSTEM_TABLE(
95+
ConIn = sti,
96+
ConOut = sto,
7197
RuntimeServices = gRT,
7298
BootServices = gBS,
7399
NumberOfTableEntries = 0,
@@ -79,4 +105,4 @@ def initialize(ql: Qiling, context: UefiContext, gST: int):
79105

80106
__all__ = [
81107
'initialize'
82-
]
108+
]

0 commit comments

Comments
 (0)