平臺 | 內核版本 |
---|---|
RK1108 | Linux3.1 |
實踐
查看當前設備分區表
命令cat /proc/partitions
kernel
爲例,其大小爲8192
KB/1024
= 8
MB 。
那麼上面這個大小是哪裏設置,看下面。
修改配置文件
目錄:build/setting.ini
文件中關鍵的解釋如下:
意義 | |
---|---|
name |
分區名 |
Type |
類型:0x1:Vendor, 0x2:IDBlock, 0x4:Kernel, 0x8:boot, 0x80000000:data |
Partoffset |
偏移地址 |
PartSize |
分區大小 |
Flag |
1:skip flag, 2:reserved flag, 4:no partition size flag |
File |
文件目錄 |
其中Flag
詳細解釋爲:
a.written partition file and fill up to partition size
Flag=
File=partition file
b.partition be filled up to partition size
Flag=0x2
File=/*do not set*/
c.skip,none of data be written to partition
Flag=0x1
File=/*do not set*/
d.last partition,partition size be set at runtime,alloc all of remain flash to it
Flag=0x4
File=/*set file as required*/
setting.ini
詳細內容如下:
#Flag 1:skip flag, 2:reserved flag, 4:no partition size flag
#type 0x1:Vendor, 0x2:IDBlock, 0x4:Kernel, 0x8:boot, 0x80000000:data
#PartSize and PartOffset unit by sector
#Gpt_Enable 1:compact gpt, 0:normal gpt
#Backup_Partition_Enable 0:no backup,1:backup
#FILL_BYTE's value is used to fill blank
[System]
FwVersion=15.48.1
Gpt_Enable=
Backup_Partition_Enable=0
Nano=
[UserPart1]
Name=IDBlock
Type=0x2
PartOffset=0x40
PartSize=0x380
Flag=0x0
File=../rockimg/Image-cvr/rv1108ddr.bin,../rockimg/Image-cvr/rv1108loader.bin
[UserPart2]
Name=kernel
Type=0x4
PartOffset=0x400
PartSize=0x4000
Flag=0x0
File=../rockimg/Image-cvr/kernel.img
[UserPart3]
Name=rootfs
Type=0x8
PartOffset=0x4400
PartSize=0x10000
Flag=0x0
File=../rockimg/Image-cvr/rootfs.img
[UserPart4]
Name=recovery
Type=0x10
PartOffset=0x14400
PartSize=0x4000
Flag=0x0
File=../rockimg/Image-cvr/kernel.img
[UserPart5]
Name=storage
Type=0x80000000
PartOffset=0x18400
PartSize=0x1B800
Flag=0x0
File=../common/storage.img
文件中PartOffset
通過前面分區表的偏移地址+分區大小得出。
以kernel
分區爲例:分區大小爲0x400
、十進制轉換爲16384
、大小爲16384
/1024
/2
= 8M
,可以和我們上面cat /proc/partitions
讀到的分區大小對上了。
上面還有一部分system沒有解釋:
- set format of firmware
Gpt_Enable= /*flat rk firmware*/
Gpt_Enable=0 /*flat gpt firmware*/
Gpt_Enable=1 /*compact gpt firmware*/
- backup header of firmware or not
Backup_Partition_Enable=1 /*backup firmware header*/
Backup_Partition_Enable= /*default,no backup firmware header,when you don't know flash size,no backup*/
注意
上面的storage
分區需要根據分區表大小去製作。
目錄:config/Makefile
#TODO: compare the img size with the setting in setting.ini
#$(Q)make_ext4fs -l 62914560 $(RV_TOPDIR)/common/storage.img $(RV_TOPDIR)/common/storage
firmware-gen fwg fw: pack-kernel pack-rootfs
@$(call MESSAGE,"Package Firmware.img")
$(Q)cp $(KERNEL_PKGDIR)/kernel.img $(OUT_IMAGE_DIR)
$(Q)cp $(RV_TOPDIR)/rockimg/Image-release/rv1108loader.bin $(OUT_IMAGE_DIR)
$(Q)cp $(RV_TOPDIR)/rockimg/Image-release/rv1108ddr.bin $(OUT_IMAGE_DIR)
$(Q)make_ext4fs -l 57671680 $(RV_TOPDIR)/common/storage.img $(RV_TOPDIR)/common/storage
$(Q)$(RV_TOPDIR)/build/firmwareMerger -p $(RV_TOPDIR)/build/setting.ini $(OUT_IMAGE_DIR)/
其中storage
分區是系統默認添加的分區,後面博客會介紹如何添加一個新的分區。
操作設備節點方式改寫
節點名:/dev/fw_header_p
驅動程序路徑:kernel/drivers/rkflash$ vim rkflash_blk.c
,若此方式操作失敗需確認驅動是否加載。
程序:
頭文件
//ota
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <pwd.h>
#include <errno.h>
#include <signal.h>
#include <linux/watchdog.h>
#include <linux/reboot.h>
#include <time.h>
結構體
typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
#define RK_PARTITION_TAG (0x50464B52)
typedef enum {
PART_VENDOR = 1 << 0,
PART_IDBLOCK = 1 << 1,
PART_KERNEL = 1 << 2,
PART_BOOT = 1 << 3,
PART_RECOVERY = 1 << 4,
PART_DTB = 1 << 5,
PART_UBOOT = 1 << 6,
PART_USER = 1 << 31
} enum_parttion_type;
typedef struct {
uint16 year;
uint8 month;
uint8 day;
uint8 hour;
uint8 min;
uint8 sec;
uint8 reserve;
} struct_datetime, *pstruct_datetime;
typedef struct {
uint32 uiFwTag; //"RKFP"
struct_datetime dtReleaseDataTime;
uint32 uiFwVer;
uint32 uiSize;//size of sturct,unit of uint8
uint32 uiPartEntryOffset;//unit of sector
uint32 uiBackupPartEntryOffset;
uint32 uiPartEntrySize;//unit of uint8
uint32 uiPartEntryCount;
uint32 uiFwSize;//unit of uint8
uint8 reserved[464];
uint32 uiPartEntryCrc;
uint32 uiHeaderCrc;
} struct_fw_header, *pstruct_fw_header;
typedef struct {
uint8 szName[32];
enum_parttion_type emPartType;
uint32 uiPartOffset;//unit of sector
uint32 uiPartSize;//unit of sector
uint32 uiDataLength;//unit of uint8
uint32 uiPartProperty;
uint8 reserved[76];
} struct_part_entry, *pstruct_part_entry;
typedef struct {
struct_fw_header hdr; //0.5KB
struct_part_entry part[12]; //1.5KB
} struct_part_info, *pstruct_part_info;
#define FW_HEAD_DEV "/dev/fw_header_p"
操作函數
int getFwPartInfo(struct_part_info *Info)
{
int imagefd;
char imagepath[40];
imagefd = open(FW_HEAD_DEV, O_RDONLY);
if (imagefd < 0) {
printf("Firmware open %s failed \n", FW_HEAD_DEV);
return -1;
}
if (read(imagefd, Info, sizeof(struct_part_info)) <= 0) {
printf("Firmware read %s failed \n", FW_HEAD_DEV);
return -1;
}
if (Info->hdr.uiFwTag != RK_PARTITION_TAG) {
printf("Firmware Tag error\n");
return -1;
}
close(imagefd);
return 0;
}
int debugFwPartInfo(struct_part_info *Info)
{
int i;
for (i = 0; i < Info->hdr.uiPartEntryCount; i++) {
printf("Info.part[%d].szName %s\n", i, Info->part[i].szName);
printf("Info.part[%d].emPartType %x\n", i, Info->part[i].emPartType);
printf("Info.part[%d].uiPartOffset %x\n", i, Info->part[i].uiPartOffset);
printf("Info.part[%d].uiPartSize %x\n", i, Info->part[i].uiPartSize);
printf("Info.part[%d].uiDataLength %x\n", i, Info->part[i].uiDataLength);
printf("Info.part[%d].uiPartProperty%x\n", i, Info->part[i].uiPartProperty);
}
return 0;
}
int setFwPartInfo(struct_part_info *Info)
{
int imagefd;
char imagepath[40];
imagefd = open(FW_HEAD_DEV, O_RDWR);
if (imagefd < 0) {
printf("Firmware open %s failed \n", FW_HEAD_DEV);
return -1;
}
if (write(imagefd, Info, sizeof(struct_part_info)) <= 0) {
printf("Firmware write %s failed \n", FW_HEAD_DEV);
return -1;
}
close(imagefd);
return 0;
}
主程序操作
struct_part_info Info;
getFwPartInfo(&Info);
debugFwPartInfo(&Info);
Info.hdr.uiPartEntryCount = 6;
memcpy(Info.part[4].szName, "recovery", 8);
Info.part[4].emPartType = 0x10;
Info.part[4].uiPartOffset = 0x14400;
Info.part[4].uiPartSize = 0x4000;
Info.part[4].uiDataLength = 0x51b514;
memcpy(Info.part[5].szName, "storage", 8);
Info.part[5].emPartType = 0x80000000;
Info.part[5].uiPartOffset = 0x18400;
Info.part[5].uiPartSize = 0x1b800;
Info.part[5].uiDataLength = 0x3700000;
setFwPartInfo(&Info);
getFwPartInfo(&Info);
debugFwPartInfo(&Info);
if(access("/dev/recovery",F_OK)!=-1) {
printf("yang this dev recovery ok\n");
system("dd if=/dev/kernel of=/dev/recovery bs=1K");
system("busybox mkfs.ext2 /dev/storage");
system("busybox mount -t ext4 /dev/storage /mnt/storage");
system("sync");
} else {
printf("yang this not have recovery\n");
printf("yang thsi is will be reboot\n");
system("reboot");
}
思考
分區是打包到固件裏?
我們查找資料解釋如下:
firmware_merger read setting.ini to get partition info and create firmware.firmware_merger can generate
three kinds of firmware(1.flat rk firmware 2.flat gpt firmware 3.compact gpt firmware).flat firmware can be
directly written into flash by 'wl'command.Compact firmware can only be written by productiontool. when SPL
is rk miniloader,firmware use flat rk format.when SPL is u-boot,firmware use flat gpt.
大概意思就是 firmware_merger
會讀取setting.ini
。
回顧之前的config/Makefile
也可以發現:
跟Firmware
有關:
@echo 'Firmware:'
@echo ' firmware-gen - Generate firmware'
@echo ' firmware-write - Write firmware to board'
#TODO: compare the img size with the setting in setting.ini
#$(Q)make_ext4fs -l 62914560 $(RV_TOPDIR)/common/storage.img $(RV_TOPDIR)/common/storage
firmware-gen fwg fw: pack-kernel pack-rootfs
@$(call MESSAGE,"Package Firmware.img")
$(Q)cp $(KERNEL_PKGDIR)/kernel.img $(OUT_IMAGE_DIR)
$(Q)cp $(RV_TOPDIR)/rockimg/Image-release/rv1108loader.bin $(OUT_IMAGE_DIR)
$(Q)cp $(RV_TOPDIR)/rockimg/Image-release/rv1108ddr.bin $(OUT_IMAGE_DIR)
$(Q)make_ext4fs -l 57671680 $(RV_TOPDIR)/common/storage.img $(RV_TOPDIR)/common/storage
$(Q)$(RV_TOPDIR)/build/firmwareMerger -p $(RV_TOPDIR)/build/setting.ini $(OUT_IMAGE_DIR)/
firmware-gen->target-post-image
target-post-image: prepare prepare-rootfs target-finalize firmware-gen
@$(foreach s, $(call qstrip,$(RV_ROOTFS_POST_IMAGE_SCRIPT)), \
$(call MESSAGE,"Executing post-image script $(s)"); \
$(EXTRA_ENV) $(s) $(BINARIES_DIR) $(call qstrip,$(RV_ROOTFS_POST_SCRIPT_ARGS))$(sep))
其中:world: target-post-image
@echo 'Build:'
@echo ' all - make world'
因此在make all
或者 make fw
會重新讀取setting.ini