diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2020-09-25 08:06:20 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2020-09-25 08:06:20 +0200 |
commit | 39bdcdfb814a22c8143c04938268378e9994b7dd (patch) | |
tree | 4eeea3247892cab65f10a25d2910fad021cbe7f0 /arch/sandbox | |
parent | e083790340aa4cf1b8edaa50f6b9fbb1edfe56d0 (diff) | |
parent | 8fb0a2bf6efb67084a5d7a7f3822b4d480fca685 (diff) | |
download | barebox-39bdcdfb814a22c8143c04938268378e9994b7dd.tar.gz barebox-39bdcdfb814a22c8143c04938268378e9994b7dd.tar.xz |
Merge branch 'for-next/misc' into master
Diffstat (limited to 'arch/sandbox')
-rw-r--r-- | arch/sandbox/Kconfig | 10 | ||||
-rw-r--r-- | arch/sandbox/Makefile | 2 | ||||
-rw-r--r-- | arch/sandbox/board/dtb.c | 2 | ||||
-rw-r--r-- | arch/sandbox/board/hostfile.c | 118 | ||||
-rw-r--r-- | arch/sandbox/board/poweroff.c | 25 | ||||
-rw-r--r-- | arch/sandbox/configs/hosttools_defconfig | 7 | ||||
-rw-r--r-- | arch/sandbox/dts/sandbox-state-example.dtsi | 2 | ||||
-rw-r--r-- | arch/sandbox/dts/skeleton.dtsi | 4 | ||||
-rw-r--r-- | arch/sandbox/lib/unwind.c | 2 | ||||
-rw-r--r-- | arch/sandbox/mach-sandbox/include/mach/hostfile.h | 3 | ||||
-rw-r--r-- | arch/sandbox/mach-sandbox/include/mach/linux.h | 2 | ||||
-rw-r--r-- | arch/sandbox/os/common.c | 90 | ||||
-rw-r--r-- | arch/sandbox/os/tap.c | 2 |
13 files changed, 220 insertions, 49 deletions
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 81f7a96bd6..bced81f25e 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -7,6 +7,9 @@ config SANDBOX select ARCH_HAS_UBSAN_SANITIZE_ALL select HAVE_ARCH_ASAN select HAS_DMA + select BLOCK + select BLOCK_WRITE + select PARTITION_DISK default y config ARCH_TEXT_BASE @@ -24,6 +27,13 @@ config SANDBOX_UNWIND select ARCH_HAS_STACK_DUMP depends on UBSAN || ASAN +config SANDBOX_REEXEC + prompt "exec(2) reset handler" + def_bool y + help + The normal reset handler hangs barebox. On Linux, barebox + instead can exec itself to simulate a reset. + config PHYS_ADDR_T_64BIT bool diff --git a/arch/sandbox/Makefile b/arch/sandbox/Makefile index ce1fe3b672..09112c3ba8 100644 --- a/arch/sandbox/Makefile +++ b/arch/sandbox/Makefile @@ -25,7 +25,7 @@ KBUILD_CFLAGS += -Dmalloc=barebox_malloc -Dcalloc=barebox_calloc \ -Dglob=barebox_glob -Dglobfree=barebox_globfree \ -Dioctl=barebox_ioctl -Dfstat=barebox_fstat \ -Dopendir=barebox_opendir -Dreaddir=barebox_readdir \ - -Dclosedir=barebox_closedir \ + -Dclosedir=barebox_closedir -Dreadlink=barebox_readlink \ -Doptarg=barebox_optarg -Doptind=barebox_optind machdirs := $(patsubst %,arch/sandbox/mach-%/,$(machine-y)) diff --git a/arch/sandbox/board/dtb.c b/arch/sandbox/board/dtb.c index 74ecbadf42..d11bde0249 100644 --- a/arch/sandbox/board/dtb.c +++ b/arch/sandbox/board/dtb.c @@ -46,7 +46,7 @@ static int of_sandbox_init(void) if (ret) return ret; - ret = of_property_write_u32(root, "#size-cells", 1); + ret = of_property_write_u32(root, "#size-cells", 2); if (ret) return ret; } diff --git a/arch/sandbox/board/hostfile.c b/arch/sandbox/board/hostfile.c index 5f0d7e0a4b..63530bd25e 100644 --- a/arch/sandbox/board/hostfile.c +++ b/arch/sandbox/board/hostfile.c @@ -16,6 +16,8 @@ #include <common.h> #include <driver.h> +#include <block.h> +#include <disks.h> #include <malloc.h> #include <mach/linux.h> #include <init.h> @@ -27,14 +29,16 @@ #include <linux/err.h> struct hf_priv { - struct cdev cdev; + union { + struct block_device blk; + struct cdev cdev; + }; const char *filename; int fd; }; -static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags) +static ssize_t hf_read(struct hf_priv *priv, void *buf, size_t count, loff_t offset, ulong flags) { - struct hf_priv *priv= cdev->priv; int fd = priv->fd; if (linux_lseek(fd, offset) != offset) @@ -43,9 +47,8 @@ static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, loff_t offset return linux_read(fd, buf, count); } -static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags) +static ssize_t hf_write(struct hf_priv *priv, const void *buf, size_t count, loff_t offset, ulong flags) { - struct hf_priv *priv = cdev->priv; int fd = priv->fd; if (linux_lseek(fd, offset) != offset) @@ -54,6 +57,40 @@ static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, loff_t return linux_write(fd, buf, count); } +static ssize_t hf_cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags) +{ + return hf_read(cdev->priv, buf, count, offset, flags); +} + +static ssize_t hf_cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags) +{ + return hf_write(cdev->priv, buf, count, offset, flags); +} + +static struct cdev_operations hf_cdev_ops = { + .read = hf_cdev_read, + .write = hf_cdev_write, +}; + +static int hf_blk_read(struct block_device *blk, void *buf, int block, int num_blocks) +{ + ssize_t ret = hf_read(container_of(blk, struct hf_priv, blk), buf, + num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0); + return ret > 0 ? 0 : ret; +} + +static int hf_blk_write(struct block_device *blk, const void *buf, int block, int num_blocks) +{ + ssize_t ret = hf_write(container_of(blk, struct hf_priv, blk), buf, + num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0); + return ret > 0 ? 0 : ret; +} + +static struct block_device_ops hf_blk_ops = { + .read = hf_blk_read, + .write = hf_blk_write, +}; + static void hf_info(struct device_d *dev) { struct hf_priv *priv = dev->priv; @@ -61,29 +98,28 @@ static void hf_info(struct device_d *dev) printf("file: %s\n", priv->filename); } -static struct cdev_operations hf_fops = { - .read = hf_read, - .write = hf_write, -}; - static int hf_probe(struct device_d *dev) { + struct device_node *np = dev->device_node; struct hf_priv *priv = xzalloc(sizeof(*priv)); struct resource *res; + struct cdev *cdev; + bool is_blockdev; + resource_size_t size; int err; res = dev_get_resource(dev, IORESOURCE_MEM, 0); if (IS_ERR(res)) return PTR_ERR(res); - priv->cdev.size = resource_size(res); + size = resource_size(res); - if (!dev->device_node) + if (!np) return -ENODEV; - of_property_read_u32(dev->device_node, "barebox,fd", &priv->fd); + of_property_read_u32(np, "barebox,fd", &priv->fd); - err = of_property_read_string(dev->device_node, "barebox,filename", + err = of_property_read_string(np, "barebox,filename", &priv->filename); if (err) return err; @@ -91,20 +127,50 @@ static int hf_probe(struct device_d *dev) if (!priv->fd) priv->fd = linux_open(priv->filename, true); - priv->cdev.name = dev->device_node->name; - priv->cdev.dev = dev; - priv->cdev.ops = &hf_fops; - priv->cdev.priv = priv; + if (priv->fd < 0) + return priv->fd; dev->info = hf_info; dev->priv = priv; - err = devfs_create(&priv->cdev); - if (err) - return err; + is_blockdev = of_property_read_bool(np, "barebox,blockdev"); + + cdev = is_blockdev ? &priv->blk.cdev : &priv->cdev; + + cdev->device_node = np; + + if (is_blockdev) { + cdev->name = np->name; + priv->blk.dev = dev; + priv->blk.ops = &hf_blk_ops; + priv->blk.blockbits = SECTOR_SHIFT; + priv->blk.num_blocks = size / SECTOR_SIZE; - of_parse_partitions(&priv->cdev, dev->device_node); - of_partitions_register_fixup(&priv->cdev); + err = blockdevice_register(&priv->blk); + if (err) + return err; + + err = parse_partition_table(&priv->blk); + if (err) + dev_warn(dev, "No partition table found\n"); + + dev_info(dev, "registered as block device\n"); + } else { + cdev->name = np->name; + cdev->dev = dev; + cdev->ops = &hf_cdev_ops; + cdev->size = size; + cdev->priv = priv; + + err = devfs_create(cdev); + if (err) + return err; + + dev_info(dev, "registered as character device\n"); + } + + of_parse_partitions(cdev, np); + of_partitions_register_fixup(cdev); return 0; } @@ -122,7 +188,7 @@ static struct driver_d hf_drv = { .of_compatible = DRV_OF_COMPAT(hostfile_dt_ids), .probe = hf_probe, }; -coredevice_platform_driver(hf_drv); +device_platform_driver(hf_drv); static int of_hostfile_fixup(struct device_node *root, void *ctx) { @@ -131,6 +197,7 @@ static int of_hostfile_fixup(struct device_node *root, void *ctx) uint32_t reg[] = { hf->base >> 32, hf->base, + hf->size >> 32, hf->size }; int ret; @@ -151,6 +218,9 @@ static int of_hostfile_fixup(struct device_node *root, void *ctx) ret = of_property_write_string(node, "barebox,filename", hf->filename); + if (hf->is_blockdev) + ret = of_property_write_bool(node, "barebox,blockdev", true); + return ret; } diff --git a/arch/sandbox/board/poweroff.c b/arch/sandbox/board/poweroff.c index 6b5a6dff15..8ce739af72 100644 --- a/arch/sandbox/board/poweroff.c +++ b/arch/sandbox/board/poweroff.c @@ -1,6 +1,7 @@ #include <common.h> #include <init.h> #include <poweroff.h> +#include <restart.h> #include <mach/linux.h> static void sandbox_poweroff(struct poweroff_handler *poweroff) @@ -8,9 +9,33 @@ static void sandbox_poweroff(struct poweroff_handler *poweroff) linux_exit(); } +static void sandbox_rst_hang(struct restart_handler *rst) +{ + linux_hang(); +} + +static struct restart_handler rst_hang = { + .name = "hang", + .restart = sandbox_rst_hang +}; + +static void sandbox_rst_reexec(struct restart_handler *rst) +{ + linux_reexec(); +} + +static struct restart_handler rst_reexec = { + .name = "reexec", .priority = 200, + .restart = sandbox_rst_reexec, +}; + static int poweroff_register_feature(void) { poweroff_handler_register_fn(sandbox_poweroff); + restart_handler_register(&rst_hang); + + if (IS_ENABLED(CONFIG_SANDBOX_REEXEC)) + restart_handler_register(&rst_reexec); return 0; } diff --git a/arch/sandbox/configs/hosttools_defconfig b/arch/sandbox/configs/hosttools_defconfig new file mode 100644 index 0000000000..72ec0fc462 --- /dev/null +++ b/arch/sandbox/configs/hosttools_defconfig @@ -0,0 +1,7 @@ +CONFIG_IMD=y +CONFIG_COMPILE_HOST_TOOLS=y +CONFIG_ARCH_IMX_USBLOADER=y +CONFIG_MVEBU_HOSTTOOLS=y +CONFIG_MXS_HOSTTOOLS=y +CONFIG_OMAP3_USB_LOADER=y +CONFIG_OMAP4_HOSTTOOL_USBBOOT=y diff --git a/arch/sandbox/dts/sandbox-state-example.dtsi b/arch/sandbox/dts/sandbox-state-example.dtsi index fc17bd0788..98640f6677 100644 --- a/arch/sandbox/dts/sandbox-state-example.dtsi +++ b/arch/sandbox/dts/sandbox-state-example.dtsi @@ -6,7 +6,7 @@ disk { compatible = "barebox,hostfile"; barebox,filename = "disk"; - reg = <0x0 0x0 0x100000>; + reg = <0x0 0x0 0x0 0x100000>; partitions { compatible = "fixed-partitions"; diff --git a/arch/sandbox/dts/skeleton.dtsi b/arch/sandbox/dts/skeleton.dtsi index 38ead821bb..8ba7663eb5 100644 --- a/arch/sandbox/dts/skeleton.dtsi +++ b/arch/sandbox/dts/skeleton.dtsi @@ -6,8 +6,8 @@ / { #address-cells = <2>; - #size-cells = <1>; + #size-cells = <2>; chosen { }; aliases { }; - memory { device_type = "memory"; reg = <0 0 0>; }; + memory { device_type = "memory"; reg = <0 0 0 0>; }; }; diff --git a/arch/sandbox/lib/unwind.c b/arch/sandbox/lib/unwind.c index 15a2798cc4..f46365ac2b 100644 --- a/arch/sandbox/lib/unwind.c +++ b/arch/sandbox/lib/unwind.c @@ -7,5 +7,5 @@ void __sanitizer_print_stack_trace(void); void dump_stack(void) { - __sanitizer_print_stack_trace(); + __sanitizer_print_stack_trace(); } diff --git a/arch/sandbox/mach-sandbox/include/mach/hostfile.h b/arch/sandbox/mach-sandbox/include/mach/hostfile.h index 54f690be5f..c3f9af97c4 100644 --- a/arch/sandbox/mach-sandbox/include/mach/hostfile.h +++ b/arch/sandbox/mach-sandbox/include/mach/hostfile.h @@ -4,9 +4,10 @@ struct hf_info { int fd; unsigned long long base; - size_t size; + unsigned long long size; const char *devname; const char *filename; + unsigned int is_blockdev:1; }; int barebox_register_filedev(struct hf_info *hf); diff --git a/arch/sandbox/mach-sandbox/include/mach/linux.h b/arch/sandbox/mach-sandbox/include/mach/linux.h index 9759a376ec..1ab48e52a0 100644 --- a/arch/sandbox/mach-sandbox/include/mach/linux.h +++ b/arch/sandbox/mach-sandbox/include/mach/linux.h @@ -17,6 +17,8 @@ ssize_t linux_write(int fd, const void *buf, size_t count); off_t linux_lseek(int fildes, off_t offset); int linux_tstc(int fd); void __attribute__((noreturn)) linux_exit(void); +void linux_hang(void); +void linux_reexec(void); int linux_execve(const char * filename, char *const argv[], char *const envp[]); diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c index 9fb5faf41d..43ee95edb6 100644 --- a/arch/sandbox/os/common.c +++ b/arch/sandbox/os/common.c @@ -44,6 +44,8 @@ #include <mach/linux.h> #include <mach/hostfile.h> +#define DELETED_OFFSET (sizeof(" (deleted)") - 1) + void __sanitizer_set_death_callback(void (*callback)(void)); int sdl_xres; @@ -122,9 +124,40 @@ void __attribute__((noreturn)) linux_exit(void) exit(0); } +static char **saved_argv; + +void linux_reexec(void) +{ + char buf[4097]; + ssize_t ret; + + cookmode(); + + /* we must follow the symlink, so we can exec an updated executable */ + ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1); + if (0 < ret && ret < sizeof(buf) - 1) { + buf[ret] = '\0'; + execv(buf, saved_argv); + if (!strcmp(&buf[ret - DELETED_OFFSET], " (deleted)")) { + printf("barebox image on disk changed. Loading new.\n"); + buf[ret - DELETED_OFFSET] = '\0'; + execv(buf, saved_argv); + } + } + + printf("exec(%s) failed: %d\n", buf, errno); + /* falls through to generic hang() */ +} + +void linux_hang(void) +{ + cookmode(); + /* falls through to generic hang() */ +} + int linux_open(const char *filename, int readwrite) { - return open(filename, readwrite ? O_RDWR : O_RDONLY); + return open(filename, (readwrite ? O_RDWR : O_RDONLY) | O_CLOEXEC); } int linux_read(int fd, void *buf, size_t count) @@ -212,12 +245,14 @@ int linux_execve(const char * filename, char *const argv[], char *const envp[]) extern void start_barebox(void); extern void mem_malloc_init(void *start, void *end); -static int add_image(char *str, char *devname_template, int *devname_number) +extern char * strsep_unescaped(char **s, const char *ct); + +static int add_image(const char *_str, char *devname_template, int *devname_number) { struct hf_info *hf = malloc(sizeof(struct hf_info)); - char *filename, *devname; + char *str, *filename, *devname; char tmp[16]; - int readonly = 0; + int readonly = 0, cdev = 0, blkdev = 0; struct stat s; char *opt; int fd, ret; @@ -225,15 +260,21 @@ static int add_image(char *str, char *devname_template, int *devname_number) if (!hf) return -1; - filename = strtok(str, ","); - while ((opt = strtok(NULL, ","))) { + str = strdup(_str); + + filename = strsep_unescaped(&str, ","); + while ((opt = strsep_unescaped(&str, ","))) { if (!strcmp(opt, "ro")) readonly = 1; + if (!strcmp(opt, "cdev")) + cdev = 1; + if (!strcmp(opt, "blkdev")) + blkdev = 1; } /* parses: "devname=filename" */ - devname = strtok(filename, "="); - filename = strtok(NULL, "="); + devname = strsep_unescaped(&filename, "="); + filename = strsep_unescaped(&filename, "="); if (!filename) { filename = devname; snprintf(tmp, sizeof(tmp), @@ -244,9 +285,10 @@ static int add_image(char *str, char *devname_template, int *devname_number) printf("add %s backed by file %s%s\n", devname, filename, readonly ? "(ro)" : ""); - fd = open(filename, readonly ? O_RDONLY : O_RDWR); + fd = open(filename, (readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC); hf->fd = fd; hf->filename = filename; + hf->is_blockdev = blkdev; if (fd < 0) { perror("open"); @@ -266,13 +308,25 @@ static int add_image(char *str, char *devname_template, int *devname_number) perror("ioctl"); goto err_out; } + if (!cdev) + hf->is_blockdev = 1; } - hf->base = (unsigned long)mmap(NULL, hf->size, - PROT_READ | (readonly ? 0 : PROT_WRITE), - MAP_SHARED, fd, 0); + if (hf->size <= SIZE_MAX) + hf->base = (unsigned long)mmap(NULL, hf->size, + PROT_READ | (readonly ? 0 : PROT_WRITE), + MAP_SHARED, fd, 0); + else + printf("warning: %s: contiguous map failed\n", filename); + if (hf->base == (unsigned long)MAP_FAILED) printf("warning: mmapping %s failed: %s\n", filename, strerror(errno)); + if (blkdev && hf->size % 512 != 0) { + printf("warning: registering %s as block device failed: invalid block size\n", + filename); + return -EINVAL; + } + ret = barebox_register_filedev(hf); if (ret) goto err_out; @@ -291,7 +345,7 @@ static int add_dtb(const char *file) void *dtb = NULL; int fd; - fd = open(file, O_RDONLY); + fd = open(file, O_RDONLY | O_CLOEXEC); if (fd < 0) { perror("open"); goto err_out; @@ -351,6 +405,8 @@ int main(int argc, char *argv[]) __sanitizer_set_death_callback(cookmode); #endif + saved_argv = argv; + while (1) { option_index = 0; opt = getopt_long(argc, argv, optstring, @@ -422,7 +478,7 @@ int main(int argc, char *argv[]) exit(1); break; case 'O': - fd = open(optarg, O_WRONLY); + fd = open(optarg, O_WRONLY | O_CLOEXEC); if (fd < 0) { perror("open"); exit(1); @@ -431,7 +487,7 @@ int main(int argc, char *argv[]) barebox_register_console(-1, fd); break; case 'I': - fd = open(optarg, O_RDWR); + fd = open(optarg, O_RDWR | O_CLOEXEC); if (fd < 0) { perror("open"); exit(1); @@ -447,7 +503,7 @@ int main(int argc, char *argv[]) } /* open stdout file */ - fd = open(aux + 1, O_WRONLY); + fd = open(aux + 1, O_WRONLY | O_CLOEXEC); if (fd < 0) { perror("open stdout"); exit(1); @@ -455,7 +511,7 @@ int main(int argc, char *argv[]) /* open stdin file */ aux = strndup(optarg, aux - optarg); - fd2 = open(aux, O_RDWR); + fd2 = open(aux, O_RDWR | O_CLOEXEC); if (fd2 < 0) { perror("open stdin"); exit(1); diff --git a/arch/sandbox/os/tap.c b/arch/sandbox/os/tap.c index 72b7fbb5ac..83b97ffd49 100644 --- a/arch/sandbox/os/tap.c +++ b/arch/sandbox/os/tap.c @@ -30,7 +30,7 @@ int tap_alloc(const char *dev) struct ifreq ifr; int fd, err; - if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { + if ((fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC)) < 0) { perror("could not open /dev/net/tun"); return -1; } |