• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ufs_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 {
GetDeviceLunNum()28 uint32_t UfsPtable::GetDeviceLunNum()
29 {
30     return deviceLunNum_;
31 }
32 
GetDeviceLunCapacity(const uint32_t lunIndex)33 uint64_t UfsPtable::GetDeviceLunCapacity(const uint32_t lunIndex)
34 {
35     char lunIndexName = 'a' + lunIndex;
36     std::string capacityPath = std::string(PREFIX_SYS_CLASS_BLOCK) + lunIndexName + "/size";
37     uint64_t capacity = 0;
38     GetCapacity(capacityPath, capacity);
39     return capacity;
40 }
41 
GetPtableExtraOffset(void)42 uint32_t UfsPtable::GetPtableExtraOffset(void)
43 {
44     return 0;
45 }
46 
47 // avoid u disk being recognized as a valid gpt lun device
IsUsbPath(const uint32_t lunIndex)48 bool UfsPtable::IsUsbPath(const uint32_t lunIndex)
49 {
50     constexpr uint32_t minRemoveableStartIdx = 3;
51     if (lunIndex <= minRemoveableStartIdx) {
52         return false;
53     }
54     char lunIndexName = 'a' + lunIndex;
55     const char* targetUsbString = "usb";
56     const char* targetXhciString = "xhci";
57     char linkBuf[READ_LINK_BUFFER_LENTH] = {0};
58     std::string filePath = std::string(PREFIX_SYS_CLASS_BLOCK) + lunIndexName;
59     ssize_t retSize = readlink(filePath.c_str(), linkBuf, READ_LINK_BUFFER_LENTH - 1);
60     LOG(INFO) << "readlink " << filePath << " retSzie " << retSize << ", linkBuf is: " << linkBuf;
61     if (retSize > 0 && (strstr(linkBuf, targetUsbString) != nullptr || strstr(linkBuf, targetXhciString) != nullptr)) {
62         return true;
63     }
64     return false;
65 }
66 
CheckDeviceLunRemoveable(const uint32_t lunIndex)67 bool UfsPtable::CheckDeviceLunRemoveable(const uint32_t lunIndex)
68 {
69     constexpr uint32_t minRemoveableStartIdx = 3;
70     if (lunIndex <= minRemoveableStartIdx) {
71         return false;
72     }
73     char lunIndexName = 'a' + lunIndex;
74     std::string removableNode = std::string(PREFIX_SYS_CLASS_BLOCK) + lunIndexName + "/removable";
75     std::string removableResult {};
76     std::ifstream fin(removableNode, std::ios::in);
77     if (!fin.is_open()) {
78         LOG(ERROR) << "open " << removableNode << " failed";
79         return false;
80     }
81     fin >> removableResult;
82     LOG(INFO) << "lun " << lunIndex << " removable result is : " << removableResult;
83     return removableResult == "1";
84 }
85 
GetDeviceBlockSize(void)86 uint32_t UfsPtable::GetDeviceBlockSize(void)
87 {
88     return ptableData_.blockSize;
89 }
90 
GetDeviceLunNodePath(const uint32_t lun)91 std::string UfsPtable::GetDeviceLunNodePath(const uint32_t lun)
92 {
93     char lunIndexName = 'a' + lun;
94     return std::string(PREFIX_UFS_NODE) + lunIndexName;
95 }
96 
SetDeviceLunNum()97 void UfsPtable::SetDeviceLunNum()
98 {
99     if (deviceLunNum_ > 0) {
100         return;
101     }
102     uint32_t lunIndex;
103     for (lunIndex = 0; lunIndex < MAX_LUN_NUMBERS; lunIndex++) {
104         std::string ufsNode = GetDeviceLunNodePath(lunIndex);
105         if (!CheckFileExist(ufsNode)) {
106             LOG(ERROR) << "file " << ufsNode << " is not exist";
107             break;
108         }
109 #ifndef UPDATER_UT
110         if (CheckDeviceLunRemoveable(lunIndex) || IsUsbPath(lunIndex)) {
111             LOG(ERROR) << "device " << ufsNode << " is removable, may be a u disk";
112             break;
113         }
114 #endif
115     }
116     deviceLunNum_ = lunIndex;
117     LOG(INFO) << "device lun num is " << deviceLunNum_;
118     return;
119 }
120 
ParseGptHeaderByUfsLun(const uint8_t * gptImage,const uint32_t len,const uint32_t lun,const uint32_t blockSize)121 bool UfsPtable::ParseGptHeaderByUfsLun(const uint8_t *gptImage, const uint32_t len,
122     const uint32_t lun, const uint32_t blockSize)
123 {
124     GPTHeaderInfo gptHeaderInfo;
125     (void)memset_s(&gptHeaderInfo, sizeof(GPTHeaderInfo), 0, sizeof(GPTHeaderInfo));
126     if (!GetPartitionGptHeaderInfo(gptImage + blockSize, blockSize, gptHeaderInfo)) {
127         LOG(ERROR) << "GetPartitionGptHeaderInfo fail";
128         return false;
129     }
130     uint32_t deviceBlockSize = GetDeviceBlockSize();
131     if (deviceBlockSize == 0) {
132         LOG(ERROR) << "block device size invalid " << deviceBlockSize;
133         return false;
134     }
135     uint64_t lunDeviceSize = GetDeviceLunCapacity(lun);
136     uint32_t lunLbaNum = lunDeviceSize / deviceBlockSize;
137     return PartitionCheckGptHeader(gptImage, len, lunLbaNum, blockSize, gptHeaderInfo);
138 }
139 
UfsReadGpt(const uint8_t * gptImage,const uint32_t len,const uint32_t lun,const uint32_t blockSize)140 bool UfsPtable::UfsReadGpt(const uint8_t *gptImage, const uint32_t len,
141     const uint32_t lun, const uint32_t blockSize)
142 {
143     if (gptImage == nullptr || len < ptableData_.writeDeviceLunSize || lun >= MAX_LUN_NUMBERS || blockSize == 0) {
144         LOG(ERROR) << "invaild input";
145         return false;
146     }
147     if (!ParseGptHeaderByUfsLun(gptImage, len, lun, blockSize)) {
148         LOG(ERROR) << "Primary signature invalid";
149         return false;
150     }
151     auto startIter = partitionInfo_.end();
152     for (auto it = partitionInfo_.begin(); it != partitionInfo_.end();) {
153         if ((*it).lun == lun) {
154             it = partitionInfo_.erase(it);
155             startIter = it;
156             continue;
157         }
158         it++;
159     }
160     UfsReadGptEntry(gptImage, lun, blockSize, startIter);
161     return true;
162 }
163 
UfsReadGptEntry(const uint8_t * gptImage,const uint32_t lun,const uint32_t blockSize,std::vector<PtnInfo>::iterator startIter)164 void UfsPtable::UfsReadGptEntry(const uint8_t *gptImage, const uint32_t lun,
165                                 const uint32_t blockSize, std::vector<PtnInfo>::iterator startIter)
166 {
167     uint32_t partEntryCnt = blockSize / PARTITION_ENTRY_SIZE;
168     uint32_t partition0 = GET_LLWORD_FROM_BYTE(gptImage + blockSize + PARTITION_ENTRIES_OFFSET);
169 
170     uint32_t count = 0;
171     const uint8_t *data = nullptr;
172     bool tailPartFlag = false;
173     for (uint32_t i = 0; i < (MAX_PARTITION_NUM / partEntryCnt) && count < MAX_PARTITION_NUM; i++) {
174         data = gptImage + (partition0 + i) * blockSize;
175         for (uint32_t j = 0; j < partEntryCnt; j++) {
176             uint8_t typeGuid[GPT_PARTITION_TYPE_GUID_LEN] = {0};
177             if (memcpy_s(typeGuid, sizeof(typeGuid), &data[(j * PARTITION_ENTRY_SIZE)], sizeof(typeGuid)) != EOK) {
178                 LOG(ERROR) << "memcpy guid fail";
179             }
180             if (typeGuid[0] == 0x00 && typeGuid[1] == 0x00) { // 0x00 means no partition
181                 i = MAX_PARTITION_NUM / partEntryCnt;
182                 break;
183             }
184             uint64_t firstLba = GET_LLWORD_FROM_BYTE(&data[(j * PARTITION_ENTRY_SIZE) + FIRST_LBA_OFFSET]);
185             uint64_t lastLba = GET_LLWORD_FROM_BYTE(&data[(j * PARTITION_ENTRY_SIZE) + LAST_LBA_OFFSET]);
186             // add a new partition info into partitionInfo_ vector
187             PtnInfo newPtnInfo = {};
188             newPtnInfo.startAddr = firstLba * static_cast<uint64_t>(GetDeviceBlockSize());
189             newPtnInfo.writePath = GetDeviceLunNodePath(lun);
190             // General algorithm : calculate partition size by lba
191             newPtnInfo.partitionSize = (lastLba - firstLba + 1) * static_cast<uint64_t>(GetDeviceBlockSize());
192             const uint8_t *nameOffset = data + (j * PARTITION_ENTRY_SIZE + GPT_PARTITION_NAME_OFFSET);
193             // 2 bytes for 1 charactor of partition name
194             ParsePartitionName(nameOffset, MAX_GPT_NAME_SIZE, newPtnInfo.dispName, MAX_GPT_NAME_SIZE / 2);
195             SetPartitionType(newPtnInfo.dispName, newPtnInfo);
196             (void)memcpy_s(newPtnInfo.partitionTypeGuid, sizeof(newPtnInfo.partitionTypeGuid),
197                 typeGuid, sizeof(typeGuid));
198             newPtnInfo.isTailPart = tailPartFlag;
199             newPtnInfo.lun = lun;
200             newPtnInfo.gptEntryBufOffset = static_cast<int>((partition0 + i) * blockSize + j * PARTITION_ENTRY_SIZE -
201                                                             2 * blockSize); // 2 : pmbr and gpt header
202             if (newPtnInfo.dispName == USERDATA_PARTITION) {
203                 tailPartFlag = true;
204                 usrDataPtnIndex_ = std::distance(partitionInfo_.begin(), startIter);
205             }
206             startIter = ++(partitionInfo_.insert(startIter, newPtnInfo));
207             count++;
208         }
209     }
210     if (tailPartFlag) {
211         endPtnIndex_ = static_cast<int>(std::distance(partitionInfo_.begin(), startIter)) - 1;
212         startPtnIndex_ = endPtnIndex_  + 1 - static_cast<int>(count);
213         hasTailpart_ = partitionInfo_[endPtnIndex_].isTailPart;
214     }
215     return;
216 }
217 
UfsPatchGptHeader(UfsPartitionDataInfo & ptnDataInfo,const uint32_t blockSize)218 void UfsPtable::UfsPatchGptHeader(UfsPartitionDataInfo &ptnDataInfo, const uint32_t blockSize)
219 {
220     uint32_t deviceBlockSize = GetDeviceBlockSize();
221     // mbr len + gptHeader len = 2 blockSize
222     if (blockSize == 0 || ptnDataInfo.writeDataLen < 2 * blockSize || ptnDataInfo.lunSize == 0 ||
223         deviceBlockSize == 0) {
224         LOG(ERROR) << "invaild argument";
225         return;
226     }
227     uint64_t cardSizeSector = ptnDataInfo.lunSize / deviceBlockSize;
228     if (cardSizeSector == 0) {
229         cardSizeSector = DEFAULT_SECTOR_NUM;
230     }
231     // Patching primary header
232     uint8_t *primaryGptHeader = ptnDataInfo.data + blockSize;
233     uint64_t lastUsableSector = cardSizeSector - 1 - (hasBackupPtable_ ? GPT_PTABLE_BACKUP_SIZE : 0);
234     if (reservedSize_ != 0 && lastUsableSector > reservedSize_) {
235         LOG(INFO) << "reserve " << reservedSize_ << "block for " << GetDeviceLunNodePath(ptnDataInfo.lunIndex);
236         lastUsableSector -= reservedSize_;
237     }
238     LOG(INFO) << "cardSizeSector " << cardSizeSector << ", lastUsableSector " << lastUsableSector;
239     PUT_LONG_LONG(primaryGptHeader + BACKUP_HEADER_OFFSET, (cardSizeSector - 1));
240     PUT_LONG_LONG(primaryGptHeader + LAST_USABLE_LBA_OFFSET, lastUsableSector);
241     // Find last partition
242     uint32_t totalPart = 0;
243     while (((TMP_DATA_SIZE - blockSize - blockSize) > totalPart * PARTITION_ENTRY_SIZE) &&
244         (*(primaryGptHeader + blockSize + totalPart * PARTITION_ENTRY_SIZE) != 0)) {
245         totalPart++;
246     }
247     if (totalPart == 0) {
248         LOG(ERROR) << "no partition exist";
249         return;
250     }
251     // Patching last partition
252     uint8_t *lastPartOffset = primaryGptHeader + blockSize + (totalPart - 1) * PARTITION_ENTRY_SIZE;
253     uint64_t lastLba = GET_LLWORD_FROM_BYTE(lastPartOffset + PARTITION_ENTRY_LAST_LBA);
254     uint64_t firstLba = GET_LLWORD_FROM_BYTE(lastPartOffset + FIRST_LBA_OFFSET);
255     // General algorithm : calculate partition size by lba
256     uint64_t partitionSize = (lastLba - firstLba + 1) * deviceBlockSize;
257     std::string partitionName;
258     uint8_t *nameOffset = lastPartOffset + GPT_PARTITION_NAME_OFFSET;
259     // 2 bytes for 1 charactor of partition name
260     ParsePartitionName(nameOffset, MAX_GPT_NAME_SIZE, partitionName, MAX_GPT_NAME_SIZE / 2);
261     if (partitionName == USERDATA_PARTITION || (totalPart == 1 && partitionSize == 0)) {
262         // patch userdata or only one partition
263         PUT_LONG_LONG(lastPartOffset + PARTITION_ENTRY_LAST_LBA, lastUsableSector);
264         LOG(INFO) << "partitionSize=" << partitionSize << ", partition_name:" << partitionName;
265     }
266 
267     // Updating CRC of the Partition entry array in both headers
268     uint32_t partCount = GET_LWORD_FROM_BYTE(primaryGptHeader + PARTITION_COUNT_OFFSET);
269     uint32_t entrySize = GET_LWORD_FROM_BYTE(primaryGptHeader + PENTRY_SIZE_OFFSET);
270     // mbr len + gptHeader len = 2 blockSize
271     uint32_t crcValue = CalculateCrc32(ptnDataInfo.data + (blockSize * 2), partCount * entrySize);
272     PUT_LONG(primaryGptHeader + PARTITION_CRC_OFFSET, crcValue);
273     // Clearing CRC fields to calculate
274     PUT_LONG(primaryGptHeader + HEADER_CRC_OFFSET, 0);
275     crcValue = CalculateCrc32(primaryGptHeader, GPT_CRC_LEN);
276     PUT_LONG(primaryGptHeader + HEADER_CRC_OFFSET, crcValue);
277     return;
278 }
279 
280 // 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)281 bool UfsPtable::ParsePartitionFromBuffer(uint8_t *ptbImgBuffer, const uint32_t imgBufSize)
282 {
283     if (ptbImgBuffer == nullptr) {
284         LOG(ERROR) << "input param invalid";
285         return false;
286     }
287 
288     uint32_t imgBlockSize = ptableData_.lbaLen; // 512
289     uint32_t deviceBlockSize = GetDeviceBlockSize();
290     if (imgBufSize < ptableData_.emmcGptDataLen + ptableData_.imgLuSize + GetPtableExtraOffset()) {
291         LOG(ERROR) << "input param invalid imgBufSize";
292         return false;
293     }
294 
295     SetDeviceLunNum();
296     LOG(INFO) << "lun number of ptable:" << deviceLunNum_;
297     ufsPtnDataInfo_.clear();
298     for (uint32_t i = 0; i < deviceLunNum_; i++) {
299         UfsPartitionDataInfo newLunPtnDataInfo;
300         (void)memset_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, 0, TMP_DATA_SIZE);
301         uint8_t *lunStart = GetPtableImageUfsLunPmbrStart(ptbImgBuffer, i);
302         uint8_t *gptHeaderStart = GetPtableImageUfsLunGptHeaderStart(ptbImgBuffer, i);
303         // first block is mbr, second block is gptHeader
304         if (!CheckProtectiveMbr(lunStart, imgBlockSize) || !CheckIfValidGpt(gptHeaderStart, imgBlockSize)) {
305             newLunPtnDataInfo.isGptVaild = false;
306             ufsPtnDataInfo_.push_back(newLunPtnDataInfo);
307             continue;
308         }
309         // for hisi: change ptable.img(512 bytes/block) into format of device(4096 bytes/block)
310         if (memcpy_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, lunStart, imgBlockSize) != EOK) {
311             LOG(WARNING) << "memcpy_s pmbr fail";
312         }
313         if (memcpy_s(newLunPtnDataInfo.data + deviceBlockSize, TMP_DATA_SIZE - deviceBlockSize,
314             gptHeaderStart, imgBlockSize) != EOK) {
315             LOG(WARNING) << "memcpy_s gpt header fail";
316         }
317         // skip 2 lba length to set gpt entry
318         if (memcpy_s(newLunPtnDataInfo.data + 2 * deviceBlockSize, TMP_DATA_SIZE - 2 * deviceBlockSize,
319             GetPtableImageUfsLunEntryStart(ptbImgBuffer, i), GPT_ENTRYS_SIZE) != EOK) {
320             LOG(WARNING) << "memcpy_s gpt data fail";
321         }
322         newLunPtnDataInfo.writeDataLen = ptableData_.writeDeviceLunSize;
323         newLunPtnDataInfo.lunIndex = i + ptableData_.startLunNumber;
324         newLunPtnDataInfo.lunSize = GetDeviceLunCapacity(newLunPtnDataInfo.lunIndex);
325         UfsPatchGptHeader(newLunPtnDataInfo, deviceBlockSize);
326         newLunPtnDataInfo.isGptVaild = true;
327         ufsPtnDataInfo_.push_back(newLunPtnDataInfo);
328         if (!UfsReadGpt(newLunPtnDataInfo.data, newLunPtnDataInfo.writeDataLen,
329             newLunPtnDataInfo.lunIndex, deviceBlockSize)) {
330             LOG(ERROR) << "parse ufs gpt fail";
331             return false;
332         }
333     }
334     return true;
335 }
336 
ReadAndCheckMbr(const uint32_t lunIndex,const uint32_t blockSize)337 bool UfsPtable::ReadAndCheckMbr(const uint32_t lunIndex, const uint32_t blockSize)
338 {
339     if (blockSize <= 0 || lunIndex < 0 || lunIndex > deviceLunNum_) {
340         LOG(ERROR) << "blockSize <= 0";
341         return false;
342     }
343 
344     uint8_t *buffer = new(std::nothrow) uint8_t[blockSize]();
345     if (buffer == nullptr) {
346         LOG(ERROR) << "new buffer failed!";
347         return false;
348     }
349     std::string ufsNode = GetDeviceLunNodePath(lunIndex);
350     if (!MemReadWithOffset(ufsNode, 0, buffer, blockSize)) {
351         LOG(ERROR) << "read " << blockSize << " bytes from ufsNode " << ufsNode << " failed!";
352         delete [] buffer;
353         return false;
354     }
355 
356     bool result = CheckProtectiveMbr(buffer, blockSize);
357 
358     delete [] buffer;
359     return result;
360 }
361 
GetLunNumFromNode(const std::string & ufsNode)362 int32_t UfsPtable::GetLunNumFromNode(const std::string &ufsNode)
363 {
364     if (std::char_traits<char>::length(PREFIX_UFS_NODE) + 1 != ufsNode.length()) {
365         LOG(ERROR) << "ufsNode length is " << ufsNode.length() << ", \
366             not equal to PREFIX_UFS_NODE(" << std::char_traits<char>::length(PREFIX_UFS_NODE) << ") + 1";
367         return -1;
368     }
369     char ufsLunIndex = ufsNode.back();
370     // such as : 'a' - 'a'
371     return (ufsLunIndex - 'a');
372 }
373 
LoadPartitionInfoFromLun(const uint32_t lunIndex,const uint32_t imgLen)374 bool UfsPtable::LoadPartitionInfoFromLun(const uint32_t lunIndex, const uint32_t imgLen)
375 {
376     if (imgLen == 0 || lunIndex < 0 || lunIndex > deviceLunNum_) {
377         LOG(ERROR) << "imgLen or lunIndex is invaild " << imgLen << " " << lunIndex;
378         return false;
379     }
380     std::string ufsNode = GetDeviceLunNodePath(lunIndex);
381 
382     uint8_t *buffer = new(std::nothrow) uint8_t[imgLen]();
383     if (buffer == nullptr) {
384         LOG(ERROR) << "new buffer failed!";
385         return false;
386     }
387     if (!MemReadWithOffset(ufsNode, 0, buffer, imgLen)) {
388         LOG(ERROR) << "read " << imgLen << " bytes from ufsNode " << ufsNode << " failed!";
389         delete [] buffer;
390         return false;
391     }
392     UfsPartitionDataInfo newLunPtnDataInfo;
393     newLunPtnDataInfo.isGptVaild = true;
394     newLunPtnDataInfo.lunIndex = lunIndex;
395     newLunPtnDataInfo.lunSize = imgLen;
396     newLunPtnDataInfo.writeDataLen = imgLen;
397     (void)memset_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, 0, TMP_DATA_SIZE);
398     if (memcpy_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, buffer, imgLen) != EOK) {
399         LOG(WARNING) << "memcpy_s mbr fail";
400     }
401 
402     ufsPtnDataInfo_.push_back(newLunPtnDataInfo);
403     int32_t result = UfsReadGpt(buffer, imgLen, lunIndex, GetDeviceBlockSize());
404     delete [] buffer;
405     return result;
406 }
407 
LoadAllLunPartitions()408 uint32_t UfsPtable::LoadAllLunPartitions()
409 {
410     uint32_t lunIndex;
411     for (lunIndex = 0; lunIndex < deviceLunNum_; lunIndex++) {
412         if (ReadAndCheckMbr(lunIndex, GetDeviceBlockSize())) {
413             LoadPartitionInfoFromLun(lunIndex, ptableData_.writeDeviceLunSize);
414         }
415     }
416     return lunIndex;
417 }
418 
LoadPtableFromDevice()419 bool UfsPtable::LoadPtableFromDevice()
420 {
421     if (!partitionInfo_.empty()) {
422         LOG(INFO) << "ptable is already loaded to ram";
423         return true;
424     }
425     SetDeviceLunNum();
426     if (LoadAllLunPartitions() == 0) {
427         LOG(ERROR) << "init ptable to ram fail";
428         return false;
429     }
430     LOG(INFO) << "init ptable to ram ok";
431     return true;
432 }
433 
WritePartitionTable()434 bool UfsPtable::WritePartitionTable()
435 {
436     if (ufsPtnDataInfo_.empty()) {
437         LOG(ERROR) << "ufsPtnDataInfo_ is empty, write failed!";
438         return false;
439     }
440     for (uint32_t i = 0; i < ufsPtnDataInfo_.size(); i++) {
441         uint64_t writeDataLen = ufsPtnDataInfo_[i].writeDataLen;
442         std::string ufsNode = GetDeviceLunNodePath(ufsPtnDataInfo_[i].lunIndex);
443         LOG(INFO) << "ufs node name:" << ufsNode << ", writeDataLen = " << writeDataLen;
444 
445         if (!ufsPtnDataInfo_[i].isGptVaild) {
446             LOG(WARNING) <<  "invaild ptable, no need to update";
447             continue;
448         }
449         if (!WriteBufferToPath(ufsNode, 0, ufsPtnDataInfo_[i].data, writeDataLen)) {
450             LOG(ERROR) << "write first gpt fail";
451             return false;
452         }
453 #ifndef UPDATER_UT
454         if (hasBackupPtable_) {
455             LOG(INFO) << "should write back up ptable to device";
456             uint64_t lunSize = GetDeviceLunCapacity(ufsPtnDataInfo_[i].lunIndex);
457             WriteBackupPartitionTable(ufsPtnDataInfo_[i].lunIndex, lunSize);
458         }
459 #endif
460     }
461     return true;
462 }
463 
WriteBackupPartitionTable(uint32_t lunIdx,uint64_t lunSize)464 bool UfsPtable::WriteBackupPartitionTable(uint32_t lunIdx, uint64_t lunSize)
465 {
466     if (lunIdx >= ufsPtnDataInfo_.size()) {
467         LOG(ERROR) << "lunIdx invalid , lunIdx = " << lunIdx << ", ufsPtnDataInfo size = " << ufsPtnDataInfo_.size();
468         return false;
469     }
470 
471     std::string ufsNode = GetDeviceLunNodePath(lunIdx);
472     uint32_t deviceBlockSize = GetDeviceBlockSize();
473     if (lunSize == 0 || lunSize <= GPT_PTABLE_BACKUP_SIZE * deviceBlockSize) {
474         LOG(ERROR) << "lun size invalid, lun size = " << lunSize;
475         return false;
476     }
477     if (deviceBlockSize == 0) {
478         LOG(ERROR) << "deviceBlockSize is invalid";
479         return false;
480     }
481     uint64_t deviceBackGptEntryOffset = lunSize - GPT_PTABLE_BACKUP_SIZE * deviceBlockSize;
482     uint64_t deviceBackGptHeaderOffset = lunSize - deviceBlockSize;
483     std::unique_ptr<uint8_t[]> backUpHeader = std::make_unique<uint8_t[]>(deviceBlockSize);
484     if (memcpy_s(backUpHeader.get(), deviceBlockSize, ufsPtnDataInfo_[lunIdx].data +
485         deviceBlockSize, deviceBlockSize) != EOK) {
486         LOG(ERROR) << "memcpy error, deviceBlockSize:" << deviceBlockSize;
487         return false;
488     }
489     PatchBackUpGptHeader(backUpHeader.get(), deviceBlockSize, deviceBackGptEntryOffset / deviceBlockSize);
490     if (!WriteBufferToPath(ufsNode, deviceBackGptHeaderOffset, backUpHeader.get(), deviceBlockSize)) {
491         LOG(ERROR) << "write back up gpt header failed, deviceBackGptHeaderOffset = " << deviceBackGptHeaderOffset
492             << ", deviceBlockSize = " << deviceBlockSize;
493         return false;
494     }
495 
496     if (!WriteBufferToPath(ufsNode, deviceBackGptEntryOffset, ufsPtnDataInfo_[lunIdx].data +
497         deviceBlockSize * 2, (GPT_PTABLE_BACKUP_SIZE - 1) * deviceBlockSize)) { // 2 : pmbr(1) + gpt header(1)
498         LOG(ERROR) << "write back up gpt entries failed, deviceBackGptEntryOffset = " << deviceBackGptEntryOffset
499             << ", deviceBlockSize = " << deviceBlockSize;
500         return false;
501     }
502     LOG(INFO) << "write backup partition table successful";
503     return true;
504 }
505 
GetPtableImageUfsLunPmbrStart(uint8_t * imageBuf,const uint32_t lunIndex)506 uint8_t *UfsPtable::GetPtableImageUfsLunPmbrStart(uint8_t *imageBuf, const uint32_t lunIndex)
507 {
508     uint32_t pmbrStart = ptableData_.emmcGptDataLen + GetPtableExtraOffset() + lunIndex * ptableData_.imgLuSize;
509     LOG(INFO) << "GetPtableImageUfsLunPmbrStart : " << std::hex << pmbrStart << std::dec;
510     return imageBuf + pmbrStart;
511 }
512 
GetPtableImageUfsLunGptHeaderStart(uint8_t * imageBuf,const uint32_t lunIndex)513 uint8_t *UfsPtable::GetPtableImageUfsLunGptHeaderStart(uint8_t *imageBuf, const uint32_t lunIndex)
514 {
515     uint32_t gptHeaderStart = ptableData_.emmcGptDataLen + GetPtableExtraOffset() + lunIndex * ptableData_.imgLuSize +
516         ptableData_.lbaLen;
517     LOG(INFO) << "GetPtableImageUfsLunGptHeaderStart : " << std::hex << gptHeaderStart << std::dec;
518     return imageBuf + gptHeaderStart;
519 }
520 
GetPtableImageUfsLunEntryStart(uint8_t * imageBuf,const uint32_t lunIndex)521 uint8_t *UfsPtable::GetPtableImageUfsLunEntryStart(uint8_t *imageBuf, const uint32_t lunIndex)
522 {
523     uint32_t entryStart = ptableData_.emmcGptDataLen + GetPtableExtraOffset() + lunIndex * ptableData_.imgLuSize +
524         ptableData_.lbaLen + ptableData_.gptHeaderLen;
525     LOG(INFO) << "GetPtableImageUfsLunEntryStart : " << std::hex << entryStart << std::dec;
526     return imageBuf + entryStart;
527 }
528 
CorrectBufByPtnList(uint8_t * imageBuf,uint64_t imgBufSize,const std::vector<PtnInfo> & srcInfo,const std::vector<PtnInfo> & dstInfo)529 bool UfsPtable::CorrectBufByPtnList(uint8_t *imageBuf, uint64_t imgBufSize, const std::vector<PtnInfo> &srcInfo,
530                                     const std::vector<PtnInfo> &dstInfo)
531 {
532     int srcSize = static_cast<int>(srcInfo.size());
533     int dstSize = static_cast<int>(dstInfo.size());
534     if (imageBuf == nullptr || imgBufSize == 0 || srcSize != dstSize) {
535         LOG(ERROR) << "invalid input. imgBufSize : " << imgBufSize << " srcInfo.size: " << srcSize
536                    << " dstInfo.size:" << dstSize;
537         return false;
538     }
539     if (usrDataPtnIndex_ < 0 || endPtnIndex_ < 0 || usrDataPtnIndex_ >= dstSize ||
540         endPtnIndex_ >= dstSize) {
541         LOG(ERROR) << "invaild dst ptn info list";
542         return false;
543     }
544     uint8_t* ufsLunEntryStart = GetPtableImageUfsLunEntryStart(imageBuf, dstInfo[usrDataPtnIndex_].lun);
545     const uint32_t editLen = PARTITION_ENTRY_SIZE * MAX_PARTITION_NUM;
546     std::vector<uint8_t> newBuf(ufsLunEntryStart, ufsLunEntryStart + editLen);
547     for (int i = startPtnIndex_; i <= endPtnIndex_; i++) {
548         if (srcInfo[i].startAddr == dstInfo[i].startAddr && srcInfo[i].partitionSize == dstInfo[i].partitionSize
549             && srcInfo[i].dispName == dstInfo[i].dispName) {
550             continue;
551         }
552         LOG(INFO) << srcInfo[i].dispName << "should adjust";
553         std::vector<uint8_t> newEntryBuf(ufsLunEntryStart + dstInfo[i].gptEntryBufOffset,
554                                          ufsLunEntryStart + dstInfo[i].gptEntryBufOffset + PARTITION_ENTRY_SIZE);
555         PUT_LONG_LONG(newEntryBuf.data() + FIRST_LBA_OFFSET, dstInfo[i].startAddr / GetDeviceBlockSize());
556         PUT_LONG_LONG(newEntryBuf.data() + LAST_LBA_OFFSET,
557                       (dstInfo[i].startAddr + dstInfo[i].partitionSize) / GetDeviceBlockSize() - 1);
558         if (srcInfo[i].gptEntryBufOffset > static_cast<int>(editLen - PARTITION_ENTRY_SIZE)) {
559             LOG(ERROR) << "srcInfo[" << i << "] error. gptEntryBufOffset = " << srcInfo[i].gptEntryBufOffset;
560             return false;
561         }
562         std::copy(newEntryBuf.begin(), newEntryBuf.end(), newBuf.begin() + srcInfo[i].gptEntryBufOffset);
563     }
564     if (memcpy_s(ufsLunEntryStart, imgBufSize - (ufsLunEntryStart - imageBuf), newBuf.data(), editLen) != 0) {
565         LOG(ERROR) << "memcpy fail. destSize :" << imgBufSize - (ufsLunEntryStart - imageBuf);
566         return false;
567     }
568     return true;
569 }
570 
EditPartitionBuf(uint8_t * imageBuf,uint64_t imgBufSize,std::vector<PtnInfo> & modifyList)571 bool UfsPtable::EditPartitionBuf(uint8_t *imageBuf, uint64_t imgBufSize, std::vector<PtnInfo> &modifyList)
572 {
573     if (imageBuf == nullptr || imgBufSize == 0 || modifyList.empty() || ptableData_.blockSize == 0) {
574         LOG(ERROR) << "input invalid";
575         return false;
576     }
577     if (imgBufSize < ptableData_.emmcGptDataLen || deviceLunNum_ == 0) {
578         LOG(ERROR) << "can not get offset, imgBufsize =" << imgBufSize << ",emmcGptDataLen ="
579             << ptableData_.emmcGptDataLen << ", deviceLunNum = " << deviceLunNum_;
580         return false;
581     }
582 
583     uint32_t gptSize = ptableData_.imgLuSize;
584     uint32_t imgBlockSize = ptableData_.lbaLen; // 512
585     uint32_t deviceBlockSize = GetDeviceBlockSize(); // 4096 or 512
586     uint32_t startLu = ptableData_.startLunNumber;
587     for (uint32_t i = 0; i < deviceLunNum_; ++i) {
588         UfsPartitionDataInfo newLunPtnDataInfo;
589         (void)memset_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, 0, TMP_DATA_SIZE);
590         std::string ufsNode = GetDeviceLunNodePath(i + startLu);
591         newLunPtnDataInfo.lunSize = GetDeviceLunCapacity(i + startLu);
592         if (newLunPtnDataInfo.lunSize == 0) {
593             LOG(ERROR) << "get devDenisity failed in " << ufsNode;
594             return false;
595         }
596         uint8_t *curGptBuf = GetPtableImageUfsLunPmbrStart(imageBuf, i + startLu);
597         if (!ufsPtnDataInfo_[i].isGptVaild) {
598             continue;
599         }
600         struct GptParseInfo gptInfo(imgBlockSize, deviceBlockSize, newLunPtnDataInfo.lunSize -
601             (hasBackupPtable_ ? (GPT_PTABLE_BACKUP_SIZE * deviceBlockSize) : 0));
602         for (auto &t : modifyList) {
603             if (static_cast<uint32_t>(t.lun) == i + startLu && !ChangeGpt(curGptBuf, gptSize, gptInfo, t)) {
604                 LOG(ERROR) << "ChangeGpt failed";
605                 return false;
606             }
607         }
608         /* mbr block = 1 block */
609         if (memcpy_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, curGptBuf, imgBlockSize) != EOK) {
610             LOG(WARNING) << "memcpy_s fail";
611         }
612         newLunPtnDataInfo.writeDataLen = ptableData_.writeDeviceLunSize;
613         UfsPatchGptHeader(newLunPtnDataInfo, imgBlockSize);
614     }
615     return true;
616 }
617 
GetPtableImageBuffer(uint8_t * imageBuf,const uint32_t imgBufSize)618 bool UfsPtable::GetPtableImageBuffer(uint8_t *imageBuf, const uint32_t imgBufSize)
619 {
620     uint32_t imgBlockSize = ptableData_.lbaLen; // 512
621     uint32_t deviceBlockSize = GetDeviceBlockSize();
622     SetDeviceLunNum();
623     if (imageBuf == nullptr || imgBufSize == 0 ||
624         imgBufSize < ptableData_.emmcGptDataLen + GetPtableExtraOffset() + ptableData_.imgLuSize * deviceLunNum_) {
625         LOG(ERROR) << "input param invalid";
626         return false;
627     }
628     for (uint32_t i = 0; i < deviceLunNum_; ++i) {
629         uint32_t curImgOffset = 0;
630         uint32_t curDevOffset = 0;
631         uint32_t imgOffset = ptableData_.emmcGptDataLen + GetPtableExtraOffset() + ptableData_.imgLuSize * i;
632         /* get ufs node name */
633         std::string ufsNode = GetDeviceLunNodePath(i + ptableData_.startLunNumber);
634         if (!CheckFileExist(ufsNode)) {
635             LOG(ERROR) << "file " << ufsNode << " is not exist";
636             return false;
637         }
638         /* get mbr head */
639         if (!MemReadWithOffset(ufsNode, curDevOffset, imageBuf + curImgOffset + imgOffset, imgBlockSize)) {
640             LOG(ERROR) << "MemReadWithOffset " << ufsNode << " error";
641             return false;
642         }
643         bool isGptExist = CheckProtectiveMbr(imageBuf + curImgOffset + imgOffset, imgBlockSize);
644         curImgOffset += imgBlockSize;
645         curDevOffset += deviceBlockSize;
646         if (!isGptExist) {
647             continue;
648         }
649         /* get gpt head */
650         if (!MemReadWithOffset(ufsNode, curDevOffset, imageBuf + curImgOffset + imgOffset, imgBlockSize)) {
651             LOG(ERROR) << "MemReadWithOffset " << ufsNode << " error";
652             return false;
653         }
654         uint32_t maxPartCount = GET_LWORD_FROM_BYTE(&imageBuf[imgOffset + curImgOffset + PARTITION_COUNT_OFFSET]);
655         uint32_t entrySize = GET_LWORD_FROM_BYTE(&imageBuf[imgOffset + curImgOffset + PENTRY_SIZE_OFFSET]);
656         curImgOffset += imgBlockSize;
657         curDevOffset += deviceBlockSize;
658         /* get gpt buf */
659         uint32_t gptInfoLen = maxPartCount * entrySize;
660         if (!MemReadWithOffset(ufsNode, curDevOffset, imageBuf + curImgOffset + imgOffset, gptInfoLen)) {
661             LOG(ERROR) << "MemReadWithOffset " << ufsNode << " error" << gptInfoLen;
662             return false;
663         }
664     }
665     return true;
666 }
667 } // namespace Updater
668