From: acevest Date: Tue, 20 Jun 2023 13:11:04 +0000 (+0800) Subject: ide ata disk 简单支持设备号 X-Git-Url: http://zhaoyanbai.com/repos/man.rndc.conf.html?a=commitdiff_plain;h=2bab0e22903978bb296e995af94c186dd63386fe;p=kernel.git ide ata disk 简单支持设备号 --- diff --git a/drivers/ata.c b/drivers/ata.c index 30cf4d2..2384f4a 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include @@ -69,6 +70,51 @@ void ata_read_identity_string(const uint16_t *identify, int bgn, int end, char * 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++) { @@ -77,6 +123,7 @@ void ide_ata_init() { 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 @@ -115,13 +162,13 @@ void ide_ata_init() { 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 @@ -129,14 +176,14 @@ void ide_ata_init() { // 第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]; @@ -175,8 +222,8 @@ void ide_ata_init() { 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); @@ -187,53 +234,49 @@ void ide_ata_init() { 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) { diff --git a/drivers/block.c b/drivers/block.c new file mode 100644 index 0000000..6cf9a00 --- /dev/null +++ b/drivers/block.c @@ -0,0 +1,26 @@ +/* + * ------------------------------------------------------------------------ + * File Name: block.c + * Author: Zhao Yanbai + * 2023-06-20 19:30:47 Tuesday CST + * Description: none + * ------------------------------------------------------------------------ + */ + +#include +#include +#include + +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; +} diff --git a/drivers/ide.c b/drivers/ide.c index 32c8fb2..aa0f61e 100644 --- a/drivers/ide.c +++ b/drivers/ide.c @@ -158,10 +158,26 @@ void ide_init() { 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; } diff --git a/drivers/ide.h b/drivers/ide.h index 4043c31..bab04db 100644 --- a/drivers/ide.h +++ b/drivers/ide.h @@ -150,16 +150,15 @@ #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 { @@ -198,15 +197,20 @@ extern ide_pci_controller_t ide_pci_controller[NR_IDE_CONTROLLER]; 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(); diff --git a/fs/buffer.c b/fs/buffer.c new file mode 100644 index 0000000..c6d01af --- /dev/null +++ b/fs/buffer.c @@ -0,0 +1,8 @@ +/* + * ------------------------------------------------------------------------ + * File Name: buffer.c + * Author: Zhao Yanbai + * 2023-06-20 19:30:33 Tuesday CST + * Description: none + * ------------------------------------------------------------------------ + */ diff --git a/fs/ext2.c b/fs/ext2.c index ed56e5b..36345ce 100644 --- a/fs/ext2.c +++ b/fs/ext2.c @@ -12,6 +12,15 @@ #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; diff --git a/fs/ext2.h b/fs/ext2.h index ef26ee0..b5e88a6 100644 --- a/fs/ext2.h +++ b/fs/ext2.h @@ -37,7 +37,7 @@ 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) @@ -62,6 +62,12 @@ unsigned long ext2_block_size(); * 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 */ diff --git a/fs/vfs.c b/fs/vfs.c index 54eaf8a..c7b7578 100644 --- a/fs/vfs.c +++ b/fs/vfs.c @@ -7,6 +7,38 @@ * ------------------------------------------------------------------------ */ +#include #include -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; +} diff --git a/fs/vfs.h b/fs/vfs.h index 9242a33..1684dac 100644 --- a/fs/vfs.h +++ b/fs/vfs.h @@ -9,42 +9,88 @@ #pragma once -typedef struct vfs_dentry vfs_dentry_t; +#include -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); diff --git a/include/disk.h b/include/disk.h index 920fb48..76d382c 100644 --- a/include/disk.h +++ b/include/disk.h @@ -46,3 +46,5 @@ typedef struct { } 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); diff --git a/include/fs.h b/include/fs.h index 5e2ca12..b9057b5 100644 --- a/include/fs.h +++ b/include/fs.h @@ -37,7 +37,7 @@ #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) @@ -87,7 +87,7 @@ static inline int read_file(const pInode inode, void *buf, size_t count) return ext2_read_file(inode, buf, count); } -/* 在多进程下这样肯定不行 +/* 在多进程下这样肯定不行 * 管不了这么多了,先这样写吧 */ static inline pInode find_empty_inode() @@ -107,4 +107,14 @@ 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 diff --git a/include/page.h b/include/page.h index e13173a..30e2238 100644 --- a/include/page.h +++ b/include/page.h @@ -133,6 +133,7 @@ enum page_flags { struct kmem_cache; typedef struct kmem_cache kmem_cache_t; +struct blk_buffer; typedef struct page { unsigned long count; unsigned long flags; @@ -140,13 +141,17 @@ typedef struct page { 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); diff --git a/kernel/task_disk.c b/kernel/task_disk.c index c02bc1a..b26ac64 100644 --- a/kernel/task_disk.c +++ b/kernel/task_disk.c @@ -21,14 +21,7 @@ void send_disk_request(disk_request_t *r) { 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); @@ -84,8 +77,8 @@ void disk_task_entry(void *arg) { 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"); } @@ -107,6 +100,7 @@ void disk_task_entry(void *arg) { } // 等待硬盘中断 + printk("down ide req\n"); down(&ide_ctrl->disk_intr_sem); // 读数据 diff --git a/kernel/task_init.c b/kernel/task_init.c index 2e541ad..30753e7 100644 --- a/kernel/task_init.c +++ b/kernel/task_init.c @@ -13,6 +13,12 @@ int sysc_wait(uint32_t ticks); 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); diff --git a/kernel/task_root.c b/kernel/task_root.c index 394332f..b959074 100644 --- a/kernel/task_root.c +++ b/kernel/task_root.c @@ -178,9 +178,9 @@ void root_task_entry() { // 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) { diff --git a/scripts/grub.cfg b/scripts/grub.cfg index 6febc86..6ec73aa 100644 --- a/scripts/grub.cfg +++ b/scripts/grub.cfg @@ -4,6 +4,6 @@ set timeout=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 }