diff options
-rw-r--r-- | src/include/ipxe/efi/Protocol/Cpu.h | 302 | ||||
-rw-r--r-- | src/include/ipxe/efi/efi_timer.h | 18 | ||||
-rw-r--r-- | src/interface/efi/efi_timer.c | 118 |
3 files changed, 86 insertions, 352 deletions
diff --git a/src/include/ipxe/efi/Protocol/Cpu.h b/src/include/ipxe/efi/Protocol/Cpu.h deleted file mode 100644 index 665924e8..00000000 --- a/src/include/ipxe/efi/Protocol/Cpu.h +++ /dev/null @@ -1,302 +0,0 @@ -/** @file - CPU Architectural Protocol as defined in PI spec Volume 2 DXE - - This code abstracts the DXE core from processor implementation details. - - Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> - 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. - -**/ - -#ifndef __ARCH_PROTOCOL_CPU_H__ -#define __ARCH_PROTOCOL_CPU_H__ - -FILE_LICENCE ( BSD3 ); - -#include <ipxe/efi/Protocol/DebugSupport.h> - -#define EFI_CPU_ARCH_PROTOCOL_GUID \ - { 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } - -typedef struct _EFI_CPU_ARCH_PROTOCOL EFI_CPU_ARCH_PROTOCOL; - -/// -/// The type of flush operation -/// -typedef enum { - EfiCpuFlushTypeWriteBackInvalidate, - EfiCpuFlushTypeWriteBack, - EfiCpuFlushTypeInvalidate, - EfiCpuMaxFlushType -} EFI_CPU_FLUSH_TYPE; - -/// -/// The type of processor INIT. -/// -typedef enum { - EfiCpuInit, - EfiCpuMaxInitType -} EFI_CPU_INIT_TYPE; - -/** - EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs. - - @param InterruptType Defines the type of interrupt or exception that - occurred on the processor.This parameter is processor architecture specific. - @param SystemContext A pointer to the processor context when - the interrupt occurred on the processor. - - @return None - -**/ -typedef -VOID -(EFIAPI *EFI_CPU_INTERRUPT_HANDLER)( - IN CONST EFI_EXCEPTION_TYPE InterruptType, - IN CONST EFI_SYSTEM_CONTEXT SystemContext - ); - -/** - This function flushes the range of addresses from Start to Start+Length - from the processor's data cache. If Start is not aligned to a cache line - boundary, then the bytes before Start to the preceding cache line boundary - are also flushed. If Start+Length is not aligned to a cache line boundary, - then the bytes past Start+Length to the end of the next cache line boundary - are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be - supported. If the data cache is fully coherent with all DMA operations, then - this function can just return EFI_SUCCESS. If the processor does not support - flushing a range of the data cache, then the entire data cache can be flushed. - - @param This The EFI_CPU_ARCH_PROTOCOL instance. - @param Start The beginning physical address to flush from the processor's data - cache. - @param Length The number of bytes to flush from the processor's data cache. This - function may flush more bytes than Length specifies depending upon - the granularity of the flush operation that the processor supports. - @param FlushType Specifies the type of flush operation to perform. - - @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from - the processor's data cache. - @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified - by FlushType. - @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed - from the processor's data cache. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_CPU_FLUSH_DATA_CACHE)( - IN EFI_CPU_ARCH_PROTOCOL *This, - IN EFI_PHYSICAL_ADDRESS Start, - IN UINT64 Length, - IN EFI_CPU_FLUSH_TYPE FlushType - ); - - -/** - This function enables interrupt processing by the processor. - - @param This The EFI_CPU_ARCH_PROTOCOL instance. - - @retval EFI_SUCCESS Interrupts are enabled on the processor. - @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_CPU_ENABLE_INTERRUPT)( - IN EFI_CPU_ARCH_PROTOCOL *This - ); - - -/** - This function disables interrupt processing by the processor. - - @param This The EFI_CPU_ARCH_PROTOCOL instance. - - @retval EFI_SUCCESS Interrupts are disabled on the processor. - @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_CPU_DISABLE_INTERRUPT)( - IN EFI_CPU_ARCH_PROTOCOL *This - ); - - -/** - This function retrieves the processor's current interrupt state a returns it in - State. If interrupts are currently enabled, then TRUE is returned. If interrupts - are currently disabled, then FALSE is returned. - - @param This The EFI_CPU_ARCH_PROTOCOL instance. - @param State A pointer to the processor's current interrupt state. Set to TRUE if - interrupts are enabled and FALSE if interrupts are disabled. - - @retval EFI_SUCCESS The processor's current interrupt state was returned in State. - @retval EFI_INVALID_PARAMETER State is NULL. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_CPU_GET_INTERRUPT_STATE)( - IN EFI_CPU_ARCH_PROTOCOL *This, - OUT BOOLEAN *State - ); - - -/** - This function generates an INIT on the processor. If this function succeeds, then the - processor will be reset, and control will not be returned to the caller. If InitType is - not supported by this processor, or the processor cannot programmatically generate an - INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error - occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned. - - @param This The EFI_CPU_ARCH_PROTOCOL instance. - @param InitType The type of processor INIT to perform. - - @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen. - @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported - by this processor. - @retval EFI_DEVICE_ERROR The processor INIT failed. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_CPU_INIT)( - IN EFI_CPU_ARCH_PROTOCOL *This, - IN EFI_CPU_INIT_TYPE InitType - ); - - -/** - This function registers and enables the handler specified by InterruptHandler for a processor - interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the - handler for the processor interrupt or exception type specified by InterruptType is uninstalled. - The installed handler is called once for each processor interrupt or exception. - - @param This The EFI_CPU_ARCH_PROTOCOL instance. - @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts - are enabled and FALSE if interrupts are disabled. - @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called - when a processor interrupt occurs. If this parameter is NULL, then the handler - will be uninstalled. - - @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. - @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was - previously installed. - @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not - previously installed. - @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_CPU_REGISTER_INTERRUPT_HANDLER)( - IN EFI_CPU_ARCH_PROTOCOL *This, - IN EFI_EXCEPTION_TYPE InterruptType, - IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler - ); - - -/** - This function reads the processor timer specified by TimerIndex and returns it in TimerValue. - - @param This The EFI_CPU_ARCH_PROTOCOL instance. - @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter - must be between 0 and NumberOfTimers-1. - @param TimerValue Pointer to the returned timer value. - @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment - of TimerValue. If TimerValue does not increment at a predictable rate, then 0 is - returned. This parameter is optional and may be NULL. - - @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue. - @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers. - @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid. - @retval EFI_UNSUPPORTED The processor does not have any readable timers. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_CPU_GET_TIMER_VALUE)( - IN EFI_CPU_ARCH_PROTOCOL *This, - IN UINT32 TimerIndex, - OUT UINT64 *TimerValue, - OUT UINT64 *TimerPeriod OPTIONAL - ); - - -/** - This function modifies the attributes for the memory region specified by BaseAddress and - Length from their current attributes to the attributes specified by Attributes. - - @param This The EFI_CPU_ARCH_PROTOCOL instance. - @param BaseAddress The physical address that is the start address of a memory region. - @param Length The size in bytes of the memory region. - @param Attributes The bit mask of attributes to set for the memory region. - - @retval EFI_SUCCESS The attributes were set for the memory region. - @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by - BaseAddress and Length cannot be modified. - @retval EFI_INVALID_PARAMETER Length is zero. - Attributes specified an illegal combination of attributes that - cannot be set together. - @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of - the memory resource range. - @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory - resource range specified by BaseAddress and Length. - The bit mask of attributes is not support for the memory resource - range specified by BaseAddress and Length. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_CPU_SET_MEMORY_ATTRIBUTES)( - IN EFI_CPU_ARCH_PROTOCOL *This, - IN EFI_PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN UINT64 Attributes - ); - - -/// -/// The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE -/// Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt -/// vectors and exception vectors, reading internal processor timers, resetting the processor, and -/// determining the processor frequency. -/// -struct _EFI_CPU_ARCH_PROTOCOL { - EFI_CPU_FLUSH_DATA_CACHE FlushDataCache; - EFI_CPU_ENABLE_INTERRUPT EnableInterrupt; - EFI_CPU_DISABLE_INTERRUPT DisableInterrupt; - EFI_CPU_GET_INTERRUPT_STATE GetInterruptState; - EFI_CPU_INIT Init; - EFI_CPU_REGISTER_INTERRUPT_HANDLER RegisterInterruptHandler; - EFI_CPU_GET_TIMER_VALUE GetTimerValue; - EFI_CPU_SET_MEMORY_ATTRIBUTES SetMemoryAttributes; - /// - /// The number of timers that are available in a processor. The value in this - /// field is a constant that must not be modified after the CPU Architectural - /// Protocol is installed. All consumers must treat this as a read-only field. - /// - UINT32 NumberOfTimers; - /// - /// The size, in bytes, of the alignment required for DMA buffer allocations. - /// This is typically the size of the largest data cache line in the platform. - /// The value in this field is a constant that must not be modified after the - /// CPU Architectural Protocol is installed. All consumers must treat this as - /// a read-only field. - /// - UINT32 DmaBufferAlignment; -}; - -extern EFI_GUID gEfiCpuArchProtocolGuid; - -#endif diff --git a/src/include/ipxe/efi/efi_timer.h b/src/include/ipxe/efi/efi_timer.h index c0376539..c4987598 100644 --- a/src/include/ipxe/efi/efi_timer.h +++ b/src/include/ipxe/efi/efi_timer.h @@ -15,4 +15,22 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define TIMER_PREFIX_efi __efi_ #endif +/** + * Number of ticks per second + * + * This is a policy decision. + */ +#define EFI_TICKS_PER_SEC 20 + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static inline __attribute__ (( always_inline )) unsigned long +TIMER_INLINE ( efi, ticks_per_sec ) ( void ) { + + return EFI_TICKS_PER_SEC; +} + #endif /* _IPXE_EFI_TIMER_H */ diff --git a/src/interface/efi/efi_timer.c b/src/interface/efi/efi_timer.c index 81620c92..a574e204 100644 --- a/src/interface/efi/efi_timer.c +++ b/src/interface/efi/efi_timer.c @@ -25,12 +25,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <string.h> #include <errno.h> -#include <limits.h> -#include <assert.h> #include <unistd.h> #include <ipxe/timer.h> +#include <ipxe/init.h> #include <ipxe/efi/efi.h> -#include <ipxe/efi/Protocol/Cpu.h> /** @file * @@ -38,19 +36,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ -/** Scale factor to apply to CPU timer 0 - * - * The timer is scaled down in order to ensure that reasonable values - * for "number of ticks" don't exceed the size of an unsigned long. - */ -#define EFI_TIMER0_SHIFT 12 +/** Current tick count */ +static unsigned long efi_jiffies; -/** Calibration time */ -#define EFI_CALIBRATE_DELAY_MS 1 +/** Timer tick event */ +static EFI_EVENT efi_tick_event; -/** CPU protocol */ -static EFI_CPU_ARCH_PROTOCOL *cpu_arch; -EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch ); +/** Colour for debug messages */ +#define colour &efi_jiffies /** * Delay for a fixed number of microseconds @@ -64,8 +57,8 @@ static void efi_udelay ( unsigned long usecs ) { if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) { rc = -EEFI ( efirc ); - DBG ( "EFI could not delay for %ldus: %s\n", - usecs, strerror ( rc ) ); + DBGC ( colour, "EFI could not delay for %ldus: %s\n", + usecs, strerror ( rc ) ); /* Probably screwed */ } } @@ -76,53 +69,78 @@ static void efi_udelay ( unsigned long usecs ) { * @ret ticks Current time, in ticks */ static unsigned long efi_currticks ( void ) { - UINT64 time; + + return efi_jiffies; +} + +/** + * Timer tick + * + * @v event Timer tick event + * @v context Event context + */ +static EFIAPI void efi_tick ( EFI_EVENT event __unused, + void *context __unused ) { + + /* Increment tick count */ + efi_jiffies++; +} + +/** + * Start timer tick + * + */ +static void efi_tick_startup ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_STATUS efirc; int rc; - /* Read CPU timer 0 (TSC) */ - if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time, - NULL ) ) != 0 ) { + /* Create timer tick event */ + if ( ( efirc = bs->CreateEvent ( ( EVT_TIMER | EVT_NOTIFY_SIGNAL ), + TPL_CALLBACK, efi_tick, NULL, + &efi_tick_event ) ) != 0 ) { rc = -EEFI ( efirc ); - DBG ( "EFI could not read CPU timer: %s\n", strerror ( rc ) ); - /* Probably screwed */ - return -1UL; + DBGC ( colour, "EFI could not create timer tick: %s\n", + strerror ( rc ) ); + /* Nothing we can do about it */ + return; } - return ( time >> EFI_TIMER0_SHIFT ); + /* Start timer tick */ + if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerPeriodic, + ( 10000000 / EFI_TICKS_PER_SEC ) ) ) !=0){ + rc = -EEFI ( efirc ); + DBGC ( colour, "EFI could not start timer tick: %s\n", + strerror ( rc ) ); + /* Nothing we can do about it */ + return; + } + DBGC ( colour, "EFI timer started at %d ticks per second\n", + EFI_TICKS_PER_SEC ); } /** - * Get number of ticks per second + * Stop timer tick * - * @ret ticks_per_sec Number of ticks per second + * @v booting System is shutting down in order to boot */ -static unsigned long efi_ticks_per_sec ( void ) { - static unsigned long ticks_per_sec = 0; - - /* Calibrate timer, if necessary. EFI does nominally provide - * the timer speed via the (optional) TimerPeriod parameter to - * the GetTimerValue() call, but it gets the speed slightly - * wrong. By up to three orders of magnitude. Not helpful. - */ - if ( ! ticks_per_sec ) { - unsigned long start; - unsigned long elapsed; - - DBG ( "Calibrating EFI timer with a %d ms delay\n", - EFI_CALIBRATE_DELAY_MS ); - start = currticks(); - mdelay ( EFI_CALIBRATE_DELAY_MS ); - elapsed = ( currticks() - start ); - ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS )); - DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld " - "ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS, - ticks_per_sec ); - } +static void efi_tick_shutdown ( int booting __unused ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - return ticks_per_sec; + /* Stop timer tick */ + bs->SetTimer ( efi_tick_event, TimerCancel, 0 ); + DBGC ( colour, "EFI timer stopped\n" ); + + /* Destroy timer tick event */ + bs->CloseEvent ( efi_tick_event ); } +/** Timer tick startup function */ +struct startup_fn efi_tick_startup_fn __startup_fn ( STARTUP_EARLY ) = { + .startup = efi_tick_startup, + .shutdown = efi_tick_shutdown, +}; + PROVIDE_TIMER ( efi, udelay, efi_udelay ); PROVIDE_TIMER ( efi, currticks, efi_currticks ); -PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec ); +PROVIDE_TIMER_INLINE ( efi, ticks_per_sec ); |