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