Skip to content

Commit 4c06349

Browse files
committed
Implement PEI debug agent
This commit implements a PEI debug agent that supports post-memory environments. Because the PEI core doesn't have proper debug agent support, this also introduces a simple PEIM that initialized the debug agent. This PEIM has will only be dispatched when memory is discovered.
1 parent 6718ef6 commit 4c06349

6 files changed

Lines changed: 403 additions & 0 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/** @file
2+
Thin PEIM wrapper that invokes the PEI debug agent library.
3+
4+
This PEIM is dispatched after permanent memory is available (DEPEX on
5+
gEfiPeiMemoryDiscoveredPpiGuid). It simply calls InitializeDebugAgent
6+
to let the library perform all initialization.
7+
8+
Copyright (c) Microsoft Corporation.
9+
SPDX-License-Identifier: BSD-2-Clause-Patent
10+
11+
**/
12+
13+
#include <PiPei.h>
14+
#include <Library/DebugAgentLib.h>
15+
16+
/**
17+
PEIM entry point. Invokes the debug agent library initialization.
18+
19+
@param[in] FileHandle Handle of the file being loaded.
20+
@param[in] PeiServices Pointer to PEI Services table.
21+
22+
@retval EFI_SUCCESS Debug agent initialized successfully.
23+
24+
**/
25+
EFI_STATUS
26+
EFIAPI
27+
DebugAgentPeiEntry (
28+
IN EFI_PEI_FILE_HANDLE FileHandle,
29+
IN CONST EFI_PEI_SERVICES **PeiServices
30+
)
31+
{
32+
InitializeDebugAgent (DEBUG_AGENT_INIT_PEI, NULL, NULL);
33+
return EFI_SUCCESS;
34+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## @file
2+
#
3+
# Thin PEIM wrapper for the PEI debug agent. All logic lives in
4+
# DebugAgentLib (PeiDebugAgentLib). This PEIM is dispatched after
5+
# permanent memory is installed.
6+
#
7+
# Copyright (c) Microsoft Corporation.
8+
# SPDX-License-Identifier: BSD-2-Clause-Patent
9+
#
10+
##
11+
12+
13+
[Defines]
14+
INF_VERSION = 1.27
15+
BASE_NAME = DebugAgentPei
16+
FILE_GUID = 7A4F8B72-E12D-4A62-B5C4-D43F89735E28
17+
MODULE_TYPE = PEIM
18+
VERSION_STRING = 1.0
19+
ENTRY_POINT = DebugAgentPeiEntry
20+
21+
[Sources]
22+
DebugAgentPei.c
23+
24+
[Packages]
25+
MdePkg/MdePkg.dec
26+
MdeModulePkg/MdeModulePkg.dec
27+
DebuggerFeaturePkg/DebuggerFeaturePkg.dec
28+
29+
[LibraryClasses]
30+
PeimEntryPoint
31+
DebugAgentLib
32+
PrintLib
33+
34+
[Ppis]
35+
gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES
36+
37+
[Depex]
38+
gEfiPeiMemoryDiscoveredPpiGuid

DebuggerFeaturePkg/DebuggerFeaturePkg.dec

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@
5454
# phase implementation.
5555
DebuggerFeaturePkgTokenSpaceGuid.PcdForceEnableDebugger|FALSE|BOOLEAN|0x00000003
5656

57+
## Forcibly enables the PEI debugger. This is the only way to enable the PEI
58+
# phase debugger. No HOB or dynamic configuration is supported for PEI.
59+
DebuggerFeaturePkgTokenSpaceGuid.PcdForceEnablePeiDebugger|FALSE|BOOLEAN|0x00000005
60+
5761
## Enabled work-arounds in the debugger for bugs in windbg's GDB implementation.
5862
# This should not break GDB debuggers, but may cause slightly unexpected behavior.
5963
DebuggerFeaturePkgTokenSpaceGuid.PcdEnableWindbgWorkarounds|TRUE|BOOLEAN|0x00000004

DebuggerFeaturePkg/DebuggerFeaturePkg.dsc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@
3838
WatchdogTimerLib|DebuggerFeaturePkg/Library/WatchdogTimerLibNull/WatchdogTimerLibNull.inf
3939
TransportLogControlLib|DebuggerFeaturePkg/Library/TransportLogControlLibNull/TransportLogControlLibNull.inf
4040

41+
CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLibNull/BaseCacheMaintenanceLibNull.inf
42+
CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
43+
SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
44+
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
45+
DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
46+
HwResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
47+
4148
StackCheckLib|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
4249

4350
[LibraryClasses.common.PEIM]
@@ -54,3 +61,8 @@
5461
[Components.X64, Components.AARCH64]
5562
DebuggerFeaturePkg/Library/DebugAgent/DebugAgentDxe.inf
5663
DebuggerFeaturePkg/Library/DebugAgent/DebugAgentMm.inf
64+
DebuggerFeaturePkg/Library/DebugAgent/DebugAgentPeiLib.inf
65+
DebuggerFeaturePkg/DebugAgentPei/DebugAgentPei.inf {
66+
<LibraryClasses>
67+
DebugAgentLib|DebuggerFeaturePkg/Library/DebugAgent/DebugAgentPeiLib.inf
68+
}
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/** @file DebugAgentPeiLib.c
2+
3+
Implementation of the DebugAgentLib for PEI phase (post-memory only).
4+
5+
Copyright (c) Microsoft Corporation.
6+
SPDX-License-Identifier: BSD-2-Clause-Patent
7+
8+
**/
9+
10+
#include <Uefi.h>
11+
12+
#include <Library/BaseLib.h>
13+
#include <Library/BaseMemoryLib.h>
14+
#include <Library/CacheMaintenanceLib.h>
15+
#include <Library/CpuExceptionHandlerLib.h>
16+
#include <Library/DebugLib.h>
17+
#include <Library/DebugAgentLib.h>
18+
#include <Library/DebugTransportLib.h>
19+
#include <Library/HobLib.h>
20+
#include <Library/PcdLib.h>
21+
#include <Library/PeiServicesLib.h>
22+
#include <Library/TimerLib.h>
23+
#include <Library/TransportLogControlLib.h>
24+
#include <Library/WatchdogTimerLib.h>
25+
26+
#include <DebuggerControlHob.h>
27+
28+
#include "DebugAgent.h"
29+
30+
CONST CHAR8 *gDebuggerInfo = "PEI UEFI Debugger";
31+
32+
//
33+
// Default PEI debug configuration. No timeout, initial breakpoint enabled.
34+
//
35+
36+
DEBUGGER_CONTROL_HOB DefaultPeiDebugConfig = {
37+
.Control.AsUint32 = 0x1, // InitialBreakpoint only
38+
.PerformanceCounterFreq = 0x300000, // Reasonable guess, timing may be inaccurate.
39+
.InitialBreakpointTimeout = 0 // No timeout
40+
};
41+
42+
//
43+
// Debug log buffers
44+
//
45+
46+
#ifdef DBG_DEBUG
47+
CHAR8 DbgLogBuffer[DBG_LOG_SIZE];
48+
UINTN DbgLogOffset = 0;
49+
#endif
50+
51+
/**
52+
This routine removes the exception handling support.
53+
54+
**/
55+
VOID
56+
DebugAgentExceptionDestroy (
57+
)
58+
{
59+
UINT8 Index;
60+
61+
for (Index = 0; mArchExceptionTypes[Index] != MAX_UINT32; Index += 1) {
62+
RegisterCpuInterruptHandler (mArchExceptionTypes[Index], NULL);
63+
}
64+
}
65+
66+
/**
67+
This routine initializes the debugger exception handling support.
68+
69+
@retval EFI_SUCCESS On success.
70+
@retval EFI_STATUS On failure.
71+
72+
**/
73+
EFI_STATUS
74+
DebugAgentExceptionInitialize (
75+
)
76+
{
77+
UINT8 Index;
78+
EFI_STATUS Status;
79+
80+
Status = InitializeCpuExceptionHandlers (NULL);
81+
if (EFI_ERROR (Status)) {
82+
DEBUG ((DEBUG_ERROR, "%a: InitializeCpuExceptionHandlers failed - %r\n", __func__, Status));
83+
return Status;
84+
}
85+
86+
for (Index = 0; mArchExceptionTypes[Index] != MAX_UINT32; Index += 1) {
87+
Status = RegisterCpuInterruptHandler (mArchExceptionTypes[Index], DebuggerExceptionHandler);
88+
if (EFI_ERROR (Status)) {
89+
ASSERT_EFI_ERROR (Status);
90+
DebugAgentExceptionDestroy ();
91+
return Status;
92+
}
93+
}
94+
95+
return Status;
96+
}
97+
98+
/**
99+
Reboots the system.
100+
101+
**/
102+
VOID
103+
DebugReboot (
104+
VOID
105+
)
106+
{
107+
// NOT IMPLEMENTED for PEI.
108+
return;
109+
}
110+
111+
/**
112+
Read system memory. In PEI post-mem, all memory is directly accessible.
113+
114+
@param[in] Address The virtual address of the memory access.
115+
@param[out] Data The buffer to read memory into.
116+
@param[in] Length The length of the memory range.
117+
118+
@retval TRUE Memory access was complete successfully.
119+
@retval FALSE Memory access failed, either completely or partially.
120+
**/
121+
BOOLEAN
122+
DbgReadMemory (
123+
IN UINTN Address,
124+
OUT VOID *Data,
125+
IN UINTN Length
126+
)
127+
{
128+
if (!IsPageReadable (Address)) {
129+
return FALSE;
130+
}
131+
132+
CopyMem (Data, (VOID *)Address, Length);
133+
return TRUE;
134+
}
135+
136+
/**
137+
Write to system memory. In PEI post-mem, all memory is directly accessible.
138+
139+
@param[in] Address The virtual address of the memory access.
140+
@param[in] Data The buffer of data to write.
141+
@param[in] Length The length of the memory range.
142+
143+
@retval TRUE Memory access was complete successfully.
144+
@retval FALSE Memory access failed, either completely or partially.
145+
**/
146+
BOOLEAN
147+
DbgWriteMemory (
148+
IN UINTN Address,
149+
IN VOID *Data,
150+
IN UINTN Length
151+
)
152+
{
153+
if (!IsPageWritable (Address)) {
154+
return FALSE;
155+
}
156+
157+
CopyMem ((VOID *)Address, Data, Length);
158+
return TRUE;
159+
}
160+
161+
/**
162+
Setup the debugger to break when a particular module is loaded.
163+
164+
@param[in] Module The name of the module.
165+
166+
@retval TRUE The break on module was set.
167+
@retval FALSE The break on module was not set.
168+
169+
**/
170+
BOOLEAN
171+
DbgSetBreakOnModuleLoad (
172+
IN CHAR8 *Module
173+
)
174+
{
175+
// NOT SUPPORTED in PEI.
176+
return FALSE;
177+
}
178+
179+
/**
180+
Initialize debug agent.
181+
182+
When called with DEBUG_AGENT_INIT_PEI, performs the full PEI debug agent
183+
initialization: transport, architecture-specific setup, exception handlers,
184+
and initial breakpoint.
185+
186+
@param[in] InitFlag Init flag. DEBUG_AGENT_INIT_PEI to initialize.
187+
@param[in] Context Context needed according to InitFlag; it was optional.
188+
@param[in] Function Continue function called by debug agent library; it was
189+
optional.
190+
191+
**/
192+
VOID
193+
EFIAPI
194+
InitializeDebugAgent (
195+
IN UINT32 InitFlag,
196+
IN VOID *Context OPTIONAL,
197+
IN DEBUG_AGENT_CONTINUE Function OPTIONAL
198+
)
199+
{
200+
EFI_STATUS Status;
201+
202+
if (!PcdGetBool (PcdForceEnablePeiDebugger)) {
203+
DEBUG ((DEBUG_INFO, "%a: PEI debugger not enabled.\n", __func__));
204+
return;
205+
}
206+
207+
Status = DebugTransportInitialize ();
208+
if (EFI_ERROR (Status)) {
209+
DEBUG ((DEBUG_ERROR, "%a: Transport init failed - %r\n", __func__, Status));
210+
return;
211+
}
212+
213+
DebugArchInit (&DefaultPeiDebugConfig);
214+
215+
Status = DebugAgentExceptionInitialize ();
216+
if (EFI_ERROR (Status)) {
217+
DEBUG ((DEBUG_ERROR, "%a: Exception init failed - %r\n", __func__, Status));
218+
return;
219+
}
220+
221+
DEBUG ((DEBUG_INFO, "%a: PEI debug agent initialized.\n", __func__));
222+
223+
//
224+
// Always perform an initial breakpoint with no timeout for PEI.
225+
//
226+
DebuggerInitialBreakpoint (0);
227+
}
228+
229+
/**
230+
Enable/Disable the interrupt of debug timer and return the interrupt state
231+
prior to the operation.
232+
233+
If EnableStatus is TRUE, enable the interrupt of debug timer.
234+
If EnableStatus is FALSE, disable the interrupt of debug timer.
235+
236+
@param[in] EnableStatus Enable/Disable.
237+
238+
@return FALSE always.
239+
240+
**/
241+
BOOLEAN
242+
EFIAPI
243+
SaveAndSetDebugTimerInterrupt (
244+
IN BOOLEAN EnableStatus
245+
)
246+
{
247+
return FALSE;
248+
}

0 commit comments

Comments
 (0)