diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp index 23443eca9..feacaa14c 100644 --- a/fastboot/bootimg_utils.cpp +++ b/fastboot/bootimg_utils.cpp @@ -34,16 +34,15 @@ #include #include -void bootimg_set_cmdline(boot_img_hdr_v1* h, const char* cmdline) { - if (strlen(cmdline) >= sizeof(h->cmdline)) die("command line too large: %zu", strlen(cmdline)); - strcpy(reinterpret_cast(h->cmdline), cmdline); +void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline) { + if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size()); + strcpy(reinterpret_cast(h->cmdline), cmdline.c_str()); } -boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset, void* ramdisk, - int64_t ramdisk_size, off_t ramdisk_offset, void* second, - int64_t second_size, off_t second_offset, size_t page_size, size_t base, - off_t tags_offset, uint32_t header_version, int64_t* bootimg_size) { - size_t page_mask = page_size - 1; +boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, void* ramdisk, int64_t ramdisk_size, + void* second, int64_t second_size, size_t base, + const boot_img_hdr_v1& src, int64_t* bootimg_size) { + const size_t page_mask = src.page_size - 1; int64_t header_actual = sizeof(boot_img_hdr_v1) & (~page_mask); int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask); @@ -53,30 +52,26 @@ boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offse *bootimg_size = header_actual + kernel_actual + ramdisk_actual + second_actual; boot_img_hdr_v1* hdr = reinterpret_cast(calloc(*bootimg_size, 1)); - if (hdr == nullptr) { - return hdr; - } + if (hdr == nullptr) die("couldn't allocate boot image: %" PRId64 " bytes", *bootimg_size); + *hdr = src; memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); hdr->kernel_size = kernel_size; hdr->ramdisk_size = ramdisk_size; hdr->second_size = second_size; - hdr->kernel_addr = base + kernel_offset; - hdr->ramdisk_addr = base + ramdisk_offset; - hdr->second_addr = base + second_offset; - hdr->tags_addr = base + tags_offset; + hdr->kernel_addr += base; + hdr->ramdisk_addr += base; + hdr->second_addr += base; + hdr->tags_addr += base; - hdr->page_size = page_size; - - if (header_version) { - hdr->header_version = header_version; + if (hdr->header_version != 0) { hdr->header_size = sizeof(boot_img_hdr_v1); } - memcpy(hdr->magic + page_size, kernel, kernel_size); - memcpy(hdr->magic + page_size + kernel_actual, ramdisk, ramdisk_size); - memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual, second, second_size); + memcpy(hdr->magic + hdr->page_size, kernel, kernel_size); + memcpy(hdr->magic + hdr->page_size + kernel_actual, ramdisk, ramdisk_size); + memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual, second, second_size); return hdr; } diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h index d3993f5c8..fe805b007 100644 --- a/fastboot/bootimg_utils.h +++ b/fastboot/bootimg_utils.h @@ -26,17 +26,15 @@ * SUCH DAMAGE. */ -#ifndef _FASTBOOT_BOOTIMG_UTILS_H_ -#define _FASTBOOT_BOOTIMG_UTILS_H_ +#pragma once #include #include #include -void bootimg_set_cmdline(boot_img_hdr_v1* h, const char* cmdline); -boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset, void* ramdisk, - int64_t ramdisk_size, off_t ramdisk_offset, void* second, - int64_t second_size, off_t second_offset, size_t page_size, size_t base, - off_t tags_offset, uint32_t header_version, int64_t* bootimg_size); +#include -#endif +boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, void* ramdisk, int64_t ramdisk_size, + void* second, int64_t second_size, size_t base, + const boot_img_hdr_v1& src, int64_t* bootimg_size); +void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline); diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 4f0b5eb4c..cf130c9a4 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -76,9 +76,9 @@ using android::base::unique_fd; char cur_product[FB_RESPONSE_SZ + 1]; static const char* serial = nullptr; -static const char* cmdline = nullptr; + static unsigned short vendor_id = 0; -static int long_listing = 0; +static bool g_long_listing = false; // Don't resparse files in too-big chunks. // libsparse will support INT_MAX, but this results in large allocations, so // let's keep it at 1GB to avoid memory pressure on the host. @@ -86,12 +86,9 @@ static constexpr int64_t RESPARSE_LIMIT = 1 * 1024 * 1024 * 1024; static int64_t sparse_limit = -1; static int64_t target_sparse_limit = -1; -static unsigned page_size = 2048; -static unsigned base_addr = 0x10000000; -static unsigned kernel_offset = 0x00008000; -static unsigned ramdisk_offset = 0x01000000; -static unsigned second_offset = 0x00f00000; -static unsigned tags_offset = 0x00000100; +static unsigned g_base_addr = 0x10000000; +static boot_img_hdr_v1 g_boot_img_hdr = {}; +static std::string g_cmdline; static bool g_disable_verity = false; static bool g_disable_verification = false; @@ -223,7 +220,7 @@ static int list_devices_callback(usb_ifc_info* info) { serial = "????????????"; } // output compatible with "adb devices" - if (!long_listing) { + if (!g_long_listing) { printf("%s\tfastboot", serial.c_str()); } else { printf("%-22s fastboot", serial.c_str()); @@ -360,14 +357,18 @@ static int show_help() { " Download and boot kernel from RAM.\n" " flash:raw PARTITION KERNEL [RAMDISK [SECOND]]\n" " Create boot image and flash it.\n" - // TODO: give -c a long option, and remove the short options for this group? - " -c CMDLINE Override kernel command line.\n" + " --cmdline CMDLINE Override kernel command line.\n" " --base ADDRESS Set kernel base address (default: 0x10000000).\n" " --kernel-offset Set kernel offset (default: 0x00008000).\n" " --ramdisk-offset Set ramdisk offset (default: 0x01000000).\n" " --tags-offset Set tags offset (default: 0x00000100).\n" " --page-size BYTES Set flash page size (default: 2048).\n" " --header-version VERSION Set boot image header version.\n" + " --os-version MAJOR[.MINOR[.PATCH]]\n" + " Set boot image OS version (default: 0.0.0).\n" + " --os-patch-level YYYY-MM-DD\n" + " Set boot image OS security patch level.\n" + // TODO: still missing: `second_addr`, `name`, `id`, `recovery_dtbo_*`. "\n" // TODO: what device(s) used this? is there any documentation? //" continue Continue with autoboot.\n" @@ -404,8 +405,7 @@ static int show_help() { } static void* load_bootable_image(const std::string& kernel, const std::string& ramdisk, - const std::string& second_stage, int64_t* sz, - const char* cmdline, uint32_t header_version) { + const std::string& second_stage, int64_t* sz) { int64_t ksize; void* kdata = load_file(kernel.c_str(), &ksize); if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno)); @@ -415,12 +415,14 @@ static void* load_bootable_image(const std::string& kernel, const std::string& r die("cannot load '%s': too short", kernel.c_str()); } if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { - if (cmdline) bootimg_set_cmdline(reinterpret_cast(kdata), cmdline); + if (!g_cmdline.empty()) { + bootimg_set_cmdline(reinterpret_cast(kdata), g_cmdline); + } uint32_t header_version_existing = reinterpret_cast(kdata)->header_version; - if (header_version != header_version_existing) { + if (g_boot_img_hdr.header_version != header_version_existing) { die("header version mismatch, expected: %" PRIu32 " found %" PRIu32 "", - header_version, header_version_existing); + g_boot_img_hdr.header_version, header_version_existing); } if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk"); @@ -444,16 +446,12 @@ static void* load_bootable_image(const std::string& kernel, const std::string& r } fprintf(stderr,"creating boot image...\n"); - int64_t bsize = 0; - boot_img_hdr_v1* bdata = mkbootimg(kdata, ksize, kernel_offset, - rdata, rsize, ramdisk_offset, - sdata, ssize, second_offset, - page_size, base_addr, tags_offset, header_version, &bsize); + boot_img_hdr_v1* bdata = mkbootimg(kdata, ksize, rdata, rsize, sdata, ssize, + g_base_addr, g_boot_img_hdr, sz); if (bdata == nullptr) die("failed to create boot.img"); - if (cmdline) bootimg_set_cmdline(bdata, cmdline); - fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize); - *sz = bsize; + if (!g_cmdline.empty()) bootimg_set_cmdline(bdata, g_cmdline); + fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", *sz); return bdata; } @@ -1422,34 +1420,37 @@ int main(int argc, char **argv) bool skip_secondary = false; bool set_fbe_marker = false; void *data; - uint32_t header_version = 0; int64_t sz; int longindex; std::string slot_override; std::string next_active; + g_boot_img_hdr.kernel_addr = 0x00008000; + g_boot_img_hdr.ramdisk_addr = 0x01000000; + g_boot_img_hdr.second_addr = 0x00f00000; + g_boot_img_hdr.tags_addr = 0x00000100; + g_boot_img_hdr.page_size = 2048; + const struct option longopts[] = { - {"base", required_argument, 0, 'b'}, - {"kernel_offset", required_argument, 0, 'k'}, - {"kernel-offset", required_argument, 0, 'k'}, - {"page_size", required_argument, 0, 'n'}, - {"page-size", required_argument, 0, 'n'}, - {"ramdisk_offset", required_argument, 0, 'r'}, - {"ramdisk-offset", required_argument, 0, 'r'}, - {"tags_offset", required_argument, 0, 't'}, - {"tags-offset", required_argument, 0, 't'}, + {"base", required_argument, 0, 0}, + {"cmdline", required_argument, 0, 0}, + {"disable-verification", no_argument, 0, 0}, + {"disable-verity", no_argument, 0, 0}, + {"header-version", required_argument, 0, 0}, {"help", no_argument, 0, 'h'}, - {"unbuffered", no_argument, 0, 0}, - {"slot", required_argument, 0, 0}, - {"set_active", optional_argument, 0, 'a'}, + {"kernel-offset", required_argument, 0, 0}, + {"os-patch-level", required_argument, 0, 0}, + {"os-version", required_argument, 0, 0}, + {"page-size", required_argument, 0, 0}, + {"ramdisk-offset", required_argument, 0, 0}, {"set-active", optional_argument, 0, 'a'}, - {"skip-secondary", no_argument, 0, 0}, {"skip-reboot", no_argument, 0, 0}, + {"skip-secondary", no_argument, 0, 0}, + {"slot", required_argument, 0, 0}, + {"tags-offset", required_argument, 0, 0}, + {"unbuffered", no_argument, 0, 0}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 0}, - {"disable-verity", no_argument, 0, 0}, - {"disable-verification", no_argument, 0, 0}, - {"header-version", required_argument, 0, 0}, #if !defined(_WIN32) {"wipe-and-use-fbe", no_argument, 0, 0}, #endif @@ -1458,98 +1459,108 @@ int main(int argc, char **argv) serial = getenv("ANDROID_SERIAL"); - while (1) { - int c = getopt_long(argc, argv, "vwb:k:n:r:t:s:S:lc:i:m:ha::", longopts, &longindex); - if (c < 0) { - break; - } - /* Alphabetical cases */ - switch (c) { - case 'a': - wants_set_active = true; - if (optarg) - next_active = optarg; - break; - case 'b': - base_addr = strtoul(optarg, 0, 16); - break; - case 'c': - cmdline = optarg; - break; - case 'h': - return show_help(); - case 'i': { - char *endptr = nullptr; - unsigned long val; - - val = strtoul(optarg, &endptr, 0); - if (!endptr || *endptr != '\0' || (val & ~0xffff)) - die("invalid vendor id '%s'", optarg); - vendor_id = (unsigned short)val; - break; - } - case 'k': - kernel_offset = strtoul(optarg, 0, 16); - break; - case 'l': - long_listing = 1; - break; - case 'n': - page_size = (unsigned)strtoul(optarg, nullptr, 0); - if (!page_size) die("invalid page size"); - break; - case 'r': - ramdisk_offset = strtoul(optarg, 0, 16); - break; - case 't': - tags_offset = strtoul(optarg, 0, 16); - break; - case 's': - serial = optarg; - break; - case 'S': - sparse_limit = parse_num(optarg); - if (sparse_limit < 0) die("invalid sparse limit"); - break; - case 'v': - set_verbose(); - break; - case 'w': - wants_wipe = true; - break; - case '?': - return 1; - case 0: - if (strcmp("unbuffered", longopts[longindex].name) == 0) { + int c; + while ((c = getopt_long(argc, argv, "a::hi:ls:S:vw", longopts, &longindex)) != -1) { + if (c == 0) { + std::string name{longopts[longindex].name}; + if (name == "base") { + g_base_addr = strtoul(optarg, 0, 16); + } else if (name == "cmdline") { + g_cmdline = optarg; + } else if (name == "disable-verification") { + g_disable_verification = true; + } else if (name == "disable-verity") { + g_disable_verity = true; + } else if (name == "header-version") { + g_boot_img_hdr.header_version = strtoul(optarg, nullptr, 0); + } else if (name == "kernel-offset") { + g_boot_img_hdr.kernel_addr = strtoul(optarg, 0, 16); + } else if (name == "os-patch-level") { + unsigned year, month, day; + if (sscanf(optarg, "%u-%u-%u", &year, &month, &day) != 3) { + syntax_error("OS patch level should be YYYY-MM-DD: %s", optarg); + } + if (year < 2000 || year >= 2128) syntax_error("year out of range: %d", year); + if (month < 1 || month > 12) syntax_error("month out of range: %d", month); + g_boot_img_hdr.SetOsPatchLevel(year, month); + } else if (name == "os-version") { + unsigned major = 0, minor = 0, patch = 0; + std::vector versions = android::base::Split(optarg, "."); + if (versions.size() < 1 || versions.size() > 3 || + (versions.size() >= 1 && !android::base::ParseUint(versions[0], &major)) || + (versions.size() >= 2 && !android::base::ParseUint(versions[1], &minor)) || + (versions.size() == 3 && !android::base::ParseUint(versions[2], &patch)) || + (major > 0x7f || minor > 0x7f || patch > 0x7f)) { + syntax_error("bad OS version: %s", optarg); + } + g_boot_img_hdr.SetOsVersion(major, minor, patch); + } else if (name == "page-size") { + g_boot_img_hdr.page_size = strtoul(optarg, nullptr, 0); + if (g_boot_img_hdr.page_size == 0) die("invalid page size"); + } else if (name == "ramdisk-offset") { + g_boot_img_hdr.ramdisk_addr = strtoul(optarg, 0, 16); + } else if (name == "skip-reboot") { + skip_reboot = true; + } else if (name == "skip-secondary") { + skip_secondary = true; + } else if (name == "slot") { + slot_override = optarg; + } else if (name == "tags-offset") { + g_boot_img_hdr.tags_addr = strtoul(optarg, 0, 16); + } else if (name == "unbuffered") { setvbuf(stdout, nullptr, _IONBF, 0); setvbuf(stderr, nullptr, _IONBF, 0); - } else if (strcmp("version", longopts[longindex].name) == 0) { + } else if (name == "version") { fprintf(stdout, "fastboot version %s\n", FASTBOOT_VERSION); fprintf(stdout, "Installed as %s\n", android::base::GetExecutablePath().c_str()); return 0; - } else if (strcmp("slot", longopts[longindex].name) == 0) { - slot_override = std::string(optarg); - } else if (strcmp("skip-secondary", longopts[longindex].name) == 0 ) { - skip_secondary = true; - } else if (strcmp("skip-reboot", longopts[longindex].name) == 0 ) { - skip_reboot = true; - } else if (strcmp("disable-verity", longopts[longindex].name) == 0 ) { - g_disable_verity = true; - } else if (strcmp("disable-verification", longopts[longindex].name) == 0 ) { - g_disable_verification = true; #if !defined(_WIN32) - } else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) { + } else if (name == "wipe-and-use-fbe") { wants_wipe = true; set_fbe_marker = true; #endif - } else if (strcmp("header-version", longopts[longindex].name) == 0) { - header_version = strtoul(optarg, nullptr, 0); } else { die("unknown option %s", longopts[longindex].name); } - break; - default: - abort(); + } else { + switch (c) { + case 'a': + wants_set_active = true; + if (optarg) next_active = optarg; + break; + case 'h': + return show_help(); + case 'i': + { + char *endptr = nullptr; + unsigned long val = strtoul(optarg, &endptr, 0); + if (!endptr || *endptr != '\0' || (val & ~0xffff)) { + die("invalid vendor id '%s'", optarg); + } + vendor_id = (unsigned short)val; + break; + } + case 'l': + g_long_listing = true; + break; + case 's': + serial = optarg; + break; + case 'S': + sparse_limit = parse_num(optarg); + if (sparse_limit < 0) die("invalid sparse limit"); + break; + case 'v': + set_verbose(); + break; + case 'w': + wants_wipe = true; + break; + case '?': + return 1; + default: + abort(); + } } } @@ -1668,7 +1679,7 @@ int main(int argc, char **argv) std::string second_stage; if (!args.empty()) second_stage = next_arg(&args); - data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline, header_version); + data = load_bootable_image(kernel, ramdisk, second_stage, &sz); fb_queue_download("boot.img", data, sz); fb_queue_command("boot", "booting"); } else if (command == "flash") { @@ -1694,7 +1705,7 @@ int main(int argc, char **argv) std::string second_stage; if (!args.empty()) second_stage = next_arg(&args); - data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline, header_version); + data = load_bootable_image(kernel, ramdisk, second_stage, &sz); auto flashraw = [&](const std::string& partition) { fb_queue_flash(partition, data, sz); }; diff --git a/mkbootimg/include/bootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h index 4311b46f9..406e20832 100644 --- a/mkbootimg/include/bootimg/bootimg.h +++ b/mkbootimg/include/bootimg/bootimg.h @@ -1,37 +1,33 @@ -/* tools/mkbootimg/bootimg.h -** -** Copyright 2007, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once #include -#ifndef _BOOT_IMAGE_H_ -#define _BOOT_IMAGE_H_ - #define BOOT_MAGIC "ANDROID!" #define BOOT_MAGIC_SIZE 8 #define BOOT_NAME_SIZE 16 #define BOOT_ARGS_SIZE 512 #define BOOT_EXTRA_ARGS_SIZE 1024 -#define BOOT_HEADER_VERSION_ZERO 0 -/* - * Bootloader expects the structure of boot_img_hdr with header version - * BOOT_HEADER_VERSION_ZERO to be as follows: - */ +// The bootloader expects the structure of boot_img_hdr with header +// version 0 to be as follows: struct boot_img_hdr_v0 { + // Must be BOOT_MAGIC. uint8_t magic[BOOT_MAGIC_SIZE]; uint32_t kernel_size; /* size in bytes */ @@ -45,26 +41,36 @@ struct boot_img_hdr_v0 { uint32_t tags_addr; /* physical addr for kernel tags */ uint32_t page_size; /* flash page size we assume */ - /* - * version for the boot image header. - */ + + // Version of the boot image header. uint32_t header_version; - /* operating system version and security patch level; for - * version "A.B.C" and patch level "Y-M-D": - * ver = A << 14 | B << 7 | C (7 bits for each of A, B, C) - * lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M) - * os_version = ver << 11 | lvl */ + // Operating system version and security patch level. + // For version "A.B.C" and patch level "Y-M-D": + // (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M) + // os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0] uint32_t os_version; +#if __cplusplus + void SetOsVersion(unsigned major, unsigned minor, unsigned patch) { + os_version &= ((1 << 11) - 1); + os_version |= (((major & 0x7f) << 25) | ((minor & 0x7f) << 18) | ((patch & 0x7f) << 11)); + } + + void SetOsPatchLevel(unsigned year, unsigned month) { + os_version &= ~((1 << 11) - 1); + os_version |= (((year - 2000) & 0x7f) << 4) | ((month & 0xf) << 0); + } +#endif + uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */ uint8_t cmdline[BOOT_ARGS_SIZE]; uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ - /* Supplemental command line data; kept here to maintain - * binary compatibility with older versions of mkbootimg */ + // Supplemental command line data; kept here to maintain + // binary compatibility with older versions of mkbootimg. uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE]; } __attribute__((packed)); @@ -74,7 +80,7 @@ struct boot_img_hdr_v0 { */ typedef struct boot_img_hdr_v0 boot_img_hdr; -/* When a boot header is of version BOOT_HEADER_VERSION_ZERO, the structure of boot image is as +/* When a boot header is of version 0, the structure of boot image is as * follows: * * +-----------------+ @@ -103,15 +109,13 @@ typedef struct boot_img_hdr_v0 boot_img_hdr; * else: jump to kernel_addr */ -#define BOOT_HEADER_VERSION_ONE 1 - struct boot_img_hdr_v1 : public boot_img_hdr_v0 { uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO image */ uint64_t recovery_dtbo_offset; /* physical load addr */ uint32_t header_size; } __attribute__((packed)); -/* When the boot image header has a version of BOOT_HEADER_VERSION_ONE, the structure of the boot +/* When the boot image header has a version of 1, the structure of the boot * image is as follows: * * +-----------------+ @@ -142,23 +146,3 @@ struct boot_img_hdr_v1 : public boot_img_hdr_v0 { * 7. if second_size != 0: jump to second_addr * else: jump to kernel_addr */ - -#if 0 -typedef struct ptentry ptentry; - -struct ptentry { - char name[16]; /* asciiz partition name */ - unsigned start; /* starting block number */ - unsigned length; /* length in blocks */ - unsigned flags; /* set to zero */ -}; - -/* MSM Partition Table ATAG -** -** length: 2 + 7 * n -** atag: 0x4d534d70 -** x n -*/ -#endif - -#endif