1/**
2 * \file
3 * \brief Implementation of the BF ARMv7 boot protocol.
4 */
5
6/*
7 * Copyright (c) 2016, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <kernel.h>
16
17#include <assert.h>
18#include <boot_protocol.h>
19#include <cp15.h>
20#include <paging_kernel_arch.h>
21#include <arch/arm/platform.h>
22#include <startup_arch.h>
23
24/*
25 * \brief Boot an ARM APP core
26 *
27 * \param core_id   MPID of the core to try booting
28 * \param entry     Entry address for new kernel in the destination
29 *                  architecture's lvaddr_t
30 *
31 * \returns Zero on successful boot, non-zero (error code) on failure
32 */
33errval_t boot_aps(hwid_t target, genpaddr_t gen_entry, genpaddr_t context)
34{
35
36    assert(paging_mmu_enabled());
37
38    /* XXX - we're abusing the gen_entry pointer here.  Change the interface
39     * to make this arch-specific. */
40    lpaddr_t new_core_data_ptr= (lpaddr_t)gen_entry;
41
42    /* This mailbox is in the boot driver's BSS. */
43    struct armv7_boot_record *br=
44        (struct armv7_boot_record *)core_data->target_bootrecs;
45
46    /* Acquire the lock on the boot record. */
47    spinlock_acquire(&br->lock);
48
49    /* Pass the core data pointer. */
50    br->core_data= new_core_data_ptr;
51
52    /* Clear the completion notification. */
53    br->done= 0;
54
55    /* Flag which core should boot. */
56    /* XXX - this will only work for single-cluster systems, whose MPID fits
57     * entirely within the low 8 bits.  Make core IDs bigger! */
58    br->target_mpid= target;
59
60    /* The boot driver will read this value with its MMU and caches disabled,
61     * so we need to make sure it's visible. */
62    dmb(); isb();
63    clean_invalidate_to_poc(&br->core_data);
64    clean_invalidate_to_poc(&br->done);
65    clean_invalidate_to_poc(&br->target_mpid);
66
67    /* We need to ensure that the clean has finished before we wake them. */
68    dmb(); isb();
69
70    /* Wake all sleeping cores. */
71    sev();
72
73    /* The target core will let us know that it's exited the boot driver by
74     * setting done to one *with its MMU, and hence coherency, enabled*. */
75    volatile uint32_t *mailbox= &br->done;
76    while(!*mailbox) wfe();
77
78    /* Release the lock on the boot record. */
79    spinlock_release(&br->lock);
80
81    return 0;
82}
83
84void
85platform_notify_bsp(uint32_t *mailbox) {
86    assert(paging_mmu_enabled());
87
88    /* Set the flag to one (this is br->done, above). */
89    *mailbox= 1;
90
91    /* Make sure that the write has completed. */
92    dmb(); isb();
93
94    /* Wake the booting core. */
95    sev();
96}
97