forked from Mirrors/opensbi

csr_read() is marked as volatile and clobbering memory, which is generally the safe thing to do. However, these two CSRs do not have any side effects, and the values returned do not change between calls. The compiler can generate better code if we allow it to reorder calls to these functions and cache the return value. Introduce csr_read_relaxed() for this use case. Signed-off-by: Samuel Holland <samuel.holland@sifive.com> Reviewed-by: Anup Patel <anup@brainfault.org>
262 lines
9.0 KiB
C
262 lines
9.0 KiB
C
/*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
|
*
|
|
* Authors:
|
|
* Anup Patel <anup.patel@wdc.com>
|
|
*/
|
|
|
|
#ifndef __SBI_SCRATCH_H__
|
|
#define __SBI_SCRATCH_H__
|
|
|
|
#include <sbi/riscv_asm.h>
|
|
|
|
/* clang-format off */
|
|
|
|
/** Offset of fw_start member in sbi_scratch */
|
|
#define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__)
|
|
/** Offset of fw_size member in sbi_scratch */
|
|
#define SBI_SCRATCH_FW_SIZE_OFFSET (1 * __SIZEOF_POINTER__)
|
|
/** Offset (in sbi_scratch) of the R/W Offset */
|
|
#define SBI_SCRATCH_FW_RW_OFFSET (2 * __SIZEOF_POINTER__)
|
|
/** Offset of fw_heap_offset member in sbi_scratch */
|
|
#define SBI_SCRATCH_FW_HEAP_OFFSET (3 * __SIZEOF_POINTER__)
|
|
/** Offset of fw_heap_size_offset member in sbi_scratch */
|
|
#define SBI_SCRATCH_FW_HEAP_SIZE_OFFSET (4 * __SIZEOF_POINTER__)
|
|
/** Offset of next_arg1 member in sbi_scratch */
|
|
#define SBI_SCRATCH_NEXT_ARG1_OFFSET (5 * __SIZEOF_POINTER__)
|
|
/** Offset of next_addr member in sbi_scratch */
|
|
#define SBI_SCRATCH_NEXT_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
|
|
/** Offset of next_mode member in sbi_scratch */
|
|
#define SBI_SCRATCH_NEXT_MODE_OFFSET (7 * __SIZEOF_POINTER__)
|
|
/** Offset of warmboot_addr member in sbi_scratch */
|
|
#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (8 * __SIZEOF_POINTER__)
|
|
/** Offset of platform_addr member in sbi_scratch */
|
|
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (9 * __SIZEOF_POINTER__)
|
|
/** Offset of hartid_to_scratch member in sbi_scratch */
|
|
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (10 * __SIZEOF_POINTER__)
|
|
/** Offset of trap_context member in sbi_scratch */
|
|
#define SBI_SCRATCH_TRAP_CONTEXT_OFFSET (11 * __SIZEOF_POINTER__)
|
|
/** Offset of tmp0 member in sbi_scratch */
|
|
#define SBI_SCRATCH_TMP0_OFFSET (12 * __SIZEOF_POINTER__)
|
|
/** Offset of options member in sbi_scratch */
|
|
#define SBI_SCRATCH_OPTIONS_OFFSET (13 * __SIZEOF_POINTER__)
|
|
/** Offset of hartindex member in sbi_scratch */
|
|
#define SBI_SCRATCH_HARTINDEX_OFFSET (14 * __SIZEOF_POINTER__)
|
|
/** Offset of extra space in sbi_scratch */
|
|
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (15 * __SIZEOF_POINTER__)
|
|
/** Maximum size of sbi_scratch (4KB) */
|
|
#define SBI_SCRATCH_SIZE (0x1000)
|
|
|
|
/* clang-format on */
|
|
|
|
#ifndef __ASSEMBLER__
|
|
|
|
#include <sbi/sbi_types.h>
|
|
|
|
/** Representation of per-HART scratch space */
|
|
struct sbi_scratch {
|
|
/** Start (or base) address of firmware linked to OpenSBI library */
|
|
unsigned long fw_start;
|
|
/** Size (in bytes) of firmware linked to OpenSBI library */
|
|
unsigned long fw_size;
|
|
/** Offset (in bytes) of the R/W section */
|
|
unsigned long fw_rw_offset;
|
|
/** Offset (in bytes) of the heap area */
|
|
unsigned long fw_heap_offset;
|
|
/** Size (in bytes) of the heap area */
|
|
unsigned long fw_heap_size;
|
|
/** Arg1 (or 'a1' register) of next booting stage for this HART */
|
|
unsigned long next_arg1;
|
|
/** Address of next booting stage for this HART */
|
|
unsigned long next_addr;
|
|
/** Privilege mode of next booting stage for this HART */
|
|
unsigned long next_mode;
|
|
/** Warm boot entry point address for this HART */
|
|
unsigned long warmboot_addr;
|
|
/** Address of sbi_platform */
|
|
unsigned long platform_addr;
|
|
/** Address of HART ID to sbi_scratch conversion function */
|
|
unsigned long hartid_to_scratch;
|
|
/** Address of current trap context */
|
|
unsigned long trap_context;
|
|
/** Temporary storage */
|
|
unsigned long tmp0;
|
|
/** Options for OpenSBI library */
|
|
unsigned long options;
|
|
/** Index of the hart */
|
|
unsigned long hartindex;
|
|
};
|
|
|
|
/**
|
|
* Prevent modification of struct sbi_scratch from affecting
|
|
* SBI_SCRATCH_xxx_OFFSET
|
|
*/
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, fw_start)
|
|
== SBI_SCRATCH_FW_START_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_FW_START_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, fw_size)
|
|
== SBI_SCRATCH_FW_SIZE_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_FW_SIZE_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, next_arg1)
|
|
== SBI_SCRATCH_NEXT_ARG1_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_NEXT_ARG1_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, next_addr)
|
|
== SBI_SCRATCH_NEXT_ADDR_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_NEXT_ADDR_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, next_mode)
|
|
== SBI_SCRATCH_NEXT_MODE_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_NEXT_MODE_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, warmboot_addr)
|
|
== SBI_SCRATCH_WARMBOOT_ADDR_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_WARMBOOT_ADDR_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, platform_addr)
|
|
== SBI_SCRATCH_PLATFORM_ADDR_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_PLATFORM_ADDR_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, hartid_to_scratch)
|
|
== SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, trap_context)
|
|
== SBI_SCRATCH_TRAP_CONTEXT_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_TRAP_CONTEXT_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, tmp0)
|
|
== SBI_SCRATCH_TMP0_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_TMP0_OFFSET");
|
|
_Static_assert(
|
|
offsetof(struct sbi_scratch, options)
|
|
== SBI_SCRATCH_OPTIONS_OFFSET,
|
|
"struct sbi_scratch definition has changed, please redefine "
|
|
"SBI_SCRATCH_OPTIONS_OFFSET");
|
|
|
|
/** Possible options for OpenSBI library */
|
|
enum sbi_scratch_options {
|
|
/** Disable prints during boot */
|
|
SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0),
|
|
/** Enable runtime debug prints */
|
|
SBI_SCRATCH_DEBUG_PRINTS = (1 << 1),
|
|
};
|
|
|
|
/** Get pointer to sbi_scratch for current HART */
|
|
#define sbi_scratch_thishart_ptr() \
|
|
((struct sbi_scratch *)csr_read_relaxed(CSR_MSCRATCH))
|
|
|
|
/** Get Arg1 of next booting stage for current HART */
|
|
#define sbi_scratch_thishart_arg1_ptr() \
|
|
((void *)(sbi_scratch_thishart_ptr()->next_arg1))
|
|
|
|
/** Initialize scratch table and allocator */
|
|
int sbi_scratch_init(struct sbi_scratch *scratch);
|
|
|
|
/**
|
|
* Allocate from extra space in sbi_scratch
|
|
*
|
|
* @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
|
|
* on success
|
|
*/
|
|
unsigned long sbi_scratch_alloc_offset(unsigned long size);
|
|
|
|
/** Free-up extra space in sbi_scratch */
|
|
void sbi_scratch_free_offset(unsigned long offset);
|
|
|
|
/** Amount (in bytes) of used space in in sbi_scratch */
|
|
unsigned long sbi_scratch_used_space(void);
|
|
|
|
/** Get pointer from offset in sbi_scratch */
|
|
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset))
|
|
|
|
/** Get pointer from offset in sbi_scratch for current HART */
|
|
#define sbi_scratch_thishart_offset_ptr(offset) \
|
|
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
|
|
|
|
/** Allocate offset for a data type in sbi_scratch */
|
|
#define sbi_scratch_alloc_type_offset(__type) \
|
|
sbi_scratch_alloc_offset(sizeof(__type))
|
|
|
|
/** Read a data type from sbi_scratch at given offset */
|
|
#define sbi_scratch_read_type(__scratch, __type, __offset) \
|
|
({ \
|
|
*((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))); \
|
|
})
|
|
|
|
/** Write a data type to sbi_scratch at given offset */
|
|
#define sbi_scratch_write_type(__scratch, __type, __offset, __ptr) \
|
|
do { \
|
|
*((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))) \
|
|
= (__type)(__ptr); \
|
|
} while (0)
|
|
|
|
/** Get the hart index of the current hart */
|
|
#define current_hartindex() \
|
|
(sbi_scratch_thishart_ptr()->hartindex)
|
|
|
|
/** Last HART index having a sbi_scratch pointer */
|
|
extern u32 last_hartindex_having_scratch;
|
|
|
|
/** Get last HART index having a sbi_scratch pointer */
|
|
#define sbi_scratch_last_hartindex() last_hartindex_having_scratch
|
|
|
|
/** Check whether a particular HART index is valid or not */
|
|
#define sbi_hartindex_valid(__hartindex) \
|
|
(((__hartindex) <= sbi_scratch_last_hartindex()) ? true : false)
|
|
|
|
/** HART index to HART id table */
|
|
extern u32 hartindex_to_hartid_table[];
|
|
|
|
/** Get sbi_scratch from HART index */
|
|
#define sbi_hartindex_to_hartid(__hartindex) \
|
|
({ \
|
|
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
|
|
hartindex_to_hartid_table[__hartindex] : -1U; \
|
|
})
|
|
|
|
/** HART index to scratch table */
|
|
extern struct sbi_scratch *hartindex_to_scratch_table[];
|
|
|
|
/** Get sbi_scratch from HART index */
|
|
#define sbi_hartindex_to_scratch(__hartindex) \
|
|
({ \
|
|
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
|
|
hartindex_to_scratch_table[__hartindex] : NULL;\
|
|
})
|
|
|
|
/**
|
|
* Get logical index for given HART id
|
|
* @param hartid physical HART id
|
|
* @returns value between 0 to SBI_HARTMASK_MAX_BITS upon success and
|
|
* SBI_HARTMASK_MAX_BITS upon failure.
|
|
*/
|
|
u32 sbi_hartid_to_hartindex(u32 hartid);
|
|
|
|
/** Get sbi_scratch from HART id */
|
|
#define sbi_hartid_to_scratch(__hartid) \
|
|
sbi_hartindex_to_scratch(sbi_hartid_to_hartindex(__hartid))
|
|
|
|
/** Check whether particular HART id is valid or not */
|
|
#define sbi_hartid_valid(__hartid) \
|
|
sbi_hartindex_valid(sbi_hartid_to_hartindex(__hartid))
|
|
|
|
#endif
|
|
|
|
#endif
|