Files
lk/platform/bcm28xx/platform.c
Travis Geiselbrecht e47183725d [arch][arm64] move secondary cpu entry point to separate function
- Make the secondary entry point be logically separate function, though
  declared in the same file.
- Add a trick where the kernel base + 4 is the secondary entry point.
  Not really useful except makes it easy to compute the offset
  elsewhere.
- Changed the entry point to arm64_reset and move _start to the linker
  script, which is what most other arches do.
- While was in the linker script, make sure the text segment is aligned
  on MAXPAGESIZE, though doesn't make any real difference currently.
- Generally clean up the assembly in start.S with newer macros from
  Fuchsia, and avoid using ldr X, =value as much as possible.
- Fix and make sure arm64 can build and run with WITH_SMP set to false.
  Add a new no-smp project to test this.

Note this will likely break systems where all of the cpus enter the
kernel simultaneously, which we can fix if that becomes an issue.
Secondary code now completely assumes the cpu number is passed in x0.
This can be emulated with platform specific trampoline code if it needs
to that then just directs into the the secondary entry point, instead of
trying to make the arch code have to deal with all cases.
2025-10-12 19:47:33 -07:00

221 lines
5.4 KiB
C

/*
* Copyright (c) 2015 Travis Geiselbrecht
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#include <lk/reg.h>
#include <lk/err.h>
#include <lk/debug.h>
#include <lk/trace.h>
#include <dev/uart.h>
#include <arch.h>
#include <lk/init.h>
#include <kernel/vm.h>
#include <kernel/spinlock.h>
#include <dev/timer/arm_generic.h>
#include <platform.h>
#include <platform/interrupts.h>
#include <platform/bcm28xx.h>
#if BCM2836
#include <arch/arm.h>
#include <arch/arm/mmu.h>
/* initial memory mappings. parsed by start.S */
struct mmu_initial_mapping mmu_initial_mappings[] = {
/* 1GB of sdram space */
{
.phys = SDRAM_BASE,
.virt = KERNEL_BASE,
.size = MEMSIZE,
.flags = 0,
.name = "memory"
},
/* peripherals */
{
.phys = BCM_PERIPH_BASE_PHYS,
.virt = BCM_PERIPH_BASE_VIRT,
.size = BCM_PERIPH_SIZE,
.flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
.name = "bcm peripherals"
},
/* identity map to let the boot code run */
{
.phys = SDRAM_BASE,
.virt = SDRAM_BASE,
.size = 16*1024*1024,
.flags = MMU_INITIAL_MAPPING_TEMPORARY
},
/* null entry to terminate the list */
{ 0 }
};
extern void arm_reset(void);
#define DEBUG_UART 0
#elif BCM2837
#include <libfdt.h>
#include <arch/arm64.h>
#include <arch/arm64/mmu.h>
#include <platform/mailbox.h>
/* initial memory mappings. parsed by start.S */
struct mmu_initial_mapping mmu_initial_mappings[] = {
/* 1GB of sdram space */
{
.phys = SDRAM_BASE,
.virt = KERNEL_BASE,
.size = MEMORY_APERTURE_SIZE,
.flags = 0,
.name = "memory"
},
/* peripherals */
{
.phys = BCM_PERIPH_BASE_PHYS,
.virt = BCM_PERIPH_BASE_VIRT,
.size = BCM_PERIPH_SIZE,
.flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
.name = "bcm peripherals"
},
/* null entry to terminate the list */
{ 0 }
};
#define DEBUG_UART 1
extern void arm64_reset(void);
#else
#error Unknown BCM28XX Variant
#endif
extern void intc_init(void);
static pmm_arena_t arena = {
.name = "sdram",
.base = SDRAM_BASE,
.size = MEMSIZE,
.flags = PMM_ARENA_FLAG_KMAP,
};
void platform_init_mmu_mappings(void) {
}
void platform_early_init(void) {
uart_init_early();
intc_init();
#if BCM2837
arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 0);
/* look for a flattened device tree just before the kernel */
const void *fdt = (void *)KERNEL_BASE;
int err = fdt_check_header(fdt);
if (err >= 0) {
/* walk the nodes, looking for 'memory' */
int depth = 0;
int offset = 0;
for (;;) {
offset = fdt_next_node(fdt, offset, &depth);
if (offset < 0)
break;
/* get the name */
const char *name = fdt_get_name(fdt, offset, NULL);
if (!name)
continue;
/* look for the 'memory' property */
if (strcmp(name, "memory") == 0) {
printf("Found memory in fdt\n");
int lenp;
const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp);
if (prop_ptr && lenp == 0x10) {
/* we're looking at a memory descriptor */
//uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr);
uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1));
/* trim size on certain platforms */
#if ARCH_ARM
if (len > 1024*1024*1024U) {
len = 1024*1024*1024; /* only use the first 1GB on ARM32 */
printf("trimming memory to 1GB\n");
}
#endif
/* set the size in the pmm arena */
arena.size = len;
}
}
}
}
#elif BCM2836
arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 1000000);
#else
#error Unknown BCM28XX Variant
#endif
/* add the main memory arena */
pmm_add_arena(&arena);
#if BCM2837
/* reserve the first 64k of ram, which should be holding the fdt */
struct list_node list = LIST_INITIAL_VALUE(list);
pmm_alloc_range(MEMBASE, 0x80000 / PAGE_SIZE, &list);
#endif
#if WITH_SMP
#if BCM2837
// Secondary entry point for arm64 is 4 bytes into the kernel image
uintptr_t sec_entry = (uintptr_t)(&arm64_reset) - KERNEL_ASPACE_BASE + 4;
unsigned long long *spin_table = (void *)(KERNEL_ASPACE_BASE + 0xd8);
for (uint i = 1; i <= 3; i++) {
spin_table[i] = sec_entry;
__asm__ __volatile__ ("" : : : "memory");
arch_clean_cache_range(0xffff000000000000,256);
__asm__ __volatile__("sev");
}
#else
/* start the other cpus */
uintptr_t sec_entry = (uintptr_t)&arm_reset;
sec_entry -= (KERNEL_BASE - MEMBASE);
for (uint i = 1; i <= 3; i++) {
*REG32(ARM_LOCAL_BASE + 0x8c + 0x10 * i) = sec_entry;
}
#endif
#endif
}
void platform_init(void) {
uart_init();
#if BCM2837
init_framebuffer();
#endif
}
void platform_dputc(char c) {
if (c == '\n')
uart_putc(DEBUG_UART, '\r');
uart_putc(DEBUG_UART, c);
}
int platform_dgetc(char *c, bool wait) {
int ret = uart_getc(DEBUG_UART, wait);
if (ret == -1)
return -1;
*c = ret;
return 0;
}