blob: 3a1e18383c8fbda50b2b6c9d221f8b07ba4391f2 [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>
6
7inline uint ext2_block_size(struct ext2_superblock *sb)
8{
9 return 1024 << sb->block_size_shift;
10}
11
12void ext2_read_block(struct ext2_superblock *sb, void *buffer, uint block)
13{
14 uint block_size = ext2_block_size(sb) / 512;
15 uint block_start = block_size * block;
16
17 ata_pio_read_sectors(buffer, block_start, block_size);
18}
swissChili4418ca52021-06-14 17:36:00 -070019
20struct ext2_superblock ext2_read_superblock()
21{
22 uchar buffer[512 * 2];
23 ata_pio_read_sectors(buffer, 2, 2);
24
25 struct ext2_superblock *sb = (void *)(buffer);
26 return *sb;
27}
swissChilief829f32021-06-13 20:00:54 -070028
swissChilie5adca52021-06-16 21:00:31 -070029uint ext2_num_block_groups(struct ext2_superblock *sb)
30{
31 // This is a mildly janky way of rounding up
32 uint a = (sb->total_blocks - 1) / (sb->blocks_per_block_group + 1);
33 uint b = (sb->total_inodes - 1) / (sb->inodes_per_block_group + 1);
34
35 if (a == b)
36 {
37 return a;
38 }
39 else
40 {
41 kprintf(ERROR "EXT2 cannot find number of block groups, %d and %d "
42 "should equal.\n",
43 a, b);
44 kpanic("Corrupted filesystem");
45 }
46}
47
swissChilib7ef65d2021-07-17 12:51:52 -070048struct ext2_block_group_descriptor ext2_load_block_group_descriptor(
49 struct ext2_superblock *sb, uint block_group)
swissChilie5adca52021-06-16 21:00:31 -070050{
51 /**
52 * The BGDT (not to be confused with the GDT) is located the block after the
53 * superblock. On any block size EXCEPT 1024 (the minimum, remember that the
54 * block size is specified by X where 1024 << X is the real size) this is
55 * the second block (0-indexed, so 1). On 1024 this is the third block.
56 */
57 uint bgdt_block = 1;
58 uint block_size = ext2_block_size(sb);
59
60 if (block_size == 1024)
61 bgdt_block = 2;
62
swissChilib7ef65d2021-07-17 12:51:52 -070063 const uint bgd_size = sizeof(struct ext2_block_group_descriptor);
64
65 // Disk page that the BGD is on relative to the initial FILE SYSTEM block
66 uint hd_page = block_group / (512 / bgd_size);
67 // The offset from the beginning of that page the BGD is at
68 uint bgd_offset = block_group % (512 / bgd_size);
69
70 struct ext2_block_group_descriptor descriptors[512 / bgd_size];
71 kassert(sizeof(descriptors) == 512, "Wrong BGD size");
72
73 uint lba = (block_size / 512) * bgdt_block + hd_page;
74
75 ata_pio_read_sectors(&descriptors, lba, 1);
76
77 return descriptors[bgd_offset];
78}
79
80static void print_entry(uint inode, const char *name, void *data)
81{
82 kprintf("%d\t %s\n", inode, name);
swissChilie5adca52021-06-16 21:00:31 -070083}
84
swissChilief829f32021-06-13 20:00:54 -070085void ext2_mount(struct fs_node *where)
86{
swissChili4418ca52021-06-14 17:36:00 -070087 struct ext2_superblock sb = ext2_read_superblock();
88
swissChilie5adca52021-06-16 21:00:31 -070089 kprintf(DEBUG "EXT2 magic = 0x%x\n", sb.signature);
swissChilib7ef65d2021-07-17 12:51:52 -070090
91 // Read the root inode 2
92 struct ext2_inode root;
swissChilie5adca52021-06-16 21:00:31 -070093
swissChilib7ef65d2021-07-17 12:51:52 -070094 if (ext2_find_inode(&sb, 2, &root))
95 {
96 kprintf(OKAY "Found root inode 2 (size=0x%x, num_blocks=0x%x)\n", root.size, root.num_blocks);
97 // kprintf(DEBUG "Root.mode = 0x%x\n", root.mode & 0xf000);
98 kassert((root.mode & 0xf000) == EXT2_S_IFDIR, "Root (inode 2) is not a directory.");
99
100 kprintf("ls /\n");
101 kprintf("inode\t name\n");
102 kprintf("--------------------\n");
103 ext2_dir_ls(&sb, &root, print_entry, NULL);
104 }
105 else
106 {
107 kprintf(WARN "Failed to find root inode 2\n");
108 }
swissChilief829f32021-06-13 20:00:54 -0700109}
swissChili9bd74de2021-06-15 20:30:48 -0700110
111bool ext2_valid_filesystem()
112{
113 struct ext2_superblock sb = ext2_read_superblock();
114
swissChili276b8cf2021-07-16 13:24:42 -0700115 kprintf(DEBUG "superblock signature is %d (0x%x)\n", sb.signature, sb.signature);
116
swissChili9bd74de2021-06-15 20:30:48 -0700117 return sb.signature == EXT2_SIGNATURE;
swissChilie5adca52021-06-16 21:00:31 -0700118}
swissChilib7ef65d2021-07-17 12:51:52 -0700119
120void ext2_write_superblock(struct ext2_superblock *sb)
121{
122 ushort *wp = (ushort *)sb;
123
124 ata_pio_write_sectors(2, 2, wp);
125}
126
127void ext2_corrupt_superblock_for_fun()
128{
129 struct ext2_superblock sb = ext2_read_superblock();
130 sb.signature = 0xDEAD;
131 ext2_write_superblock(&sb);
132}
133
134bool ext2_find_inode(struct ext2_superblock *sb, uint number, struct ext2_inode *inode)
135{
136 if (number == 0)
137 return false;
138
139 uint block_group = (number - 1) / sb->inodes_per_block_group;
140 uint local_index = (number - 1) % sb->inodes_per_block_group;
141
142 // Load this from the block group descriptor table
143 struct ext2_block_group_descriptor descriptor =
144 ext2_load_block_group_descriptor(sb, block_group);
145
146 kprintf(DEBUG "Descriptor inode_table = 0x%x\n", descriptor.inode_table_start_block);
147
148 // We need to figure out what FS block the inode is on, we know how many
149 // inodes there are total in this BGD and the number per page, so this is
150 // simple.
151
152 const uint block_size = ext2_block_size(sb);
153
154 const uint inodes_per_block = block_size / sizeof(struct ext2_inode);
155
156 uint inode_block = local_index / inodes_per_block;
157 uint inode_index = local_index % inodes_per_block;
158
159 struct ext2_inode inodes[block_size / sizeof(struct ext2_inode)];
160
161 ext2_read_block(sb, inodes, descriptor.inode_table_start_block +
162 inode_block);
163
164 *inode = inodes[inode_index];
165
166 return true;
167}
168
169bool ext2_dir_ls(struct ext2_superblock *sb,
170 struct ext2_inode *dir,
171 void (*cb)(uint inode,
172 const char *name,
173 void *data),
174 void *data)
175{
176 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
177 return false;
178
179 for (int i = 0; i < dir->num_blocks; i++)
180 {
181 uchar buffer[ext2_block_size(sb)];
182 ext2_read_inode_block(sb, dir, buffer, i);
183
184 struct ext2_dirent *ent = (void *)buffer;
185
186 // While there are files in this block
187 while (ent < buffer + ext2_block_size(sb))
188 {
189 if (ent->inode == 0)
190 return true;
191
192 if (cb)
193 {
194 char name[257];
195
196 memcpy(name, ent->name, ent->name_len);
197 name[ent->name_len] = '\0';
198
199 cb(ent->inode, name, data);
200 }
201
202 ent = (void *)(((uint)(void *)ent) + ent->rec_len);
203 }
204 // We ran out of files in this block, continue to the next one. This
205 // works because files cannot span blocks
206 }
207
208 return true;
209}
210
211bool ext2_read_inode_block(struct ext2_superblock *sb,
212 struct ext2_inode *inode,
213 void *buffer,
214 uint block)
215{
216 if (block >= 12)
217 {
218 kprintf(ERROR "Sorry, EXT2 can only access the first 12 (direct) blocks "
219 "of an inode for now. Indirect look-up will be added later\n");
220 kpanic("Invalid inode block");
221 }
222
223 uint block_address = inode->blocks[block];
224
225 ext2_read_block(sb, buffer, block_address);
226}