diff options
97 files changed, 2892 insertions, 505 deletions
@@ -224,6 +224,16 @@ config BUILD_ROM which are not shipped in the U-Boot source tree. Please, see doc/README.x86 for details. +config SPL_IMAGE + string "SPL image used in the combined SPL+U-Boot image" + default "spl/boot.bin" if ARCH_AT91 && SPL_NAND_SUPPORT + default "spl/u-boot-spl.bin" + help + Select the SPL build target that shall be generated by the SPL + build process (default spl/u-boot-spl.bin). This image will be + used to generate a combined image with SPL and main U-Boot + proper as one single image. + config BUILD_TARGET string "Build target special images" default "u-boot-with-spl.sfp" if TARGET_SOCFPGA_ARRIA10 @@ -232,6 +242,7 @@ config BUILD_TARGET default "u-boot-elf.srec" if RCAR_GEN3 default "u-boot.itb" if SPL_LOAD_FIT && ARCH_SUNXI default "u-boot.kwb" if KIRKWOOD + default "u-boot-with-spl.bin" if ARCH_AT91 && SPL_NAND_SUPPORT help Some SoCs need special image types (e.g. U-Boot binary with a special header) as build targets. By defining @@ -1246,9 +1246,11 @@ else SPL_PAYLOAD := u-boot.bin endif +SPL_IMAGE := $(CONFIG_SPL_IMAGE:"%"=%) + OBJCOPYFLAGS_u-boot-with-spl.bin = -I binary -O binary \ --pad-to=$(CONFIG_SPL_PAD_TO) -u-boot-with-spl.bin: spl/u-boot-spl.bin $(SPL_PAYLOAD) FORCE +u-boot-with-spl.bin: $(SPL_IMAGE) $(SPL_PAYLOAD) FORCE $(call if_changed,pad_cat) ifeq ($(CONFIG_ARCH_LPC32XX)$(CONFIG_SPL),yy) @@ -767,9 +767,6 @@ The following options need to be configured: SoC, then define this variable and provide board specific code for the "hw_watchdog_reset" function. - CONFIG_AT91_HW_WDT_TIMEOUT - specify the timeout in seconds. default 2 seconds. - - Real-Time Clock: When CONFIG_CMD_DATE is selected, the type of the RTC diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 8a4efee..86a01c2 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -599,6 +599,8 @@ dtb-$(CONFIG_TARGET_AT91SAM9260EK) += \ dtb-$(CONFIG_TARGET_AT91SAM9M10G45EK) += at91sam9m10g45ek.dtb +dtb-$(CONFIG_TARGET_PM9G45) += at91sam9m10g45ek.dtb + dtb-$(CONFIG_TARGET_AT91SAM9X5EK) += \ at91sam9g15ek.dtb \ at91sam9g25ek.dtb \ @@ -608,6 +610,9 @@ dtb-$(CONFIG_TARGET_AT91SAM9X5EK) += \ dtb-$(CONFIG_TARGET_AT91SAM9N12EK) += at91sam9n12ek.dtb +dtb-$(CONFIG_TARGET_GARDENA_SMART_GATEWAY_AT91SAM) += \ + at91sam9g25-gardena-smart-gateway.dtb + dtb-$(CONFIG_TARGET_ETHERNUT5) += ethernut5.dtb dtb-$(CONFIG_TARGET_USB_A9263) += usb_a9263.dtb diff --git a/arch/arm/dts/at91sam9g25-gardena-smart-gateway-u-boot.dtsi b/arch/arm/dts/at91sam9g25-gardena-smart-gateway-u-boot.dtsi new file mode 100644 index 0000000..732dee6 --- /dev/null +++ b/arch/arm/dts/at91sam9g25-gardena-smart-gateway-u-boot.dtsi @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0+ + +&dbgu { + u-boot,dm-pre-reloc; +}; diff --git a/arch/arm/dts/at91sam9g25-gardena-smart-gateway.dts b/arch/arm/dts/at91sam9g25-gardena-smart-gateway.dts new file mode 100644 index 0000000..e2f8d80 --- /dev/null +++ b/arch/arm/dts/at91sam9g25-gardena-smart-gateway.dts @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Device Tree file for the GARDENA smart Gateway (AT91SAM) + * + * Copyright (C) 2012 Atmel, + * 2012 Nicolas Ferre <nicolas.ferre@atmel.com> + */ + +/dts-v1/; + +#include "at91sam9g25.dtsi" + +/ { + model = "GARDENA smart Gateway (AT91SAM)"; + compatible = "gardena,smart-gateway-at91sam", "atmel,at91sam9"; + + aliases { + serial0 = &dbgu; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0x20000000 0x8000000>; + }; + + clocks { + slow_xtal { + clock-frequency = <32768>; + }; + + main_xtal { + clock-frequency = <12000000>; + }; + }; + + leds { + compatible = "gpio-leds"; + + power_blue { + label = "smartgw:power:blue"; + gpios = <&pioC 21 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + power_green { + label = "smartgw:power:green"; + gpios = <&pioC 20 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + power_red { + label = "smartgw:power:red"; + gpios = <&pioC 19 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + radio_blue { + label = "smartgw:radio:blue"; + gpios = <&pioC 18 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + radio_green { + label = "smartgw:radio:green"; + gpios = <&pioC 17 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + radio_red { + label = "smartgw:radio:red"; + gpios = <&pioC 16 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + internet_blue { + label = "smartgw:internet:blue"; + gpios = <&pioC 15 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + internet_green { + label = "smartgw:internet:green"; + gpios = <&pioC 14 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + internet_red { + label = "smartgw:internet:red"; + gpios = <&pioC 13 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; +}; + +&dbgu { + status = "okay"; +}; + +&macb0 { + phy-mode = "rmii"; + status = "okay"; +}; + +&nand0 { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + atmel,has-pmecc; /* Enable PMECC */ + atmel,pmecc-cap = <2>; + atmel,pmecc-sector-size = <512>; + nand-on-flash-bbt; + status = "okay"; +}; + +&watchdog { + status = "okay"; + timeout-sec = <16>; +}; diff --git a/arch/arm/dts/at91sam9x5.dtsi b/arch/arm/dts/at91sam9x5.dtsi index ea319cc..bd4abe0 100644 --- a/arch/arm/dts/at91sam9x5.dtsi +++ b/arch/arm/dts/at91sam9x5.dtsi @@ -1180,7 +1180,7 @@ }; }; - watchdog@fffffe40 { + watchdog: watchdog@fffffe40 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffe40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index a6329dc..a089e94 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -147,6 +147,13 @@ config TARGET_AT91SAM9X5EK select BOARD_LATE_INIT select SUPPORT_SPL +config TARGET_GARDENA_SMART_GATEWAY_AT91SAM + bool "GARDENA smart Gateway (AT91SAM)" + select AT91SAM9X5 + select BOARD_EARLY_INIT_F + select BOARD_LATE_INIT + select SUPPORT_SPL + config TARGET_SAMA5D2_PTC_EK bool "SAMA5D2 PTC EK board" select BOARD_EARLY_INIT_F @@ -283,6 +290,7 @@ source "board/bluewater/snapper9260/Kconfig" source "board/calao/usb_a9263/Kconfig" source "board/egnite/ethernut5/Kconfig" source "board/esd/meesc/Kconfig" +source "board/gardena/smart-gateway-at91sam/Kconfig" source "board/l+g/vinco/Kconfig" source "board/mini-box/picosam9g45/Kconfig" source "board/ronetix/pm9261/Kconfig" diff --git a/arch/arm/mach-at91/arm926ejs/Makefile b/arch/arm/mach-at91/arm926ejs/Makefile index 0639d7e..6b0b289 100644 --- a/arch/arm/mach-at91/arm926ejs/Makefile +++ b/arch/arm/mach-at91/arm926ejs/Makefile @@ -24,8 +24,10 @@ obj-y += timer.o endif ifndef CONFIG_SKIP_LOWLEVEL_INIT +ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY obj-y += lowlevel_init.o endif +endif ifdef CONFIG_$(SPL_)SYS_THUMB_BUILD ifndef CONFIG_HAS_THUMB2 diff --git a/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds b/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds index f18b17d..3955bea 100644 --- a/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds +++ b/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds @@ -39,6 +39,8 @@ SECTIONS *(.__end) } >.sram + _image_binary_end = .; + .bss : { . = ALIGN(4); diff --git a/arch/arm/mach-at91/armv7/sama5d2_devices.c b/arch/arm/mach-at91/armv7/sama5d2_devices.c index 6432f66..59a0c44 100644 --- a/arch/arm/mach-at91/armv7/sama5d2_devices.c +++ b/arch/arm/mach-at91/armv7/sama5d2_devices.c @@ -9,7 +9,7 @@ #include <asm/arch/clk.h> #include <asm/arch/sama5d2.h> -int cpu_is_sama5d2(void) +int _cpu_is_sama5d2(void) { unsigned int chip_id = get_chip_id(); diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index 64cbc3d..1d3df2c 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -5,12 +5,17 @@ */ #include <common.h> +#include <dm.h> +#include <wdt.h> #include <asm/io.h> #include <asm/arch/hardware.h> #include <asm/arch/at91_pmc.h> +#include <asm/arch/at91_wdt.h> #define EN_UPLL_TIMEOUT 500 +static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL; + void at91_periph_clk_enable(int id) { struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; @@ -118,3 +123,46 @@ void at91_pllicpr_init(u32 icpr) writel(icpr, &pmc->pllicpr); } + +/* Called by macro WATCHDOG_RESET */ +void watchdog_reset(void) +{ + static ulong next_reset; + ulong now; + + if (!watchdog_dev) + return; + + now = get_timer(0); + + /* Do not reset the watchdog too often */ + if (now > next_reset) { + next_reset = now + 1000; /* reset every 1000ms */ + wdt_reset(watchdog_dev); + } +} + +int arch_early_init_r(void) +{ + struct at91_wdt_priv *priv; + + /* Init watchdog */ + if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) { + debug("Watchdog: Not found by seq!\n"); + if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) { + puts("Watchdog: Not found!\n"); + return 0; + } + } + + priv = dev_get_priv(watchdog_dev); + if (!priv) { + printf("Watchdog: priv not available!\n"); + return 0; + } + + wdt_start(watchdog_dev, priv->timeout * 1000, 0); + printf("Watchdog: Started\n"); + + return 0; +} diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h b/arch/arm/mach-at91/include/mach/at91_wdt.h index cd22723..a8fc73b 100644 --- a/arch/arm/mach-at91/include/mach/at91_wdt.h +++ b/arch/arm/mach-at91/include/mach/at91_wdt.h @@ -25,6 +25,12 @@ typedef struct at91_wdt { u32 sr; } at91_wdt_t; +struct at91_wdt_priv { + void __iomem *regs; + u32 regval; + u32 timeout; +}; + #endif /* Watchdog Control Register */ @@ -43,4 +49,8 @@ typedef struct at91_wdt { #define AT91_WDT_MR_WDDBGHLT 0x10000000 #define AT91_WDT_MR_WDIDLEHLT 0x20000000 +/* Hardware timeout in seconds */ +#define WDT_MAX_TIMEOUT 16 +#define WDT_DEFAULT_TIMEOUT 2 + #endif diff --git a/arch/arm/mach-at91/include/mach/sama5d2.h b/arch/arm/mach-at91/include/mach/sama5d2.h index 37806cb..c7d9bb5 100644 --- a/arch/arm/mach-at91/include/mach/sama5d2.h +++ b/arch/arm/mach-at91/include/mach/sama5d2.h @@ -222,6 +222,9 @@ #define ARCH_EXID_SAMA5D27C_D1G 0x00000033 #define ARCH_EXID_SAMA5D28C_D1G 0x00000013 +/* Checked if defined in ethernet driver macb */ +#define cpu_is_sama5d2 _cpu_is_sama5d2 + /* PIT Timer(PIT_PIIR) */ #define CONFIG_SYS_TIMER_COUNTER 0xf804803c @@ -231,7 +234,7 @@ #ifndef __ASSEMBLY__ unsigned int get_chip_id(void); unsigned int get_extension_chip_id(void); -int cpu_is_sama5d2(void); +int _cpu_is_sama5d2(void); unsigned int has_lcdc(void); char *get_cpu_name(void); #endif diff --git a/arch/arm/mach-at91/spl_at91.c b/arch/arm/mach-at91/spl_at91.c index 23ebaa9..1065f09 100644 --- a/arch/arm/mach-at91/spl_at91.c +++ b/arch/arm/mach-at91/spl_at91.c @@ -75,6 +75,16 @@ void __weak spl_board_init(void) void board_init_f(ulong dummy) { +#if CONFIG_IS_ENABLED(OF_CONTROL) + int ret; + + ret = spl_early_init(); + if (ret) { + debug("spl_early_init() failed: %d\n", ret); + hang(); + } +#endif + lowlevel_clock_init(); #if !defined(CONFIG_WDT_AT91) at91_disable_wdt(); diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 36512a8..ae8ff7b 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -109,6 +109,24 @@ config SIFIVE_CLINT The SiFive CLINT block holds memory-mapped control and status registers associated with software and timer interrupts. +config ANDES_PLIC + bool + depends on RISCV_MMODE + select REGMAP + select SYSCON + help + The Andes PLIC block holds memory-mapped claim and pending registers + associated with software interrupt. + +config ANDES_PLMT + bool + depends on RISCV_MMODE + select REGMAP + select SYSCON + help + The Andes PLMT block holds memory-mapped mtime register + associated with timer tick. + config RISCV_RDTIME bool default y if RISCV_SMODE @@ -120,4 +138,32 @@ config RISCV_RDTIME config SYS_MALLOC_F_LEN default 0x1000 +config SMP + bool "Symmetric Multi-Processing" + help + This enables support for systems with more than one CPU. If + you say N here, U-Boot will run on single and multiprocessor + machines, but will use only one CPU of a multiprocessor + machine. If you say Y here, U-Boot will run on many, but not + all, single processor machines. + +config NR_CPUS + int "Maximum number of CPUs (2-32)" + range 2 32 + depends on SMP + default 8 + help + On multiprocessor machines, U-Boot sets up a stack for each CPU. + Stack memory is pre-allocated. U-Boot must therefore know the + maximum number of CPUs that may be present. + +config SBI_IPI + bool + default y if RISCV_SMODE + depends on SMP + +config STACK_SIZE_SHIFT + int + default 13 + endmenu diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig index e9dbca2..6b4b92e 100644 --- a/arch/riscv/cpu/ax25/Kconfig +++ b/arch/riscv/cpu/ax25/Kconfig @@ -1,5 +1,11 @@ config RISCV_NDS bool + select ARCH_EARLY_INIT_R + imply CPU + imply CPU_RISCV + imply RISCV_TIMER + imply ANDES_PLIC if RISCV_MMODE + imply ANDES_PLMT if RISCV_MMODE help Run U-Boot on AndeStar V5 platforms and use some specific features which are provided by Andes Technology AndeStar V5 families. @@ -8,6 +14,7 @@ if RISCV_NDS config RISCV_NDS_CACHE bool "AndeStar V5 families specific cache support" + depends on RISCV_MMODE help Provide Andes Technology AndeStar V5 families specific cache support. diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index e662140..c32de8a 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -12,10 +12,17 @@ #include <dm/uclass-internal.h> /* - * prior_stage_fdt_address must be stored in the data section since it is used + * The variables here must be stored in the data section since they are used * before the bss section is available. */ phys_addr_t prior_stage_fdt_address __attribute__((section(".data"))); +u32 hart_lottery __attribute__((section(".data"))) = 0; + +/* + * The main hart running U-Boot has acquired available_harts_lock until it has + * finished initialization of global data. + */ +u32 available_harts_lock = 1; static inline bool supports_extension(char ext) { diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S index 81ea52b..a4433fb 100644 --- a/arch/riscv/cpu/start.S +++ b/arch/riscv/cpu/start.S @@ -13,6 +13,7 @@ #include <config.h> #include <common.h> #include <elf.h> +#include <asm/csr.h> #include <asm/encoding.h> #include <generated/asm-offsets.h> @@ -32,11 +33,19 @@ #define SYM_SIZE 0x18 #endif +.section .data +secondary_harts_relocation_error: + .ascii "Relocation of secondary harts has failed, error %d\n" + .section .text .globl _start _start: +#ifdef CONFIG_RISCV_MMODE + csrr a0, mhartid +#endif + /* save hart id and dtb pointer */ - mv s0, a0 + mv tp, a0 mv s1, a1 la t0, trap_entry @@ -45,9 +54,22 @@ _start: /* mask all interrupts */ csrw MODE_PREFIX(ie), zero - /* Enable cache */ - jal icache_enable - jal dcache_enable +#ifdef CONFIG_SMP + /* check if hart is within range */ + /* tp: hart id */ + li t0, CONFIG_NR_CPUS + bge tp, t0, hart_out_of_bounds_loop +#endif + +#ifdef CONFIG_SMP + /* set xSIE bit to receive IPIs */ +#ifdef CONFIG_RISCV_MMODE + li t0, MIE_MSIE +#else + li t0, SIE_SSIE +#endif + csrs MODE_PREFIX(ie), t0 +#endif /* * Set stackpointer in internal/ex RAM to call board_init_f @@ -57,14 +79,33 @@ call_board_init_f: li t1, CONFIG_SYS_INIT_SP_ADDR and sp, t1, t0 /* force 16 byte alignment */ -#ifdef CONFIG_DEBUG_UART - jal debug_uart_init -#endif - call_board_init_f_0: mv a0, sp jal board_init_f_alloc_reserve + + /* + * Set global data pointer here for all harts, uninitialized at this + * point. + */ + mv gp, a0 + + /* setup stack */ +#ifdef CONFIG_SMP + /* tp: hart id */ + slli t0, tp, CONFIG_STACK_SIZE_SHIFT + sub sp, a0, t0 +#else mv sp, a0 +#endif + + /* + * Pick hart to initialize global data and run U-Boot. The other harts + * wait for initialization to complete. + */ + la t0, hart_lottery + li s2, 1 + amoswap.w s2, t1, 0(t0) + bnez s2, wait_for_gd_init la t0, prior_stage_fdt_address SREG s1, 0(t0) @@ -72,7 +113,42 @@ call_board_init_f_0: jal board_init_f_init_reserve /* save the boot hart id to global_data */ - SREG s0, GD_BOOT_HART(gp) + SREG tp, GD_BOOT_HART(gp) + + la t0, available_harts_lock + fence rw, w + amoswap.w zero, zero, 0(t0) + +wait_for_gd_init: + la t0, available_harts_lock + li t1, 1 +1: amoswap.w t1, t1, 0(t0) + fence r, rw + bnez t1, 1b + + /* register available harts in the available_harts mask */ + li t1, 1 + sll t1, t1, tp + LREG t2, GD_AVAILABLE_HARTS(gp) + or t2, t2, t1 + SREG t2, GD_AVAILABLE_HARTS(gp) + + fence rw, w + amoswap.w zero, zero, 0(t0) + + /* + * Continue on hart lottery winner, others branch to + * secondary_hart_loop. + */ + bnez s2, secondary_hart_loop + + /* Enable cache */ + jal icache_enable + jal dcache_enable + +#ifdef CONFIG_DEBUG_UART + jal debug_uart_init +#endif mv a0, zero /* a0 <-- boot_flags = 0 */ la t5, board_init_f @@ -95,7 +171,14 @@ relocate_code: *Set up the stack */ stack_setup: +#ifdef CONFIG_SMP + /* tp: hart id */ + slli t0, tp, CONFIG_STACK_SIZE_SHIFT + sub sp, s2, t0 +#else mv sp, s2 +#endif + la t0, _start sub t6, s4, t0 /* t6 <- relocation offset */ beq t0, s4, clear_bss /* skip relocation */ @@ -175,13 +258,37 @@ clear_bss: add t0, t0, t6 /* t0 <- rel __bss_start in RAM */ la t1, __bss_end /* t1 <- rel __bss_end in FLASH */ add t1, t1, t6 /* t1 <- rel __bss_end in RAM */ - beq t0, t1, call_board_init_r + beq t0, t1, relocate_secondary_harts clbss_l: SREG zero, 0(t0) /* clear loop... */ addi t0, t0, REGBYTES bne t0, t1, clbss_l +relocate_secondary_harts: +#ifdef CONFIG_SMP + /* send relocation IPI */ + la t0, secondary_hart_relocate + add a0, t0, t6 + + /* store relocation offset */ + mv s5, t6 + + mv a1, s2 + mv a2, s3 + jal smp_call_function + + /* hang if relocation of secondary harts has failed */ + beqz a0, 1f + mv a1, a0 + la a0, secondary_harts_relocation_error + jal printf + jal hang + + /* restore relocation offset */ +1: mv t6, s5 +#endif + /* * We are done. Do not return, instead branch to second part of board * initialization, now running from RAM. @@ -202,3 +309,43 @@ call_board_init_r: * jump to it ... */ jr t4 /* jump to board_init_r() */ + +#ifdef CONFIG_SMP +hart_out_of_bounds_loop: + /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */ + wfi + j hart_out_of_bounds_loop +#endif + +#ifdef CONFIG_SMP +/* SMP relocation entry */ +secondary_hart_relocate: + /* a1: new sp */ + /* a2: new gd */ + /* tp: hart id */ + + /* setup stack */ + slli t0, tp, CONFIG_STACK_SIZE_SHIFT + sub sp, a1, t0 + + /* update global data pointer */ + mv gp, a2 +#endif + +secondary_hart_loop: + wfi + +#ifdef CONFIG_SMP + csrr t0, MODE_PREFIX(ip) +#ifdef CONFIG_RISCV_MMODE + andi t0, t0, MIE_MSIE +#else + andi t0, t0, SIE_SSIE +#endif + beqz t0, secondary_hart_loop + + mv a0, tp + jal handle_ipi +#endif + + j secondary_hart_loop diff --git a/arch/riscv/dts/Makefile b/arch/riscv/dts/Makefile index b400def..f9cd606 100644 --- a/arch/riscv/dts/Makefile +++ b/arch/riscv/dts/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ +dtb-$(CONFIG_TARGET_AX25_AE350) += ae350_32.dtb ae350_64.dtb + targets += $(dtb-y) DTC_FLAGS += -R 4 -p 0x1000 diff --git a/arch/riscv/dts/ae350_32.dts b/arch/riscv/dts/ae350_32.dts index 0679827..2ec01a5 100644 --- a/arch/riscv/dts/ae350_32.dts +++ b/arch/riscv/dts/ae350_32.dts @@ -26,16 +26,49 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv32imafdc"; + riscv,priv-major = <1>; + riscv,priv-minor = <10>; mmu-type = "riscv,sv32"; clock-frequency = <60000000>; + i-cache-size = <0x8000>; + i-cache-line-size = <32>; d-cache-size = <0x8000>; d-cache-line-size = <32>; + next-level-cache = <&L2>; CPU0_intc: interrupt-controller { #interrupt-cells = <1>; interrupt-controller; compatible = "riscv,cpu-intc"; }; }; + CPU1: cpu@1 { + device_type = "cpu"; + reg = <1>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv32imafdc"; + riscv,priv-major = <1>; + riscv,priv-minor = <10>; + mmu-type = "riscv,sv32"; + clock-frequency = <60000000>; + i-cache-size = <0x8000>; + i-cache-line-size = <32>; + d-cache-size = <0x8000>; + d-cache-line-size = <32>; + next-level-cache = <&L2>; + CPU1_intc: interrupt-controller { + #interrupt-cells = <1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + + L2: l2-cache@e0500000 { + compatible = "cache"; + cache-level = <2>; + cache-size = <0x40000>; + reg = <0x0 0xe0500000 0x0 0x40000>; + }; }; memory@0 { @@ -46,32 +79,32 @@ soc { #address-cells = <1>; #size-cells = <1>; - compatible = "andestech,riscv-ae350-soc"; + compatible = "simple-bus"; ranges; - plic0: interrupt-controller@e4000000 { - compatible = "riscv,plic0"; - #address-cells = <1>; - #interrupt-cells = <1>; - interrupt-controller; - reg = <0xe4000000 0x2000000>; - riscv,ndev=<71>; - interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9>; - }; + plic0: interrupt-controller@e4000000 { + compatible = "riscv,plic0"; + #address-cells = <1>; + #interrupt-cells = <1>; + interrupt-controller; + reg = <0xe4000000 0x2000000>; + riscv,ndev=<71>; + interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 &CPU1_intc 11 &CPU1_intc 9>; + }; - plic1: interrupt-controller@e6400000 { - compatible = "riscv,plic1"; - #address-cells = <1>; - #interrupt-cells = <1>; - interrupt-controller; - reg = <0xe6400000 0x400000>; - riscv,ndev=<1>; - interrupts-extended = <&CPU0_intc 3>; - }; + plic1: interrupt-controller@e6400000 { + compatible = "riscv,plic1"; + #address-cells = <1>; + #interrupt-cells = <1>; + interrupt-controller; + reg = <0xe6400000 0x400000>; + riscv,ndev=<2>; + interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3>; + }; - plmt0@e6000000 { - compatible = "riscv,plmt0"; - interrupts-extended = <&CPU0_intc 7>; + plmt0@e6000000 { + compatible = "riscv,plmt0"; + interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7>; reg = <0xe6000000 0x100000>; }; }; @@ -146,6 +179,10 @@ interrupt-parent = <&plic0>; }; + pmu { + compatible = "riscv,base-pmu"; + }; + virtio_mmio@fe007000 { interrupts = <0x17 0x4>; interrupt-parent = <0x2>; diff --git a/arch/riscv/dts/ae350_64.dts b/arch/riscv/dts/ae350_64.dts index e48c298..cde5cde 100644 --- a/arch/riscv/dts/ae350_64.dts +++ b/arch/riscv/dts/ae350_64.dts @@ -26,16 +26,49 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv64imafdc"; + riscv,priv-major = <1>; + riscv,priv-minor = <10>; mmu-type = "riscv,sv39"; clock-frequency = <60000000>; + i-cache-size = <0x8000>; + i-cache-line-size = <32>; d-cache-size = <0x8000>; d-cache-line-size = <32>; + next-level-cache = <&L2>; CPU0_intc: interrupt-controller { #interrupt-cells = <1>; interrupt-controller; compatible = "riscv,cpu-intc"; }; }; + CPU1: cpu@1 { + device_type = "cpu"; + reg = <1>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + riscv,priv-major = <1>; + riscv,priv-minor = <10>; + mmu-type = "riscv,sv39"; + clock-frequency = <60000000>; + i-cache-size = <0x8000>; + i-cache-line-size = <32>; + d-cache-size = <0x8000>; + d-cache-line-size = <32>; + next-level-cache = <&L2>; + CPU1_intc: interrupt-controller { + #interrupt-cells = <1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + + L2: l2-cache@e0500000 { + compatible = "cache"; + cache-level = <2>; + cache-size = <0x40000>; + reg = <0x0 0xe0500000 0x0 0x40000>; + }; }; memory@0 { @@ -46,32 +79,32 @@ soc { #address-cells = <2>; #size-cells = <2>; - compatible = "andestech,riscv-ae350-soc"; + compatible = "simple-bus"; ranges; - plic0: interrupt-controller@e4000000 { - compatible = "riscv,plic0"; - #address-cells = <2>; - #interrupt-cells = <2>; - interrupt-controller; - reg = <0x0 0xe4000000 0x0 0x2000000>; - riscv,ndev=<71>; - interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9>; - }; + plic0: interrupt-controller@e4000000 { + compatible = "riscv,plic0"; + #address-cells = <2>; + #interrupt-cells = <2>; + interrupt-controller; + reg = <0x0 0xe4000000 0x0 0x2000000>; + riscv,ndev=<71>; + interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 &CPU1_intc 11 &CPU1_intc 9>; + }; - plic1: interrupt-controller@e6400000 { - compatible = "riscv,plic1"; - #address-cells = <2>; - #interrupt-cells = <2>; - interrupt-controller; - reg = <0x0 0xe6400000 0x0 0x400000>; - riscv,ndev=<1>; - interrupts-extended = <&CPU0_intc 3>; - }; + plic1: interrupt-controller@e6400000 { + compatible = "riscv,plic1"; + #address-cells = <2>; + #interrupt-cells = <2>; + interrupt-controller; + reg = <0x0 0xe6400000 0x0 0x400000>; + riscv,ndev=<2>; + interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3>; + }; - plmt0@e6000000 { - compatible = "riscv,plmt0"; - interrupts-extended = <&CPU0_intc 7>; + plmt0@e6000000 { + compatible = "riscv,plmt0"; + interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7>; reg = <0x0 0xe6000000 0x0 0x100000>; }; }; @@ -146,6 +179,10 @@ interrupt-parent = <&plic0>; }; + pmu { + compatible = "riscv,base-pmu"; + }; + virtio_mmio@fe007000 { interrupts = <0x17 0x4>; interrupt-parent = <0x2>; diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 86136f5..644e6ba 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -46,6 +46,7 @@ #endif /* Interrupt Enable and Interrupt Pending flags */ +#define MIE_MSIE _AC(0x00000008, UL) /* Software Interrupt Enable */ #define SIE_SSIE _AC(0x00000002, UL) /* Software Interrupt Enable */ #define SIE_STIE _AC(0x00000020, UL) /* Timer Interrupt Enable */ diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h index a3a342c..dffcd45 100644 --- a/arch/riscv/include/asm/global_data.h +++ b/arch/riscv/include/asm/global_data.h @@ -10,12 +10,24 @@ #ifndef __ASM_GBL_DATA_H #define __ASM_GBL_DATA_H +#include <asm/smp.h> + /* Architecture-specific global data */ struct arch_global_data { long boot_hart; /* boot hart id */ #ifdef CONFIG_SIFIVE_CLINT void __iomem *clint; /* clint base address */ #endif +#ifdef CONFIG_ANDES_PLIC + void __iomem *plic; /* plic base address */ +#endif +#ifdef CONFIG_ANDES_PLMT + void __iomem *plmt; /* plmt base address */ +#endif +#ifdef CONFIG_SMP + struct ipi_data ipi[CONFIG_NR_CPUS]; +#endif + ulong available_harts; }; #include <asm-generic/global_data.h> diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h new file mode 100644 index 0000000..ced57de --- /dev/null +++ b/arch/riscv/include/asm/sbi.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2015 Regents of the University of California + * + * Taken from Linux arch/riscv/include/asm/sbi.h + */ + +#ifndef _ASM_RISCV_SBI_H +#define _ASM_RISCV_SBI_H + +#include <linux/types.h> + +#define SBI_SET_TIMER 0 +#define SBI_CONSOLE_PUTCHAR 1 +#define SBI_CONSOLE_GETCHAR 2 +#define SBI_CLEAR_IPI 3 +#define SBI_SEND_IPI 4 +#define SBI_REMOTE_FENCE_I 5 +#define SBI_REMOTE_SFENCE_VMA 6 +#define SBI_REMOTE_SFENCE_VMA_ASID 7 +#define SBI_SHUTDOWN 8 + +#define SBI_CALL(which, arg0, arg1, arg2) ({ \ + register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); \ + register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); \ + register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); \ + register uintptr_t a7 asm ("a7") = (uintptr_t)(which); \ + asm volatile ("ecall" \ + : "+r" (a0) \ + : "r" (a1), "r" (a2), "r" (a7) \ + : "memory"); \ + a0; \ +}) + +/* Lazy implementations until SBI is finalized */ +#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0) +#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0) +#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0) + +static inline void sbi_console_putchar(int ch) +{ + SBI_CALL_1(SBI_CONSOLE_PUTCHAR, ch); +} + +static inline int sbi_console_getchar(void) +{ + return SBI_CALL_0(SBI_CONSOLE_GETCHAR); +} + +static inline void sbi_set_timer(uint64_t stime_value) +{ +#if __riscv_xlen == 32 + SBI_CALL_2(SBI_SET_TIMER, stime_value, stime_value >> 32); +#else + SBI_CALL_1(SBI_SET_TIMER, stime_value); +#endif +} + +static inline void sbi_shutdown(void) +{ + SBI_CALL_0(SBI_SHUTDOWN); +} + +static inline void sbi_clear_ipi(void) +{ + SBI_CALL_0(SBI_CLEAR_IPI); +} + +static inline void sbi_send_ipi(const unsigned long *hart_mask) +{ + SBI_CALL_1(SBI_SEND_IPI, hart_mask); +} + +static inline void sbi_remote_fence_i(const unsigned long *hart_mask) +{ + SBI_CALL_1(SBI_REMOTE_FENCE_I, hart_mask); +} + +static inline void sbi_remote_sfence_vma(const unsigned long *hart_mask, + unsigned long start, + unsigned long size) +{ + SBI_CALL_1(SBI_REMOTE_SFENCE_VMA, hart_mask); +} + +static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, + unsigned long start, + unsigned long size, + unsigned long asid) +{ + SBI_CALL_1(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask); +} + +#endif diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h new file mode 100644 index 0000000..bc863fd --- /dev/null +++ b/arch/riscv/include/asm/smp.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Fraunhofer AISEC, + * Lukas Auer <lukas.auer@aisec.fraunhofer.de> + */ + +#ifndef _ASM_RISCV_SMP_H +#define _ASM_RISCV_SMP_H + +/** + * struct ipi_data - Inter-processor interrupt (IPI) data structure + * + * IPIs are used for SMP support to communicate to other harts what function to + * call. Functions are in the form + * void (*addr)(ulong hart, ulong arg0, ulong arg1). + * + * The function address and the two arguments, arg0 and arg1, are stored in the + * IPI data structure. The hart ID is inserted by the hart handling the IPI and + * calling the function. + * + * @addr: Address of function + * @arg0: First argument of function + * @arg1: Second argument of function + */ +struct ipi_data { + ulong addr; + ulong arg0; + ulong arg1; +}; + +/** + * handle_ipi() - interrupt handler for software interrupts + * + * The IPI interrupt handler must be called to handle software interrupts. It + * calls the function specified in the hart's IPI data structure. + * + * @hart: Hart ID of the current hart + */ +void handle_ipi(ulong hart); + +/** + * smp_call_function() - Call a function on all other harts + * + * Send IPIs with the specified function call to all harts. + * + * @addr: Address of function + * @arg0: First argument of function + * @arg1: Second argument of function + * @return 0 if OK, -ve on error + */ +int smp_call_function(ulong addr, ulong arg0, ulong arg1); + +#endif diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h index d311ee6..26a008c 100644 --- a/arch/riscv/include/asm/syscon.h +++ b/arch/riscv/include/asm/syscon.h @@ -8,12 +8,12 @@ /* * System controllers in a RISC-V system - * - * So far only SiFive's Core Local Interruptor (CLINT) is defined. */ enum { RISCV_NONE, RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */ + RISCV_SYSCON_PLIC, /* Platform Level Interrupt Controller (PLIC) */ + RISCV_SYSCON_PLMT, /* Platform Level Machine Timer (PLMT) */ }; #endif /* _ASM_SYSCON_H */ diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index edfa616..1c332db 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -11,9 +11,13 @@ obj-$(CONFIG_CMD_GO) += boot.o obj-y += cache.o obj-$(CONFIG_RISCV_RDTIME) += rdtime.o obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o +obj-$(CONFIG_ANDES_PLIC) += andes_plic.o +obj-$(CONFIG_ANDES_PLMT) += andes_plmt.o obj-y += interrupts.o obj-y += reset.o +obj-$(CONFIG_SBI_IPI) += sbi_ipi.o obj-y += setjmp.o +obj-$(CONFIG_SMP) += smp.o # For building EFI apps CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI) diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c new file mode 100644 index 0000000..2ffe49a --- /dev/null +++ b/arch/riscv/lib/andes_plic.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019, Rick Chen <rick@andestech.com> + * + * U-Boot syscon driver for Andes's Platform Level Interrupt Controller (PLIC). + * The PLIC block holds memory-mapped claim and pending registers + * associated with software interrupt. + */ + +#include <common.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/uclass-internal.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/syscon.h> +#include <cpu.h> + +/* pending register */ +#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + (hart) * 8) +/* enable register */ +#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80) +/* claim register */ +#define CLAIM_REG(base, hart) ((ulong)(base) + 0x200004 + (hart) * 0x1000) + +#define ENABLE_HART_IPI (0x80808080) +#define SEND_IPI_TO_HART(hart) (0x80 >> (hart)) + +DECLARE_GLOBAL_DATA_PTR; +static int init_plic(void); + +#define PLIC_BASE_GET(void) \ + do { \ + long *ret; \ + \ + if (!gd->arch.plic) { \ + ret = syscon_get_first_range(RISCV_SYSCON_PLIC); \ + if (IS_ERR(ret)) \ + return PTR_ERR(ret); \ + gd->arch.plic = ret; \ + init_plic(); \ + } \ + } while (0) + +static int enable_ipi(int harts) +{ + int i; + int en = ENABLE_HART_IPI; + + for (i = 0; i < harts; i++) { + en = en >> i; + writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic, i)); + } + + return 0; +} + +static int init_plic(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_find_first_device(UCLASS_CPU, &dev); + if (ret) + return ret; + + if (ret == 0 && dev) { + ret = cpu_get_count(dev); + if (ret < 0) + return ret; + + enable_ipi(ret); + return 0; + } + + return -ENODEV; +} + +int riscv_send_ipi(int hart) +{ + PLIC_BASE_GET(); + + writel(SEND_IPI_TO_HART(hart), + (void __iomem *)PENDING_REG(gd->arch.plic, gd->arch.boot_hart)); + + return 0; +} + +int riscv_clear_ipi(int hart) +{ + u32 source_id; + + PLIC_BASE_GET(); + + source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart)); + writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart)); + + return 0; +} + +static const struct udevice_id andes_plic_ids[] = { + { .compatible = "riscv,plic1", .data = RISCV_SYSCON_PLIC }, + { } +}; + +U_BOOT_DRIVER(andes_plic) = { + .name = "andes_plic", + .id = UCLASS_SYSCON, + .of_match = andes_plic_ids, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/arch/riscv/lib/andes_plmt.c b/arch/riscv/lib/andes_plmt.c new file mode 100644 index 0000000..84f4607 --- /dev/null +++ b/arch/riscv/lib/andes_plmt.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019, Rick Chen <rick@andestech.com> + * + * U-Boot syscon driver for Andes's Platform Level Machine Timer (PLMT). + * The PLMT block holds memory-mapped mtime register + * associated with timer tick. + */ + +#include <common.h> +#include <dm.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/syscon.h> + +/* mtime register */ +#define MTIME_REG(base) ((ulong)(base)) + +DECLARE_GLOBAL_DATA_PTR; + +#define PLMT_BASE_GET(void) \ + do { \ + long *ret; \ + \ + if (!gd->arch.plmt) { \ + ret = syscon_get_first_range(RISCV_SYSCON_PLMT); \ + if (IS_ERR(ret)) \ + return PTR_ERR(ret); \ + gd->arch.plmt = ret; \ + } \ + } while (0) + +int riscv_get_time(u64 *time) +{ + PLMT_BASE_GET(); + + *time = readq((void __iomem *)MTIME_REG(gd->arch.plmt)); + + return 0; +} + +static const struct udevice_id andes_plmt_ids[] = { + { .compatible = "riscv,plmt0", .data = RISCV_SYSCON_PLMT }, + { } +}; + +U_BOOT_DRIVER(andes_plmt) = { + .name = "andes_plmt", + .id = UCLASS_SYSCON, + .of_match = andes_plmt_ids, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c index e0b71f5..f998402 100644 --- a/arch/riscv/lib/asm-offsets.c +++ b/arch/riscv/lib/asm-offsets.c @@ -14,6 +14,7 @@ int main(void) { DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart)); + DEFINE(GD_AVAILABLE_HARTS, offsetof(gd_t, arch.available_harts)); return 0; } diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c index f36b870..efbd3e2 100644 --- a/arch/riscv/lib/bootm.c +++ b/arch/riscv/lib/bootm.c @@ -13,6 +13,7 @@ #include <image.h> #include <asm/byteorder.h> #include <asm/csr.h> +#include <asm/smp.h> #include <dm/device.h> #include <dm/root.h> #include <u-boot/zlib.h> @@ -81,6 +82,9 @@ static void boot_jump_linux(bootm_headers_t *images, int flag) { void (*kernel)(ulong hart, void *dtb); int fake = (flag & BOOTM_STATE_OS_FAKE_GO); +#ifdef CONFIG_SMP + int ret; +#endif kernel = (void (*)(ulong, void *))images->ep; @@ -92,8 +96,15 @@ static void boot_jump_linux(bootm_headers_t *images, int flag) announce_and_cleanup(fake); if (!fake) { - if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) + if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) { +#ifdef CONFIG_SMP + ret = smp_call_function(images->ep, + (ulong)images->ft_addr, 0); + if (ret) + hang(); +#endif kernel(gd->arch.boot_hart, images->ft_addr); + } } } diff --git a/arch/riscv/lib/sbi_ipi.c b/arch/riscv/lib/sbi_ipi.c new file mode 100644 index 0000000..170346d --- /dev/null +++ b/arch/riscv/lib/sbi_ipi.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Fraunhofer AISEC, + * Lukas Auer <lukas.auer@aisec.fraunhofer.de> + */ + +#include <common.h> +#include <asm/sbi.h> + +int riscv_send_ipi(int hart) +{ + ulong mask; + + mask = 1UL << hart; + sbi_send_ipi(&mask); + + return 0; +} + +int riscv_clear_ipi(int hart) +{ + sbi_clear_ipi(); + + return 0; +} diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c new file mode 100644 index 0000000..caa292c --- /dev/null +++ b/arch/riscv/lib/smp.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Fraunhofer AISEC, + * Lukas Auer <lukas.auer@aisec.fraunhofer.de> + */ + +#include <common.h> +#include <dm.h> +#include <asm/barrier.h> +#include <asm/smp.h> + +DECLARE_GLOBAL_DATA_PTR; + +/** + * riscv_send_ipi() - Send inter-processor interrupt (IPI) + * + * Platform code must provide this function. + * + * @hart: Hart ID of receiving hart + * @return 0 if OK, -ve on error + */ +extern int riscv_send_ipi(int hart); + +/** + * riscv_clear_ipi() - Clear inter-processor interrupt (IPI) + * + * Platform code must provide this function. + * + * @hart: Hart ID of hart to be cleared + * @return 0 if OK, -ve on error + */ +extern int riscv_clear_ipi(int hart); + +static int send_ipi_many(struct ipi_data *ipi) +{ + ofnode node, cpus; + u32 reg; + int ret; + + cpus = ofnode_path("/cpus"); + if (!ofnode_valid(cpus)) { + pr_err("Can't find cpus node!\n"); + return -EINVAL; + } + + ofnode_for_each_subnode(node, cpus) { + /* skip if hart is marked as not available in the device tree */ + if (!ofnode_is_available(node)) + continue; + + /* read hart ID of CPU */ + ret = ofnode_read_u32(node, "reg", ®); + if (ret) + continue; + + /* skip if it is the hart we are running on */ + if (reg == gd->arch.boot_hart) + continue; + + if (reg >= CONFIG_NR_CPUS) { + pr_err("Hart ID %d is out of range, increase CONFIG_NR_CPUS\n", + reg); + continue; + } + + /* skip if hart is not available */ + if (!(gd->arch.available_harts & (1 << reg))) + continue; + + gd->arch.ipi[reg].addr = ipi->addr; + gd->arch.ipi[reg].arg0 = ipi->arg0; + gd->arch.ipi[reg].arg1 = ipi->arg1; + + ret = riscv_send_ipi(reg); + if (ret) { + pr_err("Cannot send IPI to hart %d\n", reg); + return ret; + } + } + + return 0; +} + +void handle_ipi(ulong hart) +{ + int ret; + void (*smp_function)(ulong hart, ulong arg0, ulong arg1); + + if (hart >= CONFIG_NR_CPUS) + return; + + ret = riscv_clear_ipi(hart); + if (ret) { + pr_err("Cannot clear IPI of hart %ld\n", hart); + return; + } + + __smp_mb(); + + smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr; + invalidate_icache_all(); + + smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1); +} + +int smp_call_function(ulong addr, ulong arg0, ulong arg1) +{ + int ret = 0; + struct ipi_data ipi; + + ipi.addr = addr; + ipi.arg0 = arg0; + ipi.arg1 = arg1; + + ret = send_ipi_many(&ipi); + + return ret; +} diff --git a/board/AndesTech/ax25-ae350/Kconfig b/board/AndesTech/ax25-ae350/Kconfig index 44cb302..5e682b6 100644 --- a/board/AndesTech/ax25-ae350/Kconfig +++ b/board/AndesTech/ax25-ae350/Kconfig @@ -24,5 +24,6 @@ config ENV_OFFSET config BOARD_SPECIFIC_OPTIONS # dummy def_bool y select RISCV_NDS + imply SMP endif diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig index 88d07d5..cf057e7 100644 --- a/board/emulation/qemu-riscv/Kconfig +++ b/board/emulation/qemu-riscv/Kconfig @@ -34,5 +34,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy imply BOARD_LATE_INIT imply OF_BOARD_SETUP imply SIFIVE_SERIAL + imply SMP endif diff --git a/board/gardena/smart-gateway-at91sam/Kconfig b/board/gardena/smart-gateway-at91sam/Kconfig new file mode 100644 index 0000000..ea2b5ff --- /dev/null +++ b/board/gardena/smart-gateway-at91sam/Kconfig @@ -0,0 +1,12 @@ +if TARGET_GARDENA_SMART_GATEWAY_AT91SAM + +config SYS_BOARD + default "smart-gateway-at91sam" + +config SYS_VENDOR + default "gardena" + +config SYS_CONFIG_NAME + default "gardena-smart-gateway-at91sam" + +endif diff --git a/board/gardena/smart-gateway-at91sam/MAINTAINERS b/board/gardena/smart-gateway-at91sam/MAINTAINERS new file mode 100644 index 0000000..a5e4c71 --- /dev/null +++ b/board/gardena/smart-gateway-at91sam/MAINTAINERS @@ -0,0 +1,7 @@ +GARDENA_SMART_GATEWAY_AT91SAM BOARD +M: Stefan Roese <sr@denx.de> +S: Maintained +F: board/gardena/smart-gateway-at91sam/ +F: include/configs/gardena-smart-gateway-at91sam.h +F: configs/gardena-smart-gateway-at91sam_defconfig +F: arch/arm/dts/gardena-smart-gateway-at91sam.dts diff --git a/board/gardena/smart-gateway-at91sam/Makefile b/board/gardena/smart-gateway-at91sam/Makefile new file mode 100644 index 0000000..a2ed79f --- /dev/null +++ b/board/gardena/smart-gateway-at91sam/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += board.o + +ifdef CONFIG_SPL_BUILD +obj-y += spl.o +endif diff --git a/board/gardena/smart-gateway-at91sam/board.c b/board/gardena/smart-gateway-at91sam/board.c new file mode 100644 index 0000000..6a1389e --- /dev/null +++ b/board/gardena/smart-gateway-at91sam/board.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2012 Atmel Corporation + * Copyright (C) 2019 Stefan Roese <sr@denx.de> + */ + +#include <common.h> +#include <debug_uart.h> +#include <led.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/clk.h> + +DECLARE_GLOBAL_DATA_PTR; + +static void at91_prepare_cpu_var(void) +{ + env_set("cpu", get_cpu_name()); +} + +int board_late_init(void) +{ + at91_prepare_cpu_var(); + + if (IS_ENABLED(CONFIG_LED)) + led_default_state(); + + return 0; +} + +#ifdef CONFIG_DEBUG_UART_BOARD_INIT +void board_debug_uart_init(void) +{ + at91_seriald_hw_init(); +} +#endif + +int board_early_init_f(void) +{ +#ifdef CONFIG_DEBUG_UART + debug_uart_init(); +#endif + return 0; +} + +int board_init(void) +{ + /* Address of boot parameters */ + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; + + return 0; +} + +int dram_init(void) +{ + gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, + CONFIG_SYS_SDRAM_SIZE); + + return 0; +} diff --git a/board/gardena/smart-gateway-at91sam/spl.c b/board/gardena/smart-gateway-at91sam/spl.c new file mode 100644 index 0000000..3ab6760 --- /dev/null +++ b/board/gardena/smart-gateway-at91sam/spl.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2012 Atmel Corporation + * Copyright (C) 2019 Stefan Roese <sr@denx.de> + */ + +#include <common.h> +#include <nand.h> +#include <spl.h> +#include <asm/arch/at91sam9x5_matrix.h> +#include <asm/arch/at91sam9_smc.h> +#include <asm/arch/atmel_mpddrc.h> +#include <asm/arch/clk.h> +#include <asm/arch/gpio.h> + +static void at91sam9x5ek_nand_hw_init(void) +{ + struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC; + struct at91_matrix *matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX; + unsigned long csa; + + /* Enable CS3 */ + csa = readl(&matrix->ebicsa); + csa |= AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA; + + /* NAND flash on D16 */ + csa |= AT91_MATRIX_NFD0_ON_D16; + + /* Configure IO drive */ + csa &= ~AT91_MATRIX_EBI_EBI_IOSR_NORMAL; + + writel(csa, &matrix->ebicsa); + + /* Configure SMC CS3 for NAND/SmartMedia */ + writel(AT91_SMC_SETUP_NWE(1) | AT91_SMC_SETUP_NCS_WR(0) | + AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(0), + &smc->cs[3].setup); + writel(AT91_SMC_PULSE_NWE(3) | AT91_SMC_PULSE_NCS_WR(5) | + AT91_SMC_PULSE_NRD(4) | AT91_SMC_PULSE_NCS_RD(6), + &smc->cs[3].pulse); + writel(AT91_SMC_CYCLE_NWE(5) | AT91_SMC_CYCLE_NRD(6), + &smc->cs[3].cycle); + writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE | + AT91_SMC_MODE_EXNW_DISABLE | +#ifdef CONFIG_SYS_NAND_DBW_16 + AT91_SMC_MODE_DBW_16 | +#else /* CONFIG_SYS_NAND_DBW_8 */ + AT91_SMC_MODE_DBW_8 | +#endif + AT91_SMC_MODE_TDF_CYCLE(1), + &smc->cs[3].mode); + + at91_periph_clk_enable(ATMEL_ID_PIOCD); + + /* Configure RDY/BSY */ + at91_set_gpio_input(CONFIG_SYS_NAND_READY_PIN, 1); + + /* Enable NandFlash */ + at91_set_gpio_output(CONFIG_SYS_NAND_ENABLE_PIN, 1); + + at91_pio3_set_a_periph(AT91_PIO_PORTD, 0, 1); /* NAND OE */ + at91_pio3_set_a_periph(AT91_PIO_PORTD, 1, 1); /* NAND WE */ + at91_pio3_set_a_periph(AT91_PIO_PORTD, 2, 1); /* NAND ALE */ + at91_pio3_set_a_periph(AT91_PIO_PORTD, 3, 1); /* NAND CLE */ + at91_pio3_set_a_periph(AT91_PIO_PORTD, 6, 1); + at91_pio3_set_a_periph(AT91_PIO_PORTD, 7, 1); + at91_pio3_set_a_periph(AT91_PIO_PORTD, 8, 1); + at91_pio3_set_a_periph(AT91_PIO_PORTD, 9, 1); + at91_pio3_set_a_periph(AT91_PIO_PORTD, 10, 1); + at91_pio3_set_a_periph(AT91_PIO_PORTD, 11, 1); + at91_pio3_set_a_periph(AT91_PIO_PORTD, 12, 1); + at91_pio3_set_a_periph(AT91_PIO_PORTD, 13, 1); +} + +void at91_spl_board_init(void) +{ + at91sam9x5ek_nand_hw_init(); +} + +static void ddr2_conf(struct atmel_mpddrc_config *ddr2) +{ + ddr2->md = (ATMEL_MPDDRC_MD_DBW_16_BITS | ATMEL_MPDDRC_MD_DDR2_SDRAM); + + ddr2->cr = (ATMEL_MPDDRC_CR_NC_COL_10 | + ATMEL_MPDDRC_CR_NR_ROW_13 | + ATMEL_MPDDRC_CR_CAS_DDR_CAS3 | + ATMEL_MPDDRC_CR_NB_8BANKS | + ATMEL_MPDDRC_CR_DECOD_INTERLEAVED); + + ddr2->rtr = 0x411; + + ddr2->tpr0 = (6 << ATMEL_MPDDRC_TPR0_TRAS_OFFSET | + 2 << ATMEL_MPDDRC_TPR0_TRCD_OFFSET | + 2 << ATMEL_MPDDRC_TPR0_TWR_OFFSET | + 8 << ATMEL_MPDDRC_TPR0_TRC_OFFSET | + 2 << ATMEL_MPDDRC_TPR0_TRP_OFFSET | + 2 << ATMEL_MPDDRC_TPR0_TRRD_OFFSET | + 2 << ATMEL_MPDDRC_TPR0_TWTR_OFFSET | + 2 << ATMEL_MPDDRC_TPR0_TMRD_OFFSET); + + ddr2->tpr1 = (2 << ATMEL_MPDDRC_TPR1_TXP_OFFSET | + 200 << ATMEL_MPDDRC_TPR1_TXSRD_OFFSET | + 19 << ATMEL_MPDDRC_TPR1_TXSNR_OFFSET | + 18 << ATMEL_MPDDRC_TPR1_TRFC_OFFSET); + + ddr2->tpr2 = (7 << ATMEL_MPDDRC_TPR2_TFAW_OFFSET | + 2 << ATMEL_MPDDRC_TPR2_TRTP_OFFSET | + 3 << ATMEL_MPDDRC_TPR2_TRPA_OFFSET | + 7 << ATMEL_MPDDRC_TPR2_TXARDS_OFFSET | + 2 << ATMEL_MPDDRC_TPR2_TXARD_OFFSET); +} + +void mem_init(void) +{ + struct at91_matrix *matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX; + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + struct atmel_mpddrc_config ddr2; + unsigned long csa; + + ddr2_conf(&ddr2); + + /* Enable DDR2 clock */ + writel(AT91_PMC_DDR, &pmc->scer); + + /* Chip select 1 is for DDR2/SDRAM */ + csa = readl(&matrix->ebicsa); + csa |= AT91_MATRIX_EBI_CS1A_SDRAMC; + csa &= ~AT91_MATRIX_EBI_DBPU_OFF; + csa |= AT91_MATRIX_EBI_DBPD_OFF; + csa |= AT91_MATRIX_EBI_EBI_IOSR_NORMAL; + writel(csa, &matrix->ebicsa); + + /* DDRAM2 Controller initialize */ + ddr2_init(ATMEL_BASE_DDRSDRC, ATMEL_BASE_CS1, &ddr2); +} diff --git a/board/ronetix/pm9g45/pm9g45.c b/board/ronetix/pm9g45/pm9g45.c index 17e520a..c5d28c6 100644 --- a/board/ronetix/pm9g45/pm9g45.c +++ b/board/ronetix/pm9g45/pm9g45.c @@ -124,7 +124,7 @@ int board_init(void) /* arch number of AT91SAM9M10G45EK-Board */ gd->bd->bi_arch_number = MACH_TYPE_PM9G45; /* adress of boot parameters */ - gd->bd->bi_boot_params = PHYS_SDRAM + 0x100; + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; #ifdef CONFIG_CMD_NAND pm9g45_nand_hw_init(); @@ -139,15 +139,15 @@ int board_init(void) int dram_init(void) { /* dram_init must store complete ramsize in gd->ram_size */ - gd->ram_size = get_ram_size((void *)PHYS_SDRAM, - PHYS_SDRAM_SIZE); + gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, + CONFIG_SYS_SDRAM_SIZE); return 0; } int dram_init_banksize(void) { - gd->bd->bi_dram[0].start = PHYS_SDRAM; - gd->bd->bi_dram[0].size = PHYS_SDRAM_SIZE; + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; + gd->bd->bi_dram[0].size = CONFIG_SYS_SDRAM_SIZE; return 0; } diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig index 6be3d88..f464379 100644 --- a/board/sifive/fu540/Kconfig +++ b/board/sifive/fu540/Kconfig @@ -38,5 +38,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy imply PHY_LIB imply PHY_MSCC imply SIFIVE_SERIAL + imply SMP endif @@ -76,6 +76,20 @@ U_BOOT_CMD( " device type 'interface' instance 'dev'." ) +static int do_ln_wrapper(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + return do_ln(cmdtp, flag, argc, argv, FS_TYPE_ANY); +} + +U_BOOT_CMD( + ln, 5, 1, do_ln_wrapper, + "Create a symbolic link", + "<interface> <dev[:part]> target linkname\n" + " - create a symbolic link to 'target' with the name 'linkname' on\n" + " device type 'interface' instance 'dev'." +) + static int do_fstype_wrapper(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { diff --git a/configs/ae350_rv32_defconfig b/configs/ae350_rv32_defconfig index 6e0be88..f029455 100644 --- a/configs/ae350_rv32_defconfig +++ b/configs/ae350_rv32_defconfig @@ -34,4 +34,3 @@ CONFIG_BAUDRATE=38400 CONFIG_SYS_NS16550=y CONFIG_SPI=y CONFIG_ATCSPI200_SPI=y -CONFIG_ATCPIT100_TIMER=y diff --git a/configs/ae350_rv64_defconfig b/configs/ae350_rv64_defconfig index b472a76..98635a2 100644 --- a/configs/ae350_rv64_defconfig +++ b/configs/ae350_rv64_defconfig @@ -35,4 +35,3 @@ CONFIG_BAUDRATE=38400 CONFIG_SYS_NS16550=y CONFIG_SPI=y CONFIG_ATCSPI200_SPI=y -CONFIG_ATCPIT100_TIMER=y diff --git a/configs/gardena-smart-gateway-at91sam_defconfig b/configs/gardena-smart-gateway-at91sam_defconfig new file mode 100644 index 0000000..b395a5a --- /dev/null +++ b/configs/gardena-smart-gateway-at91sam_defconfig @@ -0,0 +1,83 @@ +CONFIG_ARM=y +CONFIG_SYS_THUMB_BUILD=y +CONFIG_ARCH_AT91=y +CONFIG_SYS_TEXT_BASE=0x22900000 +CONFIG_TARGET_GARDENA_SMART_GATEWAY_AT91SAM=y +CONFIG_SPL_GPIO_SUPPORT=y +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SPL_SERIAL_SUPPORT=y +CONFIG_SPL_SYS_MALLOC_F_LEN=0x1000 +CONFIG_SPL=y +CONFIG_DEBUG_UART_BOARD_INIT=y +CONFIG_DEBUG_UART_BASE=0xfffff200 +CONFIG_DEBUG_UART_CLOCK=132000000 +CONFIG_SMBIOS_PRODUCT_NAME="at91sam9x5ek" +CONFIG_DEBUG_UART=y +CONFIG_NR_DRAM_BANKS=1 +CONFIG_FIT=y +CONFIG_NAND_BOOT=y +CONFIG_BOOTDELAY=3 +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256k(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs rw" +CONFIG_SYS_CONSOLE_IS_IN_ENV=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_ARCH_EARLY_INIT_R=y +CONFIG_SPL_SYS_MALLOC_SIMPLE=y +CONFIG_SPL_SEPARATE_BSS=y +# CONFIG_TPL_BANNER_PRINT is not set +# CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR is not set +CONFIG_SPL_NAND_SUPPORT=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_BOOTZ=y +CONFIG_CMD_DM=y +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_GPIO=y +CONFIG_CMD_MTD=y +CONFIG_CMD_NAND=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_FAT=y +CONFIG_CMD_MTDPARTS=y +CONFIG_MTDIDS_DEFAULT="nand0=nand0" +CONFIG_MTDPARTS_DEFAULT="nand0:1536k(uboot),1024k(unused),512k(dtb_old),4608k(kernel_old),86528k(ubi),-(rootfs_old)" +CONFIG_CMD_UBI=y +CONFIG_OF_CONTROL=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_DEFAULT_DEVICE_TREE="at91sam9g25-gardena-smart-gateway" +CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clocks clock-names interrupts interrupt-parent interrupts-extended dmas dma-names" +CONFIG_ENV_IS_IN_UBI=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_DM=y +CONFIG_SPL_DM=y +CONFIG_BLK=y +CONFIG_CLK=y +CONFIG_CLK_AT91=y +CONFIG_DM_GPIO=y +CONFIG_AT91_GPIO=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +# CONFIG_MMC is not set +CONFIG_NAND_ATMEL=y +CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER=y +# CONFIG_CONFIG_UBI_SILENCE_MSG is not set +CONFIG_DM_ETH=y +CONFIG_MACB=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_AT91=y +CONFIG_DM_SERIAL=y +CONFIG_DEBUG_UART_ATMEL=y +CONFIG_ATMEL_USART=y +CONFIG_TIMER=y +CONFIG_SPL_TIMER=y +CONFIG_ATMEL_PIT_TIMER=y +# CONFIG_SYS_WHITE_ON_BLACK is not set +CONFIG_WATCHDOG=y +CONFIG_WDT=y +CONFIG_WDT_AT91=y +# CONFIG_UBIFS_SILENCE_MSG is not set +CONFIG_USE_TINY_PRINTF=y diff --git a/configs/pm9g45_defconfig b/configs/pm9g45_defconfig index 928e446..c3f7e14 100644 --- a/configs/pm9g45_defconfig +++ b/configs/pm9g45_defconfig @@ -2,27 +2,57 @@ CONFIG_ARM=y CONFIG_ARCH_AT91=y CONFIG_SYS_TEXT_BASE=0x73f00000 CONFIG_TARGET_PM9G45=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_DEBUG_UART_BOARD_INIT=y +CONFIG_DEBUG_UART_BASE=0xffffee00 +CONFIG_DEBUG_UART_CLOCK=132000000 +CONFIG_DEBUG_UART=y CONFIG_NR_DRAM_BANKS=1 -CONFIG_SYS_EXTRA_OPTIONS="AT91SAM9G45" +CONFIG_NAND_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="fbcon=rotate:3 console=tty0 console=ttyS0,115200 root=/dev/mtdblock4 mtdparts=atmel_nand:128k(bootstrap)ro,256k(uboot)ro,1664k(env),2M(linux)ro,-(root) rw rootfstype=jffs2" -# CONFIG_DISPLAY_CPUINFO is not set +# CONFIG_CONSOLE_MUX is not set +CONFIG_SYS_CONSOLE_IS_IN_ENV=y # CONFIG_DISPLAY_BOARDINFO is not set -CONFIG_BOARD_EARLY_INIT_F=y CONFIG_HUSH_PARSER=y CONFIG_SYS_PROMPT="U-Boot> " +# CONFIG_CMD_BDI is not set +CONFIG_CMD_BOOTZ=y +# CONFIG_CMD_IMI is not set # CONFIG_CMD_FLASH is not set +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_MMC=y CONFIG_CMD_NAND=y CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y CONFIG_CMD_PING=y -CONFIG_CMD_CACHE=y -CONFIG_CMD_JFFS2=y +CONFIG_CMD_FAT=y +CONFIG_OF_CONTROL=y +CONFIG_DEFAULT_DEVICE_TREE="at91sam9m10g45ek" CONFIG_ENV_IS_IN_NAND=y -# CONFIG_MMC is not set -CONFIG_NAND=y +CONFIG_DM=y +CONFIG_CLK=y +CONFIG_CLK_AT91=y +CONFIG_DM_GPIO=y +CONFIG_AT91_GPIO=y +CONFIG_DM_MMC=y +CONFIG_GENERIC_ATMEL_MCI=y CONFIG_NAND_ATMEL=y +CONFIG_DM_ETH=y +CONFIG_MACB=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_AT91=y +CONFIG_DM_SERIAL=y +CONFIG_DEBUG_UART_ATMEL=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_ATMEL_USART=y +CONFIG_TIMER=y +CONFIG_ATMEL_PIT_TIMER=y CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y CONFIG_USB_STORAGE=y diff --git a/configs/smartweb_defconfig b/configs/smartweb_defconfig index 7c7220a..807a569 100644 --- a/configs/smartweb_defconfig +++ b/configs/smartweb_defconfig @@ -59,6 +59,5 @@ CONFIG_USB_ETHER_ASIX=y CONFIG_USB_ETHER_MCS7830=y CONFIG_WDT=y CONFIG_WDT_AT91=y -CONFIG_AT91_HW_WDT_TIMEOUT=y CONFIG_SPL_TINY_MEMSET=y # CONFIG_EFI_LOADER is not set diff --git a/configs/taurus_defconfig b/configs/taurus_defconfig index 022b0b6..d69f489 100644 --- a/configs/taurus_defconfig +++ b/configs/taurus_defconfig @@ -62,5 +62,4 @@ CONFIG_USB_GADGET_PRODUCT_NUM=0x02d2 CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_WDT=y CONFIG_WDT_AT91=y -CONFIG_AT91_HW_WDT_TIMEOUT=y CONFIG_USE_TINY_PRINTF=y diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 8ad0c62..2c2faaf 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -18,6 +18,7 @@ void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr); #include <hexdump.h> +#ifndef __UBOOT__ #define ubi_assert(expr) do { \ if (unlikely(!(expr))) { \ pr_crit("UBI assert failed in %s at %u (pid %d)\n", \ @@ -25,6 +26,15 @@ void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr); dump_stack(); \ } \ } while (0) +#else +#define ubi_assert(expr) do { \ + if (unlikely(!(expr))) { \ + pr_debug("UBI assert failed in %s at %u\n", \ + __func__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) +#endif #define ubi_dbg_print_hex_dump(ps, pt, r, g, b, len, a) \ print_hex_dump(ps, pt, r, g, b, len, a) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 182331f..7261416 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -550,8 +550,14 @@ static int macb_phy_init(struct macb_device *macb, const char *name) for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { status = macb_mdio_read(macb, MII_BMSR); - if (status & BMSR_LSTATUS) + if (status & BMSR_LSTATUS) { + /* + * Delay a bit after the link is established, + * so that the next xfer does not fail + */ + mdelay(10); break; + } udelay(100); } } diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 4bdad62..27f274f 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -37,6 +37,9 @@ struct at91_pinctrl_priv { #define OUTPUT BIT(7) #define OUTPUT_VAL_SHIFT 8 #define OUTPUT_VAL (0x1 << OUTPUT_VAL_SHIFT) +#define SLEWRATE_SHIFT 9 +#define SLEWRATE_MASK 0x1 +#define SLEWRATE (SLEWRATE_MASK << SLEWRATE_SHIFT) #define DEBOUNCE BIT(16) #define DEBOUNCE_VAL_SHIFT 17 #define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT) @@ -50,10 +53,22 @@ struct at91_pinctrl_priv { * DRIVE_STRENGTH_DEFAULT is just a placeholder to avoid changing the drive * strength when there is no dt config for it. */ -#define DRIVE_STRENGTH_DEFAULT (0 << DRIVE_STRENGTH_SHIFT) -#define DRIVE_STRENGTH_LOW (1 << DRIVE_STRENGTH_SHIFT) -#define DRIVE_STRENGTH_MED (2 << DRIVE_STRENGTH_SHIFT) -#define DRIVE_STRENGTH_HI (3 << DRIVE_STRENGTH_SHIFT) +enum drive_strength_bit { + DRIVE_STRENGTH_BIT_DEF, + DRIVE_STRENGTH_BIT_LOW, + DRIVE_STRENGTH_BIT_MED, + DRIVE_STRENGTH_BIT_HI, +}; + +#define DRIVE_STRENGTH_BIT_MSK(name) (DRIVE_STRENGTH_BIT_##name << \ + DRIVE_STRENGTH_SHIFT) + +enum slewrate_bit { + SLEWRATE_BIT_DIS, + SLEWRATE_BIT_ENA, +}; + +#define SLEWRATE_BIT_MSK(name) (SLEWRATE_BIT_##name << SLEWRATE_SHIFT) enum at91_mux { AT91_MUX_GPIO = 0, @@ -90,6 +105,7 @@ struct at91_pinctrl_mux_ops { void (*disable_schmitt_trig)(struct at91_port *pio, u32 mask); void (*set_drivestrength)(struct at91_port *pio, u32 pin, u32 strength); + void (*set_slewrate)(struct at91_port *pio, u32 pin, u32 slewrate); }; static u32 two_bit_pin_value_shift_amount(u32 pin) @@ -238,11 +254,52 @@ static void at91_mux_sam9x5_set_drivestrength(struct at91_port *pio, /* strength is inverse on SAM9x5s with our defines * 0 = hi, 1 = med, 2 = low, 3 = rsvd */ - setting = DRIVE_STRENGTH_HI - setting; + setting = DRIVE_STRENGTH_BIT_MSK(HI) - setting; set_drive_strength(reg, pin, setting); } +static void at91_mux_sam9x60_set_drivestrength(struct at91_port *pio, u32 pin, + u32 setting) +{ + void *reg = &pio->driver12; + u32 tmp; + + if (setting <= DRIVE_STRENGTH_BIT_DEF || + setting == DRIVE_STRENGTH_BIT_MED || + setting > DRIVE_STRENGTH_BIT_HI) + return; + + tmp = readl(reg); + + /* Strength is 0: low, 1: hi */ + if (setting == DRIVE_STRENGTH_BIT_LOW) + tmp &= ~BIT(pin); + else + tmp |= BIT(pin); + + writel(tmp, reg); +} + +static void at91_mux_sam9x60_set_slewrate(struct at91_port *pio, u32 pin, + u32 setting) +{ + void *reg = &pio->reserved12[3]; + u32 tmp; + + if (setting < SLEWRATE_BIT_DIS || setting > SLEWRATE_BIT_ENA) + return; + + tmp = readl(reg); + + if (setting == SLEWRATE_BIT_DIS) + tmp &= ~BIT(pin); + else + tmp |= BIT(pin); + + writel(tmp, reg); +} + static struct at91_pinctrl_mux_ops at91rm9200_ops = { .mux_A_periph = at91_mux_set_A_periph, .mux_B_periph = at91_mux_set_B_periph, @@ -273,6 +330,19 @@ static struct at91_pinctrl_mux_ops sama5d3_ops = { .set_drivestrength = at91_mux_sama5d3_set_drivestrength, }; +static struct at91_pinctrl_mux_ops sam9x60_ops = { + .mux_A_periph = at91_mux_pio3_set_A_periph, + .mux_B_periph = at91_mux_pio3_set_B_periph, + .mux_C_periph = at91_mux_pio3_set_C_periph, + .mux_D_periph = at91_mux_pio3_set_D_periph, + .set_deglitch = at91_mux_pio3_set_deglitch, + .set_debounce = at91_mux_pio3_set_debounce, + .set_pulldown = at91_mux_pio3_set_pulldown, + .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, + .set_drivestrength = at91_mux_sam9x60_set_drivestrength, + .set_slewrate = at91_mux_sam9x60_set_slewrate, +}; + static void at91_mux_gpio_disable(struct at91_port *pio, u32 mask) { writel(mask, &pio->pdr); @@ -339,6 +409,9 @@ static int at91_pinconf_set(struct at91_pinctrl_mux_ops *ops, if (ops->set_drivestrength) ops->set_drivestrength(pio, pin, (config & DRIVE_STRENGTH) >> DRIVE_STRENGTH_SHIFT); + if (ops->set_slewrate) + ops->set_slewrate(pio, pin, + (config & SLEWRATE) >> SLEWRATE_SHIFT); return 0; } @@ -440,6 +513,7 @@ static const struct udevice_id at91_pinctrl_match[] = { { .compatible = "atmel,sama5d3-pinctrl", .data = (ulong)&sama5d3_ops }, { .compatible = "atmel,at91sam9x5-pinctrl", .data = (ulong)&at91sam9x5_ops }, { .compatible = "atmel,at91rm9200-pinctrl", .data = (ulong)&at91rm9200_ops }, + { .compatible = "microchip,sam9x60-pinctrl", .data = (ulong)&sam9x60_ops }, {} }; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 887cd68..fcbb0a8 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -508,6 +508,15 @@ config ATMEL_USART configured in the device tree, and input clock frequency can be got from the clk node. +config SPL_UART_CLOCK + int "SPL fixed UART input clock" + depends on ATMEL_USART && SPL && !SPL_CLK + default 132096000 if ARCH_AT91 + help + Provide a fixed clock value as input to the UART controller. This + might be needed on platforms which can't enable CONFIG_SPL_CLK + because of SPL image size restrictions. + config BCM283X_MU_SERIAL bool "Support for BCM283x Mini-UART" depends on DM_SERIAL && ARCH_BCM283X diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c index aa8cdff..c450a4e 100644 --- a/drivers/serial/atmel_usart.c +++ b/drivers/serial/atmel_usart.c @@ -218,6 +218,17 @@ static const struct dm_serial_ops atmel_serial_ops = { .setbrg = atmel_serial_setbrg, }; +#if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_CLK) +static int atmel_serial_enable_clk(struct udevice *dev) +{ + struct atmel_serial_priv *priv = dev_get_priv(dev); + + /* Use fixed clock value in SPL */ + priv->usart_clk_rate = CONFIG_SPL_UART_CLOCK; + + return 0; +} +#else static int atmel_serial_enable_clk(struct udevice *dev) { struct atmel_serial_priv *priv = dev_get_priv(dev); @@ -245,6 +256,7 @@ static int atmel_serial_enable_clk(struct udevice *dev) return 0; } +#endif static int atmel_serial_probe(struct udevice *dev) { diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 115fc45..34e78be 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -139,10 +139,6 @@ config WDT_AT91 Select this to enable Microchip watchdog timer, which can be found on some AT91 devices. -config AT91_HW_WDT_TIMEOUT - bool "AT91 watchdog timeout specified" - depends on WDT_AT91 - config WDT_MT7621 bool "MediaTek MT7621 watchdog timer support" depends on WDT && ARCH_MT7620 diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index 13f8772..000769d 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -17,6 +17,7 @@ #include <asm/io.h> #include <asm/arch/at91_wdt.h> #include <common.h> +#include <div64.h> #include <dm.h> #include <errno.h> #include <wdt.h> @@ -30,28 +31,21 @@ DECLARE_GLOBAL_DATA_PTR; */ #define WDT_SEC2TICKS(s) (((s) << 8) - 1) -/* Hardware timeout in seconds */ -#define WDT_MAX_TIMEOUT 16 -#define WDT_MIN_TIMEOUT 0 -#define WDT_DEFAULT_TIMEOUT 2 - -struct at91_wdt_priv { - void __iomem *regs; - u32 regval; - u32 timeout; -}; - /* * Set the watchdog time interval in 1/256Hz (write-once) * Counter is 12 bit. */ -static int at91_wdt_start(struct udevice *dev, u64 timeout_s, ulong flags) +static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) { struct at91_wdt_priv *priv = dev_get_priv(dev); - u32 timeout = WDT_SEC2TICKS(timeout_s); + u64 timeout; + u32 ticks; - if (timeout_s > WDT_MAX_TIMEOUT || timeout_s < WDT_MIN_TIMEOUT) - timeout = priv->timeout; + /* Calculate timeout in seconds and the resulting ticks */ + timeout = timeout_ms; + do_div(timeout, 1000); + timeout = min_t(u64, timeout, WDT_MAX_TIMEOUT); + ticks = WDT_SEC2TICKS(timeout); /* Check if disabled */ if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) { @@ -65,12 +59,10 @@ static int at91_wdt_start(struct udevice *dev, u64 timeout_s, ulong flags) * Since WDV is a 12-bit counter, the maximum period is * 4096 / 256 = 16 seconds. */ - priv->regval = AT91_WDT_MR_WDRSTEN /* causes watchdog reset */ | AT91_WDT_MR_WDDBGHLT /* disabled in debug mode */ | AT91_WDT_MR_WDD(0xfff) /* restart at any time */ - | AT91_WDT_MR_WDV(timeout); /* timer value */ - + | AT91_WDT_MR_WDV(ticks); /* timer value */ writel(priv->regval, priv->regs + AT91_WDT_MR); return 0; @@ -115,10 +107,12 @@ static int at91_wdt_probe(struct udevice *dev) if (!priv->regs) return -EINVAL; -#ifdef CONFIG_AT91_HW_WDT_TIMEOUT +#if CONFIG_IS_ENABLED(OF_CONTROL) priv->timeout = dev_read_u32_default(dev, "timeout-sec", WDT_DEFAULT_TIMEOUT); debug("%s: timeout %d", __func__, priv->timeout); +#else + priv->timeout = WDT_DEFAULT_TIMEOUT; #endif debug("%s: Probing wdt%u\n", __func__, dev->seq); @@ -60,7 +60,7 @@ static int env_ext4_save(void) } err = ext4fs_write(CONFIG_ENV_EXT4_FILE, (void *)&env_new, - sizeof(env_t)); + sizeof(env_t), FILETYPE_REG); ext4fs_close(); if (err == -1) { diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 67e2471..464c33d 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -190,7 +190,7 @@ uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n) return res; } -void put_ext4(uint64_t off, void *buf, uint32_t size) +void put_ext4(uint64_t off, const void *buf, uint32_t size) { uint64_t startblock; uint64_t remainder; @@ -510,7 +510,8 @@ restart: restart_read: /* read the block no allocated to a file */ - first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx); + first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx, + NULL); if (first_block_no_of_root <= 0) goto fail; @@ -607,7 +608,7 @@ restart_read: dir->direntlen = cpu_to_le16(fs->blksz - totalbytes); dir->namelen = strlen(filename); - dir->filetype = FILETYPE_REG; /* regular file */ + dir->filetype = file_type; temp_dir = (char *)dir; temp_dir = temp_dir + sizeof(struct ext2_dirent); memcpy(temp_dir, filename, strlen(filename)); @@ -646,7 +647,7 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname) /* get the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { - blknr = read_allocated_block(parent_inode, blk_idx); + blknr = read_allocated_block(parent_inode, blk_idx, NULL); if (blknr <= 0) goto fail; @@ -943,7 +944,7 @@ int ext4fs_filename_unlink(char *filename) /* read the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { - blknr = read_allocated_block(g_parent_inode, blk_idx); + blknr = read_allocated_block(g_parent_inode, blk_idx, NULL); if (blknr <= 0) break; inodeno = unlink_filename(filename, blknr); @@ -1522,7 +1523,7 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode, #endif static struct ext4_extent_header *ext4fs_get_extent_block - (struct ext2_data *data, char *buf, + (struct ext2_data *data, struct ext_block_cache *cache, struct ext4_extent_header *ext_block, uint32_t fileblock, int log2_blksz) { @@ -1546,17 +1547,19 @@ static struct ext4_extent_header *ext4fs_get_extent_block break; } while (fileblock >= le32_to_cpu(index[i].ei_block)); - if (--i < 0) - return NULL; + /* + * If first logical block number is higher than requested fileblock, + * it is a sparse file. This is handled on upper layer. + */ + if (i > 0) + i--; block = le16_to_cpu(index[i].ei_leaf_hi); block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); - - if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz, - buf)) - ext_block = (struct ext4_extent_header *)buf; - else + block <<= log2_blksz; + if (!ext_cache_read(cache, (lbaint_t)block, blksz)) return NULL; + ext_block = (struct ext4_extent_header *)cache->buf; } } @@ -1584,7 +1587,7 @@ static int ext4fs_blockgroup int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) { - struct ext2_block_group blkgrp; + struct ext2_block_group *blkgrp; struct ext2_sblock *sblock = &data->sblock; struct ext_filesystem *fs = get_fs(); int log2blksz = get_fs()->dev_desc->log2blksz; @@ -1592,17 +1595,28 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) long int blkno; unsigned int blkoff; + /* Allocate blkgrp based on gdsize (for 64-bit support). */ + blkgrp = zalloc(get_fs()->gdsize); + if (!blkgrp) + return 0; + /* It is easier to calculate if the first inode is 0. */ ino--; status = ext4fs_blockgroup(data, ino / le32_to_cpu - (sblock->inodes_per_group), &blkgrp); - if (status == 0) + (sblock->inodes_per_group), blkgrp); + if (status == 0) { + free(blkgrp); return 0; + } inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz; - blkno = ext4fs_bg_get_inode_table_id(&blkgrp, fs) + + blkno = ext4fs_bg_get_inode_table_id(blkgrp, fs) + (ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; blkoff = (ino % inodes_per_block) * fs->inodesz; + + /* Free blkgrp as it is no longer required. */ + free(blkgrp); + /* Read the inode. */ status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) - log2blksz), blkoff, @@ -1613,7 +1627,8 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) return 1; } -long int read_allocated_block(struct ext2_inode *inode, int fileblock) +long int read_allocated_block(struct ext2_inode *inode, int fileblock, + struct ext_block_cache *cache) { long int blknr; int blksz; @@ -1630,20 +1645,26 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) { long int startblock, endblock; - char *buf = zalloc(blksz); - if (!buf) - return -ENOMEM; + struct ext_block_cache *c, cd; struct ext4_extent_header *ext_block; struct ext4_extent *extent; int i; + + if (cache) { + c = cache; + } else { + c = &cd; + ext_cache_init(c); + } ext_block = - ext4fs_get_extent_block(ext4fs_root, buf, + ext4fs_get_extent_block(ext4fs_root, c, (struct ext4_extent_header *) inode->b.blocks.dir_blocks, fileblock, log2_blksz); if (!ext_block) { printf("invalid extent block\n"); - free(buf); + if (!cache) + ext_cache_fini(c); return -EINVAL; } @@ -1655,19 +1676,22 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) if (startblock > fileblock) { /* Sparse file */ - free(buf); + if (!cache) + ext_cache_fini(c); return 0; } else if (fileblock < endblock) { start = le16_to_cpu(extent[i].ee_start_hi); start = (start << 32) + le32_to_cpu(extent[i].ee_start_lo); - free(buf); + if (!cache) + ext_cache_fini(c); return (fileblock - startblock) + start; } } - free(buf); + if (!cache) + ext_cache_fini(c); return 0; } diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h index 1ee81ab..4dff191 100644 --- a/fs/ext4/ext4_common.h +++ b/fs/ext4/ext4_common.h @@ -72,7 +72,7 @@ int ext4fs_iget(int inode_no, struct ext2_inode *inode); void ext4fs_allocate_blocks(struct ext2_inode *file_inode, unsigned int total_remaining_blocks, unsigned int *total_no_of_block); -void put_ext4(uint64_t off, void *buf, uint32_t size); +void put_ext4(uint64_t off, const void *buf, uint32_t size); struct ext2_block_group *ext4fs_get_group_descriptor (const struct ext_filesystem *fs, uint32_t bg_idx); uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg, diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c index 148593d..6adbab9 100644 --- a/fs/ext4/ext4_journal.c +++ b/fs/ext4/ext4_journal.c @@ -347,7 +347,7 @@ void recover_transaction(int prev_desc_logical_no) ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, (struct ext2_inode *)&inode_journal); blknr = read_allocated_block((struct ext2_inode *) - &inode_journal, i); + &inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); p_jdb = (char *)temp_buff; @@ -372,7 +372,7 @@ void recover_transaction(int prev_desc_logical_no) be32_to_cpu(jdb->h_sequence)) == 0) continue; } - blknr = read_allocated_block(&inode_journal, i); + blknr = read_allocated_block(&inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, metadata_buff); put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz), @@ -419,7 +419,8 @@ int ext4fs_check_journal_state(int recovery_flag) } ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); - blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK); + blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, + NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; @@ -443,7 +444,7 @@ int ext4fs_check_journal_state(int recovery_flag) i = be32_to_cpu(jsb->s_first); while (1) { - blknr = read_allocated_block(&inode_journal, i); + blknr = read_allocated_block(&inode_journal, i, NULL); memset(temp_buff1, '\0', fs->blksz); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff1); @@ -537,7 +538,7 @@ end: ext4_read_superblock((char *)fs->sb); blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), (struct journal_superblock_t *)temp_buff, (uint32_t) fs->blksz); @@ -566,7 +567,7 @@ static void update_descriptor_block(long int blknr) ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; @@ -618,7 +619,7 @@ static void update_commit_block(long int blknr) ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; @@ -645,16 +646,17 @@ void ext4fs_update_journal(void) long int blknr; int i; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); - blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); + blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL); update_descriptor_block(blknr); for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { if (journal_ptr[i]->blknr == -1) break; - blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); + blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, + NULL); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), journal_ptr[i]->buf, fs->blksz); } - blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); + blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL); update_commit_block(blknr); printf("update journal finished\n"); } diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index 4eb77c3..504d23a 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -465,6 +465,15 @@ static int ext4fs_delete_file(int inodeno) if (le32_to_cpu(inode.size) % fs->blksz) no_blocks++; + /* + * special case for symlinks whose target are small enough that + *it fits in struct ext2_inode.b.symlink: no block had been allocated + */ + if ((le16_to_cpu(inode.mode) & S_IFLNK) && + le32_to_cpu(inode.size) <= sizeof(inode.b.symlink)) { + no_blocks = 0; + } + if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) { /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */ struct ext4_extent_header *eh = @@ -479,7 +488,7 @@ static int ext4fs_delete_file(int inodeno) /* release data blocks */ for (i = 0; i < no_blocks; i++) { - blknr = read_allocated_block(&inode, i); + blknr = read_allocated_block(&inode, i, NULL); if (blknr == 0) continue; if (blknr < 0) @@ -695,7 +704,7 @@ void ext4fs_deinit(void) ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *)temp_buff; @@ -752,7 +761,7 @@ void ext4fs_deinit(void) * contigous sectors as ext4fs_read_file */ static int ext4fs_write_file(struct ext2_inode *file_inode, - int pos, unsigned int len, char *buf) + int pos, unsigned int len, const char *buf) { int i; int blockcnt; @@ -764,7 +773,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, int delayed_start = 0; int delayed_extent = 0; int delayed_next = 0; - char *delayed_buf = NULL; + const char *delayed_buf = NULL; /* Adjust len so it we can't read past the end of the file. */ if (len > filesize) @@ -776,7 +785,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, long int blknr; int blockend = fs->blksz; int skipfirst = 0; - blknr = read_allocated_block(file_inode, i); + blknr = read_allocated_block(file_inode, i, NULL); if (blknr <= 0) return -1; @@ -816,7 +825,6 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, (uint32_t) delayed_extent); previous_block_number = -1; } - memset(buf, 0, fs->blksz - skipfirst); } buf += fs->blksz - skipfirst; } @@ -830,8 +838,8 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, return len; } -int ext4fs_write(const char *fname, unsigned char *buffer, - unsigned long sizebytes) +int ext4fs_write(const char *fname, const char *buffer, + unsigned long sizebytes, int type) { int ret = 0; struct ext2_inode *file_inode = NULL; @@ -854,8 +862,12 @@ int ext4fs_write(const char *fname, unsigned char *buffer, struct ext2_block_group *bgd = NULL; struct ext_filesystem *fs = get_fs(); ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256); + bool store_link_in_inode = false; memset(filename, 0x00, 256); + if (type != FILETYPE_REG && type != FILETYPE_SYMLINK) + return -1; + g_parent_inode = zalloc(fs->inodesz); if (!g_parent_inode) goto fail; @@ -893,8 +905,16 @@ int ext4fs_write(const char *fname, unsigned char *buffer, if (ret) goto fail; } - /* calucalate how many blocks required */ - bytes_reqd_for_file = sizebytes; + + /* calculate how many blocks required */ + if (type == FILETYPE_SYMLINK && + sizebytes <= sizeof(file_inode->b.symlink)) { + store_link_in_inode = true; + bytes_reqd_for_file = 0; + } else { + bytes_reqd_for_file = sizebytes; + } + blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz); if (do_div(bytes_reqd_for_file, fs->blksz) != 0) { blks_reqd_for_file++; @@ -907,7 +927,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, goto fail; } - inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG); + inodeno = ext4fs_update_parent_dentry(filename, type); if (inodeno == -1) goto fail; /* prepare file inode */ @@ -915,14 +935,23 @@ int ext4fs_write(const char *fname, unsigned char *buffer, if (!inode_buffer) goto fail; file_inode = (struct ext2_inode *)inode_buffer; - file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | - S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH); + file_inode->size = cpu_to_le32(sizebytes); + if (type == FILETYPE_SYMLINK) { + file_inode->mode = cpu_to_le16(S_IFLNK | S_IRWXU | S_IRWXG | + S_IRWXO); + if (store_link_in_inode) { + strncpy(file_inode->b.symlink, buffer, sizebytes); + sizebytes = 0; + } + } else { + file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | S_IRGRP | + S_IROTH | S_IXGRP | S_IXOTH); + } /* ToDo: Update correct time */ file_inode->mtime = cpu_to_le32(timestamp); file_inode->atime = cpu_to_le32(timestamp); file_inode->ctime = cpu_to_le32(timestamp); file_inode->nlinks = cpu_to_le16(1); - file_inode->size = cpu_to_le32(sizebytes); /* Allocate data blocks */ ext4fs_allocate_blocks(file_inode, blocks_remaining, @@ -949,7 +978,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, if (ext4fs_put_metadata(temp_ptr, itable_blkno)) goto fail; /* copy the file content into data blocks */ - if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) { + if (ext4fs_write_file(file_inode, 0, sizebytes, buffer) == -1) { printf("Error in copying content\n"); /* FIXME: Deallocate data blocks */ goto fail; @@ -1014,7 +1043,7 @@ int ext4_write_file(const char *filename, void *buf, loff_t offset, return -1; } - ret = ext4fs_write(filename, buf, len); + ret = ext4fs_write(filename, buf, len, FILETYPE_REG); if (ret) { printf("** Error ext4fs_write() **\n"); goto fail; @@ -1029,3 +1058,8 @@ fail: return -1; } + +int ext4fs_create_link(const char *target, const char *fname) +{ + return ext4fs_write(fname, target, strlen(target), FILETYPE_SYMLINK); +} diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index 2a28031..26db677 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c @@ -62,6 +62,9 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, lbaint_t delayed_next = 0; char *delayed_buf = NULL; short status; + struct ext_block_cache cache; + + ext_cache_init(&cache); if (blocksize <= 0) return -1; @@ -77,9 +80,11 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, int blockoff = pos - (blocksize * i); int blockend = blocksize; int skipfirst = 0; - blknr = read_allocated_block(&(node->inode), i); - if (blknr < 0) + blknr = read_allocated_block(&node->inode, i, &cache); + if (blknr < 0) { + ext_cache_fini(&cache); return -1; + } blknr = blknr << log2_fs_blocksize; @@ -109,8 +114,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, delayed_skipfirst, delayed_extent, delayed_buf); - if (status == 0) + if (status == 0) { + ext_cache_fini(&cache); return -1; + } previous_block_number = blknr; delayed_start = blknr; delayed_extent = blockend; @@ -136,8 +143,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, delayed_skipfirst, delayed_extent, delayed_buf); - if (status == 0) + if (status == 0) { + ext_cache_fini(&cache); return -1; + } previous_block_number = -1; } /* Zero no more than `len' bytes. */ @@ -153,12 +162,15 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, status = ext4fs_devread(delayed_start, delayed_skipfirst, delayed_extent, delayed_buf); - if (status == 0) + if (status == 0) { + ext_cache_fini(&cache); return -1; + } previous_block_number = -1; } *actread = len; + ext_cache_fini(&cache); return 0; } @@ -252,3 +264,32 @@ int ext4fs_uuid(char *uuid_str) return -ENOSYS; #endif } + +void ext_cache_init(struct ext_block_cache *cache) +{ + memset(cache, 0, sizeof(*cache)); +} + +void ext_cache_fini(struct ext_block_cache *cache) +{ + free(cache->buf); + ext_cache_init(cache); +} + +int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size) +{ + /* This could be more lenient, but this is simple and enough for now */ + if (cache->buf && cache->block == block && cache->size == size) + return 1; + ext_cache_fini(cache); + cache->buf = malloc(size); + if (!cache->buf) + return 0; + if (!ext4fs_devread(block, 0, size, cache->buf)) { + free(cache->buf); + return 0; + } + cache->block = block; + cache->size = size; + return 1; +} diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 6ade4ea..c5997c2 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -602,8 +602,13 @@ static int get_fs_info(fsdata *mydata) mydata->data_begin = mydata->rootdir_sect + mydata->rootdir_size - (mydata->clust_size * 2); - mydata->root_cluster = - sect_to_clust(mydata, mydata->rootdir_sect); + + /* + * The root directory is not cluster-aligned and may be on a + * "negative" cluster, this will be handled specially in + * next_cluster(). + */ + mydata->root_cluster = 0; } mydata->fatbufnum = -1; @@ -733,20 +738,38 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) itr->last_cluster = 0; } -static void *next_cluster(fat_itr *itr) +static void *next_cluster(fat_itr *itr, unsigned *nbytes) { fsdata *mydata = itr->fsdata; /* for silly macros */ int ret; u32 sect; + u32 read_size; /* have we reached the end? */ if (itr->last_cluster) return NULL; - sect = clust_to_sect(itr->fsdata, itr->next_clust); + if (itr->is_root && itr->fsdata->fatsize != 32) { + /* + * The root directory is located before the data area and + * cannot be indexed using the regular unsigned cluster + * numbers (it may start at a "negative" cluster or not at a + * cluster boundary at all), so consider itr->next_clust to be + * a offset in cluster-sized units from the start of rootdir. + */ + unsigned sect_offset = itr->next_clust * itr->fsdata->clust_size; + unsigned remaining_sects = itr->fsdata->rootdir_size - sect_offset; + sect = itr->fsdata->rootdir_sect + sect_offset; + /* do not read past the end of rootdir */ + read_size = min_t(u32, itr->fsdata->clust_size, + remaining_sects); + } else { + sect = clust_to_sect(itr->fsdata, itr->next_clust); + read_size = itr->fsdata->clust_size; + } - debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n", - sect, itr->fsdata->clust_size, DIRENTSPERBLOCK); + debug("FAT read(sect=%d), clust_size=%d, read_size=%u, DIRENTSPERBLOCK=%zd\n", + sect, itr->fsdata->clust_size, read_size, DIRENTSPERBLOCK); /* * NOTE: do_fat_read_at() had complicated logic to deal w/ @@ -757,18 +780,17 @@ static void *next_cluster(fat_itr *itr) * dent at a time and iteratively constructing the vfat long * name. */ - ret = disk_read(sect, itr->fsdata->clust_size, - itr->block); + ret = disk_read(sect, read_size, itr->block); if (ret < 0) { debug("Error: reading block\n"); return NULL; } + *nbytes = read_size * itr->fsdata->sect_size; itr->clust = itr->next_clust; if (itr->is_root && itr->fsdata->fatsize != 32) { itr->next_clust++; - sect = clust_to_sect(itr->fsdata, itr->next_clust); - if (sect - itr->fsdata->rootdir_sect >= + if (itr->next_clust * itr->fsdata->clust_size >= itr->fsdata->rootdir_size) { debug("nextclust: 0x%x\n", itr->next_clust); itr->last_cluster = 1; @@ -787,9 +809,8 @@ static void *next_cluster(fat_itr *itr) static dir_entry *next_dent(fat_itr *itr) { if (itr->remaining == 0) { - struct dir_entry *dent = next_cluster(itr); - unsigned nbytes = itr->fsdata->sect_size * - itr->fsdata->clust_size; + unsigned nbytes; + struct dir_entry *dent = next_cluster(itr, &nbytes); /* have we reached the last cluster? */ if (!dent) { @@ -90,6 +90,11 @@ static inline int fs_write_unsupported(const char *filename, void *buf, return -1; } +static inline int fs_ln_unsupported(const char *filename, const char *target) +{ + return -1; +} + static inline void fs_close_unsupported(void) { } @@ -154,6 +159,7 @@ struct fstype_info { void (*closedir)(struct fs_dir_stream *dirs); int (*unlink)(const char *filename); int (*mkdir)(const char *dirname); + int (*ln)(const char *filename, const char *target); }; static struct fstype_info fstypes[] = { @@ -181,6 +187,7 @@ static struct fstype_info fstypes[] = { .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, + .ln = fs_ln_unsupported, }, #endif @@ -197,8 +204,10 @@ static struct fstype_info fstypes[] = { .read = ext4_read_file, #ifdef CONFIG_CMD_EXT4_WRITE .write = ext4_write_file, + .ln = ext4fs_create_link, #else .write = fs_write_unsupported, + .ln = fs_ln_unsupported, #endif .uuid = ext4fs_uuid, .opendir = fs_opendir_unsupported, @@ -222,6 +231,7 @@ static struct fstype_info fstypes[] = { .opendir = fs_opendir_unsupported, .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, + .ln = fs_ln_unsupported, }, #endif #ifdef CONFIG_CMD_UBIFS @@ -240,6 +250,7 @@ static struct fstype_info fstypes[] = { .opendir = fs_opendir_unsupported, .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, + .ln = fs_ln_unsupported, }, #endif #ifdef CONFIG_FS_BTRFS @@ -258,6 +269,7 @@ static struct fstype_info fstypes[] = { .opendir = fs_opendir_unsupported, .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, + .ln = fs_ln_unsupported, }, #endif { @@ -275,6 +287,7 @@ static struct fstype_info fstypes[] = { .opendir = fs_opendir_unsupported, .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, + .ln = fs_ln_unsupported, }, }; @@ -602,6 +615,22 @@ int fs_mkdir(const char *dirname) return ret; } +int fs_ln(const char *fname, const char *target) +{ + struct fstype_info *info = fs_get_info(fs_type); + int ret; + + ret = info->ln(fname, target); + + if (ret < 0) { + printf("** Unable to create link %s -> %s **\n", fname, target); + ret = -1; + } + fs_close(); + + return ret; +} + int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int fstype) { @@ -840,3 +869,18 @@ int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], return 0; } + +int do_ln(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int fstype) +{ + if (argc != 5) + return CMD_RET_USAGE; + + if (fs_set_blk_dev(argv[1], argv[2], fstype)) + return 1; + + if (fs_ln(argv[3], argv[4])) + return 1; + + return 0; +} diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index bad0c67..5f6e127 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -167,7 +167,7 @@ struct ubifs_global_debug_info { #else #define ubifs_assert(expr) do { \ if (unlikely(!(expr))) { \ - pr_crit("UBIFS assert failed in %s at %u\n", \ + pr_debug("UBIFS assert failed in %s at %u\n", \ __func__, __LINE__); \ dump_stack(); \ } \ @@ -176,7 +176,7 @@ struct ubifs_global_debug_info { #define ubifs_assert_cmt_locked(c) do { \ if (unlikely(down_write_trylock(&(c)->commit_sem))) { \ up_write(&(c)->commit_sem); \ - pr_crit("commit lock is not locked!\n"); \ + pr_debug("commit lock is not locked!\n"); \ ubifs_assert(0); \ } \ } while (0) diff --git a/include/configs/corvus.h b/include/configs/corvus.h index 5dd5c28..749a67d 100644 --- a/include/configs/corvus.h +++ b/include/configs/corvus.h @@ -139,4 +139,7 @@ #define CONFIG_SYS_MCKR 0x1301 #define CONFIG_SYS_MCKR_CSS 0x1302 +#define CONFIG_SPL_PAD_TO CONFIG_SYS_NAND_U_BOOT_OFFS +#define CONFIG_SYS_SPL_LEN CONFIG_SPL_PAD_TO + #endif diff --git a/include/configs/gardena-smart-gateway-at91sam.h b/include/configs/gardena-smart-gateway-at91sam.h new file mode 100644 index 0000000..e9a06e6 --- /dev/null +++ b/include/configs/gardena-smart-gateway-at91sam.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2012 Atmel Corporation + * Copyright (C) 2019 Stefan Roese <sr@denx.de> + * + * Configuation settings for the GARDENA smart Gateway (AT91SAM9G25) + */ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +/* ARM asynchronous clock */ +#define CONFIG_SYS_AT91_SLOW_CLOCK 32768 +#define CONFIG_SYS_AT91_MAIN_CLOCK 12000000 /* 12 MHz crystal */ + +#ifndef CONFIG_SPL_BUILD +#define CONFIG_SKIP_LOWLEVEL_INIT +#endif +#define CONFIG_SKIP_LOWLEVEL_INIT_ONLY + +/* general purpose I/O */ +#define CONFIG_ATMEL_LEGACY /* required until (g)pio is fixed */ + +/* SDRAM */ +#define CONFIG_SYS_SDRAM_BASE 0x20000000 +#define CONFIG_SYS_SDRAM_SIZE 0x08000000 /* 128 megs */ + +#define CONFIG_SYS_INIT_SP_ADDR \ + (CONFIG_SYS_SDRAM_BASE + 16 * 1024 - GENERATED_GBL_DATA_SIZE) + +#define CONFIG_SYS_MALLOC_LEN (16 * 1024 * 1024) + +/* NAND flash */ +#define CONFIG_SYS_MAX_NAND_DEVICE 1 +#define CONFIG_SYS_NAND_BASE 0x40000000 +#define CONFIG_SYS_NAND_DBW_8 1 +/* our ALE is AD21 */ +#define CONFIG_SYS_NAND_MASK_ALE BIT(21) +/* our CLE is AD22 */ +#define CONFIG_SYS_NAND_MASK_CLE BIT(22) +#define CONFIG_SYS_NAND_ENABLE_PIN AT91_PIN_PD4 +#define CONFIG_SYS_NAND_READY_PIN AT91_PIN_PD5 + +#define CONFIG_SYS_LOAD_ADDR 0x22000000 /* load address */ + +/* environment organization */ +#define CONFIG_ENV_UBI_PART "ubi" +#define CONFIG_ENV_UBI_VOLUME "env" +#define CONFIG_ENV_UBI_VOLUME_REDUND "env_r" +#define CONFIG_ENV_SIZE (64 << 10) + +/* SPL */ +#define CONFIG_SPL_TEXT_BASE 0x300000 +#define CONFIG_SPL_MAX_SIZE 0x7000 +#define CONFIG_SPL_STACK 0x308000 + +#define CONFIG_SPL_BSS_START_ADDR 0x20000000 +#define CONFIG_SPL_BSS_MAX_SIZE 0x80000 +#define CONFIG_SYS_SPL_MALLOC_START 0x20080000 +#define CONFIG_SYS_SPL_MALLOC_SIZE 0x80000 + +#define CONFIG_SYS_MONITOR_LEN (512 << 10) + +#define CONFIG_SYS_MASTER_CLOCK 132096000 +#define CONFIG_SYS_AT91_PLLA 0x20c73f03 +#define CONFIG_SYS_MCKR 0x1301 +#define CONFIG_SYS_MCKR_CSS 0x1302 + +#define CONFIG_SPL_NAND_DRIVERS +#define CONFIG_SPL_NAND_BASE +#define CONFIG_SPL_NAND_RAW_ONLY +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x40000 +#define CONFIG_SYS_NAND_U_BOOT_SIZE 0xa0000 +#define CONFIG_SYS_UBOOT_START CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_NAND_U_BOOT_DST CONFIG_SYS_TEXT_BASE + +#define CONFIG_SYS_NAND_5_ADDR_CYCLE +#define CONFIG_SYS_NAND_PAGE_SIZE 0x800 +#define CONFIG_SYS_NAND_PAGE_COUNT 64 +#define CONFIG_SYS_NAND_OOBSIZE 64 +#define CONFIG_SYS_NAND_BLOCK_SIZE 0x20000 +#define CONFIG_SYS_NAND_BAD_BLOCK_POS 0x0 + +#define CONFIG_SPL_PAD_TO CONFIG_SYS_NAND_U_BOOT_OFFS +#define CONFIG_SYS_SPL_LEN CONFIG_SPL_PAD_TO + +#endif diff --git a/include/configs/pm9g45.h b/include/configs/pm9g45.h index 46b8030..e34873c 100644 --- a/include/configs/pm9g45.h +++ b/include/configs/pm9g45.h @@ -15,110 +15,119 @@ #ifndef __CONFIG_H #define __CONFIG_H -/* - * SoC must be defined first, before hardware.h is included. - * In this case SoC is defined in boards.cfg. - */ -#include <asm/hardware.h> - -#define CONFIG_SYS_AT91_CPU_NAME "AT91SAM9G45" - -#define CONFIG_MACH_TYPE MACH_TYPE_PM9G45 - /* ARM asynchronous clock */ -#define CONFIG_SYS_AT91_MAIN_CLOCK 12000000 /* from 12 MHz crystal */ -#define CONFIG_SYS_AT91_SLOW_CLOCK 32768 /* slow clock xtal */ - -#define CONFIG_ARCH_CPU_INIT - -#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */ -#define CONFIG_SETUP_MEMORY_TAGS 1 -#define CONFIG_INITRD_TAG 1 +#define CONFIG_SYS_AT91_SLOW_CLOCK 32768 +#define CONFIG_SYS_AT91_MAIN_CLOCK 12000000 /* from 12 MHz crystal */ +#define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */ +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_INITRD_TAG #define CONFIG_SKIP_LOWLEVEL_INIT -/* - * Hardware drivers - */ -#define CONFIG_AT91_GPIO 1 -#define CONFIG_ATMEL_USART 1 -#define CONFIG_USART_BASE ATMEL_BASE_DBGU -#define CONFIG_USART_ID ATMEL_ID_SYS - -#define CONFIG_SYS_USE_NANDFLASH 1 - -/* LED */ -#define CONFIG_AT91_LED -#define CONFIG_RED_LED GPIO_PIN_PD(31) /* this is the user1 led */ -#define CONFIG_GREEN_LED GPIO_PIN_PD(0) /* this is the user2 led */ - +/* general purpose I/O */ +#define CONFIG_ATMEL_LEGACY /* required until (g)pio is fixed */ /* * BOOTP options */ -#define CONFIG_BOOTP_BOOTFILESIZE 1 - -#define CONFIG_JFFS2_CMDLINE 1 -#define CONFIG_JFFS2_NAND 1 -#define CONFIG_JFFS2_DEV "nand0" /* NAND dev jffs2 lives on */ -#define CONFIG_JFFS2_PART_OFFSET 0 /* start of jffs2 partition */ -#define CONFIG_JFFS2_PART_SIZE (256 * 1024 * 1024) /* partition */ +#define CONFIG_BOOTP_BOOTFILESIZE /* SDRAM */ -#define PHYS_SDRAM 0x70000000 -#define PHYS_SDRAM_SIZE 0x08000000 /* 128 megs */ +#define CONFIG_SYS_SDRAM_BASE 0x70000000 +#define CONFIG_SYS_SDRAM_SIZE 0x08000000 + +#define CONFIG_SYS_INIT_SP_ADDR \ + (CONFIG_SYS_SDRAM_BASE + 16 * 1024 - GENERATED_GBL_DATA_SIZE) /* NAND flash */ #ifdef CONFIG_CMD_NAND -#define CONFIG_SYS_MAX_NAND_DEVICE 1 -#define CONFIG_SYS_NAND_BASE 0x40000000 -#define CONFIG_SYS_NAND_DBW_8 1 +#define CONFIG_SYS_MAX_NAND_DEVICE 1 +#define CONFIG_SYS_NAND_BASE ATMEL_BASE_CS3 +#define CONFIG_SYS_NAND_DBW_8 /* our ALE is AD21 */ -#define CONFIG_SYS_NAND_MASK_ALE (1 << 21) +#define CONFIG_SYS_NAND_MASK_ALE BIT(21) /* our CLE is AD22 */ -#define CONFIG_SYS_NAND_MASK_CLE (1 << 22) -#define CONFIG_SYS_NAND_ENABLE_PIN GPIO_PIN_PC(14) -#define CONFIG_SYS_NAND_READY_PIN GPIO_PIN_PD(3) - +#define CONFIG_SYS_NAND_MASK_CLE BIT(22) +#define CONFIG_SYS_NAND_ENABLE_PIN AT91_PIN_PC14 +#define CONFIG_SYS_NAND_READY_PIN AT91_PIN_PD3 +#define CONFIG_SYS_NAND_DRIVER_ECC_LAYOUT #endif /* Ethernet */ -#define CONFIG_MACB 1 -#define CONFIG_RMII 1 -#define CONFIG_NET_RETRY_COUNT 20 -#define CONFIG_RESET_PHY_R 1 - -/* USB */ -#define CONFIG_USB_ATMEL -#define CONFIG_USB_ATMEL_CLK_SEL_UPLL -#define CONFIG_USB_OHCI_NEW 1 -#define CONFIG_SYS_USB_OHCI_CPU_INIT 1 -#define CONFIG_SYS_USB_OHCI_REGS_BASE 0x00700000 /* _UHP_OHCI_BASE */ -#define CONFIG_SYS_USB_OHCI_SLOT_NAME "at91sam9g45" -#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 2 - -/* board specific(not enough SRAM) */ -#define CONFIG_AT91SAM9G45_LCD_BASE PHYS_SDRAM + 0xE00000 - -#define CONFIG_SYS_LOAD_ADDR PHYS_SDRAM + 0x2000000 /* load addr */ - -#define CONFIG_SYS_MEMTEST_START PHYS_SDRAM -#define CONFIG_SYS_MEMTEST_END CONFIG_AT91SAM9G45_LCD_BASE - -/* bootstrap + u-boot + env + linux in nandflash */ -#define CONFIG_ENV_OFFSET 0x60000 -#define CONFIG_ENV_OFFSET_REDUND 0x80000 -#define CONFIG_ENV_SIZE 0x20000 /* 1 sector = 128 kB */ -#define CONFIG_BOOTCOMMAND "nand read 0x72000000 0x200000 0x200000; bootm" +#define CONFIG_RESET_PHY_R +#define CONFIG_AT91_WANTS_COMMON_PHY + +#define CONFIG_SYS_LOAD_ADDR 0x22000000 /* load address */ + +#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE +#define CONFIG_SYS_MEMTEST_END 0x23e00000 + +#ifdef CONFIG_NAND_BOOT +/* bootstrap + u-boot + env in nandflash */ +#define CONFIG_ENV_OFFSET 0x140000 +#define CONFIG_ENV_OFFSET_REDUND 0x100000 +#define CONFIG_ENV_SIZE 0x20000 + +#define CONFIG_BOOTCOMMAND \ + "nand read 0x70000000 0x200000 0x300000;" \ + "bootm 0x70000000" +#elif CONFIG_SD_BOOT +/* bootstrap + u-boot + env + linux in mmc */ +#define CONFIG_ENV_SIZE 0x4000 + +#define CONFIG_BOOTCOMMAND "fatload mmc 0:1 0x71000000 dtb; " \ + "fatload mmc 0:1 0x72000000 zImage; " \ + "bootz 0x72000000 - 0x71000000" +#endif /* * Size of malloc() pool */ -#define CONFIG_SYS_MALLOC_LEN ROUND(3 * CONFIG_ENV_SIZE + 128*1024,\ - 0x1000) +#define CONFIG_SYS_MALLOC_LEN ROUND(3 * CONFIG_ENV_SIZE + \ + 128 * 1024, 0x1000) + +/* Defines for SPL */ +#define CONFIG_SPL_TEXT_BASE 0x300000 +#define CONFIG_SPL_MAX_SIZE 0x010000 +#define CONFIG_SPL_STACK 0x310000 + +#define CONFIG_SYS_MONITOR_LEN 0x80000 + +#ifdef CONFIG_SD_BOOT + +#define CONFIG_SPL_BSS_START_ADDR 0x70000000 +#define CONFIG_SPL_BSS_MAX_SIZE 0x00080000 +#define CONFIG_SYS_SPL_MALLOC_START 0x70080000 +#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00080000 + +#define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 1 +#define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "u-boot.img" + +#elif CONFIG_NAND_BOOT +#define CONFIG_SPL_NAND_DRIVERS +#define CONFIG_SPL_NAND_BASE +#define CONFIG_SPL_NAND_ECC +#define CONFIG_SPL_NAND_SOFTECC +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x40000 +#define CONFIG_SYS_NAND_U_BOOT_SIZE 0x80000 +#define CONFIG_SYS_NAND_5_ADDR_CYCLE + +#define CONFIG_SYS_NAND_PAGE_SIZE 0x800 +#define CONFIG_SYS_NAND_BLOCK_SIZE 0x20000 +#define CONFIG_SYS_NAND_PAGE_COUNT 64 +#define CONFIG_SYS_NAND_BAD_BLOCK_POS NAND_LARGE_BADBLOCK_POS +#define CONFIG_SYS_NAND_ECCSIZE 256 +#define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_SYS_NAND_OOBSIZE 64 +#define CONFIG_SYS_NAND_ECCPOS { 40, 41, 42, 43, 44, 45, 46, 47, \ + 48, 49, 50, 51, 52, 53, 54, 55, \ + 56, 57, 58, 59, 60, 61, 62, 63, } +#endif -#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM -#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - \ - GENERATED_GBL_DATA_SIZE) +#define CONFIG_SPL_ATMEL_SIZE +#define CONFIG_SYS_MASTER_CLOCK 132096000 +#define CONFIG_SYS_AT91_PLLA 0x20c73f03 +#define CONFIG_SYS_MCKR 0x1301 +#define CONFIG_SYS_MCKR_CSS 0x1302 #endif diff --git a/include/configs/smartweb.h b/include/configs/smartweb.h index 28af575..f95b294 100644 --- a/include/configs/smartweb.h +++ b/include/configs/smartweb.h @@ -221,4 +221,8 @@ #define CONFIG_SYS_ICACHE_OFF #define CONFIG_SYS_DCACHE_OFF #endif + +#define CONFIG_SPL_PAD_TO CONFIG_SYS_NAND_U_BOOT_OFFS +#define CONFIG_SYS_SPL_LEN CONFIG_SPL_PAD_TO + #endif /* __CONFIG_H */ diff --git a/include/configs/taurus.h b/include/configs/taurus.h index 1d24577..3582eb2 100644 --- a/include/configs/taurus.h +++ b/include/configs/taurus.h @@ -173,4 +173,7 @@ #define CONFIG_SYS_MCKR_CSS (0x02 | CONFIG_SYS_MCKR) #define CONFIG_SYS_AT91_PLLB 0x10193F05 +#define CONFIG_SPL_PAD_TO CONFIG_SYS_NAND_U_BOOT_OFFS +#define CONFIG_SYS_SPL_LEN CONFIG_SPL_PAD_TO + #endif diff --git a/include/dt-bindings/pinctrl/at91.h b/include/dt-bindings/pinctrl/at91.h index 2732d6c..616f5ce 100644 --- a/include/dt-bindings/pinctrl/at91.h +++ b/include/dt-bindings/pinctrl/at91.h @@ -17,6 +17,7 @@ #define AT91_PINCTRL_DIS_SCHMIT (1 << 4) #define AT91_PINCTRL_OUTPUT (1 << 7) #define AT91_PINCTRL_OUTPUT_VAL(x) ((x & 0x1) << 8) +#define AT91_PINCTRL_SLEWRATE (1 << 9) #define AT91_PINCTRL_DEBOUNCE (1 << 16) #define AT91_PINCTRL_DEBOUNCE_VAL(x) (x << 17) @@ -27,6 +28,9 @@ #define AT91_PINCTRL_DRIVE_STRENGTH_MED (0x2 << 5) #define AT91_PINCTRL_DRIVE_STRENGTH_HI (0x3 << 5) +#define AT91_PINCTRL_SLEWRATE_DIS (0x0 << 9) +#define AT91_PINCTRL_SLEWRATE_ENA (0x1 << 9) + #define AT91_PIOA 0 #define AT91_PIOB 1 #define AT91_PIOC 2 diff --git a/include/efi_api.h b/include/efi_api.h index 8647bfa..5b0a100 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -333,6 +333,10 @@ struct efi_system_table { EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, \ 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define LOADED_IMAGE_DEVICE_PATH_GUID \ + EFI_GUID(0xbc62157e, 0x3e33, 0x4fec, \ + 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf) + #define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000 struct efi_loaded_image { diff --git a/include/efi_loader.h b/include/efi_loader.h index 512880a..00b81c6 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -135,6 +135,7 @@ extern const efi_guid_t efi_guid_event_group_reset_system; /* GUID of the device tree table */ extern const efi_guid_t efi_guid_fdt; extern const efi_guid_t efi_guid_loaded_image; +extern const efi_guid_t efi_guid_loaded_image_device_path; extern const efi_guid_t efi_guid_device_path_to_text_protocol; extern const efi_guid_t efi_simple_file_system_protocol_guid; extern const efi_guid_t efi_file_info_guid; @@ -203,15 +204,11 @@ struct efi_object { * struct efi_loaded_image_obj - handle of a loaded image * * @header: EFI object header - * @reloc_base: base address for the relocated image - * @reloc_size: size of the relocated image * @exit_jmp: long jump buffer for returning form started image * @entry: entry address of the relocated image */ struct efi_loaded_image_obj { struct efi_object header; - void *reloc_base; - aligned_u64 reloc_size; efi_status_t exit_status; struct jmp_buf_data exit_jmp; EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, @@ -320,10 +317,19 @@ efi_status_t efi_create_handle(efi_handle_t *handle); void efi_delete_handle(efi_handle_t obj); /* Call this to validate a handle and find the EFI object for it */ struct efi_object *efi_search_obj(const efi_handle_t handle); +/* Load image */ +efi_status_t EFIAPI efi_load_image(bool boot_policy, + efi_handle_t parent_image, + struct efi_device_path *file_path, + void *source_buffer, + efi_uintn_t source_size, + efi_handle_t *image_handle); /* Start image */ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, efi_uintn_t *exit_data_size, u16 **exit_data); +/* Unload image */ +efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle); /* Find a protocol on a handle */ efi_status_t efi_search_protocol(const efi_handle_t handle, const efi_guid_t *protocol_guid, diff --git a/include/ext4fs.h b/include/ext4fs.h index 2421011..34585d4 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h @@ -117,6 +117,12 @@ struct ext_filesystem { struct blk_desc *dev_desc; }; +struct ext_block_cache { + char *buf; + lbaint_t block; + int size; +}; + extern struct ext2_data *ext4fs_root; extern struct ext2fs_node *ext4fs_file; @@ -128,10 +134,11 @@ extern int gindex; int ext4fs_init(void); void ext4fs_deinit(void); int ext4fs_filename_unlink(char *filename); -int ext4fs_write(const char *fname, unsigned char *buffer, - unsigned long sizebytes); +int ext4fs_write(const char *fname, const char *buffer, + unsigned long sizebytes, int type); int ext4_write_file(const char *filename, void *buf, loff_t offset, loff_t len, loff_t *actwrite); +int ext4fs_create_link(const char *target, const char *fname); #endif struct ext_filesystem *get_fs(void); @@ -146,11 +153,15 @@ int ext4fs_size(const char *filename, loff_t *size); void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot); int ext4fs_devread(lbaint_t sector, int byte_offset, int byte_len, char *buf); void ext4fs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info); -long int read_allocated_block(struct ext2_inode *inode, int fileblock); +long int read_allocated_block(struct ext2_inode *inode, int fileblock, + struct ext_block_cache *cache); int ext4fs_probe(struct blk_desc *fs_dev_desc, disk_partition_t *fs_partition); int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len, loff_t *actread); int ext4_read_superblock(char *buffer); int ext4fs_uuid(char *uuid_str); +void ext_cache_init(struct ext_block_cache *cache); +void ext_cache_fini(struct ext_block_cache *cache); +int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size); #endif diff --git a/include/fs.h b/include/fs.h index aa3604d..6854597 100644 --- a/include/fs.h +++ b/include/fs.h @@ -191,6 +191,8 @@ int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int fstype); int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int fstype); +int do_ln(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int fstype); /* * Determine the UUID of the specified filesystem and print it. Optionally it is diff --git a/include/watchdog.h b/include/watchdog.h index 14073cf..3a357de 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -51,9 +51,15 @@ int init_func_watchdog_reset(void); #if defined(__ASSEMBLY__) #define WATCHDOG_RESET bl watchdog_reset #else - extern void watchdog_reset(void); + /* Don't require the watchdog to be enabled in SPL */ + #if defined(CONFIG_SPL_BUILD) && \ + !defined(CONFIG_SPL_WATCHDOG_SUPPORT) + #define WATCHDOG_RESET() {} + #else + extern void watchdog_reset(void); - #define WATCHDOG_RESET watchdog_reset + #define WATCHDOG_RESET watchdog_reset + #endif #endif #else /* diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 4170161..4fccadc 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -141,6 +141,7 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path, efi_deserialize_load_option(&lo, load_option); if (lo.attributes & LOAD_OPTION_ACTIVE) { + u32 attributes; efi_status_t ret; debug("%s: trying to load \"%ls\" from %pD\n", @@ -151,6 +152,16 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path, if (ret != EFI_SUCCESS) goto error; + attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + size = sizeof(n); + ret = EFI_CALL(efi_set_variable( + L"BootCurrent", + (efi_guid_t *)&efi_global_variable_guid, + attributes, size, &n)); + if (ret != EFI_SUCCESS) + goto error; + printf("Booting: %ls\n", lo.label); efi_dp_split_file_path(lo.file_path, device_path, file_path); } @@ -162,21 +173,53 @@ error: } /* - * Attempt to load, in the order specified by BootOrder EFI variable, the - * available load-options, finding and returning the first one that can - * be loaded successfully. + * Attempt to load from BootNext or in the order specified by BootOrder + * EFI variable, the available load-options, finding and returning + * the first one that can be loaded successfully. */ void *efi_bootmgr_load(struct efi_device_path **device_path, struct efi_device_path **file_path) { - uint16_t *bootorder; + u16 bootnext, *bootorder; efi_uintn_t size; void *image = NULL; int i, num; + efi_status_t ret; bs = systab.boottime; rs = systab.runtime; + /* BootNext */ + bootnext = 0; + size = sizeof(bootnext); + ret = EFI_CALL(efi_get_variable(L"BootNext", + (efi_guid_t *)&efi_global_variable_guid, + NULL, &size, &bootnext)); + if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { + /* BootNext does exist here */ + if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) + printf("BootNext must be 16-bit integer\n"); + + /* delete BootNext */ + ret = EFI_CALL(efi_set_variable( + L"BootNext", + (efi_guid_t *)&efi_global_variable_guid, + 0, 0, &bootnext)); + + /* load BootNext */ + if (ret == EFI_SUCCESS) { + if (size == sizeof(u16)) { + image = try_load_entry(bootnext, device_path, + file_path); + if (image) + return image; + } + } else { + printf("Deleting BootNext failed\n"); + } + } + + /* BootOrder */ bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size); if (!bootorder) { printf("BootOrder not defined\n"); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4fc550d..b215bd7 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -26,6 +26,9 @@ LIST_HEAD(efi_obj_list); /* List of all events */ LIST_HEAD(efi_events); +/* Handle of the currently executing image */ +static efi_handle_t current_image; + /* * If we're running on nasty systems (32bit ARM booting into non-EFI Linux) * we need to do trickery with caches. Since we don't want to break the EFI @@ -1519,6 +1522,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, efi_status_t ret; struct efi_loaded_image *info = NULL; struct efi_loaded_image_obj *obj = NULL; + struct efi_device_path *dp; /* In case of EFI_OUT_OF_RESOURCES avoid illegal free by caller. */ *handle_ptr = NULL; @@ -1542,15 +1546,19 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, if (device_path) { info->device_handle = efi_dp_find_obj(device_path, NULL); - /* - * When asking for the device path interface, return - * bootefi_device_path - */ - ret = efi_add_protocol(&obj->header, - &efi_guid_device_path, device_path); - if (ret != EFI_SUCCESS) + + dp = efi_dp_append(device_path, file_path); + if (!dp) { + ret = EFI_OUT_OF_RESOURCES; goto failure; + } + } else { + dp = NULL; } + ret = efi_add_protocol(&obj->header, + &efi_guid_loaded_image_device_path, dp); + if (ret != EFI_SUCCESS) + goto failure; /* * When asking for the loaded_image interface, just @@ -1679,18 +1687,19 @@ error: * * Return: status code */ -static efi_status_t EFIAPI efi_load_image(bool boot_policy, - efi_handle_t parent_image, - struct efi_device_path *file_path, - void *source_buffer, - efi_uintn_t source_size, - efi_handle_t *image_handle) +efi_status_t EFIAPI efi_load_image(bool boot_policy, + efi_handle_t parent_image, + struct efi_device_path *file_path, + void *source_buffer, + efi_uintn_t source_size, + efi_handle_t *image_handle) { struct efi_device_path *dp, *fp; struct efi_loaded_image *info = NULL; struct efi_loaded_image_obj **image_obj = (struct efi_loaded_image_obj **)image_handle; efi_status_t ret; + void *dest_buffer; EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image, file_path, source_buffer, source_size, image_handle); @@ -1706,7 +1715,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, } if (!source_buffer) { - ret = efi_load_image_from_path(file_path, &source_buffer, + ret = efi_load_image_from_path(file_path, &dest_buffer, &source_size); if (ret != EFI_SUCCESS) goto error; @@ -1719,155 +1728,31 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, /* In this case, file_path is the "device" path, i.e. * something like a HARDWARE_DEVICE:MEMORY_MAPPED */ - u64 addr; - void *dest_buffer; - - ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, - EFI_RUNTIME_SERVICES_CODE, - efi_size_in_pages(source_size), &addr); - if (ret != EFI_SUCCESS) - goto error; - dest_buffer = (void *)(uintptr_t)addr; - memcpy(dest_buffer, source_buffer, source_size); - source_buffer = dest_buffer; - + dest_buffer = source_buffer; dp = file_path; fp = NULL; } ret = efi_setup_loaded_image(dp, fp, image_obj, &info); - if (ret != EFI_SUCCESS) - goto error_invalid_image; - ret = efi_load_pe(*image_obj, source_buffer, info); - if (ret != EFI_SUCCESS) - goto error_invalid_image; - /* Update the type of the allocated memory */ - efi_add_memory_map((uintptr_t)source_buffer, - efi_size_in_pages(source_size), - info->image_code_type, false); - info->system_table = &systab; - info->parent_handle = parent_image; - return EFI_EXIT(EFI_SUCCESS); -error_invalid_image: - /* The image is invalid. Release all associated resources. */ - efi_free_pages((uintptr_t)source_buffer, - efi_size_in_pages(source_size)); - efi_delete_handle(*image_handle); - *image_handle = NULL; - free(info); + if (ret == EFI_SUCCESS) + ret = efi_load_pe(*image_obj, dest_buffer, info); + if (!source_buffer) + /* Release buffer to which file was loaded */ + efi_free_pages((uintptr_t)dest_buffer, + efi_size_in_pages(source_size)); + if (ret == EFI_SUCCESS) { + info->system_table = &systab; + info->parent_handle = parent_image; + } else { + /* The image is invalid. Release all associated resources. */ + efi_delete_handle(*image_handle); + *image_handle = NULL; + free(info); + } error: return EFI_EXIT(ret); } /** - * efi_start_image() - call the entry point of an image - * @image_handle: handle of the image - * @exit_data_size: size of the buffer - * @exit_data: buffer to receive the exit data of the called image - * - * This function implements the StartImage service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * Return: status code - */ -efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, - efi_uintn_t *exit_data_size, - u16 **exit_data) -{ - struct efi_loaded_image_obj *image_obj = - (struct efi_loaded_image_obj *)image_handle; - efi_status_t ret; - - EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); - - efi_is_direct_boot = false; - - /* call the image! */ - if (setjmp(&image_obj->exit_jmp)) { - /* - * We called the entry point of the child image with EFI_CALL - * in the lines below. The child image called the Exit() boot - * service efi_exit() which executed the long jump that brought - * us to the current line. This implies that the second half - * of the EFI_CALL macro has not been executed. - */ -#ifdef CONFIG_ARM - /* - * efi_exit() called efi_restore_gd(). We have to undo this - * otherwise __efi_entry_check() will put the wrong value into - * app_gd. - */ - gd = app_gd; -#endif - /* - * To get ready to call EFI_EXIT below we have to execute the - * missed out steps of EFI_CALL. - */ - assert(__efi_entry_check()); - debug("%sEFI: %lu returned by started image\n", - __efi_nesting_dec(), - (unsigned long)((uintptr_t)image_obj->exit_status & - ~EFI_ERROR_MASK)); - return EFI_EXIT(image_obj->exit_status); - } - - ret = EFI_CALL(image_obj->entry(image_handle, &systab)); - - /* - * Usually UEFI applications call Exit() instead of returning. - * But because the world doesn't consist of ponies and unicorns, - * we're happy to emulate that behavior on behalf of a payload - * that forgot. - */ - return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL)); -} - -/** - * efi_exit() - leave an EFI application or driver - * @image_handle: handle of the application or driver that is exiting - * @exit_status: status code - * @exit_data_size: size of the buffer in bytes - * @exit_data: buffer with data describing an error - * - * This function implements the Exit service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * Return: status code - */ -static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, - efi_status_t exit_status, - efi_uintn_t exit_data_size, - u16 *exit_data) -{ - /* - * TODO: We should call the unload procedure of the loaded - * image protocol. - */ - struct efi_loaded_image_obj *image_obj = - (struct efi_loaded_image_obj *)image_handle; - - EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status, - exit_data_size, exit_data); - - /* Make sure entry/exit counts for EFI world cross-overs match */ - EFI_EXIT(exit_status); - - /* - * But longjmp out with the U-Boot gd, not the application's, as - * the other end is a setjmp call inside EFI context. - */ - efi_restore_gd(); - - image_obj->exit_status = exit_status; - longjmp(&image_obj->exit_jmp, 1); - - panic("EFI application exited"); -} - -/** * efi_unload_image() - unload an EFI image * @image_handle: handle of the image to be unloaded * @@ -1878,7 +1763,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, * * Return: status code */ -static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle) +efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle) { struct efi_object *efiobj; @@ -2735,6 +2620,139 @@ out: } /** + * efi_start_image() - call the entry point of an image + * @image_handle: handle of the image + * @exit_data_size: size of the buffer + * @exit_data: buffer to receive the exit data of the called image + * + * This function implements the StartImage service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code + */ +efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, + efi_uintn_t *exit_data_size, + u16 **exit_data) +{ + struct efi_loaded_image_obj *image_obj = + (struct efi_loaded_image_obj *)image_handle; + efi_status_t ret; + void *info; + efi_handle_t parent_image = current_image; + + EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); + + /* Check parameters */ + ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image, + &info, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL)); + if (ret != EFI_SUCCESS) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + efi_is_direct_boot = false; + + /* call the image! */ + if (setjmp(&image_obj->exit_jmp)) { + /* + * We called the entry point of the child image with EFI_CALL + * in the lines below. The child image called the Exit() boot + * service efi_exit() which executed the long jump that brought + * us to the current line. This implies that the second half + * of the EFI_CALL macro has not been executed. + */ +#ifdef CONFIG_ARM + /* + * efi_exit() called efi_restore_gd(). We have to undo this + * otherwise __efi_entry_check() will put the wrong value into + * app_gd. + */ + gd = app_gd; +#endif + /* + * To get ready to call EFI_EXIT below we have to execute the + * missed out steps of EFI_CALL. + */ + assert(__efi_entry_check()); + debug("%sEFI: %lu returned by started image\n", + __efi_nesting_dec(), + (unsigned long)((uintptr_t)image_obj->exit_status & + ~EFI_ERROR_MASK)); + current_image = parent_image; + return EFI_EXIT(image_obj->exit_status); + } + + current_image = image_handle; + ret = EFI_CALL(image_obj->entry(image_handle, &systab)); + + /* + * Usually UEFI applications call Exit() instead of returning. + * But because the world doesn't consist of ponies and unicorns, + * we're happy to emulate that behavior on behalf of a payload + * that forgot. + */ + return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL)); +} + +/** + * efi_exit() - leave an EFI application or driver + * @image_handle: handle of the application or driver that is exiting + * @exit_status: status code + * @exit_data_size: size of the buffer in bytes + * @exit_data: buffer with data describing an error + * + * This function implements the Exit service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code + */ +static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, + efi_status_t exit_status, + efi_uintn_t exit_data_size, + u16 *exit_data) +{ + /* + * TODO: We should call the unload procedure of the loaded + * image protocol. + */ + efi_status_t ret; + void *info; + struct efi_loaded_image_obj *image_obj = + (struct efi_loaded_image_obj *)image_handle; + + EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status, + exit_data_size, exit_data); + + /* Check parameters */ + if (image_handle != current_image) + goto out; + ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image, + &info, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL)); + if (ret != EFI_SUCCESS) + goto out; + + /* Make sure entry/exit counts for EFI world cross-overs match */ + EFI_EXIT(exit_status); + + /* + * But longjmp out with the U-Boot gd, not the application's, as + * the other end is a setjmp call inside EFI context. + */ + efi_restore_gd(); + + image_obj->exit_status = exit_status; + longjmp(&image_obj->exit_jmp, 1); + + panic("EFI application exited"); +out: + return EFI_EXIT(EFI_INVALID_PARAMETER); +} + +/** * efi_handle_protocol() - get interface of a protocol on a handle * @handle: handle on which the protocol shall be opened * @protocol: GUID of the protocol diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 8e0965b..051fc1d 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -797,9 +797,26 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke_ex( ret = EFI_NOT_READY; goto out; } + /* + * CTRL+A - CTRL+Z have to be signaled as a - z. + * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z. + */ + switch (next_key.key.unicode_char) { + case 0x01 ... 0x07: + case 0x0b ... 0x0c: + case 0x0e ... 0x1a: + if (!(next_key.key_state.key_toggle_state & + EFI_CAPS_LOCK_ACTIVE) ^ + !(next_key.key_state.key_shift_state & + (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED))) + next_key.key.unicode_char += 0x40; + else + next_key.key.unicode_char += 0x60; + } *key_data = next_key; key_available = false; efi_con_in.wait_for_key->is_signaled = false; + out: return EFI_EXIT(ret); } diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 0483403..182d735 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -135,6 +135,25 @@ static int sanitize_path(char *path) } /** + * efi_create_file() - create file or directory + * + * @fh: file handle + * @attributes: attributes for newly created file + * Returns: 0 for success + */ +static int efi_create_file(struct file_handle *fh, u64 attributes) +{ + loff_t actwrite; + void *buffer = &actwrite; + + if (attributes & EFI_FILE_DIRECTORY) + return fs_mkdir(fh->path); + else + return fs_write(fh->path, map_to_sysmem(buffer), 0, 0, + &actwrite); +} + +/** * file_open() - open a file handle * * @fs: file system @@ -176,6 +195,7 @@ static struct efi_file_handle *file_open(struct file_system *fs, if (parent) { char *p = fh->path; + int exists; if (plen > 0) { strcpy(p, parent->path); @@ -192,18 +212,17 @@ static struct efi_file_handle *file_open(struct file_system *fs, if (set_blk_dev(fh)) goto error; - if ((mode & EFI_FILE_MODE_CREATE) && - (attributes & EFI_FILE_DIRECTORY)) { - if (fs_mkdir(fh->path)) - goto error; - } else if (!((mode & EFI_FILE_MODE_CREATE) || - fs_exists(fh->path))) - goto error; - + exists = fs_exists(fh->path); /* fs_exists() calls fs_close(), so open file system again */ if (set_blk_dev(fh)) goto error; + if (!exists) { + if (!(mode & EFI_FILE_MODE_CREATE) || + efi_create_file(fh, attributes)) + goto error; + } + /* figure out if file is a directory: */ fh->isdir = is_dir(fh); } else { @@ -257,10 +276,12 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, /* Open file */ *new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes); - if (*new_handle) + if (*new_handle) { + EFI_PRINT("file handle %p\n", *new_handle); ret = EFI_SUCCESS; - else + } else { ret = EFI_NOT_FOUND; + } out: return EFI_EXIT(ret); } @@ -616,9 +637,72 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, efi_uintn_t buffer_size, void *buffer) { - EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer); + struct file_handle *fh = to_fh(file); + efi_status_t ret = EFI_UNSUPPORTED; + + EFI_ENTRY("%p, %pUl, %zu, %p", file, info_type, buffer_size, buffer); + + if (!guidcmp(info_type, &efi_file_info_guid)) { + struct efi_file_info *info = (struct efi_file_info *)buffer; + char *filename = basename(fh); + char *new_file_name, *pos; + loff_t file_size; - return EFI_EXIT(EFI_UNSUPPORTED); + if (buffer_size < sizeof(struct efi_file_info)) { + ret = EFI_BAD_BUFFER_SIZE; + goto out; + } + /* We cannot change the directory attribute */ + if (!fh->isdir != !(info->attribute & EFI_FILE_DIRECTORY)) { + ret = EFI_ACCESS_DENIED; + goto out; + } + /* Check for renaming */ + new_file_name = malloc(utf16_utf8_strlen(info->file_name)); + if (!new_file_name) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + pos = new_file_name; + utf16_utf8_strcpy(&pos, info->file_name); + if (strcmp(new_file_name, filename)) { + /* TODO: we do not support renaming */ + EFI_PRINT("Renaming not supported\n"); + free(new_file_name); + ret = EFI_ACCESS_DENIED; + goto out; + } + free(new_file_name); + /* Check for truncation */ + if (set_blk_dev(fh)) { + ret = EFI_DEVICE_ERROR; + goto out; + } + if (fs_size(fh->path, &file_size)) { + ret = EFI_DEVICE_ERROR; + goto out; + } + if (file_size != info->file_size) { + /* TODO: we do not support truncation */ + EFI_PRINT("Truncation not supported\n"); + ret = EFI_ACCESS_DENIED; + goto out; + } + /* + * We do not care for the other attributes + * TODO: Support read only + */ + ret = EFI_SUCCESS; + } else if (!guidcmp(info_type, &efi_file_system_info_guid)) { + if (buffer_size < sizeof(struct efi_file_system_info)) { + ret = EFI_BAD_BUFFER_SIZE; + goto out; + } + } else { + ret = EFI_UNSUPPORTED; + } +out: + return EFI_EXIT(ret); } static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file) diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index fe66e7b..93feefd 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -14,6 +14,8 @@ const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID; const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID; const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID; +const efi_guid_t efi_guid_loaded_image_device_path + = LOADED_IMAGE_DEVICE_PATH_GUID; const efi_guid_t efi_simple_file_system_protocol_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; @@ -59,10 +61,10 @@ static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj, { printf("UEFI image"); printf(" [0x%p:0x%p]", - obj->reloc_base, obj->reloc_base + obj->reloc_size - 1); - if (pc && pc >= obj->reloc_base && - pc < obj->reloc_base + obj->reloc_size) - printf(" pc=0x%zx", pc - obj->reloc_base); + image->image_base, image->image_base + image->image_size - 1); + if (pc && pc >= image->image_base && + pc < image->image_base + image->image_size) + printf(" pc=0x%zx", pc - image->image_base); if (image->file_path) printf(" '%pD'", image->file_path); printf("\n"); @@ -227,7 +229,6 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, unsigned long rel_size; int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC; uint64_t image_base; - uint64_t image_size; unsigned long virt_size = 0; int supported = 0; @@ -271,7 +272,6 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, IMAGE_NT_HEADERS64 *nt64 = (void *)nt; IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader; image_base = opt->ImageBase; - image_size = opt->SizeOfImage; efi_set_code_and_data_type(loaded_image_info, opt->Subsystem); efi_reloc = efi_alloc(virt_size, loaded_image_info->image_code_type); @@ -287,7 +287,6 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, } else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader; image_base = opt->ImageBase; - image_size = opt->SizeOfImage; efi_set_code_and_data_type(loaded_image_info, opt->Subsystem); efi_reloc = efi_alloc(virt_size, loaded_image_info->image_code_type); @@ -306,6 +305,11 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, return EFI_LOAD_ERROR; } + /* Copy PE headers */ + memcpy(efi_reloc, efi, sizeof(*dos) + sizeof(*nt) + + nt->FileHeader.SizeOfOptionalHeader + + num_sections * sizeof(IMAGE_SECTION_HEADER)); + /* Load sections into RAM */ for (i = num_sections - 1; i >= 0; i--) { IMAGE_SECTION_HEADER *sec = §ions[i]; @@ -330,10 +334,8 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, invalidate_icache_all(); /* Populate the loaded image interface bits */ - loaded_image_info->image_base = efi; - loaded_image_info->image_size = image_size; - handle->reloc_base = efi_reloc; - handle->reloc_size = virt_size; + loaded_image_info->image_base = efi_reloc; + loaded_image_info->image_size = virt_size; return EFI_SUCCESS; } diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 55622d2..dbe29b8 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -15,6 +15,9 @@ DECLARE_GLOBAL_DATA_PTR; +/* Magic number identifying memory allocated from pool */ +#define EFI_ALLOC_POOL_MAGIC 0x1fe67ddf6491caa2 + efi_uintn_t efi_memory_map_key; struct efi_mem_list { @@ -33,7 +36,12 @@ LIST_HEAD(efi_mem); void *efi_bounce_buffer; #endif -/* +/** + * efi_pool_allocation - memory block allocated from pool + * + * @num_pages: number of pages allocated + * @checksum: checksum + * * U-Boot services each EFI AllocatePool request as a separate * (multiple) page allocation. We have to track the number of pages * to be able to free the correct amount later. @@ -43,9 +51,26 @@ void *efi_bounce_buffer; */ struct efi_pool_allocation { u64 num_pages; + u64 checksum; char data[] __aligned(ARCH_DMA_MINALIGN); }; +/** + * checksum() - calculate checksum for memory allocated from pool + * + * @alloc: allocation header + * Return: checksum, always non-zero + */ +static u64 checksum(struct efi_pool_allocation *alloc) +{ + u64 addr = (uintptr_t)alloc; + u64 ret = (addr >> 32) ^ (addr << 32) ^ alloc->num_pages ^ + EFI_ALLOC_POOL_MAGIC; + if (!ret) + ++ret; + return ret; +} + /* * Sorts the memory list from highest address to lowest address * @@ -204,8 +229,8 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, bool carve_again; uint64_t carved_pages = 0; - debug("%s: 0x%llx 0x%llx %d %s\n", __func__, - start, pages, memory_type, overlap_only_ram ? "yes" : "no"); + EFI_PRINT("%s: 0x%llx 0x%llx %d %s\n", __func__, + start, pages, memory_type, overlap_only_ram ? "yes" : "no"); if (memory_type >= EFI_MAX_MEMORY_TYPE) return EFI_INVALID_PARAMETER; @@ -409,17 +434,24 @@ void *efi_alloc(uint64_t len, int memory_type) return NULL; } -/* - * Free memory pages. +/** + * efi_free_pages() - free memory pages * - * @memory start of the memory area to be freed - * @pages number of pages to be freed - * @return status code + * @memory: start of the memory area to be freed + * @pages: number of pages to be freed + * Return: status code */ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) { uint64_t r = 0; + /* Sanity check */ + if (!memory || (memory & EFI_PAGE_MASK)) { + printf("%s: illegal free 0x%llx, 0x%zx\n", __func__, + memory, pages); + return EFI_INVALID_PARAMETER; + } + r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false); /* Merging of adjacent free regions is missing */ @@ -429,13 +461,13 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) return EFI_NOT_FOUND; } -/* - * Allocate memory from pool. +/** + * efi_allocate_pool - allocate memory from pool * - * @pool_type type of the pool from which memory is to be allocated - * @size number of bytes to be allocated - * @buffer allocated memory - * @return status code + * @pool_type: type of the pool from which memory is to be allocated + * @size: number of bytes to be allocated + * @buffer: allocated memory + * Return: status code */ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer) { @@ -458,17 +490,18 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer) if (r == EFI_SUCCESS) { alloc = (struct efi_pool_allocation *)(uintptr_t)addr; alloc->num_pages = num_pages; + alloc->checksum = checksum(alloc); *buffer = alloc->data; } return r; } -/* - * Free memory from pool. +/** + * efi_free_pool() - free memory from pool * - * @buffer start of memory to be freed - * @return status code + * @buffer: start of memory to be freed + * Return: status code */ efi_status_t efi_free_pool(void *buffer) { @@ -479,8 +512,15 @@ efi_status_t efi_free_pool(void *buffer) return EFI_INVALID_PARAMETER; alloc = container_of(buffer, struct efi_pool_allocation, data); - /* Sanity check, was the supplied address returned by allocate_pool */ - assert(((uintptr_t)alloc & EFI_PAGE_MASK) == 0); + + /* Check that this memory was allocated by efi_allocate_pool() */ + if (((uintptr_t)alloc & EFI_PAGE_MASK) || + alloc->checksum != checksum(alloc)) { + printf("%s: illegal free 0x%p\n", __func__, buffer); + return EFI_INVALID_PARAMETER; + } + /* Avoid double free */ + alloc->checksum = 0; r = efi_free_pages((uintptr_t)alloc, alloc->num_pages); diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 8266d06..a908843 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -10,6 +10,9 @@ #define OBJ_LIST_NOT_INITIALIZED 1 +/* Language code for American English according to RFC 4646 */ +#define EN_US L"en-US" + static efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED; /* Initialize and populate EFI object list */ @@ -24,6 +27,30 @@ efi_status_t efi_init_obj_list(void) */ efi_save_gd(); + /* + * Variable PlatformLang defines the language that the machine has been + * configured for. + */ + ret = EFI_CALL(efi_set_variable(L"PlatformLang", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(EN_US), EN_US)); + if (ret != EFI_SUCCESS) + goto out; + + /* + * Variable PlatformLangCodes defines the language codes that the + * machine can support. + */ + ret = EFI_CALL(efi_set_variable(L"PlatformLangCodes", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(EN_US), EN_US)); + if (ret != EFI_SUCCESS) + goto out; + /* Initialize once only */ if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) return efi_obj_list_initialized; diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 699f418..37728c3 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -180,7 +180,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, if (ret) return EFI_EXIT(ret); - debug("%s: get '%s'\n", __func__, native_name); + EFI_PRINT("get '%s'\n", native_name); val = env_get(native_name); free(native_name); @@ -211,7 +211,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, if (hex2bin(data, s, len)) return EFI_EXIT(EFI_DEVICE_ERROR); - debug("%s: got value: \"%s\"\n", __func__, s); + EFI_PRINT("got value: \"%s\"\n", s); } else if ((s = prefix(val, "(utf8)"))) { unsigned len = strlen(s) + 1; @@ -226,9 +226,9 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, memcpy(data, s, len); ((char *)data)[len] = '\0'; - debug("%s: got value: \"%s\"\n", __func__, (char *)data); + EFI_PRINT("got value: \"%s\"\n", (char *)data); } else { - debug("%s: invalid value: '%s'\n", __func__, val); + EFI_PRINT("invalid value: '%s'\n", val); return EFI_EXIT(EFI_DEVICE_ERROR); } @@ -485,7 +485,7 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, s = bin2hex(s, data, data_size); *s = '\0'; - debug("%s: setting: %s=%s\n", __func__, native_name, val); + EFI_PRINT("setting: %s=%s\n", native_name, val); if (env_set(native_name, val)) ret = EFI_DEVICE_ERROR; diff --git a/lib/efi_selftest/efi_selftest_miniapp_exit.c b/lib/efi_selftest/efi_selftest_miniapp_exit.c index 2ffdd65..d63b9e3 100644 --- a/lib/efi_selftest/efi_selftest_miniapp_exit.c +++ b/lib/efi_selftest/efi_selftest_miniapp_exit.c @@ -11,22 +11,70 @@ #include <common.h> #include <efi_api.h> -/* +static efi_guid_t loaded_image_protocol_guid = LOADED_IMAGE_GUID; + +/** + * check_loaded_image_protocol() - check image_base/image_size + * + * Try to open the loaded image protocol. Check that this function is located + * between image_base and image_base + image_size. + * + * @image_handle: handle of the loaded image + * @systable: system table + * @return: status code + */ +static efi_status_t EFIAPI check_loaded_image_protocol + (efi_handle_t image_handle, struct efi_system_table *systable) +{ + struct efi_simple_text_output_protocol *cout = systable->con_out; + struct efi_boot_services *boottime = systable->boottime; + struct efi_loaded_image *loaded_image_protocol; + efi_status_t ret; + + /* + * Open the loaded image protocol. + */ + ret = boottime->open_protocol + (image_handle, &loaded_image_protocol_guid, + (void **)&loaded_image_protocol, NULL, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + cout->output_string(cout, + L"Could not open loaded image protocol"); + return ret; + } + if ((void *)check_loaded_image_protocol < + loaded_image_protocol->image_base || + (void *)check_loaded_image_protocol >= + loaded_image_protocol->image_base + + loaded_image_protocol->image_size) { + cout->output_string(cout, + L"Incorrect image_base or image_size\n"); + return EFI_NOT_FOUND; + } + return EFI_SUCCESS; +} + +/** * Entry point of the EFI application. * - * @handle handle of the loaded image - * @systable system table - * @return status code + * @handle: handle of the loaded image + * @systable: system table + * @return: status code */ efi_status_t EFIAPI efi_main(efi_handle_t handle, struct efi_system_table *systable) { struct efi_simple_text_output_protocol *con_out = systable->con_out; + efi_status_t ret = EFI_UNSUPPORTED; con_out->output_string(con_out, L"EFI application calling Exit\n"); + if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS) + ret = EFI_NOT_FOUND; + /* The return value is checked by the calling test */ - systable->boottime->exit(handle, EFI_UNSUPPORTED, 0, NULL); + systable->boottime->exit(handle, ret, 0, NULL); /* * This statement should not be reached. diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 54b160d..56dbbe1 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -179,10 +179,10 @@ MKIMAGEFLAGS_boot.bin = -T atmelimage ifeq ($(CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER),y) MKIMAGEFLAGS_boot.bin += -n $(shell $(obj)/../tools/atmel_pmecc_params) -boot.bin: $(obj)/../tools/atmel_pmecc_params +$(obj)/boot.bin: $(obj)/../tools/atmel_pmecc_params endif -boot.bin: $(obj)/u-boot-spl.bin FORCE +$(obj)/boot.bin: $(obj)/u-boot-spl.bin FORCE $(call if_changed,mkimage) else ifdef CONFIG_ARCH_ZYNQ @@ -225,7 +225,7 @@ endif endif ifeq ($(CONFIG_SYS_SOC),"at91") -ALL-y += boot.bin +ALL-y += $(obj)/boot.bin endif ALL-$(CONFIG_SPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-16bit-spl.bin diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py index 36b35ee..bc226a8 100644 --- a/test/py/tests/test_efi_selftest.py +++ b/test/py/tests/test_efi_selftest.py @@ -141,7 +141,7 @@ def test_efi_selftest_text_input_ex(u_boot_console): u_boot_console.run_command(cmd=chr(4), wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 4 \(unknown\), scan code 0 \(CTRL\+Null\)']) + ['Unicode char 100 \\(\'d\'\\), scan code 0 \\(CTRL\\+Null\\)']) if m != 0: raise Exception('EOT failed in \'text input\' test') u_boot_console.drain_console() diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py index 43eeb4b..9324657 100644 --- a/test/py/tests/test_fs/conftest.py +++ b/test/py/tests/test_fs/conftest.py @@ -13,6 +13,7 @@ supported_fs_basic = ['fat16', 'fat32', 'ext4'] supported_fs_ext = ['fat16', 'fat32'] supported_fs_mkdir = ['fat16', 'fat32'] supported_fs_unlink = ['fat16', 'fat32'] +supported_fs_symlink = ['ext4'] # # Filesystem test specific setup @@ -48,6 +49,7 @@ def pytest_configure(config): global supported_fs_ext global supported_fs_mkdir global supported_fs_unlink + global supported_fs_symlink def intersect(listA, listB): return [x for x in listA if x in listB] @@ -59,6 +61,7 @@ def pytest_configure(config): supported_fs_ext = intersect(supported_fs, supported_fs_ext) supported_fs_mkdir = intersect(supported_fs, supported_fs_mkdir) supported_fs_unlink = intersect(supported_fs, supported_fs_unlink) + supported_fs_symlink = intersect(supported_fs, supported_fs_symlink) def pytest_generate_tests(metafunc): """Parametrize fixtures, fs_obj_xxx @@ -84,6 +87,9 @@ def pytest_generate_tests(metafunc): if 'fs_obj_unlink' in metafunc.fixturenames: metafunc.parametrize('fs_obj_unlink', supported_fs_unlink, indirect=True, scope='module') + if 'fs_obj_symlink' in metafunc.fixturenames: + metafunc.parametrize('fs_obj_symlink', supported_fs_symlink, + indirect=True, scope='module') # # Helper functions @@ -143,6 +149,8 @@ def mk_fs(config, fs_type, size, id): mkfs_opt = '-F 16' elif fs_type == 'fat32': mkfs_opt = '-F 32' + elif fs_type == 'ext4': + mkfs_opt = '-O ^metadata_csum' else: mkfs_opt = '' @@ -523,3 +531,72 @@ def fs_obj_unlink(request, u_boot_config): call('rmdir %s' % mount_dir, shell=True) if fs_img: call('rm -f %s' % fs_img, shell=True) + +# +# Fixture for symlink fs test +# +# NOTE: yield_fixture was deprecated since pytest-3.0 +@pytest.yield_fixture() +def fs_obj_symlink(request, u_boot_config): + """Set up a file system to be used in symlink fs test. + + Args: + request: Pytest request object. + u_boot_config: U-boot configuration. + + Return: + A fixture for basic fs test, i.e. a triplet of file system type, + volume file name and a list of MD5 hashes. + """ + fs_type = request.param + fs_img = '' + + fs_ubtype = fstype_to_ubname(fs_type) + check_ubconfig(u_boot_config, fs_ubtype) + + mount_dir = u_boot_config.persistent_data_dir + '/mnt' + + small_file = mount_dir + '/' + SMALL_FILE + medium_file = mount_dir + '/' + MEDIUM_FILE + + try: + + # 3GiB volume + fs_img = mk_fs(u_boot_config, fs_type, 0x40000000, '1GB') + + # Mount the image so we can populate it. + check_call('mkdir -p %s' % mount_dir, shell=True) + mount_fs(fs_type, fs_img, mount_dir) + + # Create a subdirectory. + check_call('mkdir %s/SUBDIR' % mount_dir, shell=True) + + # Create a small file in this image. + check_call('dd if=/dev/urandom of=%s bs=1M count=1' + % small_file, shell=True) + + # Create a medium file in this image. + check_call('dd if=/dev/urandom of=%s bs=10M count=1' + % medium_file, shell=True) + + # Generate the md5sums of reads that we will test against small file + out = check_output( + 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum' + % small_file, shell=True) + md5val = [out.split()[0]] + out = check_output( + 'dd if=%s bs=10M skip=0 count=1 2> /dev/null | md5sum' + % medium_file, shell=True) + md5val.extend([out.split()[0]]) + + umount_fs(mount_dir) + except CalledProcessError: + pytest.skip('Setup failed for filesystem: ' + fs_type) + return + else: + yield [fs_ubtype, fs_img, md5val] + finally: + umount_fs(mount_dir) + call('rmdir %s' % mount_dir, shell=True) + if fs_img: + call('rm -f %s' % fs_img, shell=True) diff --git a/test/py/tests/test_fs/fstest_defs.py b/test/py/tests/test_fs/fstest_defs.py index 5f10756..35b2bb6 100644 --- a/test/py/tests/test_fs/fstest_defs.py +++ b/test/py/tests/test_fs/fstest_defs.py @@ -6,6 +6,9 @@ MIN_FILE='testfile' # $SMALL_FILE is the name of the 1MB file in the file system image SMALL_FILE='1MB.file' +# $MEDIUM_FILE is the name of the 10MB file in the file system image +MEDIUM_FILE='10MB.file' + # $BIG_FILE is the name of the 2.5GB file in the file system image BIG_FILE='2.5GB.file' diff --git a/test/py/tests/test_fs/fstest_helpers.py b/test/py/tests/test_fs/fstest_helpers.py new file mode 100644 index 0000000..faec298 --- /dev/null +++ b/test/py/tests/test_fs/fstest_helpers.py @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2019, Texas Instrument +# Author: JJ Hiblot <jjhiblot@ti.com> +# + +from subprocess import check_call, CalledProcessError + +def assert_fs_integrity(fs_type, fs_img): + try: + if fs_type == 'ext4': + check_call('fsck.ext4 -n -f %s' % fs_img, shell=True) + except CalledProcessError: + raise diff --git a/test/py/tests/test_fs/test_basic.py b/test/py/tests/test_fs/test_basic.py index 140ca29..71f3e86 100644 --- a/test/py/tests/test_fs/test_basic.py +++ b/test/py/tests/test_fs/test_basic.py @@ -11,6 +11,7 @@ This test verifies basic read/write operation on file system. import pytest import re from fstest_defs import * +from fstest_helpers import assert_fs_integrity @pytest.mark.boardspec('sandbox') @pytest.mark.slow @@ -237,6 +238,7 @@ class TestFsBasic(object): 'md5sum %x $filesize' % ADDR, 'setenv filesize']) assert(md5val[0] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_fs12(self, u_boot_console, fs_obj_basic): """ @@ -252,6 +254,7 @@ class TestFsBasic(object): 'host bind 0 %s' % fs_img, '%swrite host 0:0 %x /. 0x10' % (fs_type, ADDR)]) assert('Unable to write' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_fs13(self, u_boot_console, fs_obj_basic): """ @@ -286,3 +289,4 @@ class TestFsBasic(object): 'md5sum %x $filesize' % ADDR, 'setenv filesize']) assert(md5val[0] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) diff --git a/test/py/tests/test_fs/test_ext.py b/test/py/tests/test_fs/test_ext.py index 06cad55..2c47738 100644 --- a/test/py/tests/test_fs/test_ext.py +++ b/test/py/tests/test_fs/test_ext.py @@ -11,6 +11,7 @@ This test verifies extended write operation on file system. import pytest import re from fstest_defs import * +from fstest_helpers import assert_fs_integrity @pytest.mark.boardspec('sandbox') @pytest.mark.slow @@ -36,6 +37,7 @@ class TestFsExt(object): 'md5sum %x $filesize' % ADDR, 'setenv filesize']) assert(md5val[0] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_fs_ext2(self, u_boot_console, fs_obj_ext): """ @@ -58,6 +60,7 @@ class TestFsExt(object): 'md5sum %x $filesize' % ADDR, 'setenv filesize']) assert(md5val[0] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_fs_ext3(self, u_boot_console, fs_obj_ext): """ @@ -72,6 +75,7 @@ class TestFsExt(object): '%swrite host 0:0 %x /dir1/none/%s.w3 $filesize' % (fs_type, ADDR, MIN_FILE)]) assert('Unable to write "/dir1/none/' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_fs_ext4(self, u_boot_console, fs_obj_ext): """ @@ -104,6 +108,7 @@ class TestFsExt(object): 'md5sum %x $filesize' % ADDR, 'setenv filesize']) assert(md5val[1] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_fs_ext5(self, u_boot_console, fs_obj_ext): """ @@ -136,6 +141,7 @@ class TestFsExt(object): 'md5sum %x $filesize' % ADDR, 'setenv filesize']) assert(md5val[2] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_fs_ext6(self, u_boot_console, fs_obj_ext): """ @@ -160,6 +166,7 @@ class TestFsExt(object): 'printenv filesize', 'setenv filesize']) assert('filesize=0' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_fs_ext7(self, u_boot_console, fs_obj_ext): """ @@ -192,6 +199,7 @@ class TestFsExt(object): 'md5sum %x $filesize' % ADDR, 'setenv filesize']) assert(md5val[3] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_fs_ext8(self, u_boot_console, fs_obj_ext): """ @@ -209,6 +217,7 @@ class TestFsExt(object): '%swrite host 0:0 %x /dir1/%s.w8 0x1400 %x' % (fs_type, ADDR, MIN_FILE, 0x100000 + 0x1400)) assert('Unable to write "/dir1' in output) + assert_fs_integrity(fs_type, fs_img) def test_fs_ext9(self, u_boot_console, fs_obj_ext): """ @@ -223,3 +232,4 @@ class TestFsExt(object): '%swrite host 0:0 %x /dir1/%s.w9 0x1400 0x1400' % (fs_type, ADDR, MIN_FILE)]) assert('Unable to write "/dir1' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) diff --git a/test/py/tests/test_fs/test_mkdir.py b/test/py/tests/test_fs/test_mkdir.py index b3fe11c..fa9561e 100644 --- a/test/py/tests/test_fs/test_mkdir.py +++ b/test/py/tests/test_fs/test_mkdir.py @@ -9,6 +9,7 @@ This test verifies mkdir operation on file system. """ import pytest +from fstest_helpers import assert_fs_integrity @pytest.mark.boardspec('sandbox') @pytest.mark.slow @@ -29,6 +30,8 @@ class TestMkdir(object): '%sls host 0:0 dir1' % fs_type) assert('./' in output) assert('../' in output) + assert_fs_integrity(fs_type, fs_img) + def test_mkdir2(self, u_boot_console, fs_obj_mkdir): """ @@ -46,6 +49,7 @@ class TestMkdir(object): '%sls host 0:0 dir1/dir2' % fs_type) assert('./' in output) assert('../' in output) + assert_fs_integrity(fs_type, fs_img) def test_mkdir3(self, u_boot_console, fs_obj_mkdir): """ @@ -58,6 +62,7 @@ class TestMkdir(object): 'host bind 0 %s' % fs_img, '%smkdir host 0:0 none/dir3' % fs_type]) assert('Unable to create a directory' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_mkdir4(self, u_boot_console, fs_obj_mkdir): """ @@ -69,6 +74,7 @@ class TestMkdir(object): 'host bind 0 %s' % fs_img, '%smkdir host 0:0 .' % fs_type]) assert('Unable to create a directory' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_mkdir5(self, u_boot_console, fs_obj_mkdir): """ @@ -80,6 +86,7 @@ class TestMkdir(object): 'host bind 0 %s' % fs_img, '%smkdir host 0:0 ..' % fs_type]) assert('Unable to create a directory' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_mkdir6(self, u_boot_console, fs_obj_mkdir): """ @@ -111,3 +118,4 @@ class TestMkdir(object): '%sls host 0:0 dir6/0123456789abcdef13/..' % fs_type) assert('0123456789abcdef00/' in output) assert('0123456789abcdef13/' in output) + assert_fs_integrity(fs_type, fs_img) diff --git a/test/py/tests/test_fs/test_symlink.py b/test/py/tests/test_fs/test_symlink.py new file mode 100644 index 0000000..9ced101 --- /dev/null +++ b/test/py/tests/test_fs/test_symlink.py @@ -0,0 +1,130 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2019, Texas Instrument +# Author: Jean-Jacques Hiblot <jjhiblot@ti.com> +# +# U-Boot File System:symlink Test + +""" +This test verifies unlink operation (deleting a file or a directory) +on file system. +""" + +import pytest +import re +from fstest_defs import * +from fstest_helpers import assert_fs_integrity + + +@pytest.mark.boardspec('sandbox') +@pytest.mark.slow +class TestSymlink(object): + def test_symlink1(self, u_boot_console, fs_obj_symlink): + """ + Test Case 1 - create a link. and follow it when reading + """ + fs_type, fs_img, md5val = fs_obj_symlink + with u_boot_console.log.section('Test Case 1 - create link and read'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'ln host 0:0 %s /%s.link ' % (SMALL_FILE, SMALL_FILE), + ]) + assert('' in ''.join(output)) + + output = u_boot_console.run_command_list([ + '%sload host 0:0 %x /%s.link' % (fs_type, ADDR, SMALL_FILE), + 'printenv filesize']) + assert('filesize=100000' in ''.join(output)) + + # Test Case 4b - Read full 1MB of small file + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[0] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_symlink2(self, u_boot_console, fs_obj_symlink): + """ + Test Case 2 - create chained links + """ + fs_type, fs_img, md5val = fs_obj_symlink + with u_boot_console.log.section('Test Case 2 - create chained links'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'ln host 0:0 %s /%s.link1 ' % (SMALL_FILE, SMALL_FILE), + 'ln host 0:0 /%s.link1 /SUBDIR/%s.link2' % ( + SMALL_FILE, SMALL_FILE), + 'ln host 0:0 SUBDIR/%s.link2 /%s.link3' % ( + SMALL_FILE, SMALL_FILE), + ]) + assert('' in ''.join(output)) + + output = u_boot_console.run_command_list([ + '%sload host 0:0 %x /%s.link3' % (fs_type, ADDR, SMALL_FILE), + 'printenv filesize']) + assert('filesize=100000' in ''.join(output)) + + # Test Case 4b - Read full 1MB of small file + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[0] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_symlink3(self, u_boot_console, fs_obj_symlink): + """ + Test Case 3 - replace file/link with link + """ + fs_type, fs_img, md5val = fs_obj_symlink + with u_boot_console.log.section('Test Case 1 - create link and read'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'ln host 0:0 %s /%s ' % (MEDIUM_FILE, SMALL_FILE), + 'ln host 0:0 %s /%s.link ' % (MEDIUM_FILE, MEDIUM_FILE), + ]) + assert('' in ''.join(output)) + + output = u_boot_console.run_command_list([ + '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE), + 'printenv filesize']) + assert('filesize=a00000' in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[1] in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'ln host 0:0 %s.link /%s ' % (MEDIUM_FILE, SMALL_FILE), + '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE), + 'printenv filesize']) + assert('filesize=a00000' in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[1] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_symlink4(self, u_boot_console, fs_obj_symlink): + """ + Test Case 4 - create a broken link + """ + fs_type, fs_img, md5val = fs_obj_symlink + with u_boot_console.log.section('Test Case 1 - create link and read'): + + output = u_boot_console.run_command_list([ + 'setenv filesize', + 'ln host 0:0 nowhere /link ', + ]) + assert('' in ''.join(output)) + + output = u_boot_console.run_command( + '%sload host 0:0 %x /link' % + (fs_type, ADDR)) + with u_boot_console.disable_check('error_notification'): + output = u_boot_console.run_command('printenv filesize') + assert('"filesize" not defined' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) diff --git a/test/py/tests/test_fs/test_unlink.py b/test/py/tests/test_fs/test_unlink.py index 2b81746..97aafc6 100644 --- a/test/py/tests/test_fs/test_unlink.py +++ b/test/py/tests/test_fs/test_unlink.py @@ -10,6 +10,7 @@ on file system. """ import pytest +from fstest_helpers import assert_fs_integrity @pytest.mark.boardspec('sandbox') @pytest.mark.slow @@ -30,6 +31,7 @@ class TestUnlink(object): '%sls host 0:0 dir1/' % fs_type) assert(not 'file1' in output) assert('file2' in output) + assert_fs_integrity(fs_type, fs_img) def test_unlink2(self, u_boot_console, fs_obj_unlink): """ @@ -48,6 +50,7 @@ class TestUnlink(object): output = u_boot_console.run_command( '%sls host 0:0 dir2' % fs_type) assert('0 file(s), 2 dir(s)' in output) + assert_fs_integrity(fs_type, fs_img) def test_unlink3(self, u_boot_console, fs_obj_unlink): """ @@ -59,6 +62,7 @@ class TestUnlink(object): 'host bind 0 %s' % fs_img, '%srm host 0:0 dir1/nofile' % fs_type]) assert('nofile: doesn\'t exist' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_unlink4(self, u_boot_console, fs_obj_unlink): """ @@ -71,9 +75,10 @@ class TestUnlink(object): '%srm host 0:0 dir4' % fs_type]) assert('' == ''.join(output)) - output = u_boot_console.run_command( - '%sls host 0:0 /' % fs_type) - assert(not 'dir4' in output) + output = u_boot_console.run_command( + '%sls host 0:0 /' % fs_type) + assert(not 'dir4' in output) + assert_fs_integrity(fs_type, fs_img) def test_unlink5(self, u_boot_console, fs_obj_unlink): """ @@ -86,6 +91,7 @@ class TestUnlink(object): 'host bind 0 %s' % fs_img, '%srm host 0:0 dir5' % fs_type]) assert('directory is not empty' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_unlink6(self, u_boot_console, fs_obj_unlink): """ @@ -97,6 +103,7 @@ class TestUnlink(object): 'host bind 0 %s' % fs_img, '%srm host 0:0 dir5/.' % fs_type]) assert('directory is not empty' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) def test_unlink7(self, u_boot_console, fs_obj_unlink): """ @@ -108,3 +115,4 @@ class TestUnlink(object): 'host bind 0 %s' % fs_img, '%srm host 0:0 dir5/..' % fs_type]) assert('directory is not empty' in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) diff --git a/test/py/tests/test_mmc_rd.py b/test/py/tests/test_mmc_rd.py index a13bc0a..2dc715b 100644 --- a/test/py/tests/test_mmc_rd.py +++ b/test/py/tests/test_mmc_rd.py @@ -6,6 +6,7 @@ # read if the test configuration contains a CRC of the expected data. import pytest +import time import u_boot_utils """ @@ -57,6 +58,116 @@ env__mmc_rd_configs = ( ) """ +def mmc_dev(u_boot_console, is_emmc, devid, partid): + """Run the "mmc dev" command. + + Args: + u_boot_console: A U-Boot console connection. + is_emmc: Whether the device is eMMC + devid: Device ID + partid: Partition ID + + Returns: + Nothing. + """ + + # Select MMC device + cmd = 'mmc dev %d' % devid + if is_emmc: + cmd += ' %d' % partid + response = u_boot_console.run_command(cmd) + assert 'no card present' not in response + if is_emmc: + partid_response = '(part %d)' % partid + else: + partid_response = '' + good_response = 'mmc%d%s is current device' % (devid, partid_response) + assert good_response in response + +@pytest.mark.buildconfigspec('cmd_mmc') +def test_mmc_dev(u_boot_console, env__mmc_rd_config): + """Test the "mmc dev" command. + + Args: + u_boot_console: A U-Boot console connection. + env__mmc_rd_config: The single MMC configuration on which + to run the test. See the file-level comment above for details + of the format. + + Returns: + Nothing. + """ + + is_emmc = env__mmc_rd_config['is_emmc'] + devid = env__mmc_rd_config['devid'] + partid = env__mmc_rd_config.get('partid', 0) + + # Select MMC device + mmc_dev(u_boot_console, is_emmc, devid, partid) + +@pytest.mark.buildconfigspec('cmd_mmc') +def test_mmc_rescan(u_boot_console, env__mmc_rd_config): + """Test the "mmc rescan" command. + + Args: + u_boot_console: A U-Boot console connection. + env__mmc_rd_config: The single MMC configuration on which + to run the test. See the file-level comment above for details + of the format. + + Returns: + Nothing. + """ + + is_emmc = env__mmc_rd_config['is_emmc'] + devid = env__mmc_rd_config['devid'] + partid = env__mmc_rd_config.get('partid', 0) + + # Select MMC device + mmc_dev(u_boot_console, is_emmc, devid, partid) + + # Rescan MMC device + cmd = 'mmc rescan' + response = u_boot_console.run_command(cmd) + assert 'no card present' not in response + +@pytest.mark.buildconfigspec('cmd_mmc') +def test_mmc_info(u_boot_console, env__mmc_rd_config): + """Test the "mmc info" command. + + Args: + u_boot_console: A U-Boot console connection. + env__mmc_rd_config: The single MMC configuration on which + to run the test. See the file-level comment above for details + of the format. + + Returns: + Nothing. + """ + + is_emmc = env__mmc_rd_config['is_emmc'] + devid = env__mmc_rd_config['devid'] + partid = env__mmc_rd_config.get('partid', 0) + info_device = env__mmc_rd_config['info_device'] + info_speed = env__mmc_rd_config['info_speed'] + info_mode = env__mmc_rd_config['info_mode'] + info_buswidth = env__mmc_rd_config['info_buswidth'] + + # Select MMC device + mmc_dev(u_boot_console, is_emmc, devid, partid) + + # Read MMC device information + cmd = 'mmc info' + response = u_boot_console.run_command(cmd) + good_response = "Device: %s" % info_device + assert good_response in response + good_response = "Bus Speed: %s" % info_speed + assert good_response in response + good_response = "Mode : %s" % info_mode + assert good_response in response + good_response = "Bus Width: %s" % info_buswidth + assert good_response in response + @pytest.mark.buildconfigspec('cmd_mmc') def test_mmc_rd(u_boot_console, env__mmc_rd_config): """Test the "mmc read" command. @@ -77,6 +188,7 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config): sector = env__mmc_rd_config.get('sector', 0) count_sectors = env__mmc_rd_config.get('count', 1) expected_crc32 = env__mmc_rd_config.get('crc32', None) + read_duration_max = env__mmc_rd_config.get('read_duration_max', 0) count_bytes = count_sectors * 512 bcfg = u_boot_console.config.buildconfig @@ -86,17 +198,7 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config): addr = '0x%08x' % ram_base # Select MMC device - cmd = 'mmc dev %d' % devid - if is_emmc: - cmd += ' %d' % partid - response = u_boot_console.run_command(cmd) - assert 'no card present' not in response - if is_emmc: - partid_response = '(part %d)' % partid - else: - partid_response = '' - good_response = 'mmc%d%s is current device' % (devid, partid_response) - assert good_response in response + mmc_dev(u_boot_console, is_emmc, devid, partid) # Clear target RAM if expected_crc32: @@ -113,7 +215,9 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config): # Read data cmd = 'mmc read %s %x %x' % (addr, sector, count_sectors) + tstart = time.time() response = u_boot_console.run_command(cmd) + tend = time.time() good_response = 'MMC read: dev # %d, block # %d, count %d ... %d blocks read: OK' % ( devid, sector, count_sectors, count_sectors) assert good_response in response @@ -126,3 +230,10 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config): assert expected_crc32 in response else: u_boot_console.log.warning('CONFIG_CMD_CRC32 != y: Skipping check') + + # Check if the command did not take too long + if read_duration_max: + elapsed = tend - tstart + u_boot_console.log.info('Reading %d bytes took %f seconds' % + (count_bytes, elapsed)) + assert elapsed <= (read_duration_max - 0.01) |