• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ufs_ptable.h"
17 
18 #include <algorithm>
19 #include <fcntl.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 
23 #include "log/log.h"
24 #include "securec.h"
25 #include "updater/updater_const.h"
26 
27 namespace Updater {
GetDeviceLunNum()28 uint32_t UfsPtable::GetDeviceLunNum()
29 {
30     return deviceLunNum_;
31 }
32 
GetDeviceLunCapacity(const uint32_t lunIndex)33 uint64_t UfsPtable::GetDeviceLunCapacity(const uint32_t lunIndex)
34 {
35     char lunIndexName = 'a' + lunIndex;
36     std::string capacityPath = std::string(PREFIX_SYS_CLASS_BLOCK) + lunIndexName + "/size";
37     uint64_t capacity = 0;
38     GetCapacity(capacityPath, capacity);
39     return capacity;
40 }
41 
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