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 #ifndef UPDATER_PTABLE_H
17 #define UPDATER_PTABLE_H
18 #define LAST_PATITION_NAME "USERDATA"
19 
20 #include "macros_updater.h"
21 #include "json_node.h"
22 
23 namespace Updater {
24 class Ptable {
25 public:
26     Ptable() = default;
27     DISALLOW_COPY_MOVE(Ptable);
~Ptable()28     virtual ~Ptable() {}
29 
30     static constexpr uint32_t GPT_PARTITION_TYPE_GUID_LEN = 16;
31     static constexpr const char *PREFIX_SYS_CLASS_BLOCK = "/sys/class/block/sd";
32 
33     struct PtnInfo {
34         uint64_t startAddr {};
35         uint64_t partitionSize {};
36         uint8_t partitionTypeGuid[GPT_PARTITION_TYPE_GUID_LEN] {};
37         uint32_t lun {};
38         std::string dispName {};
39         std::string writeMode {"WRITE_RAW"};
40         std::string writePath {};
41     };
42 
43     struct GptParseInfo {
GptParseInfoGptParseInfo44     GptParseInfo(uint64_t imgBlockSize, uint64_t devBlockSize, uint64_t devDensity)
45         : imgBlockSize(imgBlockSize), devBlockSize(devBlockSize), devDensity(devDensity) {}
46     uint64_t imgBlockSize;
47     uint64_t devBlockSize;
48     uint64_t devDensity;
49     };
50     std::vector<PtnInfo> GetPtablePartitionInfo() const;
51     uint32_t GetPtablePartitionNum() const;
52     void SetReservedSize(uint64_t reservedSize);
53     bool InitPtable();
54     uint32_t GetDefaultImageSize() const;
55     void PrintPtableInfo() const;
56     void PrintPtableInfo(const std::vector<PtnInfo> &ptnInfo) const;
57     bool GetPartionInfoByName(const std::string &partitionName, PtnInfo &ptnInfo, int32_t &index);
58     std::vector<PtnInfo>& GetPtablePartitionInfoInstance();
59     bool LoadPtnInfo(const std::vector<PtnInfo>& ptnInfo);
60 
61     virtual bool ParsePartitionFromBuffer(uint8_t *ptbImgBuffer, const uint32_t imgBufSize) = 0;
62     virtual bool LoadPtableFromDevice() = 0;
63     virtual bool WritePartitionTable() = 0;
64     virtual bool EditPartitionBuf(uint8_t *imageBuf, uint64_t imgBufSize, std::vector<PtnInfo> &modifyList) = 0;
65     virtual bool GetPtableImageBuffer(uint8_t *imageBuf, const uint32_t imgBufSize) = 0;
AddChildPtable(std::unique_ptr<Ptable> child)66     virtual void AddChildPtable(std::unique_ptr<Ptable> child) {}
67 
68 #ifndef UPDATER_UT
69 protected:
70 #else
71 public:
72 #endif
73     const std::string USERDATA_PARTITION = "USERDATA";
74     static constexpr uint32_t PARTITION_ENTRY_SIZE = 128;
75     static constexpr uint32_t MAX_PARTITION_NUM = 128;
76     static constexpr uint32_t FIRST_LBA_OFFSET = 32;
77     static constexpr uint32_t LAST_LBA_OFFSET = 40;
78     static constexpr uint32_t GPT_PARTITION_NAME_OFFSET = 56;
79     static constexpr uint32_t MAX_GPT_NAME_SIZE = 72;
80     static constexpr uint32_t PARTITION_ENTRIES_OFFSET = 72;
81     static constexpr uint32_t PARTITION_CRC_OFFSET = 88;
82     static constexpr uint32_t GPT_DISP_NAME_LEN = 32;
83     static constexpr uint64_t DEFAULT_SECTOR_NUM = (4 * 1024 * 1024 * 2 - 1);
84     static constexpr uint32_t GPT_HEADER_OFFSET = 24;
85     static constexpr uint32_t BACKUP_HEADER_OFFSET = 32;
86     static constexpr uint32_t PARTITION_ENTRY_OFFSET = 72;
87     static constexpr uint32_t LAST_USABLE_LBA_OFFSET = 48;
88     static constexpr uint32_t PARTITION_ENTRY_LAST_LBA = 40;
89     static constexpr uint32_t PARTITION_COUNT_OFFSET = 80;
90     static constexpr uint32_t PENTRY_SIZE_OFFSET = 84;
91     static constexpr uint32_t HEADER_CRC_OFFSET = 16;
92     static constexpr uint32_t GPT_CRC_LEN = 92;
93     static constexpr uint32_t GPT_ENTRYS_SIZE = 128 * 128;
94 
95     // set 32 bits data
PUT_LONG(uint8_t * x,const uint32_t y)96     inline void PUT_LONG(uint8_t *x, const uint32_t y)
97     {
98         *(x) = (y) & 0xff;
99         *((x) + 1) = ((y) >> 8) & 0xff;
100         *((x) + 2) = ((y) >> 16) & 0xff;
101         *((x) + 3) = ((y) >> 24) & 0xff;
102     }
103 
104     // set 64 bits data
PUT_LONG_LONG(uint8_t * x,const uint64_t y)105     inline void PUT_LONG_LONG(uint8_t *x, const uint64_t y)
106     {
107         *(x) = (y) & 0xff;
108         *((x) + 1) = (((y) >> 8) & 0xff);
109         *((x) + 2) = (((y) >> 16) & 0xff);
110         *((x) + 3) = (((y) >> 24) & 0xff);
111         *((x) + 4) = (((y) >> 32) & 0xff);
112         *((x) + 5) = (((y) >> 40) & 0xff);
113         *((x) + 6) = (((y) >> 48) & 0xff);
114         *((x) + 7) = (((y) >> 56) & 0xff);
115     }
116 
117     // LWORD = 4 bytes (32 bits)
GET_LWORD_FROM_BYTE(const uint8_t * x)118     inline uint32_t GET_LWORD_FROM_BYTE(const uint8_t *x)
119     {
120         uint32_t res = static_cast<unsigned int>(*x) |
121             (static_cast<unsigned int>(*(x + 1)) << 8) |
122             (static_cast<unsigned int>(*(x + 2)) << 16) |
123             (static_cast<unsigned int>(*(x + 3)) << 24);
124         return res;
125     }
126 
127     // LLWORD = 8 bytes (64 bits)
GET_LLWORD_FROM_BYTE(const uint8_t * x)128     inline uint64_t GET_LLWORD_FROM_BYTE(const uint8_t *x)
129     {
130         uint64_t res = static_cast<unsigned long long>(*x) |
131             (static_cast<unsigned long long>(*(x + 1)) << 8) |
132             (static_cast<unsigned long long>(*(x + 2)) << 16) |
133             (static_cast<unsigned long long>(*(x + 3)) << 24) |
134             (static_cast<unsigned long long>(*(x + 4)) << 32) |
135             (static_cast<unsigned long long>(*(x + 5)) << 40) |
136             (static_cast<unsigned long long>(*(x + 6)) << 48) |
137             (static_cast<unsigned long long>(*(x + 7)) << 56);
138         return res;
139     }
140 
141     struct GPTHeaderInfo {
142         uint32_t headerSize {};
143         uint32_t partitionEntrySize {};
144         uint32_t maxPartitionCount {};
145         uint64_t firstUsableLba {};
146     };
147 
148     struct PtableData {
149         bool dataValid {};
150         uint32_t emmcGptDataLen {};
151         uint32_t lbaLen {};
152         uint32_t gptHeaderLen {};
153         uint32_t blockSize {};
154         uint32_t imgLuSize {};
155         uint32_t startLunNumber {};
156         uint32_t writeDeviceLunSize {};
157         uint32_t defaultLunNum {};
158     };
159 
160     std::vector<PtnInfo> partitionInfo_;
161     PtableData ptableData_;
162     uint64_t reservedSize_ {0};
163 
164     PtableData GetPtableData() const;
165     bool MemReadWithOffset(const std::string &filePath, const uint64_t offset,
166         uint8_t *outData, const uint32_t dataSize);
167     bool CheckProtectiveMbr(const uint8_t *gptImage, const uint32_t imgLen);
168     bool CheckIfValidGpt(const uint8_t *gptImage, const uint32_t gptImageLen);
169     bool GetCapacity(const std::string &filePath, uint64_t &lunCapacity);
170     bool GetPartitionGptHeaderInfo(const uint8_t *buffer, const uint32_t bufferLen, GPTHeaderInfo& gptHeaderInfo);
171     void PatchBackUpGptHeader(uint8_t *gptHeader, const uint32_t len, uint64_t backGptEntryStart);
172     bool PartitionCheckGptHeader(const uint8_t *gptImage, const uint32_t len, const uint64_t lbaNum,
173         const uint32_t blockSize, GPTHeaderInfo& gptHeaderInfo);
174     void ParsePartitionName(const uint8_t *data, const uint32_t dataLen,
175         std::string &name, const uint32_t nameLen);
176     uint32_t CalculateCrc32(const uint8_t *buffer, const uint32_t len);
177     bool WritePtablePartition(const std::string &path, uint64_t offset, const uint8_t *buffer, uint32_t size);
178     bool CheckFileExist(const std::string &fileName);
179     bool WriteBufferToPath(const std::string &path, const uint64_t offset, const uint8_t *buffer, const uint32_t size);
180     bool ChangeGpt(uint8_t *gptBuf, uint64_t gptSize, GptParseInfo gptInfo, PtnInfo &modifyInfo);
181     bool AdjustGpt(uint8_t *ptnInfoBuf, uint64_t bufSize, const std::string &ptnName, uint64_t preLastLBA,
182     uint64_t lastPtnLastLBA);
183 
184 private:
185     static constexpr uint64_t MBR_MAGIC_NUM_POS = 0x1FE;
186     static constexpr uint8_t MBR_MAGIC_NUM_0 = 0x55;
187     static constexpr uint8_t MBR_MAGIC_NUM_1 = 0xAA;
188     static constexpr uint32_t MBR_GPT_MAX_NUM = 4; // one disk has most 4 main partitions
189     static constexpr uint32_t MBR_GPT_ENTRY = 0x1BE;
190     static constexpr uint32_t MBR_GPT_ENTRY_SIZE = 0x010;
191     static constexpr uint32_t GPT_TYPE_SIGN_OFFSET = 0x04;
192     static constexpr uint32_t MBR_PROTECTIVE_GPT_TYPE = 0xEE;
193     static constexpr uint64_t EFI_MAGIC_NUMBER = 0x5452415020494645; // GPT SIGNATURE(8 bytes), little-end, (EFI PART)
194     static constexpr uint32_t SECTOR_SIZE = 512;
195     static constexpr uint32_t LBA_LENGTH = SECTOR_SIZE;
196     static constexpr uint32_t HEADER_SIZE_OFFSET = 12;
197     static constexpr uint32_t FIRST_USABLE_LBA_OFFSET = 40;
198     static constexpr uint32_t GPT_HEADER_SIZE = 92;
199     static constexpr uint32_t PRIMARY_HEADER_OFFSET = 24;
200     static constexpr uint32_t MIN_PARTITION_ARRAY_SIZE = 0x4000;
201 
202     bool VerifyMbrMagicNum(const uint8_t *buffer, const uint32_t size);
203     uint32_t Reflect(uint32_t data, const uint32_t len);
204 
205     bool CheckGptHeader(uint8_t *buffer, const uint32_t bufferLen, const uint64_t lbaNum,
206         const GPTHeaderInfo& gptHeaderInfo);
207     void SetPartitionName(const std::string &name, uint8_t *data, const uint32_t size);
208     bool ParsePtableDataNode(const JsonNode &ptableDataNode);
209     bool ParsePtableData();
210 };
211 } // namespace Updater
212 #endif // UPDATER_PTABLE_H
213