summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2011-12-07 12:03:13 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2011-12-07 12:03:13 +0100
commit0ee6847f7b6d396d3756f6ecd0781a00b9cca980 (patch)
tree1f1bed639ac0bbc9091685538c791b4648f4c342 /common
parent61b62f6d33d55c9b89ba8a6fbae84cb9c33e342a (diff)
parent8b3d10265da20b8be6138799cee704d53dee1c63 (diff)
downloadbarebox-0ee6847f7b6d396d3756f6ecd0781a00b9cca980.tar.gz
Merge branch 'next'
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig18
-rw-r--r--common/Makefile4
-rw-r--r--common/console.c24
-rw-r--r--common/console_simple.c4
-rw-r--r--common/env.c22
-rw-r--r--common/filetype.c99
-rw-r--r--common/hush.c8
-rw-r--r--common/image.c3
-rw-r--r--common/memory.c58
-rw-r--r--common/partitions.c200
-rw-r--r--common/resource.c121
11 files changed, 554 insertions, 7 deletions
diff --git a/common/Kconfig b/common/Kconfig
index 8e96920..1318e7d 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 7bb8ea4..9bce479 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 e5c0581..cab8689 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 61a233d..73e4752 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 05ed714..e57a520 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 0000000..5635d40
--- /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 573bd3e..b59e59d 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 4a6402d..d68889b 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 0ba9a18..7d0f4ca 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 0000000..e4f3ad6
--- /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 0000000..63e9c49
--- /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);