OpenWrt 中sdcard.img 制作过程
sdcard.img 的文件组成
分区表
u-boot
boot.img
rootfs.img
制作脚本分析
openwrt/target/linux/sunxi/image/gen_sunxi_sdcard_img.sh
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 | #!/usr/bin/env bash # # Copyright (C) 2013 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # set -ex [ $ # -eq 6 ] || { echo "SYNTAX: $0 <file> <bootfs image> <rootfs image> <bootfs size> <rootfs size> <u-boot image>" exit 1 } OUTPUT= "$1" BOOTFS= "$2" ROOTFS= "$3" BOOTFSSIZE= "$4" ROOTFSSIZE= "$5" UBOOT= "$6" head =4 sect=63 # 1.这里写分区表 set `ptgen -o $OUTPUT -h $ head -s $sect -l 1024 -t c -p ${BOOTFSSIZE}M -t 83 -p ${ROOTFSSIZE}M` BOOTOFFSET= "$(($1 / 512))" BOOTSIZE= "$(($2 / 512))" ROOTFSOFFSET= "$(($3 / 512))" ROOTFSSIZE= "$(($4 / 512))" # 2.接下来写 u-boot + boot.img + rootfs.mg dd bs=1024 if = "$UBOOT" of= "$OUTPUT" seek=8 conv=notrunc dd bs=512 if = "$BOOTFS" of= "$OUTPUT" seek= "$BOOTOFFSET" conv=notrunc dd bs=512 if = "$ROOTFS" of= "$OUTPUT" seek= "$ROOTFSOFFSET" conv=notrunc |
重要的工具:ptgen
ptgen 用于生成分区表,分区表占用 512 字节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Usage: . /ptgen [- v ] -h <heads> -s <sectors> -o <outputfile> [-a 0..4] [-l <align kB>] [[-t < type >] -p <size>...] lql@debian:~ /work/openwrt/staging_dir/host/bin $ . /ptgen -o /tmp/test .img -h 4 -s 63 -l 1024 -t c -p 5M -t 83 -p 32M 1048576 5242880 7340032 33554432 lql@debian:~ /work/openwrt/staging_dir/host/bin $ ls -lh /tmp/test .img -rw-r--r-- 1 lql lql 512 May 19 15:11 /tmp/test .img lql@debian:~ /work/openwrt/staging_dir/host/bin $ ls -lh /tmp/test .img -rw-r--r-- 1 lql lql 512 May 19 15:11 /tmp/test .img lql@debian:~ /work/openwrt/staging_dir/host/bin $ lql@debian:~ /work/openwrt/staging_dir/host/bin $ hexdump -C /tmp/test .img 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 000001b0 00 00 00 00 00 00 00 00 4f 57 52 54 00 00 80 00 |........OWRT....| 000001c0 21 08 0c 03 03 30 00 08 00 00 00 28 00 00 00 03 |!....0.....(....| 000001d0 24 38 83 03 73 3c 00 38 00 00 00 00 01 00 00 00 |$8..s<.8........| 000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| 00000200 |
上面 ls -lh /tmp/test.img 可以看出分区表大小是 512 字节。
ptgen 最多生成4个分区
已知的问题:ptgen 生成的分区中间会有1M的空隙,不知道是有意为之还是 bug ?
1 2 3 4 5 6 7 8 9 | +-------+ | | +-------+ 1M | | boot.img(5M) +-------+ 6M | | <-------- 1M 的空隙 +-------+ 7M | | rootfs.img(32M) +-------+ |
源码:位于 openwrt/tools/firmware-utils/src/ptgen.c
代码摘要:
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 | /* Partition table entry */ struct pte { uint8_t active; uint8_t chs_start[3]; uint8_t type; uint8_t chs_end[3]; uint32_t start; uint32_t length; }; static int gen_ptable(uint32_t signature, int nr) { struct pte pte[4]; unsigned long sect = 0; int i, fd, ret = -1, start, len; memset (pte, 0, sizeof ( struct pte) * 4); for (i = 0; i < nr; i++) { if (!parts[i].size) { fprintf (stderr, "Invalid size in partition %d!\n" , i); return -1; } pte[i].active = ((i + 1) == active) ? 0x80 : 0; pte[i].type = parts[i].type; start = sect + sectors; if (kb_align != 0) start = round_to_kb(start); pte[i].start = cpu_to_le32(start); sect = start + parts[i].size * 2; if (kb_align == 0) sect = round_to_cyl(sect); pte[i].length = cpu_to_le32(len = sect - start); to_chs(start, pte[i].chs_start); to_chs(start + len - 1, pte[i].chs_end); if (verbose) fprintf (stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n" , i, ( long )start * 512, (( long )start + ( long )len) * 512, ( long )len * 512); printf ( "%ld\n" , ( long )start * 512); printf ( "%ld\n" , ( long )len * 512); } if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { fprintf (stderr, "Can't open output file '%s'\n" ,filename); return -1; } lseek(fd, 440, SEEK_SET); if (write(fd, &signature, sizeof (signature)) != sizeof (signature)) { fprintf (stderr, "write failed.\n" ); goto fail; } lseek(fd, 446, SEEK_SET); if (write(fd, pte, sizeof ( struct pte) * 4) != sizeof ( struct pte) * 4) { fprintf (stderr, "write failed.\n" ); goto fail; } lseek(fd, 446, SEEK_SET); if (write(fd, pte, sizeof ( struct pte) * 4) != sizeof ( struct pte) * 4) { fprintf (stderr, "write failed.\n" ); goto fail; } lseek(fd, 510, SEEK_SET); if (write(fd, "\x55\xaa" , 2) != 2) { fprintf (stderr, "write failed.\n" ); goto fail; } ret = 0; fail: close(fd); return ret; } |
本站的文章和资源来自互联网或者站长的原创,按照 CC BY -NC -SA 3.0 CN协议发布和共享,转载或引用本站文章应遵循相同协议。如果有侵犯版权的资 源请尽快联系站长,我们会在24h内删除有争议的资源。欢迎大家多多交流,期待共同学习进步。