diff --git a/Config.uk b/Config.uk new file mode 100644 index 0000000000000000000000000000000000000000..42d63fc1b993fa1ebe4d0124360e80b1450241e0 --- /dev/null +++ b/Config.uk @@ -0,0 +1,33 @@ +menuconfig PLAT_RASPI + bool "Raspberry Pi 3B+" + default n + depends on ARCH_ARM_64 + select HAVE_FDT + select LIBUKOFW + select HAVE_INTCTLR + select LIBUKINTCTLR_BCM_INTC + select LIBUKINTCTLR_BCM2836_INTC + select LIBUKTTY_PL011 + select ARM_GENERIC_TIMER + help + Create a Unikraft image that runs as a Raspberry Pi 3B+ + +if (PLAT_RASPI) + +menu "Profiling" +config RASPI_WATERMARK_STACK + bool "Watermark Stack" + default n + depends on ARCH_ARM_64 +endmenu + +config RAM_BASE_ADDR + hex + prompt "Starting address of kernel stored in ram" + default 0x80000 + +config PLATRASPI_TEST + bool "Enable unit tests" + default n + +endif diff --git a/Linker.uk b/Linker.uk new file mode 100644 index 0000000000000000000000000000000000000000..15a1dfd76888a34bdeafa3c5514f9448484adcff --- /dev/null +++ b/Linker.uk @@ -0,0 +1,62 @@ +RASPI_LDFLAGS-y += -Wl,-m,aarch64elf +ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) +RASPI_LDFLAGS-y += -mfix-cortex-a53-843419 +endif + + +## +## Link image +## +RASPI_IMAGE := $(BUILD_DIR)/$(CONFIG_UK_NAME)_raspi-$(CONFIG_UK_ARCH) +RASPI_ELF_IMAGE := $(RASPI_IMAGE).elf + +RASPI_LD_SCRIPT_FLAGS := $(addprefix -Wl$(comma)-dT$(comma),\ + $(UK_PLAT_RASPI_DEF_LDS)) +RASPI_LD_SCRIPT_FLAGS += $(addprefix -Wl$(comma)-T$(comma),\ + $(LIBRASPIPLAT_DEF_LDS) $(EXTRA_LD_SCRIPT-y)) + +$(RASPI_ELF_IMAGE): $(RASPI_ALIBS) $(RASPI_ALIBS-y) $(RASPI_OLIBS) $(RASPI_OLIBS-y) \ + $(UK_ALIBS) $(UK_ALIBS-y) $(UK_OLIBS) $(UK_OLIBS-y) + $(call build_cmd,LD,,$(RASPI_IMAGE).ld.o,\ + $(LD) -r $(LIBLDFLAGS) $(LIBLDFLAGS-y) \ + $(RASPI_LDFLAGS) $(RASPI_LDFLAGS-y) \ + $(RASPI_OLIBS) $(RASPI_OLIBS-y) \ + $(UK_OLIBS) $(UK_OLIBS-y) \ + -lgcc \ + -Wl$(comma)--start-group \ + $(RASPI_ALIBS) $(RASPI_ALIBS-y) \ + $(UK_ALIBS) $(UK_ALIBS-y) \ + -Wl$(comma)--end-group \ + -o $(RASPI_IMAGE).ld.o) + $(call build_cmd,OBJCOPY,,$(RASPI_IMAGE).o,\ + $(OBJCOPY) -w -G _libraspiplat_entry \ + $(RASPI_IMAGE).ld.o $(RASPI_IMAGE).o) + $(call build_cmd,LD,,$@,\ + $(LD) $(LDFLAGS) $(LDFLAGS-y) \ + $(RASPI_LDFLAGS) $(RASPI_LDFLAGS-y) \ + $(RASPI_LD_SCRIPT_FLAGS) \ + $(RASPI_IMAGE).o -o $@) + $(call build_bootinfo,$@) + +$(RASPI_IMAGE): $(RASPI_IMAGE).elf + $(call build_cmd,SCSTRIP,,$@,\ + $(STRIP) -s \ + $(SECT_STRIP_FLAGS) $(SECT_STRIP_FLAGS-y) \ + $< -o $@ 2>&1 | \ + { grep -v "Empty loadable segment detected" || true; }) + $(call build_cmd,OBJCOPY,,$(RASPI_IMAGE).img,\ + $(OBJCOPY) -O binary $(RASPI_ELF_IMAGE) $(BUILD_DIR)/kernel8.img) + +# register images to the build +ifeq ($(CONFIG_PLAT_RASPI),y) +UK_DEBUG_IMAGES-y += $(RASPI_ELF_IMAGE) +UK_IMAGES-y += $(RASPI_IMAGE) +endif + +# ...for cleaning: +LIBRASPIPLAT_CLEAN += $(call build_clean,$(RASPI_IMAGE).o) +LIBRASPIPLAT_CLEAN += $(call build_clean,$(RASPI_IMAGE).ld.o) +LIBRASPIPLAT_CLEAN += $(call build_clean,$(RASPI_IMAGE).elf) +LIBRASPIPLAT_CLEAN += $(call build_clean,$(RASPI_IMAGE).img) +LIBRASPIPLAT_CLEAN += $(call build_clean,$(RASPI_ELF_IMAGE).bootinfo) +LIBRASPIPLAT_CLEAN += $(call build_clean,$(BUILD_DIR)/kernel8.img) diff --git a/Makefile.uk b/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..e35e61ebf27da1c259b0a796ef5a90e000e6baf0 --- /dev/null +++ b/Makefile.uk @@ -0,0 +1,81 @@ +## +## RASPI platform registration +## +$(eval $(call addplat_s,raspi,$(CONFIG_PLAT_RASPI))) + +## +## RASPI platform library registration +## +$(eval $(call addplatlib,raspi,libraspiplat)) + +## +## Platform library definitions +## +LIBRASPIPLAT_ASINCLUDES-y += -I$(LIBRASPIPLAT_BASE)/include +LIBRASPIPLAT_ASINCLUDES-y += -I$(UK_PLAT_COMMON_BASE)/include +LIBRASPIPLAT_CINCLUDES-y += -I$(LIBRASPIPLAT_BASE)/include +LIBRASPIPLAT_CINCLUDES-y += -I$(UK_PLAT_COMMON_BASE)/include +LIBRASPIPLAT_CINCLUDES-y += -I$(UK_PLAT_DRIVERS_BASE)/include + +LIBRASPIPLAT_ASFLAGS += -DRASPIPLAT +LIBRASPIPLAT_CFLAGS += -DRASPIPLAT +LIBRASPIPLAT_CXXFLAGS += -DRASPIPLAT + +LIBRASPIPLAT_ASFLAGS-y += -DUK_USE_SECTION_SEGMENTS +LIBRASPIPLAT_CFLAGS-y += -DUK_USE_SECTION_SEGMENTS +LIBRASPIPLAT_CXXFLAGS-y += -DUK_USE_SECTION_SEGMENTS + +## +## Default Linker script +UK_PLAT_RASPI_DEF_LDS := $(UK_PLAT_COMMON_BASE)/arm/link64.lds.S + +## +## Architecture library definitions +## +ifeq ($(findstring y,$(CONFIG_RASPI_PRINTF_SERIAL_CONSOLE) $(CONFIG_RASPI_KERNEL_SERIAL_CONSOLE) $(CONFIG_RASPI_DEBUG_SERIAL_CONSOLE)),y) +## TODO: Check if both implementations are actually doing the same thing +#LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/pl011.c|common +endif +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/cpu_native.c|common +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/cache64.S|common +#LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/psci_arm64.S|common +#LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/traps.c|common +ifneq ($(CONFIG_HAVE_SYSTICK),y) +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/generic_timer.c|common +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/time.c|common +endif +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/lcpu.c|arm64_common +LIBRASPIPLAT_SRCS-y += $(UK_PLAT_COMMON_BASE)/lcpu.c|common +LIBRASPIPLAT_SRCS-y += $(UK_PLAT_COMMON_BASE)/memory.c|common +LIBRASPIPLAT_SRCS-y += $(UK_PLAT_COMMON_BASE)/tls.c|common +ifeq ($(CONFIG_ENFORCE_W_XOR_X),y) +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/w_xor_x.c|common +endif +LIBRASPIPLAT_SRCS-$(CONFIG_FPSIMD) += $(UK_PLAT_COMMON_BASE)/arm/fp_arm64.c|isr +ifeq ($(CONFIG_PAGING),y) +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/paging.c|isr +endif + +LIBRASPIPLAT_SRCS-y += $(UK_PLAT_COMMON_BASE)/bootinfo.c|common +LIBRASPIPLAT_SRCS-$(CONFIG_LIBFDT) += $(UK_PLAT_COMMON_BASE)/bootinfo_fdt.c|common +LIBRASPIPLAT_SRCS-y += $(UK_PLAT_COMMON_BASE)/bootinfo.lds.S|common + +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/start.S +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/mm.S +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/console.c +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/io.c +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/lcpu.c +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/mbox.c +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/gpio.c +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/memory.c +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/setup.c +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/shutdown.c +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/exceptions64.S|isr +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBRASPIPLAT_BASE)/mmu.S|isr +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBRASPIPLAT_BASE)/raspi_bpt64.S|arm +LIBRASPIPLAT_SRCS-y += $(UK_PLAT_RASPI_DEF_LDS) + +LIBRASPIPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/traps_arm64.c|isr +ifneq ($(filter y,$(CONFIG_PLATRASPI_TEST) $(CONFIG_LIBUKTEST_ALL)),) +LIBRASPIPLAT_SRCS-y += $(LIBRASPIPLAT_BASE)/tests/test_paging.c +endif diff --git a/console.c b/console.c new file mode 100644 index 0000000000000000000000000000000000000000..5bebb3cb812e5df6cc339b47c353a03227100b08 --- /dev/null +++ b/console.c @@ -0,0 +1,46 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void _libraspiplat_init_console(void *dtb) +{ + PL011_REG_WRITE(REG_UARTCR_OFFSET, 0); + /* set up clock for consistent divisor values */ + /* ARM to VedioCore*/ + mbox_msg_create(9, 4*9, MBOX_REQUEST, MBOX_TAG_SETCLKRATE, + 12, 8, 2, 4000000, 0, MBOX_TAG_LAST); + + if (mbox_call(MBOX_CH_PROP) != 1) { + UK_CRASH("mbox call failed!\n"); + return; + } + + if (map_uart_to_gpio()) { + UK_CRASH("gpio mapping failed!\n"); + return; + } + + pl011_console_init(dtb); +} diff --git a/gpio.c b/gpio.c new file mode 100644 index 0000000000000000000000000000000000000000..8c04ff849270d9eb77dbf275e44d7010870de748 --- /dev/null +++ b/gpio.c @@ -0,0 +1,78 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +/* Macros to access gpio Registers with base address 'gpio_mem_addr'*/ +#define GPIO_REG(r) ((uint32_t *)(gpio_mem_addr + (r))) +#define GPIO_REG_READ(r) ioreg_read32(GPIO_REG(r)) +#define GPIO_REG_WRITE(r, v) ioreg_write32(GPIO_REG(r), v) + +/*store base address of gpio*/ +static uint64_t gpio_mem_addr; +static uint8_t gpio_initialized; + +static void wait_cycles(unsigned int n) +{ + if (n) { + while (n--) + asm volatile("nop"); + } +} + +void _libraspiplat_init_gpio(void *fdtp) +{ + int gpio_offset, rc; + uint64_t addr, size; + + gpio_offset = fdt_node_offset_by_compatible(fdtp, -1, + "brcm,bcm2835-gpio"); + + if (gpio_offset < 0) + UK_CRASH("No gpio device found!\n"); + + rc = fdt_get_address(fdtp, gpio_offset, 0, &addr, &size); + if (rc < 0) + UK_CRASH("Could not find gpio address!\n"); + + gpio_mem_addr = addr; + gpio_initialized = 1; +} + +int map_uart_to_gpio(void) +{ + if (!gpio_initialized) { + UK_CRASH("GPIO not initialized!\n"); + return -1; + } + register uint32_t r; + /* map UART0 to GPIO pins */ + r = GPIO_REG_READ(GPFSEL1); + r &= ~((7 << 12) | (7 << 15)); // gpio14, gpio15 + r |= (4 << 12) | (4 << 15); // alt0 + GPIO_REG_WRITE(GPFSEL1, r); + GPIO_REG_WRITE(GPPUD, 0); + wait_cycles(150); + GPIO_REG_WRITE(GPPUDCLK0, (1 << 14) | (1 << 15)); + wait_cycles(150); + GPIO_REG_WRITE(GPPUDCLK0, 0); + return 0; +} + diff --git a/include/raspi/console.h b/include/raspi/console.h new file mode 100644 index 0000000000000000000000000000000000000000..a3510c807d1f06f4c8289ddfa1bd4c8b8b4ebb18 --- /dev/null +++ b/include/raspi/console.h @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __RASPI_CONSOLE_H__ +#define __RASPI_CONSOLE_H__ + +void _libraspiplat_init_console(void *dtb); + +#endif /* __RASPI_CONSOLE_H__ */ diff --git a/include/raspi/gpio.h b/include/raspi/gpio.h new file mode 100644 index 0000000000000000000000000000000000000000..0472ea8cf78c54fabccf3ea216fbfafed51f2ed8 --- /dev/null +++ b/include/raspi/gpio.h @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __RASPI_GPIO_H__ +#define __RASPI_GPIO_H__ + +#include +#include + +/*GPIO Register offset*/ +#define GPFSEL0 0x0 +#define GPFSEL1 0x04 +#define GPFSEL2 0x08 +#define GPFSEL3 0x0C +#define GPFSEL4 0x10 +#define GPFSEL5 0x14 +#define GPSET0 0x1C +#define GPSET1 0x20 +#define GPCLR0 0x28 +#define GPLEV0 0x34 +#define GPLEV1 0x38 +#define GPEDS0 0x40 +#define GPEDS1 0x44 +#define GPHEN0 0x64 +#define GPHEN1 0x68 +#define GPPUD 0x94 +#define GPPUDCLK0 0x98 +#define GPPUDCLK1 0x9C + +void _libraspiplat_init_gpio(void *fdtp); + +/** + * @brief map uart0 to gpio14/15 + * + * @return -1: gpio not initialized, mapping error + * 0: mapping success + */ +int map_uart_to_gpio(void); +#endif /* __RASPI_GPIO_H__ */ diff --git a/include/raspi/mbox.h b/include/raspi/mbox.h new file mode 100644 index 0000000000000000000000000000000000000000..b609d29d17a00eb5bcacee4ccdc4b78c1dfc170b --- /dev/null +++ b/include/raspi/mbox.h @@ -0,0 +1,100 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __RASPI_MBOX_H__ +#define __RASPI_MBOX_H__ + +/* A properly aligned buffer */ +#define MBOX_BUFFER_LENGTH 36 + +#define MBOX_REQUEST 0 + +/* Channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* Tags */ +#define MBOX_TAG_SETPOWER 0x28001 +#define MBOX_TAG_SETCLKRATE 0x38002 +#define MBOX_TAG_LAST 0 + +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 +#define MBOX_RESPONSE_ERROR 0x80000001 +#define MBOX_RESPONSE_NORMAL 0x80000000 + +/** + * The following table shows the register offsets for the different mailboxes. + * Mailbox Read/Write Peek Sender Status Config + * 0 0x00 0x10 0x14 0x18 0x1c + * 1 0x20 + */ +#define MBOX_READ 0x0 +#define MBOX_POLL 0x10 +#define MBOX_SENDER 0x14 +#define MBOX_STATUS 0x18 +#define MBOX_CONFIG 0x1C +#define MBOX_WRITE 0x20 + +/** + * @brief Make a mailbox call. + * + * @param ch channel index of raspi, only 8 work. + * + * @return -1: Mailbox not initialized, error + * 0: recv wrong response code 0x80000001 + * 1: recv right response code 0x80000000 + */ +int mbox_call(unsigned char ch); + +/** + * @brief Parsing .dtb file to get base address of raspi mailbox reg. + * + * @param fdtp address of .dtb file. + * + */ +void _libraspiplat_init_mbox(void *fdtp); + +/** + * @brief Creates a message to be sent to the VideoCore (VC) GPU. + * + * @param paras_num Number of elements to be passed to the mbox array. + * @param ... Variable number of parameters + * representing specific elements for the mbox array. + * - The second parameter specifies the size of the data to be sent. + * - The third parameter is either MBOX_REQUEST or MBOX_RESPONSE. + * - The fourth parameter represents the specific command. + * - Followed by specific parameters tagged accordingly. + * - The last parameter is always fixed to MBOX_TAG_LAST (0). + * + * @return No explicit return value. The message is created in the mbox array. + * @note For specific msg format details, please refer to + * the [Mailbox Property Interface] + * (https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface) + */ +void mbox_msg_create(int paras_num, ...); + +extern void clean_and_invalidate_dcache_range( + unsigned long addr, unsigned long length); + +#endif /* __RASPI_MBOX_H__ */ diff --git a/include/raspi/setup.h b/include/raspi/setup.h new file mode 100644 index 0000000000000000000000000000000000000000..0e9a8613d3812f9d636ee376b0753a56c55c8375 --- /dev/null +++ b/include/raspi/setup.h @@ -0,0 +1,28 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __RASPI_SETUP_H__ +#define __RASPI_SETUP_H__ + +#include + +uint64_t _libraspiplat_get_reset_time(void); +uint64_t _libraspiplat_get_hardware_init_time(void); + +uint64_t get_sp ( void ); +uint64_t get_sp_start ( void ); + +#endif /* __RASPI_SETUP_H__ */ diff --git a/include/raspi/sysregs.h b/include/raspi/sysregs.h new file mode 100644 index 0000000000000000000000000000000000000000..f7d9c75dfa175bcdbecb23907b518f131b34a9cf --- /dev/null +++ b/include/raspi/sysregs.h @@ -0,0 +1,72 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __RASPI_SYSREGS_H__ +#define __RASPI_SYSREGS_H__ + +// *************************************** +// SCTLR_EL1, System Control Register (EL1), Page 2654 of AArch64-Reference-Manual. +// *************************************** +#define SCTLR_EL1_WFE_NORMAL (1 << 18) +#define SCTLR_EL1_WFI_NORMAL (1 << 16) +#define SCTLR_EL1_MMU_ENABLED (1 << 0) + +// enable I-Cache(bit 12) and D-Cache(bit 2) +#define SCTLR_EL1_CACHE_ENABLED ((1 << 2) | (1 << 12)) + +#define SCTLR_EL1_VALUE_MMU_DISABLED (SCTLR_EL1_WFE_NORMAL | SCTLR_EL1_WFI_NORMAL) +#define SCTLR_EL1_VALUE_MMU_ENABLED (SCTLR_EL1_WFE_NORMAL | SCTLR_EL1_WFI_NORMAL | SCTLR_EL1_MMU_ENABLED) +#define SCTLR_EL1_VALUE_MMU_CACHE_ENABLED \ + (SCTLR_EL1_VALUE_MMU_ENABLED | SCTLR_EL1_CACHE_ENABLED) +#define SCTLR_EL2_VALUE (0) + +// *************************************** +// HCR_EL2, Hypervisor Configuration Register (EL2), Page 2487 of AArch64-Reference-Manual. +// *************************************** + +#define HCR_EL2_RW (1 << 31) +#define HCR_EL2_IMO (1 << 4) +#define HCR_EL2_SWIO (1 << 1) +#define HCR_EL2_VALUE (HCR_EL2_RW) + +// *************************************** +// SCR_EL3, Secure Configuration Register (EL3), Page 2648 of AArch64-Reference-Manual. +// *************************************** + +#define CPACR_EL1_TTA (1 << 28) +#define CPACR_EL1_FPEN_TRAP_EL0_EL1 (0 << 20) +#define CPACR_EL1_FPEN_TRAP_EL0 (1 << 20) +#define CPACR_EL1_FPEN_TRAP_NONE (3 << 20) +#define CPACR_EL1_VALUE (CPACR_EL1_FPEN_TRAP_NONE) + +// *************************************** +// CPACR_EL1, Architectural Feature Access Control Register. +// *************************************** + +#define SCR_RESERVED (3 << 4) +#define SCR_RW (1 << 10) +#define SCR_NS (1 << 0) +#define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS) + +// *************************************** +// SPSR_EL3, Saved Program Status Register (EL3) Page 389 of AArch64-Reference-Manual. +// *************************************** + +#define SPSR_MASK_ALL (7 << 6) +#define SPSR_ELxh (5 << 0) +#define SPSR_EL2_VALUE (SPSR_MASK_ALL | SPSR_ELxh) + +#endif /* __RASPI_SYSREGS_H__ */ diff --git a/io.c b/io.c new file mode 100644 index 0000000000000000000000000000000000000000..858e7c149938b244bfb91e3fb94898c3a4fc8cca --- /dev/null +++ b/io.c @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +/** + * TODO: + * For our Raspberry Pi platform, the guest virtual address == guest physical address. + * We may have to reconsider this implementation when condition changes. + */ +__paddr_t ukplat_virt_to_phys(const volatile void *address) +{ + return (__paddr_t)address; +} diff --git a/lcpu.c b/lcpu.c new file mode 100644 index 0000000000000000000000000000000000000000..6533133642d7892cabfcfd4318c002f560c08eec --- /dev/null +++ b/lcpu.c @@ -0,0 +1,66 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +void ukplat_lcpu_enable_irq(void) +{ + local_irq_enable(); +} + +void ukplat_lcpu_disable_irq(void) +{ + local_irq_disable(); +} + +void ukplat_lcpu_halt_irq(void) +{ + UK_ASSERT(ukplat_lcpu_irqs_disabled()); + + /* Note: If priority masking is enabled + * interrupts need to be unmasked in the GIC. + * + * See Linux `cpu_do_idle(void)` implementation + */ + halt(); +} + +unsigned long ukplat_lcpu_save_irqf(void) +{ + unsigned long flags; + + local_irq_save(flags); + + return flags; +} + +void ukplat_lcpu_restore_irqf(unsigned long flags) +{ + local_irq_restore(flags); +} + +int ukplat_lcpu_irqs_disabled(void) +{ + return irqs_disabled(); +} + +void ukplat_lcpu_irqs_handle_pending(void) +{ + // TODO +} diff --git a/mbox.c b/mbox.c new file mode 100644 index 0000000000000000000000000000000000000000..5e806cca4d6e52e0e55d3df79402aff2af8cad99 --- /dev/null +++ b/mbox.c @@ -0,0 +1,113 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +/* mailbox message buffer */ +static unsigned int __align(16) mbox[MBOX_BUFFER_LENGTH]; + +static uint64_t mbox_mem_addr; +static uint8_t mbox_initialized; + +/* Macros to access Mailbox Registers with base address 'mbox_mem_addr'*/ +#define MBOX_REG(r) ((uint32_t *)(mbox_mem_addr + (r))) +#define MBOX_REG_READ(r) ioreg_read32(MBOX_REG(r)) +#define MBOX_REG_WRITE(r, v) ioreg_write32(MBOX_REG(r), v) + + /*mbox full return true, else return false */ +static inline bool mbox_full(void) +{ + return (MBOX_REG_READ(MBOX_STATUS) & MBOX_FULL); +} + +// /*mbox empty return true, else return false */ +static inline bool mbox_empty(void) +{ + return (MBOX_REG_READ(MBOX_STATUS) & MBOX_EMPTY); +} + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mbox_call(unsigned char ch) +{ + if (!mbox_initialized) { + UK_CRASH("MBOX not initialized!\n"); + return -1; + } + /** + * The buffer mbox is 16-byte aligned + * only the upper 28 bits of the address + * can be passed via the mailbox. The last 4 bits + * take the lower 4 digits of the channel, also 16-byte aligned. + */ + unsigned int r = (((uint32_t)((uint64_t)&mbox)&~0xF) | (ch&0xF)); + /* wait until we can write to the mailbox */ + do { + asm volatile("nop"); + } while (mbox_full()); + MBOX_REG_WRITE(MBOX_WRITE, r); + + barrier(); + clean_and_invalidate_dcache_range( + (unsigned long)&mbox, MBOX_BUFFER_LENGTH*sizeof(mbox[0])); + + /* now wait for the response */ + do { + asm volatile("nop"); + } while (mbox_empty() || + r != MBOX_REG_READ(MBOX_READ) || mbox[1] == MBOX_REQUEST); + + return mbox[1] == MBOX_RESPONSE_NORMAL; +} + +void _libraspiplat_init_mbox(void *fdtp) +{ + int mbox_offset, rc; + uint64_t addr, size; + + mbox_offset = fdt_node_offset_by_compatible(fdtp, -1, + "brcm,bcm2835-mbox"); + + if (mbox_offset < 0) + UK_CRASH("No mailbox device found!\n"); + + rc = fdt_get_address(fdtp, mbox_offset, 0, &addr, &size); + if (rc < 0) + UK_CRASH("Could not find Mailbox address!\n"); + + mbox_mem_addr = addr; + mbox_initialized = 1; +} + +void mbox_msg_create(int paras_num, ...) +{ + va_list args; + + va_start(args, paras_num); + + for (int i = 0; i < paras_num && i < MBOX_BUFFER_LENGTH; ++i) + mbox[i] = va_arg(args, uint32_t); + + va_end(args); + + for (int i = paras_num; i < MBOX_BUFFER_LENGTH; ++i) + mbox[i] = 0; +} diff --git a/memory.c b/memory.c new file mode 100644 index 0000000000000000000000000000000000000000..cb01b6bc0a9b8c14978e6a3460c7fe106f510760 --- /dev/null +++ b/memory.c @@ -0,0 +1,20 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +int _ukplat_mem_mappings_init(void) +{ + return 0; +} diff --git a/mm.S b/mm.S new file mode 100644 index 0000000000000000000000000000000000000000..7d9768b0f6e1a786d244a00d36c3df2ce36f0cf5 --- /dev/null +++ b/mm.S @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret diff --git a/mmu.S b/mmu.S new file mode 100644 index 0000000000000000000000000000000000000000..2efd812b20488196fe79fdd66b14fb6cd9e14ca3 --- /dev/null +++ b/mmu.S @@ -0,0 +1,70 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include + +ENTRY(start_mmu) + /* Load ttbr0, pagetable starts from _end */ + ur_ldr x27, arm64_bpt_l3_pt0 + msr ttbr0_el1, x27 + isb + + /* Clear the Monitor Debug System control register */ + msr mdscr_el1, xzr + + /* Invalidate the TLB to avoid stale one */ + tlbi vmalle1 + dsb nsh + + ldr x2, =MAIR_INIT_ATTR + msr mair_el1, x2 + + /* Set up TCR_EL1. The platform must provide a + * configuration compatible with the paging API. + */ + ldr x2, =TCR_INIT_FLAGS + msr tcr_el1, x2 + + /* Setup SCTLR */ + ldr x2, =SCTLR_SET_BITS + ldr x3, =SCTLR_CLEAR_BITS + mrs x1, sctlr_el1 + bic x1, x1, x3 /* Clear the required bits */ + orr x1, x1, x2 /* Set the required bits */ + msr sctlr_el1, x1 + isb + + ret +END(start_mmu) + +ENTRY(clear_bss) +clear_bss_start: + // Clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +clear_bss_loop: + cbz w2, clear_bss_done + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, clear_bss_loop +clear_bss_done: + ret +END(clear_bss) diff --git a/raspi_bpt64.S b/raspi_bpt64.S new file mode 100644 index 0000000000000000000000000000000000000000..fb95e9bc4bb732dd80dabbc4840c06c9a457031d --- /dev/null +++ b/raspi_bpt64.S @@ -0,0 +1,102 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +/* ------------------------- Memory Map of raspi ----------------------- + * + * 0x0000000000000 - 0x000003EFFFFFF NormalMem: 0-1008M attr:normal + * 0x000003F000000 - 0x000003FFFFFFF Device: 1008MiB-1024MiB attr:device + * 0x0000040000000 - 0x00000401FFFFF Peripheral:1024MiB-1026MiB attr:device + * + * Notice: The page tables below use the Unikraft indexing convention. + */ + +.section .data +.align 4 +.global bpt_unmap_mrd +bpt_unmap_mrd: + .quad 0x000000000001000 /* 4K */ + .quad 0x000000000001000 /* 4k */ + /* Used for struct ukplat_memregion_desc + * Unmapping starts at 4K and ends at 1G + */ + .quad 0x000000003EFFF000 + .short 0x0000000000000000 + .short 0x0000000000000010 /* UKPLAT_MEMRF_UNMAP */ + .space 36 + +.global arm64_bpt_l3_pt0 +/* L3: 0 - 256TiB (512GiB / entry) + * + * 0x0000000000000 - 0x0007fffffffff Table descriptor to l2_pt0 + * 0x0008000000000 - 0x0FF7FFFFFFFFF Unmapped + * 0x0ff8000000000 - 0x0ffffffffffff Table descriptor to l2_pt511 + */ +.align 12 +arm64_bpt_l3_pt0: + ur_pte arm64_bpt_l2_pt0, PTE_TYPE_TABLE + pte_zero , 510 +#if CONFIG_PAGING + ur_pte arm64_bpt_l2_pt511, PTE_TYPE_TABLE +#else /* !CONFIG_PAGING */ + pte_zero , 1 +#endif /* !CONFIG_PAGING */ + +/* L2: 0 - 512GiB (1GiB / entry) + * + * 0x0000000000000000 - 0x000000003FFFFFFF Table descriptor to l1_pt0 + * 0x0000000040000000 - 0x000000007FFFFFFF Table descriptor to l1_pt1 + * 0x0000000080000000 - 0x0000007FFFFFFFFF Unmapped + */ +.align 12 +arm64_bpt_l2_pt0: + ur_pte arm64_bpt_l1_pt0, PTE_TYPE_TABLE + ur_pte arm64_bpt_l1_pt1, PTE_TYPE_TABLE + pte_zero ,510 + +#if CONFIG_PAGING +/* L2: 255.5 TiB - 256TiB (1GiB / entry) + * + * 0x0000ff8000000000 - 0x0000ffffffffffff Direct-mapped + */ +.align 12 +arm64_bpt_l2_pt511: + pte_fill 0x0000000000000000, 1, 2, PTE_BLOCK_NORMAL_RW + pte_zero , 511 +#endif /* CONFIG_PAGING */ + +/* L1: 0 - 1GiB (2MiB / entry) + * 0x0000000000 - 0x00003EFFFFFF NormalMem 948M - 1008MiB attr:normal + * 0x003F000000 - 0x00003FFFFFFF Device: 1008MiB - 1024MiB attr: device + * There could be an arm64_bpt_l0_pt0,but it has no attribute difference + * from arm64_bpt_l1_pt0's first page,and 512 entries of 2MiB will cover all + * raspi memory,so it is not necessary for an arm64_bpt_l0_pt0. + */ +.align 12 +arm64_bpt_l1_pt0: + pte_fill 0x0000000000000000, 504, 1, PTE_BLOCK_NORMAL_RWX + pte_fill 0x000000003F000000, 8, 1, PTE_BLOCK_DEVICE_nGnRnE + +/* L1: 1 - 2GiB (2MiB / entry)(0-2Mi covered by arm64_bpt_l0_pt0 ) + * 0x0000000040000000 - 0x00007fffffff device @1GiB device + */ +.align 12 +arm64_bpt_l1_pt1: + pte_fill 0x0000000040000000, 1, 1, PTE_BLOCK_DEVICE_nGnRnE + pte_zero , 511 diff --git a/setup.c b/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..b0cf1b66a77b473afb38d817f013451d0b7516d9 --- /dev/null +++ b/setup.c @@ -0,0 +1,130 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +smccc_conduit_fn_t smccc_psci_call; + +static char *cmdline; +static __sz cmdline_len; + +static inline int cmdline_init(struct ukplat_bootinfo *bi) +{ + char *cmdl; + + if (bi->cmdline_len) { + cmdl = (char *)bi->cmdline; + cmdline_len = bi->cmdline_len; + } else { + cmdl = CONFIG_UK_NAME; + cmdline_len = sizeof(CONFIG_UK_NAME) - 1; + } + + /* TODO: Only extract what we need before passing to application. */ + + /* This is not the original command-line, but one that will be thrashed + * by `ukplat_entry_argp` to obtain argc/argv. So mark it as a kernel + * resource instead. + */ + cmdline = ukplat_memregion_alloc(cmdline_len + 1, UKPLAT_MEMRT_KERNEL, + UKPLAT_MEMRF_READ | + UKPLAT_MEMRF_WRITE | + UKPLAT_MEMRF_MAP); + if (unlikely(!cmdline)) + return -ENOMEM; + + memcpy(cmdline, cmdl, cmdline_len); + cmdline[cmdline_len] = 0; + + return 0; +} + +static void __noreturn _ukplat_entry2(void) +{ + ukplat_entry_argp(NULL, cmdline, cmdline_len); + + ukplat_lcpu_halt(); +} + + +void _libraspiplat_entry(void *fdtp) +{ + int rc; + void *bstack; + struct ukplat_bootinfo *bi; + + _libraspiplat_init_mbox(fdtp); + _libraspiplat_init_gpio(fdtp); + _libraspiplat_init_console(fdtp); + + ukplat_bootinfo_fdt_setup(fdtp); + bi = ukplat_bootinfo_get(); + if (unlikely(!bi)) + UK_CRASH("Invalid bootinfo"); + + uk_pr_debug("Device tree location @%p\n", bi); + + rc = cmdline_init(bi); + if (unlikely(rc < 0)) + UK_CRASH("Failed to initialize command-line\n"); + + /* Allocate boot stack */ + bstack = ukplat_memregion_alloc(__STACK_SIZE, UKPLAT_MEMRT_STACK, + UKPLAT_MEMRF_READ | + UKPLAT_MEMRF_WRITE | + UKPLAT_MEMRF_MAP); + if (unlikely(!bstack)) + UK_CRASH("Boot stack alloc failed\n"); + bstack = (void *)((__uptr)bstack + __STACK_SIZE); + + /* Initialize paging */ + rc = ukplat_mem_init(); + if (unlikely(rc)) + UK_CRASH("Could not initialize paging (%d)\n", rc); + +#if defined(CONFIG_ENFORCE_W_XOR_X) && defined(CONFIG_PAGING) + enforce_w_xor_x(); +#endif /* CONFIG_ENFORCE_W_XOR_X && CONFIG_PAGING */ + + /* Initialize interrupt controller */ + rc = uk_intctlr_probe(); + if (unlikely(rc)) + UK_CRASH("Could not initialize the IRQ controller: %d\n", rc); + + /* Initialize logical boot CPU */ + rc = lcpu_init(lcpu_get_bsp()); + if (unlikely(rc)) + UK_CRASH("Failed to initialize bootstrapping CPU: %d\n", rc); + + /* + * Switch away from the bootstrap stack as early as possible. + */ + uk_pr_info("Switch from bootstrap stack to stack @%p\n", bstack); + + /* Print boot information */ + uk_pr_info("Print bootinfo before jump to entry:\n"); + ukplat_bootinfo_print(); + + /* + * Enter Unikraft with new allocated stack. + */ + lcpu_arch_jump_to(bstack, _ukplat_entry2); +} diff --git a/shutdown.c b/shutdown.c new file mode 100644 index 0000000000000000000000000000000000000000..8de38cec290675a5c78db5c5622e5bdb3d23351b --- /dev/null +++ b/shutdown.c @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +static void cpu_halt(void) __noreturn; + +void ukplat_terminate(enum ukplat_gstate request __unused) +{ + cpu_halt(); +} + +static void cpu_halt(void) +{ + __CPU_HALT(); +} + +int ukplat_suspend(void) +{ + return -EBUSY; +} diff --git a/start.S b/start.S new file mode 100644 index 0000000000000000000000000000000000000000..d9767e958b465e11df77267150111037fa129214 --- /dev/null +++ b/start.S @@ -0,0 +1,126 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#define VA_START 0 +#define BOOTSTACK_SIZE 4096 + +.section .bss +.align 16 +.space BOOTSTACK_SIZE +lcpu_bootstack: + +.section ".text.boot" + +.global _start +_start: + + /* preserve dtb addr */ + mov x25, x0 + + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, master + +// If the cpu id is > 0, hang here +hang: wfe + b hang + +// Continue if cpu id == 0 +master: + // disable mmu and cache + mrs x2, sctlr_el1 + mov x3, #SCTLR_EL1_M_BIT|SCTLR_EL1_C_BIT + bic x2, x2, x3 + msr sctlr_el1, x2 + + ldr x0, =SCTLR_EL2_VALUE + msr sctlr_el2, x0 + isb + + // Disable coprocessor traps + ldr x0, =CPACR_EL1_VALUE + msr cpacr_el1, x0 + + // define register width, el1: aarch64, el0: by code. other bits are 0. + ldr x0, =HCR_EL2_VALUE + msr hcr_el2, x0 + + // Set the SPSR state to restore when returning from EL2 to EL1 + ldr x0, =SPSR_EL2_VALUE + msr spsr_el2, x0 + + // set return address when returning from EL2 to EL1 + adr x0, el1_entry + msr elr_el2, x0 + + eret + +el1_entry: + /* + * We will disable MMU and cache before the pagetables are ready. + * This means we will change memory with cache disabled, so we need to + * invalidate the cache to ensure there is no stale data in it. + * But it would be expensive to invalidate the whole cache. + * In this case, just need to invalidate what we are going to use: + * DTB, TEXT, DATA, BSS, and bootstack. + */ + ldr x0, =_start_ram_addr + ldr x1, =_end + sub x1, x1, x0 + bl clean_and_invalidate_dcache_range + + /* Enable the mmu */ + bl start_mmu + +#if CONFIG_RASPI_WATERMARK_STACK +watermark_stack_start: + ldr x1, =VA_START + ldr w2, =0x10000 +watermark_stack_loop: + cbz w2, watermark_stack_done + str x2, [x1], #8 + sub w2, w2, #1 + cbnz w2, watermark_stack_loop +watermark_stack_done: +#endif + + bl clear_bss + + ldr x0, =lcpu_bootstack + and x0, x0, ~(__STACK_ALIGN_SIZE - 1) + mov sp, x0 + + /* Set exception vector table*/ + ldr x0, =vectors_el1 + msr vbar_el1, x0 + + /* Set the context id */ + msr contextidr_el1, xzr + + /* Load dtb address to x0 as a parameter */ + mov x0, x25 + + bl _libraspiplat_entry + + /* As a failsafe, we also hang the main core */ + b hang diff --git a/tests/test_paging.c b/tests/test_paging.c new file mode 100644 index 0000000000000000000000000000000000000000..937e062396fc1a87dfc2aed5bcfa46604a6ae901 --- /dev/null +++ b/tests/test_paging.c @@ -0,0 +1,120 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef CONFIG_PAGING +#include +#include +#include +#include +#define __PLAT_CMN_ARCH_PAGING_H__ +#if defined CONFIG_ARCH_ARM_64 +#include +#elif defined CONFIG_ARCH_X86_64 +#include +#else +#error "Architecture not supported by paging API" +#endif + + +#define MAPPED_DIRECT_OFFSET 0x0000ff8000000000 +extern struct ukplat_memregion_desc bpt_unmap_mrd; + + +/* 确保unmap段正确性 */ +UK_TESTCASE(plat_raspi, test_unmap_mrd) +{ + UK_TEST_EXPECT_SNUM_EQ(bpt_unmap_mrd.pbase, 0x1000); + UK_TEST_EXPECT_SNUM_EQ(bpt_unmap_mrd.vbase, 0x1000); + UK_TEST_EXPECT_SNUM_EQ(bpt_unmap_mrd.len, 0x40000000-0x1000); + UK_TEST_EXPECT_SNUM_EQ(bpt_unmap_mrd.flags, UKPLAT_MEMRF_UNMAP); +} +UK_TESTCASE(plat_raspi, test_pt_str) +{ + struct uk_pagetable *pt; + unsigned long pbase = ukarch_pt_read_base(); + unsigned int lvl; + int rc; + + pt = ukplat_pt_get_active(); + UK_TEST_EXPECT_SNUM_EQ(pt->pt_pbase, pbase); + UK_TEST_EXPECT_SNUM_EQ(pt->fa, MAPPED_DIRECT_OFFSET); + UK_TEST_EXPECT_SNUM_EQ(pbase, pt->pt_vbase-MAPPED_DIRECT_OFFSET); + + unsigned long address = 0x40000000000; + __pte_t lpte; + + unsigned int level = 0; + __vaddr_t *pt_vaddr = pt->pt_vbase; + __pte_t pte; + int attr; + + //successfully mapped,THIS ADDRESS SHOULD BE NORMAL R/W PERMISSION + rc = ukplat_page_map(pt, address, 0x3F200000, 1, PAGE_ATTR_PROT_RW, 16); + UK_TEST_EXPECT_ZERO(rc); + + + + ukplat_pt_walk(pt, address, + &level, pt->pt_vbase, &pte); + //NON-S + attr = pgarch_attr_from_pte(pte, 0); + UK_TEST_EXPECT_ZERO(attr & PTE_ATTR_SH_MASK); + // PROT + UK_TEST_EXPECT_SNUM_EQ(attr & 0x03, 3); + //device + UK_TEST_EXPECT_SNUM_EQ(attr & PTE_ATTR_IDX_MASK, DEVICE_nGnRnE); + + //any addr with prot R/W + level = 0; + ukplat_pt_walk(pt, __VADDR_ANY, &level, + pt->pt_vbase, &pte); + UK_TEST_EXPECT_SNUM_EQ(pgarch_attr_from_pte(pte, 0) & 0x03, 3); + + level = 0; + ukplat_pt_walk(pt, 0x1000, &level, + pt->pt_vbase, &pte); + //Normal段 + attr = pgarch_attr_from_pte(pte, 0); + UK_TEST_EXPECT_SNUM_GT(attr & PTE_ATTR_IDX_MASK, 2); + UK_TEST_EXPECT_SNUM_EQ(attr & 0x03, 3); + + level = 0; + ukplat_pt_walk(pt, 0xFF8000000000, &level, + pt->pt_vbase, &pte); + attr = pgarch_attr_from_pte(pte, 0); + UK_TEST_EXPECT_SNUM_EQ(attr & 0x03, 3); + + level = 0; + ukplat_pt_walk(pt, 0, &level, + pt->pt_vbase, &pte); + attr = pgarch_attr_from_pte(pte, 0); + UK_TEST_EXPECT_SNUM_EQ(attr & 0x03, 3); + + //LVL3 l3pt511,DIRECT MAPPING,proving a 4-level pagetable + __vaddr_t vaddr = (__vaddr_t) pt->pt_vbase; + int pteindex; + __vaddr_t ptvbase = (__vaddr_t) pt->pt_vbase; + + UK_TEST_EXPECT_SNUM_GT(vaddr, 0xFF8000000000); + + pteindex = PT_Lx_IDX(vaddr, 3); + UK_TEST_EXPECT_SNUM_EQ(pteindex, 511); +} + +/* 注册raspi测试套事件 */ +uk_testsuite_plat_prio(plat_raspi, NULL, __UK_PRIO_AFTER_0); +#endif /* CONFIG_PAGING */ +