1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "emmc_ptable.h"
17 
18 #include <algorithm>
19 #include <fcntl.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 
23 #include "log/log.h"
24 #include "securec.h"
25 #include "updater/updater_const.h"
26 
27 namespace Updater {
28 
GetDeviceCapacity()29 uint64_t EmmcPtable::GetDeviceCapacity()
30 {
31     uint64_t capacity = 0;
32     std::string capacityPath = std::string(MMC_SIZE_FILE);
33     GetCapacity(capacityPath, capacity);
34     return capacity;
35 }
36 
EmmcPatchGptHeader(EmmcPartitionDataInfo & ptnDataInfo,const uint32_t blockSize)37 void EmmcPtable::EmmcPatchGptHeader(EmmcPartitionDataInfo &ptnDataInfo, const uint32_t blockSize)
38 {
39     // mbr len + gptHeader len = 2 blockSize
40     if (blockSize == 0 || ptnDataInfo.writeDataLen < 2 * blockSize) {
41         LOG(ERROR) << "invaild argument";
42         return;
43     }
44 
45     uint64_t devDensity = GetDeviceCapacity();
46 
47     uint64_t devBlockSize = EMMC_BLOCK_SIZE;
48     uint64_t cardSizeSector = devDensity / devBlockSize;
49 
50     // Patching primary header
51     uint8_t *primaryGptHeader = ptnDataInfo.data + blockSize;
52     PUT_LONG_LONG(primaryGptHeader + BACKUP_HEADER_OFFSET, (cardSizeSector - 1));
53     PUT_LONG_LONG(primaryGptHeader + LAST_USABLE_LBA_OFFSET, (cardSizeSector - 1));
54     // Find last partition
55     uint32_t totalPart = 0;
56     while (((GPT_PARTITION_SIZE - blockSize - blockSize) > totalPart * PARTITION_ENTRY_SIZE) &&
57         (*(primaryGptHeader + blockSize + totalPart * PARTITION_ENTRY_SIZE) != 0)) {
58         totalPart++;
59     }
60     if (totalPart == 0) {
61         LOG(ERROR) << "no partition exist";
62         return;
63     }
64     // Patching last partition
65     uint8_t *lastPartOffset = primaryGptHeader + blockSize + (totalPart - 1) * PARTITION_ENTRY_SIZE;
66     uint64_t lastLba = GET_LLWORD_FROM_BYTE(lastPartOffset + PARTITION_ENTRY_LAST_LBA);
67     uint64_t firstLba = GET_LLWORD_FROM_BYTE(lastPartOffset + FIRST_LBA_OFFSET);
68     // General algorithm : calculate partition size by lba
69     uint64_t partitionSize = (lastLba - firstLba + 1) * MIN_EMMC_WRITE_SIZE;
70     std::string partitionName;
71     uint8_t *nameOffset = lastPartOffset + GPT_PARTITION_NAME_OFFSET;
72     // 2 bytes for 1 charactor of partition name
73     ParsePartitionName(nameOffset, MAX_GPT_NAME_SIZE, partitionName, MAX_GPT_NAME_SIZE / 2);
74     if (partitionName == USERDATA_PARTITION || (totalPart == 1 && partitionSize == 0)) {
75         // patch userdata or only one partition
76         PUT_LONG_LONG(lastPartOffset + PARTITION_ENTRY_LAST_LBA, (cardSizeSector - 1));
77         LOG(INFO) << "partitionSize=" << (cardSizeSector - 1) << ", partition_name:" << partitionName;
78     }
79 
80     // Updating CRC of the Partition entry array in both headers
81     uint32_t partCount = GET_LWORD_FROM_BYTE(primaryGptHeader + PARTITION_COUNT_OFFSET);
82     uint32_t entrySize = GET_LWORD_FROM_BYTE(primaryGptHeader + PENTRY_SIZE_OFFSET);
83     // mbr len + gptHeader len = 2 blockSize
84     uint32_t crcValue = CalculateCrc32(ptnDataInfo.data + (blockSize * 2), partCount * entrySize);
85     PUT_LONG(primaryGptHeader + PARTITION_CRC_OFFSET, crcValue);
86     // Clearing CRC fields to calculate
87     PUT_LONG(primaryGptHeader + HEADER_CRC_OFFSET, 0);
88     crcValue = CalculateCrc32(primaryGptHeader, GPT_CRC_LEN);
89     PUT_LONG(primaryGptHeader + HEADER_CRC_OFFSET, crcValue);
90     return;
91 }
92 
WritePartitionTable()93 bool EmmcPtable::WritePartitionTable()
94 {
95     if (partitionInfo_.empty()) {
96         LOG(ERROR) << "emmcPtnDataInfo_ is empty, write failed!";
97         return false;
98     }
99 
100     if (!emmcPtnDataInfo_.isGptVaild) {
101         LOG(WARNING) <<  "invaild ptable, no need to update";
102         return false;
103     }
104 
105     std::string emmcNode = std::string(MMC_BLOCK_DEV_NAME);
106     if (!WriteBufferToPath(emmcNode, 0, emmcPtnDataInfo_.data, GPT_PARTITION_SIZE)) {
107         LOG(ERROR) << "write gpt fail";
108         return false;
109     }
110     return true;
111 }
112 
113 // blocksize is 4096, lbaLen is 512. Because in ptable.img block is 512 while in device block is 4096
ParsePartitionFromBuffer(uint8_t * ptbImgBuffer,const uint32_t imgBufSize)114 bool EmmcPtable::ParsePartitionFromBuffer(uint8_t *ptbImgBuffer, const uint32_t imgBufSize)
115 {
116     if (ptbImgBuffer == nullptr || imgBufSize < GPT_PARTITION_SIZE) {
117         LOG(ERROR) << "ptbImgBuffer == NULL || imgBufSize < GPT_PARTITION_SIZE";
118         return false;
119     }
120     return UpdateCommInitializeGptPartition(ptbImgBuffer, imgBufSize);
121 }
122 
ParseGptHeaderByEmmc(uint8_t * gptImage,const uint32_t len)123 bool EmmcPtable::ParseGptHeaderByEmmc(uint8_t *gptImage, const uint32_t len)
124 {
125     GPTHeaderInfo gptHeaderInfo;
126     uint32_t blockSize = EMMC_BLOCK_SIZE;
127     (void)memset_s(&gptHeaderInfo, sizeof(GPTHeaderInfo), 0, sizeof(GPTHeaderInfo));
128     if (!GetPartitionGptHeaderInfo(gptImage + blockSize, blockSize, gptHeaderInfo)) {
129         LOG(ERROR) << "GetPartitionGptHeaderInfo fail";
130         return false;
131     }
132 #ifndef UPDATER_UT
133     uint64_t deviceSize = GetDeviceCapacity();
134     uint32_t lbaNum = deviceSize / MIN_EMMC_WRITE_SIZE;
135 #else
136     uint32_t lbaNum = 0xFFFFFFFF; // init to maximum
137 #endif
138     return PartitionCheckGptHeader(gptImage, len, lbaNum, blockSize, gptHeaderInfo);
139 }
140 
EmmcReadGpt(uint8_t * ptableData,uint32_t len)141 bool EmmcPtable::EmmcReadGpt(uint8_t *ptableData, uint32_t len)
142 {
143     uint32_t number = 0;
144 
145     partitionInfo_.clear();
146     if (!ParseGptHeaderByEmmc(emmcPtnDataInfo_.data, len)) {
147         LOG(ERROR) << "Primary signature invalid";
148         return false;
149     }
150     for (uint32_t i = 0; i < MAX_PARTITION_NUM; i++) {
151         uint8_t *startLbaOffset = ptableData + GPT_PARTITION_START_LBA_OFFSET;
152         uint8_t *endLbaOffset = ptableData + GPT_PARTITION_START_LBA_OFFSET + GPT_PARTITION_END_LBA_OFFSET;
153         uint8_t *typeGuidOffset = ptableData + GPT_PARTITION_TYPE_GUID_OFFSET;
154         uint8_t *nameOffset = ptableData + GPT_PARTITION_NAME_OFFSET;
155         PtnInfo newPtnInfo;
156         (void)memset_s(&newPtnInfo, sizeof(newPtnInfo), 0, sizeof(newPtnInfo));
157         ParsePartitionName(nameOffset, MAX_GPT_NAME_SIZE, newPtnInfo.dispName, GPT_DISP_NAME_LEN);
158         if (newPtnInfo.dispName[0] == 0) {
159             break;
160         }
161         uint64_t startLba = GET_LLWORD_FROM_BYTE(startLbaOffset);
162         uint64_t endLba = GET_LLWORD_FROM_BYTE(endLbaOffset);
163         if (memcpy_s(newPtnInfo.partitionTypeGuid, GPT_PARTITION_TYPE_GUID_LEN,
164             typeGuidOffset, GPT_PARTITION_TYPE_GUID_LEN) != EOK) {
165             LOG(ERROR) << "memcpy guid fail";
166         }
167         newPtnInfo.startAddr = startLba * LBA_LENGTH;
168         newPtnInfo.writePath = MMC_BLOCK_DEV_NAME;
169         newPtnInfo.writeMode = "WRITE_RAW";
170         /* General algorithm : calculate partition size by lba */
171         newPtnInfo.partitionSize = (endLba - startLba + 1) * LBA_LENGTH;
172         ptableData += GPT_PARTITION_INFO_LENGTH;
173         partitionInfo_.push_back(newPtnInfo);
174         number++;
175     }
176 
177     return number != 0;
178 }
179 
UpdateCommInitializeGptPartition(uint8_t * gptImage,const uint32_t len)180 bool EmmcPtable::UpdateCommInitializeGptPartition(uint8_t *gptImage, const uint32_t len)
181 {
182     if (gptImage == nullptr || len < GPT_PARTITION_SIZE) {
183         LOG(ERROR) << "input param invalid";
184         return false;
185     }
186     uint32_t imgBlockSize = ptableData_.lbaLen; // 512
187     uint32_t deviceBlockSize = EMMC_BLOCK_SIZE;
188 
189     uint8_t *gptHeaderStart = gptImage + imgBlockSize;
190     uint8_t *ptableData = gptImage + PROTECTIVE_MBR_SIZE + LBA_LENGTH; /* skip MBR and gpt header */
191 
192     if (!CheckProtectiveMbr(gptImage, imgBlockSize) || !CheckIfValidGpt(gptHeaderStart, imgBlockSize)) {
193         LOG(ERROR) << "check mbr or header fail";
194         emmcPtnDataInfo_.isGptVaild = false;
195         return false;
196     }
197 
198     // for hisi: change ptable.img(512 bytes/block) into format of device(4096 bytes/block)
199     if (memcpy_s(emmcPtnDataInfo_.data, GPT_PARTITION_SIZE, gptImage, imgBlockSize) != EOK) {
200         LOG(ERROR) << "memcpy_s mbr fail";
201         return false;
202     }
203     if (memcpy_s(emmcPtnDataInfo_.data + deviceBlockSize, GPT_PARTITION_SIZE - deviceBlockSize,
204         gptHeaderStart, imgBlockSize) != EOK) {
205         LOG(ERROR) << "memcpy_s gpt header fail";
206         return false;
207     }
208     // skip 2 lba length to set gpt entry
209     if (memcpy_s(emmcPtnDataInfo_.data + 2 * deviceBlockSize, GPT_PARTITION_SIZE - 2 * deviceBlockSize,
210         ptableData, GPT_PARTITION_SIZE - 2 * deviceBlockSize) != EOK) {
211         LOG(ERROR) << "memcpy_s gpt data fail";
212         return false;
213     }
214     emmcPtnDataInfo_.writeDataLen = len;
215     EmmcPatchGptHeader(emmcPtnDataInfo_, deviceBlockSize);
216     emmcPtnDataInfo_.isGptVaild = true;
217 
218     return EmmcReadGpt(emmcPtnDataInfo_.data + 2 * deviceBlockSize, len); // 2:skip 2 lba length to set gpt entry
219 }
220 
ReadEmmcGptImageToRam()221 bool EmmcPtable::ReadEmmcGptImageToRam()
222 {
223 #ifndef UPDATER_UT
224     std::string emmcNode = std::string(MMC_BLOCK_DEV_NAME);
225 #else
226     std::string emmcNode = "/data/updater_ext/ptable_parse/ptable.img";
227 #endif
228     int32_t imgLen = GPT_PARTITION_SIZE;
229     auto buf = std::make_unique<uint8_t[]>(imgLen);
230     uint8_t *buffer = buf.get();
231     uint32_t deviceBlockSize = EMMC_BLOCK_SIZE;
232     if (buffer == nullptr) {
233         LOG(ERROR) << "new buffer failed!";
234         return false;
235     }
236     if (!MemReadWithOffset(emmcNode, 0, buffer, imgLen)) {
237         LOG(ERROR) << "read " << imgLen << " bytes from emmcNode " << emmcNode << " failed!";
238         return false;
239     }
240 
241 #ifdef UPDATER_UT
242     deviceBlockSize = ptableData_.lbaLen;
243 #endif
244     uint8_t *gptHeaderStart = buffer + deviceBlockSize; // if image imgBlockSize, if device deviceBlockSize
245     if (!CheckProtectiveMbr(buffer, deviceBlockSize) || !CheckIfValidGpt(gptHeaderStart, deviceBlockSize)) {
246         LOG(ERROR) << "check mbr or header fail";
247         return false;
248     }
249 
250     (void)memset_s(emmcPtnDataInfo_.data, GPT_PARTITION_SIZE, 0, GPT_PARTITION_SIZE);
251     if (memcpy_s(emmcPtnDataInfo_.data, GPT_PARTITION_SIZE, buffer, imgLen) != EOK) {
252         LOG(ERROR) << "memcpy_s GPT fail";
253         return false;
254     }
255 
256     emmcPtnDataInfo_.isGptVaild = true;
257     uint8_t *ptableData = buffer + 2 * deviceBlockSize; /* skip MBR and gpt header */
258     return EmmcReadGpt(ptableData, imgLen);
259 }
260 
LoadPtableFromDevice()261 bool EmmcPtable::LoadPtableFromDevice()
262 {
263     if (!partitionInfo_.empty()) {
264         LOG(INFO) << "ptable is already loaded to ram";
265         return true;
266     }
267     if (ReadEmmcGptImageToRam()) {
268         LOG(INFO) << "init ptable to ram ok";
269         return true;
270     }
271     return false;
272 }
273 
GetPtableImageBuffer(uint8_t * imageBuf,const uint32_t imgBufSize)274 bool EmmcPtable::GetPtableImageBuffer(uint8_t *imageBuf, const uint32_t imgBufSize)
275 {
276     if (imageBuf == nullptr || imgBufSize == 0) {
277         LOG(ERROR) << "input invalid";
278         return false;
279     }
280     if (memcpy_s(imageBuf, imgBufSize, emmcPtnDataInfo_.data, GPT_PARTITION_SIZE) != EOK) {
281         LOG(ERROR) << "memcpy_s failed";
282         return false;
283     }
284     return true;
285 }
286 
EditPartitionBuf(uint8_t * imageBuf,uint64_t imgBufSize,std::vector<PtnInfo> & modifyList)287 bool EmmcPtable::EditPartitionBuf(uint8_t *imageBuf, uint64_t imgBufSize, std::vector<PtnInfo> &modifyList)
288 {
289     if (imageBuf == nullptr || imgBufSize == 0 || modifyList.empty()) {
290         LOG(ERROR) << "input invalid";
291         return false;
292     }
293     uint8_t *gptImage = imageBuf;
294     uint32_t imgBlockSize = EMMC_BLOCK_SIZE;
295     uint8_t *gptHeader = gptImage + imgBlockSize;
296     uint32_t maxPtnCnt = GET_LWORD_FROM_BYTE(&gptHeader[PARTITION_COUNT_OFFSET]);
297     uint32_t ptnEntrySize = GET_LWORD_FROM_BYTE(&gptHeader[PENTRY_SIZE_OFFSET]);
298     uint64_t gptHeaderLen = EMMC_BLOCK_SIZE;
299     uint64_t gptSize = static_cast<uint64_t>(maxPtnCnt) * ptnEntrySize + imgBlockSize + gptHeaderLen;
300     uint64_t devDensity = GetDeviceCapacity();
301     if (devDensity == 0) {
302         LOG(ERROR) << "get emmc capacity fail";
303         return false;
304     }
305     uint32_t devBlockSize = EMMC_BLOCK_SIZE;
306     struct GptParseInfo gptInfo(imgBlockSize, devBlockSize, devDensity);
307     for (auto &t : modifyList) {
308         if (!ChangeGpt(gptImage, gptSize, gptInfo, t)) {
309             LOG(ERROR) << "ChangeGpt failed";
310             return false;
311         }
312     }
313     EmmcPartitionDataInfo newEmmcPartitionDataInfo;
314     newEmmcPartitionDataInfo.writeDataLen = ptableData_.emmcGptDataLen;
315     (void)memset_s(newEmmcPartitionDataInfo.data, GPT_PARTITION_SIZE, 0, GPT_PARTITION_SIZE);
316     if (memcpy_s(newEmmcPartitionDataInfo.data, GPT_PARTITION_SIZE, imageBuf, imgBlockSize) != EOK) {
317         LOG(ERROR) << "memcpy_s failed";
318         return false;
319     }
320     EmmcPatchGptHeader(newEmmcPartitionDataInfo, imgBlockSize);
321     return true;
322 }
323 }