diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2011-12-07 12:03:13 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2011-12-07 12:03:13 +0100 |
commit | 0ee6847f7b6d396d3756f6ecd0781a00b9cca980 (patch) | |
tree | 1f1bed639ac0bbc9091685538c791b4648f4c342 /common | |
parent | 61b62f6d33d55c9b89ba8a6fbae84cb9c33e342a (diff) | |
parent | 8b3d10265da20b8be6138799cee704d53dee1c63 (diff) | |
download | barebox-0ee6847f7b6d396d3756f6ecd0781a00b9cca980.tar.gz barebox-0ee6847f7b6d396d3756f6ecd0781a00b9cca980.tar.xz |
Merge branch 'next'
Diffstat (limited to 'common')
-rw-r--r-- | common/Kconfig | 18 | ||||
-rw-r--r-- | common/Makefile | 4 | ||||
-rw-r--r-- | common/console.c | 24 | ||||
-rw-r--r-- | common/console_simple.c | 4 | ||||
-rw-r--r-- | common/env.c | 22 | ||||
-rw-r--r-- | common/filetype.c | 99 | ||||
-rw-r--r-- | common/hush.c | 8 | ||||
-rw-r--r-- | common/image.c | 3 | ||||
-rw-r--r-- | common/memory.c | 58 | ||||
-rw-r--r-- | common/partitions.c | 200 | ||||
-rw-r--r-- | common/resource.c | 121 |
11 files changed, 554 insertions, 7 deletions
diff --git a/common/Kconfig b/common/Kconfig index 8e96920e48..1318e7d747 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -406,6 +406,24 @@ config PARTITION bool prompt "Enable Partitions" +if PARTITION + +config PARTITION_DISK + bool "DISK partition support" + help + Add support for handling common partition tables on all kind of disk + like devices (harddisks, CF cards, SD cards and so on) + +if PARTITION_DISK + +config PARTITION_DISK_DOS + bool "DOS partition support" + help + Add support to handle partitions in DOS style. + +endif +endif + config DEFAULT_ENVIRONMENT bool default y diff --git a/common/Makefile b/common/Makefile index 7bb8ea4322..9bce47943c 100644 --- a/common/Makefile +++ b/common/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_ENV_HANDLING) += environment.o obj-$(CONFIG_AUTO_COMPLETE) += complete.o obj-$(CONFIG_POLLER) += poller.o obj-$(CONFIG_BLOCK) += block.o +obj-$(CONFIG_PARTITION_DISK) += partitions.o + obj-$(CONFIG_CMD_LOADS) += s_record.o obj-$(CONFIG_OFTREE) += oftree.o @@ -24,6 +26,8 @@ obj-$(CONFIG_CMD_BOOTM) += image.o obj-y += startup.o obj-y += misc.o obj-y += memsize.o +obj-y += filetype.o +obj-y += resource.o obj-$(CONFIG_MENU) += menu.o obj-$(CONFIG_PASSWORD) += password.o obj-$(CONFIG_MODULES) += module.o diff --git a/common/console.c b/common/console.c index e5c0581381..cab8689252 100644 --- a/common/console.c +++ b/common/console.c @@ -154,13 +154,9 @@ int console_register(struct console_device *newcdev) list_add_tail(&newcdev->list, &console_list); - if (console_output_buffer) { - while (kfifo_getc(console_output_buffer, &ch) == 0) - console_putc(CONSOLE_STDOUT, ch); - kfifo_free(console_output_buffer); - console_output_buffer = NULL; - } + while (kfifo_getc(console_output_buffer, &ch) == 0) + console_putc(CONSOLE_STDOUT, ch); if (first) barebox_banner(); @@ -168,6 +164,22 @@ int console_register(struct console_device *newcdev) } EXPORT_SYMBOL(console_register); +int console_unregister(struct console_device *cdev) +{ + struct device_d *dev = &cdev->class_dev; + int status; + + list_del(&cdev->list); + if (list_empty(&console_list)) + initialized = CONSOLE_UNINITIALIZED; + + status = unregister_device(dev); + if (!status) + memset(cdev, 0, sizeof(*cdev)); + return status; +} +EXPORT_SYMBOL(console_unregister); + static int getc_raw(void) { struct console_device *cdev; diff --git a/common/console_simple.c b/common/console_simple.c index 61a233d1b5..73e4752cd8 100644 --- a/common/console_simple.c +++ b/common/console_simple.c @@ -164,3 +164,7 @@ int console_register(struct console_device *newcdev) } return 0; } + +int console_unregister(struct console_device *cdev) +{ +} diff --git a/common/env.c b/common/env.c index 05ed71418e..e57a520a35 100644 --- a/common/env.c +++ b/common/env.c @@ -251,3 +251,25 @@ int export(const char *varname) return 0; } EXPORT_SYMBOL(export); + +void export_env_ull(const char *name, unsigned long long val) +{ + char *valstr = asprintf("%lld", val); + + setenv(name, valstr); + export(name); + + kfree(valstr); +} +EXPORT_SYMBOL(export_env_ull); + +unsigned long long getenv_ull(const char *name) +{ + const char *valstr = getenv(name); + + if (!valstr) + return 0; + + return simple_strtoull(valstr, NULL, 0); +} +EXPORT_SYMBOL(getenv_ull); diff --git a/common/filetype.c b/common/filetype.c new file mode 100644 index 0000000000..5635d40af0 --- /dev/null +++ b/common/filetype.c @@ -0,0 +1,99 @@ +/* + * filetype.c - detect filetypes + * + * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation. + */ +#include <common.h> +#include <filetype.h> +#include <asm/byteorder.h> +#include <fcntl.h> +#include <fs.h> +#include <malloc.h> + +static const char *filetype_str[] = { + [filetype_unknown] = "unknown", + [filetype_arm_zimage] = "arm Linux zImage", + [filetype_lzo_compressed] = "lzo compressed", + [filetype_arm_barebox] = "arm barebox image", + [filetype_uimage] = "U-Boot uImage", + [filetype_ubi] = "UBI image", + [filetype_jffs2] = "JFFS2 image", + [filetype_gzip] = "gzip compressed", + [filetype_bzip2] = "bzip2 compressed", +}; + +const char *file_type_to_string(enum filetype f) +{ + if (f < ARRAY_SIZE(filetype_str)) + return filetype_str[f]; + + return NULL; +} + +enum filetype file_detect_type(void *_buf) +{ + u32 *buf = _buf; + u8 *buf8 = _buf; + + if (buf[8] == 0x65726162 && buf[9] == 0x00786f62) + return filetype_arm_barebox; + if (buf[9] == 0x016f2818 || buf[9] == 0x18286f01) + return filetype_arm_zimage; + if (buf8[0] == 0x89 && buf8[1] == 0x4c && buf8[2] == 0x5a && + buf8[3] == 0x4f) + return filetype_lzo_compressed; + if (buf[0] == be32_to_cpu(0x27051956)) + return filetype_uimage; + if (buf[0] == 0x23494255) + return filetype_ubi; + if (buf[0] == 0x20031985) + return filetype_jffs2; + if (buf8[0] == 0x1f && buf8[1] == 0x8b && buf8[2] == 0x08) + return filetype_gzip; + if (buf8[0] == 'B' && buf8[1] == 'Z' && buf8[2] == 'h' && + buf8[3] > '0' && buf8[3] <= '9') + return filetype_bzip2; + + return filetype_unknown; +} + +enum filetype file_name_detect_type(const char *filename) +{ + int fd, ret; + void *buf; + enum filetype type = filetype_unknown; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return fd; + + buf = xmalloc(512); + + ret = read(fd, buf, 512); + if (ret != 512) + goto err_out; + + type = file_detect_type(buf); + +err_out: + close(fd); + free(buf); + + return type; +} diff --git a/common/hush.c b/common/hush.c index 573bd3ef1d..b59e59dd17 100644 --- a/common/hush.c +++ b/common/hush.c @@ -122,6 +122,7 @@ #include <glob.h> #include <getopt.h> #include <libbb.h> +#include <magicvar.h> #include <linux/list.h> /*cmd_boot.c*/ @@ -540,6 +541,8 @@ static int builtin_getopt(struct p_context *ctx, struct child_prog *child) return 0; } + +BAREBOX_MAGICVAR(OPTARG, "optarg for hush builtin getopt"); #endif /* run_pipe_real() starts all the jobs, but doesn't wait for anything @@ -1721,6 +1724,11 @@ BAREBOX_CMD_START(getopt) BAREBOX_CMD_END #endif +BAREBOX_MAGICVAR(PATH, "colon seperated list of pathes to search for executables"); +#ifdef CONFIG_HUSH_FANCY_PROMPT +BAREBOX_MAGICVAR(PS1, "hush prompt"); +#endif + /** * @file * @brief A prototype Bourne shell grammar parser diff --git a/common/image.c b/common/image.c index 4a6402d8b9..d68889bc0f 100644 --- a/common/image.c +++ b/common/image.c @@ -290,7 +290,7 @@ void image_print_contents(const image_header_t *hdr, void *data) printf ("%sEntry Point: %08x\n", p, image_get_ep(hdr)); type = image_get_type(hdr); - if (type == IH_TYPE_MULTI || type == IH_TYPE_SCRIPT) { + if (data && (type == IH_TYPE_MULTI || type == IH_TYPE_SCRIPT)) { int i; ulong img_data, len; ulong count = image_multi_count(data); @@ -404,6 +404,7 @@ err_out: close(fd); if (handle->flags & IH_MALLOC) free(handle->data); + free(handle->data_entries); free(handle); return NULL; } diff --git a/common/memory.c b/common/memory.c index 0ba9a18e88..7d0f4cab2a 100644 --- a/common/memory.c +++ b/common/memory.c @@ -25,6 +25,9 @@ #include <of.h> #include <init.h> #include <libfdt.h> +#include <linux/ioport.h> +#include <asm-generic/memory_layout.h> +#include <asm/sections.h> /* * Begin and End of memory area for malloc(), and current "brk" @@ -50,6 +53,33 @@ void mem_malloc_init(void *start, void *end) malloc_brk = malloc_start; } +static int mem_malloc_resource(void) +{ + /* + * Normally it's a bug when one of these fails, + * but we have some setups where some of these + * regions are outside of sdram in which case + * the following fails. + */ + request_sdram_region("malloc space", + malloc_start, + malloc_end - malloc_start + 1); + request_sdram_region("barebox", + (unsigned long)&_stext, + (unsigned long)&_etext - + (unsigned long)&_stext + 1); + request_sdram_region("bss", + (unsigned long)&__bss_start, + (unsigned long)&__bss_stop - + (unsigned long)&__bss_start + 1); +#ifdef STACK_BASE + request_sdram_region("stack", STACK_BASE, STACK_SIZE); +#endif + + return 0; +} +coredevice_initcall(mem_malloc_resource); + static void *sbrk_no_zero(ptrdiff_t increment) { unsigned long old = malloc_brk; @@ -82,6 +112,10 @@ void barebox_add_memory_bank(const char *name, resource_size_t start, struct memory_bank *bank = xzalloc(sizeof(*bank)); struct device_d *dev; + bank->res = request_iomem_region(name, start, size); + + BUG_ON(!bank->res); + dev = add_mem_device(name, start, size, IORESOURCE_MEM_WRITEABLE); bank->dev = dev; @@ -91,6 +125,30 @@ void barebox_add_memory_bank(const char *name, resource_size_t start, list_add_tail(&bank->list, &memory_banks); } +/* + * Request a region from the registered sdram + */ +struct resource *request_sdram_region(const char *name, resource_size_t start, + resource_size_t size) +{ + struct memory_bank *bank; + + for_each_memory_bank(bank) { + struct resource *res; + + res = request_region(bank->res, name, start, size); + if (res) + return res; + } + + return NULL; +} + +int release_sdram_region(struct resource *res) +{ + return release_region(res); +} + #ifdef CONFIG_OFTREE /* diff --git a/common/partitions.c b/common/partitions.c new file mode 100644 index 0000000000..e4f3ad69e3 --- /dev/null +++ b/common/partitions.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2009...2011 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Generic support for partition tables on disk like media + * + * @todo Support for disks larger than 4 GiB + * @todo Reliable size detection for BIOS based disks (on x86 only) + */ +#include <common.h> +#include <malloc.h> +#include <errno.h> +#include <block.h> +#include <asm/unaligned.h> +#include <disks.h> + +struct partition { + uint64_t first_sec; + uint64_t size; +}; + +struct partition_desc { + int used_entries; + struct partition parts[8]; +}; + +/** + * Reject values which cannot be used in Barebox + * @param val Value to be check + * @return 0 if value can be used in Barebox, -EINVAL if not + * + * @note this routine can be removed when Barebox uses file offsets larger + * than 32 bit + */ +static int check_offset_value(uint64_t val) +{ +#if 1 /* until Barebox can handle 64 bit offsets */ + if (val > (__INT_MAX__ / SECTOR_SIZE)) + return -EINVAL; +#endif + return 0; +} + +/** + * Guess the size of the disk, based on the partition table entries + * @param dev device to create partitions for + * @param table partition table + * @return sector count + */ +static int disk_guess_size(struct device_d *dev, struct partition_entry *table) +{ + uint64_t size = 0; + int i; + + for (i = 0; i < 4; i++) { + if (table[i].partition_start != 0) { + size += get_unaligned(&table[i].partition_start) - size; + size += get_unaligned(&table[i].partition_size); + } + } + /* limit disk sector counts we can't handle due to 32 bit limits */ + if (check_offset_value(size) != 0) { + dev_warn(dev, "Warning: Sector count limited due to 31 bit" + "contraints\n"); + size = __INT_MAX__ / SECTOR_SIZE; + } + + return (int)size; +} + +/** + * Check if a DOS like partition describes this block device + * @param blk Block device to register to + * @param pd Where to store the partition information + * + * It seems at least on ARM this routine canot use temp. stack space for the + * sector. So, keep the malloc/free. + */ +static void __maybe_unused try_dos_partition(struct block_device *blk, + struct partition_desc *pd) +{ + uint8_t *buffer; + struct partition_entry *table; + struct partition pentry; + int i, rc; + + buffer = xmalloc(SECTOR_SIZE); + + /* read in the MBR to get the partition table */ + rc = blk->ops->read(blk, buffer, 0, 1); + if (rc != 0) { + dev_err(blk->dev, "Cannot read MBR/partition table\n"); + goto on_error; + } + + if ((buffer[510] != 0x55) || (buffer[511] != 0xAA)) { + dev_info(blk->dev, "No partition table found\n"); + goto on_error; + } + + table = (struct partition_entry *)&buffer[446]; + + /* valid for x86 BIOS based disks only */ + if (blk->num_blocks == 0) + blk->num_blocks = disk_guess_size(blk->dev, table); + + for (i = 0; i < 4; i++) { + pentry.first_sec = get_unaligned(&table[i].partition_start); + pentry.size = get_unaligned(&table[i].partition_size); + + /* do we have to ignore this partition due to limitations? */ + if (check_offset_value(pentry.first_sec) != 0) + continue; + if (check_offset_value(pentry.size) != 0) + continue; + + if (pentry.first_sec != 0) { + pd->parts[pd->used_entries].first_sec = pentry.first_sec; + pd->parts[pd->used_entries].size = pentry.size; + pd->used_entries++; + } else { + dev_dbg(blk->dev, "Skipping empty partition %d\n", i); + } + } + +on_error: + free(buffer); +} + +/** + * Register one partition on the given block device + * @param blk Block device to register to + * @param part Partition description + * @param no Partition number + * @return 0 on success + */ +static int register_one_partition(struct block_device *blk, + struct partition *part, int no) +{ + char partition_name[19]; + + sprintf(partition_name, "%s.%d", blk->cdev.name, no); + dev_dbg(blk->dev, "Registering partition %s on drive %s\n", + partition_name, blk->cdev.name); + return devfs_add_partition(blk->cdev.name, + part->first_sec * SECTOR_SIZE, + part->size * SECTOR_SIZE, + DEVFS_PARTITION_FIXED, partition_name); +} + +/** + * Try to collect partition information on the given block device + * @param blk Block device to examine + * @return 0 most of the time, negative value else + * + * It is not a failure if no partition information is found + */ +int parse_partition_table(struct block_device *blk) +{ + struct partition_desc pdesc = { .used_entries = 0, }; + int i; + int rc = 0; + +#ifdef CONFIG_PARTITION_DISK_DOS + try_dos_partition(blk, &pdesc); +#endif + if (!pdesc.used_entries) + return 0; + + /* at least one partition description found */ + for (i = 0; i < pdesc.used_entries; i++) { + rc = register_one_partition(blk, &pdesc.parts[i], i); + if (rc != 0) + dev_err(blk->dev, + "Failed to register partition %d on %s (%d)\n", + i, blk->cdev.name, rc); + if (rc != -ENODEV) + rc = 0; + } + + return rc; +} diff --git a/common/resource.c b/common/resource.c new file mode 100644 index 0000000000..63e9c49ca1 --- /dev/null +++ b/common/resource.c @@ -0,0 +1,121 @@ +/* + * resource.c - barebox resource management + * + * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation. + */ +#include <common.h> +#include <malloc.h> +#include <errno.h> +#include <init.h> +#include <linux/ioport.h> + +static int init_resource(struct resource *res, const char *name) +{ + INIT_LIST_HEAD(&res->children); + res->parent = NULL; + res->name = xstrdup(name); + + return 0; +} + +/* + * request a region. + * This will succedd when the requested region is completely inside + * the parent resource and does not conflict with any of the child + * resources. + */ +struct resource *request_region(struct resource *parent, + const char *name, resource_size_t start, + resource_size_t size) +{ + struct resource *r, *new; + + /* outside parent resource? */ + if (start < parent->start || + start + size > parent->start + parent->size) { + debug("%s: 0x%08x:0x%08x outside parent resource 0x%08x:0x%08x\n", + __func__, start, size, parent->start, + parent->size); + return NULL; + } + + /* + * We keep the list of child resources ordered which helps + * us searching for conflicts here. + */ + list_for_each_entry(r, &parent->children, sibling) { + if (start + size <= r->start) + goto ok; + if (start >= r->start + r->size) + continue; + debug("%s: 0x%08x:0x%08x conflicts with 0x%08x:0x%08x\n", + __func__, start, size, r->start, r->size); + return NULL; + } + +ok: + debug("%s ok: 0x%08x 0x%08x\n", __func__, start, size); + + new = xzalloc(sizeof(*new)); + init_resource(new, name); + new->start = start; + new->size = size; + new->parent = parent; + list_add_tail(&new->sibling, &r->sibling); + + return new; +} + +/* + * release a region previously requested with request_region + */ +int release_region(struct resource *res) +{ + if (!list_empty(&res->children)) + return -EBUSY; + + list_del(&res->sibling); + free((char *)res->name); + free(res); + + return 0; +} + +/* The root resource for the whole io space */ +struct resource iomem_resource = { + .start = 0, + .size = ~0, +}; + +/* + * request a region inside the io space + */ +struct resource *request_iomem_region(const char *name, + resource_size_t start, resource_size_t size) +{ + return request_region(&iomem_resource, name, start, size); +} + +static int iomem_init(void) +{ + init_resource(&iomem_resource, "iomem"); + + return 0; +} +postcore_initcall(iomem_init); |