Skip to content
/ edk2 Public
forked from tianocore/edk2

Commit

Permalink
PPC64LE: boot to shell
Browse files Browse the repository at this point in the history
- 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 <andrey.warkentin@gmail.com>
  • Loading branch information
andreiw committed Oct 13, 2015
1 parent e6b7442 commit a59f179
Show file tree
Hide file tree
Showing 10 changed files with 429 additions and 18 deletions.
1 change: 1 addition & 0 deletions MdePkg/Library/BaseLib/BaseLib.inf
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@
PPC64/SwitchStack.S
PPC64/CpuBreakpoint.S
PPC64/SetJump.S
PPC64/CpuPause.S
Unaligned.c
Math64.c

Expand Down
37 changes: 37 additions & 0 deletions MdePkg/Library/BaseLib/PPC64/CpuPause.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Copyright (c) 2015, Andrei Warkentin <andrey.warkentin@gmail.com>
//
// This program and the accompanying materials
// are licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//

#define SMT_VERY_LOW or 31, 31, 31
#define SMT_MEDIUM or 2, 2, 2

/**
//
// Requests CPU to pause for a short period of time.
//
// Requests CPU to pause for a short period of time. Typically used in MP
// systems to prevent memory starvation while waiting for a spin lock.
//
VOID
EFIAPI
CpuPause (
VOID
)
**/
ASM_FUNC(CpuPause)
SMT_VERY_LOW
nop
nop
nop
nop
nop
SMT_MEDIUM
blr
109 changes: 100 additions & 9 deletions PPC64Pkg/Drivers/TimerDxe/TimerDxe.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,28 @@
//

#include <PiDxe.h>

#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Chipset/PPC64Intrinsics.h>
#include <Library/UefiLib.h>
#include <Library/PcdLib.h>
#include <Protocol/Timer.h>
#include <Protocol/Cpu.h>
#include <Pcr.h>

// CPU architecture protocol, because timer does not go through XICS.
EFI_CPU_ARCH_PROTOCOL *gCpu;

// The notification function to call on every timer interrupt.
EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY)NULL;
EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY) NULL;
EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT) NULL;

// The current period of the timer interrupt
UINT64 mTimerPeriod = 0;
// The latest Timer Tick calculated for mTimerPeriod
UINT64 mTimerTicks = 0;

/**
This function registers the handler NotifyFunction so it is called every time
Expand Down Expand Up @@ -85,6 +92,7 @@ ExitBootServicesEvent (
IN VOID *Context
)
{
hdec_disable ();
}

/**
Expand Down Expand Up @@ -122,10 +130,37 @@ TimerDriverSetTimerPeriod (
IN UINT64 TimerPeriod
)
{
UINT64 TimerTicks;
EFI_TPL OriginalTPL;

// Always disable the timer
hdec_disable ();

if (TimerPeriod != 0) {
TimerTicks = MultU64x32 (TimerPeriod, PcrGet()->TBFreq);
TimerTicks = DivU64x32 (TimerTicks, 10000000U) - 1;

// Raise TPL to update the mTimerTicks and mTimerPeriod to ensure these values
// are coherent in the interrupt handler
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);

// Save the new timer period
mTimerPeriod = TimerPeriod;
// Reset the elapsed period
mTimerTicks = TimerTicks;
mTimerPeriod = TimerPeriod;

gBS->RestoreTPL (OriginalTPL);

//
// This is unlikely, so no need to implement it now.
//
ASSERT(mTimerTicks <= DEC_MAX_USABLE);
SET_HDEC(mTimerTicks);

// Enable the timer
hdec_enable ();
} else {
// Save the new timer period
mTimerPeriod = TimerPeriod;
}

return EFI_SUCCESS;
}
Expand Down Expand Up @@ -225,6 +260,47 @@ EFI_TIMER_ARCH_PROTOCOL gTimer = {
TimerDriverGenerateSoftInterrupt
};

/**
C Interrupt Handler called in the interrupt context on timer event
@param InterruptType Local decrementer exception vector.
@param SystemContext Pointer to system register context. Mostly used by debuggers and will
update the system context after the return from the interrupt if
modified. Don't change these values unless you know what you are doing
**/
VOID
EFIAPI
TimerInterruptHandler (
IN EFI_EXCEPTION_TYPE InterruptType,
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
EFI_TPL OriginalTPL;

//
// DXE core uses this callback for the EFI timer tick. The DXE core uses locks
// that raise to TPL_HIGH and then restore back to current level. Thus we need
// to make sure TPL level is set to TPL_HIGH while we are handling the timer tick.
//
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);

if (mTimerNotifyFunction) {
mTimerNotifyFunction (mTimerPeriod);
}

SET_HDEC(mTimerTicks);

//
// Reload the Timer
//

gBS->RestoreTPL (OriginalTPL);
}


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

// Find the CPU architecture protocol. ASSERT if not found.
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL,
(VOID **)&gCpu);
ASSERT_EFI_ERROR (Status);

// Disable the timer
hdec_disable ();

// Install the handler.
Status = gCpu->RegisterInterruptHandler (gCpu, EXCEPT_PPC64_HDEC,
TimerInterruptHandler);
ASSERT_EFI_ERROR (Status);

// Set up default timer
Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); // TIMER_DEFAULT_PERIOD
ASSERT_EFI_ERROR (Status);

// Install the Timer Architectural Protocol onto a new handle
Status = gBS->InstallMultipleProtocolInterfaces(
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gEfiTimerArchProtocolGuid, &gTimer,
&gEfiTimerArchProtocolGuid, &gTimer,
NULL
);
ASSERT_EFI_ERROR(Status);
ASSERT_EFI_ERROR (Status);

hdec_enable ();

// Register for an ExitBootServicesEvent
Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);
Expand Down
2 changes: 1 addition & 1 deletion PPC64Pkg/Include/Chipset/PPC64.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,6 @@
* to the maximum value that doesn't cause an interrupt, which is
* the value with MSB bit set to 0.
*/
#define DEC_DISABLE_FOR_A_WHILE 0x7fffffff
#define DEC_MAX_USABLE 0x7fffffff

#endif // __PPC64_H__
29 changes: 28 additions & 1 deletion PPC64Pkg/Include/Chipset/PPC64Intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ REG_READ_FN(DSISR)
#undef _S
#undef __S

static inline UINT64
mftb(void)
{
UINT64 tb;
asm volatile("mftb %0" : "=r"(tb) : : "memory");
return tb;
}

static inline UINT64
mfmsr(void)
{
Expand All @@ -70,8 +78,27 @@ mtmsr(UINT64 val)
}

static inline void __attribute__((always_inline))
mtmsrd(UINT64 val, const int l)
mtmsrd(UINT64 val, const UINTN l)
{
asm volatile("mtmsrd %0,%1" : : "r"(val), "i"(l) : "memory");
}

static inline VOID
smt_medium(VOID)
{
asm volatile("or 2, 2, 2");
}

static inline VOID
hdec_enable(VOID)
{
SET_LPCR(GET_LPCR() | LPCR_HDICE);
}

static inline VOID
hdec_disable(VOID)
{
SET_LPCR(GET_LPCR() & ~LPCR_HDICE);
}

#endif // __PPC64_INTRINSICSH__
25 changes: 20 additions & 5 deletions PPC64Pkg/Ipl/Ipl.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <Guid/LzmaDecompress.h>
#include <Guid/FdtHob.h>
#include <libfdt.h>
#include <Chipset/PPC64Intrinsics.h>
#include <Endian.h>
#include <Pcr.h>
#include "LzmaDecompress.h"
Expand Down Expand Up @@ -58,9 +59,17 @@ Log (
SerialPortWrite ((UINT8 *) Buffer, Count);
}

VOID
CpuInit (
VOID
)
{
smt_medium ();
hdec_disable ();
}

UINT64
InitializeSystemMemory (
VOID
ParseFDT (
IN VOID *DeviceTreeBase
)
{
Expand All @@ -70,6 +79,7 @@ InitializeSystemMemory (
CONST CHAR8 *Type;
INT32 Len;
CONST UINT64 *RegProp;
CONST UINT32 *RegProp32;

NewBase = 0;
NewSize = 0;
Expand Down Expand Up @@ -109,10 +119,13 @@ InitializeSystemMemory (
__FUNCTION__));
}
break;
} else if (Type && AsciiStrnCmp (Type, "cpu", Len) == 0) {
RegProp32 = fdt_getprop (DeviceTreeBase, Node,
"timebase-frequency", NULL);
PcrGet()->TBFreq = fdt32_to_cpu (ReadUnaligned32 (RegProp32));
DEBUG ((EFI_D_INFO, "TB %lu Hz\n", PcrGet()->TBFreq));
}
}

return NewSize;
}


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

InitializeSystemMemory ((VOID *) FDTBase);
CpuInit ();

ParseFDT ((VOID *) FDTBase);
DEBUG ((EFI_D_INFO, "System RAM @ 0x%lx - 0x%lx\n",
PcdGet64 (PcdSystemMemoryBase),
PcdGet64 (PcdSystemMemoryBase) +
Expand Down
Loading

0 comments on commit a59f179

Please sign in to comment.