summaryrefslogtreecommitdiffstats
path: root/scripts/setupmbr/setupmbr.c
blob: 01e8c645f02348614b84fcec5685cb2328dab843 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>

/* 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 <barebox image> -d <hd image>\n", pname);
	printf(" [options] are:\n -s <count> sector count of the persistant environment storage\n");
	printf(" <barebox image> barebox's boot image file\n");
	printf(" <hd image> HD image to store the barebox image\n");
	printf(" If no '-s <x>' 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 = (\<size of barebox image\> + 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.
*/