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