Skip to content

Commit a59f179

Browse files
committed
PPC64LE: boot to shell
- working HDEC-based TimerDxe - TB-based TimerLib - Shell needed the unicode collation driver. - set correct PcdShellFile to have the shell be recognised by BDS - TB frequency set in Ipl today through the Pcr, at some point this should be set through a PCD by a FDT-parsing DXE. Fixes issue tianocore#2 Closes Milestone UEFI Shell Boot Signed-off-by: Andrei Warkentin <[email protected]>
1 parent e6b7442 commit a59f179

File tree

10 files changed

+429
-18
lines changed

10 files changed

+429
-18
lines changed

MdePkg/Library/BaseLib/BaseLib.inf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@
505505
PPC64/SwitchStack.S
506506
PPC64/CpuBreakpoint.S
507507
PPC64/SetJump.S
508+
PPC64/CpuPause.S
508509
Unaligned.c
509510
Math64.c
510511

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// Copyright (c) 2015, Andrei Warkentin <[email protected]>
3+
//
4+
// This program and the accompanying materials
5+
// are licensed and made available under the terms and conditions of the BSD License
6+
// which accompanies this distribution. The full text of the license may be found at
7+
// http://opensource.org/licenses/bsd-license.php
8+
//
9+
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11+
//
12+
13+
#define SMT_VERY_LOW or 31, 31, 31
14+
#define SMT_MEDIUM or 2, 2, 2
15+
16+
/**
17+
//
18+
// Requests CPU to pause for a short period of time.
19+
//
20+
// Requests CPU to pause for a short period of time. Typically used in MP
21+
// systems to prevent memory starvation while waiting for a spin lock.
22+
//
23+
VOID
24+
EFIAPI
25+
CpuPause (
26+
VOID
27+
)
28+
**/
29+
ASM_FUNC(CpuPause)
30+
SMT_VERY_LOW
31+
nop
32+
nop
33+
nop
34+
nop
35+
nop
36+
SMT_MEDIUM
37+
blr

PPC64Pkg/Drivers/TimerDxe/TimerDxe.c

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,28 @@
1111
//
1212

1313
#include <PiDxe.h>
14-
1514
#include <Library/BaseLib.h>
1615
#include <Library/DebugLib.h>
1716
#include <Library/BaseMemoryLib.h>
1817
#include <Library/UefiBootServicesTableLib.h>
18+
#include <Chipset/PPC64Intrinsics.h>
1919
#include <Library/UefiLib.h>
2020
#include <Library/PcdLib.h>
2121
#include <Protocol/Timer.h>
22+
#include <Protocol/Cpu.h>
23+
#include <Pcr.h>
24+
25+
// CPU architecture protocol, because timer does not go through XICS.
26+
EFI_CPU_ARCH_PROTOCOL *gCpu;
2227

2328
// The notification function to call on every timer interrupt.
24-
EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY)NULL;
25-
EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
29+
EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY) NULL;
30+
EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT) NULL;
2631

2732
// The current period of the timer interrupt
2833
UINT64 mTimerPeriod = 0;
34+
// The latest Timer Tick calculated for mTimerPeriod
35+
UINT64 mTimerTicks = 0;
2936

3037
/**
3138
This function registers the handler NotifyFunction so it is called every time
@@ -85,6 +92,7 @@ ExitBootServicesEvent (
8592
IN VOID *Context
8693
)
8794
{
95+
hdec_disable ();
8896
}
8997

9098
/**
@@ -122,10 +130,37 @@ TimerDriverSetTimerPeriod (
122130
IN UINT64 TimerPeriod
123131
)
124132
{
133+
UINT64 TimerTicks;
134+
EFI_TPL OriginalTPL;
135+
136+
// Always disable the timer
137+
hdec_disable ();
138+
139+
if (TimerPeriod != 0) {
140+
TimerTicks = MultU64x32 (TimerPeriod, PcrGet()->TBFreq);
141+
TimerTicks = DivU64x32 (TimerTicks, 10000000U) - 1;
142+
143+
// Raise TPL to update the mTimerTicks and mTimerPeriod to ensure these values
144+
// are coherent in the interrupt handler
145+
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
125146

126-
// Save the new timer period
127-
mTimerPeriod = TimerPeriod;
128-
// Reset the elapsed period
147+
mTimerTicks = TimerTicks;
148+
mTimerPeriod = TimerPeriod;
149+
150+
gBS->RestoreTPL (OriginalTPL);
151+
152+
//
153+
// This is unlikely, so no need to implement it now.
154+
//
155+
ASSERT(mTimerTicks <= DEC_MAX_USABLE);
156+
SET_HDEC(mTimerTicks);
157+
158+
// Enable the timer
159+
hdec_enable ();
160+
} else {
161+
// Save the new timer period
162+
mTimerPeriod = TimerPeriod;
163+
}
129164

130165
return EFI_SUCCESS;
131166
}
@@ -225,6 +260,47 @@ EFI_TIMER_ARCH_PROTOCOL gTimer = {
225260
TimerDriverGenerateSoftInterrupt
226261
};
227262

263+
/**
264+
265+
C Interrupt Handler called in the interrupt context on timer event
266+
267+
268+
@param InterruptType Local decrementer exception vector.
269+
270+
@param SystemContext Pointer to system register context. Mostly used by debuggers and will
271+
update the system context after the return from the interrupt if
272+
modified. Don't change these values unless you know what you are doing
273+
274+
**/
275+
VOID
276+
EFIAPI
277+
TimerInterruptHandler (
278+
IN EFI_EXCEPTION_TYPE InterruptType,
279+
IN EFI_SYSTEM_CONTEXT SystemContext
280+
)
281+
{
282+
EFI_TPL OriginalTPL;
283+
284+
//
285+
// DXE core uses this callback for the EFI timer tick. The DXE core uses locks
286+
// that raise to TPL_HIGH and then restore back to current level. Thus we need
287+
// to make sure TPL level is set to TPL_HIGH while we are handling the timer tick.
288+
//
289+
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
290+
291+
if (mTimerNotifyFunction) {
292+
mTimerNotifyFunction (mTimerPeriod);
293+
}
294+
295+
SET_HDEC(mTimerTicks);
296+
297+
//
298+
// Reload the Timer
299+
//
300+
301+
gBS->RestoreTPL (OriginalTPL);
302+
}
303+
228304

229305
/**
230306
Initialize the state information for the Timer Architectural Protocol and
@@ -249,17 +325,32 @@ TimerInitialize (
249325
EFI_HANDLE Handle = NULL;
250326
EFI_STATUS Status;
251327

328+
// Find the CPU architecture protocol. ASSERT if not found.
329+
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL,
330+
(VOID **)&gCpu);
331+
ASSERT_EFI_ERROR (Status);
332+
333+
// Disable the timer
334+
hdec_disable ();
335+
336+
// Install the handler.
337+
Status = gCpu->RegisterInterruptHandler (gCpu, EXCEPT_PPC64_HDEC,
338+
TimerInterruptHandler);
339+
ASSERT_EFI_ERROR (Status);
340+
252341
// Set up default timer
253342
Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); // TIMER_DEFAULT_PERIOD
254343
ASSERT_EFI_ERROR (Status);
255344

256345
// Install the Timer Architectural Protocol onto a new handle
257-
Status = gBS->InstallMultipleProtocolInterfaces(
346+
Status = gBS->InstallMultipleProtocolInterfaces (
258347
&Handle,
259-
&gEfiTimerArchProtocolGuid, &gTimer,
348+
&gEfiTimerArchProtocolGuid, &gTimer,
260349
NULL
261350
);
262-
ASSERT_EFI_ERROR(Status);
351+
ASSERT_EFI_ERROR (Status);
352+
353+
hdec_enable ();
263354

264355
// Register for an ExitBootServicesEvent
265356
Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);

PPC64Pkg/Include/Chipset/PPC64.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,6 @@
114114
* to the maximum value that doesn't cause an interrupt, which is
115115
* the value with MSB bit set to 0.
116116
*/
117-
#define DEC_DISABLE_FOR_A_WHILE 0x7fffffff
117+
#define DEC_MAX_USABLE 0x7fffffff
118118

119119
#endif // __PPC64_H__

PPC64Pkg/Include/Chipset/PPC64Intrinsics.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ REG_READ_FN(DSISR)
5353
#undef _S
5454
#undef __S
5555

56+
static inline UINT64
57+
mftb(void)
58+
{
59+
UINT64 tb;
60+
asm volatile("mftb %0" : "=r"(tb) : : "memory");
61+
return tb;
62+
}
63+
5664
static inline UINT64
5765
mfmsr(void)
5866
{
@@ -70,8 +78,27 @@ mtmsr(UINT64 val)
7078
}
7179

7280
static inline void __attribute__((always_inline))
73-
mtmsrd(UINT64 val, const int l)
81+
mtmsrd(UINT64 val, const UINTN l)
7482
{
7583
asm volatile("mtmsrd %0,%1" : : "r"(val), "i"(l) : "memory");
7684
}
85+
86+
static inline VOID
87+
smt_medium(VOID)
88+
{
89+
asm volatile("or 2, 2, 2");
90+
}
91+
92+
static inline VOID
93+
hdec_enable(VOID)
94+
{
95+
SET_LPCR(GET_LPCR() | LPCR_HDICE);
96+
}
97+
98+
static inline VOID
99+
hdec_disable(VOID)
100+
{
101+
SET_LPCR(GET_LPCR() & ~LPCR_HDICE);
102+
}
103+
77104
#endif // __PPC64_INTRINSICSH__

PPC64Pkg/Ipl/Ipl.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <Guid/LzmaDecompress.h>
2323
#include <Guid/FdtHob.h>
2424
#include <libfdt.h>
25+
#include <Chipset/PPC64Intrinsics.h>
2526
#include <Endian.h>
2627
#include <Pcr.h>
2728
#include "LzmaDecompress.h"
@@ -58,9 +59,17 @@ Log (
5859
SerialPortWrite ((UINT8 *) Buffer, Count);
5960
}
6061

62+
VOID
63+
CpuInit (
64+
VOID
65+
)
66+
{
67+
smt_medium ();
68+
hdec_disable ();
69+
}
6170

62-
UINT64
63-
InitializeSystemMemory (
71+
VOID
72+
ParseFDT (
6473
IN VOID *DeviceTreeBase
6574
)
6675
{
@@ -70,6 +79,7 @@ InitializeSystemMemory (
7079
CONST CHAR8 *Type;
7180
INT32 Len;
7281
CONST UINT64 *RegProp;
82+
CONST UINT32 *RegProp32;
7383

7484
NewBase = 0;
7585
NewSize = 0;
@@ -109,10 +119,13 @@ InitializeSystemMemory (
109119
__FUNCTION__));
110120
}
111121
break;
122+
} else if (Type && AsciiStrnCmp (Type, "cpu", Len) == 0) {
123+
RegProp32 = fdt_getprop (DeviceTreeBase, Node,
124+
"timebase-frequency", NULL);
125+
PcrGet()->TBFreq = fdt32_to_cpu (ReadUnaligned32 (RegProp32));
126+
DEBUG ((EFI_D_INFO, "TB %lu Hz\n", PcrGet()->TBFreq));
112127
}
113128
}
114-
115-
return NewSize;
116129
}
117130

118131

@@ -232,7 +245,9 @@ CEntryPoint (
232245
Log (L"PPC64LE UEFI firmware (version %s built at %a on %a)\n",
233246
(CHAR16*) PcdGetPtr (PcdFirmwareVersionString), __TIME__, __DATE__);
234247

235-
InitializeSystemMemory ((VOID *) FDTBase);
248+
CpuInit ();
249+
250+
ParseFDT ((VOID *) FDTBase);
236251
DEBUG ((EFI_D_INFO, "System RAM @ 0x%lx - 0x%lx\n",
237252
PcdGet64 (PcdSystemMemoryBase),
238253
PcdGet64 (PcdSystemMemoryBase) +

0 commit comments

Comments
 (0)