xaizek / tos (License: GPLv3 only) (since 2018-12-07)
This is an alternative version of sources presented as part of Write Your Own OS video tutorial by Viktor Engelmann.
Commit 3c3364de4f9eb02a15a7d175ca36482cdb4624ae

Introduce and use Field[s] class
Author: xaizek
Author date (UTC): 2018-04-12 11:45
Committer name: xaizek
Committer date (UTC): 2018-04-12 13:51
Parent(s): 1be74550a6ab6b6e7176fb9e9eacc2df79e87d3b
Signing key: 99DC5E4DB05F6BE2
Tree: 0e492794698b999762212f1d9f01e8297d52c765
File Lines added Lines deleted
src/fs/fat.cpp 21 12
src/fs/fat.hpp 66 43
src/fs/mbr.cpp 10 8
src/fs/mbr.hpp 32 21
src/utils/struct.hpp 169 0
File src/fs/fat.cpp changed (mode: 100644) (index a8659ca..2856226)
... ... using namespace fs;
7 7
8 8 FAT::FAT(drv::ATA &hd, std::uint32_t partitionOffset) : hd(hd) FAT::FAT(drv::ATA &hd, std::uint32_t partitionOffset) : hd(hd)
9 9 { {
10 hd.read28(partitionOffset, as_writable_bytes(bpb));
10 std::uint8_t bpbData[512];
11 hd.read28(partitionOffset, bpbData);
11 12
12 kprint("sectors per cluster: ", bpb.sectorsPerCluster, "\n");
13 BiosParameterBlock32 bpb(bpbData);
13 14
14 15 fatStart = partitionOffset + bpb.reservedSectors; fatStart = partitionOffset + bpb.reservedSectors;
15 16 dataStart = fatStart + bpb.tableSize*bpb.fatCopies; dataStart = fatStart + bpb.tableSize*bpb.fatCopies;
16 17 rootStart = dataStart + bpb.sectorsPerCluster*(bpb.rootCluster - 2); rootStart = dataStart + bpb.sectorsPerCluster*(bpb.rootCluster - 2);
18 sectorsPerCluster = bpb.sectorsPerCluster;
19
20 kprint("sectors per cluster: ", sectorsPerCluster, "\n");
17 21 } }
18 22
19 23 void void
20 24 FAT::printFiles() FAT::printFiles()
21 25 { {
22 DirectoryEntryFat32 dirent[16];
23 hd.read28(rootStart, as_writable_bytes(dirent));
26 std::uint8_t dirData[512];
27 hd.read28(rootStart, dirData);
28
29 std::uint8_t *dataPtr = dirData;
30 Fields<DirectoryEntryFat32, 16> dirent(dataPtr);
24 31
25 32 for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i) {
26 if (dirent[i].name[0] == 0x00) {
33 DirectoryEntryFat32 &ent = dirent[i];
34
35 if (ent.name[0] == 0x00) {
27 36 break; break;
28 37 } }
29 38
30 if ((dirent[i].attributes & 0x0f) == 0x0f) {
39 if ((ent.attributes & 0x0f) == 0x0f) {
31 40 continue; continue;
32 41 } }
33 42
34 43 char foo[] = " \n"; char foo[] = " \n";
35 44 for (int j = 0; j < 8; ++j) { for (int j = 0; j < 8; ++j) {
36 foo[j] = dirent[i].name[j];
45 foo[j] = ent.name[j];
37 46 } }
38 47 kprint(foo); kprint(foo);
39 48
40 49 // Skip directories. // Skip directories.
41 if (!(dirent[i].attributes & 0x10)) {
42 printFileContents(dirent[i]);
50 if (!(ent.attributes & 0x10)) {
51 printFileContents(ent);
43 52 } }
44 53 } }
45 54 } }
 
... ... FAT::printFileContents(const DirectoryEntryFat32 &ent) const
56 65
57 66 while (size > 0) { while (size > 0) {
58 67 std::uint32_t sector = dataStart std::uint32_t sector = dataStart
59 + bpb.sectorsPerCluster*(currentCluster - 2);
60 int sectorOffset = 0;
68 + sectorsPerCluster*(currentCluster - 2);
69 std::uint32_t sectorOffset = 0;
61 70
62 71 while (size > 0) { while (size > 0) {
63 72 hd.read28(sector + sectorOffset, { buffer, 512 }); hd.read28(sector + sectorOffset, { buffer, 512 });
 
... ... FAT::printFileContents(const DirectoryEntryFat32 &ent) const
67 76
68 77 size -= 512; size -= 512;
69 78
70 if (++sectorOffset == bpb.sectorsPerCluster) {
79 if (++sectorOffset == sectorsPerCluster) {
71 80 break; break;
72 81 } }
73 82 } }
File src/fs/fat.hpp changed (mode: 100644) (index 9c37b88..0256b67)
3 3
4 4 #include <cstdint> #include <cstdint>
5 5
6 #include "utils/struct.hpp"
7
6 8 namespace drv { namespace drv {
7 9 class ATA; class ATA;
8 10 } }
 
... ... namespace fs {
11 13
12 14 struct BiosParameterBlock32 struct BiosParameterBlock32
13 15 { {
14 std::uint8_t jump[3];
15 std::uint8_t softName[8];
16 std::uint16_t bytesPerSector;
17 std::uint8_t sectorsPerCluster;
18 std::uint16_t reservedSectors;
19 std::uint8_t fatCopies;
20 std::uint16_t rootDirEntries;
21 std::uint16_t totalSectors;
22 std::uint8_t mediaType;
23 std::uint16_t fatSectorCount;
24 std::uint16_t sectorsPerTrack;
25 std::uint16_t headCount;
26 std::uint32_t hiddenSectors;
27 std::uint32_t totalSectorCount;
16 Fields<std::uint8_t, 3> jump;
17 Fields<std::uint8_t, 8> softName;
18 Field<std::uint16_t> bytesPerSector;
19 Field<std::uint8_t> sectorsPerCluster;
20 Field<std::uint16_t> reservedSectors;
21 Field<std::uint8_t> fatCopies;
22 Field<std::uint16_t> rootDirEntries;
23 Field<std::uint16_t> totalSectors;
24 Field<std::uint8_t> mediaType;
25 Field<std::uint16_t> fatSectorCount;
26 Field<std::uint16_t> sectorsPerTrack;
27 Field<std::uint16_t> headCount;
28 Field<std::uint32_t> hiddenSectors;
29 Field<std::uint32_t> totalSectorCount;
30
31 Field<std::uint32_t> tableSize;
32 Field<std::uint16_t> extFlags;
33 Field<std::uint16_t> fatVersion;
34 Field<std::uint32_t> rootCluster;
35 Field<std::uint16_t> fatInfo;
36 Field<std::uint16_t> backupSector;
37 Fields<std::uint8_t, 12> reserved0;
38 Field<std::uint8_t> driveNumber;
39 Field<std::uint8_t> reserved;
40 Field<std::uint8_t> bootSignature;
41 Field<std::uint32_t> volumeId;
42 Fields<std::uint8_t, 11> volumeLabel;
43 Fields<std::uint8_t, 8> fatTypeLabel;
28 44
29 std::uint32_t tableSize;
30 std::uint16_t extFlags;
31 std::uint16_t fatVersion;
32 std::uint32_t rootCluster;
33 std::uint16_t fatInfo;
34 std::uint16_t backupSector;
35 std::uint8_t reserved0[12];
36 std::uint8_t driveNumber;
37 std::uint8_t reserved;
38 std::uint8_t bootSignature;
39 std::uint32_t volumeId;
40 std::uint8_t volumeLabel[11];
41 std::uint8_t fatTypeLabel[8];
42 } __attribute__((packed));
45 explicit BiosParameterBlock32(std::uint8_t data[])
46 : jump(data), softName(data), bytesPerSector(data),
47 sectorsPerCluster(data), reservedSectors(data), fatCopies(data),
48 rootDirEntries(data), totalSectors(data), mediaType(data),
49 fatSectorCount(data), sectorsPerTrack(data), headCount(data),
50 hiddenSectors(data), totalSectorCount(data), tableSize(data),
51 extFlags(data), fatVersion(data), rootCluster(data), fatInfo(data),
52 backupSector(data), reserved0(data), driveNumber(data),
53 reserved(data), bootSignature(data), volumeId(data),
54 volumeLabel(data), fatTypeLabel(data)
55 {
56 }
57 };
43 58
44 59 struct DirectoryEntryFat32 struct DirectoryEntryFat32
45 60 { {
46 std::uint8_t name[8];
47 std::uint8_t ext[3];
48 std::uint8_t attributes;
49 std::uint8_t reserved;
50 std::uint8_t cTimeTenth;
51 std::uint16_t cTime;
52 std::uint16_t cDate;
53 std::uint16_t aTime;
54 std::uint16_t firstClusterHi;
55 std::uint16_t wTime;
56 std::uint16_t wDate;
57 std::uint16_t firstClusterLow;
58 std::uint32_t size;
59 } __attribute__((packed));
61 Fields<std::uint8_t, 8> name;
62 Fields<std::uint8_t, 3> ext;
63 Field<std::uint8_t> attributes;
64 Field<std::uint8_t> reserved;
65 Field<std::uint8_t> cTimeTenth;
66 Field<std::uint16_t> cTime;
67 Field<std::uint16_t> cDate;
68 Field<std::uint16_t> aTime;
69 Field<std::uint16_t> firstClusterHi;
70 Field<std::uint16_t> wTime;
71 Field<std::uint16_t> wDate;
72 Field<std::uint16_t> firstClusterLow;
73 Field<std::uint32_t> size;
74
75 explicit DirectoryEntryFat32(std::uint8_t *&data)
76 : name(data), ext(data), attributes(data), reserved(data),
77 cTimeTenth(data), cTime(data), cDate(data), aTime(data),
78 firstClusterHi(data), wTime(data), wDate(data), firstClusterLow(data),
79 size(data)
80 {
81 }
82 };
60 83
61 84 class FAT class FAT
62 85 { {
 
... ... private:
71 94
72 95 private: private:
73 96 drv::ATA &hd; drv::ATA &hd;
74 BiosParameterBlock32 bpb;
75 97 std::uint32_t fatStart; std::uint32_t fatStart;
76 98 std::uint32_t dataStart; std::uint32_t dataStart;
77 99 std::uint32_t rootStart; std::uint32_t rootStart;
100 std::uint32_t sectorsPerCluster;
78 101 }; };
79 102
80 103 } }
File src/fs/mbr.cpp changed (mode: 100644) (index 09c1e21..6c32bc4)
... ... using namespace fs;
10 10 void void
11 11 MBR::readPartitions(drv::ATA &hd) MBR::readPartitions(drv::ATA &hd)
12 12 { {
13 MasterBootRecord mbr;
14
15 13 kprint("MBR: "); kprint("MBR: ");
16 14
17 hd.read28(0, as_writable_bytes(mbr));
15 std::uint8_t mbrSector[512];
16 hd.read28(0, mbrSector);
17
18 MasterBootRecord mbr(mbrSector);
18 19
19 20 if (mbr.magicnumber != 0xAA55) { if (mbr.magicnumber != 0xAA55) {
20 21 kprint("illegal MBR"); kprint("illegal MBR");
 
... ... MBR::readPartitions(drv::ATA &hd)
23 24
24 25 kprint("\n"); kprint("\n");
25 26 for (std::uint8_t i = 0; i < 4; ++i) { for (std::uint8_t i = 0; i < 4; ++i) {
26 if (mbr.primaryPartition[i].partition_id == 0x00) {
27 const std::uint8_t id = mbr.primaryPartition[i]->partition_id;
28 if (id == 0x00) {
27 29 continue; continue;
28 30 } }
29 31
30 const char *is = mbr.primaryPartition[i].bootable == 0x80 ? "" : " not";
31 kprint(" Partition ", i, is, " bootable. Type 0x",
32 mbr.primaryPartition[i].partition_id, ".\n");
32 const char *is = mbr.primaryPartition[i]->bootable == 0x80 ? ""
33 : " not";
34 kprint(" Partition ", i, is, " bootable. Type 0x", id, ".\n");
33 35
34 FAT fat(hd, mbr.primaryPartition[i].start_lba);
36 FAT fat(hd, mbr.primaryPartition[i]->start_lba);
35 37 fat.printFiles(); fat.printFiles();
36 38 } }
37 39 } }
File src/fs/mbr.hpp changed (mode: 100644) (index 45749e7..d0adde5)
3 3
4 4 #include <cstdint> #include <cstdint>
5 5
6 #include "utils/struct.hpp"
7
6 8 namespace drv { namespace drv {
7 9 class ATA; class ATA;
8 10 } }
 
... ... namespace fs {
11 13
12 14 struct PartitionTableEntry struct PartitionTableEntry
13 15 { {
14 std::uint8_t bootable;
15
16 std::uint8_t start_head;
17 std::uint8_t start_sector : 6;
18 std::uint16_t start_cylinder : 10;
19
20 std::uint8_t partition_id;
21
22 std::uint8_t end_head;
23 std::uint8_t end_sector : 6;
24 std::uint16_t end_cylinder : 10;
25
26 std::uint32_t start_lba;
27 std::uint32_t length;
28 } __attribute__((packed));
16 Field<std::uint8_t> bootable;
17 Field<std::uint32_t, 3> startCHS;
18 Field<std::uint8_t> partition_id;
19 Field<std::uint32_t, 3> endCHS;
20 Field<std::uint32_t> start_lba;
21 Field<std::uint32_t> length;
22
23 explicit PartitionTableEntry(std::uint8_t *&data)
24 : bootable(data), startCHS(data), partition_id(data), endCHS(data),
25 start_lba(data), length(data)
26 {
27 }
28
29 static constexpr std::ptrdiff_t size()
30 {
31 return 16;
32 }
33 };
29 34
30 35 struct MasterBootRecord struct MasterBootRecord
31 36 { {
32 std::uint8_t bootloader[440];
33 std::uint32_t signature;
34 std::uint16_t unused;
37 Fields<std::uint8_t, 440> bootloader;
38 Field<std::uint32_t> signature;
39 Field<std::uint16_t> unused;
35 40
36 PartitionTableEntry primaryPartition[4];
41 Fields<PartitionTableEntry, 4> primaryPartition;
37 42
38 std::uint16_t magicnumber;
39 } __attribute__((packed));
43 Field<std::uint16_t> magicnumber;
44
45 explicit MasterBootRecord(std::uint8_t data[])
46 : bootloader(data), signature(data), unused(data),
47 primaryPartition(data), magicnumber(data)
48 {
49 }
50 };
40 51
41 52 class MBR class MBR
42 53 { {
File src/utils/struct.hpp changed (mode: 100644) (index 3bdf2c4..2b5005c)
... ... private:
91 91 NetOrder<T> cached; NetOrder<T> cached;
92 92 }; };
93 93
94 template <typename T, std::size_t N = sizeof(T)>
95 class Field
96 {
97 static_assert(std::is_integral<T>::value,
98 "Field accepts only integral types!");
99 static_assert(!std::is_signed<T>::value,
100 "Field accepts only unsigned types!");
101 static_assert(N <= sizeof(T),
102 "Field width can't be bigger than size of the type!");
103 static_assert(N > 0U,
104 "Field can't handle field of zero width!");
105
106 public:
107 static constexpr std::size_t size = N;
108
109 public:
110 explicit Field(std::uint8_t *&data) : ptr(data), cached()
111 {
112 for (std::size_t i = N; i != 0U; --i) {
113 cached = (cached << 8) | ptr[i - 1U];
114 }
115 data += N;
116 }
117
118 // Fields aren't supposed to be copied or assigned in any way.
119 Field(Field &&rhs) = delete;
120 Field & operator=(Field &&rhs) = delete;
121
122 public:
123 Field & operator=(T value)
124 {
125 cached = value;
126 for (std::size_t i = 0; i < N; ++i) {
127 ptr[i] = value & 0xff;
128 value >>= 8;
129 }
130 return *this;
131 }
132
133 operator T() const
134 {
135 return cached;
136 }
137
138 private:
139 std::uint8_t *ptr;
140 T cached;
141 };
142
143 template <typename T, bool = std::is_integral<T>::value>
144 class ArrayField
145 {
146 public:
147 static constexpr std::size_t N = T::size();
148 static constexpr std::size_t size = N;
149
150 public:
151 explicit ArrayField(std::uint8_t *&data) : field(data)
152 {
153 }
154
155 // Fields aren't supposed to be copied or assigned in any way.
156 ArrayField(ArrayField &&rhs) = delete;
157 ArrayField & operator=(ArrayField &&rhs) = delete;
158
159 public:
160 operator T&()
161 {
162 return field;
163 }
164
165 T * operator->()
166 {
167 return &field;
168 }
169
170 private:
171 T field;
172 };
173
174 template <typename T>
175 class ArrayField<T, true>
176 {
177 static_assert(!std::is_signed<T>::value,
178 "ArrayField accepts only unsigned types!");
179
180 public:
181 static constexpr std::size_t N = sizeof(T);
182 static constexpr std::size_t size = N;
183
184 public:
185 explicit ArrayField(std::uint8_t *&data) : ptr(data), cached()
186 {
187 for (std::size_t i = N; i != 0U; --i) {
188 cached = (cached << 8) | ptr[i - 1U];
189 }
190 data += N;
191 }
192
193 // Fields aren't supposed to be copied or assigned in any way.
194 ArrayField(ArrayField &&rhs) = delete;
195 ArrayField & operator=(ArrayField &&rhs) = delete;
196
197 public:
198 ArrayField & operator=(T value)
199 {
200 cached = value;
201 for (std::size_t i = 0; i < N; ++i) {
202 ptr[i] = value & 0xff;
203 value >>= 8;
204 }
205 return *this;
206 }
207
208 operator T() const
209 {
210 return cached;
211 }
212
213 private:
214 std::uint8_t *ptr;
215 T cached;
216 };
217
218 template <typename T, std::size_t C>
219 class Fields
220 {
221 static_assert(C > 0U, "Fields can't have zero size!");
222
223 public:
224 static constexpr std::size_t size = C*ArrayField<T>::size();
225
226 public:
227 explicit Fields(std::uint8_t *&data)
228 {
229 for (std::size_t i = 0U; i < C; ++i) {
230 fields[i] = new(&datas[i].field) ArrayField<T>(data);
231 }
232 }
233
234 ~Fields()
235 {
236 for (Data &field : datas) {
237 field.field.~ArrayField();
238 }
239 }
240
241 // Fields aren't supposed to be copied or assigned in any way.
242 Fields(Fields &&rhs) = delete;
243 Fields & operator=(Fields &&rhs) = delete;
244
245 public:
246 ArrayField<T> & operator[](std::size_t idx)
247 {
248 return *fields[idx];
249 }
250
251 private:
252 union Data {
253 ArrayField<T> field;
254
255 Data() {}
256 ~Data() {}
257 };
258 Data datas[C];
259
260 ArrayField<T> *fields[C];
261 };
262
94 263 #endif // TOS__UTILS__STRUCT_HPP__ #endif // TOS__UTILS__STRUCT_HPP__
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/tos

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/tos

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master