blob: ad416be23153c7b5ddcccd371bb4f1ad5b749875 [file] [log] [blame]
swissChili4749d022021-07-19 12:33:06 -07001#include <alloc.h>
swissChili4418ca52021-06-14 17:36:00 -07002#include <dri/ata_pio/ata_pio.h>
swissChilie5adca52021-06-16 21:00:31 -07003#include <dri/fs/ext2/ext2.h>
swissChili4749d022021-07-19 12:33:06 -07004#include <io.h>
swissChilief829f32021-06-13 20:00:54 -07005#include <kint.h>
swissChili4418ca52021-06-14 17:36:00 -07006#include <log.h>
swissChilib7ef65d2021-07-17 12:51:52 -07007
8inline uint ext2_block_size(struct ext2_superblock *sb)
9{
10 return 1024 << sb->block_size_shift;
11}
12
13void ext2_read_block(struct ext2_superblock *sb, void *buffer, uint block)
14{
15 uint block_size = ext2_block_size(sb) / 512;
16 uint block_start = block_size * block;
17
18 ata_pio_read_sectors(buffer, block_start, block_size);
19}
swissChili4418ca52021-06-14 17:36:00 -070020
swissChili4749d022021-07-19 12:33:06 -070021void ext2_write_block(struct ext2_superblock *sb, void *buffer, uint block)
22{
23 uint block_size = ext2_block_size(sb) / 512;
24 uint block_start = block_size * block;
25
26 ata_pio_write_sectors(block_start, block_size, buffer);
27}
28
swissChili4418ca52021-06-14 17:36:00 -070029struct ext2_superblock ext2_read_superblock()
30{
31 uchar buffer[512 * 2];
32 ata_pio_read_sectors(buffer, 2, 2);
33
34 struct ext2_superblock *sb = (void *)(buffer);
35 return *sb;
36}
swissChilief829f32021-06-13 20:00:54 -070037
swissChilie5adca52021-06-16 21:00:31 -070038uint ext2_num_block_groups(struct ext2_superblock *sb)
39{
40 // This is a mildly janky way of rounding up
41 uint a = (sb->total_blocks - 1) / (sb->blocks_per_block_group + 1);
42 uint b = (sb->total_inodes - 1) / (sb->inodes_per_block_group + 1);
43
44 if (a == b)
45 {
46 return a;
47 }
48 else
49 {
50 kprintf(ERROR "EXT2 cannot find number of block groups, %d and %d "
51 "should equal.\n",
52 a, b);
53 kpanic("Corrupted filesystem");
54 }
55}
56
swissChilib7ef65d2021-07-17 12:51:52 -070057struct ext2_block_group_descriptor ext2_load_block_group_descriptor(
58 struct ext2_superblock *sb, uint block_group)
swissChilie5adca52021-06-16 21:00:31 -070059{
60 /**
61 * The BGDT (not to be confused with the GDT) is located the block after the
62 * superblock. On any block size EXCEPT 1024 (the minimum, remember that the
63 * block size is specified by X where 1024 << X is the real size) this is
64 * the second block (0-indexed, so 1). On 1024 this is the third block.
65 */
66 uint bgdt_block = 1;
67 uint block_size = ext2_block_size(sb);
68
69 if (block_size == 1024)
70 bgdt_block = 2;
71
swissChilib7ef65d2021-07-17 12:51:52 -070072 const uint bgd_size = sizeof(struct ext2_block_group_descriptor);
73
74 // Disk page that the BGD is on relative to the initial FILE SYSTEM block
75 uint hd_page = block_group / (512 / bgd_size);
76 // The offset from the beginning of that page the BGD is at
77 uint bgd_offset = block_group % (512 / bgd_size);
78
79 struct ext2_block_group_descriptor descriptors[512 / bgd_size];
80 kassert(sizeof(descriptors) == 512, "Wrong BGD size");
81
82 uint lba = (block_size / 512) * bgdt_block + hd_page;
83
84 ata_pio_read_sectors(&descriptors, lba, 1);
85
86 return descriptors[bgd_offset];
87}
88
swissChilicbd43632021-07-17 16:19:44 -070089static void print_entry(uint inode, const char *name, void *sb)
swissChilib7ef65d2021-07-17 12:51:52 -070090{
91 kprintf("%d\t %s\n", inode, name);
swissChilicbd43632021-07-17 16:19:44 -070092
93 struct ext2_inode in;
94
95 if (ext2_find_inode(sb, inode, &in))
96 {
97 if ((in.mode & EXT2_F_TYPE) == EXT2_S_IFREG)
98 {
99 char buffer[65];
100 uint read = ext2_read_inode(sb, &in, buffer, 64);
101 buffer[read] = 0;
102
103 kprintf("contents: %d\n'%s'\n", read, buffer);
104 }
105 }
106
107 return;
swissChilie5adca52021-06-16 21:00:31 -0700108}
109
swissChilief829f32021-06-13 20:00:54 -0700110void ext2_mount(struct fs_node *where)
111{
swissChili4418ca52021-06-14 17:36:00 -0700112 struct ext2_superblock sb = ext2_read_superblock();
113
swissChilie5adca52021-06-16 21:00:31 -0700114 kprintf(DEBUG "EXT2 magic = 0x%x\n", sb.signature);
swissChili4749d022021-07-19 12:33:06 -0700115
swissChilib7ef65d2021-07-17 12:51:52 -0700116 // Read the root inode 2
117 struct ext2_inode root;
swissChilie5adca52021-06-16 21:00:31 -0700118
swissChilib7ef65d2021-07-17 12:51:52 -0700119 if (ext2_find_inode(&sb, 2, &root))
120 {
swissChili4749d022021-07-19 12:33:06 -0700121 kprintf(OKAY "Found root inode 2 (size=0x%x, num_blocks=0x%x)\n",
122 root.size, root.num_blocks);
swissChilib7ef65d2021-07-17 12:51:52 -0700123 // kprintf(DEBUG "Root.mode = 0x%x\n", root.mode & 0xf000);
swissChili4749d022021-07-19 12:33:06 -0700124 kassert((root.mode & 0xf000) == EXT2_S_IFDIR,
125 "Root (inode 2) is not a directory.");
swissChilib7ef65d2021-07-17 12:51:52 -0700126
127 kprintf("ls /\n");
128 kprintf("inode\t name\n");
129 kprintf("--------------------\n");
swissChilicbd43632021-07-17 16:19:44 -0700130 ext2_dir_ls(&sb, &root, print_entry, &sb);
swissChilib7ef65d2021-07-17 12:51:52 -0700131 }
132 else
133 {
134 kprintf(WARN "Failed to find root inode 2\n");
135 }
swissChili4749d022021-07-19 12:33:06 -0700136
137 kprintf(INFO "First free inode is %d\n", ext2_first_free_inode(&sb));
swissChilief829f32021-06-13 20:00:54 -0700138}
swissChili9bd74de2021-06-15 20:30:48 -0700139
140bool ext2_valid_filesystem()
141{
142 struct ext2_superblock sb = ext2_read_superblock();
143
swissChili4749d022021-07-19 12:33:06 -0700144 kprintf(DEBUG "superblock signature is %d (0x%x)\n", sb.signature,
145 sb.signature);
swissChili276b8cf2021-07-16 13:24:42 -0700146
swissChili9bd74de2021-06-15 20:30:48 -0700147 return sb.signature == EXT2_SIGNATURE;
swissChilie5adca52021-06-16 21:00:31 -0700148}
swissChilib7ef65d2021-07-17 12:51:52 -0700149
150void ext2_write_superblock(struct ext2_superblock *sb)
151{
152 ushort *wp = (ushort *)sb;
153
154 ata_pio_write_sectors(2, 2, wp);
155}
156
157void ext2_corrupt_superblock_for_fun()
158{
159 struct ext2_superblock sb = ext2_read_superblock();
160 sb.signature = 0xDEAD;
161 ext2_write_superblock(&sb);
162}
163
swissChili4749d022021-07-19 12:33:06 -0700164bool ext2_find_inode(struct ext2_superblock *sb, uint number,
165 struct ext2_inode *inode)
swissChilib7ef65d2021-07-17 12:51:52 -0700166{
167 if (number == 0)
168 return false;
169
170 uint block_group = (number - 1) / sb->inodes_per_block_group;
171 uint local_index = (number - 1) % sb->inodes_per_block_group;
172
173 // Load this from the block group descriptor table
174 struct ext2_block_group_descriptor descriptor =
175 ext2_load_block_group_descriptor(sb, block_group);
176
swissChili4749d022021-07-19 12:33:06 -0700177 // kprintf(DEBUG "Descriptor inode_table = 0x%x\n",
178 // descriptor.inode_table_start_block);
swissChilib7ef65d2021-07-17 12:51:52 -0700179
180 // We need to figure out what FS block the inode is on, we know how many
181 // inodes there are total in this BGD and the number per page, so this is
182 // simple.
183
184 const uint block_size = ext2_block_size(sb);
185
186 const uint inodes_per_block = block_size / sizeof(struct ext2_inode);
187
188 uint inode_block = local_index / inodes_per_block;
189 uint inode_index = local_index % inodes_per_block;
190
191 struct ext2_inode inodes[block_size / sizeof(struct ext2_inode)];
192
swissChili4749d022021-07-19 12:33:06 -0700193 ext2_read_block(sb, inodes,
194 descriptor.inode_table_start_block + inode_block);
swissChilib7ef65d2021-07-17 12:51:52 -0700195
196 *inode = inodes[inode_index];
197
198 return true;
199}
200
swissChili4749d022021-07-19 12:33:06 -0700201bool ext2_dir_ls(struct ext2_superblock *sb, struct ext2_inode *dir,
202 void (*cb)(uint inode, const char *name, void *data),
swissChilib7ef65d2021-07-17 12:51:52 -0700203 void *data)
204{
205 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
206 return false;
207
208 for (int i = 0; i < dir->num_blocks; i++)
209 {
210 uchar buffer[ext2_block_size(sb)];
211 ext2_read_inode_block(sb, dir, buffer, i);
212
213 struct ext2_dirent *ent = (void *)buffer;
214
215 // While there are files in this block
swissChilicbd43632021-07-17 16:19:44 -0700216 while ((uint)ent < (uint)(buffer + ext2_block_size(sb)))
swissChilib7ef65d2021-07-17 12:51:52 -0700217 {
218 if (ent->inode == 0)
219 return true;
220
221 if (cb)
222 {
223 char name[257];
224
225 memcpy(name, ent->name, ent->name_len);
226 name[ent->name_len] = '\0';
swissChilicbd43632021-07-17 16:19:44 -0700227
swissChilib7ef65d2021-07-17 12:51:52 -0700228 cb(ent->inode, name, data);
229 }
230
231 ent = (void *)(((uint)(void *)ent) + ent->rec_len);
232 }
233 // We ran out of files in this block, continue to the next one. This
234 // works because files cannot span blocks
235 }
236
237 return true;
238}
239
swissChili4749d022021-07-19 12:33:06 -0700240ssize_t ext2_read_inode(struct ext2_superblock *sb, struct ext2_inode *inode,
241 void *buffer, ssize_t size)
swissChilicbd43632021-07-17 16:19:44 -0700242{
243 const uint block_size = ext2_block_size(sb);
244 char transfer[block_size];
245
246 uint fsize = MIN(inode->size, size);
247 uint i;
248
249 // Transfer full blocks straight to the output buffer
250 for (i = 0; i < fsize / block_size; i++)
251 {
252 ext2_read_inode_block(sb, inode, buffer + i * block_size, i);
253 }
254
swissChili4749d022021-07-19 12:33:06 -0700255 // If we have part of a block left over read it here first, then transfer
256 // what we need
swissChilicbd43632021-07-17 16:19:44 -0700257 if (i * block_size < fsize)
258 {
259 uint remainder = fsize % block_size;
260
261 ext2_read_inode_block(sb, inode, transfer, i);
262 memcpy(buffer + i * block_size, transfer, remainder);
263 }
264
265 return fsize;
266}
267
swissChili4749d022021-07-19 12:33:06 -0700268bool ext2_read_inode_block(struct ext2_superblock *sb, struct ext2_inode *inode,
269 void *buffer, uint block)
swissChilib7ef65d2021-07-17 12:51:52 -0700270{
271 if (block >= 12)
272 {
swissChili4749d022021-07-19 12:33:06 -0700273 kprintf(ERROR
274 "Sorry, EXT2 can only access the first 12 (direct) blocks "
275 "of an inode for now. Indirect look-up will be added later\n");
swissChilib7ef65d2021-07-17 12:51:52 -0700276 kpanic("Invalid inode block");
277 }
278
279 uint block_address = inode->blocks[block];
280
281 ext2_read_block(sb, buffer, block_address);
swissChilicbd43632021-07-17 16:19:44 -0700282
283 return true;
swissChilib7ef65d2021-07-17 12:51:52 -0700284}
swissChili4749d022021-07-19 12:33:06 -0700285
286static const uint ext2_bitmap_block(struct ext2_superblock *sb,
287 uint *bitmap_block, uint *index)
288{
289 const uint block_size = ext2_block_size(sb);
290
291 while (index > block_size)
292 {
293 index -= block_size;
294 bitmap_block += 1;
295 }
296
297 return block_size;
298}
299
300bool ext2_check_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
301 uint index)
302{
303 const uint block_size = ext2_bitmap_block(sb, &bitmap_block, &index);
304
305 uint byte = index / 8;
306 uint bit = index % 8;
307
308 uchar buffer[block_size];
309
310 ext2_read_block(sb, buffer, bitmap_block);
311
312 return !!(buffer[byte] & (1 << bit));
313}
314
315void ext2_set_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
316 uint index, bool value)
317{
318 const uint block_size = ext2_bitmap_block(sb, &bitmap_block, &index);
319
320 uint byte = index / 8;
321 uint bit = index % 8;
322
323 uchar buffer[block_size];
324
325 ext2_read_block(sb, buffer, bitmap_block);
326
327 uchar target_bit = 1 << bit;
328 buffer[byte] =
329 value ? (buffer[byte] | target_bit) : (buffer[byte] | ~target_bit);
330
331 ext2_write_block(sb, buffer, bitmap_block);
332}
333
334uint ext2_first_zero_bit(struct ext2_superblock *sb, uint bitmap_block,
335 uint num_blocks, uint start_at)
336{
337 uint block_size = ext2_block_size(sb);
338
339 for (uint block = bitmap_block; block < bitmap_block + num_blocks; block++)
340 {
341 // dword-array for performance
342 uint buffer[block_size / 4];
343
344 ext2_read_block(sb, buffer, block);
345
346 // If this is the first block start at start_at, otherwise 0
347 for (int i = 0; i < block_size / 4; i++)
348 {
349 // The bitwise negative will be non-zero if there are zero bits in
350 // the original.
351 if (~buffer[i])
352 {
353 // 4 bytes * 8 bits * i dwords
354 uint index =
355 (4 * 8 * i) + (block - bitmap_block) * 8 * block_size;
356
357 kprintf(DEBUG "buffer[i] = 0x%x, i = %d, index = %d\n",
358 buffer[i], i, index);
359
360 // __builtin_ffs gives us the index of the least-significant 1
361 // bit. Since we take the bitwise inverse this is actuall the
362 // least significant 0 bit. This is a GCC intrinsic. This works
363 // particularly well on little-endian systems where the least
364 // significant bit happens to also correspond to the first bit
365 // in the dword bitset.
366 //
367 // ________ ________ ________ ________
368 // ^ this is the LSB ^
369 // | this is the MSB
370 //
371 // This means that the LSB is also the first bit in the bitset.
372 uint trailing = __builtin_ffs(~buffer[i]);
373
374 kprintf(DEBUG "Trailing = %d, 0x%x\n", trailing, trailing);
375
376 return trailing + index;
377 }
378 }
379 }
380
381 return -1;
382}
383
384uint ext2_first_free_inode(struct ext2_superblock *sb)
385{
386 // For now just check the first block group
387 struct ext2_block_group_descriptor bgd =
388 ext2_load_block_group_descriptor(sb, 0);
389
390 const uint block_size = ext2_block_size(sb);
391 // + 1 because we need to round up (ie 1025 for 1024 size blocks will yield
392 // 1, should 2)
393 uint bitset_blocks = (sb->inodes_per_block_group / 8) / block_size + 1;
394
395 // inodes start at 1
396 uint inode = ext2_first_zero_bit(sb, bgd.inode_bitmap, bitset_blocks, 12) + 1;
397 // This will overflow back to zero if no inode was found
398
399 if (!inode)
400 {
401 kpanic("No inodes left in first block group, FIXME");
402 }
403
404 return inode;
405}