diff options
author | Marvin Borner | 2020-07-23 21:06:44 +0200 |
---|---|---|
committer | Marvin Borner | 2020-07-23 21:06:44 +0200 |
commit | 6becbff5724d79cb3a958db297b5c3310200daea (patch) | |
tree | 295a5b4bf7ee2234fdc56c24fec28f936927de21 | |
parent | a0b8c61b09200aa3f9e27878cb866648a7d26502 (diff) |
Added *very* simple ide and ext2 support
-rw-r--r-- | Makefile | 4 | ||||
-rwxr-xr-x | run | 4 | ||||
-rw-r--r-- | src/drivers/cpu.c | 8 | ||||
-rw-r--r-- | src/drivers/ide.c | 41 | ||||
-rw-r--r-- | src/features/fs.c | 150 | ||||
-rw-r--r-- | src/inc/cpu.h | 1 | ||||
-rw-r--r-- | src/inc/fs.h | 97 | ||||
-rw-r--r-- | src/inc/ide.h | 40 | ||||
-rw-r--r-- | src/lib/inc/str.h | 1 | ||||
-rw-r--r-- | src/lib/str.c | 16 | ||||
-rw-r--r-- | src/main.c | 5 |
11 files changed, 364 insertions, 3 deletions
@@ -7,6 +7,8 @@ COBJS = src/main.o \ src/drivers/interrupts.o \ src/drivers/interrupts_asm.o \ src/drivers/keyboard.o \ + src/drivers/ide.o \ + src/features/fs.o \ src/lib/str.o \ src/lib/mem.o \ src/lib/math.o \ @@ -17,7 +19,7 @@ LD = cross/opt/bin/i686-elf-ld AS = nasm # TODO: Use lib as external library -CFLAGS = -Wall -Wextra -nostdlib -nostdinc -ffreestanding -mgeneral-regs-only -mno-80387 -std=c99 -pedantic-errors -Isrc/lib/inc/ -Isrc/inc/ -c +CFLAGS = -Wall -Wextra -nostdlib -nostdinc -ffreestanding -mgeneral-regs-only -std=c99 -pedantic-errors -Isrc/lib/inc/ -Isrc/inc/ -c ASFLAGS = -f elf32 @@ -73,7 +73,9 @@ make_build() { dd if=/dev/zero of=build/disk.img bs=1k count=16k sudo mke2fs build/disk.img >/dev/null dd if=build/boot.bin of=build/disk.img conv=notrunc - ./ext2util/ext2util -x build/disk.img -wf build/kernel.bin -i 5 >/dev/null + cp build/kernel.bin . # For nicer disk img + ./ext2util/ext2util -x build/disk.img -wf kernel.bin -i 5 >/dev/null + rm kernel.bin printf "Build finshed successfully!\n\n" } diff --git a/src/drivers/cpu.c b/src/drivers/cpu.c index 22691fb..d6a1760 100644 --- a/src/drivers/cpu.c +++ b/src/drivers/cpu.c @@ -24,6 +24,14 @@ u32 inl(u16 port) return value; } +void insl(u16 port, void *addr, int n) +{ + __asm__("cld; rep insl" + : "=D"(addr), "=c"(n) + : "d"(port), "0"(addr), "1"(n) + : "memory", "cc"); +} + void outb(u16 port, u8 data) { __asm__("outb %0, %1" ::"a"(data), "Nd"(port)); diff --git a/src/drivers/ide.c b/src/drivers/ide.c new file mode 100644 index 0000000..fe3955c --- /dev/null +++ b/src/drivers/ide.c @@ -0,0 +1,41 @@ +// MIT License, Copyright (c) 2020 Marvin Borner + +#include <cpu.h> +#include <def.h> +#include <ide.h> + +int ide_wait(int check) +{ + char r; + + // Wait while drive is busy. Once just ready is set, exit the loop + while (((r = (char)inb(IDE_IO | IDE_CMD)) & (IDE_BUSY | IDE_READY)) != IDE_READY) + ; + + // Check for errors + if (check && (r & (IDE_DRIVE_FAULT | IDE_ERROR)) != 0) + return 0xF; + return 0; +} + +void *ide_read(void *b, u32 block) +{ + int sector_per_block = BLOCK_SIZE / SECTOR_SIZE; // 2 + int sector = block * sector_per_block; + + ide_wait(0); + outb(IDE_IO | IDE_SECTOR_COUNT, sector_per_block); // Number of sectors + outb(IDE_IO | IDE_LOW, LBA_LOW(sector)); + outb(IDE_IO | IDE_MID, LBA_MID(sector)); + outb(IDE_IO | IDE_HIGH, LBA_HIGH(sector)); + + // Slave/Master << 4 and last 4 bits + outb(IDE_IO | IDE_HEAD, 0xE0 | (1 << 4) | LBA_LAST(sector)); + outb(IDE_IO | IDE_CMD, IDE_CMD_READ); + ide_wait(0); + + // Read-only + insl(IDE_IO, b, BLOCK_SIZE / 4); + + return b; +} diff --git a/src/features/fs.c b/src/features/fs.c new file mode 100644 index 0000000..ba66033 --- /dev/null +++ b/src/features/fs.c @@ -0,0 +1,150 @@ +// MIT License, Copyright (c) 2020 Marvin Borner +// EXT2 based filesystem + +#include <def.h> +#include <fs.h> +#include <ide.h> +#include <mem.h> +#include <print.h> +#include <str.h> + +void *buffer_read(int block) +{ + return ide_read(malloc(BLOCK_SIZE), block); +} + +struct superblock *get_superblock() +{ + struct superblock *sb = buffer_read(EXT2_SUPER); + if (sb->magic != EXT2_MAGIC) + return NULL; + return sb; +} + +struct bgd *get_bgd() +{ + return buffer_read(EXT2_SUPER + 1); +} + +struct inode *get_inode(int i) +{ + struct superblock *s = get_superblock(); + struct bgd *b = get_bgd(); + + int block_group = (i - 1) / s->inodes_per_group; + int index = (i - 1) % s->inodes_per_group; + int block = (index * INODE_SIZE) / BLOCK_SIZE; + b += block_group; + + u32 *data = buffer_read(b->inode_table + block); + struct inode *in = + (struct inode *)((u32)data + (index % (BLOCK_SIZE / INODE_SIZE)) * INODE_SIZE); + return in; +} + +u32 read_indirect(u32 indirect, u32 block_num) +{ + char *data = buffer_read(indirect); + return *(u32 *)((u32)data + block_num * 4); +} + +void *read_file(struct inode *in) +{ + //assert(in); + if (!in) + return NULL; + + int num_blocks = in->blocks / (BLOCK_SIZE / SECTOR_SIZE); + + // assert(num_blocks != 0); + if (!num_blocks) + return NULL; + + u32 sz = BLOCK_SIZE * num_blocks; + void *buf = malloc(sz); + //assert(buf != NULL); + + int indirect = 0; + + // Single indirect pointer + if (num_blocks > 12) { + indirect = in->block[13]; + } + + int blocknum = 0; + char *data; + for (int i = 0; i < num_blocks; i++) { + if (i < 12) { + blocknum = in->block[i]; + data = buffer_read(blocknum); + memcpy((void *)((u32)buf + (i * BLOCK_SIZE)), data, BLOCK_SIZE); + } + if (i > 12) { + blocknum = read_indirect(indirect, i - 13); + data = buffer_read(blocknum); + memcpy((void *)((u32)buf + ((i - 1) * BLOCK_SIZE)), data, BLOCK_SIZE); + } + } + return buf; +} + +int find_inode(const char *name, int dir_inode) +{ + if (!dir_inode) + return -1; + + struct inode *i = get_inode(dir_inode); + + char *buf = malloc(BLOCK_SIZE * i->blocks / 2); + memset(buf, 0, BLOCK_SIZE * i->blocks / 2); + + for (u32 q = 0; q < i->blocks / 2; q++) { + char *data = buffer_read(i->block[q]); + memcpy((void *)((u32)buf + (q * BLOCK_SIZE)), data, BLOCK_SIZE); + } + + struct dirent *d = (struct dirent *)buf; + + u32 sum = 0; + do { + // Calculate the 4byte aligned size of each entry + sum += d->total_len; + //printf("%2d %10s\t%2d %3d\n", (int)d->inode, d->name, d->name_len, d->rec_len); + if (strncmp((void *)d->name, name, d->name_len) == 0) { + free(buf); + return d->inode_num; + } + d = (struct dirent *)((u32)d + d->total_len); + + } while (sum < (1024 * i->blocks / 2)); + free(buf); + return -1; +} + +void ls_root() +{ + struct inode *i = get_inode(2); + + char *buf = malloc(BLOCK_SIZE * i->blocks / 2); + + for (u32 q = 0; q < i->blocks / 2; q++) { + char *data = buffer_read(i->block[q]); + memcpy((void *)((u32)buf + (q * BLOCK_SIZE)), data, BLOCK_SIZE); + } + + struct dirent *d = (struct dirent *)buf; + + int sum = 0; + int calc = 0; + printf("Root directory:\n"); + do { + calc = (sizeof(struct dirent) + d->name_len + 4) & ~0x3; + sum += d->total_len; + printf("/%s\n", d->name); + if (d->total_len != calc && sum == 1024) + d->total_len = calc; + + d = (struct dirent *)((u32)d + d->total_len); + + } while (sum < 1024); +} diff --git a/src/inc/cpu.h b/src/inc/cpu.h index ad83896..b8897de 100644 --- a/src/inc/cpu.h +++ b/src/inc/cpu.h @@ -8,6 +8,7 @@ u8 inb(u16 port); u16 inw(u16 port); u32 inl(u16 port); +void insl(u16 port, void *addr, int n); void outb(u16 port, u8 data); void outw(u16 port, u16 data); diff --git a/src/inc/fs.h b/src/inc/fs.h new file mode 100644 index 0000000..e5e1ca7 --- /dev/null +++ b/src/inc/fs.h @@ -0,0 +1,97 @@ +// MIT License, Copyright (c) 2020 Marvin Borner +// EXT2 based filesystem + +#ifndef FS_H +#define FS_H + +#include <def.h> + +#define EXT2_BOOT 0 +#define EXT2_SUPER 1 +#define EXT2_MAGIC 0x0000EF53 + +struct superblock { + u32 total_inodes; + u32 total_blocks; + u32 su_res_blocks; // Superuser reserved + u32 free_blocks; + u32 free_inodes; + u32 superblock_block_num; + u32 log2_block_size; + u32 log2_frag_size; + u32 blocks_per_group; + u32 frags_per_group; + u32 inodes_per_group; + u32 last_mount_time; + u32 last_write_time; + u16 mounts_since_fsck; + u16 max_mounts_since_fsck; + u16 magic; + u16 state; // 1 clean; 2 errors + u16 error_action; + u16 minor_version; + u32 last_fsck_time; + u32 max_time_since_fsck; + u32 creator_os_id; + u32 major_version; + u16 res_block_uid; + u16 res_block_gid; +}; + +struct bgd { + u32 block_bitmap; + u32 inode_bitmap; + u32 inode_table; + u16 free_blocks; + u16 free_inodes; + u16 used_dirs; + u16 pad; + u8 bg_reserved[12]; +}; + +struct inode { + u16 mode; + u16 uid; + u32 size; + + u32 last_access_time; + u32 creation_time; + u32 last_modification_time; + u32 deletion_time; + + u16 gid; + u16 link_count; + u32 blocks; + u32 flags; + u32 os_specific_val1; + u32 block[15]; + u32 generation; + + u32 reserved1; + u32 reserved2; + + u32 fragment_addr; + u8 os_specific_val2[12]; +}; +#define INODE_SIZE (sizeof(struct inode)) + +struct dirent { + u32 inode_num; + u16 total_len; + u8 name_len; + u8 type_indicator; + u8 name[]; +}; + +struct file { + struct inode inode; + u32 pos; + u8 block_index; + u8 *buf; + u32 curr_block_pos; +}; + +// DEMO ;) +void ls_root(); + +#endif diff --git a/src/inc/ide.h b/src/inc/ide.h new file mode 100644 index 0000000..9d753ae --- /dev/null +++ b/src/inc/ide.h @@ -0,0 +1,40 @@ +// MIT License, Copyright (c) 2020 Marvin Borner + +#ifndef IDE_H +#define IDE_H + +#include <def.h> + +#define BLOCK_SIZE 1024 +#define SECTOR_SIZE 512 + +#define IDE_BUSY (1 << 7) +#define IDE_READY (1 << 6) +#define IDE_DRIVE_FAULT (1 << 5) +#define IDE_ERROR (1 << 0) + +#define IDE_IO 0x1F0 +#define IDE_DATA 0x0 +#define IDE_FEATURES 0x1 +#define IDE_SECTOR_COUNT 0x2 +#define IDE_LOW 0x3 +#define IDE_MID 0x4 +#define IDE_HIGH 0x5 +#define IDE_HEAD 0x6 +#define IDE_CMD 0x7 +#define IDE_ALTERNATE 0x3F6 + +#define LBA_LOW(c) ((u8)(c & 0xFF)) +#define LBA_MID(c) ((u8)(c >> 8) & 0xFF) +#define LBA_HIGH(c) ((u8)(c >> 16) & 0xFF) +#define LBA_LAST(c) ((u8)(c >> 24) & 0xF) + +#define IDE_CMD_READ (BLOCK_SIZE / SECTOR_SIZE == 1) ? 0x20 : 0xC4 +#define IDE_CMD_WRITE (BLOCK_SIZE / SECTOR_SIZE == 1) ? 0x30 : 0xC5 +#define IDE_CMD_READ_MUL 0xC4 +#define IDE_CMD_WRITE_MUL 0xC5 + +int ide_wait(int check); +void *ide_read(void *b, u32 block); + +#endif diff --git a/src/lib/inc/str.h b/src/lib/inc/str.h index 0e00e75..f4c63b1 100644 --- a/src/lib/inc/str.h +++ b/src/lib/inc/str.h @@ -10,6 +10,7 @@ char *strcpy(char *dst, const char *src); char *strchr(const char *s, int c); char *strcat(char *dst, const char *src); int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, u32 n); char *strinv(char *s); char *strdup(const char *s); diff --git a/src/lib/str.c b/src/lib/str.c index 24f95e5..d1ee325 100644 --- a/src/lib/str.c +++ b/src/lib/str.c @@ -40,6 +40,22 @@ int strcmp(const char *s1, const char *s2) return d; } +int strncmp(const char *s1, const char *s2, u32 n) +{ + const u8 *c1 = (const u8 *)s1; + const u8 *c2 = (const u8 *)s2; + u8 ch; + int d = 0; + + while (n--) { + d = (int)(ch = *c1++) - (int)*c2++; + if (d || !ch) + break; + } + + return d; +} + char *strchr(const char *s, int c) { while (*s != (char)c) { @@ -2,6 +2,7 @@ #include <boot.h> #include <def.h> +#include <fs.h> #include <interrupts.h> #include <keyboard.h> #include <print.h> @@ -24,7 +25,9 @@ void main(struct mem_info *mem_info, struct vid_info *vid_info) vesa_fill(terminal_background); serial_install(); - printf("hello"); + printf("hello\n"); + + ls_root(); while (1) { }; |