diff options
Diffstat (limited to 'src/arch/arm64/armv8')
-rw-r--r-- | src/arch/arm64/armv8/Makefile.inc | 4 | ||||
-rw-r--r-- | src/arch/arm64/armv8/lib/Makefile.inc | 4 | ||||
-rw-r--r-- | src/arch/arm64/armv8/secmon/Makefile.inc | 53 | ||||
-rw-r--r-- | src/arch/arm64/armv8/secmon/psci.c | 705 | ||||
-rw-r--r-- | src/arch/arm64/armv8/secmon/secmon.h | 29 | ||||
-rw-r--r-- | src/arch/arm64/armv8/secmon/secmon_init.c | 132 | ||||
-rw-r--r-- | src/arch/arm64/armv8/secmon/smc.c | 163 | ||||
-rw-r--r-- | src/arch/arm64/armv8/secmon/trampoline.S | 47 | ||||
-rw-r--r-- | src/arch/arm64/armv8/secmon_loader.c | 157 |
9 files changed, 0 insertions, 1294 deletions
diff --git a/src/arch/arm64/armv8/Makefile.inc b/src/arch/arm64/armv8/Makefile.inc index 48358adb97..357159d6a7 100644 --- a/src/arch/arm64/armv8/Makefile.inc +++ b/src/arch/arm64/armv8/Makefile.inc @@ -17,8 +17,6 @@ subdirs-y += lib/ -subdirs-$(CONFIG_ARM64_USE_SECURE_MONITOR) += secmon/ - armv8_flags = -march=armv8-a -I$(src)/arch/arm64/include/armv8/ -D__COREBOOT_ARM_ARCH__=8 armv8_asm_flags = $(armv8_flags) @@ -88,8 +86,6 @@ ramstage-y += cpu.S ramstage-y += exception.c ramstage-y += mmu.c -ramstage-$(CONFIG_ARM64_USE_SECURE_MONITOR) += secmon_loader.c - ramstage-c-ccopts += $(armv8_flags) ramstage-S-ccopts += $(armv8_asm_flags) diff --git a/src/arch/arm64/armv8/lib/Makefile.inc b/src/arch/arm64/armv8/lib/Makefile.inc index c3de597c54..2bf1a37c7a 100644 --- a/src/arch/arm64/armv8/lib/Makefile.inc +++ b/src/arch/arm64/armv8/lib/Makefile.inc @@ -32,8 +32,4 @@ endif ifeq ($(CONFIG_ARCH_RAMSTAGE_ARMV8_64),y) ramstage-y += $(lib_access) -ifeq ($(CONFIG_ARM64_USE_SECURE_MONITOR),y) -secmon-y += $(lib_access) -endif - endif diff --git a/src/arch/arm64/armv8/secmon/Makefile.inc b/src/arch/arm64/armv8/secmon/Makefile.inc deleted file mode 100644 index 7d66adfcc1..0000000000 --- a/src/arch/arm64/armv8/secmon/Makefile.inc +++ /dev/null @@ -1,53 +0,0 @@ -################################################################################ -## -## This file is part of the coreboot project. -## -## Copyright (C) 2014 Google Inc. -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; version 2 of the License. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -################################################################################ - -$(eval $(call create_class_compiler,secmon,arm64)) - -SECMON_DIR=$(obj)/arch/arm64/armv8/secmon -SECMON_BIN=$(SECMON_DIR)/secmon -SECMON_OBJ=$(SECMON_BIN).o -SECMON_ELF=$(SECMON_BIN).elf -SECMON_RMOD=$(SECMON_ELF).rmod -SECMON_RAMSTAGE=$(SECMON_DIR)/secmon.manual - -secmon-generic-ccopts += -I$(src)/arch/arm64/include/armv8/ -include $(src)/include/kconfig.h -D__SECMON__ - -secmon-y += secmon_init.c -secmon-y += psci.c -secmon-y += smc.c -secmon-y += trampoline.S -secmon-y += ../cache.c -secmon-y += ../cache_helpers.S -secmon-y += ../cpu.S -secmon-y += ../exception.c -secmon-y += ../../cpu.c -secmon-y += ../../transition_asm.S ../../transition.c -secmon-y += ../../../../drivers/gic/gic.c - -ramstage-srcs += $(SECMON_RAMSTAGE) - -$(SECMON_OBJ): $$(secmon-objs) - $(CC_secmon) $(LDFLAGS) -nostdlib -r -o $@ $^ - -$(eval $(call rmodule_link,$(SECMON_ELF), $(SECMON_OBJ), 8192,arm64)) - -$(SECMON_BIN): $(SECMON_RMOD) - $(OBJCOPY_secmon) -O binary $< $@ - -$(SECMON_BIN).ramstage.manual: $(SECMON_BIN) - @printf " OBJCOPY $(subst $(obj)/,,$(@))\n" - cd $(dir $@); $(OBJCOPY_secmon) -I binary $(notdir $<) -O elf64-littleaarch64 -B aarch64 $(notdir $@) diff --git a/src/arch/arm64/armv8/secmon/psci.c b/src/arch/arm64/armv8/secmon/psci.c deleted file mode 100644 index 9ae8cc5c7f..0000000000 --- a/src/arch/arm64/armv8/secmon/psci.c +++ /dev/null @@ -1,705 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <gic.h> -#include <string.h> -#include <stdlib.h> -#include <smp/spinlock.h> -#include <arch/cpu.h> -#include <arch/psci.h> -#include <arch/smc.h> -#include <arch/transition.h> -#include <arch/lib_helpers.h> -#include <console/console.h> -#include "secmon.h" - -DECLARE_SPIN_LOCK(psci_spinlock); - -/* Root of PSCI node tree. */ -static struct psci_node psci_root; - -/* Array of all the psci_nodes in system. */ -static size_t psci_num_nodes; -static struct psci_node **psci_nodes; - -static inline void psci_lock(void) -{ - spin_lock(&psci_spinlock); -} - -static inline void psci_unlock(void) -{ - spin_unlock(&psci_spinlock); -} - -static inline int psci_state_locked(const struct psci_node *e) -{ - return e->state; -} - -static inline void psci_set_state_locked(struct psci_node *e, int s) -{ - e->state = s; -} - -static struct psci_node *psci_node_lookup(uint64_t mpidr, int level) -{ - size_t i; - - /* The array of node pointers are in depth-first order of the tree. */ - for (i = 0; i < psci_num_nodes; i++) { - struct psci_node *current = psci_nodes[i]; - - if (current->mpidr > mpidr) - break; - if (current->mpidr < mpidr) - continue; - if (current->level == level) - return current; - } - return NULL; -} - -static inline struct psci_node *node_self(void) -{ - return psci_node_lookup(cpu_info()->mpidr, PSCI_AFFINITY_LEVEL_0); -} - -/* Find the ancestor of node affected by a state transition limited by level. */ -static struct psci_node *psci_find_ancestor(struct psci_node *e, int level, - int state) -{ - struct psci_node *p; - - /* If all siblings of the node are already off then parent can be - * set to off as well. */ - if (state == PSCI_STATE_OFF) { - while (1) { - size_t i; - struct psci_node *s; - - if (psci_root_node(e)) - return e; - - p = psci_node_parent(e); - - if (p->level > level) - return e; - - for (i = 0; i < p->children.num; i++) { - s = &p->children.nodes[i]; - /* Don't check target. */ - if (s == e) - continue; - if (psci_state_locked(s) != PSCI_STATE_OFF) - return e; - } - - e = p; - } - } - - /* All ancestors in state OFF are affected. */ - if (state == PSCI_STATE_ON_PENDING) { - while (1) { - /* At the root. Return last affected node. */ - if (psci_root_node(e)) - return e; - - p = psci_node_parent(e); - - if (p->level > level) - return e; - - /* This parent is already ON. */ - if (psci_state_locked(p) != PSCI_STATE_OFF) - return e; - - e = p; - } - } - - /* Default to returning node passed in. */ - return e; -} - -static void psci_set_hierarchy_state(struct psci_node *from, - struct psci_node *to, - int state) -{ - struct psci_node *end; - - end = psci_node_parent(to); - - while (from != end) { - /* Raced with another CPU as state is already set. */ - if (psci_state_locked(from) == state) - break; - psci_set_state_locked(from, state); - from = psci_node_parent(from); - } -} - -static void psci_cpu_on_callback(void *arg) -{ - struct exc_state state; - int target_el; - struct psci_node *e = arg; - - psci_lock(); - psci_set_hierarchy_state(e, e->cpu_state.ancestor, PSCI_STATE_ON); - psci_unlock(); - - /* Target EL is determined if HVC is enabled or not. */ - target_el = (raw_read_scr_el3() & SCR_HVC_ENABLE) ? EL2 : EL1; - - memset(&state, 0, sizeof(state)); - state.elx.spsr = get_eret_el(target_el, SPSR_USE_H); - transition_with_entry(e->cpu_state.startup.run, - e->cpu_state.startup.arg, &state); -} - -static void psci_cpu_on_prepare(struct psci_cmd *cmd, - const struct cpu_action *a) -{ - struct psci_node *ancestor; - struct psci_node *e; - int state = PSCI_STATE_ON_PENDING; - - e = cmd->target; - e->cpu_state.startup = *a; - ancestor = psci_find_ancestor(e, PSCI_AFFINITY_LEVEL_HIGHEST, state); - e->cpu_state.ancestor = ancestor; - cmd->ancestor = ancestor; -} - -static int psci_schedule_cpu_on(struct psci_node *e) -{ - struct cpu_info *ci; - struct cpu_action action = { - .run = &psci_cpu_on_callback, - .arg = e, - }; - - ci = e->cpu_state.ci; - if (ci == NULL || arch_run_on_cpu_async(ci->id, &action)) { - psci_set_hierarchy_state(e, e->cpu_state.ancestor, - PSCI_STATE_OFF); - return PSCI_RET_INTERNAL_FAILURE; - } - - return PSCI_RET_SUCCESS; -} - -static void psci_cpu_resume_prepare(struct psci_cmd *cmd, - const struct cpu_action *a) -{ - struct psci_node *ancestor; - struct psci_node *e; - int state = PSCI_STATE_ON_PENDING; - - e = cmd->target; - e->cpu_state.resume = *a; - ancestor = psci_find_ancestor(e, PSCI_AFFINITY_LEVEL_HIGHEST, state); - e->cpu_state.ancestor = ancestor; - cmd->ancestor = ancestor; -} - -static void psci_schedule_cpu_resume(struct psci_node *e) -{ - struct cpu_info *ci; - struct cpu_action *action; - - if (e->cpu_state.resume.run == NULL) - return; - - ci = e->cpu_state.ci; - action = &e->cpu_state.resume; - - arch_run_on_cpu(ci->id, action); -} - -void psci_turn_on_self(const struct cpu_action *action) -{ - struct psci_node *e = node_self(); - struct psci_cmd cmd = { - .type = PSCI_CMD_ON, - }; - - if (e == NULL) { - printk(BIOS_ERR, "Couldn't turn on self: mpidr %llx\n", - cpu_info()->mpidr); - return; - } - - cmd.target = e; - - psci_lock(); - psci_cpu_on_prepare(&cmd, action); - psci_set_hierarchy_state(e, cmd.ancestor, PSCI_STATE_ON_PENDING); - psci_unlock(); - - psci_schedule_cpu_on(e); -} - -void psci_cpu_entry(void) -{ - gic_enable(); - - /* - * Just wait for an action to be performed. - */ - psci_schedule_cpu_resume(node_self()); - secmon_wait_for_action(); -} - -static void psci_cpu_resume(void *arg) -{ - uint64_t power_state = (uint64_t)arg; - struct psci_node *e; - struct psci_power_state state; - struct psci_cmd cmd = { - .type = PSCI_CMD_RESUME, - }; - - psci_power_state_unpack(power_state, &state); - - psci_lock(); - - e = node_self(); - /* clear the resume action after resume */ - e->cpu_state.resume.run = NULL; - e->cpu_state.resume.arg = NULL; - - cmd.target = e; - cmd.state = &state; - soc_psci_ops.cmd_prepare(&cmd); - - psci_unlock(); - - soc_psci_ops.cmd_commit(&cmd); - - psci_lock(); - psci_set_hierarchy_state(e, e->cpu_state.ancestor, PSCI_STATE_ON); - psci_unlock(); - - psci_schedule_cpu_on(node_self()); -} - -static void psci_cpu_suspend(struct psci_func *pf) -{ - uint64_t power_state; - uint64_t entry; - uint64_t context_id; - struct psci_node *e; - struct psci_power_state state; - struct cpu_action action; - struct cpu_action resume_action; - struct psci_cmd cmd = { - .type = PSCI_CMD_SUSPEND, - }; - int ret; - - power_state = psci64_arg(pf, PSCI_PARAM_0); - entry = psci64_arg(pf, PSCI_PARAM_1); - context_id = psci64_arg(pf, PSCI_PARAM_2); - psci_power_state_unpack(power_state, &state); - - psci_lock(); - - e = node_self(); - cmd.target = e; - cmd.state = &state; - action.run = (void *)entry; - action.arg = (void *)context_id; - resume_action.run = &psci_cpu_resume; - resume_action.arg = (void*)power_state; - - psci_cpu_on_prepare(&cmd, &action); - psci_cpu_resume_prepare(&cmd, &resume_action); - - ret = soc_psci_ops.cmd_prepare(&cmd); - - if (ret == PSCI_RET_SUCCESS) - psci_set_hierarchy_state(e, cmd.ancestor, PSCI_STATE_OFF); - - psci_unlock(); - - if (ret != PSCI_RET_SUCCESS) - return psci32_return(pf, ret); - - gic_disable(); - - ret = soc_psci_ops.cmd_commit(&cmd); - - /* PSCI_POWER_STATE_TYPE_STANDBY mode only */ - - psci_lock(); - resume_action.run = NULL; - resume_action.arg = NULL; - psci_cpu_resume_prepare(&cmd, &resume_action); - psci_unlock(); - - if (ret != PSCI_RET_SUCCESS) - return psci32_return(pf, ret); - - psci_lock(); - psci_set_hierarchy_state(e, e->cpu_state.ancestor, PSCI_STATE_ON); - psci_unlock(); - - psci32_return(pf, PSCI_RET_SUCCESS); -} - -static void psci_cpu_on(struct psci_func *pf) -{ - uint64_t entry; - uint64_t target_mpidr; - uint64_t context_id; - int cpu_state; - int ret; - struct psci_node *e; - struct cpu_action action; - struct psci_cmd cmd = { - .type = PSCI_CMD_ON, - }; - - target_mpidr = psci64_arg(pf, PSCI_PARAM_0); - entry = psci64_arg(pf, PSCI_PARAM_1); - context_id = psci64_arg(pf, PSCI_PARAM_2); - - e = psci_node_lookup(target_mpidr, PSCI_AFFINITY_LEVEL_0); - - if (e == NULL) { - psci32_return(pf, PSCI_RET_INVALID_PARAMETERS); - return; - } - - psci_lock(); - cpu_state = psci_state_locked(e); - - if (cpu_state == PSCI_STATE_ON_PENDING) { - psci32_return(pf, PSCI_RET_ON_PENDING); - psci_unlock(); - return; - } else if (cpu_state == PSCI_STATE_ON) { - psci32_return(pf, PSCI_RET_ALREADY_ON); - psci_unlock(); - return; - } - - cmd.target = e; - action.run = (void *)entry; - action.arg = (void *)context_id; - psci_cpu_on_prepare(&cmd, &action); - - ret = soc_psci_ops.cmd_prepare(&cmd); - - if (ret == PSCI_RET_SUCCESS) - psci_set_hierarchy_state(e, cmd.ancestor, - PSCI_STATE_ON_PENDING); - - psci_unlock(); - - if (ret != PSCI_RET_SUCCESS) - return psci32_return(pf, ret); - - ret = soc_psci_ops.cmd_commit(&cmd); - - if (ret != PSCI_RET_SUCCESS) { - psci_lock(); - psci_set_hierarchy_state(e, cmd.ancestor, PSCI_STATE_OFF); - psci_unlock(); - return psci32_return(pf, ret); - } - - psci32_return(pf, psci_schedule_cpu_on(e)); -} - -static int psci_turn_off_node(struct psci_node *e, int level, - int state_id) -{ - int ret; - struct psci_cmd cmd = { - .type = PSCI_CMD_OFF, - .state_id = state_id, - .target = e, - }; - - psci_lock(); - - cmd.ancestor = psci_find_ancestor(e, level, PSCI_STATE_OFF); - - ret = soc_psci_ops.cmd_prepare(&cmd); - - if (ret == PSCI_RET_SUCCESS) - psci_set_hierarchy_state(e, cmd.ancestor, PSCI_STATE_OFF); - - psci_unlock(); - - if (ret != PSCI_RET_SUCCESS) - return ret; - - gic_disable(); - - /* Should never return. */ - ret = soc_psci_ops.cmd_commit(&cmd); - - /* Adjust ret to be an error. */ - if (ret == PSCI_RET_SUCCESS) - ret = PSCI_RET_INTERNAL_FAILURE; - - /* Turn things back on. */ - psci_lock(); - psci_set_hierarchy_state(e, cmd.ancestor, PSCI_STATE_ON); - psci_unlock(); - - return ret; -} - -int psci_turn_off_self(void) -{ - struct psci_node *e = node_self(); - - if (e == NULL) { - printk(BIOS_ERR, "No PSCI node for MPIDR %llx.\n", - cpu_info()->mpidr); - return PSCI_RET_INTERNAL_FAILURE; - } - - /* -1 state id indicates to SoC to make its own decision for - * internal state when powering off the node. */ - return psci_turn_off_node(e, PSCI_AFFINITY_LEVEL_HIGHEST, -1); -} - -static int psci_handler(struct smc_call *smc) -{ - struct psci_func pf_storage; - struct psci_func *pf = &pf_storage; - - psci_func_init(pf, smc); - - switch (pf->id) { - case PSCI_CPU_SUSPEND64: - psci_cpu_suspend(pf); - break; - case PSCI_CPU_ON64: - psci_cpu_on(pf); - break; - case PSCI_CPU_OFF32: - psci32_return(pf, psci_turn_off_self()); - break; - default: - psci32_return(pf, PSCI_RET_NOT_SUPPORTED); - break; - } - - return 0; -} - -static void psci_link_cpu_info(void *arg) -{ - struct psci_node *e = node_self(); - - if (e == NULL) { - printk(BIOS_ERR, "No PSCI node for MPIDR %llx.\n", - cpu_info()->mpidr); - return; - } - - e->cpu_state.ci = cpu_info(); -} - -static int psci_init_node(struct psci_node *e, - struct psci_node *parent, - int level, uint64_t mpidr) -{ - size_t i; - uint64_t mpidr_inc; - struct psci_node_group *ng; - size_t num_children; - - memset(e, 0, sizeof(*e)); - e->mpidr = mpidr; - psci_set_state_locked(e, PSCI_STATE_OFF); - e->parent = parent; - e->level = level; - - if (level == PSCI_AFFINITY_LEVEL_0) - return 0; - - num_children = soc_psci_ops.children_at_level(level, mpidr); - - if (num_children == 0) - return 0; - - ng = &e->children; - ng->num = num_children; - ng->nodes = malloc(ng->num * sizeof(struct psci_node)); - if (ng->nodes == NULL) { - printk(BIOS_DEBUG, "PSCI: Allocation failure at level %d\n", - level); - return -1; - } - - /* Switch to next level below. */ - level = psci_level_below(level); - mpidr_inc = mpidr_mask(!!(level == PSCI_AFFINITY_LEVEL_3), - !!(level == PSCI_AFFINITY_LEVEL_2), - !!(level == PSCI_AFFINITY_LEVEL_1), - !!(level == PSCI_AFFINITY_LEVEL_0)); - - for (i = 0; i < ng->num; i++) { - struct psci_node *c = &ng->nodes[i]; - - /* Recursively initialize the nodes. */ - if (psci_init_node(c, e, level, mpidr)) - return -1; - mpidr += mpidr_inc; - } - - return 0; -} - -static size_t psci_count_children(struct psci_node *e) -{ - size_t i; - size_t count; - - if (e->level == PSCI_AFFINITY_LEVEL_0) - return 0; - - count = e->children.num; - for (i = 0; i < e->children.num; i++) - count += psci_count_children(&e->children.nodes[i]); - - return count; -} - -static size_t psci_write_nodes(struct psci_node *e, size_t index) -{ - size_t i; - - /* - * Recursively save node pointers in array. Node pointers are - * ordered in ascending mpidr and descending level within same mpidr. - * i.e. each node is saved in depth-first order of the tree. - */ - if (e->level != PSCI_AFFINITY_ROOT) { - psci_nodes[index] = e; - index++; - } - - if (e->level == PSCI_AFFINITY_LEVEL_0) - return index; - - for (i = 0; i < e->children.num; i++) - index = psci_write_nodes(&e->children.nodes[i], index); - - return index; -} - -static int psci_allocate_nodes(void) -{ - int level; - size_t num_children; - uint64_t mpidr; - struct psci_node *e; - - mpidr = 0; - level = PSCI_AFFINITY_ROOT; - - /* Find where the root should start. */ - while (psci_level_below(level) >= PSCI_AFFINITY_LEVEL_0) { - num_children = soc_psci_ops.children_at_level(level, mpidr); - - if (num_children == 0) { - printk(BIOS_ERR, "PSCI: No children at level %d!\n", - level); - return -1; - } - - /* The root starts where the affinity levels branch. */ - if (num_children > 1) - break; - - level = psci_level_below(level); - } - - if (psci_init_node(&psci_root, NULL, level, mpidr)) { - printk(BIOS_ERR, "PSCI init node failure.\n"); - return -1; - } - - num_children = psci_count_children(&psci_root); - /* Count the root node if isn't a fake node. */ - if (psci_root.level != PSCI_AFFINITY_ROOT) - num_children++; - - psci_nodes = malloc(num_children * sizeof(void *)); - psci_num_nodes = num_children; - - if (psci_nodes == NULL) { - printk(BIOS_ERR, "PSCI node pointer array failure.\n"); - return -1; - } - - num_children = psci_write_nodes(&psci_root, 0); - if (num_children != psci_num_nodes) { - printk(BIOS_ERR, "Wrong nodes written: %zd vs %zd.\n", - num_children, psci_num_nodes); - return -1; - } - - /* - * By default all nodes are set to PSCI_STATE_OFF. In order not - * to race with other CPUs turning themselves off set the BSPs - * affinity node to ON. - */ - e = node_self(); - if (e == NULL) { - printk(BIOS_ERR, "No PSCI node for BSP.\n"); - return -1; - } - psci_set_state_locked(e, PSCI_STATE_ON); - - return 0; -} - -void psci_init(uintptr_t cpu_on_entry) -{ - struct cpu_action action = { - .run = &psci_link_cpu_info, - }; - - if (psci_allocate_nodes()) { - printk(BIOS_ERR, "PSCI support not enabled.\n"); - return; - } - - if (arch_run_on_all_cpus_async(&action)) - printk(BIOS_ERR, "Error linking cpu_info to PSCI nodes.\n"); - - /* Register PSCI handlers. */ - if (smc_register_range(PSCI_CPU_SUSPEND32, PSCI_CPU_ON32, - &psci_handler)) - printk(BIOS_ERR, "Couldn't register PSCI handler.\n"); - - if (smc_register_range(PSCI_CPU_SUSPEND64, PSCI_CPU_ON64, - &psci_handler)) - printk(BIOS_ERR, "Couldn't register PSCI handler.\n"); - - /* Inform SoC layer of CPU_ON entry point. */ - psci_soc_init(cpu_on_entry); -} diff --git a/src/arch/arm64/armv8/secmon/secmon.h b/src/arch/arm64/armv8/secmon/secmon.h deleted file mode 100644 index 26ce9fc22f..0000000000 --- a/src/arch/arm64/armv8/secmon/secmon.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 Google Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of - * the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __SECMON_SECMON_H__ -#define __SECMON_SECMON_H__ - -/* - * The secmon_trampoline() switches mode to EL3t, reinitializing both - * EL3t and EL3h stacks. - */ -void secmon_trampoline(void *entry, void *arg); - -/* Wait for action to take place. */ -void secmon_wait_for_action(void); - -#endif /* __SECMON_SECMON_H__ */ diff --git a/src/arch/arm64/armv8/secmon/secmon_init.c b/src/arch/arm64/armv8/secmon/secmon_init.c deleted file mode 100644 index 2ac59fbb5f..0000000000 --- a/src/arch/arm64/armv8/secmon/secmon_init.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2014 Google Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of - * the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <arch/barrier.h> -#include <arch/cache.h> -#include <arch/io.h> -#include <arch/exception.h> -#include <arch/lib_helpers.h> -#include <arch/psci.h> -#include <arch/secmon.h> -#include <arch/smc.h> -#include <arch/startup.h> -#include <console/console.h> -#include <stddef.h> -#include "secmon.h" - -static void secmon_init(struct secmon_params *params, int bsp); - -static void secmon_init_bsp(void *arg) -{ - secmon_init(arg, 1); -} - -static void secmon_init_nonbsp(void *arg) -{ - secmon_init(arg, 0); -} - -/* - * This variable holds entry point for secmon init code. Once the stacks are - * setup by the stage_entry.S, it jumps to c_entry. - */ -void (*c_entry[2])(void *) = { &secmon_init_bsp, &secmon_init_nonbsp }; - -static void cpu_resume(void *unused) -{ - psci_cpu_entry(); -} - -static void cpu_resume_init(void) -{ - /* Change entry points into secmon. */ - c_entry[0] = c_entry[1] = cpu_resume; - dcache_clean_by_mva(&c_entry, sizeof(c_entry)); - - /* Back up state. */ - startup_save_cpu_data(); -} - -static void start_up_cpu(void *arg) -{ - struct secmon_params *params = arg; - struct cpu_action *action; - - if (cpu_is_bsp()) - action = ¶ms->bsp; - else - action = ¶ms->secondary; - - - if (action->run == NULL) - psci_turn_off_self(); - - psci_turn_on_self(action); -} - -static void cpu_init(int bsp) -{ - struct cpu_info *ci = cpu_info(); - - ci->id = smp_processor_id(); - cpu_mark_online(ci); - - if (bsp) - cpu_set_bsp(); -} - -static void wait_for_all_cpus(size_t expected) -{ - while (cpus_online() != expected) - ; -} - -static void secmon_init(struct secmon_params *params, int bsp) -{ - struct cpu_action action = { - .run = start_up_cpu, - .arg = params, - }; - - exception_hwinit(); - cpu_init(bsp); - - if (!cpu_is_bsp()) - secmon_wait_for_action(); - - /* Wait for all CPUs to enter secmon. */ - wait_for_all_cpus(params->online_cpus); - - smc_init(); - psci_init((uintptr_t)arm64_cpu_startup_resume); - - /* Initialize the resume path. */ - cpu_resume_init(); - - /* Make sure all non-BSP CPUs take action before the BSP. */ - arch_run_on_all_cpus_but_self_async(&action); - /* Turn on BSP. */ - start_up_cpu(params); - - printk(BIOS_ERR, "CPU turn on failed for BSP.\n"); - - secmon_wait_for_action(); -} - -void secmon_wait_for_action(void) -{ - arch_cpu_wait_for_action(); -} diff --git a/src/arch/arm64/armv8/secmon/smc.c b/src/arch/arm64/armv8/secmon/smc.c deleted file mode 100644 index 6fa6294933..0000000000 --- a/src/arch/arm64/armv8/secmon/smc.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <string.h> -#include <stdlib.h> -#include <arch/cpu.h> -#include <arch/smc.h> -#include <arch/exception.h> -#include <arch/lib_helpers.h> -#include <console/console.h> - -enum { - /* SMC called from AARCH32 */ - EC_SMC_AARCH32 = 0x13, - /* SMC called from AARCH64 */ - EC_SMC_AARCH64 = 0x17, - - SMC_NUM_RANGES = 8, -}; - -struct smc_range { - uint32_t func_begin; - uint32_t func_end; - int (*handler)(struct smc_call *); -}; - -struct smc_ranges { - size_t used; - struct smc_range handlers[SMC_NUM_RANGES]; -}; - -static struct smc_ranges smc_functions; - -static struct smc_range *smc_handler_by_function(uint32_t fid) -{ - int i; - - for (i = 0; i < smc_functions.used; i++) { - struct smc_range *r = &smc_functions.handlers[i]; - - if (fid >= r->func_begin && fid <= r->func_end) - return r; - } - - return NULL; -} - -int smc_register_range(uint32_t min, uint32_t max, int (*h)(struct smc_call *)) -{ - struct smc_range *r; - - if (smc_functions.used == SMC_NUM_RANGES) - return -1; - - if (min > max) - return -1; - - /* This check isn't exhaustive but it's fairly quick. */ - if (smc_handler_by_function(min) || smc_handler_by_function(max)) - return -1; - - r = &smc_functions.handlers[smc_functions.used]; - r->func_begin = min; - r->func_end = max; - r->handler = h; - smc_functions.used++; - - return 0; -} - -static int smc_cleanup(struct exc_state *state, struct smc_call *smc, int ret) -{ - memcpy(&state->regs.x, &smc->results, sizeof(smc->results)); - - return ret; -} - -static int smc_return_with_error(struct exc_state *state, struct smc_call *smc) -{ - smc32_return(smc, SMC_UNKNOWN_FUNC); - return smc_cleanup(state, smc, EXC_RET_HANDLED); -} - -static int smc_handler(struct exc_state *state, uint64_t vector_id) -{ - struct smc_call smc_storage; - struct smc_call *smc = &smc_storage; - uint32_t exception_class; - uint32_t esr; - struct smc_range *r; - - memcpy(&smc->args, &state->regs.x, sizeof(smc->args)); - memcpy(&smc->results, &state->regs.x, sizeof(smc->results)); - - esr = raw_read_esr_el3(); - exception_class = (esr >> 26) & 0x3f; - - /* No support for SMC calls from AARCH32 */ - if (exception_class == EC_SMC_AARCH32) - return smc_return_with_error(state, smc); - - /* Check to ensure this is an SMC from AARCH64. */ - if (exception_class != EC_SMC_AARCH64) - return EXC_RET_IGNORED; - - /* Ensure immediate value is 0. */ - if ((esr & 0xffff) != 0) - return smc_return_with_error(state, smc); - - r = smc_handler_by_function(smc_function_id(smc)); - - if (r != NULL) { - if (!r->handler(smc)) - return smc_cleanup(state, smc, EXC_RET_HANDLED); - } - - return smc_return_with_error(state, smc); -} - -/* SMC calls can be generated by 32-bit or 64-bit code. */ -static struct exception_handler smc_handler64 = { - .handler = &smc_handler, -}; - -static struct exception_handler smc_handler32 = { - .handler = &smc_handler, -}; - -static void enable_smc(void *arg) -{ - uint32_t scr; - - /* Enable SMC */ - scr = raw_read_scr_el3(); - scr &= ~(SCR_SMC_MASK); - scr |= SCR_SMC_ENABLE; - raw_write_scr_el3(scr); -} - -void smc_init(void) -{ - struct cpu_action action = { - .run = enable_smc, - }; - - arch_run_on_all_cpus_async(&action); - - /* Register SMC handlers. */ - exception_handler_register(EXC_VID_LOW64_SYNC, &smc_handler64); - exception_handler_register(EXC_VID_LOW32_SYNC, &smc_handler32); -} diff --git a/src/arch/arm64/armv8/secmon/trampoline.S b/src/arch/arm64/armv8/secmon/trampoline.S deleted file mode 100644 index 5db904a429..0000000000 --- a/src/arch/arm64/armv8/secmon/trampoline.S +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <arch/asm.h> - -/* - * Call entry(arg) after reinitializing stack state. - * void secmon_trampoline(void *entry, void *arg); - */ -ENTRY(secmon_trampoline) - mov x22, x0 /* x22 = function pointer */ - mov x23, x1 /* x23 = argument */ - bl smp_processor_id /* x0 = cpu */ - mov x24, x0 - - /* Set the exception stack for this cpu. */ - bl cpu_get_exception_stack - msr SPSel, #1 - isb - mov sp, x0 - - /* Have stack pointer use SP_EL0. */ - msr SPSel, #0 - isb - - /* Set stack for this cpu. */ - mov x0, x24 /* x0 = cpu */ - bl cpu_get_stack - mov sp, x0 - - /* Call the function with specified argument. */ - mov x1, x22 - mov x0, x23 - br x1 -ENDPROC(secmon_trampoline) diff --git a/src/arch/arm64/armv8/secmon_loader.c b/src/arch/arm64/armv8/secmon_loader.c deleted file mode 100644 index 946ca0f9e9..0000000000 --- a/src/arch/arm64/armv8/secmon_loader.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2014 Google Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of - * the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * secmon_loader.c: Responsible for loading the rmodule, providing entry point - * and parameter location for the rmodule. - */ - -#include <arch/cache.h> -#include <arch/lib_helpers.h> -#include <arch/secmon.h> -#include <arch/spintable.h> -#include <arch/stages.h> -#include <console/console.h> -#include <rmodule.h> -#include <string.h> - -/* SECMON entry point encoded as an rmodule */ -extern unsigned char _binary_secmon_start[]; - -typedef void (*secmon_entry_t)(struct secmon_params *); - -void __attribute__((weak)) soc_get_secmon_base_size(uint64_t *secmon_base, size_t *secmon_size) -{ - /* Default weak implementation initializes to 0 */ - *secmon_base = 0; - *secmon_size = 0; -} - -static secmon_entry_t secmon_load_rmodule(void) -{ - struct rmodule secmon_mod; - uint64_t secmon_base; - size_t secmon_size; - - /* Get base address and size of the area available for secure monitor - * rmodule. - */ - soc_get_secmon_base_size(&secmon_base, &secmon_size); - - if ((secmon_base == 0) || (secmon_size == 0)) { - printk(BIOS_ERR, "ARM64: secmon_base / secmon_size invalid\n"); - return NULL; - } - - printk(BIOS_DEBUG,"secmon_base:%lx,secmon_size:%lx\n", - (unsigned long)secmon_base, (unsigned long)secmon_size); - - /* Fail if can't parse secmon module */ - if (rmodule_parse(&_binary_secmon_start, &secmon_mod)) { - printk(BIOS_ERR, "ARM64: secmon_mod not found\n"); - return NULL; - } - - /* Load rmodule at secmon_base */ - if (rmodule_load((void *)secmon_base, &secmon_mod)) { - printk(BIOS_ERR, "ARM64:secmon_mod cannot load\n"); - return NULL; - } - - /* Identify the entry point for secure monitor */ - return rmodule_entry(&secmon_mod); -} - -struct secmon_runit { - secmon_entry_t entry; - struct secmon_params params; -}; - -static void secmon_start(void *arg) -{ - uint32_t scr; - secmon_entry_t entry; - struct secmon_params *p; - struct secmon_runit *r = arg; - - entry = r->entry; - p = &r->params; - - /* Obtain secondary entry point for non-BSP CPUs. */ - if (!cpu_is_bsp()) - entry = secondary_entry_point(entry); - - printk(BIOS_DEBUG, "CPU%x entering secure monitor %p.\n", - cpu_info()->id, entry); - - /* We want to enforce the following policies: - * NS bit is set for lower EL - */ - scr = raw_read_scr_el3(); - scr |= SCR_NS; - raw_write_scr_el3(scr); - - /* Invalidate instruction cache. Necessary for non-BSP. */ - icache_invalidate_all(); - entry(p); -} - -static void fill_secmon_params(struct secmon_params *p, - void (*bsp_entry)(void *), void *bsp_arg) -{ - const struct spintable_attributes *spin_attrs; - - memset(p, 0, sizeof(*p)); - - p->online_cpus = cpus_online(); - - spin_attrs = spintable_get_attributes(); - - if (spin_attrs != NULL) { - p->secondary.run = spin_attrs->entry; - p->secondary.arg = spin_attrs->addr; - } - - p->bsp.run = bsp_entry; - p->bsp.arg = bsp_arg; -} - -void secmon_run(void (*entry)(void *), void *cb_tables) -{ - static struct secmon_runit runit; - struct cpu_action action = { - .run = secmon_start, - .arg = &runit, - }; - - printk(BIOS_SPEW, "payload jump @ %p\n", entry); - - if (get_current_el() != EL3) { - printk(BIOS_DEBUG, "Secmon Error: Can only be loaded in EL3\n"); - return; - } - - runit.entry = secmon_load_rmodule(); - - if (runit.entry == NULL) - die("ARM64 Error: secmon load error"); - - printk(BIOS_DEBUG, "ARM64: Loaded the el3 monitor...jumping to %p\n", - runit.entry); - - fill_secmon_params(&runit.params, entry, cb_tables); - - arch_run_on_all_cpus_but_self_async(&action); - secmon_start(&runit); -} |