mirror of https://github.com/acidanthera/audk.git
356 lines
11 KiB
C
356 lines
11 KiB
C
/** @file
|
|
RISC-V specific functionality for cache.
|
|
|
|
Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
|
|
Copyright (c) 2023, Rivos Inc. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include <Base.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/PcdLib.h>
|
|
|
|
//
|
|
// TODO: Grab cache block size and make Cache Management Operation
|
|
// enabling decision based on RISC-V CPU HOB in
|
|
// future when it is available and convert PcdRiscVFeatureOverride
|
|
// PCD to a pointer that contains pointer to bitmap structure
|
|
// which can be operated more elegantly.
|
|
//
|
|
#define RISCV_CACHE_BLOCK_SIZE 64
|
|
#define RISCV_CPU_FEATURE_CMO_BITMASK 0x1
|
|
|
|
typedef enum {
|
|
CacheOpClean,
|
|
CacheOpFlush,
|
|
CacheOpInvld,
|
|
} CACHE_OP;
|
|
|
|
/**
|
|
Verify CBOs are supported by this HW
|
|
TODO: Use RISC-V CPU HOB once available.
|
|
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
RiscVIsCMOEnabled (
|
|
VOID
|
|
)
|
|
{
|
|
// If CMO is disabled in HW, skip Override check
|
|
// Otherwise this PCD can override settings
|
|
return ((PcdGet64 (PcdRiscVFeatureOverride) & RISCV_CPU_FEATURE_CMO_BITMASK) != 0);
|
|
}
|
|
|
|
/**
|
|
Performs required opeartion on cache lines in the cache coherency domain
|
|
of the calling CPU. If Address is not aligned on a cache line boundary,
|
|
then entire cache line containing Address is operated. If Address + Length
|
|
is not aligned on a cache line boundary, then the entire cache line
|
|
containing Address + Length -1 is operated.
|
|
If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
|
|
@param Address The base address of the cache lines to
|
|
invalidate.
|
|
@param Length The number of bytes to invalidate from the instruction
|
|
cache.
|
|
@param Op Type of CMO operation to be performed
|
|
@return Address.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
CacheOpCacheRange (
|
|
IN VOID *Address,
|
|
IN UINTN Length,
|
|
IN CACHE_OP Op
|
|
)
|
|
{
|
|
UINTN CacheLineSize;
|
|
UINTN Start;
|
|
UINTN End;
|
|
|
|
if (Length == 0) {
|
|
return;
|
|
}
|
|
|
|
if ((Op != CacheOpInvld) && (Op != CacheOpFlush) && (Op != CacheOpClean)) {
|
|
return;
|
|
}
|
|
|
|
ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Address));
|
|
|
|
CacheLineSize = RISCV_CACHE_BLOCK_SIZE;
|
|
|
|
Start = (UINTN)Address;
|
|
//
|
|
// Calculate the cache line alignment
|
|
//
|
|
End = (Start + Length + (CacheLineSize - 1)) & ~(CacheLineSize - 1);
|
|
Start &= ~((UINTN)CacheLineSize - 1);
|
|
|
|
DEBUG (
|
|
(DEBUG_VERBOSE,
|
|
"CacheOpCacheRange: Performing Cache Management Operation %d \n", Op)
|
|
);
|
|
|
|
do {
|
|
switch (Op) {
|
|
case CacheOpInvld:
|
|
RiscVCpuCacheInvalCmoAsm (Start);
|
|
break;
|
|
case CacheOpFlush:
|
|
RiscVCpuCacheFlushCmoAsm (Start);
|
|
break;
|
|
case CacheOpClean:
|
|
RiscVCpuCacheCleanCmoAsm (Start);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Start = Start + CacheLineSize;
|
|
} while (Start != End);
|
|
}
|
|
|
|
/**
|
|
Invalidates the entire instruction cache in cache coherency domain of the
|
|
calling CPU. Risc-V does not have currently an CBO implementation which can
|
|
invalidate the entire I-cache. Hence using Fence instruction for now. P.S.
|
|
Fence instruction may or may not implement full I-cache invd functionality
|
|
on all implementations.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
InvalidateInstructionCache (
|
|
VOID
|
|
)
|
|
{
|
|
RiscVInvalidateInstCacheFenceAsm ();
|
|
}
|
|
|
|
/**
|
|
Invalidates a range of instruction cache lines in the cache coherency domain
|
|
of the calling CPU.
|
|
|
|
An operation from a CMO instruction is defined to operate only on the copies
|
|
of a cache block that are cached in the caches accessible by the explicit
|
|
memory accesses performed by the set of coherent agents.In other words CMO
|
|
operations are not applicable to instruction cache. Use fence.i instruction
|
|
instead to achieve the same purpose.
|
|
@param Address The base address of the instruction cache lines to
|
|
invalidate. If the CPU is in a physical addressing mode, then
|
|
Address is a physical address. If the CPU is in a virtual
|
|
addressing mode, then Address is a virtual address.
|
|
|
|
@param Length The number of bytes to invalidate from the instruction cache.
|
|
|
|
@return Address.
|
|
|
|
**/
|
|
VOID *
|
|
EFIAPI
|
|
InvalidateInstructionCacheRange (
|
|
IN VOID *Address,
|
|
IN UINTN Length
|
|
)
|
|
{
|
|
DEBUG (
|
|
(DEBUG_VERBOSE,
|
|
"InvalidateInstructionCacheRange: RISC-V unsupported function.\n"
|
|
"Invalidating the whole instruction cache instead.\n"
|
|
)
|
|
);
|
|
InvalidateInstructionCache ();
|
|
return Address;
|
|
}
|
|
|
|
/**
|
|
Writes back and invalidates the entire data cache in cache coherency domain
|
|
of the calling CPU.
|
|
|
|
Writes back and invalidates the entire data cache in cache coherency domain
|
|
of the calling CPU. This function guarantees that all dirty cache lines are
|
|
written back to system memory, and also invalidates all the data cache lines
|
|
in the cache coherency domain of the calling CPU.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
WriteBackInvalidateDataCache (
|
|
VOID
|
|
)
|
|
{
|
|
ASSERT (FALSE);
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"WriteBackInvalidateDataCache: RISC-V unsupported function.\n"
|
|
));
|
|
}
|
|
|
|
/**
|
|
Writes back and invalidates a range of data cache lines in the cache
|
|
coherency domain of the calling CPU.
|
|
|
|
Writes back and invalidates the data cache lines specified by Address and
|
|
Length. If Address is not aligned on a cache line boundary, then entire data
|
|
cache line containing Address is written back and invalidated. If Address +
|
|
Length is not aligned on a cache line boundary, then the entire data cache
|
|
line containing Address + Length -1 is written back and invalidated. This
|
|
function may choose to write back and invalidate the entire data cache if
|
|
that is more efficient than writing back and invalidating the specified
|
|
range. If Length is 0, then no data cache lines are written back and
|
|
invalidated. Address is returned.
|
|
|
|
If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
|
|
|
|
@param Address The base address of the data cache lines to write back and
|
|
invalidate. If the CPU is in a physical addressing mode, then
|
|
Address is a physical address. If the CPU is in a virtual
|
|
addressing mode, then Address is a virtual address.
|
|
@param Length The number of bytes to write back and invalidate from the
|
|
data cache.
|
|
|
|
@return Address of cache invalidation.
|
|
|
|
**/
|
|
VOID *
|
|
EFIAPI
|
|
WriteBackInvalidateDataCacheRange (
|
|
IN VOID *Address,
|
|
IN UINTN Length
|
|
)
|
|
{
|
|
if (RiscVIsCMOEnabled ()) {
|
|
CacheOpCacheRange (Address, Length, CacheOpFlush);
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
return Address;
|
|
}
|
|
|
|
/**
|
|
Writes back the entire data cache in cache coherency domain of the calling
|
|
CPU.
|
|
|
|
Writes back the entire data cache in cache coherency domain of the calling
|
|
CPU. This function guarantees that all dirty cache lines are written back to
|
|
system memory. This function may also invalidate all the data cache lines in
|
|
the cache coherency domain of the calling CPU.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
WriteBackDataCache (
|
|
VOID
|
|
)
|
|
{
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
/**
|
|
Writes back a range of data cache lines in the cache coherency domain of the
|
|
calling CPU.
|
|
|
|
Writes back the data cache lines specified by Address and Length. If Address
|
|
is not aligned on a cache line boundary, then entire data cache line
|
|
containing Address is written back. If Address + Length is not aligned on a
|
|
cache line boundary, then the entire data cache line containing Address +
|
|
Length -1 is written back. This function may choose to write back the entire
|
|
data cache if that is more efficient than writing back the specified range.
|
|
If Length is 0, then no data cache lines are written back. This function may
|
|
also invalidate all the data cache lines in the specified range of the cache
|
|
coherency domain of the calling CPU. Address is returned.
|
|
|
|
If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
|
|
|
|
@param Address The base address of the data cache lines to write back.
|
|
@param Length The number of bytes to write back from the data cache.
|
|
|
|
@return Address of cache written in main memory.
|
|
|
|
**/
|
|
VOID *
|
|
EFIAPI
|
|
WriteBackDataCacheRange (
|
|
IN VOID *Address,
|
|
IN UINTN Length
|
|
)
|
|
{
|
|
if (RiscVIsCMOEnabled ()) {
|
|
CacheOpCacheRange (Address, Length, CacheOpClean);
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
return Address;
|
|
}
|
|
|
|
/**
|
|
Invalidates the entire data cache in cache coherency domain of the calling
|
|
CPU.
|
|
|
|
Invalidates the entire data cache in cache coherency domain of the calling
|
|
CPU. This function must be used with care because dirty cache lines are not
|
|
written back to system memory. It is typically used for cache diagnostics. If
|
|
the CPU does not support invalidation of the entire data cache, then a write
|
|
back and invalidate operation should be performed on the entire data cache.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
InvalidateDataCache (
|
|
VOID
|
|
)
|
|
{
|
|
RiscVInvalidateDataCacheFenceAsm ();
|
|
}
|
|
|
|
/**
|
|
Invalidates a range of data cache lines in the cache coherency domain of the
|
|
calling CPU.
|
|
|
|
Invalidates the data cache lines specified by Address and Length. If Address
|
|
is not aligned on a cache line boundary, then entire data cache line
|
|
containing Address is invalidated. If Address + Length is not aligned on a
|
|
cache line boundary, then the entire data cache line containing Address +
|
|
Length -1 is invalidated. This function must never invalidate any cache lines
|
|
outside the specified range. If Length is 0, then no data cache lines are
|
|
invalidated. Address is returned. This function must be used with care
|
|
because dirty cache lines are not written back to system memory. It is
|
|
typically used for cache diagnostics. If the CPU does not support
|
|
invalidation of a data cache range, then a write back and invalidate
|
|
operation should be performed on the data cache range.
|
|
|
|
If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
|
|
|
|
@param Address The base address of the data cache lines to invalidate.
|
|
@param Length The number of bytes to invalidate from the data cache.
|
|
|
|
@return Address.
|
|
|
|
**/
|
|
VOID *
|
|
EFIAPI
|
|
InvalidateDataCacheRange (
|
|
IN VOID *Address,
|
|
IN UINTN Length
|
|
)
|
|
{
|
|
if (RiscVIsCMOEnabled ()) {
|
|
CacheOpCacheRange (Address, Length, CacheOpInvld);
|
|
} else {
|
|
DEBUG (
|
|
(DEBUG_VERBOSE,
|
|
"InvalidateDataCacheRange: Zicbom not supported.\n"
|
|
"Invalidating the whole Data cache instead.\n")
|
|
);
|
|
InvalidateDataCache ();
|
|
}
|
|
|
|
return Address;
|
|
}
|