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
SetDeviceLunNum()42 void UfsPtable::SetDeviceLunNum()
43 {
44 if (deviceLunNum_ > 0) {
45 return;
46 }
47 uint32_t lunIndex;
48 for (lunIndex = 0; lunIndex < MAX_LUN_NUMBERS; lunIndex++) {
49 char lunIndexName = 'a' + lunIndex;
50 std::string ufsNode = std::string(PREFIX_UFS_NODE) + lunIndexName;
51 if (!CheckFileExist(ufsNode)) {
52 LOG(ERROR) << "file " << ufsNode << " is not exist";
53 break;
54 }
55 }
56 deviceLunNum_ = lunIndex;
57 return;
58 }
59
ParseGptHeaderByUfsLun(const uint8_t * gptImage,const uint32_t len,const uint32_t lun,const uint32_t blockSize)60 bool UfsPtable::ParseGptHeaderByUfsLun(const uint8_t *gptImage, const uint32_t len,
61 const uint32_t lun, const uint32_t blockSize)
62 {
63 GPTHeaderInfo gptHeaderInfo;
64 (void)memset_s(&gptHeaderInfo, sizeof(GPTHeaderInfo), 0, sizeof(GPTHeaderInfo));
65 if (!GetPartitionGptHeaderInfo(gptImage + blockSize, blockSize, gptHeaderInfo)) {
66 LOG(ERROR) << "GetPartitionGptHeaderInfo fail";
67 return false;
68 }
69 uint64_t lunDeviceSize = GetDeviceLunCapacity(lun);
70 uint32_t lunLbaNum = lunDeviceSize / MIN_UFS_WRITE_SIZE;
71 return PartitionCheckGptHeader(gptImage, len, lunLbaNum, blockSize, gptHeaderInfo);
72 }
73
UfsReadGpt(const uint8_t * gptImage,const uint32_t len,const uint32_t lun,const uint32_t blockSize)74 bool UfsPtable::UfsReadGpt(const uint8_t *gptImage, const uint32_t len,
75 const uint32_t lun, const uint32_t blockSize)
76 {
77 if (gptImage == nullptr || len < ptableData_.writeDeviceLunSize || lun >= MAX_LUN_NUMBERS || blockSize == 0) {
78 LOG(ERROR) << "invaild input";
79 return false;
80 }
81 if (!ParseGptHeaderByUfsLun(gptImage, len, lun, blockSize)) {
82 LOG(ERROR) << "Primary signature invalid";
83 return false;
84 }
85
86 uint32_t partEntryCnt = blockSize / PARTITION_ENTRY_SIZE;
87 uint32_t partition0 = GET_LLWORD_FROM_BYTE(gptImage + blockSize + PARTITION_ENTRIES_OFFSET);
88
89 uint32_t count = 0;
90 const uint8_t *data = nullptr;
91 for (uint32_t i = 0; i < (MAX_PARTITION_NUM / partEntryCnt) && count < MAX_PARTITION_NUM; i++) {
92 data = gptImage + (partition0 + i) * blockSize;
93 for (uint32_t j = 0; j < partEntryCnt; j++) {
94 uint8_t typeGuid[GPT_PARTITION_TYPE_GUID_LEN] = {0};
95 if (memcpy_s(typeGuid, sizeof(typeGuid), &data[(j * PARTITION_ENTRY_SIZE)], sizeof(typeGuid)) != EOK) {
96 LOG(ERROR) << "memcpy guid fail";
97 }
98 if (typeGuid[0] == 0x00 && typeGuid[1] == 0x00) { // 0x00 means no partition
99 i = MAX_PARTITION_NUM / partEntryCnt;
100 break;
101 }
102 uint64_t firstLba = GET_LLWORD_FROM_BYTE(&data[(j * PARTITION_ENTRY_SIZE) + FIRST_LBA_OFFSET]);
103 uint64_t lastLba = GET_LLWORD_FROM_BYTE(&data[(j * PARTITION_ENTRY_SIZE) + LAST_LBA_OFFSET]);
104 // add a new partition info into partitionInfo_ vector
105 PtnInfo newPtnInfo;
106 (void)memset_s(&newPtnInfo, sizeof(newPtnInfo), 0, sizeof(newPtnInfo));
107 newPtnInfo.startAddr = firstLba * static_cast<uint64_t>(MIN_UFS_WRITE_SIZE);
108 // General algorithm : calculate partition size by lba
109 newPtnInfo.partitionSize = (lastLba - firstLba + 1) * static_cast<uint64_t>(MIN_UFS_WRITE_SIZE);
110 const uint8_t *nameOffset = data + (j * PARTITION_ENTRY_SIZE + GPT_PARTITION_NAME_OFFSET);
111 // 2 bytes for 1 charactor of partition name
112 ParsePartitionName(nameOffset, MAX_GPT_NAME_SIZE, newPtnInfo.dispName, MAX_GPT_NAME_SIZE / 2);
113 (void)memcpy_s(newPtnInfo.partitionTypeGuid, sizeof(newPtnInfo.partitionTypeGuid),
114 typeGuid, sizeof(typeGuid));
115 newPtnInfo.lun = lun;
116 partitionInfo_.push_back(newPtnInfo);
117 count++;
118 }
119 }
120 return true;
121 }
122
123
UfsPatchGptHeader(UfsPartitionDataInfo & ptnDataInfo,const uint32_t blockSize)124 void UfsPtable::UfsPatchGptHeader(UfsPartitionDataInfo &ptnDataInfo, const uint32_t blockSize)
125 {
126 // mbr len + gptHeader len = 2 blockSize
127 if (blockSize == 0 || ptnDataInfo.writeDataLen < 2 * blockSize || ptnDataInfo.lunSize == 0) {
128 LOG(ERROR) << "invaild argument";
129 return;
130 }
131 uint64_t cardSizeSector = ptnDataInfo.lunSize / MIN_UFS_WRITE_SIZE;
132 if (cardSizeSector == 0) {
133 cardSizeSector = DEFAULT_SECTOR_NUM;
134 }
135 // Patching primary header
136 uint8_t *primaryGptHeader = ptnDataInfo.data + blockSize;
137 PUT_LONG_LONG(primaryGptHeader + BACKUP_HEADER_OFFSET, (cardSizeSector - 1));
138 PUT_LONG_LONG(primaryGptHeader + LAST_USABLE_LBA_OFFSET, (cardSizeSector - 1));
139 // Find last partition
140 uint32_t totalPart = 0;
141 while (((TMP_DATA_SIZE - blockSize - blockSize) > totalPart * PARTITION_ENTRY_SIZE) &&
142 (*(primaryGptHeader + blockSize + totalPart * PARTITION_ENTRY_SIZE) != 0)) {
143 totalPart++;
144 }
145 if (totalPart == 0) {
146 LOG(ERROR) << "no partition exist";
147 return;
148 }
149 // Patching last partition
150 uint8_t *lastPartOffset = primaryGptHeader + blockSize + (totalPart - 1) * PARTITION_ENTRY_SIZE;
151 uint64_t lastLba = GET_LLWORD_FROM_BYTE(lastPartOffset + PARTITION_ENTRY_LAST_LBA);
152 uint64_t firstLba = GET_LLWORD_FROM_BYTE(lastPartOffset + FIRST_LBA_OFFSET);
153 // General algorithm : calculate partition size by lba
154 uint64_t partitionSize = (lastLba - firstLba + 1) * MIN_UFS_WRITE_SIZE;
155 std::string partitionName;
156 uint8_t *nameOffset = lastPartOffset + GPT_PARTITION_NAME_OFFSET;
157 // 2 bytes for 1 charactor of partition name
158 ParsePartitionName(nameOffset, MAX_GPT_NAME_SIZE, partitionName, MAX_GPT_NAME_SIZE / 2);
159 if (partitionName == USERDATA_PARTITION || (totalPart == 1 && partitionSize == 0)) {
160 // patch userdata or only one partition
161 PUT_LONG_LONG(lastPartOffset + PARTITION_ENTRY_LAST_LBA, (cardSizeSector - 1));
162 LOG(INFO) << "partitionSize=" << partitionSize << ", partition_name:" << partitionName;
163 }
164
165 // Updating CRC of the Partition entry array in both headers
166 uint32_t partCount = GET_LWORD_FROM_BYTE(primaryGptHeader + PARTITION_COUNT_OFFSET);
167 uint32_t entrySize = GET_LWORD_FROM_BYTE(primaryGptHeader + PENTRY_SIZE_OFFSET);
168 // mbr len + gptHeader len = 2 blockSize
169 uint32_t crcValue = CalculateCrc32(ptnDataInfo.data + (blockSize * 2), partCount * entrySize);
170 PUT_LONG(primaryGptHeader + PARTITION_CRC_OFFSET, crcValue);
171 // Clearing CRC fields to calculate
172 PUT_LONG(primaryGptHeader + HEADER_CRC_OFFSET, 0);
173 crcValue = CalculateCrc32(primaryGptHeader, GPT_CRC_LEN);
174 PUT_LONG(primaryGptHeader + HEADER_CRC_OFFSET, crcValue);
175 return;
176 }
177
178 // 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)179 bool UfsPtable::ParsePartitionFromBuffer(uint8_t *ptbImgBuffer, const uint32_t imgBufSize)
180 {
181 if (ptbImgBuffer == nullptr) {
182 LOG(ERROR) << "input param invalid";
183 return false;
184 }
185
186 uint32_t imgBlockSize = ptableData_.lbaLen; // 512
187 uint32_t deviceBlockSize = ptableData_.blockSize; // 4096
188 if (imgBufSize < ptableData_.emmcGptDataLen + ptableData_.imgLuSize) {
189 LOG(ERROR) << "input param invalid imgBufSize";
190 return false;
191 }
192
193 SetDeviceLunNum();
194 LOG(INFO) << "lun number of ptable:" << deviceLunNum_;
195
196 for (uint32_t i = 0; i < deviceLunNum_; i++) {
197 UfsPartitionDataInfo newLunPtnDataInfo;
198 (void)memset_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, 0, TMP_DATA_SIZE);
199 uint8_t *lunStart = GetPtableImageUfsLunPmbrStart(ptbImgBuffer, i);
200 uint8_t *gptHeaderStart = GetPtableImageUfsLunGptHeaderStart(ptbImgBuffer, i);
201 // first block is mbr, second block is gptHeader
202 if (!CheckProtectiveMbr(lunStart, imgBlockSize) || !CheckIfValidGpt(gptHeaderStart, imgBlockSize)) {
203 newLunPtnDataInfo.isGptVaild = false;
204 ufsPtnDataInfo_.push_back(newLunPtnDataInfo);
205 continue;
206 }
207 // for hisi: change ptable.img(512 bytes/block) into format of device(4096 bytes/block)
208 if (memcpy_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, lunStart, imgBlockSize) != EOK) {
209 LOG(WARNING) << "memcpy_s pmbr fail";
210 }
211 if (memcpy_s(newLunPtnDataInfo.data + deviceBlockSize, TMP_DATA_SIZE - deviceBlockSize,
212 gptHeaderStart, imgBlockSize) != EOK) {
213 LOG(WARNING) << "memcpy_s gpt header fail";
214 }
215 // skip 2 lba length to set gpt entry
216 if (memcpy_s(newLunPtnDataInfo.data + 2 * deviceBlockSize, TMP_DATA_SIZE - 2 * deviceBlockSize,
217 GetPtableImageUfsLunEntryStart(ptbImgBuffer, i), GPT_ENTRYS_SIZE) != EOK) {
218 LOG(WARNING) << "memcpy_s gpt data fail";
219 }
220 newLunPtnDataInfo.writeDataLen = ptableData_.writeDeviceLunSize;
221 newLunPtnDataInfo.lunIndex = i + ptableData_.startLunNumber;
222 newLunPtnDataInfo.lunSize = GetDeviceLunCapacity(newLunPtnDataInfo.lunIndex);
223 UfsPatchGptHeader(newLunPtnDataInfo, deviceBlockSize);
224 newLunPtnDataInfo.isGptVaild = true;
225 ufsPtnDataInfo_.push_back(newLunPtnDataInfo);
226 if (!UfsReadGpt(newLunPtnDataInfo.data, newLunPtnDataInfo.writeDataLen,
227 newLunPtnDataInfo.lunIndex, deviceBlockSize)) {
228 LOG(ERROR) << "parse ufs gpt fail";
229 return false;
230 }
231 }
232 return true;
233 }
234
ReadAndCheckMbr(const uint32_t lunIndex,const uint32_t blockSize)235 bool UfsPtable::ReadAndCheckMbr(const uint32_t lunIndex, const uint32_t blockSize)
236 {
237 if (blockSize <= 0 || lunIndex < 0 || lunIndex > deviceLunNum_) {
238 LOG(ERROR) << "blockSize <= 0";
239 return false;
240 }
241
242 uint8_t *buffer = new(std::nothrow) uint8_t[blockSize]();
243 if (buffer == nullptr) {
244 LOG(ERROR) << "new buffer failed!";
245 return false;
246 }
247 char lunIndexName = 'a' + lunIndex;
248 std::string ufsNode = std::string(PREFIX_UFS_NODE) + lunIndexName;
249 if (!MemReadWithOffset(ufsNode, 0, buffer, blockSize)) {
250 LOG(ERROR) << "read " << blockSize << " bytes from ufsNode " << ufsNode << " failed!";
251 delete [] buffer;
252 return false;
253 }
254
255 bool result = CheckProtectiveMbr(buffer, blockSize);
256
257 delete [] buffer;
258 return result;
259 }
260
GetLunNumFromNode(const std::string & ufsNode)261 int32_t UfsPtable::GetLunNumFromNode(const std::string &ufsNode)
262 {
263 if (std::char_traits<char>::length(PREFIX_UFS_NODE) + 1 != ufsNode.length()) {
264 LOG(ERROR) << "ufsNode length is " << ufsNode.length() << ", \
265 not equal to PREFIX_UFS_NODE(" << std::char_traits<char>::length(PREFIX_UFS_NODE) << ") + 1";
266 return -1;
267 }
268 char ufsLunIndex = ufsNode.back();
269 // such as : 'a' - 'a'
270 return (ufsLunIndex - 'a');
271 }
272
LoadPartitionInfoFromLun(const uint32_t lunIndex,const uint32_t imgLen)273 bool UfsPtable::LoadPartitionInfoFromLun(const uint32_t lunIndex, const uint32_t imgLen)
274 {
275 if (imgLen == 0 || lunIndex < 0 || lunIndex > deviceLunNum_) {
276 LOG(ERROR) << "imgLen or lunIndex is invaild";
277 return false;
278 }
279 char lunIndexName = 'a' + lunIndex;
280 std::string ufsNode = std::string(PREFIX_UFS_NODE) + lunIndexName;
281
282 uint8_t *buffer = new(std::nothrow) uint8_t[imgLen]();
283 if (buffer == nullptr) {
284 LOG(ERROR) << "new buffer failed!";
285 return false;
286 }
287 if (!MemReadWithOffset(ufsNode, 0, buffer, imgLen)) {
288 LOG(ERROR) << "read " << imgLen << " bytes from ufsNode " << ufsNode << " failed!";
289 delete [] buffer;
290 return false;
291 }
292 UfsPartitionDataInfo newLunPtnDataInfo;
293 newLunPtnDataInfo.isGptVaild = true;
294 newLunPtnDataInfo.lunIndex = lunIndex;
295 newLunPtnDataInfo.lunSize = imgLen;
296 newLunPtnDataInfo.writeDataLen = imgLen;
297 (void)memset_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, 0, TMP_DATA_SIZE);
298 if (memcpy_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, buffer, imgLen) != EOK) {
299 LOG(WARNING) << "memcpy_s mbr fail";
300 }
301
302 ufsPtnDataInfo_.push_back(newLunPtnDataInfo);
303 int32_t result = UfsReadGpt(buffer, imgLen, lunIndex, MIN_UFS_WRITE_SIZE);
304 delete [] buffer;
305 return result;
306 }
307
LoadAllLunPartitions()308 uint32_t UfsPtable::LoadAllLunPartitions()
309 {
310 uint32_t lunIndex;
311 for (lunIndex = 0; lunIndex < deviceLunNum_; lunIndex++) {
312 if (ReadAndCheckMbr(lunIndex, MIN_UFS_WRITE_SIZE)) {
313 LoadPartitionInfoFromLun(lunIndex, ptableData_.writeDeviceLunSize);
314 }
315 }
316 return lunIndex;
317 }
318
LoadPtableFromDevice()319 bool UfsPtable::LoadPtableFromDevice()
320 {
321 if (!partitionInfo_.empty()) {
322 LOG(INFO) << "ptable is already loaded to ram";
323 return true;
324 }
325 SetDeviceLunNum();
326 if (LoadAllLunPartitions() == 0) {
327 LOG(ERROR) << "init ptable to ram fail";
328 return false;
329 }
330 LOG(INFO) << "init ptable to ram ok";
331 return true;
332 }
333
WritePartitionTable()334 bool UfsPtable::WritePartitionTable()
335 {
336 if (ufsPtnDataInfo_.empty()) {
337 LOG(ERROR) << "ufsPtnDataInfo_ is empty, write failed!";
338 return false;
339 }
340 for (uint32_t i = 0; i < ufsPtnDataInfo_.size(); i++) {
341 uint64_t writeDataLen = ufsPtnDataInfo_[i].writeDataLen;
342 char lunIndexName = 'a' + ufsPtnDataInfo_[i].lunIndex;
343 std::string ufsNode = std::string(PREFIX_UFS_NODE) + lunIndexName;
344 LOG(INFO) << "ufs node name:" << ufsNode << ", writeDataLen = " << writeDataLen;
345
346 if (!ufsPtnDataInfo_[i].isGptVaild) {
347 LOG(WARNING) << "invaild ptable, no need to update";
348 continue;
349 }
350 if (!WriteBufferToPath(ufsNode, 0, ufsPtnDataInfo_[i].data, writeDataLen)) {
351 LOG(ERROR) << "write first gpt fail";
352 return false;
353 }
354 }
355 return true;
356 }
357
GetPtableImageUfsLunPmbrStart(uint8_t * imageBuf,const uint32_t lunIndex)358 uint8_t *UfsPtable::GetPtableImageUfsLunPmbrStart(uint8_t *imageBuf, const uint32_t lunIndex)
359 {
360 uint32_t pmbrStart = ptableData_.emmcGptDataLen + lunIndex * ptableData_.imgLuSize;
361 LOG(INFO) << "GetPtableImageUfsLunPmbrStart : " << std::hex << pmbrStart << std::dec;
362 return imageBuf + pmbrStart;
363 }
364
GetPtableImageUfsLunGptHeaderStart(uint8_t * imageBuf,const uint32_t lunIndex)365 uint8_t *UfsPtable::GetPtableImageUfsLunGptHeaderStart(uint8_t *imageBuf, const uint32_t lunIndex)
366 {
367 uint32_t gptHeaderStart = ptableData_.emmcGptDataLen + lunIndex * ptableData_.imgLuSize + ptableData_.lbaLen;
368 LOG(INFO) << "GetPtableImageUfsLunGptHeaderStart : " << std::hex << gptHeaderStart << std::dec;
369 return imageBuf + gptHeaderStart;
370 }
371
GetPtableImageUfsLunEntryStart(uint8_t * imageBuf,const uint32_t lunIndex)372 uint8_t *UfsPtable::GetPtableImageUfsLunEntryStart(uint8_t *imageBuf, const uint32_t lunIndex)
373 {
374 uint32_t entryStart = ptableData_.emmcGptDataLen + lunIndex * ptableData_.imgLuSize +
375 ptableData_.lbaLen + ptableData_.gptHeaderLen;
376 LOG(INFO) << "GetPtableImageUfsLunEntryStart : " << std::hex << entryStart << std::dec;
377 return imageBuf + entryStart;
378 }
379 } // namespace Updater
380