To use barebox as a BIOS based bootloader for x86 architectures, the binary must be patched to get it bootstrapped at runtime. The 'setupmbr' tool installs the barebox-binary to the given device node or image file and patch it in accordance to the needed sector information at runtime. Signed-off by: Juergen Beisert --- Doxyfile | 3 scripts/Makefile | 4 scripts/setupmbr/Makefile | 4 scripts/setupmbr/arch.h | 55 +++ scripts/setupmbr/setupmbr.c | 705 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 769 insertions(+), 2 deletions(-) Index: barebox-2009.12.0/scripts/Makefile =================================================================== --- barebox-2009.12.0.orig/scripts/Makefile +++ barebox-2009.12.0/scripts/Makefile @@ -14,5 +14,7 @@ always := $(hostprogs-y) $(hostprogs-m) subdir-y += mod +subdir-$(CONFIG_X86) += setupmbr + # Let clean descend into subdirs -subdir- += basic kconfig +subdir- += basic kconfig setupmbr Index: barebox-2009.12.0/scripts/setupmbr/Makefile =================================================================== --- /dev/null +++ barebox-2009.12.0/scripts/setupmbr/Makefile @@ -0,0 +1,4 @@ +HOST_EXTRACFLAGS=-I$(srctree) + +hostprogs-y := setupmbr +always := $(hostprogs-y) Index: barebox-2009.12.0/scripts/setupmbr/arch.h =================================================================== --- /dev/null +++ barebox-2009.12.0/scripts/setupmbr/arch.h @@ -0,0 +1,55 @@ + +/* we need the one from the host */ +#include +#include + +/* Byte-orders. */ +#define swap16(x) \ +({ \ + uint16_t _x = (x); \ + (uint16_t) ((_x << 8) | (_x >> 8)); \ +}) + +#define swap32(x) \ +({ \ + uint32_t _x = (x); \ + (uint32_t) ((_x << 24) \ + | ((_x & (uint32_t) 0xFF00UL) << 8) \ + | ((_x & (uint32_t) 0xFF0000UL) >> 8) \ + | (_x >> 24)); \ +}) + +#define swap64(x) \ +({ \ + uint64_t _x = (x); \ + (uint64_t) ((_x << 56) \ + | ((_x & (uint64_t) 0xFF00ULL) << 40) \ + | ((_x & (uint64_t) 0xFF0000ULL) << 24) \ + | ((_x & (uint64_t) 0xFF000000ULL) << 8) \ + | ((_x & (uint64_t) 0xFF00000000ULL) >> 8) \ + | ((_x & (uint64_t) 0xFF0000000000ULL) >> 24) \ + | ((_x & (uint64_t) 0xFF000000000000ULL) >> 40) \ + | (_x >> 56)); \ +}) + +#if __BYTE_ORDER == __BIG_ENDIAN + +/* Our target is a ia32 machine, always little endian */ + +# define host2target_16(x) swap16(x) +# define host2target_32(x) swap32(x) +# define host2target_64(x) swap64(x) +# define target2host_16(x) swap16(x) +# define target2host_32(x) swap32(x) +# define target2host_64(x) swap64(x) + +#else + +# define host2target_16(x) (x) +# define host2target_32(x) (x) +# define host2target_64(x) (x) +# define target2host_16(x) (x) +# define target2host_32(x) (x) +# define target2host_64(x) (x) + +#endif Index: barebox-2009.12.0/scripts/setupmbr/setupmbr.c =================================================================== --- /dev/null +++ barebox-2009.12.0/scripts/setupmbr/setupmbr.c @@ -0,0 +1,705 @@ +/* + * Copyright (C) 2009 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 Write the barebox binary to the MBR and the following disk sectors + * + * Also patch dedicated locations in the image to make it work at runtime + * + * Current restrictions are: + * - only installs into MBR and the sectors after it + * - tested only with QEMU + * - and maybe some others + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* include the info from this barebox release */ +#include "include/linux/utsrelease.h" +#include "arch/x86/include/asm/barebox.lds.h" + +/** define to disable integrity tests and debug messages */ +#define NDEBUG + +/* some infos about our target architecture */ +#include "arch.h" + +/** + * "Disk Address Packet Structure" to be used when calling int13, + * function 0x42 + * + * @note All entries are in target endianess + */ +struct DAPS +{ + uint8_t size; /**< size of this data set, 0 marks it as invalid */ + uint8_t res1; /**< always 0 */ + int8_t count; /**< number of sectors 0...127 to handle */ + uint8_t res2; /**< always 0 */ + uint16_t offset; /**< store address: offset */ + uint16_t segment; /**< store address: segment */ + uint64_t lba; /**< start sector number in LBA */ +} __attribute__ ((packed)); + +/** + * Description of one partition table entry (D*S type) + * + * @note All entries are in target endianess + */ +struct partition_entry { + uint8_t boot_indicator; + uint8_t chs_begin[3]; + uint8_t type; + uint8_t chs_end[3]; + uint32_t partition_start; /* LE */ + uint32_t partition_size; /* LE */ +} __attribute__ ((packed)); + +#ifndef NDEBUG +static void debugout(const struct DAPS *entry, int supress_entry) +{ + if (supress_entry) + printf("DAPS entry: "); + else + printf("DAPS entry % 3u: ", ((unsigned)entry & ( SECTOR_SIZE - 1)) / sizeof(struct DAPS)); + + printf("Size: % 2u, Count: % 3d, Offset: 0x%04hX, Segment: 0x%04hX, LBA: %llu\n", + entry->size, entry->count, + target2host_16(entry->offset), target2host_16(entry->segment), + target2host_64(entry->lba)); +} +#else +# define debugout(x,y) (__ASSERT_VOID_CAST(0)) +#endif + +/** + * Fill *one* DAPS + * @param sector The DAPS to fill + * @param count Sector count + * @param offset Realmode offset in the segment + * @param segment Real mode segment + * @param lba LBA of the first sector to read + * @return 0 on success + */ +static int fill_daps(struct DAPS *sector, unsigned count, unsigned offset, unsigned segment, uint64_t lba) +{ + assert(sector != NULL); + assert(count < 128); + assert(offset < 0x10000); + assert(segment < 0x10000); + + sector->size = sizeof(struct DAPS); + sector->res1 = 0; + sector->count = (int8_t)count; + sector->res2 = 0; + sector->offset = host2target_16(offset); + sector->segment = host2target_16(segment); + sector->lba = host2target_64(lba); + + return 0; +} + +/** + * Mark a DAPS invalid to let the boot loader code stop at this entry. + * @param sector The DAPS to be marked as invalid + * + * Marking as invalid must be done in accordance to the detection method + * the assembler routine in the boot loader uses: + * The current code tests for zero in the first two bytes of the DAPS. + */ +static void invalidate_daps(struct DAPS *sector) +{ + sector->size = MARK_DAPS_INVALID; + sector->res1 = 0; +} + +/** + * Create the indirect sector with the DAPS entries + * @param daps_table Where to store the entries + * @param size Size of the whole image in bytes + * @param pers_sector_count Count of sectors to skip after MBR for the persistant environment storage + * @return 0 on success + * + * This routine calculates the DAPS entries for the case the whole + * barebox images fits into the MBR itself and the sectors after it. + * This means the start of the first partition must keep enough sectors + * unused. + * It also skips 'pers_sector_count' sectors after the MBR for special + * usage if given. + */ +static int barebox_linear_image(struct DAPS *daps_table, off_t size, long pers_sector_count) +{ + unsigned offset = LOAD_AREA, next_offset; + unsigned segment = LOAD_SEGMENT; + unsigned chunk_size, i = 0; + uint64_t lba = 2 + pers_sector_count; + int rc; + + /* + * We can load up to 127 sectors in one chunk. What a bad number... + * So, we will load in chunks of 32 kiB. + */ + + /* at runtime two sectors from the image are already loaded: MBR and indirect */ + size -= 2 * SECTOR_SIZE; + /* and now round up to multiple of sector size */ + size = (size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); + + /* + * The largest image we can load with this method is: + * (SECTOR_SIZE / sizeof(DAPS) - 1) * 32 kiB + * For a 512 byte sector and a 16 byte DAPS: + * (512 / 16 - 1) * 32 kiB = 992 kiB + * Note: '- 1' to consider one entry is required to pad to a 32 kiB boundary + */ + + if (size >= (SECTOR_SIZE / sizeof(struct DAPS) - 1) * 32 * 1024) { + fprintf(stderr, "Image too large to boot. Max size is %zu kiB, image size is %lu kiB\n", + (SECTOR_SIZE / sizeof(struct DAPS) - 1) * 32, size / 1024); + return -1; + } + + if (size > 32 * 1024) { + /* first fill up until the next 32 k boundary */ + next_offset = (offset + 32 * 1024 -1) & ~0x7fff; + chunk_size = next_offset - offset; + if (chunk_size & (SECTOR_SIZE-1)) { + fprintf(stderr, "Unable to pad from %X to %X in multiple of sectors\n", offset, next_offset); + return -1; + } + + rc = fill_daps(&daps_table[i], chunk_size / SECTOR_SIZE, offset, segment, lba); + if (rc != 0) + return -1; + debugout(&daps_table[i], 0); + + /* calculate values to enter the loop for the other entries */ + size -= chunk_size; + i++; + lba += chunk_size / SECTOR_SIZE; + offset += chunk_size; + if (offset >= 0x10000) { + segment += 4096; + offset = 0; + } + + /* + * Now load the remaining image part in 32 kiB chunks + */ + while (size) { + if (size >= 32 * 1024 ) { + if (i >= (SECTOR_SIZE / sizeof(struct DAPS))) { + fprintf(stderr, "Internal tool error: Too many DAPS entries!\n"); + return -1; + } + rc = fill_daps(&daps_table[i], 64, offset, segment, lba); + if (rc != 0) + return -1; + debugout(&daps_table[i], 0); + + size -= 32 * 1024; + lba += 64; + offset += 32 * 1024; + if (offset >= 0x10000) { + segment += 4096; + offset = 0; + } + i++; + } else { + if (i >= (SECTOR_SIZE / sizeof(struct DAPS))) { + fprintf(stderr, "Internal tool error: Too many DAPS entries!\n"); + return -1; + } + rc = fill_daps(&daps_table[i], size / SECTOR_SIZE, offset, segment, lba); + if (rc != 0) + return -1; + debugout(&daps_table[i], 0); + size = 0; /* finished */ + i++; + } + }; + } else { + /* less than 32 kiB. Very small image... */ + rc = fill_daps(&daps_table[i], size / SECTOR_SIZE, offset, segment, lba); + if (rc != 0) + return -1; + debugout(&daps_table[i], 0); + i++; + } + + /* + * Do not mark an entry as invalid if the buffer is full. The + * boot code stops if all entries of a buffer are read. + */ + if (i >= (SECTOR_SIZE / sizeof(struct DAPS))) + return 0; + + /* mark the last DAPS invalid */ + invalidate_daps(&daps_table[i]); + debugout(&daps_table[i], 0); + + return 0; +} + +/** + * Do some simple sanity checks if this sector could be an MBR + * @param sector Sector with data to check + * @param size Size of the buffer + * @return 0 if successfull + */ +static int check_for_valid_mbr(const uint8_t *sector, off_t size) +{ + if (size < SECTOR_SIZE) { + fprintf(stderr, "MBR too small to be valid\n"); + return -1; + } + + if ((sector[OFFSET_OF_SIGNATURE] != 0x55) || + (sector[OFFSET_OF_SIGNATURE + 1] != 0xAA)) { + fprintf(stderr, "No MBR signature found\n"); + return -1; + } + + /* FIXME: try to check if there is a valid partition table */ + return 0; +} + +/** + * Check space between start of the image and the start of the first partition + * @param hd_image HD image to examine + * @param size Size of the barebox image + * @return 0 on success, -1 if the barebox image is too large + */ +static int check_for_space(const void *hd_image, off_t size) +{ + struct partition_entry *partition; + uint8_t *mbr_disk_sector = (uint8_t*)hd_image; + off_t spare_sector_count; + + assert(hd_image != NULL); + assert(size > 0); + + if (check_for_valid_mbr(hd_image, size) != 0) + return -1; + + /* where to read */ + partition = (struct partition_entry*) &mbr_disk_sector[OFFSET_OF_PARTITION_TABLE]; + + /* TODO describes the first entry always the first partition? */ + spare_sector_count = target2host_32(partition->partition_start); + +#ifdef DEBUG + printf("Debug: Required free sectors for barebox prior first partition: %lu, hd image provides: %lu\n", + (size + SECTOR_SIZE - 1) / SECTOR_SIZE, spare_sector_count); +#endif + spare_sector_count *= SECTOR_SIZE; + if (spare_sector_count < size) { + fprintf(stderr, "Not enough space after MBR to store barebox\n"); + fprintf(stderr, "Move begin of the first partition beyond sector %lu\n", (size + SECTOR_SIZE - 1) / SECTOR_SIZE); + return -1; + } + + return 0; +} + +/** + * Setup the persistant environment storage information + * @param patch_area Where to patch + * @param pers_sector_start Start sector of the persistant environment storage + * @param pers_sector_count Count of sectors for the persistant environment storage + * @return 0 on success + */ +static int store_pers_env_info(void *patch_area, uint64_t pers_sector_start, long pers_sector_count) +{ + uint64_t *start_lba = (uint64_t*)(patch_area + PATCH_AREA_PERS_START); + uint16_t *count_lba = (uint16_t*)(patch_area + PATCH_AREA_PERS_SIZE); + + assert(patch_area != NULL); + assert(pers_sector_count >= 0); + + if (pers_sector_count == 0) { + *count_lba = host2target_16(PATCH_AREA_PERS_SIZE_UNUSED); + return 0; + } + + *start_lba = host2target_64(pers_sector_start); + *count_lba = host2target_16(pers_sector_count); + + return 0; +} + +/** + * Prepare the MBR and indirect sector for runtime + * @param fd_barebox barebox image to use + * @param fd_hd Hard disk image to prepare + * @param pers_sector_count Count of sectors to skip after MBR for the persistant environment storage + * @return 0 on success + * + * This routine expects a prepared hard disk image file with a partition table + * in its first sector. This method only is currently supported. + */ +static int barebox_overlay_mbr(int fd_barebox, int fd_hd, long pers_sector_count) +{ + const void *barebox_image; + void *hd_image; + int rc; + struct stat sb; + struct DAPS *embed; /* part of the MBR */ + struct DAPS *indirect; /* sector with indirect DAPS */ + off_t required_size; + + if (fstat(fd_barebox, &sb) == -1) { + perror("fstat"); + return -1; + } + + /* the barebox image won't be touched */ + barebox_image = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd_barebox, 0); + if (barebox_image == MAP_FAILED) { + perror("mmap"); + return -1; + } + + rc = check_for_valid_mbr(barebox_image, sb.st_size); + if (rc != 0) { + fprintf(stderr, "barebox image seems not valid: Bad MBR signature\n"); + goto on_error_hd; + } + + /* + * the persistant environment storage is in front of the main + * barebox image. To handle both, we need more space in front of the + * the first partition. + */ + required_size = sb.st_size + pers_sector_count * SECTOR_SIZE; + + /* the hd image will be modified */ + hd_image = mmap(NULL, required_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd_hd, 0); + if (hd_image == MAP_FAILED) { + perror("mmap"); + rc = -1; + goto on_error_hd; + } + + /* check for space */ + rc = check_for_space(hd_image, required_size); + if (rc != 0) + goto on_error_space; + + /* embed barebox's boot code into the disk drive image */ + memcpy(hd_image, barebox_image, OFFSET_OF_PARTITION_TABLE); + + /* + * embed the barebox main image into the disk drive image, + * but keep the persistant environment storage untouched + * (if defined), e.g. store the main image behind this special area. + */ + memcpy(hd_image + ((pers_sector_count + 1) * SECTOR_SIZE), + barebox_image + SECTOR_SIZE, sb.st_size - SECTOR_SIZE); + + /* now, prepare this hard disk image for BIOS based booting */ + embed = hd_image + PATCH_AREA; + indirect = hd_image + ((pers_sector_count + 1) * SECTOR_SIZE); + + /* + * Fill the embedded DAPS to let the basic boot code find the + * indirect sector at runtime + */ +#ifdef DEBUG + printf("Debug: Fill in embedded DAPS\n"); +#endif + rc = fill_daps(embed, 1, INDIRECT_AREA, INDIRECT_SEGMENT, + 1 + pers_sector_count); + if (rc != 0) + goto on_error_space; + debugout(embed, 1); + +#ifdef DEBUG + printf("Debug: Fill in indirect sector\n"); +#endif + /* + * fill the indirect sector with the remaining DAPS to load the + * whole barebox image at runtime + */ + rc = barebox_linear_image(indirect, sb.st_size, pers_sector_count); + if (rc != 0) + goto on_error_space; + + /* + * TODO: Replace the fixed LBA starting number by a calculated one, + * to support barebox as a chained loader in a different start + * sector than the MBR + */ + rc = store_pers_env_info(embed, 1, pers_sector_count); + if (rc != 0) + goto on_error_space; + +on_error_space: + munmap(hd_image, required_size); + +on_error_hd: + munmap((void*)barebox_image, sb.st_size); + + return rc; +} + +static void print_usage(const char *pname) +{ + printf("%s: Preparing a hard disk image for boot with barebox on x86.\n", pname); + printf("Usage is\n %s [options] -m -d \n", pname); + printf(" [options] are:\n -s sector count of the persistant environment storage\n"); + printf(" barebox's boot image file\n"); + printf(" HD image to store the barebox image\n"); + printf(" If no '-s ' was given, barebox occupies sectors 0 to n, else sector 0 and x+1 to n\n"); +} + +int main(int argc, char *argv[]) +{ + int rc = 0, c; + char *barebox_image_filename = NULL, *hd_image_filename = NULL; + int fd_barebox_image = 0, fd_hd_image = 0; + long barebox_pers_size = -1; + + if (argc == 1) { + print_usage(argv[0]); + exit(0); + } + + /* handle command line options first */ + while (1) { + c = getopt(argc, argv, "m:d:s:hv"); + if (c == -1) + break; + + switch (c) { + case 's': + barebox_pers_size = strtol(optarg, NULL, 0); + break; + case 'm': + barebox_image_filename = strdup(optarg); + break; + case 'd': + hd_image_filename = strdup(optarg); + break; + case 'h': + print_usage(argv[0]); + rc = 0; + goto on_error; + case 'v': + printf("setupmbr for u-boot-v%s\n", UTS_RELEASE); + printf("Send bug reports to 'barebox@lists.infradead.org'\n"); + rc = 0; + goto on_error; + } + } + + if (barebox_image_filename == NULL) { + print_usage(argv[0]); + rc = -1; + goto on_error; + } + + fd_barebox_image = open(barebox_image_filename, O_RDONLY); + if (fd_barebox_image == -1) { + fprintf(stderr, "Cannot open '%s' for reading\n", + barebox_image_filename); + rc = -1; + goto on_error; + } + + fd_hd_image = open(hd_image_filename, O_RDWR); + if (fd_hd_image == -1) { + fprintf(stderr, "Cannot open '%s'\n", hd_image_filename); + rc = -1; + goto on_error; + } + + if (barebox_pers_size < 0) + barebox_pers_size = 0; + + rc = barebox_overlay_mbr(fd_barebox_image, fd_hd_image, barebox_pers_size); + +on_error: + if (fd_barebox_image != -1) + close(fd_barebox_image); + if (fd_hd_image != -1) + close(fd_hd_image); + + if (barebox_image_filename != NULL) + free(barebox_image_filename); + if (hd_image_filename != NULL) + free(hd_image_filename); + + return rc; +} + +/** @page x86_bootloader barebox acting as PC bootloader + +@section x86_bootloader_features Features + +@a barebox can act as a bootloader for PC based systems. In this case a special +binary layout will be created to be able to store it on some media the PC +BIOS can boot from. It can boot Linux kernels stored also on the same boot +media and be configured at runtime, with the possibility to store the changed +configuration on the boot media. + +@section x86_bootloader_restrictions Restrictions + +Due to some BIOS and @a barebox restrictions the boot media must be +prepared in some special way: + +@li @a barebox must be stored in the MBR (Master Boot Record) of the boot media. + Currently its not possible to store and boot it in one of the partition + sectors (to use it as a second stage loader). This is no eternal + restriction. It only needs further effort to add this feature. +@li @a barebox currently cannot run a chained boot loader. Also, this is no + eternal restriction, only further effort needed. +@li @a barebox comes with limited filesystem support. There is currently no + support for the most common and popular filesystems used in the *NIX world. + This restricts locations where to store a kernel and other runtime + information +@li @a barebox must be stored to the first n sectors of the boot media. To ensure + this does not collide with partitions on the boot media, the first + partition must start at a sector behind the ones @a barebox occupies. +@li @a barebox handles its runtime configuration in a special way: It stores it + in a binary way into some reserved sectors ("persistant storage"). + +@section x86_bootloader_preparations Boot Preparations + +To store the @a barebox image to a boot media, it comes with the tool +@p setupmbr in the directory @p scripts/setupmbr/ . To be able to use it on +the boot media of your choice, some preparations are required: + +@subsection x86_bootloader_preparations_partition Keep Sectors free + +Build the @a barebox image and check its size. At least this amount of +sectors must be kept free after the MBR prior the first partition. Do this +simple calulation: + + sectors = (\ + 511) / 512 + +To be able to store the runtime configuration, further free sectors are +required. Its up to you and your requirements, how large this persistant +storage must be. If you need 16 kiB for this purpose, you need to keep +additional 32 sectors free. + +For this example we are reserving 300 sectors for the @a barebox image and +additionaly 32 sectors for the persistant storage. So, the first partition on +the boot media must start at sector 333 or later. + +Run the @p fdisk tool to setup such a partition table: + +@verbatim +[jb@host]~> fdisk /dev/sda +Command (m for help): p + +Disk /dev/sda: 20.7 MB, 212680704 bytes +16 heads, 63 sectors/track, 406 cylinders +Units = cylinders of 1008 * 512 = 516096 bytes + + Device Boot Start End Blocks Id System +@endverbatim + +Change the used units to @p sectors for easier handling. + +@verbatim +Command (m for help): u +Changing display/entry units to sectors + +Command (m for help): p + +Disk /dev/sda: 20.7 MB, 212680704 bytes +16 heads, 63 sectors/track, 406 cylinders, total 409248 sectors +Units = sectors of 1 * 512 = 512 bytes + + Device Boot Start End Blocks Id System +@endverbatim + +Now its possible to create the first partition with the required offset: + +@verbatim +Command (m for help): n +Command action + e extended + p primary partition (1-4) +p +Partition number (1-4): 1 +First sector (63-409247, default 63): 333 +Last sector or +size or +sizeM or +sizeK (333-409247, default 409247): +18M +Command (m for help): p + +Disk /dev/sda: 20.7 MB, 212680704 bytes +16 heads, 63 sectors/track, 406 cylinders, total 409248 sectors +Units = sectors of 1 * 512 = 512 bytes + + Device Boot Start End Blocks Id System +/dev/sda 333 35489 17578+ 83 Linux +@endverbatim + +That's all. Do whatever is required now with the new partition (formatting +and populating the root filesystem for example) to make it useful. + +In the next step, @a barebox gets installed to this boot media: + +@verbatim +[jb@host]~> scripts/setupmbr/setupmbr -s 32 -m ./barebox -d /dev/sda +@endverbatim + +This command writes the @a barebox image file './barebox' onto the device +@p /dev/sda. + +The @p -s option will keep the persistant storage sectors free and untouched +and set flags in the MBR to forward its existance, size and location to +@a barebox at runtime. @p setupmbr also does not change the partition table. + +The @a barebox image gets stored on the boot media like this: + +@verbatim +sector 0 1 33 333 + |---|-------------|--------------- ~~~ ------------|-------------- + MBR persistant barebox first + storage main image partition +@endverbatim + +If the @p -s option is omitted, the "persistant storage" part simply does +not exist: + +@verbatim +sector 0 1 333 + |---|--------------- ~~~ ------------|-------------- + MBR barebox first + main image partition +@endverbatim + +@note The @p setupmbr tool is also working on real image file than on device + nodes only. So, there is no restriction what kind of file will be + modified. +*/ Index: barebox-2009.12.0/Doxyfile =================================================================== --- barebox-2009.12.0.orig/Doxyfile +++ barebox-2009.12.0/Doxyfile @@ -484,7 +484,8 @@ INPUT = Documentation \ commands \ common \ board \ - lib + lib \ + scripts/setupmbr # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default --