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