*/
#include <ata.h>
#include <disk.h>
+#include <ext2.h>
#include <ide.h>
#include <io.h>
#include <irq.h>
buf[i] = 0;
}
+void ata_read_partions(ide_part_t *part, const char *buf) {
+ int offset = PARTITION_TABLE_OFFSET;
+ const char *p = buf + offset;
+
+ for (int i = 0; i < 4; i++) {
+ part->flags = (uint8_t)p[0];
+ part->lba_start = *((uint32_t *)(p + 8));
+ part->lba_end = *((uint32_t *)(p + 12));
+ part->lba_end += part->lba_start;
+
+ printk("part[%d] %02X %u %u\n", i, part->flags, part->lba_start, part->lba_end);
+
+ // 这里应该再判断一下part->flags,如果是扩展分区还需要再读取
+ // 先这样实现
+
+ p += 16; // 每个分区16个字节
+ part++;
+ }
+}
+
+// 读hda0 的 super block
+void ata_read_ext2_sb() {
+ ide_part_t *part = ide_drives[0].partions + 1;
+ const int size = 1024;
+ const int offset = 1024;
+ char *buf = kmalloc(size, 0);
+ disk_request_t r;
+ r.dev = MAKE_DEV(DEV_MAJOR_IDE0, 1);
+ r.command = DISK_REQ_READ;
+ r.pos = part->lba_start + offset / SECT_SIZE;
+ r.count = size / SECT_SIZE;
+ r.buf = buf;
+ send_disk_request(&r);
+ ext2_sb_t *p = (ext2_sb_t *)buf;
+ printk("inodes count %u inodes per group %u free %u\n", p->s_inodes_count, p->s_inodes_per_group,
+ p->s_free_inodes_count);
+ printk("blocks count %u blocks per group %u free %u magic %04x\n", p->s_blocks_count, p->s_blocks_per_group,
+ p->s_free_blocks_count, p->s_magic);
+ printk("first ino %u inode size %u first data block %u\n", p->s_first_ino, p->s_inode_size, p->s_first_data_block);
+ printk("log block size %u write time %u\n", p->s_log_block_size, p->s_wtime);
+ p->s_volume_name[63] = 0;
+ printk("volume %s\n", p->s_volume_name);
+ kfree(buf);
+}
+
// 《AT Attachment 8 - ATA/ATAPI Command Set》
void ide_ata_init() {
for (int i = 0; i < MAX_IDE_DRIVE_CNT; i++) {
memset(ide_drives + i, 0, sizeof(ide_drive_t));
ide_drive_t *drv = ide_drives + drv_no;
+ drv->drv_no = drv_no;
drv->ide_pci_controller = ide_pci_controller + channel;
// https://wiki.osdev.org/ATA_PIO_Mode
uint8_t status = inb(REG_STATUS(drv_no));
if (status == 0 || (status & ATA_STATUS_ERR) || (status & ATA_STATUS_RDY == 0)) {
- ide_drives[i].present = 0;
+ drv->present = 0;
continue;
} else {
- ide_drives[i].present = 1;
+ drv->present = 1;
}
- printk("ata[%d] status %x %s exists\n", i, status, ide_drives[i].present == 1 ? "" : "not");
+ printk("ata[%d] status %x %s exists\n", i, status, drv->present == 1 ? "" : "not");
insl(REG_DATA(drv_no), identify, SECT_SIZE / sizeof(uint32_t));
// 第49个word的第8个bit位表示是否支持DMA
// 第100~103个word的八个字节表示user的LBA最大值
// printk("%04x %04x %d %d\n", identify[49], 1 << 8, identify[49] & (1 << 8), (identify[49] & (1 << 8)) != 0);
if ((identify[49] & (1 << 8)) != 0) {
- ide_drives[i].dma = 1;
+ drv->dma = 1;
}
u64 max_lba = *(u64 *)(identify + 100);
if ((identify[83] & (1 << 10)) != 0) {
- ide_drives[i].lba48 = 1;
- ide_drives[i].max_lba = max_lba;
+ drv->lba48 = 1;
+ drv->max_lba = max_lba;
}
#if 0
uint16_t i80 = identify[80];
break;
}
#endif
- printk("hard disk %s %s size: %u MB\n", ide_drives[i].dma == 1 ? "DMA" : "",
- ide_drives[i].lba48 == 1 ? "LBA48" : "LBA28", (max_lba * 512) >> 20);
+ printk("hard disk %s %s size: %u MB\n", drv->dma == 1 ? "DMA" : "", drv->lba48 == 1 ? "LBA48" : "LBA28",
+ (max_lba * 512) >> 20);
char s[64];
ata_read_identity_string(identify, 10, 19, s);
ata_read_identity_string(identify, 27, 46, s);
printk("HD Model: %s\n", s);
+
+ // 0 代表整个硬盘
+ // 1~4代表各个主分区
+ // 5~15 代表各个逻辑分区
+ drv->partions[0].flags = 0x00;
+ drv->partions[0].lba_start = 0;
+ drv->partions[0].lba_end = drv->max_lba;
}
}
-#if 0
-void ata_init() {
- // 初始化hard_disk与中断函数之间的信号量
-
- disk_request_t r;
- r.drv = 0;
- r.buf = (void *)identify;
- r.count = 1;
- r.pos = 0;
- r.command = DISK_REQ_IDENTIFY;
-
- send_disk_request(&r);
+void ide_read_partions() {
+ for (int i = 0; i < MAX_IDE_DRIVE_CNT; i++) {
+ ide_drive_t *drv = ide_drives + i;
+ int channel = i >> 1;
- // 第49个word的第8个bit位表示是否支持DMA
- // 第83个word的第10个bit位表示是否支持LBA48,为1表示支持。
- // 第100~103个word的八个字节表示user的LBA最大值
- printd("disk identify %04x %04x %d %d\n", identify[49], 1 << 8, identify[49] & (1 << 8),
- (identify[49] & (1 << 8)) != 0);
- if ((identify[49] & (1 << 8)) != 0) {
- printd("support DMA\n");
+ if (0 == drv->present) {
+ continue;
+ }
+ disk_request_t r;
+ char *sect = kmalloc(SECT_SIZE, 0);
+ r.dev = MAKE_DEV(DEV_MAJOR_IDE0, 0); // IDE0 0代表整个master硬盘
+ r.command = DISK_REQ_READ;
+ r.pos = 0;
+ r.count = 1;
+ r.buf = sect;
+ send_disk_request(&r);
+ ata_read_partions(drv->partions + 1, sect);
+ kfree(sect);
}
+}
- if ((identify[83] & (1 << 10)) != 0) {
- printd("support LBA48\n");
- u64 lba = *(u64 *)(identify + 100);
- printd("hard disk size: %u MB\n", (lba * 512) >> 20);
- }
+void ide_disk_read(dev_t dev, uint32_t block, uint32_t size, char *buf) {
+ ide_drive_t *drv = ide_get_drive(dev);
+ uint64_t lba_offset = drv->partions[DEV_MINOR((dev))].lba_start;
- // TODO REMOVE
- mbr_buf = kmalloc(SECT_SIZE, 0);
+ disk_request_t r;
+ r.dev = dev;
r.command = DISK_REQ_READ;
- r.pos = 0;
- r.count = 1;
- r.buf = mbr_buf;
+ r.pos = lba_offset + block / SECT_SIZE;
+ r.count = size / SECT_SIZE;
+ r.buf = buf;
send_disk_request(&r);
- uint16_t *p = (uint16_t *)mbr_buf;
- for (int i = 0; i < 256; i++) {
- if (i % 12 == 0) {
- printd("\n[%03d] ", i * 2);
- }
- printd("%04x.", p[i]);
- }
}
-#endif
// ATA_CMD_READ_DMA_EXT
void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest) {
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: block.c
+ * Author: Zhao Yanbai
+ * 2023-06-20 19:30:47 Tuesday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <disk.h>
+#include <fs.h>
+#include <ide.h>
+
+blk_buffer_t *block_read(dev_t dev, uint32_t block, uint32_t size) {
+ blk_buffer_t *bb = 0;
+
+ assert(DEV_MAJOR(dev) == DEV_MAJOR_IDE0);
+ assert(DEV_MINOR(dev) == 1);
+
+ // 目前不提供hash表组强起来的缓冲功能
+ // 直接读
+
+ ide_disk_read(dev, block, size, bb->data);
+
+ return bb;
+}
init_pci_controller(0x0101);
// init_pci_controller(0x7010);
+ request_irq(0x0E, ide_irq_handler, "hard", "IDE");
+
+ request_irq(0x0F, ide_irq_handler, "hard", "IDE");
+
// 读IDE 硬盘的identity
ide_ata_init();
+}
- request_irq(0x0E, ide_irq_handler, "hard", "IDE");
+ide_drive_t *ide_get_drive(dev_t dev) {
+ int major = DEV_MAJOR(dev);
+ int minor = DEV_MINOR(dev);
+ assert(major == DEV_MAJOR_IDE0 || major == DEV_MAJOR_IDE1);
+ assert(minor < MAX_IDE_PARTIONS * 2); // 因为一个通道有两个硬盘,每个硬盘最大MAX_IDE_PARTIONS分区
- request_irq(0x0F, ide_irq_handler, "hard", "IDE");
+ int channel = major == DEV_MAJOR_IDE0 ? 0 : 1;
+ int index = minor / MAX_IDE_PARTIONS;
+
+ int drv_no = channel * 2 + index;
+
+ ide_drive_t *drv = ide_drives + drv_no;
+
+ return drv;
}
#define PCI_IDE_PRDT 4
// #define PARTITION_CNT 4
-// #define PARTITION_TABLE_OFFSET 0x1BE
-// #define MAX_SUPPORT_PARTITION_CNT 16
+#define PARTITION_TABLE_OFFSET 0x1BE
+#define MAX_IDE_PARTIONS 16
-// typedef struct {
-// u64_t lba_start;
-// u64_t lba_end;
-// } part_t;
-
-// void ide_do_read(u64_t lba, u32_t scnt, char *buf);
-// part_t *ide_get_part(dev_t dev);
+// 分区定义
+typedef struct ide_part_ {
+ uint8_t flags;
+ uint32_t lba_start;
+ uint32_t lba_end;
+} ide_part_t;
// Physical Region Descriptor
typedef struct prdte {
typedef struct _ide_drive {
int present;
+ int drv_no;
int dma;
uint64_t lba48;
uint64_t max_lba;
ide_pci_controller_t *ide_pci_controller;
+
+ ide_part_t partions[MAX_IDE_PARTIONS];
} ide_drive_t;
#define MAX_IDE_DRIVE_CNT 4
extern ide_drive_t ide_drives[MAX_IDE_DRIVE_CNT];
+ide_drive_t *ide_get_drive(dev_t dev);
+
void sleep_on_ide();
void wait_on_ide();
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: buffer.c
+ * Author: Zhao Yanbai
+ * 2023-06-20 19:30:33 Tuesday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
#include "mm.h"
#include "string.h"
#include "system.h"
+#include "vfs.h"
+
+superblock_t *ext2_read_super(superblock_t *sb, void *data) { return sb; }
+
+fs_type_t ext2_fs_type = {
+ "ext2",
+ ext2_read_super,
+ 0,
+};
struct {
ext2_sb_t ext2_sb;
unsigned long ext2_block_size();
#define EXT2_BLOCK_SIZE ext2_block_size()
-//#define EXT2_BLOCK_SIZE (EXT2_MIN_BLOCK_SIZE << (EXT2_SB)->s_log_block_size)
+// #define EXT2_BLOCK_SIZE (EXT2_MIN_BLOCK_SIZE << (EXT2_SB)->s_log_block_size)
#define EXT2_SECT_PER_BLOCK (EXT2_BLOCK_SIZE / 512)
* EXT2 FILE SYSTEM PART
* ------------------------------------------------------------------------
*/
+// https://www.nongnu.org/ext2-doc/ext2.html
+// 关于s_first_data_block
+// 32bit value identifying the first data block, in other word the id of the block containing the superblock structure.
+// Note that this value is always 0 for file systems with a block size larger than 1KB, and always 1 for file systems
+// with a block size of 1KB. The superblock is always starting at the 1024th byte of the disk, which normally happens to
+// be the first byte of the 3rd sector.
typedef struct ext2_superblock {
u32 s_inodes_count; /* Inodes count */
u32 s_blocks_count; /* Blocks count */
* ------------------------------------------------------------------------
*/
+#include <string.h>
#include <vfs.h>
-vfs_sb_t *root_sb = 0;
\ No newline at end of file
+// 要访问一个文件就必需先访问一个目录,才能根据文件名从目录中找到该文件的目录项,进而找到其inode
+// 但是目录本身也是文件,它本身的目录项dentry又在另一个目录项中
+// 这个递归问题的出口在于,必然有一个目录,它的目录项不在其它目录中,而在一个固定的位置上
+// 或者可通过固定的算法找到,且从该目录出发就可以找到系统中的所有文件
+// 这个目录就是根目录"/",或者说是根设备上的根目录。
+// 每个文件系统都有一个根目录和一个超级块,根目录的位置及文件系统中的其它参数就记录在超级块中
+// 超级块在设备上的逻辑位置对每个文件系统来说都是固定的
+// 系统在初始化的时候要将一个存储设备作为整个系统的根设备,它的根目录就成为整个文件系统的总根目录,即"/"
+// 更确切地说,就是把根设备的根目录安装在文件系统的的总根"/"节点上。
+// 有了根设备以后,还可以把其它存储设备也安装到文件系统的空闲目录节点上。
+// 所谓“安装“就是从一个存储设备上读入超级块,在内存中建立起一个superblock结构。进而将此设备上的根目录
+// 与文件系统中已经存在的一个空白目录挂上钩。
+// 系统初始化时整个文件系统只有一个空白目录"/",所以根设备的根目录就安装到这个节点上。
+dentry_t *root_entry = 0;
+
+fs_type_t file_systems = {"filesystems", 0, 0};
+
+void register_filesystem(fs_type_t *fs) {
+ int ret = 0;
+
+ fs_type_t *add = &file_systems;
+
+ for (fs_type_t *fst = &file_systems; fst != 0; fst = fst->next) {
+ if (strcmp(fst->name, fs->name) == 0) {
+ return;
+ }
+ add = fst;
+ }
+
+ add->next = fs;
+ fs->next = 0;
+}
#pragma once
-typedef struct vfs_dentry vfs_dentry_t;
+#include <list.h>
-typedef struct vfs_sb_operations vfs_sb_operations_t;
-typedef struct vfs_inode_operations vfs_inode_operations_t;
-typedef struct vfs_dentry_operations vfs_dentry_operations_t;
+typedef struct dentry dentry_t;
+
+typedef struct sb_operations sb_operations_t;
+typedef struct inode_operations inode_operations_t;
+typedef struct dentry_operations dentry_operations_t;
// super block
-typedef struct vfs_sb {
+typedef struct superblock {
//
- vfs_dentry_t *root;
- void *private;
- vfs_sb_operations_t *sb_ops;
-} vfs_sb_t;
+ dentry_t *sb_root;
+ void *sb_private;
+ sb_operations_t *sb_ops;
+} superblock_t;
+
+// dentry和inode为什么不合二为一?
+// 每一个文件除了有一个索引节点inode(里面记录着文件在存储介质上的位置和分布信息)外还有一个目录项dentry
+// 同时dentry还有个指针指向inode结构
+// 这里inode 和 dentry 都是在从不同角度描述同个文件的各方面属性,不将他们合二为一的原因是
+// dentry和inode描述的目标是不同的,因为一个文件可能有好几个文件名,通过不同的文件名访问同一个文件时权限也可能不同
+// 所以dentry代表逻辑意义上的文件,记录的是逻辑意义上的属性
+// 而inode结构代表的是物理意义上的文件
+// 它们之间的关系是多对一的关系
+typedef struct inode {
+ superblock_t *i_sb;
+ void *i_private;
+ inode_operations_t *i_ops;
+
+ // 缓存的pages
+ list_head_t i_pages;
+} inode_t;
+
+struct dentry {
+ char *d_name;
-typedef struct vfs_inode {
//
- vfs_sb_t *sb;
- void *private;
- vfs_inode_operations_t *i_ops;
-} vfs_inode_t;
+ dentry_t *d_parent;
+
+ // 同一目录里所有结点通过d_child链接在一起
+ // 并连到它们父目录的d_subdirs队列中
+ list_head_t d_child;
+ list_head_t d_subdirs;
-struct vfs_dentry {
//
- vfs_dentry_operations_t *d_ops;
+ superblock_t *d_sb;
+
+ // 每一个dentry指向一个inode
+ // 但多个dentry可以指向同一个inode(不实现)
+ inode_t *d_inode;
+
+ //
+ dentry_operations_t *d_ops;
+
+ //
+ void *d_private;
};
-struct vfs_sb_operations {
+struct sb_operations {
//
};
-struct vfs_inode_operations {
+struct inode_operations {
//
};
-struct vfs_dentry_operations {
+struct dentry_operations {
//
};
-extern vfs_sb_t *root_sb;
\ No newline at end of file
+// 每当将一个存储设备安装到现有文件系统中的某个节点时,内核就要为之建立一个vfsmount结构
+// 这个结构中即包含着该设备的有关信息,也包含了安装点的信息
+// 系统中的每个文件系统,包括根设备的根文件系统,都要经过安装
+typedef struct vfsmount {
+} vfsmount_t;
+
+typedef struct fs_type {
+ const char *name;
+ superblock_t *(*read_super)(superblock_t *, void *);
+ struct fs_type *next;
+} fs_type_t;
+
+extern superblock_t *root_sb;
+
+void register_filesystem(fs_type_t *fs);
} disk_request_queue_t;
void send_disk_request(disk_request_t *r);
+
+void ide_disk_read(dev_t dev, uint32_t block, uint32_t size, char *buf);
#define DEV_MAJOR(dev) ((unsigned int)((dev) >> DEV_MAJOR_BITS))
#define DEV_MINOR(dev) ((unsigned int)((dev)&DEV_MINOR_MASK))
-//#define MAX_SUPT_FILE_SIZE (1)
+// #define MAX_SUPT_FILE_SIZE (1)
#define NR_FILES (1)
#define NR_OPENS (1)
return ext2_read_file(inode, buf, count);
}
-/* 在多进程下这样肯定不行
+/* 在多进程下这样肯定不行
* 管不了这么多了,先这样写吧
*/
static inline pInode find_empty_inode()
}
#endif
+typedef uint32_t dev_t;
+
+typedef struct blk_bufer {
+ uint32_t blocknr; // block number
+ char *data; //
+ uint16_t size; // block size
+ dev_t dev;
+ page_t *page;
+} blk_buffer_t;
+
#endif //_FS_H
struct kmem_cache;
typedef struct kmem_cache kmem_cache_t;
+struct blk_buffer;
typedef struct page {
unsigned long count;
unsigned long flags;
unsigned long index;
list_head_t lru;
- struct page *head_page;
+ struct page *head_page; // buddy system
unsigned int order;
void **freelist; // for slub
+
kmem_cache_t *cache;
unsigned long inuse;
+
+ //
+ struct blk_buffer *buffers;
} page_t;
void *page2va(page_t *page);
panic("null disk request");
}
- // TODO: 转换
- int drv_no = r->dev;
- // assert(drv_no == 0);
-
- assert(drv_no >= 0);
- assert(drv_no <= MAX_IDE_DRIVE_CNT);
-
- ide_drive_t *drv = ide_drives + drv_no;
+ ide_drive_t *drv = ide_get_drive(r->dev);
assert(drv->present == 1);
mutex_unlock(&ide_ctrl->request_mutex);
// TODO dev -> drv
- int drv_no = r->dev;
- ide_drive_t *drv = ide_drives + drv_no;
+ ide_drive_t *drv = ide_get_drive(r->dev);
+ int drv_no = drv->drv_no;
if (drv->present == 0) {
panic("disk not present");
}
}
// 等待硬盘中断
+ printk("down ide req\n");
down(&ide_ctrl->disk_intr_sem);
// 读数据
void init_task_entry() {
current->priority = 10;
+ void ide_read_partions();
+ ide_read_partions();
+
+ void ata_read_ext2_sb();
+ ata_read_ext2_sb();
+
while (1) {
asm("sti;hlt;");
sysc_wait(2);
// asm("hlt;");
// }
- kernel_task("tskA", taskA_entry, NULL);
- kernel_task("tskB", taskB_entry, NULL);
- kernel_task("tskC", taskC_entry, NULL);
+ // kernel_task("tskA", taskA_entry, NULL);
+ // kernel_task("tskB", taskB_entry, NULL);
+ // kernel_task("tskC", taskC_entry, NULL);
current->priority = 1;
while (1) {
menuentry 'Kernel.ISO' --class os {
#insmod ext2
set root='(hd0,1)'
- multiboot2 /boot/Kernel root=hda0 delay=2
+ multiboot2 /boot/Kernel root=hda1 delay=2
boot
}