From 967a2675ba32c88140a1656aa21256baac525986 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Thu, 24 Nov 2011 13:43:46 +0100 Subject: DISK: Add common partition handling for disk like media This covers disk like media like SD card, CF cards, regular hard disks and also USB mass storage devices. Most common used partition table is still of DOS type. This implementation is prepared to support more partition types in the future. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- common/Kconfig | 18 +++++ common/Makefile | 2 + common/partitions.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 common/partitions.c (limited to 'common') 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..3edf38f3ba 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 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 +#include +#include +#include +#include +#include + +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; +} -- cgit v1.2.3 From 76dca8279e820d3d6c254d2a8dcdd788f0d4c6e1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sun, 27 Nov 2011 13:00:47 +0100 Subject: hush: Add magicvars Signed-off-by: Sascha Hauer --- common/hush.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'common') 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 #include #include +#include #include /*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 -- cgit v1.2.3 From ac4854be5e67b4d19884fb4462982d91ca9bc815 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 25 Nov 2011 19:09:07 +0100 Subject: factor out iminfo command The rests of U-Boots iminfo command are sitting in commands/bootm.c and are in a nonusable state. Factor it out to its own file and make it work again. Signed-off-by: Sascha Hauer --- commands/Kconfig | 6 +++++ commands/Makefile | 1 + commands/bootm.c | 79 ------------------------------------------------------- commands/iminfo.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ common/image.c | 2 +- include/image.h | 3 --- 6 files changed, 79 insertions(+), 83 deletions(-) create mode 100644 commands/iminfo.c (limited to 'common') diff --git a/commands/Kconfig b/commands/Kconfig index 78b9d2a0e6..93f14b278e 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -309,6 +309,12 @@ config CMD_BOOTM_SHOW_TYPE depends on CMD_BOOTM prompt "show image information" +config CMD_IMINFO + bool + prompt "iminfo" + help + Show information about uImages + config CMD_BOOTZ tristate default y diff --git a/commands/Makefile b/commands/Makefile index 9b3a349bd2..45f9ccfd56 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o +obj-$(CONFIG_CMD_IMINFO) += iminfo.o obj-$(CONFIG_CMD_LINUX16) += linux16.o obj-$(CONFIG_CMD_LOADB) += loadb.o xyzModem.o obj-$(CONFIG_CMD_LOADY) += loadb.o xyzModem.o diff --git a/commands/bootm.c b/commands/bootm.c index d0bb35062a..8936897a04 100644 --- a/commands/bootm.c +++ b/commands/bootm.c @@ -321,85 +321,6 @@ BAREBOX_CMD_END BAREBOX_MAGICVAR(bootargs, "Linux Kernel parameters"); -/** - * @page bootm_command - -\todo What does bootm do, what kind of image does it boot? - - */ - -#ifdef CONFIG_CMD_IMI -static int do_iminfo(struct command *cmdtp, int argc, char *argv[]) -{ - int arg; - ulong addr; - int rcode=0; - - if (argc < 2) { - return image_info (load_addr); - } - - for (arg=1; arg ih_hcrc = 0; - - if (crc32 (0, (uchar *)data, len) != checksum) { - puts (" Bad Header Checksum\n"); - return 1; - } - - /* for multi-file images we need the data part, too */ - print_image_hdr ((image_header_t *)addr); - - data = addr + image_get_header_size(); - len = image_get_size(hdr); - - puts (" Verifying Checksum ... "); - if (crc32 (0, (uchar *)data, len) != image_get_dcrc(hdr)) { - puts (" Bad Data CRC\n"); - return 1; - } - puts ("OK\n"); - return 0; -} - -BAREBOX_CMD_HELP_START(iminfo) -BAREBOX_CMD_HELP_USAGE("iminfo\n") -BAREBOX_CMD_HELP_SHORT("Print header information for an application image.\n") -BAREBOX_CMD_HELP_END - -BAREBOX_CMD_START(iminfo) - .cmd = do_iminfo, - .usage = "print header information for an application image", - BAREBOX_CMD_HELP(cmd_iminfo_help) -BAREBOX_CMD_END - -#endif /* CONFIG_CMD_IMI */ - #ifdef CONFIG_BZLIB void bz_internal_error(int errcode) { diff --git a/commands/iminfo.c b/commands/iminfo.c new file mode 100644 index 0000000000..2fde9bc09c --- /dev/null +++ b/commands/iminfo.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include + +static int image_info(image_header_t *hdr) +{ + u32 len, checksum; + + if (image_get_magic(hdr) != IH_MAGIC) { + puts (" Bad Magic Number\n"); + return 1; + } + + len = image_get_header_size(); + + checksum = image_get_hcrc(hdr); + hdr->ih_hcrc = 0; + + if (crc32 (0, hdr, len) != checksum) { + puts (" Bad Header Checksum\n"); + return 1; + } + + image_print_contents(hdr, NULL); + + return 0; +} + +static int do_iminfo(struct command *cmdtp, int argc, char *argv[]) +{ + int rcode = 1; + int fd; + int ret; + image_header_t hdr; + + if (argc != 2) + return COMMAND_ERROR_USAGE; + + fd = open(argv[1], O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + ret = read(fd, &hdr, sizeof(image_header_t)); + if (ret != sizeof(image_header_t)) + goto err_out; + + printf("Image at %s:\n", argv[1]); + image_info(&hdr); + +err_out: + close(fd); + + return rcode; +} + +BAREBOX_CMD_HELP_START(iminfo) +BAREBOX_CMD_HELP_USAGE("iminfo\n") +BAREBOX_CMD_HELP_SHORT("Print header information for an application image.\n") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(iminfo) + .cmd = do_iminfo, + .usage = "print header information for an application image", + BAREBOX_CMD_HELP(cmd_iminfo_help) +BAREBOX_CMD_END diff --git a/common/image.c b/common/image.c index 4a6402d8b9..939fe4b75d 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); diff --git a/include/image.h b/include/image.h index 691bf2d88b..f3a9949e54 100644 --- a/include/image.h +++ b/include/image.h @@ -335,9 +335,6 @@ void image_print_size(uint32_t size); void image_print_contents(const image_header_t *hdr, void *data); -/* commamds/bootm.c */ -void print_image_hdr (image_header_t *hdr); - /* * Load an image into memory. Returns a pointer to the loaded * image. -- cgit v1.2.3 From a94db01cdce44acc50c7ad8ebcb9040b0020fabd Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 26 Nov 2011 13:53:42 +0100 Subject: introduce some env helpers Signed-off-by: Sascha Hauer --- common/env.c | 22 ++++++++++++++++++++++ include/environment.h | 3 +++ 2 files changed, 25 insertions(+) (limited to 'common') 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/include/environment.h b/include/environment.h index da032e21d6..6d38755ae7 100644 --- a/include/environment.h +++ b/include/environment.h @@ -59,6 +59,9 @@ static inline int setenv(const char *var, const char *val) } #endif +void export_env_ull(const char *name, unsigned long long val); +unsigned long long getenv_ull(const char *name); + int env_pop_context(void); int env_push_context(void); -- cgit v1.2.3 From 72bdddcca38dd8ad234c8a8d98651c01c503296a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sun, 27 Nov 2011 15:57:03 +0100 Subject: bootm: fix various memory leaks Signed-off-by: Sascha Hauer --- commands/bootm.c | 19 +++++++++++-------- common/image.c | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'common') diff --git a/commands/bootm.c b/commands/bootm.c index 9f3f354e66..6255c03e7d 100644 --- a/commands/bootm.c +++ b/commands/bootm.c @@ -146,10 +146,11 @@ static int do_bootm(struct command *cmdtp, int argc, char *argv[]) { int opt; image_header_t *os_header; - struct image_handle *os_handle, *initrd_handle = NULL; + struct image_handle *os_handle = NULL; struct image_handler *handler; struct image_data data; u32 initrd_start; + int ret = 1; memset(&data, 0, sizeof(struct image_data)); data.verify = 1; @@ -179,19 +180,21 @@ static int do_bootm(struct command *cmdtp, int argc, char *argv[]) data.initrd = map_image(optarg, data.verify); } if (!data.initrd) - return -1; + goto err_out; break; default: break; } } - if (optind == argc) - return COMMAND_ERROR_USAGE; + if (optind == argc) { + ret = COMMAND_ERROR_USAGE; + goto err_out; + } os_handle = map_image(argv[optind], data.verify); if (!os_handle) - return 1; + goto err_out; data.os = os_handle; os_header = &os_handle->header; @@ -225,9 +228,9 @@ static int do_bootm(struct command *cmdtp, int argc, char *argv[]) err_out: if (os_handle) unmap_image(os_handle); - if (initrd_handle) - unmap_image(initrd_handle); - return 1; + if (data.initrd) + unmap_image(data.initrd); + return ret; } BAREBOX_CMD_HELP_START(bootm) diff --git a/common/image.c b/common/image.c index 939fe4b75d..d68889bc0f 100644 --- a/common/image.c +++ b/common/image.c @@ -404,6 +404,7 @@ err_out: close(fd); if (handle->flags & IH_MALLOC) free(handle->data); + free(handle->data_entries); free(handle); return NULL; } -- cgit v1.2.3 From b6996039f622ccc8488176e211bf41315f9691c6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 25 Nov 2011 18:49:14 +0100 Subject: add file detection support Several filetypes can be autodetected. Barebox could make use of this in several ways: - Add a command to detect filetypes - detect arm zImages and uImages to unify the different boot commands - maybe detect UBI or JFFS2 images to construct parts of the kernel command line - select correct uncompression function based on filetype This patch adds basic support to detect filetypes. Signed-off-by: Sascha Hauer --- common/Makefile | 1 + common/filetype.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/filetype.h | 23 +++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 common/filetype.c create mode 100644 include/filetype.h (limited to 'common') diff --git a/common/Makefile b/common/Makefile index 3edf38f3ba..55d9dbcb43 100644 --- a/common/Makefile +++ b/common/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_CMD_BOOTM) += image.o obj-y += startup.o obj-y += misc.o obj-y += memsize.o +obj-y += filetype.o obj-$(CONFIG_MENU) += menu.o obj-$(CONFIG_PASSWORD) += password.o obj-$(CONFIG_MODULES) += module.o 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 , 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 +#include +#include +#include +#include +#include + +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/include/filetype.h b/include/filetype.h new file mode 100644 index 0000000000..64d32ef8b0 --- /dev/null +++ b/include/filetype.h @@ -0,0 +1,23 @@ +#ifndef __FILE_TYPE_H +#define __FILE_TYPE_H + +/* + * List of file types we know + */ +enum filetype { + filetype_unknown, + filetype_arm_zimage, + filetype_lzo_compressed, + filetype_arm_barebox, + filetype_uimage, + filetype_ubi, + filetype_jffs2, + filetype_gzip, + filetype_bzip2, +}; + +const char *file_type_to_string(enum filetype f); +enum filetype file_detect_type(void *_buf); +enum filetype file_name_detect_type(const char *filename); + +#endif /* __FILE_TYPE_H */ -- cgit v1.2.3 From 200ae6b4eef9f6041016887f71fc01c5daee6f69 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 1 Dec 2011 21:44:02 +0100 Subject: add resource management functions It is time to track our memory usage. Add a simple resource management. Signed-off-by: Sascha Hauer --- common/Makefile | 1 + common/resource.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/ioport.h | 14 ++++++ 3 files changed, 136 insertions(+) create mode 100644 common/resource.c (limited to 'common') diff --git a/common/Makefile b/common/Makefile index 55d9dbcb43..9bce47943c 100644 --- a/common/Makefile +++ b/common/Makefile @@ -27,6 +27,7 @@ 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/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 , 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 +#include +#include +#include +#include + +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); diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 51431158d3..c837b53491 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -20,6 +20,9 @@ struct resource { resource_size_t size; const char *name; unsigned long flags; + struct resource *parent; + struct list_head children; + struct list_head sibling; }; /* @@ -111,5 +114,16 @@ static inline unsigned long resource_type(const struct resource *res) return res->flags & IORESOURCE_TYPE_BITS; } +struct resource *request_iomem_region(const char *name, + resource_size_t start, resource_size_t size); + +struct resource *request_region(struct resource *parent, + const char *name, resource_size_t start, + resource_size_t size); + +int release_region(struct resource *res); + +extern struct resource iomem_resource; + #endif /* __ASSEMBLY__ */ #endif /* _LINUX_IOPORT_H */ -- cgit v1.2.3 From ec8dd2542847c4e161d8fc521dfc6af0ed25c896 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 1 Dec 2011 22:09:49 +0100 Subject: register sdram as resources Also, request the sdram regions used by the barebox binary, bss, malloc space and stack. Signed-off-by: Sascha Hauer --- common/memory.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/memory.h | 5 +++++ 2 files changed, 63 insertions(+) (limited to 'common') 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 #include #include +#include +#include +#include /* * 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/include/memory.h b/include/memory.h index cb185afa65..4be4340b14 100644 --- a/include/memory.h +++ b/include/memory.h @@ -13,6 +13,7 @@ struct memory_bank { struct device_d *dev; unsigned long start; unsigned long size; + struct resource *res; }; extern struct list_head memory_banks; @@ -22,4 +23,8 @@ void barebox_add_memory_bank(const char *name, resource_size_t start, #define for_each_memory_bank(mem) list_for_each_entry(mem, &memory_banks, list) +struct resource *request_sdram_region(const char *name, resource_size_t start, + resource_size_t size); +int release_sdram_region(struct resource *res); + #endif -- cgit v1.2.3 From ea8314d19f6441061232549ec41ab0e21abd74ca Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 24 Nov 2011 04:01:26 +0100 Subject: console: add console unregistering Some console are transient, like the USB connected serial console which should be removed when the USB connection is severed. Enable console removal for such devices. Signed-off-by: Robert Jarzmik Signed-off-by: Sascha Hauer --- common/console.c | 24 ++++++++++++++++++------ common/console_simple.c | 4 ++++ include/console.h | 1 + 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'common') diff --git a/common/console.c b/common/console.c index 944dd07197..219148d097 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 7304d8ee05..7e0619db02 100644 --- a/common/console_simple.c +++ b/common/console_simple.c @@ -157,3 +157,7 @@ int console_register(struct console_device *newcdev) } return 0; } + +int console_unregister(struct console_device *cdev) +{ +} diff --git a/include/console.h b/include/console.h index 3bcc5dbbc0..c0817f6371 100644 --- a/include/console.h +++ b/include/console.h @@ -49,6 +49,7 @@ struct console_device { }; int console_register(struct console_device *cdev); +int console_unregister(struct console_device *cdev); extern struct list_head console_list; #define for_each_console(console) list_for_each_entry(console, &console_list, list) -- cgit v1.2.3