blob: 2cf15f55becb63bc1da8c8686f3fec0c2429c4e9 [file] [log] [blame]
swissChili4418ca52021-06-14 17:36:00 -07001#include <dri/ata_pio/ata_pio.h>
swissChilie5adca52021-06-16 21:00:31 -07002#include <dri/fs/ext2/ext2.h>
swissChilief829f32021-06-13 20:00:54 -07003#include <kint.h>
swissChili4418ca52021-06-14 17:36:00 -07004#include <log.h>
swissChilib7ef65d2021-07-17 12:51:52 -07005#include <io.h>
swissChilicbd43632021-07-17 16:19:44 -07006#include <alloc.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
21struct ext2_superblock ext2_read_superblock()
22{
23 uchar buffer[512 * 2];
24 ata_pio_read_sectors(buffer, 2, 2);
25
26 struct ext2_superblock *sb = (void *)(buffer);
27 return *sb;
28}
swissChilief829f32021-06-13 20:00:54 -070029
swissChilie5adca52021-06-16 21:00:31 -070030uint ext2_num_block_groups(struct ext2_superblock *sb)
31{
32 // This is a mildly janky way of rounding up
33 uint a = (sb->total_blocks - 1) / (sb->blocks_per_block_group + 1);
34 uint b = (sb->total_inodes - 1) / (sb->inodes_per_block_group + 1);
35
36 if (a == b)
37 {
38 return a;
39 }
40 else
41 {
42 kprintf(ERROR "EXT2 cannot find number of block groups, %d and %d "
43 "should equal.\n",
44 a, b);
45 kpanic("Corrupted filesystem");
46 }
47}
48
swissChilib7ef65d2021-07-17 12:51:52 -070049struct ext2_block_group_descriptor ext2_load_block_group_descriptor(
50 struct ext2_superblock *sb, uint block_group)
swissChilie5adca52021-06-16 21:00:31 -070051{
52 /**
53 * The BGDT (not to be confused with the GDT) is located the block after the
54 * superblock. On any block size EXCEPT 1024 (the minimum, remember that the
55 * block size is specified by X where 1024 << X is the real size) this is
56 * the second block (0-indexed, so 1). On 1024 this is the third block.
57 */
58 uint bgdt_block = 1;
59 uint block_size = ext2_block_size(sb);
60
61 if (block_size == 1024)
62 bgdt_block = 2;
63
swissChilib7ef65d2021-07-17 12:51:52 -070064 const uint bgd_size = sizeof(struct ext2_block_group_descriptor);
65
66 // Disk page that the BGD is on relative to the initial FILE SYSTEM block
67 uint hd_page = block_group / (512 / bgd_size);
68 // The offset from the beginning of that page the BGD is at
69 uint bgd_offset = block_group % (512 / bgd_size);
70
71 struct ext2_block_group_descriptor descriptors[512 / bgd_size];
72 kassert(sizeof(descriptors) == 512, "Wrong BGD size");
73
74 uint lba = (block_size / 512) * bgdt_block + hd_page;
75
76 ata_pio_read_sectors(&descriptors, lba, 1);
77
78 return descriptors[bgd_offset];
79}
80
swissChilicbd43632021-07-17 16:19:44 -070081static void print_entry(uint inode, const char *name, void *sb)
swissChilib7ef65d2021-07-17 12:51:52 -070082{
83 kprintf("%d\t %s\n", inode, name);
swissChilicbd43632021-07-17 16:19:44 -070084
85 struct ext2_inode in;
86
87 if (ext2_find_inode(sb, inode, &in))
88 {
89 if ((in.mode & EXT2_F_TYPE) == EXT2_S_IFREG)
90 {
91 char buffer[65];
92 uint read = ext2_read_inode(sb, &in, buffer, 64);
93 buffer[read] = 0;
94
95 kprintf("contents: %d\n'%s'\n", read, buffer);
96 }
97 }
98
99 return;
swissChilie5adca52021-06-16 21:00:31 -0700100}
101
swissChilief829f32021-06-13 20:00:54 -0700102void ext2_mount(struct fs_node *where)
103{
swissChili4418ca52021-06-14 17:36:00 -0700104 struct ext2_superblock sb = ext2_read_superblock();
105
swissChilie5adca52021-06-16 21:00:31 -0700106 kprintf(DEBUG "EXT2 magic = 0x%x\n", sb.signature);
swissChilib7ef65d2021-07-17 12:51:52 -0700107
108 // Read the root inode 2
109 struct ext2_inode root;
swissChilie5adca52021-06-16 21:00:31 -0700110
swissChilib7ef65d2021-07-17 12:51:52 -0700111 if (ext2_find_inode(&sb, 2, &root))
112 {
113 kprintf(OKAY "Found root inode 2 (size=0x%x, num_blocks=0x%x)\n", root.size, root.num_blocks);
114 // kprintf(DEBUG "Root.mode = 0x%x\n", root.mode & 0xf000);
115 kassert((root.mode & 0xf000) == EXT2_S_IFDIR, "Root (inode 2) is not a directory.");
116
117 kprintf("ls /\n");
118 kprintf("inode\t name\n");
119 kprintf("--------------------\n");
swissChilicbd43632021-07-17 16:19:44 -0700120 ext2_dir_ls(&sb, &root, print_entry, &sb);
swissChilib7ef65d2021-07-17 12:51:52 -0700121 }
122 else
123 {
124 kprintf(WARN "Failed to find root inode 2\n");
125 }
swissChilief829f32021-06-13 20:00:54 -0700126}
swissChili9bd74de2021-06-15 20:30:48 -0700127
128bool ext2_valid_filesystem()
129{
130 struct ext2_superblock sb = ext2_read_superblock();
131
swissChili276b8cf2021-07-16 13:24:42 -0700132 kprintf(DEBUG "superblock signature is %d (0x%x)\n", sb.signature, sb.signature);
133
swissChili9bd74de2021-06-15 20:30:48 -0700134 return sb.signature == EXT2_SIGNATURE;
swissChilie5adca52021-06-16 21:00:31 -0700135}
swissChilib7ef65d2021-07-17 12:51:52 -0700136
137void ext2_write_superblock(struct ext2_superblock *sb)
138{
139 ushort *wp = (ushort *)sb;
140
141 ata_pio_write_sectors(2, 2, wp);
142}
143
144void ext2_corrupt_superblock_for_fun()
145{
146 struct ext2_superblock sb = ext2_read_superblock();
147 sb.signature = 0xDEAD;
148 ext2_write_superblock(&sb);
149}
150
151bool ext2_find_inode(struct ext2_superblock *sb, uint number, struct ext2_inode *inode)
152{
153 if (number == 0)
154 return false;
155
156 uint block_group = (number - 1) / sb->inodes_per_block_group;
157 uint local_index = (number - 1) % sb->inodes_per_block_group;
158
159 // Load this from the block group descriptor table
160 struct ext2_block_group_descriptor descriptor =
161 ext2_load_block_group_descriptor(sb, block_group);
162
swissChilicbd43632021-07-17 16:19:44 -0700163 // kprintf(DEBUG "Descriptor inode_table = 0x%x\n", descriptor.inode_table_start_block);
swissChilib7ef65d2021-07-17 12:51:52 -0700164
165 // We need to figure out what FS block the inode is on, we know how many
166 // inodes there are total in this BGD and the number per page, so this is
167 // simple.
168
169 const uint block_size = ext2_block_size(sb);
170
171 const uint inodes_per_block = block_size / sizeof(struct ext2_inode);
172
173 uint inode_block = local_index / inodes_per_block;
174 uint inode_index = local_index % inodes_per_block;
175
176 struct ext2_inode inodes[block_size / sizeof(struct ext2_inode)];
177
178 ext2_read_block(sb, inodes, descriptor.inode_table_start_block +
179 inode_block);
180
181 *inode = inodes[inode_index];
182
183 return true;
184}
185
186bool ext2_dir_ls(struct ext2_superblock *sb,
187 struct ext2_inode *dir,
188 void (*cb)(uint inode,
189 const char *name,
190 void *data),
191 void *data)
192{
193 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
194 return false;
195
196 for (int i = 0; i < dir->num_blocks; i++)
197 {
198 uchar buffer[ext2_block_size(sb)];
199 ext2_read_inode_block(sb, dir, buffer, i);
200
201 struct ext2_dirent *ent = (void *)buffer;
202
203 // While there are files in this block
swissChilicbd43632021-07-17 16:19:44 -0700204 while ((uint)ent < (uint)(buffer + ext2_block_size(sb)))
swissChilib7ef65d2021-07-17 12:51:52 -0700205 {
206 if (ent->inode == 0)
207 return true;
208
209 if (cb)
210 {
211 char name[257];
212
213 memcpy(name, ent->name, ent->name_len);
214 name[ent->name_len] = '\0';
swissChilicbd43632021-07-17 16:19:44 -0700215
swissChilib7ef65d2021-07-17 12:51:52 -0700216 cb(ent->inode, name, data);
217 }
218
219 ent = (void *)(((uint)(void *)ent) + ent->rec_len);
220 }
221 // We ran out of files in this block, continue to the next one. This
222 // works because files cannot span blocks
223 }
224
225 return true;
226}
227
swissChilicbd43632021-07-17 16:19:44 -0700228ssize_t ext2_read_inode(struct ext2_superblock *sb, struct ext2_inode *inode, void *buffer, ssize_t size)
229{
230 const uint block_size = ext2_block_size(sb);
231 char transfer[block_size];
232
233 uint fsize = MIN(inode->size, size);
234 uint i;
235
236 // Transfer full blocks straight to the output buffer
237 for (i = 0; i < fsize / block_size; i++)
238 {
239 ext2_read_inode_block(sb, inode, buffer + i * block_size, i);
240 }
241
242 // If we have part of a block left over read it here first, then transfer what we need
243 if (i * block_size < fsize)
244 {
245 uint remainder = fsize % block_size;
246
247 ext2_read_inode_block(sb, inode, transfer, i);
248 memcpy(buffer + i * block_size, transfer, remainder);
249 }
250
251 return fsize;
252}
253
swissChilib7ef65d2021-07-17 12:51:52 -0700254bool ext2_read_inode_block(struct ext2_superblock *sb,
255 struct ext2_inode *inode,
256 void *buffer,
257 uint block)
258{
259 if (block >= 12)
260 {
261 kprintf(ERROR "Sorry, EXT2 can only access the first 12 (direct) blocks "
262 "of an inode for now. Indirect look-up will be added later\n");
263 kpanic("Invalid inode block");
264 }
265
266 uint block_address = inode->blocks[block];
267
268 ext2_read_block(sb, buffer, block_address);
swissChilicbd43632021-07-17 16:19:44 -0700269
270 return true;
swissChilib7ef65d2021-07-17 12:51:52 -0700271}