mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-25 07:41:42 +01:00
sbi: sbi_domain_context: Add spinlock for updating domain assigned_harts
Add spinlock protection to avoid race condition on assigned_harts during domain context switching. Also, rename/add variables for accessing the corresponding domain of target/current context. Signed-off-by: Alvin Chang <alvinga@andestech.com> Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com> Reviewed-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#ifndef __SBI_DOMAIN_H__
|
#ifndef __SBI_DOMAIN_H__
|
||||||
#define __SBI_DOMAIN_H__
|
#define __SBI_DOMAIN_H__
|
||||||
|
|
||||||
|
#include <sbi/riscv_locks.h>
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
#include <sbi/sbi_hartmask.h>
|
#include <sbi/sbi_hartmask.h>
|
||||||
#include <sbi/sbi_domain_context.h>
|
#include <sbi/sbi_domain_context.h>
|
||||||
@@ -173,6 +174,8 @@ struct sbi_domain {
|
|||||||
* in the coldboot path
|
* in the coldboot path
|
||||||
*/
|
*/
|
||||||
struct sbi_hartmask assigned_harts;
|
struct sbi_hartmask assigned_harts;
|
||||||
|
/** Spinlock for accessing assigned_harts */
|
||||||
|
spinlock_t assigned_harts_lock;
|
||||||
/** Name of this domain */
|
/** Name of this domain */
|
||||||
char name[64];
|
char name[64];
|
||||||
/** Possible HARTs in this domain */
|
/** Possible HARTs in this domain */
|
||||||
|
@@ -64,20 +64,34 @@ void sbi_update_hartindex_to_domain(u32 hartindex, struct sbi_domain *dom)
|
|||||||
|
|
||||||
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
|
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
|
||||||
{
|
{
|
||||||
if (dom)
|
bool ret;
|
||||||
return sbi_hartmask_test_hartid(hartid, &dom->assigned_harts);
|
struct sbi_domain *tdom = (struct sbi_domain *)dom;
|
||||||
|
|
||||||
return false;
|
if (!dom)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
spin_lock(&tdom->assigned_harts_lock);
|
||||||
|
ret = sbi_hartmask_test_hartid(hartid, &tdom->assigned_harts);
|
||||||
|
spin_unlock(&tdom->assigned_harts_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
||||||
ulong hbase)
|
ulong hbase)
|
||||||
{
|
{
|
||||||
ulong ret = 0;
|
ulong ret = 0;
|
||||||
|
struct sbi_domain *tdom = (struct sbi_domain *)dom;
|
||||||
|
|
||||||
|
if (!dom)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
spin_lock(&tdom->assigned_harts_lock);
|
||||||
for (int i = 0; i < 8 * sizeof(ret); i++) {
|
for (int i = 0; i < 8 * sizeof(ret); i++) {
|
||||||
if (sbi_domain_is_assigned_hart(dom, hbase + i))
|
if (sbi_hartmask_test_hartid(hbase + i, &tdom->assigned_harts))
|
||||||
ret |= 1UL << i;
|
ret |= 1UL << i;
|
||||||
}
|
}
|
||||||
|
spin_unlock(&tdom->assigned_harts_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -555,6 +569,9 @@ int sbi_domain_register(struct sbi_domain *dom,
|
|||||||
dom->index = domain_count++;
|
dom->index = domain_count++;
|
||||||
domidx_to_domain_table[dom->index] = dom;
|
domidx_to_domain_table[dom->index] = dom;
|
||||||
|
|
||||||
|
/* Initialize spinlock for dom->assigned_harts */
|
||||||
|
SPIN_LOCK_INIT(dom->assigned_harts_lock);
|
||||||
|
|
||||||
/* Clear assigned HARTs of domain */
|
/* Clear assigned HARTs of domain */
|
||||||
sbi_hartmask_clear_all(&dom->assigned_harts);
|
sbi_hartmask_clear_all(&dom->assigned_harts);
|
||||||
|
|
||||||
@@ -701,8 +718,14 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Ignore if boot HART assigned different domain */
|
/* Ignore if boot HART assigned different domain */
|
||||||
if (sbi_hartindex_to_domain(dhart) != dom ||
|
if (sbi_hartindex_to_domain(dhart) != dom)
|
||||||
!sbi_hartmask_test_hartindex(dhart, &dom->assigned_harts))
|
continue;
|
||||||
|
|
||||||
|
/* Ignore if boot HART is not part of the assigned HARTs */
|
||||||
|
spin_lock(&dom->assigned_harts_lock);
|
||||||
|
rc = sbi_hartmask_test_hartindex(dhart, &dom->assigned_harts);
|
||||||
|
spin_unlock(&dom->assigned_harts_lock);
|
||||||
|
if (!rc)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Startup boot HART of domain */
|
/* Startup boot HART of domain */
|
||||||
|
@@ -26,18 +26,23 @@
|
|||||||
static void switch_to_next_domain_context(struct sbi_context *ctx,
|
static void switch_to_next_domain_context(struct sbi_context *ctx,
|
||||||
struct sbi_context *dom_ctx)
|
struct sbi_context *dom_ctx)
|
||||||
{
|
{
|
||||||
u32 hartindex;
|
u32 hartindex = sbi_hartid_to_hartindex(current_hartid());
|
||||||
struct sbi_trap_regs *trap_regs;
|
struct sbi_trap_regs *trap_regs;
|
||||||
struct sbi_domain *dom = dom_ctx->dom;
|
struct sbi_domain *current_dom = ctx->dom;
|
||||||
|
struct sbi_domain *target_dom = dom_ctx->dom;
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
|
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
|
||||||
|
|
||||||
/* Assign current hart to target domain */
|
/* Assign current hart to target domain */
|
||||||
hartindex = sbi_hartid_to_hartindex(current_hartid());
|
spin_lock(¤t_dom->assigned_harts_lock);
|
||||||
sbi_hartmask_clear_hartindex(
|
sbi_hartmask_clear_hartindex(hartindex, ¤t_dom->assigned_harts);
|
||||||
hartindex, &sbi_domain_thishart_ptr()->assigned_harts);
|
spin_unlock(¤t_dom->assigned_harts_lock);
|
||||||
sbi_update_hartindex_to_domain(hartindex, dom);
|
|
||||||
sbi_hartmask_set_hartindex(hartindex, &dom->assigned_harts);
|
sbi_update_hartindex_to_domain(hartindex, target_dom);
|
||||||
|
|
||||||
|
spin_lock(&target_dom->assigned_harts_lock);
|
||||||
|
sbi_hartmask_set_hartindex(hartindex, &target_dom->assigned_harts);
|
||||||
|
spin_unlock(&target_dom->assigned_harts_lock);
|
||||||
|
|
||||||
/* Reconfigure PMP settings for the new domain */
|
/* Reconfigure PMP settings for the new domain */
|
||||||
for (int i = 0; i < pmp_count; i++) {
|
for (int i = 0; i < pmp_count; i++) {
|
||||||
@@ -72,9 +77,11 @@ static void switch_to_next_domain_context(struct sbi_context *ctx,
|
|||||||
/* If target domain context is not initialized or runnable */
|
/* If target domain context is not initialized or runnable */
|
||||||
if (!dom_ctx->initialized) {
|
if (!dom_ctx->initialized) {
|
||||||
/* Startup boot HART of target domain */
|
/* Startup boot HART of target domain */
|
||||||
if (current_hartid() == dom->boot_hartid)
|
if (current_hartid() == target_dom->boot_hartid)
|
||||||
sbi_hart_switch_mode(dom->boot_hartid, dom->next_arg1,
|
sbi_hart_switch_mode(target_dom->boot_hartid,
|
||||||
dom->next_addr, dom->next_mode,
|
target_dom->next_arg1,
|
||||||
|
target_dom->next_addr,
|
||||||
|
target_dom->next_mode,
|
||||||
false);
|
false);
|
||||||
else
|
else
|
||||||
sbi_hsm_hart_stop(scratch, true);
|
sbi_hsm_hart_stop(scratch, true);
|
||||||
|
@@ -148,7 +148,7 @@ bool sbi_system_suspend_supported(u32 sleep_type)
|
|||||||
|
|
||||||
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
|
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
|
||||||
{
|
{
|
||||||
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
|
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
|
||||||
unsigned int hartid = current_hartid();
|
unsigned int hartid = current_hartid();
|
||||||
@@ -171,13 +171,17 @@ int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
|
|||||||
if (prev_mode != PRV_S && prev_mode != PRV_U)
|
if (prev_mode != PRV_S && prev_mode != PRV_U)
|
||||||
return SBI_EFAIL;
|
return SBI_EFAIL;
|
||||||
|
|
||||||
|
spin_lock(&dom->assigned_harts_lock);
|
||||||
sbi_hartmask_for_each_hartindex(j, &dom->assigned_harts) {
|
sbi_hartmask_for_each_hartindex(j, &dom->assigned_harts) {
|
||||||
i = sbi_hartindex_to_hartid(j);
|
i = sbi_hartindex_to_hartid(j);
|
||||||
if (i == hartid)
|
if (i == hartid)
|
||||||
continue;
|
continue;
|
||||||
if (__sbi_hsm_hart_get_state(i) != SBI_HSM_STATE_STOPPED)
|
if (__sbi_hsm_hart_get_state(i) != SBI_HSM_STATE_STOPPED) {
|
||||||
|
spin_unlock(&dom->assigned_harts_lock);
|
||||||
return SBI_ERR_DENIED;
|
return SBI_ERR_DENIED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
spin_unlock(&dom->assigned_harts_lock);
|
||||||
|
|
||||||
if (!sbi_domain_check_addr(dom, resume_addr, prev_mode,
|
if (!sbi_domain_check_addr(dom, resume_addr, prev_mode,
|
||||||
SBI_DOMAIN_EXECUTE))
|
SBI_DOMAIN_EXECUTE))
|
||||||
|
Reference in New Issue
Block a user