diff --git a/Documentation/filesystems/smhfs.rst b/Documentation/filesystems/smhfs.rst new file mode 100644 index 0000000..28de146 --- /dev/null +++ b/Documentation/filesystems/smhfs.rst @@ -0,0 +1,57 @@ +.. index:: smhfs (filesystem) + +.. _filesystems_smhfs: + +File I/O over ARM semihosting support +===================================== + +Target Side Setup +----------------- + +barebox can communicate with debug programms attached via SWD/JTAG by +means of ARM semihosting protocol. + +Not all of the I/O primitives neccessary to implement a full +filesystem are exposed in ARM semihosting API and because of that some +aspects of filesystem funcionality are missing. Implementation does +not have support for listing directories. This means a +:ref:`command_ls` to a SMHFS-mounted path will show an empty +directory. Nevertheless, the files are there. + +Example:: + + mount -t smhfs /dev/null /mnt/smhfs + + +Host Side Setup +--------------- + +FIXME: Currently OpenOCD does not work correctly if Barebox is built +with MMU enabled, so before using this featrue, please make sure that +MMU is disabled in your particular configuration + +To make semihosting work host machine connected to the target via +JTAG/SWD must have semihosting capable debug software running. One +such tool would be OpenOCD. For ARM9 and ARM11 CPUs most recent +release of OpenOCD should suffice, however for ARMv7A based devices +patched version from here http://openocd.zylin.com/#/c/2908/ has to be +used. + +The following steps are required to set up a operational semihosting +channel: + + 1. In a terminal start OpenOCD and specify your particular board + and debug adapter used. + + 2. In a separate terminal connect to OpenOCD via telnet + + telnet localhost 4444 + + 3. In resulting telnet session execute the following commands: + + halt + arm semihosting on + resume + +After that is done all of the semihosting related functions should be +ready to use. diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 203f912..e5cfea5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -325,6 +325,15 @@ the performance is not affected. Currently, this feature only works with EABI compilers. If unsure say Y. +config ARM_SEMIHOSTING + bool "enable ARM semihosting support" + help + This option enables ARM semihosting support in barebox. ARM + semihosting is a communication discipline that allows code + running on target ARM cpu perform system calls and access + the data on the host computer connected to the target via + debugging channel (JTAG, SWD). If unsure say N + endmenu source common/Kconfig diff --git a/arch/arm/configs/am335x_defconfig b/arch/arm/configs/am335x_defconfig index 234042f..9563865 100644 --- a/arch/arm/configs/am335x_defconfig +++ b/arch/arm/configs/am335x_defconfig @@ -88,12 +88,12 @@ CONFIG_NET_NFS=y CONFIG_NET_NETCONSOLE=y CONFIG_NET_RESOLV=y -CONFIG_OFDEVICE=y CONFIG_OF_BAREBOX_DRIVERS=y CONFIG_DRIVER_SERIAL_NS16550=y CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y CONFIG_DRIVER_NET_CPSW=y CONFIG_MICREL_PHY=y +CONFIG_SMSC_PHY=y CONFIG_NET_USB=y CONFIG_NET_USB_ASIX=y CONFIG_NET_USB_SMSC95XX=y diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile index fb3929c..418bcab 100644 --- a/arch/arm/cpu/Makefile +++ b/arch/arm/cpu/Makefile @@ -1,7 +1,7 @@ obj-y += cpu.o obj-$(CONFIG_ARM_EXCEPTIONS) += exceptions.o obj-$(CONFIG_ARM_EXCEPTIONS) += interrupts.o -obj-y += start.o setupc.o +obj-y += start.o setupc.o entry.o # # Any variants can be called as start-armxyz.S @@ -23,7 +23,7 @@ pbl-$(CONFIG_CPU_32v7) += cache-armv7.o obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o -pbl-y += setupc.o +pbl-y += setupc.o entry.o pbl-$(CONFIG_PBL_SINGLE_IMAGE) += start-pbl.o pbl-$(CONFIG_PBL_MULTI_IMAGES) += uncompress.o diff --git a/arch/arm/cpu/cache-l2x0.c b/arch/arm/cpu/cache-l2x0.c index 428dd93..0aa2482 100644 --- a/arch/arm/cpu/cache-l2x0.c +++ b/arch/arm/cpu/cache-l2x0.c @@ -124,12 +124,10 @@ static void l2x0_disable(void) { - writel(0xff, l2x0_base + L2X0_CLEAN_INV_WAY); - while (readl(l2x0_base + L2X0_CLEAN_INV_WAY)); writel(0, l2x0_base + L2X0_CTRL); } -void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) +void l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) { __u32 aux; __u32 cache_id; @@ -161,7 +159,7 @@ break; } - l2x0_way_mask = (1 << ways) - 1; + l2x0_way_mask = (1 << ways) - 1; /* * Check if l2x0 controller is already enabled. diff --git a/arch/arm/cpu/cpu.c b/arch/arm/cpu/cpu.c index ff8f43d..e8191ec 100644 --- a/arch/arm/cpu/cpu.c +++ b/arch/arm/cpu/cpu.c @@ -80,8 +80,10 @@ void mmu_disable(void) { __mmu_cache_flush(); - if (outer_cache.disable) + if (outer_cache.disable) { + outer_cache.flush_all(); outer_cache.disable(); + } __mmu_cache_off(); } diff --git a/arch/arm/cpu/entry.c b/arch/arm/cpu/entry.c new file mode 100644 index 0000000..3b74c6a --- /dev/null +++ b/arch/arm/cpu/entry.c @@ -0,0 +1,38 @@ +#include + +#include + +#include "entry.h" + +/* + * Main ARM entry point. Call this with the memory region you can + * spare for barebox. This doesn't necessarily have to be the full + * SDRAM. The currently running binary can be inside or outside of + * this region. TEXT_BASE can be inside or outside of this + * region. boarddata will be preserved and can be accessed later with + * barebox_arm_boarddata(). + * + * -> membase + memsize + * STACK_SIZE - stack + * 16KiB, aligned to 16KiB - First level page table if early MMU support + * is enabled + * 128KiB - early memory space + * -> maximum end of barebox binary + * + * Usually a TEXT_BASE of 1MiB below your lowest possible end of memory should + * be fine. + */ + +void __naked __noreturn barebox_arm_entry(unsigned long membase, + unsigned long memsize, void *boarddata) +{ + arm_setup_stack(membase + memsize - 16); + arm_early_mmu_cache_invalidate(); + + if (IS_ENABLED(CONFIG_PBL_MULTI_IMAGES)) + barebox_multi_pbl_start(membase, memsize, boarddata); + else if (IS_ENABLED(CONFIG_PBL_SINGLE_IMAGE)) + barebox_single_pbl_start(membase, memsize, boarddata); + else + barebox_non_pbl_start(membase, memsize, boarddata); +} diff --git a/arch/arm/cpu/entry.h b/arch/arm/cpu/entry.h new file mode 100644 index 0000000..f0163a3 --- /dev/null +++ b/arch/arm/cpu/entry.h @@ -0,0 +1,18 @@ +#ifndef __ENTRY_H__ +#define __ENTRY_H__ + +#include + +void __noreturn barebox_non_pbl_start(unsigned long membase, + unsigned long memsize, + void *boarddata); + +void __noreturn barebox_multi_pbl_start(unsigned long membase, + unsigned long memsize, + void *boarddata); + +void __noreturn barebox_single_pbl_start(unsigned long membase, + unsigned long memsize, + void *boarddata); + +#endif diff --git a/arch/arm/cpu/start-pbl.c b/arch/arm/cpu/start-pbl.c index f2490fd..2075ffe 100644 --- a/arch/arm/cpu/start-pbl.c +++ b/arch/arm/cpu/start-pbl.c @@ -45,7 +45,7 @@ extern void *input_data; extern void *input_data_end; -static noinline __noreturn void __barebox_arm_entry(unsigned long membase, +__noreturn void barebox_single_pbl_start(unsigned long membase, unsigned long memsize, void *boarddata) { uint32_t offset; @@ -56,8 +56,6 @@ endmem -= STACK_SIZE; /* stack */ - arm_early_mmu_cache_invalidate(); - if (IS_ENABLED(CONFIG_PBL_RELOCATABLE)) relocate_to_current_adr(); @@ -106,28 +104,3 @@ barebox(membase, memsize, boarddata); } - -/* - * Main ARM entry point in the compressed image. Call this with the memory - * region you can spare for barebox. This doesn't necessarily have to be the - * full SDRAM. The currently running binary can be inside or outside of this - * region. TEXT_BASE can be inside or outside of this region. boarddata will - * be preserved and can be accessed later with barebox_arm_boarddata(). - * - * -> membase + memsize - * STACK_SIZE - stack - * 16KiB, aligned to 16KiB - First level page table if early MMU support - * is enabled - * 128KiB - early memory space - * -> maximum end of barebox binary - * - * Usually a TEXT_BASE of 1MiB below your lowest possible end of memory should - * be fine. - */ -void __naked __noreturn barebox_arm_entry(unsigned long membase, - unsigned long memsize, void *boarddata) -{ - arm_setup_stack(membase + memsize - 16); - - __barebox_arm_entry(membase, memsize, boarddata); -} diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c index 8e5097b..274652d 100644 --- a/arch/arm/cpu/start.c +++ b/arch/arm/cpu/start.c @@ -34,26 +34,37 @@ unsigned long arm_stack_top; static void *barebox_boarddata; -u32 barebox_arm_machine(void) +static bool blob_is_fdt(const void *blob) { - struct barebox_arm_boarddata *bd; - - if (!barebox_boarddata) - return 0; - - bd = barebox_boarddata; - - return bd->machine; + return get_unaligned_be32(blob) == FDT_MAGIC; } -static void *barebox_boot_dtb; +static bool blob_is_arm_boarddata(const void *blob) +{ + const struct barebox_arm_boarddata *bd = blob; + + return bd->magic == BAREBOX_ARM_BOARDDATA_MAGIC; +} + +u32 barebox_arm_machine(void) +{ + if (barebox_boarddata && blob_is_arm_boarddata(barebox_boarddata)) { + const struct barebox_arm_boarddata *bd = barebox_boarddata; + return bd->machine; + } else { + return 0; + } +} void *barebox_arm_boot_dtb(void) { - return barebox_boot_dtb; + if (barebox_boarddata && blob_is_fdt(barebox_boarddata)) + return barebox_boarddata; + else + return NULL; } -static noinline __noreturn void __start(unsigned long membase, +__noreturn void barebox_non_pbl_start(unsigned long membase, unsigned long memsize, void *boarddata) { unsigned long endmem = membase + memsize; @@ -70,7 +81,6 @@ pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize); - barebox_boarddata = boarddata; arm_stack_top = endmem; endmem -= STACK_SIZE; /* Stack */ @@ -89,21 +99,23 @@ } if (boarddata) { - if (get_unaligned_be32(boarddata) == FDT_MAGIC) { - uint32_t totalsize = get_unaligned_be32(boarddata + 4); + uint32_t totalsize = 0; + const char *name; + + if (blob_is_fdt(boarddata)) { + totalsize = get_unaligned_be32(boarddata + 4); + name = "DTB"; + } else if (blob_is_arm_boarddata(boarddata)) { + totalsize = sizeof(struct barebox_arm_boarddata); + name = "machine type"; + } + + if (totalsize) { endmem -= ALIGN(totalsize, 64); - barebox_boot_dtb = (void *)endmem; - pr_debug("found DTB in boarddata, copying to 0x%p\n", - barebox_boot_dtb); - memcpy(barebox_boot_dtb, boarddata, totalsize); - } else if (((struct barebox_arm_boarddata *)boarddata)->magic == - BAREBOX_ARM_BOARDDATA_MAGIC) { - endmem -= ALIGN(sizeof(struct barebox_arm_boarddata), 64); - barebox_boarddata = (void *)endmem; - pr_debug("found machine type in boarddata, copying to 0x%p\n", - barebox_boarddata); - memcpy(barebox_boarddata, boarddata, - sizeof(struct barebox_arm_boarddata)); + pr_debug("found %s in boarddata, copying to 0x%lu\n", + name, endmem); + barebox_boarddata = memcpy((void *)endmem, + boarddata, totalsize); } } @@ -149,31 +161,6 @@ barebox_arm_head(); } -/* - * Main ARM entry point in the uncompressed image. Call this with the memory - * region you can spare for barebox. This doesn't necessarily have to be the - * full SDRAM. The currently running binary can be inside or outside of this - * region. TEXT_BASE can be inside or outside of this region. boarddata will - * be preserved and can be accessed later with barebox_arm_boarddata(). - * - * -> membase + memsize - * STACK_SIZE - stack - * 16KiB, aligned to 16KiB - First level page table if early MMU support - * is enabled - * -> maximum end of barebox binary - * - * Usually a TEXT_BASE of 1MiB below your lowest possible end of memory should - * be fine. - */ -void __naked __noreturn barebox_arm_entry(unsigned long membase, - unsigned long memsize, void *boarddata) -{ - arm_setup_stack(membase + memsize - 16); - - arm_early_mmu_cache_invalidate(); - - __start(membase, memsize, boarddata); -} #else /* * First function in the uncompressed image. We get here from @@ -182,6 +169,6 @@ void __naked __section(.text_entry) start(unsigned long membase, unsigned long memsize, void *boarddata) { - __start(membase, memsize, boarddata); + barebox_non_pbl_start(membase, memsize, boarddata); } #endif diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c index b0b7c6d..dbf6b1e 100644 --- a/arch/arm/cpu/uncompress.c +++ b/arch/arm/cpu/uncompress.c @@ -41,7 +41,7 @@ __attribute__((__section__(".image_end"))) __image_end_dummy = 0xdeadbeef; -static void __noreturn noinline uncompress_start_payload(unsigned long membase, +void __noreturn barebox_multi_pbl_start(unsigned long membase, unsigned long memsize, void *boarddata) { uint32_t pg_len; @@ -52,8 +52,6 @@ void *pg_start; unsigned long pc = get_pc(); - arm_early_mmu_cache_invalidate(); - endmem -= STACK_SIZE; /* stack */ image_end = (void *)ld_var(__image_end) - get_runtime_offset(); @@ -114,15 +112,3 @@ barebox(membase, memsize, boarddata); } - -/* - * For the multi images startup process board code jumps here. We will uncompress - * the attached barebox image and start it. - */ -void __naked __noreturn barebox_arm_entry(unsigned long membase, - unsigned long memsize, void *boarddata) -{ - arm_setup_stack(membase + memsize - 16); - - uncompress_start_payload(membase, memsize, boarddata); -} diff --git a/arch/arm/dts/am335x-phytec-phyflex-som.dtsi b/arch/arm/dts/am335x-phytec-phyflex-som.dtsi index 6d488fa..c60943c 100644 --- a/arch/arm/dts/am335x-phytec-phyflex-som.dtsi +++ b/arch/arm/dts/am335x-phytec-phyflex-som.dtsi @@ -224,12 +224,13 @@ phy_id = <&davinci_mdio>, <2>; phy-mode = "rmii"; dual_emac_res_vlan = <2>; + status = "disabled"; }; &mac { pinctrl-names = "default"; - pinctrl-0 = <&emac_rgmii1_pins &emac_rmii2_pins>; - dual_emac; + slaves = <1>; + pinctrl-0 = <&emac_rgmii1_pins>; status = "okay"; }; diff --git a/arch/arm/include/asm/semihosting.h b/arch/arm/include/asm/semihosting.h new file mode 100644 index 0000000..b478dad --- /dev/null +++ b/arch/arm/include/asm/semihosting.h @@ -0,0 +1,19 @@ +#ifndef __ASM_ARM_SEMIHOSTING_H +#define __ASM_ARM_SEMIHOSTING_H + +int semihosting_open(const char *fname, int flags); +int semihosting_close(int fd); +int semihosting_writec(char c); +int semihosting_write0(const char *str); +ssize_t semihosting_write(int fd, const void *buf, size_t count); +ssize_t semihosting_read(int fd, void *buf, size_t count); +int semihosting_readc(void); +int semihosting_isatty(int fd); +int semihosting_seek(int fd, loff_t pos); +int semihosting_flen(int fd); +int semihosting_remove(const char *fname); +int semihosting_rename(const char *fname1, const char *fname2); +int semihosting_errno(void); +int semihosting_system(const char *command); + +#endif diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index a328795..e1c6f5b 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memcpy.o obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memset.o obj-$(CONFIG_ARM_UNWIND) += unwind.o +obj-$(CONFIG_ARM_SEMIHOSTING) += semihosting-trap.o semihosting.o obj-$(CONFIG_MODULES) += module.o extra-y += barebox.lds diff --git a/arch/arm/lib/semihosting-trap.S b/arch/arm/lib/semihosting-trap.S new file mode 100644 index 0000000..9e40ebf --- /dev/null +++ b/arch/arm/lib/semihosting-trap.S @@ -0,0 +1,28 @@ +/* + * semihosting-trap.S -- Assembly code needed to make a semihosting call + * + * Copyright (c) 2015 Zodiac Inflight Innovations + * Author: Andrey Smirnov + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +.section .text.semihosting_trap +ENTRY(semihosting_trap) + @ In supervisor mode SVC would clobber LR + push {lr} + ARM( svc #0x123456 ) + THUMB( svc #0xAB ) + pop {pc} +ENDPROC(semihosting_trap) diff --git a/arch/arm/lib/semihosting.c b/arch/arm/lib/semihosting.c new file mode 100644 index 0000000..a735196 --- /dev/null +++ b/arch/arm/lib/semihosting.c @@ -0,0 +1,227 @@ +/* + * semihosting.c -- ARM Semihoting API implementation + * + * Copyright (c) 2015 Zodiac Inflight Innovations + * Author: Andrey Smirnov + * + * based on a smiliar code from U-Boot + * Copyright (c) 2014 Broadcom Corporation + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + + +enum { + SEMIHOSTING_SYS_OPEN = 0x01, + SEMIHOSTING_SYS_CLOSE = 0x02, + SEMIHOSTING_SYS_WRITEC = 0x03, + SEMIHOSTING_SYS_WRITE0 = 0x04, + SEMIHOSTING_SYS_WRITE = 0x05, + SEMIHOSTING_SYS_READ = 0x06, + SEMIHOSTING_SYS_READC = 0x07, + /* SYS_ISERROR is not implemented */ + SEMIHOSTING_SYS_ISATTY = 0x09, + SEMIHOSTING_SYS_SEEK = 0x0a, + SEMIHOSTING_SYS_FLEN = 0x0c, + SEMIHOSTING_SYS_REMOVE = 0x0e, + SEMIHOSTING_SYS_RENAME = 0x0f, + SEMIHOSTING_SYS_TIME = 0x11, + SEMIHOSTING_SYS_ERRNO = 0x13, + /* SYS_GET_CMDLINE is not implemented */ + /* SYS_HEAPINFO is not implemented */ + /* angel_SWIreason_ReportException is not implemented */ + SEMIHOSTING_SYS_SYSTEM = 0x12, +}; + +uint32_t semihosting_trap(uint32_t sysnum, void *addr); + +static uint32_t semihosting_flags_to_mode(int flags) +{ + static const int semihosting_open_modeflags[12] = { + O_RDONLY, + O_RDONLY | O_BINARY, + O_RDWR, + O_RDWR | O_BINARY, + O_WRONLY | O_CREAT | O_TRUNC, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + O_WRONLY | O_CREAT | O_APPEND, + O_WRONLY | O_CREAT | O_APPEND | O_BINARY, + O_RDWR | O_CREAT | O_APPEND, + O_RDWR | O_CREAT | O_APPEND | O_BINARY + }; + + int i; + for (i = 0; i < ARRAY_SIZE(semihosting_open_modeflags); i++) { + if (semihosting_open_modeflags[i] == flags) + return i; + } + + return 0; +} + +int semihosting_open(const char *fname, int flags) +{ + struct __packed { + uint32_t fname; + uint32_t mode; + uint32_t len; + } open = { + .fname = (uint32_t)fname, + .len = strlen(fname), + .mode = semihosting_flags_to_mode(flags), + }; + + return semihosting_trap(SEMIHOSTING_SYS_OPEN, &open); +} +EXPORT_SYMBOL(semihosting_open); + +int semihosting_close(int fd) +{ + return semihosting_trap(SEMIHOSTING_SYS_CLOSE, &fd); +} +EXPORT_SYMBOL(semihosting_close); + +int semihosting_writec(char c) +{ + return semihosting_trap(SEMIHOSTING_SYS_WRITEC, &c); +} +EXPORT_SYMBOL(semihosting_writec); + +int semihosting_write0(const char *str) +{ + return semihosting_trap(SEMIHOSTING_SYS_WRITE0, (void *)str); +} +EXPORT_SYMBOL(semihosting_write0); + +struct __packed semihosting_file_io { + uint32_t fd; + uint32_t memp; + uint32_t len; +}; + +ssize_t semihosting_write(int fd, const void *buf, size_t count) +{ + struct semihosting_file_io write = { + .fd = fd, + .memp = (uint32_t)buf, + .len = count, + }; + + return semihosting_trap(SEMIHOSTING_SYS_WRITE, &write); +} +EXPORT_SYMBOL(semihosting_write); + +ssize_t semihosting_read(int fd, void *buf, size_t count) +{ + struct semihosting_file_io read = { + .fd = fd, + .memp = (uint32_t)buf, + .len = count, + }; + + return semihosting_trap(SEMIHOSTING_SYS_READ, &read); +} +EXPORT_SYMBOL(semihosting_read); + +int semihosting_readc(void) +{ + return semihosting_trap(SEMIHOSTING_SYS_READC, NULL); +} +EXPORT_SYMBOL(semihosting_readc); + +int semihosting_isatty(int fd) +{ + return semihosting_trap(SEMIHOSTING_SYS_ISATTY, &fd); +} +EXPORT_SYMBOL(semihosting_isatty); + +int semihosting_seek(int fd, off_t pos) +{ + struct __packed { + uint32_t fd; + uint32_t pos; + } seek = { + .fd = fd, + .pos = pos, + }; + + return semihosting_trap(SEMIHOSTING_SYS_SEEK, &seek); +} +EXPORT_SYMBOL(semihosting_seek); + +int semihosting_flen(int fd) +{ + return semihosting_trap(SEMIHOSTING_SYS_FLEN, &fd); +} +EXPORT_SYMBOL(semihosting_flen); + +int semihosting_remove(const char *fname) +{ + struct __packed { + uint32_t fname; + uint32_t fname_length; + } remove = { + .fname = (uint32_t)fname, + .fname_length = strlen(fname), + }; + + return semihosting_trap(SEMIHOSTING_SYS_REMOVE, &remove); +} +EXPORT_SYMBOL(semihosting_remove); + +int semihosting_rename(const char *fname1, const char *fname2) +{ + struct __packed { + uint32_t fname1; + uint32_t fname1_length; + uint32_t fname2; + uint32_t fname2_length; + } rename = { + .fname1 = (uint32_t)fname1, + .fname1_length = strlen(fname1), + .fname2 = (uint32_t)fname2, + .fname2_length = strlen(fname2), + }; + + return semihosting_trap(SEMIHOSTING_SYS_RENAME, &rename); +} +EXPORT_SYMBOL(semihosting_rename); + +int semihosting_errno(void) +{ + return semihosting_trap(SEMIHOSTING_SYS_ERRNO, NULL); +} +EXPORT_SYMBOL(semihosting_errno); + + +int semihosting_system(const char *command) +{ + struct __packed { + uint32_t cmd; + uint32_t cmd_len; + } system = { + .cmd = (uint32_t)command, + .cmd_len = strlen(command), + }; + + return semihosting_trap(SEMIHOSTING_SYS_SYSTEM, &system); +} +EXPORT_SYMBOL(semihosting_system); diff --git a/arch/arm/mach-imx/imx6.c b/arch/arm/mach-imx/imx6.c index ceabe19..c49de49 100644 --- a/arch/arm/mach-imx/imx6.c +++ b/arch/arm/mach-imx/imx6.c @@ -23,6 +23,7 @@ #include #include #include +#include #define SI_REV 0x260 @@ -195,8 +196,6 @@ return 0; } -#define L310_PREFETCH_CTRL 0xF60 - static int imx6_mmu_init(void) { void __iomem *l2x0_base = IOMEM(0x00a02000); @@ -205,8 +204,8 @@ if (!cpu_is_mx6()) return 0; - /* Configure the L2 PREFETCH and POWER registers */ - val = readl(l2x0_base + L310_PREFETCH_CTRL); + /* configure the PREFETCH register */ + val = readl(l2x0_base + L2X0_PREFETCH_CTRL); val |= 0x70800000; /* @@ -221,7 +220,18 @@ if (cpu_is_mx6q()) val &= ~(1 << 30 | 1 << 23); - writel(val, l2x0_base + L310_PREFETCH_CTRL); + writel(val, l2x0_base + L2X0_PREFETCH_CTRL); + + /* + * Set shared attribute override bit in AUX_CTRL register, this is done + * here as it must be done regardless of the usage of the L2 cache in + * barebox itself. The kernel will not touch this bit, but it must be + * set to make the system compliant to the ARMv7 ARM RevC clarifications + * regarding conflicting memory aliases. + */ + val = readl(l2x0_base + L2X0_AUX_CTRL); + val |= (1 << 22); + writel(val, l2x0_base + L2X0_AUX_CTRL); l2x0_init(l2x0_base, 0x0, ~0UL); diff --git a/arch/arm/mach-omap/omap_generic.c b/arch/arm/mach-omap/omap_generic.c index 165487c..071a1bf 100644 --- a/arch/arm/mach-omap/omap_generic.c +++ b/arch/arm/mach-omap/omap_generic.c @@ -107,7 +107,8 @@ return omap_bootmmc_dev; } -#if defined(CONFIG_DEFAULT_ENVIRONMENT) +#if defined(CONFIG_ENV_HANDLING) +#define ENV_PATH "/boot/barebox.env" static int omap_env_init(void) { struct stat s; @@ -132,18 +133,19 @@ free(partname); if (ret) { - printf("no %s. using default env\n", diskdev); + pr_err("Failed to load environment: no device '%s'\n", diskdev); return 0; } mkdir("/boot", 0666); ret = mount(diskdev, "fat", "/boot", NULL); if (ret) { - printf("failed to mount %s\n", diskdev); + pr_err("Failed to load environment: mount %s failed (%d)\n", diskdev, ret); return 0; } - default_environment_path_set("/boot/barebox.env"); + pr_debug("Loading default env from %s on device %s\n", ENV_PATH, diskdev); + default_environment_path_set(ENV_PATH); return 0; } diff --git a/arch/arm/mach-socfpga/generic.c b/arch/arm/mach-socfpga/generic.c index 6259354..234dc52 100644 --- a/arch/arm/mach-socfpga/generic.c +++ b/arch/arm/mach-socfpga/generic.c @@ -76,7 +76,8 @@ } core_initcall(socfpga_init); -#if defined(CONFIG_DEFAULT_ENVIRONMENT) +#if defined(CONFIG_ENV_HANDLING) +#define ENV_PATH "/boot/barebox.env" static int socfpga_env_init(void) { struct stat s; @@ -92,18 +93,19 @@ ret = stat(partname, &s); if (ret) { - printf("no %s. using default env\n", diskdev); + pr_err("Failed to load environment: no device '%s'\n", diskdev); goto out_free; } mkdir("/boot", 0666); ret = mount(partname, "fat", "/boot", NULL); if (ret) { - printf("failed to mount %s\n", diskdev); + pr_err("Failed to load environment: mount %s failed (%d)\n", partname, ret); goto out_free; } - default_environment_path_set("/boot/barebox.env"); + pr_debug("Loading default env from %s on device %s\n", ENV_PATH, diskdev); + default_environment_path_set(ENV_PATH); out_free: free(partname); diff --git a/fs/Kconfig b/fs/Kconfig index feab537..9217bc8 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -80,4 +80,13 @@ select CRC32 prompt "uImage FS support" +config FS_SMHFS + depends on ARM_SEMIHOSTING + bool + prompt "Semihosting FS support" + help + If enabled this filesystem provides access to the files + located on a debugging host connected to the target running + Barebox + endmenu diff --git a/fs/Makefile b/fs/Makefile index f5aae91..4693205 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_FS_UIMAGEFS) += uimagefs.o obj-$(CONFIG_FS_EFI) += efi.o obj-$(CONFIG_FS_EFIVARFS) += efivarfs.o +obj-$(CONFIG_FS_SMHFS) += smhfs.o diff --git a/fs/smhfs.c b/fs/smhfs.c new file mode 100644 index 0000000..a0df06c --- /dev/null +++ b/fs/smhfs.c @@ -0,0 +1,178 @@ +/* + * smhfs.c -- Driver implementing pseudo FS interface on top of ARM + * semihosting + * + * Copyright (c) 2015 Zodiac Inflight Innovations + * Author: Andrey Smirnov + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +static int file_to_fd(const FILE *f) +{ + return (int)f->priv; +} + +static int smhfs_create(struct device_d __always_unused *dev, + const char __always_unused *pathname, + mode_t __always_unused mode) +{ + return 0; +} + +static int smhfs_mkdir(struct device_d __always_unused *dev, + const char __always_unused *pathname) +{ + return -ENOSYS; +} + +static int smhfs_rm(struct device_d __always_unused *dev, + const char *pathname) +{ + /* Get rid of leading '/' */ + pathname = &pathname[1]; + + if (semihosting_remove(pathname) != 0) + return -semihosting_errno(); + else + return 0; +} + +static int smhfs_truncate(struct device_d __always_unused *dev, + FILE __always_unused *f, + ulong __always_unused size) +{ + return -ENOSYS; +} + +static int smhfs_open(struct device_d __always_unused *dev, + FILE *file, const char *filename) +{ + int fd; + /* Get rid of leading '/' */ + filename = &filename[1]; + + fd = semihosting_open(filename, file->flags); + if (fd < 0) + goto error; + + file->priv = (void *)fd; + file->size = semihosting_flen(fd); + if (file->size < 0) + goto error; + + return 0; +error: + return -semihosting_errno(); +} + +static int smhfs_close(struct device_d __always_unused *dev, + FILE *f) +{ + if (semihosting_close(file_to_fd(f))) + return -semihosting_errno(); + else + return 0; +} + +static int smhfs_write(struct device_d __always_unused *dev, + FILE *f, const void *inbuf, size_t insize) +{ + if (semihosting_write(file_to_fd(f), inbuf, insize)) + return -semihosting_errno(); + else + return insize; +} + +static int smhfs_read(struct device_d __always_unused *dev, + FILE *f, void *buf, size_t insize) +{ + if (!semihosting_read(file_to_fd(f), buf, insize)) + return insize; + else + return -semihosting_errno(); +} + +static loff_t smhfs_lseek(struct device_d __always_unused *dev, + FILE *f, loff_t pos) +{ + if (semihosting_seek(file_to_fd(f), pos)) { + return -semihosting_errno(); + } else { + f->pos = pos; + return f->pos; + } +} + +static DIR* smhfs_opendir(struct device_d __always_unused *dev, + const char __always_unused *pathname) +{ + return NULL; +} + +static int smhfs_stat(struct device_d __always_unused *dev, + const char *filename, struct stat *s) +{ + FILE file; + + if (smhfs_open(NULL, &file, filename) == 0) { + s->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO; + s->st_size = file.size; + } + smhfs_close(NULL, &file); + + return 0; +} + +static int smhfs_probe(struct device_d __always_unused *dev) +{ + /* TODO: Add provisions to detect if debugger is connected */ + return 0; +} + +static void smhfs_remove(struct device_d __always_unused *dev) +{ +} + +static struct fs_driver_d smhfs_driver = { + .open = smhfs_open, + .close = smhfs_close, + .read = smhfs_read, + .lseek = smhfs_lseek, + .opendir = smhfs_opendir, + .stat = smhfs_stat, + .create = smhfs_create, + .unlink = smhfs_rm, + .mkdir = smhfs_mkdir, + .rmdir = smhfs_rm, + .write = smhfs_write, + .truncate = smhfs_truncate, + .flags = FS_DRIVER_NO_DEV, + .drv = { + .probe = smhfs_probe, + .remove = smhfs_remove, + .name = "smhfs", + } +}; + +static int smhfs_init(void) +{ + return register_fs_driver(&smhfs_driver); +} +coredevice_initcall(smhfs_init);