新版文件系统重构完成 (#198)

1.重构:VFS
2. 重构:ProcFS
3. 重构:DevFS
4. 重构:FAT32
5. 重构:AHCI驱动
6. 新增:RamFS
7. 新增:MountFS
8. 新增:FAT12
9. 新增:FAT16
10. 重构:设备抽象

Co-authored-by: guanjinquan <1666320330@qq.com>
Co-authored-by: DaJiYuQia <88259094+DaJiYuQia@users.noreply.github.com>
This commit is contained in:
login
2023-03-12 22:36:11 +08:00
committed by GitHub
parent 17041e0e30
commit 004e86ff19
109 changed files with 11258 additions and 7486 deletions

View File

@ -170,6 +170,8 @@
"assert.h": "c",
"sys_version.h": "c",
"cmd.h": "c",
"user_namespace.h": "c",
"sleep.h": "c",
"net.h": "c"
},
"C_Cpp.errorSquiggles": "Enabled",

View File

@ -1,24 +0,0 @@
# devFS 设备文件系统
&emsp;&emsp;devfs是一种基于内存的伪文件系统设备可注册到devfs中。对上层模块及应用程序而言每个设备都是可操作的文件。
## 原理
&emsp;&emsp;由于每个设备被抽象为文件,因此对于驱动程序而言,只需实现文件的操作接口,上层的应用程序以及其他系统组件即可操作文件操作接口来控制硬件设备。
## 目录结构
&emsp;&emsp;按照设备的主类型的不同将多种设备放置在devfs的不同文件夹下.请注意,同一设备可以出现在不同的文件夹下。
- `char` 字符设备
- `block` 块设备
- `usb` usb设备
- stdio等设备放置在devfs的根目录下
## 设备注册
&emsp;&emsp;驱动程序可使用`devfs_register_device()`函数将设备注册到devfs之中。
## 设备卸载
&emsp;&emsp;【尚未实现】

View File

@ -1,216 +0,0 @@
# FAT32文件系统
## 简介
&emsp;&emsp;FAT32文件系统是一种相对简单的文件系统。
&emsp;&emsp;FAT32文件系统实现在`kernel/filesystem/fat32/`中。
---
## 相关数据结构
### struct fat32_BootSector_t
&emsp;&emsp;fat32启动扇区结构体
```c
struct fat32_BootSector_t
{
uint8_t BS_jmpBoot[3]; // 跳转指令
uint8_t BS_OEMName[8]; // 生产厂商名
uint16_t BPB_BytesPerSec; // 每扇区字节数
uint8_t BPB_SecPerClus; // 每簇扇区数
uint16_t BPB_RsvdSecCnt; // 保留扇区数
uint8_t BPB_NumFATs; // FAT表数量
uint16_t BPB_RootEntCnt; // 根目录文件数最大值
uint16_t BPB_TotSec16; // 16位扇区总数
uint8_t BPB_Media; // 介质描述符
uint16_t BPB_FATSz16; // FAT12/16每FAT扇区数
uint16_t BPB_SecPerTrk; // 每磁道扇区数
uint16_t BPB_NumHeads; // 磁头数
uint32_t BPB_HiddSec; // 隐藏扇区数
uint32_t BPB_TotSec32; // 32位扇区总数
uint32_t BPB_FATSz32; // FAT32每FAT扇区数
uint16_t BPB_ExtFlags; // 扩展标志
uint16_t BPB_FSVer; // 文件系统版本号
uint32_t BPB_RootClus; // 根目录起始簇号
uint16_t BPB_FSInfo; // FS info结构体的扇区号
uint16_t BPB_BkBootSec; // 引导扇区的备份扇区号
uint8_t BPB_Reserved0[12];
uint8_t BS_DrvNum; // int0x13的驱动器号
uint8_t BS_Reserved1;
uint8_t BS_BootSig; // 扩展引导标记
uint32_t BS_VolID; // 卷序列号
uint8_t BS_VolLab[11]; // 卷标
uint8_t BS_FilSysType[8]; // 文件系统类型
uint8_t BootCode[420]; // 引导代码、数据
uint16_t BS_TrailSig; // 结束标志0xAA55
} __attribute__((packed));
```
### struct fat32_FSInfo_t
&emsp; &emsp;该扇区存储了FAT32文件系统的一些参考信息。
```c
struct fat32_FSInfo_t
{
uint32_t FSI_LeadSig;
uint8_t FSI_Reserved1[480];
uint32_t FSI_StrucSig;
uint32_t FSI_Free_Count;
uint32_t FSI_Nxt_Free;
uint8_t FSI_Reserved2[12];
uint32_t FSI_TrailSig;
} __attribute__((packed));
```
**FSI_LeadSig**
&emsp;&emsp;FS info扇区标志符 数值为0x41615252
**FSI_Reserved1**
&emsp;&emsp;保留使用全部置为0
**FSI_StrucSig**
&emsp;&emsp;FS_Info扇区的另一个标志符数值为0x61417272
**FSI_Free_Count**
&emsp;&emsp;上一次记录的空闲簇数量,这是一个参考值
**FSI_Nxt_Free**
&emsp;&emsp;空闲簇的起始搜索位置,这是为驱动程序提供的参考值.
**FSI_Reserved2**
&emsp;&emsp;保留使用全部置为0
**FSI_TrailSig**
&emsp;&emsp;FS_Info扇区结束标志数值为0xaa550000
### struct fat32_Directory_t
&emsp;&emsp;短目录项结构体。
```c
struct fat32_Directory_t
{
unsigned char DIR_Name[11];
unsigned char DIR_Attr;
unsigned char DIR_NTRes;
unsigned char DIR_CrtTimeTenth;
unsigned short DIR_CrtTime;
unsigned short DIR_CrtDate;
unsigned short DIR_LastAccDate;
unsigned short DIR_FstClusHI;
unsigned short DIR_WrtTime;
unsigned short DIR_WrtDate;
unsigned short DIR_FstClusLO;
unsigned int DIR_FileSize;
} __attribute__((packed));
```
**DIR_Name**
&emsp;&emsp;目录项名称。前8bytes为基础名后3bytes为扩展名
**DIRAttr**
&emsp;&emsp;目录项属性。可选值有如下:
> - ATTR_READ_ONLY
>
> - ATTR_HIDDEN
>
> - ATTR_SYSTEM
>
> - ATTR_VOLUME_ID
>
> - ATTR_DIRECTORY
>
> - ATTR_ARCHIVE
>
> - ATTR_LONG_NAME
**DIR_NTRes**
&emsp;&emsp;该项为Windows下特有的表示区域通过该项的值表示基础名和扩展名的大小写情况。该项的值为`EXT|BASE`组合而成,其中,具有以下定义:
> BASE:LowerCase(8),UpperCase(0)
> EXT:LowerCase(16),UpperCase(0)
**DIR_CrtTimeTenth**
&emsp;&emsp;文件创建的毫秒级时间戳
**DIR_CrtTime**
&emsp;&emsp;文件创建时间
**DIR_CrtDate**
  文件创建日期
**DIR_LastAccDate**
&emsp;&emsp;文件的最后访问日期
**DIR_FstClusHI**
&emsp;&emsp; 文件起始簇号高16bit
**DIR_WrtTime**
&emsp;&emsp;最后写入时间
**DIR_WrtDate**
&emsp;&emsp;最后写入日期
**DIR_FstClusLO**
&emsp;&emsp; 文件起始簇号低16bit
**DIR_FileSize**
&emsp;&emsp;文件大小
### struct fat32_partition_info_t
&emsp;&emsp;该数据结构为FAT32分区的信息结构体并不实际存在于物理磁盘上。这个结构体在挂载文件系统时被创建作为文件系统的超级块的私有信息的一部分。
### struct fat32_inode_info_t
&emsp;&emsp;该结构体是VFS的inode结构体的私有信息部分的具体实现。
---
## 已知问题
1. 对目录项名称的检查没有按照标准严格实现
2. 当磁盘可用簇数量发生改变时未更新FS_Info扇区
3. 未填写目录项的时间字段
---
## TODO
- 完全实现VFS定义的文件接口
- 性能优化
---
## 参考资料
[FAT32 File System Specification - from Microsoft](http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc)

View File

@ -3,11 +3,11 @@
DragonOS的文件系统模块由VFS虚拟文件系统及具体的文件系统组成。
todo: 由于文件系统模块重构文档暂时不可用预计在2023年4月10日前补齐。
.. toctree::
:maxdepth: 1
:caption: 目录
vfs/index
fat32/index
rootfs/index
devfs/index

View File

@ -1,7 +0,0 @@
# rootFS 根文件系统
&emsp;&emsp;rootFS是DragonOS开启后挂载的第一个文件系统,它是一个基于内存的伪文件系统。rootfs的功能主要是在具体的磁盘文件系统被挂载之前为其他的伪文件系统提供挂载点使得系统能被正确的初始化。
&emsp;&emsp;rootfs的初始化将与VFS一同初始化。rootfs将为系统的各项文件系统的挂载创建dentry使得其他的文件系统如`devfs`等,能在磁盘文件系统被挂载之前被正确的初始化。
&emsp;&emsp;当磁盘根文件系统被挂载后,将调用`rootfs_umount()`函数。该函数将会把原本挂载在rootfs上的各种伪文件系统迁移到磁盘根文件系统上。当迁移完成后将会释放rootfs所占用的资源。

View File

@ -6,242 +6,6 @@
&emsp;&emsp;与VFS相关的系统调用有open(), read(), write(), create()等。
### dentry对象
## **TODO**
&emsp;&emsp;dentry的全称为directory entry是VFS中对于目录项的一种抽象数据结构。当读取具体文件系统时将会由创建dentry对象。dentry对象中包含了指向inode的指针。
&emsp;&emsp;dentry对象为真实文件系统上的目录结构建立了缓存一旦内存中存在对应路径的dentry对象我们就能直接获取其中的信息而不需要进行费时的磁盘操作。请注意dentry只是为提高文件系统性能而创建的一个缓存它并不会被写入到磁盘之中。
### inode对象
&emsp;&emsp;inode的全称叫做index node即索引节点。一般来说每个dentry都应当包含指向其inode的指针。inode是VFS提供的对文件对象的抽象。inode中的信息是从具体文件系统中读取而来也可以被刷回具体的文件系统之中。并且一个inode也可以被多个dentry所引用。
&emsp;&emsp;要查找某个路径下的inode我们需要调用父目录的inode的lookup()方法。请注意,该方法与具体文件系统有关,需要在具体文件系统之中实现。
### 文件描述符对象
&emsp;&emsp;当一个进程试图通过VFS打开某个文件时我们需要为这个进程创建文件描述符对象。每个文件对象都会绑定文件的dentry和文件操作方法结构体还有文件对象的私有信息。
&emsp;&emsp;文件描述符对象中还包含了诸如权限控制、当前访问位置信息等内容以便VFS对文件进行操作。
&emsp;&emsp;我们对文件进行操作都会使用到文件描述符具体来说就是要调用文件描述符之中的file_ops所包含的各种方法。
---
## 注册文件系统到VFS
&emsp;&emsp;如果需要注册或取消注册某个具体文件系统到VFS之中则需要以下两个接口
```c
#include<filesystem/vfs/VFS.h>
uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs);
uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs);
```
&emsp;&emsp;这里需要通过`struct vfs_filesystem_type_t`来描述具体的文件系统。
### struct vfs_filesystem_type_t
&emsp;&emsp;这个数据结构描述了具体文件系统的一些信息。当我们挂载具体文件系统的时候将会调用它的read_superblock方法以确定要被挂载的文件系统的具体信息。
&emsp;&emsp;该数据结构的定义在`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_filesystem_type_t
{
char *name;
int fs_flags;
// 解析文件系统引导扇区的函数为文件系统创建超级块结构。其中DPTE为磁盘分区表entryMBR、GPT不同
struct vfs_superblock_t *(*read_superblock)(void *DPTE, uint8_t DPT_type, void *buf, int8_t ahci_ctrl_num, int8_t ahci_port_num, int8_t part_num);
struct vfs_filesystem_type_t *next;
};
```
**name**
&emsp;&emsp;文件系统名称字符串
**fs_flags**
&emsp;&emsp;文件系统的一些标志位。目前DragonOS尚未实现相关功能。
**read_superblock**
&emsp;&emsp;当新的文件系统实例将要被挂载时,将会调用此方法,以读取具体的实例的信息。
**next**
&emsp;&emsp;指向链表中下一个`struct vfs_filesystem_type_t`的指针。
---
## 超级块(superblock)对象
&emsp;&emsp;一个超级块对象代表了一个被挂载到VFS中的具体文件系统。
### struct vfs_superblock_t
&emsp;&emsp;该数据结构为超级块结构体。
&emsp;&emsp;该数据结构定义在`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_superblock_t
{
struct vfs_dir_entry_t *root;
struct vfs_super_block_operations_t *sb_ops;
void *private_sb_info;
};
```
**root**
&emsp;&emsp;该具体文件系统的根目录的dentry
**sb_ops**
&emsp;&emsp;该超级块对象的操作方法。
**private_sb_info**
&emsp;&emsp;超级块的私有信息。包含了具体文件系统的私有的、全局性的信息。
### struct vfs_super_block_operations_t
&emsp;&emsp;该数据结构为超级块的操作接口。VFS通过这些接口来操作具体的文件系统的超级块。
&emsp;&emsp;该数据结构定义在`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_super_block_operations_t
{
void (*write_superblock)(struct vfs_superblock_t *sb);
void (*put_superblock)(struct vfs_superblock_t *sb);
void (*write_inode)(struct vfs_index_node_t *inode); // 将inode信息写入磁盘
};
```
**write_superblock**
&emsp;&emsp;将superblock中的信息写入磁盘
**put_superblock**
&emsp;&emsp;释放超级块
**write_inode**
&emsp;&emsp;将inode的信息写入磁盘
---
## 索引结点(inode)对象
&emsp;&emsp;每个inode对象代表了具体的文件系统之中的一个对象目录项
### struct vfs_index_node_t
&emsp;&emsp;该数据结构为inode对象的数据结构与文件系统中的具体的文件结点对象具有一对一映射的关系。
&emsp;&emsp;该数据结构定义在`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_index_node_t
{
uint64_t file_size; // 文件大小
uint64_t blocks; // 占用的扇区数
uint64_t attribute;
struct vfs_superblock_t *sb;
struct vfs_file_operations_t *file_ops;
struct vfs_inode_operations_t *inode_ops;
void *private_inode_info;
};
```
**file_size**
&emsp;&emsp;文件的大小。若为文件夹,则该值为文件夹内所有文件的大小总和(估计值)。
**blocks**
&emsp;&emsp;文件占用的磁盘块数(扇区数)
**attribute**
&emsp;&emsp;inode的属性。可选值如下
> - VFS_IF_FILE
>
> - VFS_IF_DIR
>
> - VFS_IF_DEVICE
**sb**
&emsp;&emsp;指向文件系统超级块的指针
**file_ops**
&emsp;&emsp;当前文件的操作接口
**inode_ops**
&emsp;&emsp;当前inode的操作接口
**private_inode_info**
&emsp;&emsp;与具体文件系统相关的inode信息。该部分由具体文件系统实现包含该inode在具体文件系统之中的特定格式信息。
### struct vfs_inode_operations_t
&emsp;&emsp;该接口为inode的操作方法接口由具体文件系统实现。并与具体文件系统之中的inode相互绑定。
&emsp;&emsp;该接口定义于`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_inode_operations_t
{
long (*create)(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode);
struct vfs_dir_entry_t *(*lookup)(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry);
long (*mkdir)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry, int mode);
long (*rmdir)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry);
long (*rename)(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry);
long (*getAttr)(struct vfs_dir_entry_t *dEntry, uint64_t *attr);
long (*setAttr)(struct vfs_dir_entry_t *dEntry, uint64_t *attr);
};
```
**create**
&emsp;&emsp;在父节点下创建一个新的inode并绑定到dest_dEntry上。
&emsp;&emsp;该函数的应当被`sys_open()`系统调用在使用了`O_CREAT`选项打开文件时调用从而创建一个新的文件。请注意传递给create()函数的`dest_dEntry`参数不应包含一个inode也就是说inode对象应当被具体文件系统所创建。
**lookup**
&emsp;&emsp;当VFS需要在父目录中查找一个inode的时候将会调用lookup方法。被查找的目录项的名称将会通过dest_dEntry传给lookup方法。
&emsp;&emsp;若lookup方法找到对应的目录项将填充完善dest_dEntry对象。否则返回NULL。
**mkdir**
&emsp;&emsp;该函数被mkdir()系统调用所调用用于在inode下创建子目录并将子目录的inode绑定到dEntry对象之中。
**rmdir**
&emsp;&emsp;该函数被rmdir()系统调用所调用用于删除给定inode下的子目录项。
**rename**
&emsp;&emsp;该函数被rename系统调用尚未实现所调用用于将给定的目录项重命名。
**getAttr**
&emsp;&emsp;用来获取目录项的属性。
**setAttr**
&emsp;&emsp;用来设置目录项的属性
&emsp;&emsp;VFS的设计与实现讲解

View File

@ -11,8 +11,9 @@ crate-type = ["staticlib"]
# 运行时依赖项
[dependencies]
x86_64 = "0.14.10"
bitflags = "1.3.2"
virtio-drivers = "0.2.0"
bitflags = "1.3"
# 构建时依赖项
[build-dependencies]

View File

@ -17,7 +17,7 @@ export ASFLAGS := --64
LD_LIST := head.o
kernel_subdirs := common driver process debug filesystem time arch exception mm smp sched syscall ktest libs ipc io
kernel_subdirs := common driver process debug time arch exception mm smp sched syscall ktest libs ipc io

View File

@ -10,59 +10,59 @@
*/
#pragma once
#define E2BIG 1 /* 参数列表过长或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */
#define EACCES 2 /* 访问被拒绝 Permission denied */
#define EADDRINUSE 3 /* 地址正在被使用 Address in use.*/
#define EADDRNOTAVAIL 4 /* 地址不可用 Address not available.*/
#define EAFNOSUPPORT 5 /* 地址family不支持 Address family not supported. */
#define EAGAIN 6 /* 资源不可用,请重试。 Resource unavailable, try again (may be the same value as [EWOULDBLOCK]).*/
#define EALREADY 7 /* 连接已经在处理 Connection already in progress. */
#define EBADF 8 /* 错误的文件描述符 Bad file descriptor. */
#define EBADMSG 9 /* 错误的消息 Bad message. */
#define E2BIG 1 /* 参数列表过长或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */
#define EACCES 2 /* 访问被拒绝 Permission denied */
#define EADDRINUSE 3 /* 地址正在被使用 Address in use.*/
#define EADDRNOTAVAIL 4 /* 地址不可用 Address not available.*/
#define EAFNOSUPPORT 5 /* 地址family不支持 Address family not supported. */
#define EAGAIN 6 /* 资源不可用,请重试。 Resource unavailable, try again (may be the same value as [EWOULDBLOCK]).*/
#define EALREADY 7 /* 连接已经在处理 Connection already in progress. */
#define EBADF 8 /* 错误的文件描述符 Bad file descriptor. */
#define EBADMSG 9 /* 错误的消息 Bad message. */
#define EBUSY 10 /* 设备或资源忙 Device or resource busy. */
#define ECANCELED 11 /* 操作被取消 Operation canceled. */
#define ECHILD 12 /* 没有子进程 No child processes. */
#define ECONNABORTED 13 /* 连接已断开 Connection aborted. */
#define ECONNREFUSED 14 /* 连接被拒绝 Connection refused. */
#define ECONNRESET 15 /* 连接被重置 Connection reset. */
#define EDEADLK 16 /* 资源死锁将要发生 Resource deadlock would occur. */
#define EDESTADDRREQ 17 /* 需要目标地址 Destination address required.*/
#define EDOM 18 /* 数学参数超出作用域 Mathematics argument out of domain of function. */
#define EDQUOT 19 /* 保留使用 Reserved */
#define EBUSY 10 /* 设备或资源忙 Device or resource busy. */
#define ECANCELED 11 /* 操作被取消 Operation canceled. */
#define ECHILD 12 /* 没有子进程 No child processes. */
#define ECONNABORTED 13 /* 连接已断开 Connection aborted. */
#define ECONNREFUSED 14 /* 连接被拒绝 Connection refused. */
#define ECONNRESET 15 /* 连接被重置 Connection reset. */
#define EDEADLK 16 /* 资源死锁将要发生 Resource deadlock would occur. */
#define EDESTADDRREQ 17 /* 需要目标地址 Destination address required.*/
#define EDOM 18 /* 数学参数超出作用域 Mathematics argument out of domain of function. */
#define EDQUOT 19 /* 保留使用 Reserved */
#define EEXIST 20 /* 文件已存在 File exists. */
#define EFAULT 21 /* 错误的地址 Bad address */
#define EFBIG 22 /* 文件太大 File too large. */
#define EHOSTUNREACH 23 /* 主机不可达 Host is unreachable.*/
#define EIDRM 24 /* 标志符被移除 Identifier removed. */
#define EILSEQ 25 /* 不合法的字符序列 Illegal byte sequence. */
#define EINPROGRESS 26 /* 操作正在处理 Operation in progress. */
#define EINTR 27 /* 被中断的函数 Interrupted function. */
#define EINVAL 28 /* 不可用的参数 Invalid argument. */
#define EIO 29 /* I/O错误 I/O error. */
#define EEXIST 20 /* 文件已存在 File exists. */
#define EFAULT 21 /* 错误的地址 Bad address */
#define EFBIG 22 /* 文件太大 File too large. */
#define EHOSTUNREACH 23 /* 主机不可达 Host is unreachable.*/
#define EIDRM 24 /* 标志符被移除 Identifier removed. */
#define EILSEQ 25 /* 不合法的字符序列 Illegal byte sequence. */
#define EINPROGRESS 26 /* 操作正在处理 Operation in progress. */
#define EINTR 27 /* 被中断的函数 Interrupted function. */
#define EINVAL 28 /* 不可用的参数 Invalid argument. */
#define EIO 29 /* I/O错误 I/O error. */
#define EISCONN 30 /* 套接字已连接 Socket is connected. */
#define EISDIR 31 /* 是一个目录 Is a directory */
#define ELOOP 32 /* 符号链接级别过多 Too many levels of symbolic links. */
#define EMFILE 33 /* 文件描述符的值过大 File descriptor value too large. */
#define EMLINK 34 /* 链接数过多 Too many links. */
#define EMSGSIZE 35 /* 消息过大 Message too large. */
#define EMULTIHOP 36 /* 保留使用 Reserved. */
#define ENAMETOOLONG 37 /* 文件名过长 Filename too long. */
#define ENETDOWN 38 /* 网络已关闭 Network is down. */
#define ENETRESET 39 /* 网络连接已断开 Connection aborted by network. */
#define EISCONN 30 /* 套接字已连接 Socket is connected. */
#define EISDIR 31 /* 是一个目录 Is a directory */
#define ELOOP 32 /* 符号链接级别过多 Too many levels of symbolic links. */
#define EMFILE 33 /* 文件描述符的值过大 File descriptor value too large. */
#define EMLINK 34 /* 链接数过多 Too many links. */
#define EMSGSIZE 35 /* 消息过大 Message too large. */
#define EMULTIHOP 36 /* 保留使用 Reserved. */
#define ENAMETOOLONG 37 /* 文件名过长 Filename too long. */
#define ENETDOWN 38 /* 网络已关闭 Network is down. */
#define ENETRESET 39 /* 网络连接已断开 Connection aborted by network. */
#define ENETUNREACH 40 /* 网络不可达 Network unreachable. */
#define ENFILE 41 /* 系统中打开的文件过多 Too many files open in system.*/
#define ENOBUFS 42 /* 缓冲区空间不足 No buffer space available. */
#define ENODATA 43 /* 队列头没有可读取的消息 No message is available on the STREAM head read queue. */
#define ENODEV 44 /* 没有指定的设备 No such device. */
#define ENOENT 45 /* 没有指定的文件或目录 No such file or directory. */
#define ENOEXEC 46 /* 可执行文件格式错误 Executable file format error. */
#define ENOLCK 47 /* 没有可用的锁 No locks available. */
#define ENOLINK 48 /* 保留 Reserved. */
#define ENOMEM 49 /* 没有足够的空间 Not enough space. */
#define ENETUNREACH 40 /* 网络不可达 Network unreachable. */
#define ENFILE 41 /* 系统中打开的文件过多 Too many files open in system.*/
#define ENOBUFS 42 /* 缓冲区空间不足 No buffer space available. */
#define ENODATA 43 /* 队列头没有可读取的消息 No message is available on the STREAM head read queue. */
#define ENODEV 44 /* 没有指定的设备 No such device. */
#define ENOENT 45 /* 没有指定的文件或目录 No such file or directory. */
#define ENOEXEC 46 /* 可执行文件格式错误 Executable file format error. */
#define ENOLCK 47 /* 没有可用的锁 No locks available. */
#define ENOLINK 48 /* 保留 Reserved. */
#define ENOMEM 49 /* 没有足够的空间 Not enough space. */
#define ENOMSG 50 /* 没有期待类型的消息 No message of the desired type. */
#define ENOPROTOOPT 51 /* 协议不可用 Protocol not available. */
@ -73,29 +73,29 @@
#define ENOTCONN 56 /* 套接字未连接 The socket is not connected. */
#define ENOTDIR 57 /* 不是目录 Not a directory. */
#define ENOTEMPTY 58 /* 目录非空 Directory not empty. */
#define ENOTRECOVERABLE 59 /* 状态不可覆盖 State not recoverable. */
#define ENOTRECOVERABLE 59 /* 状态不可恢复 State not recoverable. */
#define ENOTSOCK 60 /* 不是一个套接字 Not a socket.*/
#define ENOTSUP 61 /* 不被支持 Not supported (may be the same value as [EOPNOTSUPP]). */
#define ENOTTY 62 /* 不正确的I/O控制操作 Inappropriate I/O control operation. */
#define ENXIO 63 /* 没有这样的设备或地址 No such device or address. */
#define EOPNOTSUPP 64 /* 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]). */
#define EOVERFLOW 65 /* 数值过大,产生溢出 Value too large to be stored in data type. */
#define EOWNERDEAD 66 /* 之前的拥有者挂了 Previous owner died. */
#define EPERM 67 /* 操作不被允许 Operation not permitted. */
#define EPIPE 68 /* 断开的管道 Broken pipe. */
#define EPROTO 69 /* 协议错误 Protocol error. */
#define ENOTSOCK 60 /* 不是一个套接字 Not a socket.*/
#define ENOTSUP 61 /* 不被支持 Not supported (may be the same value as [EOPNOTSUPP]). */
#define ENOTTY 62 /* 不正确的I/O控制操作 Inappropriate I/O control operation. */
#define ENXIO 63 /* 没有这样的设备或地址 No such device or address. */
#define EOPNOTSUPP 64 /* 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]). */
#define EOVERFLOW 65 /* 数值过大,产生溢出 Value too large to be stored in data type. */
#define EOWNERDEAD 66 /* 之前的拥有者挂了 Previous owner died. */
#define EPERM 67 /* 操作不被允许 Operation not permitted. */
#define EPIPE 68 /* 断开的管道 Broken pipe. */
#define EPROTO 69 /* 协议错误 Protocol error. */
#define EPROTONOSUPPORT 70 /* 协议不被支持 Protocol not supported. */
#define EPROTOTYPE 71 /* 对于套接字而言,错误的协议 Protocol wrong type for socket. */
#define ERANGE 72 /* 结果过大 Result too large. */
#define EROFS 73 /* 只读的文件系统 Read-only file system. */
#define ESPIPE 74 /* 错误的寻道 Invalid seek. */
#define ESPIPE 74 /* 错误的寻道.当前文件是pipe不允许seek请求 Invalid seek. */
#define ESRCH 75 /* 没有这样的进程 No such process. */
#define ESTALE 76 /* 保留 Reserved. */
#define ETIME 77 /* 流式ioctl()超时 Stream ioctl() timeout */
#define ETIMEDOUT 78 /* 连接超时 Connection timed out.*/
#define ETXTBSY 79 /* 文本文件忙 Text file busy. */
#define EWOULDBLOCK 80 /* 操作将被禁止 Operation would block (may be the same value as [EAGAIN]). */
#define EXDEV 81 /* 跨设备连接 Cross-device link. */
#define EWOULDBLOCK 80 /* 操作将被禁止 Operation would block (may be the same value as [EAGAIN]). */
#define EXDEV 81 /* 跨设备连接 Cross-device link. */

View File

@ -25,10 +25,14 @@
#define O_NONBLOCK 00004000 // 非阻塞式IO模式
#define O_EXEC 00010000 // 以仅执行的方式打开(非目录文件)
#define O_SEARCH 00020000 // Open the directory for search only
#define O_DIRECTORY 00040000 // 打开的必须是一个目录
#define O_NOFOLLOW 00100000 // Do not follow symbolic links
#define O_DSYNC 00010000 // used to be O_SYNC, see below
#define FASYNC 00020000 // fcntl, for BSD compatibility
#define O_DIRECT 00040000 // direct disk access hint
#define O_LARGEFILE 00100000
#define O_DIRECTORY 00200000 // 打开的必须是一个目录
#define O_NOFOLLOW 00400000 // Do not follow symbolic links
#define O_NOATIME 01000000
#define O_CLOEXEC 02000000 // set close_on_exec
/*
* The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is

View File

@ -33,8 +33,8 @@ void lockref_inc(struct lockref *lock_ref);
* @brief 原子地将引用计数加1.如果原来的count≤0则操作失败。
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return int 操作成功=>true
* 操作失败=>false
* @return bool 操作成功=>true
* 操作失败=>false
*/
bool lockref_inc_not_zero(struct lockref *lock_ref);

View File

@ -24,8 +24,8 @@ struct tm
struct timespec
{
long int tv_sec; // 秒
long long tv_nsec; // 纳秒
int64_t tv_sec; // 秒
int64_t tv_nsec; // 纳秒
};
/**

View File

@ -1,636 +1,32 @@
#include "ahci.h"
#include <common/kprint.h>
#include <mm/slab.h>
#include <syscall/syscall.h>
#include <syscall/syscall_num.h>
#include <sched/sched.h>
#include <common/string.h>
#include <common/block.h>
#include <filesystem/MBR.h>
#include <debug/bug.h>
#include <common/kthread.h>
struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES];
struct blk_gendisk ahci_gendisk0 = {0}; // 暂时硬性指定一个ahci_device
static int __first_port = -1; // 临时用于存储 ahci控制器的第一个可用端口 的变量
static uint32_t count_ahci_devices = 0;
static uint64_t ahci_port_base_vaddr; // 端口映射base addr
static uint64_t ahci_port_base_phys_addr; // 端口映射的物理基地址ahci控制器的参数的地址都是物理地址
static void start_cmd(HBA_PORT *port);
static void stop_cmd(HBA_PORT *port);
static void port_rebase(HBA_PORT *port, int portno);
// 计算HBA_MEM的虚拟内存地址
#define cal_HBA_MEM_VIRT_ADDR(device_num) (AHCI_MAPPING_BASE + (ul)(((struct pci_device_structure_general_device_t *)(ahci_devs[device_num]))->BAR5 - ((((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5) & PAGE_2M_MASK)))
long ahci_open();
long ahci_close();
static long ahci_ioctl(long cmd, long arg);
static long ahci_transfer(struct blk_gendisk *gd, long cmd, uint64_t base_addr, uint64_t count, uint64_t buf);
struct block_device_operation ahci_operation =
{
.open = ahci_open,
.close = ahci_close,
.ioctl = ahci_ioctl,
.transfer = ahci_transfer,
};
/**
* @brief ahci驱动器在block_device中的私有数据结构体
*
*/
struct ahci_blk_private_data
{
uint16_t ahci_ctrl_num; // ahci控制器号
uint16_t ahci_port_num; // ahci端口号
struct MBR_disk_partition_table_t *part_table; // 分区表
};
/**
* @brief 申请ahci设备的私有信息结构体
*
* @return struct ahci_blk_private_data* 申请到的私有信息结构体
*/
static struct ahci_blk_private_data *__alloc_private_data()
{
struct ahci_blk_private_data *data = (struct ahci_blk_private_data *)kzalloc(sizeof(struct ahci_blk_private_data), 0);
data->part_table = (struct MBR_disk_partition_table_t *)kzalloc(512, 0);
return data;
}
/**
* @brief 释放ahci设备的分区的私有信息结构体
*
* @param pdata 待释放的结构体
* @return int 错误码
*/
static int __release_private_data(struct ahci_blk_private_data *pdata)
{
kfree(pdata->part_table);
kfree(pdata);
return 0;
}
/**
* @brief 初始化gendisk结构体(暂时只支持1个gendisk)
*
*/
static int ahci_init_gendisk()
{
memset(&ahci_gendisk0, 0, sizeof(ahci_gendisk0));
strcpy(ahci_gendisk0.disk_name, "ahci0");
ahci_gendisk0.flags = BLK_GF_AHCI;
ahci_gendisk0.fops = &ahci_operation;
mutex_init(&ahci_gendisk0.open_mutex);
// 为存储分区结构,分配内存空间
ahci_gendisk0.private_data = __alloc_private_data();
// 读取分区表
// 暂时假设全都是MBR分区表的
// todo: 支持GPT
((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->ahci_ctrl_num = 0;
((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->ahci_port_num = __first_port;
MBR_read_partition_table(&ahci_gendisk0, ((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->part_table);
struct MBR_disk_partition_table_t *ptable = ((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->part_table;
// 求出可用分区数量
for (int i = 0; i < 4; ++i)
{
// 分区可用
if (ptable->DPTE[i].type != 0)
++ahci_gendisk0.part_cnt;
}
if (ahci_gendisk0.part_cnt)
{
// 分配分区结构体数组的空间
ahci_gendisk0.partition = (struct block_device *)kzalloc(ahci_gendisk0.part_cnt * sizeof(struct block_device), 0);
int cnt = 0;
// 循环遍历每个分区
for (int i = 0; i < 4; ++i)
{
// 分区可用
if (ptable->DPTE[i].type != 0)
{
// 初始化分区结构体
ahci_gendisk0.partition[cnt].bd_disk = &ahci_gendisk0;
ahci_gendisk0.partition[cnt].bd_partno = cnt;
// FIXME 需要注释
ahci_gendisk0.partition[cnt].bd_sectors_num = ptable->DPTE[i].total_sectors;
ahci_gendisk0.partition[cnt].bd_start_sector = ptable->DPTE[i].starting_sector;
ahci_gendisk0.partition[cnt].bd_superblock = NULL; // 挂载文件系统时才会初始化superblock
ahci_gendisk0.partition[cnt].bd_start_LBA = ptable->DPTE[i].starting_LBA;
++cnt;
}
}
}
return 0;
};
/**
* @brief 初始化ahci模块
*
*/
void ahci_init()
/// @brief 保留了对 pci设备获取 和 mm内存映射 的依赖
void ahci_cpp_init(uint32_t *count_ahci_devices, struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES], struct pci_device_structure_general_device_t *gen_devs[MAX_AHCI_DEVICES])
{
kinfo("Initializing AHCI...");
pci_get_device_structure(0x1, 0x6, ahci_devs, &count_ahci_devices);
if (count_ahci_devices == 0)
pci_get_device_structure(0x1, 0x6, ahci_devs, count_ahci_devices);
if (*count_ahci_devices == 0)
{
kwarn("There is no AHCI device found on this computer!");
return;
}
for (int i = 0; i < *count_ahci_devices; i++)
{
gen_devs[i] = ((struct pci_device_structure_general_device_t *)(ahci_devs[i]));
}
// 映射ABAR
kdebug("phys_2_virt(ahci_devs[0])= %#018lx", (ahci_devs[0]));
kdebug("((struct pci_device_structure_general_device_t *)phys_2_virt(ahci_devs[0])))->BAR5= %#018lx", ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5);
uint32_t bar5 = ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5;
uint32_t bar5 = gen_devs[0]->BAR5;
mm_map_phys_addr(AHCI_MAPPING_BASE, (ul)(bar5)&PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
kdebug("ABAR mapped!");
for (int i = 0; i < count_ahci_devices; ++i)
{
// kdebug("[%d] class_code=%d, sub_class=%d, progIF=%d, ABAR=%#010lx", i, ahci_devs[i]->Class_code, ahci_devs[i]->SubClass, ahci_devs[i]->ProgIF, ((struct pci_device_structure_general_device_t *)(ahci_devs[i]))->BAR5);
// 赋值HBA_MEM结构体
ahci_devices[i].dev_struct = ahci_devs[i];
ahci_devices[i].hba_mem = (HBA_MEM *)(cal_HBA_MEM_VIRT_ADDR(i));
kdebug("ahci_devices[i].hba_mem = %#018lx", (ul)ahci_devices[i].hba_mem);
}
// todo: 支持多个ahci控制器。
ahci_port_base_vaddr = (uint64_t)kmalloc(1048576, 0);
kdebug("ahci_port_base_vaddr=%#018lx", ahci_port_base_vaddr);
ahci_probe_port(0);
BUG_ON(ahci_init_gendisk() != 0);
kinfo("AHCI initialized.");
}
// Check device type
static int check_type(HBA_PORT *port)
{
uint32_t ssts = port->ssts;
uint8_t ipm = (ssts >> 8) & 0x0F;
uint8_t det = ssts & 0x0F;
if (det != HBA_PORT_DET_PRESENT) // Check drive status
return AHCI_DEV_NULL;
if (ipm != HBA_PORT_IPM_ACTIVE)
return AHCI_DEV_NULL;
switch (port->sig)
{
case SATA_SIG_ATAPI:
return AHCI_DEV_SATAPI;
case SATA_SIG_SEMB:
return AHCI_DEV_SEMB;
case SATA_SIG_PM:
return AHCI_DEV_PM;
default:
return AHCI_DEV_SATA;
}
}
/**
* @brief 检测端口连接的设备的类型
*
* @param device_num ahci控制器号
*/
static void ahci_probe_port(const uint32_t device_num)
{
HBA_MEM *abar = ahci_devices[device_num].hba_mem;
uint32_t pi = abar->pi;
for (int i = 0; i < 32; ++i, (pi >>= 1))
{
if (pi & 1)
{
uint dt = check_type(&abar->ports[i]);
ahci_devices[i].type = dt;
switch (dt)
{
case AHCI_DEV_SATA:
kdebug("SATA drive found at port %d", i);
goto found;
case AHCI_DEV_SATAPI:
kdebug("SATAPI drive found at port %d", i);
goto found;
case AHCI_DEV_SEMB:
kdebug("SEMB drive found at port %d", i);
goto found;
case AHCI_DEV_PM:
kdebug("PM drive found at port %d", i);
goto found;
found:;
port_rebase(&ahci_devices[0].hba_mem->ports[i], i);
if (__first_port == -1)
__first_port = i;
break;
default:
kdebug("No drive found at port %d", i);
break;
}
}
}
}
// Start command engine
static void start_cmd(HBA_PORT *port)
{
// Wait until CR (bit15) is cleared
while ((port->cmd) & HBA_PxCMD_CR)
;
// Set FRE (bit4) and ST (bit0)
port->cmd |= HBA_PxCMD_FRE;
port->cmd |= HBA_PxCMD_ST;
}
// Stop command engine
static void stop_cmd(HBA_PORT *port)
{
// Clear ST (bit0)
port->cmd &= ~HBA_PxCMD_ST;
// Clear FRE (bit4)
port->cmd &= ~HBA_PxCMD_FRE;
// Wait until FR (bit14), CR (bit15) are cleared
while (1)
{
if (port->cmd & HBA_PxCMD_FR)
continue;
if (port->cmd & HBA_PxCMD_CR)
continue;
break;
}
}
static void port_rebase(HBA_PORT *port, int portno)
{
// Before rebasing Port memory space, OS must wait for current pending commands to finish
// and tell HBA to stop receiving FIS from the port. Otherwise an accidently incoming FIS may be
// written into a partially configured memory area.
stop_cmd(port); // Stop command engine
// Command list offset: 1K*portno
// Command list entry size = 32
// Command list entry maxim count = 32
// Command list maxim size = 32*32 = 1K per port
port->clb = virt_2_phys(ahci_port_base_vaddr + (portno << 10));
memset((void *)(phys_2_virt(port->clb)), 0, 1024);
// FIS offset: 32K+256*portno
// FIS entry size = 256 bytes per port
port->fb = virt_2_phys(ahci_port_base_vaddr + (32 << 10) + (portno << 8));
memset((void *)(phys_2_virt(port->fb)), 0, 256);
// Command table offset: 40K + 8K*portno
// Command table size = 256*32 = 8K per port
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)(phys_2_virt(port->clb));
for (int i = 0; i < 32; ++i)
{
cmdheader[i].prdtl = 8; // 8 prdt entries per command table
// 256 bytes per command table, 64+16+48+16*8
// Command table offset: 40K + 8K*portno + cmdheader_index*256
cmdheader[i].ctba = virt_2_phys((ahci_port_base_vaddr + (40 << 10) + (portno << 13) + (i << 8)));
memset((void *)phys_2_virt(cmdheader[i].ctba), 0, 256);
}
start_cmd(port); // Start command engine
}
/**
* @brief read data from SATA device using 48bit LBA address
*
* @param port HBA PORT
* @param startl low 32bits of start addr
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @param ret_slot 执行命令的插槽号(传出参数)
* @return true done
* @return false failed
*/
static int ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf, int8_t *ret_slot)
{
port->is = (uint32_t)-1; // Clear pending interrupt bits
int spin = 0; // Spin lock timeout counter
int slot = ahci_find_cmdslot(port);
if (slot == -1)
return E_NOEMPTYSLOT;
if (ret_slot)
{
*ret_slot = slot;
}
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb);
cmdheader += slot;
cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t); // Command FIS size
cmdheader->w = 0; // Read from device
cmdheader->prdtl = (uint16_t)((count - 1) >> 4) + 1; // PRDT entries count
HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL *)phys_2_virt(cmdheader->ctba);
memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) + (cmdheader->prdtl - 1) * sizeof(HBA_PRDT_ENTRY));
// 8K bytes (16 sectors) per PRDT
int i;
for (i = 0; i < cmdheader->prdtl - 1; ++i)
{
cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K bytes (this value should always be set to 1 less than the actual value)
cmdtbl->prdt_entry[i].i = 1;
buf += 4 * 1024; // 4K uint16_ts
count -= 16; // 16 sectors
}
// Last entry
cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
cmdtbl->prdt_entry[i].dbc = (count << 9) - 1; // 512 bytes per sector
cmdtbl->prdt_entry[i].i = 1;
// Setup command
FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&cmdtbl->cfis);
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1; // Command
cmdfis->command = AHCI_CMD_READ_DMA_EXT;
cmdfis->lba0 = (uint8_t)startl;
cmdfis->lba1 = (uint8_t)(startl >> 8);
cmdfis->lba2 = (uint8_t)(startl >> 16);
cmdfis->device = 1 << 6; // LBA mode
cmdfis->lba3 = (uint8_t)(startl >> 24);
cmdfis->lba4 = (uint8_t)starth;
cmdfis->lba5 = (uint8_t)(starth >> 8);
cmdfis->countl = count & 0xFF;
cmdfis->counth = (count >> 8) & 0xFF;
// The below loop waits until the port is no longer busy before issuing a new command
while ((port->tfd & (AHCI_DEV_BUSY | AHCI_DEV_DRQ)) && spin < 1000000)
{
spin++;
}
if (spin == 1000000)
{
kerror("Port is hung");
return E_PORT_HUNG;
}
port->ci = 1 << slot; // Issue command
return 0;
}
/**
* @brief 检查请求包是否已完成
*
* @param port_num HBA PORT 编号
* @param ahci_ctrl_num ahci控制号
* @param ret_slot 执行命令的插槽号
* @param err 错误信息
*/
int ahci_check_complete(uint8_t port_num, uint8_t ahci_ctrl_num, int8_t slot, char *err)
{
HBA_PORT *port = ahci_get_port(port_num, ahci_ctrl_num);
int retval = -EBUSY;
if (slot == -1)
retval = -EINVAL;
// In some longer duration reads, it may be helpful to spin on the DPS bit
// in the PxIS port field as well (1 << 5)
if ((port->ci & (1 << slot)) == 0)
retval = 0;
if (port->is & HBA_PxIS_TFES) // Task file error
{
if (err != NULL)
kerror(*err);
retval = E_TASK_FILE_ERROR;
}
return retval;
}
/**
* @brief write data to SATA device using 48bit LBA address
*
* @param port HBA PORT
* @param startl low 32bits of start addr
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @param ret_slot 执行命令的插槽号(传出参数)
* @return success 0
*/
static int ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
uint64_t buf, int8_t *ret_slot)
{
port->is = 0xffff; // Clear pending interrupt bits
int slot = ahci_find_cmdslot(port);
if (slot == -1)
return E_NOEMPTYSLOT;
if (ret_slot)
{
*ret_slot = slot;
}
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb);
cmdheader += slot;
cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t); // Command FIS size
cmdheader->w = 1;
cmdheader->c = 1;
cmdheader->p = 1;
cmdheader->prdtl = (uint16_t)((count - 1) >> 4) + 1; // PRDT entries count
HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL *)phys_2_virt(cmdheader->ctba);
memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) + (cmdheader->prdtl - 1) * sizeof(HBA_PRDT_ENTRY));
int i = 0;
for (i = 0; i < cmdheader->prdtl - 1; ++i)
{
cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K bytes
cmdtbl->prdt_entry[i].i = 0;
buf += 4 * 1024; // 4K words
count -= 16; // 16 sectors
}
cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
cmdtbl->prdt_entry[i].dbc = count << 9; // 512 bytes per sector
cmdtbl->prdt_entry[i].i = 0;
FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&cmdtbl->cfis);
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1; // Command
cmdfis->command = AHCI_CMD_WRITE_DMA_EXT;
cmdfis->lba0 = (uint8_t)startl;
cmdfis->lba1 = (uint8_t)(startl >> 8);
cmdfis->lba2 = (uint8_t)(startl >> 16);
cmdfis->lba3 = (uint8_t)(startl >> 24);
cmdfis->lba4 = (uint8_t)starth;
cmdfis->lba5 = (uint8_t)(starth >> 8);
cmdfis->device = 1 << 6; // LBA mode
cmdfis->countl = count & 0xff;
cmdfis->counth = count >> 8;
port->ci = 1; // Issue command
return 0;
}
// Find a free command list slot
int ahci_find_cmdslot(HBA_PORT *port)
{
// If not set in SACT and CI, the slot is free
uint32_t slots = (port->sact | port->ci);
int num_of_cmd_clots = (ahci_devices[0].hba_mem->cap & 0x0f00) >> 8; // bit 12-8
for (int i = 0; i < num_of_cmd_clots; i++)
{
if ((slots & 1) == 0)
return i;
slots >>= 1;
}
kerror("Cannot find free command list entry");
return -1;
}
long ahci_open()
{
return 0;
}
long ahci_close()
{
return 0;
}
/**
* @brief 创建ahci磁盘请求包
*
* @param cmd 控制命令
* @param base_addr 48位LBA地址
* @param count total sectors to read
* @param buf 缓冲区线性地址
* @param ahci_ctrl_num ahci控制器号
* @param port_num ahci控制器端口号
* @return struct block_device_request_packet*
*/
static struct ahci_request_packet_t *ahci_make_request(long cmd, uint64_t base_addr, uint64_t count, uint64_t buffer, uint8_t ahci_ctrl_num, uint8_t port_num)
{
struct ahci_request_packet_t *pack = (struct ahci_request_packet_t *)kzalloc(sizeof(struct ahci_request_packet_t), 0);
pack->blk_pak.device_type = BLK_TYPE_AHCI;
// 由于ahci不需要中断即可读取磁盘因此end handler为空
switch (cmd)
{
case AHCI_CMD_READ_DMA_EXT:
pack->blk_pak.end_handler = NULL;
pack->blk_pak.cmd = AHCI_CMD_READ_DMA_EXT;
break;
case AHCI_CMD_WRITE_DMA_EXT:
pack->blk_pak.end_handler = NULL;
pack->blk_pak.cmd = AHCI_CMD_WRITE_DMA_EXT;
break;
default:
pack->blk_pak.end_handler = NULL;
pack->blk_pak.cmd = cmd;
break;
}
pack->blk_pak.LBA_start = base_addr;
pack->blk_pak.count = count;
pack->blk_pak.buffer_vaddr = buffer;
pack->ahci_ctrl_num = ahci_ctrl_num;
pack->port_num = port_num;
return pack;
}
long ahci_query_disk(struct ahci_request_packet_t *pack, int8_t *ret_slot)
{
long ret_val = 0;
switch (pack->blk_pak.cmd)
{
case AHCI_CMD_READ_DMA_EXT:
ret_val = ahci_read(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr, ret_slot);
break;
case AHCI_CMD_WRITE_DMA_EXT:
ret_val = ahci_write(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr, ret_slot);
break;
default:
kerror("Unsupport ahci command: %#05lx", pack->blk_pak.cmd);
ret_val = E_UNSUPPORTED_CMD;
break;
}
return ret_val;
}
/**
* @brief ahci驱动程序的传输函数
*
* @param gd 磁盘设备结构体
* @param cmd 控制命令
* @param base_addr 48位LBA地址
* @param count total sectors to read
* @param buf 缓冲区线性地址
* @return long
*/
static long ahci_transfer(struct blk_gendisk *gd, long cmd, uint64_t base_addr, uint64_t count, uint64_t buf)
{
struct ahci_request_packet_t *pack = NULL;
struct ahci_blk_private_data *pdata = (struct ahci_blk_private_data *)gd->private_data;
if (cmd == AHCI_CMD_READ_DMA_EXT || cmd == AHCI_CMD_WRITE_DMA_EXT)
{
pack = ahci_make_request(cmd, base_addr, count, buf, pdata->ahci_ctrl_num, pdata->ahci_port_num);
ahci_push_request(pack);
}
else
{
kdebug("ahci_transfer: E_UNSUPPORTED_CMD");
return E_UNSUPPORTED_CMD;
}
return AHCI_SUCCESS;
}
/**
* @brief todo: io控制器函数
*
* @param cmd 命令
* @param arg 参数
* @return long
*/
static long ahci_ioctl(long cmd, long arg)
{
return 0;
}
/**
* @brief 根据端口号获取端口结构体
* @param port_num 端口号
* @param ahci_ctrl_num 控制号
*/
HBA_PORT *ahci_get_port(uint8_t port_num, uint8_t ahci_ctrl_num)
{
return &(ahci_devices[ahci_ctrl_num].hba_mem->ports[port_num]);
kinfo("ABAR mapped!");
}

View File

@ -363,70 +363,4 @@ struct ahci_request_packet_t
* @brief 初始化ahci模块
*
*/
void ahci_init();
/**
* @brief 检测端口连接的设备的类型
*
* @param device_num ahci设备号
*/
static void ahci_probe_port(const uint32_t device_num);
/**
* @brief read data from SATA device using 48bit LBA address
*
* @param port HBA PORT
* @param startl low 32bits of start addr
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @param ret_slot 执行命令的插槽号(传出参数)
* @return success 0
*/
static int ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf, int8_t *ret_slot);
/**
* @brief write data to SATA device using 48bit LBA address
*
* @param port HBA PORT
* @param startl low 32bits of start addr
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @param ret_slot 执行命令的插槽号(传出参数)
* @return success 0
*/
static int ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
uint64_t buf, int8_t *ret_slot);
void ahci_end_request();
/**
* @brief 检查请求包是否已完成
*
* @param port_num HBA PORT 编号
* @param ahci_ctrl_num ahci控制号
* @param ret_slot 执行命令的插槽号
* @param err 错误信息
*/
int ahci_check_complete(uint8_t port_num, uint8_t ahci_ctrl_num, int8_t slot, char *err);
/**
* @brief 根据端口号获取端口结构体
* @param port_num 端口号
* @param ahci_ctrl_num 控制号
*/
HBA_PORT *ahci_get_port(uint8_t port_num, uint8_t ahci_ctrl_num);
/**
* @brief Find a free command list slot
* @param port
*/
int ahci_find_cmdslot(HBA_PORT *port);
/**
* @brief 读取磁盘信息
* @param pack io请求包
* @param ret_slot 执行命令的插槽号(传出参数)
*/
long ahci_query_disk(struct ahci_request_packet_t *pack, int8_t *ret_slot);
extern void ahci_init();

View File

@ -0,0 +1,155 @@
use crate::filesystem::devfs::{DevFS, DeviceINode};
use crate::filesystem::vfs::{
core::generate_inode_id, make_rawdev, FilePrivateData, FileSystem, FileType, IndexNode,
Metadata, PollStatus,
};
use crate::io::device::BlockDevice;
use crate::{
include::bindings::bindings::{EINVAL, ENOTSUP},
libs::spinlock::SpinLock,
time::TimeSpec,
};
use alloc::{
string::String,
sync::{Arc, Weak},
vec::Vec,
};
use super::ahcidisk::LockedAhciDisk;
#[derive(Debug)]
pub struct AhciInode {
/// uuid 暂时不知道有什么用x
// uuid: Uuid,
/// 指向自身的弱引用
self_ref: Weak<LockedAhciInode>,
/// 指向inode所在的文件系统对象的指针
fs: Weak<DevFS>,
/// INode 元数据
metadata: Metadata,
/// INode 对应的磁盘
disk: Arc<LockedAhciDisk>,
}
#[derive(Debug)]
pub struct LockedAhciInode(pub SpinLock<AhciInode>);
impl LockedAhciInode {
pub fn new(disk: Arc<LockedAhciDisk>) -> Arc<Self> {
let inode = AhciInode {
// uuid: Uuid::new_v5(),
self_ref: Weak::default(),
fs: Weak::default(),
disk: disk,
metadata: Metadata {
dev_id: 1,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: FileType::BlockDevice, // 文件夹block设备char设备
mode: 0o666,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: make_rawdev(1, 3), // 这里用来作为device number
},
};
let result = Arc::new(LockedAhciInode(SpinLock::new(inode)));
result.0.lock().self_ref = Arc::downgrade(&result);
return result;
}
}
impl DeviceINode for LockedAhciInode {
fn set_fs(&self, fs: Weak<DevFS>) {
self.0.lock().fs = fs;
}
}
impl IndexNode for LockedAhciInode {
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> {
Err(-(ENOTSUP as i32))
}
fn close(&self, _data: &mut FilePrivateData) -> Result<(), i32> {
Err(-(ENOTSUP as i32))
}
fn metadata(&self) -> Result<Metadata, i32> {
return Ok(self.0.lock().metadata.clone());
}
fn fs(&self) -> Arc<dyn FileSystem> {
return self.0.lock().fs.upgrade().unwrap();
}
fn list(&self) -> Result<Vec<String>, i32> {
Err(-(ENOTSUP as i32))
}
fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> {
let mut inode = self.0.lock();
inode.metadata.atime = metadata.atime;
inode.metadata.mtime = metadata.mtime;
inode.metadata.ctime = metadata.ctime;
inode.metadata.mode = metadata.mode;
inode.metadata.uid = metadata.uid;
inode.metadata.gid = metadata.gid;
return Ok(());
}
fn poll(&self) -> Result<PollStatus, i32> {
return Ok(PollStatus {
flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK,
});
}
/// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写
fn read_at(
&self,
offset: usize, // lba地址
len: usize,
buf: &mut [u8],
data: &mut FilePrivateData,
) -> Result<usize, i32> {
if buf.len() < len {
return Err(-(EINVAL as i32));
}
if let FilePrivateData::Unused = data {
return self.0.lock().disk.read_at(offset, len, buf);
}
return Err(-(EINVAL as i32));
}
/// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写
fn write_at(
&self,
offset: usize, // lba地址
len: usize,
buf: &[u8],
data: &mut FilePrivateData,
) -> Result<usize, i32> {
if buf.len() < len {
return Err(-(EINVAL as i32));
}
if let FilePrivateData::Unused = data {
return self.0.lock().disk.write_at(offset, len, buf);
}
return Err(-(EINVAL as i32));
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <common/kprint.h>
#include <mm/slab.h>
#include <syscall/syscall.h>
#include <syscall/syscall_num.h>
#include <sched/sched.h>
#include <common/string.h>
#include <common/block.h>
#include <debug/bug.h>
#include <driver/pci/pci.h>
#include <mm/mm.h>
// 计算HBA_MEM的虚拟内存地址
#define MAX_AHCI_DEVICES 100
#define AHCI_MAPPING_BASE SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + AHCI_MAPPING_OFFSET
/// @brief 保留了对 pci设备获取 和 mm内存映射 的依赖
void ahci_cpp_init(uint32_t *count_ahci_devices, struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES], struct pci_device_structure_general_device_t *gen_devs[MAX_AHCI_DEVICES]);

View File

@ -0,0 +1,441 @@
use super::{_port, hba::HbaCmdTable, virt_2_phys};
use crate::driver::disk::ahci::HBA_PxIS_TFES;
use crate::filesystem::mbr::MbrDiskPartionTable;
use crate::include::bindings::bindings::{E2BIG, EIO};
use crate::io::{device::BlockDevice, disk_info::Partition, SeekFrom};
use crate::libs::{spinlock::SpinLock, vec_cursor::VecCursor};
use crate::mm::phys_2_virt;
use crate::{
driver::disk::ahci::hba::{
FisRegH2D, FisType, HbaCmdHeader, ATA_CMD_READ_DMA_EXT, ATA_CMD_WRITE_DMA_EXT,
ATA_DEV_BUSY, ATA_DEV_DRQ,
},
kerror,
};
use alloc::sync::Weak;
use alloc::{string::String, sync::Arc, vec::Vec};
use core::fmt::Debug;
use core::sync::atomic::compiler_fence;
use core::{mem::size_of, ptr::write_bytes};
/// @brief: 只支持MBR分区格式的磁盘结构体
pub struct AhciDisk {
pub name: String,
pub flags: u16, // 磁盘的状态flags
pub partitions: Vec<Arc<Partition>>, // 磁盘分区数组
// port: &'static mut HbaPort, // 控制硬盘的端口
pub ctrl_num: u8,
pub port_num: u8,
/// 指向LockAhciDisk的弱引用
self_ref: Weak<LockedAhciDisk>,
}
/// @brief: 带锁的AhciDisk
#[derive(Debug)]
pub struct LockedAhciDisk(pub SpinLock<AhciDisk>);
/// 函数实现
impl Debug for AhciDisk {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{{ name: {}, flags: {}, part_s: {:?} }}",
self.name, self.flags, self.partitions
)?;
return Ok(());
}
}
impl AhciDisk {
fn read_at(
&self,
lba_id_start: crate::io::device::BlockId, // 起始lba编号
count: usize, // 读取lba的数量
buf: &mut [u8],
) -> Result<usize, i32> {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let check_length = ((count - 1) >> 4) + 1; // prdt length
if count * 512 > buf.len() || check_length > u16::MAX as usize {
kerror!("ahci read: e2big");
// 不可能的操作
return Err(-(E2BIG as i32));
} else if count == 0 {
return Ok(0);
}
let port = _port(self.ctrl_num, self.port_num);
volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
let slot = port.find_cmdslot().unwrap_or(u32::MAX);
if slot == u32::MAX {
return Err(-(EIO as i32));
}
#[allow(unused_unsafe)]
let cmdheader: &mut HbaCmdHeader = unsafe {
(phys_2_virt(
volatile_read!(port.clb) as usize
+ slot as usize * size_of::<HbaCmdHeader>() as usize,
) as *mut HbaCmdHeader)
.as_mut()
.unwrap()
};
volatile_write_bit!(
cmdheader.cfl,
(1 << 5) - 1 as u8,
(size_of::<FisRegH2D>() / size_of::<u32>()) as u8
); // Command FIS size
volatile_set_bit!(cmdheader.cfl, 1 << 6, false); // Read/Write bit : Read from device
volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
// 设置数据存放地址
let mut buf_ptr = buf as *mut [u8] as *mut usize as usize;
#[allow(unused_unsafe)]
let cmdtbl = unsafe {
(phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
.as_mut()
.unwrap() // 必须使用 as_mut ,得到的才是原来的变量
};
let mut tmp_count = count;
unsafe {
// 清空整个table的旧数据
write_bytes(cmdtbl, 0, 1);
}
// 8K bytes (16 sectors) per PRDT
for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度 prdt_entry.dbc
volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断 prdt_entry.i
buf_ptr += 8 * 1024;
tmp_count -= 16;
}
// Last entry
let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
volatile_write_bit!(
cmdtbl.prdt_entry[las].dbc,
(1 << 22) - 1,
((tmp_count << 9) - 1) as u32
); // 数据长度
volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断
// 设置命令
let cmdfis = unsafe {
((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D)
.as_mut()
.unwrap()
};
volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8);
volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set
volatile_write!(cmdfis.command, ATA_CMD_READ_DMA_EXT);
volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8);
volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8);
volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8);
volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8);
volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8);
volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8);
volatile_write!(cmdfis.countl, (count & 0xFF) as u8);
volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8);
volatile_write!(cmdfis.device, 1 << 6); // LBA Mode
// 等待之前的操作完成
let mut spin_count = 0;
const SPIN_LIMIT: u32 = 10000;
while (volatile_read!(port.tfd) as u8 & (ATA_DEV_BUSY | ATA_DEV_DRQ)) > 0
&& spin_count < SPIN_LIMIT
{
spin_count += 1;
}
if spin_count == SPIN_LIMIT {
kerror!("Port is hung");
return Err(-(EIO as i32));
}
volatile_set_bit!(port.ci, 1 << slot, true); // Issue command
// kdebug!("To wait ahci read complete.");
// 等待操作完成
loop {
if (volatile_read!(port.ci) & (1 << slot)) == 0 {
break;
}
if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 {
kerror!("Read disk error");
return Err(-(EIO as i32));
}
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// successfully read
return Ok(count * 512);
}
fn write_at(
&self,
lba_id_start: crate::io::device::BlockId,
count: usize,
buf: &[u8],
) -> Result<usize, i32> {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let check_length = ((count - 1) >> 4) + 1; // prdt length
if count * 512 > buf.len() || check_length > u16::MAX as usize {
// 不可能的操作
return Err(-(E2BIG as i32));
} else if count == 0 {
return Ok(0);
}
let port = _port(self.ctrl_num, self.port_num);
volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
let slot = port.find_cmdslot().unwrap_or(u32::MAX);
if slot == u32::MAX {
return Err(-(EIO as i32));
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
#[allow(unused_unsafe)]
let cmdheader: &mut HbaCmdHeader = unsafe {
(phys_2_virt(
volatile_read!(port.clb) as usize
+ slot as usize * size_of::<HbaCmdHeader>() as usize,
) as *mut HbaCmdHeader)
.as_mut()
.unwrap()
};
compiler_fence(core::sync::atomic::Ordering::SeqCst);
volatile_write_bit!(
cmdheader.cfl,
(1 << 5) - 1 as u8,
(size_of::<FisRegH2D>() / size_of::<u32>()) as u8
); // Command FIS size
volatile_set_bit!(cmdheader.cfl, 7 << 5, true); // (p,c,w)都设置为1, Read/Write bit : Write from device
volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
// 设置数据存放地址
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let mut buf_ptr = buf as *const [u8] as *mut usize as usize;
#[allow(unused_unsafe)]
let cmdtbl = unsafe {
(phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
.as_mut()
.unwrap()
};
let mut tmp_count = count;
compiler_fence(core::sync::atomic::Ordering::SeqCst);
unsafe {
// 清空整个table的旧数据
write_bytes(cmdtbl, 0, 1);
}
// 8K bytes (16 sectors) per PRDT
for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度
volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断
buf_ptr += 8 * 1024;
tmp_count -= 16;
}
// Last entry
let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断
volatile_write_bit!(
cmdtbl.prdt_entry[las].dbc,
(1 << 22) - 1,
((tmp_count << 9) - 1) as u32
); // 数据长度
// 设置命令
let cmdfis = unsafe {
((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D)
.as_mut()
.unwrap()
};
volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8);
volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set
volatile_write!(cmdfis.command, ATA_CMD_WRITE_DMA_EXT);
volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8);
volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8);
volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8);
volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8);
volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8);
volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8);
volatile_write!(cmdfis.countl, (count & 0xFF) as u8);
volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8);
volatile_write!(cmdfis.device, 1 << 6); // LBA Mode
volatile_set_bit!(port.ci, 1 << slot, true); // Issue command
// 等待操作完成
loop {
if (volatile_read!(port.ci) & (1 << slot)) == 0 {
break;
}
if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 {
kerror!("Write disk error");
return Err(-(EIO as i32));
}
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// successfully read
return Ok(count * 512);
}
fn sync(&self) -> Result<(), i32> {
// 由于目前没有block cache, 因此sync返回成功即可
return Ok(());
}
}
impl LockedAhciDisk {
pub fn new(
name: String,
flags: u16,
ctrl_num: u8,
port_num: u8,
) -> Result<Arc<LockedAhciDisk>, i32> {
let mut part_s: Vec<Arc<Partition>> = Vec::new();
// 构建磁盘结构体
let result: Arc<LockedAhciDisk> = Arc::new(LockedAhciDisk(SpinLock::new(AhciDisk {
name,
flags,
partitions: Default::default(),
ctrl_num,
port_num,
self_ref: Weak::default(),
})));
let table: MbrDiskPartionTable = result.read_mbr_table()?;
let weak_this: Weak<LockedAhciDisk> = Arc::downgrade(&result); // 获取this的弱指针
// 求出有多少可用分区
for i in 0..4 {
if table.dpte[i].part_type != 0 {
part_s.push(Partition::new(
table.dpte[i].starting_sector() as u64,
table.dpte[i].starting_lba as u64,
table.dpte[i].total_sectors as u64,
weak_this.clone(),
i as u16,
));
}
}
result.0.lock().partitions = part_s;
result.0.lock().self_ref = weak_this;
return Ok(result);
}
/// @brief: 从磁盘中读取 MBR 分区表结构体 TODO: Cursor
pub fn read_mbr_table(&self) -> Result<MbrDiskPartionTable, i32> {
let mut table: MbrDiskPartionTable = Default::default();
// 数据缓冲区
let mut buf: Vec<u8> = Vec::new();
buf.resize(size_of::<MbrDiskPartionTable>(), 0);
self.read_at(0, 1, &mut buf)?;
// 创建 Cursor 用于按字节读取
let mut cursor = VecCursor::new(buf);
cursor.seek(SeekFrom::SeekCurrent(446))?;
for i in 0..4 {
// kdebug!("infomation of partition {}:\n", i);
table.dpte[i].flags = cursor.read_u8()?;
table.dpte[i].starting_head = cursor.read_u8()?;
table.dpte[i].starting_sector_cylinder = cursor.read_u16()?;
table.dpte[i].part_type = cursor.read_u8()?;
table.dpte[i].ending_head = cursor.read_u8()?;
table.dpte[i].ending_sector_cylingder = cursor.read_u16()?;
table.dpte[i].starting_lba = cursor.read_u32()?;
table.dpte[i].total_sectors = cursor.read_u32()?;
// kdebug!("dpte[i] = {:?}", table.dpte[i]);
}
table.bs_trailsig = cursor.read_u16()?;
// kdebug!("bs_trailsig = {}", unsafe {
// read_unaligned(addr_of!(table.bs_trailsig))
// });
return Ok(table);
}
}
impl BlockDevice for LockedAhciDisk {
#[inline]
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
#[inline]
fn blk_size_log2(&self) -> u8 {
9
}
#[inline]
fn read_at(
&self,
lba_id_start: crate::io::device::BlockId,
count: usize,
buf: &mut [u8],
) -> Result<usize, i32> {
// kdebug!(
// "ahci read at {lba_id_start}, count={count}, lock={:?}",
// self.0
// );
return self.0.lock().read_at(lba_id_start, count, buf);
}
#[inline]
fn write_at(
&self,
lba_id_start: crate::io::device::BlockId,
count: usize,
buf: &[u8],
) -> Result<usize, i32> {
self.0.lock().write_at(lba_id_start, count, buf)
}
fn sync(&self) -> Result<(), i32> {
return self.0.lock().sync();
}
#[inline]
fn device(&self) -> Arc<dyn crate::io::device::Device> {
return self.0.lock().self_ref.upgrade().unwrap();
}
fn block_size(&self) -> usize {
todo!()
}
fn partitions(&self) -> Vec<Arc<Partition>> {
return self.0.lock().partitions.clone();
}
}

View File

@ -0,0 +1,408 @@
use alloc::vec::Vec;
use core::{intrinsics::size_of, ptr};
use core::sync::atomic::compiler_fence;
use crate::mm::phys_2_virt;
/// 文件说明: 实现了 AHCI 中的控制器 HBA 的相关行为
/// 根据 AHCI 写出 HBA 的 Command
pub const ATA_CMD_READ_DMA_EXT: u8 = 0x25; // 读操作,并且退出
pub const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; // 写操作,并且退出
#[allow(dead_code)]
pub const ATA_CMD_IDENTIFY: u8 = 0xEC;
#[allow(dead_code)]
pub const ATA_CMD_IDENTIFY_PACKET: u8 = 0xA1;
#[allow(dead_code)]
pub const ATA_CMD_PACKET: u8 = 0xA0;
pub const ATA_DEV_BUSY: u8 = 0x80;
pub const ATA_DEV_DRQ: u8 = 0x08;
pub const HBA_PORT_CMD_CR: u32 = 1 << 15;
pub const HBA_PORT_CMD_FR: u32 = 1 << 14;
pub const HBA_PORT_CMD_FRE: u32 = 1 << 4;
pub const HBA_PORT_CMD_ST: u32 = 1;
#[allow(dead_code)]
pub const HBA_PORT_IS_ERR: u32 = 1 << 30 | 1 << 29 | 1 << 28 | 1 << 27;
pub const HBA_SSTS_PRESENT: u32 = 0x3;
pub const HBA_SIG_ATA: u32 = 0x00000101;
pub const HBA_SIG_ATAPI: u32 = 0xEB140101;
pub const HBA_SIG_PM: u32 = 0x96690101;
pub const HBA_SIG_SEMB: u32 = 0xC33C0101;
/// 接入 Port 的 不同设备类型
#[derive(Debug)]
pub enum HbaPortType {
None,
Unknown(u32),
SATA,
SATAPI,
PM,
SEMB,
}
/// 声明了 HBA 的所有属性
#[repr(packed)]
pub struct HbaPort {
pub clb: u64, // 0x00, command list base address, 1K-byte aligned
pub fb: u64, // 0x08, FIS base address, 256-byte aligned
pub is: u32, // 0x10, interrupt status
pub ie: u32, // 0x14, interrupt enable
pub cmd: u32, // 0x18, command and status
pub _rsv0: u32, // 0x1C, Reserved
pub tfd: u32, // 0x20, task file data
pub sig: u32, // 0x24, signature
pub ssts: u32, // 0x28, SATA status (SCR0:SStatus)
pub sctl: u32, // 0x2C, SATA control (SCR2:SControl)
pub serr: u32, // 0x30, SATA error (SCR1:SError)
pub sact: u32, // 0x34, SATA active (SCR3:SActive)
pub ci: u32, // 0x38, command issue
pub sntf: u32, // 0x3C, SATA notification (SCR4:SNotification)
pub fbs: u32, // 0x40, FIS-based switch control
pub _rsv1: [u32; 11], // 0x44 ~ 0x6F, Reserved
pub vendor: [u32; 4], // 0x70 ~ 0x7F, vendor specific
}
/// 全称 HBA Memory Register是HBA的寄存器在内存中的映射
#[repr(packed)]
pub struct HbaMem {
pub cap: u32, // 0x00, Host capability
pub ghc: u32, // 0x04, Global host control
pub is: u32, // 0x08, Interrupt status
pub pi: u32, // 0x0C, Port implemented
pub vs: u32, // 0x10, Version
pub ccc_ctl: u32, // 0x14, Command completion coalescing control
pub ccc_pts: u32, // 0x18, Command completion coalescing ports
pub em_loc: u32, // 0x1C, Enclosure management location
pub em_ctl: u32, // 0x20, Enclosure management control
pub cap2: u32, // 0x24, Host capabilities extended
pub bohc: u32, // 0x28, BIOS/OS handoff control and status
pub _rsv: [u8; 116], // 0x2C - 0x9F, Reserved
pub vendor: [u8; 96], // 0xA0 - 0xFF, Vendor specific registers
pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers
}
/// HBA Command Table 里面的 PRDT 项
/// 作用: 记录了内存中读/写数据的位置,以及长度。你可以把他类比成一个指针?
#[repr(packed)]
pub struct HbaPrdtEntry {
pub dba: u64, // Data base address
_rsv0: u32, // Reserved
pub dbc: u32, // Byte count, 4M max, interrupt = 1
}
/// HAB Command Table
/// 每个 Port 一个 Table主机和设备的交互都靠这个数据结构
#[repr(packed)]
pub struct HbaCmdTable {
// 0x00
pub cfis: [u8; 64], // Command FIS
// 0x40
pub acmd: [u8; 16], // ATAPI command, 12 or 16 bytes
// 0x50
_rsv: [u8; 48], // Reserved
// 0x80
pub prdt_entry: [HbaPrdtEntry; 65535], // Physical region descriptor table entries, 0 ~ 65535, 需要注意不要越界
}
/// HBA Command Header
/// 作用: 你可以把他类比成 Command Table 的指针。
/// 猜测: 这里多了一层 Header而不是直接在 HbaMem 结构体指向 CmdTable可能是为了兼容和可移植性
#[repr(packed)]
pub struct HbaCmdHeader {
// DW0
pub cfl: u8,
// Command FIS length in DWORDS: 5(len in [2, 16]), atapi: 1, write - host to device: 1, prefetchable: 1
pub _pm: u8, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier
pub prdtl: u16, // Physical region descriptor table length in entries
// DW1
pub _prdbc: u32, // Physical region descriptor byte count transferred
// DW2, 3
pub ctba: u64, // Command table descriptor base address
// DW4 - 7
pub _rsv1: [u32; 4], // Reserved
}
/// Port 的函数实现
impl HbaPort {
/// 获取设备类型
pub fn check_type(&mut self) -> HbaPortType {
if volatile_read!(self.ssts) & HBA_SSTS_PRESENT > 0 {
let sig = volatile_read!(self.sig);
match sig {
HBA_SIG_ATA => HbaPortType::SATA,
HBA_SIG_ATAPI => HbaPortType::SATAPI,
HBA_SIG_PM => HbaPortType::PM,
HBA_SIG_SEMB => HbaPortType::SEMB,
_ => HbaPortType::Unknown(sig),
}
} else {
HbaPortType::None
}
}
/// 启动该端口的命令引擎
pub fn start(&mut self) {
while volatile_read!(self.cmd) & HBA_PORT_CMD_CR > 0 {
core::hint::spin_loop();
}
let val: u32 = volatile_read!(self.cmd) | HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST;
volatile_write!(self.cmd, val);
}
/// 关闭该端口的命令引擎
pub fn stop(&mut self) {
#[allow(unused_unsafe)]
{
volatile_write!(
self.cmd,
(u32::MAX ^ HBA_PORT_CMD_ST) & volatile_read!(self.cmd)
);
}
while volatile_read!(self.cmd) & (HBA_PORT_CMD_FR | HBA_PORT_CMD_CR)
== (HBA_PORT_CMD_FR | HBA_PORT_CMD_CR)
{
core::hint::spin_loop();
}
#[allow(unused_unsafe)]
{
volatile_write!(
self.cmd,
(u32::MAX ^ HBA_PORT_CMD_FRE) & volatile_read!(self.cmd)
);
}
}
/// @return: 返回一个空闲 cmd table 的 id; 如果没有,则返回 Option::None
pub fn find_cmdslot(&self) -> Option<u32> {
let slots = volatile_read!(self.sact) | volatile_read!(self.ci);
for i in 0..32 {
if slots & 1 << i == 0 {
return Some(i);
}
}
return None;
}
/// 初始化, 把 CmdList 等变量的地址赋值到 HbaPort 上 - 这些空间由操作系统分配且固定
/// 等价于原C版本的 port_rebase 函数
pub fn init(&mut self, clb: u64, fb: u64, ctbas: &Vec<u64>) {
self.stop(); // 先暂停端口
// 赋值 command list base address
// Command list offset: 1K*portno
// Command list entry size = 32
// Command list entry maxim count = 32
// Command list maxim size = 32*32 = 1K per port
volatile_write!(self.clb, clb);
unsafe {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
ptr::write_bytes(phys_2_virt(clb as usize) as *mut u64, 0, 1024);
}
// 赋值 fis base address
// FIS offset: 32K+256*portno
// FIS entry size = 256 bytes per port
volatile_write!(self.fb, fb);
unsafe {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
ptr::write_bytes(phys_2_virt(fb as usize) as *mut u64, 0, 256);
}
// 赋值 command table base address
// Command table offset: 40K + 8K*portno
// Command table size = 256*32 = 8K per port
let mut cmdheaders = phys_2_virt(clb as usize) as *mut u64 as *mut HbaCmdHeader;
for i in 0..32 as usize {
volatile_write!((*cmdheaders).prdtl, 0); // 一开始没有询问prdtl = 0
volatile_write!((*cmdheaders).ctba, ctbas[i]);
// 这里限制了 prdtl <= 8, 所以一共用了256bytes如果需要修改可以修改这里
compiler_fence(core::sync::atomic::Ordering::SeqCst);
unsafe {
ptr::write_bytes(phys_2_virt(ctbas[i] as usize) as *mut u64, 0, 256);
}
cmdheaders = (cmdheaders as usize + size_of::<HbaCmdHeader>()) as *mut HbaCmdHeader;
}
#[allow(unused_unsafe)]
{
// 启动中断
volatile_write!(self.ie, 0 /*TODO: Enable interrupts: 0b10111*/);
// 错误码
volatile_write!(self.serr, volatile_read!(self.serr));
// Disable power management
volatile_write!(self.sctl, volatile_read!(self.sctl) | 7 << 8);
// Power on and spin up device
volatile_write!(self.cmd, volatile_read!(self.cmd) | 1 << 2 | 1 << 1);
}
self.start(); // 重新开启端口
}
}
#[repr(u8)]
#[allow(dead_code)]
pub enum FisType {
/// Register FIS - host to device
RegH2D = 0x27,
/// Register FIS - device to host
RegD2H = 0x34,
/// DMA activate FIS - device to host
DmaAct = 0x39,
/// DMA setup FIS - bidirectional
DmaSetup = 0x41,
/// Data FIS - bidirectional
Data = 0x46,
/// BIST activate FIS - bidirectional
Bist = 0x58,
/// PIO setup FIS - device to host
PioSetup = 0x5F,
/// Set device bits FIS - device to host
DevBits = 0xA1,
}
#[repr(packed)]
pub struct FisRegH2D {
// DWORD 0
pub fis_type: u8, // FIS_TYPE_REG_H2D
pub pm: u8, // Port multiplier, 1: Command, 0: Control
// uint8_t pmport : 4; // Port multiplier 低4位
// uint8_t rsv0 : 3; // Reserved
// uint8_t c : 1; // 1: Command, 0: Control
pub command: u8, // Command register
pub featurel: u8, // Feature register, 7:0
// DWORD 1
pub lba0: u8, // LBA low register, 7:0
pub lba1: u8, // LBA mid register, 15:8
pub lba2: u8, // LBA high register, 23:16
pub device: u8, // Device register
// DWORD 2
pub lba3: u8, // LBA register, 31:24
pub lba4: u8, // LBA register, 39:32
pub lba5: u8, // LBA register, 47:40
pub featureh: u8, // Feature register, 15:8
// DWORD 3
pub countl: u8, // Count register, 7:0
pub counth: u8, // Count register, 15:8
pub icc: u8, // Isochronous command completion
pub control: u8, // Control register
// DWORD 4
pub rsv1: [u8; 4], // Reserved
}
#[repr(packed)]
#[allow(dead_code)]
pub struct FisRegD2H {
// DWORD 0
pub fis_type: u8, // FIS_TYPE_REG_D2H
pub pm: u8, // Port multiplier, Interrupt bit: 2
pub status: u8, // Status register
pub error: u8, // Error register
// DWORD 1
pub lba0: u8, // LBA low register, 7:0
pub lba1: u8, // LBA mid register, 15:8
pub lba2: u8, // LBA high register, 23:16
pub device: u8, // Device register
// DWORD 2
pub lba3: u8, // LBA register, 31:24
pub lba4: u8, // LBA register, 39:32
pub lba5: u8, // LBA register, 47:40
pub rsv2: u8, // Reserved
// DWORD 3
pub countl: u8, // Count register, 7:0
pub counth: u8, // Count register, 15:8
pub rsv3: [u8; 2], // Reserved
// DWORD 4
pub rsv4: [u8; 4], // Reserved
}
#[repr(packed)]
#[allow(dead_code)]
pub struct FisData {
// DWORD 0
pub fis_type: u8, // FIS_TYPE_DATA
pub pm: u8, // Port multiplier
pub rsv1: [u8; 2], // Reserved
// DWORD 1 ~ N
pub data: [u8; 252], // Payload
}
#[repr(packed)]
#[allow(dead_code)]
pub struct FisPioSetup {
// DWORD 0
pub fis_type: u8, // FIS_TYPE_PIO_SETUP
pub pm: u8, // Port multiplier, direction: 4 - device to host, interrupt: 2
pub status: u8, // Status register
pub error: u8, // Error register
// DWORD 1
pub lba0: u8, // LBA low register, 7:0
pub lba1: u8, // LBA mid register, 15:8
pub lba2: u8, // LBA high register, 23:16
pub device: u8, // Device register
// DWORD 2
pub lba3: u8, // LBA register, 31:24
pub lba4: u8, // LBA register, 39:32
pub lba5: u8, // LBA register, 47:40
pub rsv2: u8, // Reserved
// DWORD 3
pub countl: u8, // Count register, 7:0
pub counth: u8, // Count register, 15:8
pub rsv3: u8, // Reserved
pub e_status: u8, // New value of status register
// DWORD 4
pub tc: u16, // Transfer count
pub rsv4: [u8; 2], // Reserved
}
#[repr(packed)]
#[allow(dead_code)]
pub struct FisDmaSetup {
// DWORD 0
pub fis_type: u8, // FIS_TYPE_DMA_SETUP
pub pm: u8, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1
pub rsv1: [u8; 2], // Reserved
// DWORD 1&2
pub dma_buffer_id: u64, /* DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */
// DWORD 3
pub rsv3: u32, // More reserved
// DWORD 4
pub dma_buffer_offset: u32, // Byte offset into buffer. First 2 bits must be 0
// DWORD 5
pub transfer_count: u32, // Number of bytes to transfer. Bit 0 must be 0
// DWORD 6
pub rsv6: u32, // Reserved
}

View File

@ -0,0 +1,215 @@
// 导出 ahci 相关的 module
pub mod ahci_inode;
pub mod ahcidisk;
pub mod hba;
use crate::io::device::BlockDevice;
// 依赖的rust工具包
use crate::filesystem::devfs::devfs_register;
use crate::io::disk_info::BLK_GF_AHCI;
use crate::kerror;
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
use crate::mm::virt_2_phys;
use crate::{
driver::disk::ahci::{
ahcidisk::LockedAhciDisk,
hba::HbaMem,
hba::{HbaPort, HbaPortType},
},
kdebug,
};
use ahci_inode::LockedAhciInode;
use alloc::boxed::Box;
use alloc::string::ToString;
use alloc::{format, string::String, sync::Arc, vec::Vec};
use core::sync::atomic::compiler_fence;
// 依赖的C结构体/常量
use crate::include::bindings::bindings::{
ahci_cpp_init, pci_device_structure_general_device_t, pci_device_structure_header_t,
AHCI_MAPPING_BASE, MAX_AHCI_DEVICES, PAGE_2M_MASK,
};
// 仅module内可见 全局数据区 hbr_port, disks
static LOCKED_HBA_MEM_LIST: SpinLock<Vec<&mut HbaMem>> = SpinLock::new(Vec::new());
static LOCKED_DISKS_LIST: SpinLock<Vec<Arc<LockedAhciDisk>>> = SpinLock::new(Vec::new());
/* TFES - Task File Error Status */
#[allow(non_upper_case_globals)]
pub const HBA_PxIS_TFES: u32 = 1 << 30;
#[no_mangle]
pub extern "C" fn ahci_init() -> i32 {
let r = ahci_rust_init();
if r.is_ok() {
return 0;
} else {
return r.unwrap_err();
}
}
/// @brief: 初始化 ahci
pub fn ahci_rust_init() -> Result<(), i32> {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let mut ahci_dev_counts: u32 = 0;
let mut ahci_devs: [*mut pci_device_structure_header_t; MAX_AHCI_DEVICES as usize] =
[0 as *mut pci_device_structure_header_t; MAX_AHCI_DEVICES as usize];
let mut gen_devs: [*mut pci_device_structure_general_device_t; MAX_AHCI_DEVICES as usize] =
[0 as *mut pci_device_structure_general_device_t; MAX_AHCI_DEVICES as usize];
compiler_fence(core::sync::atomic::Ordering::SeqCst);
unsafe {
// 单线程 init 所以写 ahci_devs 全局变量不会出错?
ahci_cpp_init(
(&mut ahci_dev_counts) as *mut u32,
(&mut ahci_devs) as *mut *mut pci_device_structure_header_t,
(&mut gen_devs) as *mut *mut pci_device_structure_general_device_t,
);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 全局数据 - 列表
let mut disks_list = LOCKED_DISKS_LIST.lock();
for i in 0..(ahci_dev_counts as usize) {
// 对于每一个ahci控制器分配一块空间 (目前slab algorithm最大支持1MB)
let ahci_port_base_vaddr =
Box::leak(Box::new([0u8; (1 << 20) as usize])) as *mut u8 as usize;
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 获取全局引用 : 计算 HBA_MEM 的虚拟地址 依赖于C的宏定义 cal_HBA_MEM_VIRT_ADDR
let virt_addr = AHCI_MAPPING_BASE as usize + unsafe { (*gen_devs[i]).BAR5 as usize }
- (unsafe { (*gen_devs[0]).BAR5 as usize } & PAGE_2M_MASK as usize);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 最后把这个引用列表放入到全局列表
let mut hba_mem_list = LOCKED_HBA_MEM_LIST.lock();
hba_mem_list.push(unsafe { (virt_addr as *mut HbaMem).as_mut().unwrap() });
let pi = volatile_read!(hba_mem_list[i].pi);
drop(hba_mem_list);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 初始化所有的port
let mut id = 0;
for j in 0..32 {
if (pi >> j) & 1 > 0 {
let mut hba_mem_list = LOCKED_HBA_MEM_LIST.lock();
let tp = hba_mem_list[i].ports[j].check_type();
match tp {
HbaPortType::None => {
kdebug!("<ahci_rust_init> Find a None type Disk.");
}
HbaPortType::Unknown(err) => {
kdebug!("<ahci_rust_init> Find a Unknown({:?}) type Disk.", err);
}
_ => {
kdebug!("<ahci_rust_init> Find a {:?} type Disk.", tp);
// 计算地址
let fb = virt_2_phys(ahci_port_base_vaddr + (32 << 10) + (j << 8));
let clb = virt_2_phys(ahci_port_base_vaddr + (j << 10));
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let ctbas = (0..32)
.map(|x| {
virt_2_phys(
ahci_port_base_vaddr + (40 << 10) + (j << 13) + (x << 8),
) as u64
})
.collect::<Vec<_>>();
// 初始化 port
hba_mem_list[i].ports[j].init(clb as u64, fb as u64, &ctbas);
// 释放锁
drop(hba_mem_list);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 创建 disk
disks_list.push(LockedAhciDisk::new(
format!("ahci_disk_{}", id),
BLK_GF_AHCI,
i as u8,
j as u8,
)?);
id += 1; // ID 从0开始
kdebug!("start register ahci device");
// 挂载到devfs上面去
let ret = devfs_register(
format!("ahci_{}", id).as_str(),
LockedAhciInode::new(disks_list.last().unwrap().clone()),
);
if let Err(err) = ret {
kerror!(
"Ahci_{} ctrl = {}, port = {} failed to register, error code = {}",
id,
i,
j,
err
);
}
}
}
}
}
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Ok(());
}
/// @brief: 获取所有的 disk
#[allow(dead_code)]
pub fn disks() -> Vec<Arc<LockedAhciDisk>> {
let disks_list = LOCKED_DISKS_LIST.lock();
return disks_list.clone();
}
/// @brief: 通过 name 获取 disk
pub fn get_disks_by_name(name: String) -> Result<Arc<LockedAhciDisk>, i32> {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let disks_list: SpinLockGuard<Vec<Arc<LockedAhciDisk>>> = LOCKED_DISKS_LIST.lock();
for i in 0..disks_list.len() {
if disks_list[i].0.lock().name == name {
return Ok(disks_list[i].clone());
}
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Err(-1);
}
/// @brief: 通过 ctrl_num 和 port_num 获取 port
pub fn _port(ctrl_num: u8, port_num: u8) -> &'static mut HbaPort {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let list: SpinLockGuard<Vec<&mut HbaMem>> = LOCKED_HBA_MEM_LIST.lock();
let port: &HbaPort = &list[ctrl_num as usize].ports[port_num as usize];
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return unsafe { (port as *const HbaPort as *mut HbaPort).as_mut().unwrap() };
}
/// @brief: 测试函数
pub fn __test_ahci() {
let _res = ahci_rust_init();
let disk: Arc<LockedAhciDisk> = get_disks_by_name("ahci_disk_0".to_string()).unwrap();
#[deny(overflowing_literals)]
let mut buf = [0u8; 3000usize];
for i in 0..2000 {
buf[i] = i as u8;
}
let _dd = disk;
// 测试1, 写两个块,读4个块
// _dd.write_at(123, 2, &buf).unwrap();
let mut read_buf = [0u8; 3000usize];
_dd.read_at(122, 4, &mut read_buf).unwrap();
// 测试2, 只读写一个字节
for i in 0..512 {
buf[i] = 233;
}
// _dd.write_at(123, 2, &buf).unwrap();
let mut read_buf2 = [0u8; 3000usize];
_dd.read_at(122, 4, &mut read_buf2).unwrap();
}

View File

@ -0,0 +1 @@
pub mod ahci;

View File

@ -0,0 +1,2 @@
pub mod ps2_keyboard;
// pub mod ps2_keyboard_inode;

View File

@ -4,7 +4,6 @@
#include <mm/slab.h>
#include <common/printk.h>
#include <filesystem/vfs/VFS.h>
#include <filesystem/devfs/devfs.h>
#include <common/wait_queue.h>
#include <common/spinlock.h>
#include <common/kfifo.h>
@ -14,6 +13,7 @@ static struct kfifo_t kb_buf;
// 缓冲区等待队列
static wait_queue_node_t ps2_keyboard_wait_queue;
extern void ps2_keyboard_register(struct vfs_file_operations_t *);
// 缓冲区读写锁
static spinlock_t ps2_kb_buf_rw_lock;
@ -48,7 +48,6 @@ hardware_intr_controller ps2_keyboard_intr_controller =
*/
long ps2_keyboard_open(struct vfs_index_node_t *inode, struct vfs_file_t *filp)
{
filp->private_data = &kb_buf;
ps2_keyboard_reset_buffer(&kb_buf);
return 0;
}
@ -62,7 +61,6 @@ long ps2_keyboard_open(struct vfs_index_node_t *inode, struct vfs_file_t *filp)
*/
long ps2_keyboard_close(struct vfs_index_node_t *inode, struct vfs_file_t *filp)
{
filp->private_data = NULL;
ps2_keyboard_reset_buffer(&kb_buf);
return 0;
}
@ -146,7 +144,7 @@ void ps2_keyboard_handler(ul irq_num, ul buf_vaddr, struct pt_regs *regs)
{
unsigned char x = io_in8(PORT_PS2_KEYBOARD_DATA);
uint8_t count = kfifo_in((struct kfifo_t*)buf_vaddr, &x, sizeof(unsigned char));
uint8_t count = kfifo_in((struct kfifo_t *)buf_vaddr, &x, sizeof(unsigned char));
if (count == 0)
{
kwarn("ps2 keyboard buffer full.");
@ -205,7 +203,8 @@ void ps2_keyboard_init()
// 先读一下键盘的数据,防止由于在键盘初始化之前,由于按键被按下从而导致接收不到中断。
io_in8(PORT_PS2_KEYBOARD_DATA);
// 将设备挂载到devfs
devfs_register_device(DEV_TYPE_CHAR, CHAR_DEV_STYPE_PS2_KEYBOARD, &ps2_keyboard_fops, NULL);
ps2_keyboard_register(&ps2_keyboard_fops);
kinfo("ps/2 keyboard registered.");
}

View File

@ -0,0 +1,155 @@
use alloc::sync::{Arc, Weak};
use crate::{
filesystem::{
devfs::{devfs_register, DevFS, DeviceINode},
vfs::{core::generate_inode_id, FileType, IndexNode, Metadata, PollStatus},
},
include::bindings::bindings::{vfs_file_operations_t, vfs_file_t, vfs_index_node_t, ENOTSUP},
kdebug,
libs::spinlock::SpinLock,
time::TimeSpec,
};
#[derive(Debug)]
pub struct LockedPS2KeyBoardInode(SpinLock<PS2KeyBoardInode>);
#[derive(Debug)]
pub struct PS2KeyBoardInode {
/// uuid 暂时不知道有什么用x
// uuid: Uuid,
/// 指向自身的弱引用
self_ref: Weak<LockedPS2KeyBoardInode>,
/// 指向inode所在的文件系统对象的指针
fs: Weak<DevFS>,
/// INode 元数据
metadata: Metadata,
/// 键盘操作函数
f_ops: vfs_file_operations_t,
}
impl LockedPS2KeyBoardInode {
pub fn new(f_ops: &vfs_file_operations_t) -> Arc<Self> {
let inode = PS2KeyBoardInode {
// uuid: Uuid::new_v5(),
self_ref: Weak::default(),
fs: Weak::default(),
f_ops: f_ops.clone(), // 从引用复制一遍获取所有权
metadata: Metadata {
dev_id: 1,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: FileType::CharDevice, // 文件夹block设备char设备
mode: 0o666,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: 0, // 这里用来作为device number
},
};
let result = Arc::new(LockedPS2KeyBoardInode(SpinLock::new(inode)));
result.0.lock().self_ref = Arc::downgrade(&result);
return result;
}
}
impl DeviceINode for LockedPS2KeyBoardInode {
fn set_fs(&self, fs: Weak<DevFS>) {
self.0.lock().fs = fs;
}
}
#[no_mangle] // 不重命名
pub extern "C" fn ps2_keyboard_register(f_ops: &vfs_file_operations_t) {
kdebug!("register keyboard = {:p}", f_ops);
devfs_register("ps2_keyboard", LockedPS2KeyBoardInode::new(f_ops))
.expect("Failed to register ps/2 keyboard");
kdebug!("register keyboard = {:p}", f_ops);
}
impl IndexNode for LockedPS2KeyBoardInode {
fn read_at(
&self,
_offset: usize,
len: usize,
buf: &mut [u8],
_data: &mut crate::filesystem::vfs::FilePrivateData,
) -> Result<usize, i32> {
let guard = self.0.lock();
let func = guard.f_ops.read.unwrap();
let r = unsafe {
func(
0 as *mut vfs_file_t,
&mut buf[0..len] as *mut [u8] as *mut i8,
len as i64,
0 as *mut i64,
)
};
return Ok(r as usize);
}
fn write_at(
&self,
_offset: usize,
_len: usize,
_buf: &[u8],
_data: &mut crate::filesystem::vfs::FilePrivateData,
) -> Result<usize, i32> {
return Err(-(ENOTSUP as i32));
}
fn open(&self, _data: &mut crate::filesystem::vfs::FilePrivateData) -> Result<(), i32> {
let guard = self.0.lock();
let func = guard.f_ops.open.unwrap();
let _ = unsafe { func(0 as *mut vfs_index_node_t, 0 as *mut vfs_file_t) };
return Ok(());
}
fn close(&self, _data: &mut crate::filesystem::vfs::FilePrivateData) -> Result<(), i32> {
let guard = self.0.lock();
let func = guard.f_ops.close.unwrap();
let _ = unsafe { func(0 as *mut vfs_index_node_t, 0 as *mut vfs_file_t) };
return Ok(());
}
fn poll(&self) -> Result<PollStatus, i32> {
return Ok(PollStatus {
flags: PollStatus::READ_MASK,
});
}
fn metadata(&self) -> Result<Metadata, i32> {
return Ok(self.0.lock().metadata.clone());
}
fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> {
let mut inode = self.0.lock();
inode.metadata.atime = metadata.atime;
inode.metadata.mtime = metadata.mtime;
inode.metadata.ctime = metadata.ctime;
inode.metadata.mode = metadata.mode;
inode.metadata.uid = metadata.uid;
inode.metadata.gid = metadata.gid;
return Ok(());
}
fn fs(&self) -> alloc::sync::Arc<dyn crate::filesystem::vfs::FileSystem> {
return self.0.lock().fs.upgrade().unwrap();
}
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, i32> {
return Err(-(ENOTSUP as i32));
}
}

View File

@ -1,3 +1,5 @@
pub mod disk;
pub mod keyboard;
pub mod pci;
pub mod timers;
pub mod uart;

View File

@ -7,7 +7,6 @@ use bitflags::bitflags;
use core::{
convert::TryFrom,
fmt::{self, Display, Formatter},
ptr::NonNull,
};
//Bar0寄存器的offset
const BAR0_OFFSET: u8 = 0x10;

View File

@ -1,4 +1,3 @@
#include <filesystem/devfs/devfs.h>
#include <filesystem/vfs/VFS.h>
#include "tty.h"
@ -86,8 +85,8 @@ struct vfs_file_operations_t tty_fops={
.write = tty_write,
};
void tty_init(){
//注册devfs
devfs_register_device(DEV_TYPE_CHAR, CHAR_DEV_STYPE_TTY, &tty_fops, &tty_inode_private_data_ptr);
kinfo("tty driver registered. uuid=%d", tty_inode_private_data_ptr->uuid);
}
// void tty_init(){
// //注册devfs
// devfs_register_device(DEV_TYPE_CHAR, CHAR_DEV_STYPE_TTY, &tty_fops, &tty_inode_private_data_ptr);
// kinfo("tty driver registered. uuid=%d", tty_inode_private_data_ptr->uuid);
// }

View File

@ -9,4 +9,4 @@
// 获取virtio-net 设备
uint8_t get_virtio_net_device(uint8_t * bus, uint8_t *device,uint8_t * function);
//寻找并加载所有virtio设备的驱动目前只有virtio-net但其他virtio设备后续也可添加
void c_virtio_probe();
extern void c_virtio_probe();

View File

@ -2,9 +2,9 @@ use crate::include::bindings::bindings::{
alloc_pages, free_pages, memory_management_struct, Page, PAGE_2M_SHIFT, PAGE_2M_SIZE,
PAGE_OFFSET, PAGE_SHARED, ZONE_NORMAL,
};
use crate::kdebug;
use core::mem::size_of;
use core::{ptr::NonNull};
use core::ptr::NonNull;
use virtio_drivers::{BufferDirection, Hal, PhysAddr, VirtAddr, PAGE_SIZE};
pub struct HalImpl;
@ -50,7 +50,6 @@ impl Hal for HalImpl {
/// @return VirtAddr 虚拟地址
fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
paddr + PAGE_OFFSET as usize
}
/// @brief 与真实物理设备共享
/// @param buffer 要共享的buffer _direction设备到driver或driver到设备

View File

@ -1,17 +0,0 @@
#include "MBR.h"
#include <common/kprint.h>
#include <driver/disk/ahci/ahci.h>
struct MBR_disk_partition_table_t MBR_partition_tables[MBR_MAX_AHCI_CTRL_NUM][MBR_MAX_AHCI_PORT_NUM] = {0};
/**
* @brief 读取磁盘的分区表
*
* @param ahci_ctrl_num ahci控制器编号
* @param ahci_port_num ahci端口编号
* @param buf 输出缓冲区512字节
*/
int MBR_read_partition_table(struct blk_gendisk *gd, void *buf)
{
return gd->fops->transfer(gd, AHCI_CMD_READ_DMA_EXT, 0, 1, (uint64_t)buf);
}

View File

@ -1,59 +0,0 @@
/**
* @file MBR.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief MBR分区表
* @version 0.1
* @date 2022-04-19
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include <common/glib.h>
#include <common/blk_types.h>
#define MBR_MAX_AHCI_CTRL_NUM 4 // 系统支持的最大的ahci控制器数量
#define MBR_MAX_AHCI_PORT_NUM 32 // 系统支持的每个ahci控制器对应的MBR磁盘数量对应ahci磁盘号
/**
* @brief MBR硬盘分区表项的结构
*
*/
struct MBR_disk_partition_table_entry_t
{
uint8_t flags; // 引导标志符,标记此分区为活动分区
uint8_t starting_head; // 起始磁头号
uint16_t starting_sector : 6, // 起始扇区号
starting_cylinder : 10; // 起始柱面号
uint8_t type; // 分区类型ID
uint8_t ending_head; // 结束磁头号
uint16_t ending_sector : 6, // 结束扇区号
ending_cylinder : 10; // 结束柱面号
uint32_t starting_LBA; // 起始逻辑扇区
uint32_t total_sectors; // 分区占用的磁盘扇区数
} __attribute__((packed));
/**
* @brief MBR磁盘分区表结构体
*
*/
struct MBR_disk_partition_table_t
{
uint8_t reserved[446];
struct MBR_disk_partition_table_entry_t DPTE[4]; // 磁盘分区表项
uint16_t BS_TrailSig;
} __attribute__((packed));
extern struct MBR_disk_partition_table_t MBR_partition_tables[MBR_MAX_AHCI_CTRL_NUM][MBR_MAX_AHCI_PORT_NUM]; // 导出全局的MBR磁盘分区表
/**
* @brief 读取磁盘的分区表
*
* @param ahci_ctrl_num ahci控制器编号
* @param ahci_port_num ahci端口编号
* @param buf 输出缓冲区512字节
*/
int MBR_read_partition_table(struct blk_gendisk* gd, void *buf);

View File

@ -1,20 +0,0 @@
CFLAGS += -I .
kernel_fs_objs:= $(shell find ./*.c)
kernel_fs_subdirs:= devfs vfs fat32 rootfs procfs
ECHO:
@echo "$@"
$(kernel_fs_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
$(kernel_fs_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
all: $(kernel_fs_objs) $(kernel_fs_subdirs)

View File

@ -1,13 +0,0 @@
#include <common/block.h>
/**
* @brief 将磁盘注册到块设备框架中
*
* @param gendisk 磁盘结构体
* @return int 错误码
*/
int blk_register_gendisk(struct blk_gendisk * gendisk)
{
// todo: 将磁盘注册到devfs中
return 0;
}

View File

@ -1,17 +0,0 @@
CFLAGS += -I .
kernel_fs_devfs_objs:= $(shell find ./*.c)
ECHO:
@echo "$@"
$(kernel_fs_devfs_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_fs_devfs_objs)

View File

@ -1,88 +0,0 @@
#include "chardev.h"
#include "internal.h"
#include <filesystem/vfs/VFS.h>
#include <common/mutex.h>
#include <common/stdlib.h>
#include <common/string.h>
#include <common/printk.h>
static struct vfs_dir_entry_t *chardev_folder_dentry = NULL;
extern struct vfs_dir_entry_t *devfs_root_dentry;
/**
* @brief 字符设备名称前缀
*
*/
static char chardev_name_prefix[CHAR_DEV_STYPE_END + 1][32] = {
[CHAR_DEV_STYPE_START] = "",
[CHAR_DEV_STYPE_PS2_KEYBOARD] = "ps2.kb",
[CHAR_DEV_STYPE_PS2_MOUSE] = "ps2.mse",
[CHAR_DEV_STYPE_USB_MOUSE] = "usb.mse",
[CHAR_DEV_STYPE_USB_KEYBOARD] = "usb.kb",
[CHAR_DEV_STYPE_BLUETOOTH_MOUSE] = "bt.mse",
[CHAR_DEV_STYPE_BLUETOOTH_KEYBOARD] = "bt.kb",
[CHAR_DEV_STYPE_TTY] = "vdev.tty",
[CHAR_DEV_STYPE_END] = "",
};
/**
* @brief 为不同类型的字符设备分配的管理信息结构体
*
*/
static struct chardev_manage_info_t
{
mutex_t lock; // 操作互斥锁
int count;
} chardev_manage_info[CHAR_DEV_STYPE_END + 1];
/**
* @brief 在devfs中注册字符设备该函数只应被devfs调用
*
* @param private_info inode私有信息
* @param target_dentry 返回的dentry的指针
* @return int 错误码
*/
int __devfs_chardev_register(struct devfs_private_inode_info_t *private_info, struct vfs_dir_entry_t **target_dentry)
{
// 检测subtype是否合法
if (private_info->sub_type <= CHAR_DEV_STYPE_START || private_info->sub_type >= CHAR_DEV_STYPE_END)
return -EINVAL;
mutex_lock(&chardev_manage_info[private_info->sub_type].lock);
// 拷贝名称
char devname[64] = {0};
strcpy(devname, chardev_name_prefix[private_info->sub_type]);
char *ptr = devname + strlen(chardev_name_prefix[private_info->sub_type]);
sprintk(ptr, "%d", chardev_manage_info[private_info->sub_type].count);
int namelen = strlen(devname);
struct vfs_dir_entry_t *dentry = vfs_alloc_dentry(namelen + 1);
__devfs_fill_dentry(dentry, devname);
__devfs_fill_inode(dentry, vfs_alloc_inode(), VFS_IF_DEVICE, private_info);
// 将dentry挂载到char文件夹下
__devfs_dentry_bind_parent(chardev_folder_dentry, dentry);
++chardev_manage_info[private_info->sub_type].count;
mutex_unlock(&chardev_manage_info[private_info->sub_type].lock);
*target_dentry = dentry;
return 0;
}
/**
* @brief 初始化chardev管理机制
*
*/
void __devfs_chardev_init()
{
// 初始化管理信息结构体
for (int i = CHAR_DEV_STYPE_START + 1; i < CHAR_DEV_STYPE_END; ++i)
{
mutex_init(&chardev_manage_info[i].lock);
chardev_manage_info[i].count = 0;
}
vfs_mkdir("/dev/char", 0, false);
// 获取char dev的dentry
chardev_folder_dentry = __devfs_find_dir(devfs_root_dentry, "char");
}

View File

@ -1,5 +0,0 @@
#pragma once
#include "devfs.h"

View File

@ -1,47 +0,0 @@
#pragma once
#include <filesystem/vfs/VFS.h>
/**
* @brief devfs_private_file_info_t的type字段值
*
*/
enum
{
DEV_TYPE_UNDEF = 0,
DEV_TYPE_CHAR = 1,
DEV_TYPE_USB,
DEV_TYPE_BLOCK,
DEV_TYPE_NET,
DEV_TYPE_BUS,
};
/**
* @brief 字符设备的sub_type字段值
*
*/
enum
{
CHAR_DEV_STYPE_START = 0,
CHAR_DEV_STYPE_PS2_KEYBOARD = 1,
CHAR_DEV_STYPE_USB_KEYBOARD,
CHAR_DEV_STYPE_PS2_MOUSE,
CHAR_DEV_STYPE_USB_MOUSE,
CHAR_DEV_STYPE_BLUETOOTH_MOUSE,
CHAR_DEV_STYPE_BLUETOOTH_KEYBOARD,
CHAR_DEV_STYPE_TTY,
CHAR_DEV_STYPE_END, // 结束标志
};
/**
* @brief 设备文件私有信息结构体
*
*/
struct devfs_private_inode_info_t
{
uint16_t type; // 设备主类型
uint16_t sub_type; // 设备子类型
struct vfs_file_operations_t *f_ops;
uint64_t uuid;
struct vfs_index_node_t * inode; // 当前私有信息所绑定的inode
};

View File

@ -1,335 +0,0 @@
#include "devfs.h"
#include "internal.h"
#include <filesystem/vfs/VFS.h>
#include <common/glib.h>
#include <common/string.h>
#include <mm/slab.h>
#include <common/spinlock.h>
#include <debug/bug.h>
struct vfs_super_block_operations_t devfs_sb_ops;
struct vfs_dir_entry_operations_t devfs_dentry_ops;
struct vfs_file_operations_t devfs_file_ops;
struct vfs_inode_operations_t devfs_inode_ops;
struct vfs_dir_entry_t *devfs_root_dentry; // 根结点的dentry
struct vfs_superblock_t devfs_sb = {0};
const char __devfs_mount_path[] = "/dev";
static spinlock_t devfs_global_lock; // devfs的全局锁
static uint64_t __tmp_uuid = 0; // devfs的临时uuid变量todo:在引入uuid lib之后删除这里
static inline uint64_t __devfs_get_uuid()
{
// todo : 更改为使用uuid库来生成uuid
return ++__tmp_uuid;
}
/**
* @brief 创建devfs的super block
*
* @param blk 未使用devfs为伪文件系统不需要物理设备
* @return struct vfs_superblock_t*
*/
struct vfs_superblock_t *devfs_read_superblock(struct block_device *blk)
{
devfs_sb.blk_device = NULL;
devfs_sb.root = devfs_root_dentry;
devfs_sb.sb_ops = &devfs_sb_ops;
devfs_sb.dir_ops = &devfs_dentry_ops;
// todo: 为devfs增加私有信息
devfs_sb.private_sb_info = NULL;
kdebug("devfs read superblock done");
return &devfs_sb;
}
static void devfs_write_superblock(struct vfs_superblock_t *sb) { return; }
static void devfs_put_superblock(struct vfs_superblock_t *sb) { return; }
static void devfs_write_inode(struct vfs_index_node_t *inode) { return; }
struct vfs_super_block_operations_t devfs_sb_ops =
{
.write_superblock = &devfs_write_superblock,
.put_superblock = &devfs_put_superblock,
.write_inode = &devfs_write_inode,
};
static long devfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) { return 0; }
static long devfs_hash(struct vfs_dir_entry_t *dEntry, char *filename) { return 0; }
static long devfs_release(struct vfs_dir_entry_t *dEntry) { return 0; }
static long devfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) { return 0; }
struct vfs_dir_entry_operations_t devfs_dentry_ops =
{
.compare = &devfs_compare,
.hash = &devfs_hash,
.release = &devfs_release,
.iput = &devfs_iput,
};
static long devfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr)
{
return 0;
}
static long devfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) { return 0; }
static long devfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; }
static long devfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; }
static long devfs_lseek(struct vfs_file_t *file_ptr, long offset, long origin) { return 0; }
static long devfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) { return 0; }
static long devfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler)
{
// 循环读取目录下的目录项
struct vfs_dir_entry_t *dentry = file_ptr->dEntry;
struct List *list = &dentry->subdirs_list;
// 先切换到position处
for (int i = 0; i <= file_ptr->position; ++i)
{
list = list_next(list);
if (list == &dentry->subdirs_list) // 找完了
goto failed;
}
// 存在目录项
// 增加偏移量
++file_ptr->position;
// 获取目标dentry由于是子目录项因此是child_node_list
struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list);
// kdebug("target name=%s, namelen=%d", target_dent->name, target_dent->name_length);
char *name = (char *)kzalloc(target_dent->name_length + 1, 0);
strncpy(name, target_dent->name, target_dent->name_length);
uint32_t dentry_type;
if (target_dent->dir_inode->attribute & VFS_IF_DIR)
dentry_type = VFS_IF_DIR;
else
dentry_type = VFS_IF_DEVICE;
return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1);
failed:;
return 0;
}
struct vfs_file_operations_t devfs_file_ops =
{
.open = &devfs_open,
.close = &devfs_close,
.read = &devfs_read,
.write = &devfs_write,
.lseek = &devfs_lseek,
.ioctl = &devfs_ioctl,
.readdir = &devfs_readdir,
};
/**
* @brief 创建新的文件
* @param parent_inode 父目录的inode结构体
* @param dest_dEntry 新文件的dentry
* @param mode 创建模式
*/
static long devfs_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode)
{
return 0;
}
static struct vfs_dir_entry_t *devfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry)
{
/*
由于devfs是伪文件系统其所有的搜索都依赖于dentry缓存。
因此不需要根据inode来搜索目标目录项。除非目录项不存在否则不会调用这个函数。
当本函数调用的时候也就意味着devfs中没有这个文件/文件夹。
综上本函数直接返回NULL即可
*/
return NULL;
}
/**
* @brief 在devfs中创建文件夹(作用是完善子文件夹的inode信息)
*
* @param inode 父目录的inode
* @param dEntry 目标dentry
* @param mode 创建模式
* @return long 错误码
*/
static long devfs_mkdir(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry, int mode)
{
dEntry->dir_inode = vfs_alloc_inode();
dEntry->dir_inode->file_ops = &devfs_file_ops;
dEntry->dir_inode->inode_ops = &devfs_inode_ops;
dEntry->dir_ops = &devfs_dentry_ops;
// todo: 增加private inode info
dEntry->dir_inode->private_inode_info = NULL;
dEntry->dir_inode->sb = &devfs_sb;
dEntry->dir_inode->attribute = VFS_IF_DIR;
return 0;
}
static long devfs_rmdir(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry) { return 0; }
static long devfs_rename(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry) { return 0; }
static long devfs_getAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) { return 0; }
static long devfs_setAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) { return 0; }
struct vfs_inode_operations_t devfs_inode_ops = {
.create = &devfs_create,
.lookup = &devfs_lookup,
.mkdir = &devfs_mkdir,
.rmdir = &devfs_rmdir,
.rename = &devfs_rename,
.getAttr = &devfs_getAttr,
.setAttr = &devfs_setAttr,
};
struct vfs_filesystem_type_t devfs_fs_type =
{
.name = "DEVFS",
.fs_flags = 0,
.read_superblock = devfs_read_superblock,
.next = NULL,
};
static __always_inline void __devfs_init_root_inode()
{
devfs_root_dentry->dir_inode = vfs_alloc_inode();
devfs_root_dentry->dir_inode->file_ops = &devfs_file_ops;
devfs_root_dentry->dir_inode->inode_ops = &devfs_inode_ops;
// todo: 增加private inode info
devfs_root_dentry->dir_inode->private_inode_info = NULL;
devfs_root_dentry->dir_inode->sb = &devfs_sb;
devfs_root_dentry->dir_inode->attribute = VFS_IF_DIR;
}
/**
* @brief 初始化devfs的根dentry
*/
static __always_inline void __devfs_init_root_dentry()
{
devfs_root_dentry = vfs_alloc_dentry(0);
devfs_root_dentry->dir_ops = &devfs_dentry_ops;
__devfs_init_root_inode();
}
/**
* @brief 在devfs中注册设备
*
* @param device_type 设备主类型
* @param sub_type 设备子类型
* @param file_ops 设备的文件操作接口
* @param ret_private_inode_info_ptr 返回的指向inode私有信息结构体的指针
* @return int 错误码
*/
int devfs_register_device(uint16_t device_type, uint16_t sub_type, struct vfs_file_operations_t *file_ops, struct devfs_private_inode_info_t **ret_private_inode_info_ptr)
{
spin_lock(&devfs_global_lock);
int retval = 0;
// 申请private info结构体
struct devfs_private_inode_info_t *private_info = (struct devfs_private_inode_info_t *)kzalloc(sizeof(struct devfs_private_inode_info_t), 0);
private_info->f_ops = file_ops;
private_info->type = device_type;
private_info->sub_type = sub_type;
private_info->uuid = __devfs_get_uuid();
struct vfs_dir_entry_t *dentry = NULL; // 该指针由对应类型设备的注册函数设置
switch (device_type)
{
case DEV_TYPE_CHAR:
retval = __devfs_chardev_register(private_info, &dentry);
break;
default:
kerror("Unsupported device type [ %d ].", device_type);
retval = -ENOTSUP;
goto failed;
break;
}
if (ret_private_inode_info_ptr != NULL)
*ret_private_inode_info_ptr = private_info;
spin_unlock(&devfs_global_lock);
return retval;
failed:;
kfree(private_info);
spin_unlock(&devfs_global_lock);
return retval;
}
/**
* @brief 卸载设备
*
* @param private_inode_info 待卸载的设备的inode私有信息
* @param put_private_info 设备被卸载后,执行的函数
* @return int 错误码
*/
int devfs_unregister_device(struct devfs_private_inode_info_t *private_inode_info)
{
int retval = 0;
spin_lock(&devfs_global_lock);
struct vfs_dir_entry_t *base_dentry = NULL;
struct vfs_dir_entry_t *target_dentry = NULL;
// 找到父目录的dentry
{
char base_path[64] = {0};
switch (private_inode_info->type)
{
case DEV_TYPE_CHAR:
strcpy(base_path, "/dev/char");
break;
default:
retval = -ENOTSUP;
goto out;
break;
}
base_dentry = vfs_path_walk(base_path, 0);
// bug
if (unlikely(base_dentry == NULL))
{
BUG_ON(1);
retval = -ENODEV;
goto out;
}
}
// 遍历子目录寻找拥有指定inode的dentry暂时不支持一个inode对应多个dentry的情况
// todo: 支持链接文件的卸载
struct List *tmp_list = NULL, *target_list = NULL;
list_for_each_safe(target_list, tmp_list, &base_dentry->subdirs_list)
{
target_dentry = list_entry(target_list, struct vfs_dir_entry_t, child_node_list);
if (target_dentry->dir_inode == private_inode_info->inode)
{
spin_lock(&target_dentry->lockref.lock);
retval = vfs_dentry_put(target_dentry);
if (retval < 0)
{
kerror("Error when try to unregister device");
spin_unlock(&target_dentry->lockref.lock);
}
else if (retval == 0) // 该设备的所有dentry均被卸载完成不必继续迭代
break;
}
}
retval = 0;
out:;
spin_unlock(&devfs_global_lock);
return retval;
}
/**
* @brief 初始化devfs
*
*/
void devfs_init()
{
__devfs_init_root_dentry();
vfs_register_filesystem(&devfs_fs_type);
spin_init(&devfs_global_lock);
vfs_mount_fs(__devfs_mount_path, "DEVFS", NULL);
__devfs_chardev_init();
}

View File

@ -1,29 +0,0 @@
#pragma once
#include "devfs-types.h"
/**
* @brief 初始化devfs
*
*/
void devfs_init();
/**
* @brief 在devfs中注册设备
*
* @param device_type 设备主类型
* @param sub_type 设备子类型
* @param file_ops 设备的文件操作接口
* @param ret_private_inode_info_ptr 返回的指向inode私有信息结构体的指针
* @return int 错误码
*/
int devfs_register_device(uint16_t device_type, uint16_t sub_type, struct vfs_file_operations_t *file_ops, struct devfs_private_inode_info_t **ret_private_inode_info_ptr);
/**
* @brief 卸载设备
*
* @param private_inode_info 待卸载的设备的inode私有信息
* @param put_private_info 设备被卸载后,执行的函数
* @return int 错误码
*/
int devfs_unregister_device(struct devfs_private_inode_info_t * private_inode_info);

View File

@ -1,106 +0,0 @@
#pragma once
#include "devfs.h"
#include <common/string.h>
extern struct vfs_super_block_operations_t devfs_sb_ops;
extern struct vfs_dir_entry_operations_t devfs_dentry_ops;
extern struct vfs_file_operations_t devfs_file_ops;
extern struct vfs_inode_operations_t devfs_inode_ops;
extern struct vfs_superblock_t devfs_sb;
/**
* @brief 在devfs中注册字符设备该函数只应被devfs调用
*
* @param private_info inode私有信息
* @param target_dentry 返回的dentry的指针
* @return int 错误码
*/
int __devfs_chardev_register(struct devfs_private_inode_info_t *private_info, struct vfs_dir_entry_t **target_dentry);
/**
* @brief 初始化chardev管理机制
*
*/
void __devfs_chardev_init();
/**
* @brief 在父dentry中寻找子dentry
*
* @param parent_dentry 父dentry结点
* @param name 子目录项名称
* @return struct vfs_dir_entry_t*
*/
static inline struct vfs_dir_entry_t *__devfs_find_dentry(struct vfs_dir_entry_t *parent_dentry, const char *name)
{
struct List *list = &parent_dentry->subdirs_list;
while (list_next(list) != &parent_dentry->subdirs_list)
{
list = list_next(list);
// 获取目标dentry由于是子目录项因此是child_node_list
struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list);
if (strcmp(target_dent->name, name) == 0)
return target_dent;
}
return NULL;
}
/**
* @brief 在父目录下查找子目录
*
* @param parent_dentry 父目录
* @param name 子目录名
* @return struct vfs_dir_entry_t* 子目录的dentry 找不到则返回NULL
*/
static inline struct vfs_dir_entry_t *__devfs_find_dir(struct vfs_dir_entry_t *parent_dentry, const char *name)
{
struct vfs_dir_entry_t *target_dent = __devfs_find_dentry(parent_dentry, name);
if (target_dent->dir_inode->attribute & VFS_IF_DIR) // 名称相符且为目录则返回dentry
return target_dent;
else
return NULL; // 否则直接返回空
}
/**
* @brief 将dentry和inode进行绑定并填充inode
*
* @param dentry 目标dentry
* @param inode 目标inode
* @param inode_attr inode的属性
* @param private_inode_data inode私有信息
*/
static inline void __devfs_fill_inode(struct vfs_dir_entry_t *dentry, struct vfs_index_node_t *inode, uint64_t inode_attr, struct devfs_private_inode_info_t *private_inode_data)
{
dentry->dir_inode = inode;
dentry->dir_inode->file_ops = private_inode_data->f_ops;
dentry->dir_inode->inode_ops = &devfs_inode_ops;
dentry->dir_inode->private_inode_info = private_inode_data;
dentry->dir_inode->sb = &devfs_sb;
dentry->dir_inode->attribute = inode_attr;
// 反向绑定inode
private_inode_data->inode = dentry->dir_inode;
}
/**
* @brief 填充dentry中的内容
*
* @param dentry 待填充的dentry
* @param name dentry名称
*/
static inline void __devfs_fill_dentry(struct vfs_dir_entry_t *dentry, const char *name)
{
strcpy(dentry->name, name);
dentry->name_length = strlen(name);
dentry->dir_ops = &devfs_dentry_ops;
}
/**
* @brief 将dentry与父dentry进行绑定
* @param parent 父目录项
* @param dentry 子目录项
*/
#define __devfs_dentry_bind_parent(parent_dentry, dentry) ({ \
(dentry)->parent = (parent_dentry); \
list_append(&((parent_dentry)->subdirs_list), &((dentry)->child_node_list)); \
})

View File

@ -1 +1,510 @@
/// 导出devfs的模块
pub mod null_dev;
pub mod zero_dev;
use super::vfs::{
core::{generate_inode_id, ROOT_INODE},
FileSystem, FileType, FsInfo, IndexNode, Metadata, PollStatus,
};
use crate::{
include::bindings::bindings::{EEXIST, EISDIR, ENOENT, ENOTDIR, ENOTSUP},
kdebug, kerror,
libs::spinlock::{SpinLock, SpinLockGuard},
time::TimeSpec,
};
use alloc::{
collections::BTreeMap,
string::{String, ToString},
sync::{Arc, Weak},
vec::Vec,
};
const DEVFS_MAX_NAMELEN: usize = 64;
/// @brief dev文件系统
#[derive(Debug)]
pub struct DevFS {
// 文件系统根节点
root_inode: Arc<LockedDevFSInode>,
}
impl FileSystem for DevFS {
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
fn root_inode(&self) -> Arc<dyn super::vfs::IndexNode> {
return self.root_inode.clone();
}
fn info(&self) -> super::vfs::FsInfo {
return FsInfo {
blk_dev_id: 0,
max_name_len: DEVFS_MAX_NAMELEN,
};
}
}
impl DevFS {
pub fn new() -> Arc<Self> {
// 初始化root inode
let root: Arc<LockedDevFSInode> = Arc::new(LockedDevFSInode(SpinLock::new(
// /dev 的权限设置为 读+执行root 可以读写
// root 的 parent 是空指针
DevFSInode::new(FileType::Dir, 0o755 as u32, 0),
)));
let devfs: Arc<DevFS> = Arc::new(DevFS { root_inode: root });
// 对root inode加锁并继续完成初始化工作
let mut root_guard: SpinLockGuard<DevFSInode> = devfs.root_inode.0.lock();
root_guard.parent = Arc::downgrade(&devfs.root_inode);
root_guard.self_ref = Arc::downgrade(&devfs.root_inode);
root_guard.fs = Arc::downgrade(&devfs);
// 释放锁
drop(root_guard);
// 创建文件夹
let root: &Arc<LockedDevFSInode> = &devfs.root_inode;
root.add_dir("char")
.expect("DevFS: Failed to create /dev/char");
root.add_dir("block")
.expect("DevFS: Failed to create /dev/block");
devfs.register_bultinin_device();
kdebug!("ls /dev: {:?}", root.list());
return devfs;
}
/// @brief 注册系统内部自带的设备
fn register_bultinin_device(&self) {
use null_dev::LockedNullInode;
use zero_dev::LockedZeroInode;
let dev_root: Arc<LockedDevFSInode> = self.root_inode.clone();
dev_root
.add_dev("null", LockedNullInode::new())
.expect("DevFS: Failed to register /dev/null");
dev_root
.add_dev("zero", LockedZeroInode::new())
.expect("DevFS: Failed to register /dev/zero");
}
/// @brief 在devfs内注册设备
///
/// @param name 设备名称
/// @param device 设备节点的结构体
pub fn register_device<T: DeviceINode>(&self, name: &str, device: Arc<T>) -> Result<(), i32> {
let dev_root_inode: Arc<LockedDevFSInode> = self.root_inode.clone();
match device.metadata().unwrap().file_type {
// 字节设备挂载在 /dev/char
FileType::CharDevice => {
if let Err(_) = dev_root_inode.find("char") {
dev_root_inode.create("char", FileType::Dir, 0o755)?;
}
let any_char_inode = dev_root_inode.find("char")?;
let dev_char_inode: &LockedDevFSInode = any_char_inode
.as_any_ref()
.downcast_ref::<LockedDevFSInode>()
.unwrap();
dev_char_inode.add_dev(name, device.clone())?;
device.set_fs(dev_char_inode.0.lock().fs.clone());
}
FileType::BlockDevice => {
if let Err(_) = dev_root_inode.find("block") {
dev_root_inode.create("block", FileType::Dir, 0o755)?;
}
let any_block_inode = dev_root_inode.find("block")?;
let dev_block_inode: &LockedDevFSInode = any_block_inode
.as_any_ref()
.downcast_ref::<LockedDevFSInode>()
.unwrap();
dev_block_inode.add_dev(name, device.clone())?;
device.set_fs(dev_block_inode.0.lock().fs.clone());
}
_ => {
return Err(-(ENOTSUP as i32));
}
}
return Ok(());
}
/// @brief 卸载设备
pub fn unregister_device<T: DeviceINode>(&self, name: &str, device: Arc<T>) -> Result<(), i32> {
let dev_root_inode: Arc<LockedDevFSInode> = self.root_inode.clone();
match device.metadata().unwrap().file_type {
// 字节设备挂载在 /dev/char
FileType::CharDevice => {
if let Err(_) = dev_root_inode.find("char") {
return Err(-(ENOENT as i32));
}
let any_char_inode = dev_root_inode.find("char")?;
let dev_char_inode = any_char_inode
.as_any_ref()
.downcast_ref::<LockedDevFSInode>()
.unwrap();
// TODO 调用设备的卸载接口(当引入卸载接口之后)
dev_char_inode.remove(name)?;
}
FileType::BlockDevice => {
if let Err(_) = dev_root_inode.find("block") {
return Err(-(ENOENT as i32));
}
let any_block_inode = dev_root_inode.find("block")?;
let dev_block_inode = any_block_inode
.as_any_ref()
.downcast_ref::<LockedDevFSInode>()
.unwrap();
dev_block_inode.remove(name)?;
}
_ => {
return Err(-(ENOTSUP as i32));
}
}
return Ok(());
}
}
/// @brief dev文件i节点(锁)
#[derive(Debug)]
pub struct LockedDevFSInode(SpinLock<DevFSInode>);
/// @brief dev文件i节点(无锁)
#[derive(Debug)]
pub struct DevFSInode {
/// 指向父Inode的弱引用
parent: Weak<LockedDevFSInode>,
/// 指向自身的弱引用
self_ref: Weak<LockedDevFSInode>,
/// 子Inode的B树
children: BTreeMap<String, Arc<dyn IndexNode>>,
/// 指向inode所在的文件系统对象的指针
fs: Weak<DevFS>,
/// INode 元数据
metadata: Metadata,
}
impl DevFSInode {
pub fn new(dev_type_: FileType, mode_: u32, data_: usize) -> Self {
return Self::new_with_parent(Weak::default(), dev_type_, mode_, data_);
}
pub fn new_with_parent(
parent: Weak<LockedDevFSInode>,
dev_type_: FileType,
mode_: u32,
data_: usize,
) -> Self {
return DevFSInode {
parent: parent,
self_ref: Weak::default(),
children: BTreeMap::new(),
metadata: Metadata {
dev_id: 1,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: dev_type_, // 文件夹
mode: mode_,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: data_,
},
fs: Weak::default(),
};
}
}
impl LockedDevFSInode {
pub fn add_dir(&self, name: &str) -> Result<(), i32> {
let guard:SpinLockGuard<DevFSInode> = self.0.lock();
if guard.children.contains_key(name) {
return Err(-(EEXIST as i32));
}
match self.do_create_with_data(guard, name, FileType::Dir, 0o755 as u32, 0) {
Ok(inode) => inode,
Err(err) => {
return Err(err);
}
};
return Ok(());
}
pub fn add_dev(&self, name: &str, dev: Arc<dyn IndexNode>) -> Result<(), i32> {
let mut this = self.0.lock();
if this.children.contains_key(name) {
return Err(-(EEXIST as i32));
}
this.children.insert(name.to_string(), dev);
return Ok(());
}
pub fn remove(&self, name: &str) -> Result<(), i32> {
let x = self
.0
.lock()
.children
.remove(name)
.ok_or(-(ENOENT as i32))?;
drop(x);
return Ok(());
}
fn do_create_with_data(&self, mut guard: SpinLockGuard<DevFSInode>,_name: &str,
_file_type: FileType,
_mode: u32,
_data: usize,) -> Result<Arc<dyn IndexNode>, i32>{
if guard.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 如果有重名的,则返回
if guard.children.contains_key(_name) {
return Err(-(EEXIST as i32));
}
// 创建inode
let result: Arc<LockedDevFSInode> = Arc::new(LockedDevFSInode(SpinLock::new(DevFSInode {
parent: guard.self_ref.clone(),
self_ref: Weak::default(),
children: BTreeMap::new(),
metadata: Metadata {
dev_id: 0,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: _file_type,
mode: _mode,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: _data,
},
fs: guard.fs.clone(),
})));
// 初始化inode的自引用的weak指针
result.0.lock().self_ref = Arc::downgrade(&result);
// 将子inode插入父inode的B树中
guard.children.insert(String::from(_name), result.clone());
return Ok(result);
}
}
impl IndexNode for LockedDevFSInode {
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
fn open(&self, _data: &mut super::vfs::FilePrivateData) -> Result<(), i32> {
return Ok(());
}
fn close(&self, _data: &mut super::vfs::FilePrivateData) -> Result<(), i32> {
return Ok(());
}
fn create_with_data(
&self,
name: &str,
file_type: FileType,
mode: u32,
data: usize,
) -> Result<Arc<dyn IndexNode>, i32> {
// 获取当前inode
let guard:SpinLockGuard<DevFSInode> = self.0.lock();
// 如果当前inode不是文件夹则返回
return self.do_create_with_data(guard, name, file_type, mode, data);
}
fn find(&self, name: &str) -> Result<Arc<dyn IndexNode>, i32> {
let inode = self.0.lock();
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
match name {
"" | "." => {
return Ok(inode.self_ref.upgrade().ok_or(-(ENOENT as i32))?);
}
".." => {
return Ok(inode.parent.upgrade().ok_or(-(ENOENT as i32))?);
}
name => {
// 在子目录项中查找
return Ok(inode.children.get(name).ok_or(-(ENOENT as i32))?.clone());
}
}
}
fn fs(&self) -> Arc<dyn FileSystem> {
return self.0.lock().fs.upgrade().unwrap();
}
fn get_entry_name(&self, ino: super::vfs::InodeId) -> Result<String, i32> {
let inode: SpinLockGuard<DevFSInode> = self.0.lock();
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
match ino {
0 => {
return Ok(String::from("."));
}
1 => {
return Ok(String::from(".."));
}
ino => {
// 暴力遍历所有的children判断inode id是否相同
// TODO: 优化这里,这个地方性能很差!
let mut key: Vec<String> = inode
.children
.keys()
.filter(|k| inode.children.get(*k).unwrap().metadata().unwrap().inode_id == ino)
.cloned()
.collect();
match key.len() {
0=>{return Err(-(ENOENT as i32));}
1=>{return Ok(key.remove(0));}
_ => panic!("Devfs get_entry_name: key.len()={key_len}>1, current inode_id={inode_id}, to find={to_find}", key_len=key.len(), inode_id = inode.metadata.inode_id, to_find=ino)
}
}
}
}
fn ioctl(&self, _cmd: u32, _data: usize) -> Result<usize, i32> {
Err(-(ENOTSUP as i32))
}
fn list(&self) -> Result<Vec<String>, i32> {
let info = self.metadata()?;
if info.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
let mut keys: Vec<String> = Vec::new();
keys.push(String::from("."));
keys.push(String::from(".."));
keys.append(&mut self.0.lock().children.keys().cloned().collect());
return Ok(keys);
}
fn metadata(&self) -> Result<Metadata, i32> {
return Ok(self.0.lock().metadata.clone());
}
fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> {
let mut inode = self.0.lock();
inode.metadata.atime = metadata.atime;
inode.metadata.mtime = metadata.mtime;
inode.metadata.ctime = metadata.ctime;
inode.metadata.mode = metadata.mode;
inode.metadata.uid = metadata.uid;
inode.metadata.gid = metadata.gid;
return Ok(());
}
fn poll(&self) -> Result<super::vfs::PollStatus, i32> {
// 加锁
let inode: SpinLockGuard<DevFSInode> = self.0.lock();
// 检查当前inode是否为一个文件夹如果是的话就返回错误
if inode.metadata.file_type == FileType::Dir {
return Err(-(EISDIR as i32));
}
return Ok(PollStatus {
flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK,
});
}
/// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写
fn read_at(
&self,
_offset: usize,
_len: usize,
_buf: &mut [u8],
_data: &mut super::vfs::file::FilePrivateData,
) -> Result<usize, i32> {
Err(-(ENOTSUP as i32))
}
/// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写
fn write_at(
&self,
_offset: usize,
_len: usize,
_buf: &[u8],
_data: &mut super::vfs::file::FilePrivateData,
) -> Result<usize, i32> {
Err(-(ENOTSUP as i32))
}
}
/// @brief 所有的设备INode都需要额外实现这个trait
pub trait DeviceINode: IndexNode {
fn set_fs(&self, fs: Weak<DevFS>);
// TODO: 增加 unregister 方法
}
/// @brief 获取devfs实例的强类型不可变引用
macro_rules! devfs_exact_ref {
() => {{
let devfs_inode: Result<Arc<dyn IndexNode>, i32> = ROOT_INODE().find("dev");
if let Err(e) = devfs_inode {
kerror!("failed to get DevFS ref. errcode = {e}");
return Err(-(ENOENT as i32));
}
let binding = devfs_inode.unwrap();
let devfs_inode: &LockedDevFSInode = binding
.as_any_ref()
.downcast_ref::<LockedDevFSInode>()
.unwrap();
let binding = devfs_inode.fs();
binding
}
.as_any_ref()
.downcast_ref::<DevFS>()
.unwrap()};
}
/// @brief devfs的设备注册函数
pub fn devfs_register<T: DeviceINode>(name: &str, device: Arc<T>) -> Result<(), i32> {
return devfs_exact_ref!().register_device(name, device);
}
/// @brief devfs的设备卸载函数
#[allow(dead_code)]
pub fn devfs_unregister<T: DeviceINode>(name: &str, device: Arc<T>) -> Result<(), i32> {
return devfs_exact_ref!().unregister_device(name, device);
}

View File

@ -0,0 +1,146 @@
use crate::filesystem::vfs::make_rawdev;
use crate::filesystem::vfs::{
core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, PollStatus,
};
use crate::{
include::bindings::bindings::{EINVAL, ENOTSUP},
libs::spinlock::SpinLock,
time::TimeSpec,
};
use alloc::{
string::String,
sync::{Arc, Weak},
vec::Vec,
};
// use uuid::{uuid, Uuid};
use super::{DevFS, DeviceINode};
#[derive(Debug)]
pub struct NullInode {
/// uuid 暂时不知道有什么用x
// uuid: Uuid,
/// 指向自身的弱引用
self_ref: Weak<LockedNullInode>,
/// 指向inode所在的文件系统对象的指针
fs: Weak<DevFS>,
/// INode 元数据
metadata: Metadata,
}
#[derive(Debug)]
pub struct LockedNullInode(SpinLock<NullInode>);
impl LockedNullInode {
pub fn new() -> Arc<Self> {
let inode = NullInode {
// uuid: Uuid::new_v5(),
self_ref: Weak::default(),
fs: Weak::default(),
metadata: Metadata {
dev_id: 1,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: FileType::CharDevice, // 文件夹block设备char设备
mode: 0o666,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: make_rawdev(1, 3), // 这里用来作为device number
},
};
let result = Arc::new(LockedNullInode(SpinLock::new(inode)));
result.0.lock().self_ref = Arc::downgrade(&result);
return result;
}
}
impl DeviceINode for LockedNullInode {
fn set_fs(&self, fs: Weak<DevFS>) {
self.0.lock().fs = fs;
}
}
impl IndexNode for LockedNullInode {
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> {
Err(-(ENOTSUP as i32))
}
fn close(&self, _data: &mut FilePrivateData) -> Result<(), i32> {
Err(-(ENOTSUP as i32))
}
fn metadata(&self) -> Result<Metadata, i32> {
return Ok(self.0.lock().metadata.clone());
}
fn fs(&self) -> Arc<dyn FileSystem> {
return self.0.lock().fs.upgrade().unwrap();
}
fn list(&self) -> Result<Vec<String>, i32> {
Err(-(ENOTSUP as i32))
}
fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> {
let mut inode = self.0.lock();
inode.metadata.atime = metadata.atime;
inode.metadata.mtime = metadata.mtime;
inode.metadata.ctime = metadata.ctime;
inode.metadata.mode = metadata.mode;
inode.metadata.uid = metadata.uid;
inode.metadata.gid = metadata.gid;
return Ok(());
}
fn poll(&self) -> Result<PollStatus, i32> {
return Ok(PollStatus {
flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK,
});
}
/// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写
fn read_at(
&self,
_offset: usize,
len: usize,
buf: &mut [u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32> {
if buf.len() < len {
return Err(-(EINVAL as i32));
}
for i in 0..len {
buf[i] = 0;
}
return Ok(len);
}
/// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写
fn write_at(
&self,
_offset: usize,
len: usize,
buf: &[u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32> {
if buf.len() < len {
return Err(-(EINVAL as i32));
}
Ok(len)
}
}

View File

@ -0,0 +1,146 @@
use crate::filesystem::vfs::make_rawdev;
use crate::filesystem::vfs::{
core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, PollStatus,
};
use crate::{
include::bindings::bindings::{EINVAL, ENOTSUP},
libs::spinlock::SpinLock,
time::TimeSpec,
};
use alloc::{
string::String,
sync::{Arc, Weak},
vec::Vec,
};
// use uuid::{uuid, Uuid};
use super::{DevFS, DeviceINode};
#[derive(Debug)]
pub struct ZeroInode {
/// uuid 暂时不知道有什么用x
// uuid: Uuid,
/// 指向自身的弱引用
self_ref: Weak<LockedZeroInode>,
/// 指向inode所在的文件系统对象的指针
fs: Weak<DevFS>,
/// INode 元数据
metadata: Metadata,
}
#[derive(Debug)]
pub struct LockedZeroInode(SpinLock<ZeroInode>);
impl LockedZeroInode {
pub fn new() -> Arc<Self> {
let inode = ZeroInode {
// uuid: Uuid::new_v5(),
self_ref: Weak::default(),
fs: Weak::default(),
metadata: Metadata {
dev_id: 1,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: FileType::CharDevice, // 文件夹block设备char设备
mode: 0o666,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: make_rawdev(1, 3), // 这里用来作为device number
},
};
let result = Arc::new(LockedZeroInode(SpinLock::new(inode)));
result.0.lock().self_ref = Arc::downgrade(&result);
return result;
}
}
impl DeviceINode for LockedZeroInode {
fn set_fs(&self, fs: Weak<DevFS>) {
self.0.lock().fs = fs;
}
}
impl IndexNode for LockedZeroInode {
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> {
Err(-(ENOTSUP as i32))
}
fn close(&self, _data: &mut FilePrivateData) -> Result<(), i32> {
Err(-(ENOTSUP as i32))
}
fn metadata(&self) -> Result<Metadata, i32> {
return Ok(self.0.lock().metadata.clone());
}
fn fs(&self) -> Arc<dyn FileSystem> {
return self.0.lock().fs.upgrade().unwrap();
}
fn list(&self) -> Result<Vec<String>, i32> {
Err(-(ENOTSUP as i32))
}
fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> {
let mut inode = self.0.lock();
inode.metadata.atime = metadata.atime;
inode.metadata.mtime = metadata.mtime;
inode.metadata.ctime = metadata.ctime;
inode.metadata.mode = metadata.mode;
inode.metadata.uid = metadata.uid;
inode.metadata.gid = metadata.gid;
return Ok(());
}
fn poll(&self) -> Result<PollStatus, i32> {
return Ok(PollStatus {
flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK,
});
}
/// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写
fn read_at(
&self,
_offset: usize,
len: usize,
buf: &mut [u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32> {
if buf.len() < len {
return Err(-(EINVAL as i32));
}
for i in 0..len {
buf[i] = 0;
}
return Ok(len);
}
/// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写
fn write_at(
&self,
_offset: usize,
len: usize,
buf: &[u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32> {
if buf.len() < len {
return Err(-(EINVAL as i32));
}
Ok(len)
}
}

View File

@ -0,0 +1,380 @@
#![allow(dead_code)]
use alloc::{sync::Arc, vec::Vec};
use crate::{
include::bindings::bindings::EINVAL,
io::{device::LBA_SIZE, disk_info::Partition, SeekFrom},
kerror,
libs::vec_cursor::VecCursor,
};
use super::fs::Cluster;
/// 对于所有的FAT文件系统都适用的Bios Parameter Block结构体
#[derive(Debug, Clone, Copy, Default)]
pub struct BiosParameterBlock {
/// 跳转指令
pub jmp_boot: [u8; 3],
/// 生产厂商名(表明是哪个操作系统格式化了这个卷)
pub oem_name: [u8; 8],
/// 每扇区字节数
pub bytes_per_sector: u16,
/// 每簇扇区数
pub sector_per_cluster: u8,
/// 保留扇区数
pub rsvd_sec_cnt: u16,
/// FAT表数量
pub num_fats: u8,
/// 根目录下的32字节目录项数量最大值只对FAT12、FAT16生效
pub root_entries_cnt: u16,
/// 当前分区的总扇区数只对FAT12、FAT16生效
pub total_sectors_16: u16,
/// 介质描述符
pub media: u8,
/// FAT12/16每FAT扇区数
pub fat_size_16: u16,
/// 每磁道扇区数
pub sector_per_track: u16,
/// 磁头数
pub num_heads: u16,
/// 隐藏扇区数
pub hidden_sectors: u32,
/// FAT32的总扇区数
pub total_sectors_32: u32,
/// FAT文件系统类型(以及他们的一些私有信息字段)
pub fat_type: FATType,
/// 引导扇区结束标志0xAA55
pub trail_sig: u16,
}
#[derive(Debug, Clone, Copy)]
pub enum FATType {
FAT12(BiosParameterBlockLegacy),
FAT16(BiosParameterBlockLegacy),
FAT32(BiosParameterBlockFAT32),
}
/// @brief FAT12/FAT16文件系统特有的BPB信息字段
#[derive(Debug, Clone, Copy, Default)]
pub struct BiosParameterBlockLegacy {
/// int0x13的驱动器号
pub drive_num: u8,
/// 保留字段
pub reserved1: u8,
/// 扩展引导标记
pub boot_sig: u8,
/// 卷号
/// BS_VolID
pub volume_id: u32,
/// 文件系统类型
pub filesystem_type: u32,
}
/// @brief FAT32文件系统特有的BPB信息字段
#[derive(Debug, Clone, Copy, Default)]
pub struct BiosParameterBlockFAT32 {
/// FAT32每FAT扇区数
/// BPB_FATSz32
pub fat_size_32: u32,
/// 扩展标记
/// Bits 0-3 -- Zero based number of active FAT活跃的FAT表的编号
/// Only valid if mirroring iFAT32s disabled
/// Bits 4-6 -- 保留
/// Bit 7 -- 0表示在运行时所有的FAT表都互为镜像
/// -- 1表示只使用1个FAT表具体使用的FAT表的编号需要看Bits 0-3
/// Bits 8-15 -- 保留备用
/// BPB_ExtFlags
pub ext_flags: u16,
/// 文件系统版本号。
/// 高字节表示主版本号,低字节表示次版本号。
/// BPB_FSVer
pub fs_version: u16,
/// 根目录的簇号
/// BPB_RootClus
pub root_cluster: u32,
/// FsInfo结构体在分区内的偏移量单位扇区
pub fs_info: u16,
/// 如果这个值非0,那么它表示备份的引导扇区号。
/// BPB_BkBootSec
pub backup_boot_sec: u16,
/// 保留备用
/// BPB_Reserved0
pub reserved0: [u8; 12],
/// int0x13的驱动器号
/// BS_DrvNum
pub drive_num: u8,
pub reserved1: u8,
/// 引导标记
/// BS_BootSig
pub boot_sig: u8,
/// 卷号
/// BS_VolID
pub volume_id: u32,
/// 卷标
/// BS_VolLab
pub volume_label: [u8; 11],
/// 文件系统类型
/// BS_FilSystype
pub filesystem_type: [u8; 8],
}
impl Default for FATType {
fn default() -> Self {
return FATType::FAT32(BiosParameterBlockFAT32::default());
}
}
impl FATType {
/// @brief 获取指定的簇对应的FAT表项在分区内的字节偏移量
///
/// @param cluster 要查询的簇
/// @param fat_start_sector FAT表的起始扇区
/// @param bytes_per_sec 文件系统每扇区的字节数
///
/// @return 指定的簇对应的FAT表项在分区内的字节偏移量
#[inline]
pub fn get_fat_bytes_offset(
&self,
cluster: Cluster,
fat_start_sector: u64,
bytes_per_sec: u64,
) -> u64 {
let current_cluster = cluster.cluster_num;
// 要查询的簇在FAT表中的字节偏移量
let fat_bytes_offset = match self {
FATType::FAT12(_) => current_cluster + (current_cluster / 2),
FATType::FAT16(_) => current_cluster * 2,
FATType::FAT32(_) => current_cluster * 4,
};
let fat_sec_number = fat_start_sector + (fat_bytes_offset / bytes_per_sec);
let fat_ent_offset = fat_bytes_offset % bytes_per_sec;
return fat_sec_number * bytes_per_sec + fat_ent_offset;
}
}
impl BiosParameterBlock {
pub fn new(partition: Arc<Partition>) -> Result<BiosParameterBlock, i32> {
let mut v = Vec::with_capacity(LBA_SIZE);
v.resize(LBA_SIZE, 0);
// 读取分区的引导扇区
partition
.disk()
.read_at(partition.lba_start as usize, 1, &mut v)?;
// 获取指针对象
let mut cursor = VecCursor::new(v);
let mut bpb = BiosParameterBlock::default();
cursor.read_exact(&mut bpb.jmp_boot)?;
cursor.read_exact(&mut bpb.oem_name)?;
bpb.bytes_per_sector = cursor.read_u16()?;
bpb.sector_per_cluster = cursor.read_u8()?;
bpb.rsvd_sec_cnt = cursor.read_u16()?;
bpb.num_fats = cursor.read_u8()?;
bpb.root_entries_cnt = cursor.read_u16()?;
bpb.total_sectors_16 = cursor.read_u16()?;
bpb.media = cursor.read_u8()?;
bpb.fat_size_16 = cursor.read_u16()?;
bpb.sector_per_track = cursor.read_u16()?;
bpb.num_heads = cursor.read_u16()?;
bpb.hidden_sectors = cursor.read_u32()?;
bpb.total_sectors_32 = cursor.read_u32()?;
let mut bpb32 = BiosParameterBlockFAT32::default();
bpb32.fat_size_32 = cursor.read_u32()?;
bpb32.ext_flags = cursor.read_u16()?;
bpb32.fs_version = cursor.read_u16()?;
bpb32.root_cluster = cursor.read_u32()?;
bpb32.fs_info = cursor.read_u16()?;
bpb32.backup_boot_sec = cursor.read_u16()?;
cursor.read_exact(&mut bpb32.reserved0)?;
bpb32.drive_num = cursor.read_u8()?;
bpb32.reserved1 = cursor.read_u8()?;
bpb32.boot_sig = cursor.read_u8()?;
bpb32.volume_id = cursor.read_u32()?;
cursor.read_exact(&mut bpb32.volume_label)?;
cursor.read_exact(&mut bpb32.filesystem_type)?;
// 跳过启动代码
cursor.seek(SeekFrom::SeekCurrent(420))?;
// 读取尾部的启动扇区标志
bpb.trail_sig = cursor.read_u16()?;
// 验证BPB32的信息是否合法
bpb.validate(&bpb32)?;
// 计算根目录项占用的空间(单位:字节)
let root_sectors = ((bpb.root_entries_cnt as u32 * 32) + (bpb.bytes_per_sector as u32 - 1))
/ (bpb.bytes_per_sector as u32);
// 每FAT扇区数
let fat_size = if bpb.fat_size_16 != 0 {
bpb.fat_size_16 as u32
} else {
bpb32.fat_size_32
};
// 当前分区总扇区数
let total_sectors = if bpb.total_sectors_16 != 0 {
bpb.total_sectors_16 as u32
} else {
bpb.total_sectors_32
};
// 数据区扇区数
let data_sectors = total_sectors
- ((bpb.rsvd_sec_cnt as u32) + (bpb.num_fats as u32) * fat_size + root_sectors);
// 总的数据簇数量(向下对齐)
let count_clusters = data_sectors / (bpb.sector_per_cluster as u32);
// 设置FAT类型
bpb.fat_type = if count_clusters < 4085 {
FATType::FAT12(BiosParameterBlockLegacy::default())
} else if count_clusters < 65525 {
FATType::FAT16(BiosParameterBlockLegacy::default())
} else {
FATType::FAT32(bpb32)
};
return Ok(bpb);
}
/// @brief 验证BPB32的信息是否合法
pub fn validate(&self, bpb32: &BiosParameterBlockFAT32) -> Result<(), i32> {
// 校验每扇区字节数是否合法
if self.bytes_per_sector.count_ones() != 1 {
kerror!("Invalid bytes per sector(not a power of 2)");
return Err(-(EINVAL as i32));
} else if self.bytes_per_sector < 512 {
kerror!("Invalid bytes per sector (value < 512)");
return Err(-(EINVAL as i32));
} else if self.bytes_per_sector > 4096 {
kerror!("Invalid bytes per sector (value > 4096)");
return Err(-(EINVAL as i32));
}
let is_fat32 = self.is_fat32();
if self.rsvd_sec_cnt < 1 {
kerror!("Invalid rsvd_sec_cnt value in BPB");
return Err(-(EINVAL as i32));
}
if self.num_fats == 0 {
kerror!("Invalid fats value in BPB");
return Err(-(EINVAL as i32));
}
if is_fat32 && self.root_entries_cnt != 0 {
kerror!("Invalid root_entries value in BPB (should be zero for FAT32)");
return Err(-(EINVAL as i32));
}
if is_fat32 && self.total_sectors_16 != 0 {
kerror!("Invalid total_sectors_16 value in BPB (should be zero for FAT32)");
return Err(-(EINVAL as i32));
}
if (self.total_sectors_16 == 0) && (self.total_sectors_32 == 0) {
kerror!("Invalid BPB (total_sectors_16 or total_sectors_32 should be non-zero)");
return Err(-(EINVAL as i32));
}
if is_fat32 && bpb32.fat_size_32 == 0 {
kerror!("Invalid fat_size_32 value in BPB (should be non-zero for FAT32)");
return Err(-(EINVAL as i32));
}
if bpb32.fs_version != 0 {
kerror!("Unknown FAT FS version");
return Err(-(EINVAL as i32));
}
let root_sectors = ((self.root_entries_cnt as u32 * 32)
+ (self.bytes_per_sector as u32 - 1))
/ (self.bytes_per_sector as u32);
// 每FAT扇区数
let fat_size = if self.fat_size_16 != 0 {
self.fat_size_16 as u32
} else {
bpb32.fat_size_32
};
// 当前分区总扇区数
let total_sectors = if self.total_sectors_16 != 0 {
self.total_sectors_16 as u32
} else {
self.total_sectors_32
};
let first_data_sector =
(self.rsvd_sec_cnt as u32) + (self.num_fats as u32) * fat_size + root_sectors;
// 数据区扇区数
let data_sectors = total_sectors - first_data_sector;
// 总的数据簇数量(向下对齐)
let count_clusters = data_sectors / (self.sector_per_cluster as u32);
// 总扇区数应当大于第一个数据扇区的扇区号
if total_sectors <= first_data_sector {
kerror!("Total sectors lesser than first data sector");
return Err(-(EINVAL as i32));
}
// 检查文件系统类型与总的数据簇数量的关系是否合法
if (is_fat32 && (count_clusters < 65525)) || ((!is_fat32) && (count_clusters >= 65525)) {
kerror!("FAT determination using tot_sec_16 and count_cluster differs");
return Err(-(EINVAL as i32));
}
return Ok(());
}
/// @brief 判断当前是否为fat32的bpb
fn is_fat32(&self) -> bool {
// fat32的bpb这个字段是0
return self.total_sectors_16 == 0;
}
pub fn get_volume_id(&self) -> u32 {
match self.fat_type {
FATType::FAT12(f) | FATType::FAT16(f) => {
return f.volume_id;
}
FATType::FAT32(f) => {
return f.volume_id;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
pub mod bpb;
pub mod entry;
pub mod fs;
pub mod utils;

View File

@ -0,0 +1,15 @@
use core::char::REPLACEMENT_CHARACTER;
/// FAT文件系统保留开头的2个簇
pub const RESERVED_CLUSTERS: u32 = 2;
/// @brief 将u8转为ascii字符。
/// 当转码成功时返回对应的ascii字符否则返回Unicode占位符
pub fn decode_u8_ascii(value: u8) -> char {
if value <= 0x7f {
return value as char;
} else {
// 如果不是ascii字符则返回Unicode占位符 U+FFFD
return REPLACEMENT_CHARACTER;
}
}

View File

@ -1,17 +0,0 @@
CFLAGS += -I .
kernel_fs_fat32_objs:= $(shell find ./*.c)
ECHO:
@echo "$@"
$(kernel_fs_fat32_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_fs_fat32_objs)

File diff suppressed because it is too large Load Diff

View File

@ -1,221 +0,0 @@
/**
* @file fat32.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief fat32文件系统
* @version 0.1
* @date 2022-04-19
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include <filesystem/MBR.h>
#include <filesystem/vfs/VFS.h>
#define FAT32_MAX_PARTITION_NUM 128 // 系统支持的最大的fat32分区数量
#define FAT32_DELETED_FLAG 0xe5 // 如果短目录项的name[0]为这个值,那么意味着这个短目录项是空闲的
/**
* @brief fat32文件系统引导扇区结构体
*
*/
struct fat32_BootSector_t
{
uint8_t BS_jmpBoot[3]; // 跳转指令
uint8_t BS_OEMName[8]; // 生产厂商名
uint16_t BPB_BytesPerSec; // 每扇区字节数
uint8_t BPB_SecPerClus; // 每簇扇区数
uint16_t BPB_RsvdSecCnt; // 保留扇区数
uint8_t BPB_NumFATs; // FAT表数量
uint16_t BPB_RootEntCnt; // 根目录文件数最大值
uint16_t BPB_TotSec16; // 16位扇区总数
uint8_t BPB_Media; // 介质描述符
uint16_t BPB_FATSz16; // FAT12/16每FAT扇区数
uint16_t BPB_SecPerTrk; // 每磁道扇区数
uint16_t BPB_NumHeads; // 磁头数
uint32_t BPB_HiddSec; // 隐藏扇区数
uint32_t BPB_TotSec32; // 32位扇区总数
uint32_t BPB_FATSz32; // FAT32每FAT扇区数
uint16_t BPB_ExtFlags; // 扩展标志
uint16_t BPB_FSVer; // 文件系统版本号
uint32_t BPB_RootClus; // 根目录起始簇号
uint16_t BPB_FSInfo; // FS info结构体的扇区号
uint16_t BPB_BkBootSec; // 引导扇区的备份扇区号
uint8_t BPB_Reserved0[12];
uint8_t BS_DrvNum; // int0x13的驱动器号
uint8_t BS_Reserved1;
uint8_t BS_BootSig; // 扩展引导标记
uint32_t BS_VolID; // 卷序列号
uint8_t BS_VolLab[11]; // 卷标
uint8_t BS_FilSysType[8]; // 文件系统类型
uint8_t BootCode[420]; // 引导代码、数据
uint16_t BS_TrailSig; // 结束标志0xAA55
} __attribute__((packed));
/**
* @brief fat32文件系统的FSInfo扇区结构体
*
*/
struct fat32_FSInfo_t
{
uint32_t FSI_LeadSig; // FS info扇区标志符 数值为0x41615252
uint8_t FSI_Reserved1[480]; // 保留使用全部置为0
uint32_t FSI_StrucSig; // 另一个标志符数值为0x61417272
uint32_t FSI_Free_Count; // 上一次记录的空闲簇数量,这是一个参考值
uint32_t FSI_Nxt_Free; // 空闲簇的起始搜索位置,这是为驱动程序提供的参考值
uint8_t FSI_Reserved2[12]; // 保留使用全部置为0
uint32_t FSI_TrailSig; // 结束标志数值为0xaa550000
} __attribute__((packed));
#define ATTR_READ_ONLY (1 << 0)
#define ATTR_HIDDEN (1 << 1)
#define ATTR_SYSTEM (1 << 2)
#define ATTR_VOLUME_ID (1 << 3)
#define ATTR_DIRECTORY (1 << 4)
#define ATTR_ARCHIVE (1 << 5)
#define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
/**
* @brief fat32文件系统短目录项,大小为32bytes
*
*/
struct fat32_Directory_t
{
unsigned char DIR_Name[11];
unsigned char DIR_Attr; // 目录项属性
unsigned char DIR_NTRes; // EXT|BASE => 8(BASE).3(EXT)
// BASE:LowerCase(8),UpperCase(0)
// EXT:LowerCase(16),UpperCase(0)
unsigned char DIR_CrtTimeTenth; // 文件创建的毫秒级时间戳
unsigned short DIR_CrtTime; // 文件创建时间
unsigned short DIR_CrtDate; // 文件创建日期
unsigned short DIR_LastAccDate; // 文件的最后访问日期
unsigned short DIR_FstClusHI; // 起始簇号高16bit
unsigned short DIR_WrtTime; // 最后写入时间
unsigned short DIR_WrtDate; // 最后写入日期
unsigned short DIR_FstClusLO; // 起始簇号低16bit
unsigned int DIR_FileSize; // 文件大小
} __attribute__((packed));
#define LOWERCASE_BASE (8)
#define LOWERCASE_EXT (16)
/**
* @brief fat32文件系统长目录项,大小为32bytes
*
*/
struct fat32_LongDirectory_t
{
unsigned char LDIR_Ord; // 长目录项的序号
unsigned short LDIR_Name1[5]; // 长文件名的第1-5个字符每个字符占2bytes
unsigned char LDIR_Attr; // 目录项属性必须为ATTR_LONG_NAME
unsigned char LDIR_Type; // 如果为0则说明这是长目录项的子项
unsigned char LDIR_Chksum; // 短文件名的校验和
unsigned short LDIR_Name2[6]; // 长文件名的第6-11个字符每个字符占2bytes
unsigned short LDIR_FstClusLO; // 必须为0
unsigned short LDIR_Name3[2]; // 长文件名的12-13个字符每个字符占2bytes
} __attribute__((packed));
/**
* @brief fat32文件系统的超级块信息结构体
*
*/
struct fat32_partition_info_t
{
uint16_t partition_id; // 全局fat32分区id
// todo: 增加mutex使得对fat32文件系统的访问是互斥的
struct fat32_BootSector_t bootsector;
struct fat32_FSInfo_t fsinfo;
uint64_t fsinfo_sector_addr_infat;
uint64_t bootsector_bak_sector_addr_infat;
uint64_t starting_sector;
uint64_t sector_count;
uint64_t sec_per_clus; // 每簇扇区数
uint64_t bytes_per_sec; // 每扇区字节数
uint64_t bytes_per_clus; // 每簇字节数
uint64_t first_data_sector; // 数据区起始扇区号
uint64_t FAT1_base_sector; // FAT1表的起始簇号
uint64_t FAT2_base_sector; // FAT2表的起始簇号
uint64_t sec_per_FAT; // 每FAT表扇区数
uint64_t NumFATs; // FAT表数
};
typedef struct fat32_partition_info_t fat32_sb_info_t;
struct fat32_inode_info_t
{
uint32_t first_clus; // 文件的起始簇号
uint64_t dEntry_location_clus; // fat entry的起始簇号 dEntry struct in cluster (0 is root, 1 is invalid)
uint64_t dEntry_location_clus_offset; // fat entry在起始簇中的偏移量(是第几个entry) dEntry struct offset in cluster
uint16_t create_date;
uint16_t create_time;
uint16_t write_time;
uint16_t write_date;
};
typedef struct fat32_inode_info_t fat32_inode_info_t;
/**
* @brief FAT32目录项插槽信息
* 一个插槽指的是 一个长目录项/短目录项
*/
struct fat32_slot_info
{
off_t i_pos; // on-disk position of directory entry(扇区号)
off_t slot_off; // offset for slot or (de) start
int num_slots; // number of slots +1(de) in filename
struct fat32_Directory_t * de;
// todo: 加入block io层后在这里引入buffer_head
void *buffer; // 记得释放这个buffer
};
/**
* @brief 注册指定磁盘上的指定分区的fat32文件系统
*
* @param blk_dev 块设备结构体
* @param part_num 磁盘分区编号
*
* @return struct vfs_super_block_t * 文件系统的超级块
*/
struct vfs_superblock_t *fat32_register_partition(struct block_device *blk_dev, uint8_t part_num);
/**
* @brief 创建fat32文件系统的超级块
*
* @param blk 块设备结构体
* @return struct vfs_superblock_t* 创建好的超级块
*/
struct vfs_superblock_t *fat32_read_superblock(struct block_device *blk);
/**
* @brief 创建新的文件
* @param parent_inode 父目录的inode结构体
* @param dest_dEntry 新文件的dentry
* @param mode 创建模式
*/
long fat32_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode);
void fat32_init();
/**
* @brief 读取文件夹(在指定目录中找出有效目录项)
*
* @param file_ptr 文件结构体指针
* @param dirent 返回的dirent
* @param filler 填充dirent的函数
* @return int64_t
*/
int64_t fat32_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler);

View File

@ -1,481 +0,0 @@
#include "fat_ent.h"
#include "internal.h"
#include <common/errno.h>
#include <driver/disk/ahci/ahci.h>
#include <mm/slab.h>
static const char unavailable_character_in_short_name[] = {0x22, 0x2a, 0x2b, 0x2c, 0x2e, 0x2f, 0x3a, 0x3b,
0x3c, 0x3d, 0x3e, 0x3f, 0x5b, 0x5c, 0x5d, 0x7c};
/**
* @brief 请求分配指定数量的簇
*
* @param inode 要分配簇的inode
* @param clusters 返回的被分配的簇的簇号结构体
* @param num_clusters 要分配的簇的数量
* @return int 错误码
*/
int fat32_alloc_clusters(struct vfs_index_node_t *inode, uint32_t *clusters, int32_t num_clusters)
{
int retval = 0;
fat32_sb_info_t *fsbi = (fat32_sb_info_t *)inode->sb->private_sb_info;
struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)inode->private_inode_info;
struct block_device *blk = inode->sb->blk_device;
uint64_t sec_per_fat = fsbi->sec_per_FAT;
// 申请1扇区的缓冲区
uint32_t *buf = (uint32_t *)kzalloc(fsbi->bytes_per_sec, 0);
int ent_per_sec = (fsbi->bytes_per_sec >> 2);
int clus_idx = 0;
for (int i = 0; i < sec_per_fat; ++i)
{
if (clus_idx >= num_clusters)
goto done;
memset(buf, 0, fsbi->bytes_per_sec);
blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, fsbi->FAT1_base_sector + i, 1, (uint64_t)buf);
// 依次检查簇是否空闲
for (int j = 0; j < ent_per_sec; ++j)
{
if (clus_idx >= num_clusters)
goto done;
// 找到空闲簇
if ((buf[j] & 0x0fffffff) == 0)
{
// kdebug("clus[%d] = %d", clus_idx, i * ent_per_sec + j);
clusters[clus_idx] = i * ent_per_sec + j;
++clus_idx;
}
}
}
// 空间不足
retval = -ENOSPC;
done:;
kfree(buf);
if (retval == 0) // 成功
{
int cluster, idx;
if (finode->first_clus == 0)
{
// 空文件
finode->first_clus = clusters[0];
cluster = finode->first_clus;
// 写入inode到磁盘
inode->sb->sb_ops->write_inode(inode);
idx = 1;
}
else
{
// 跳转到文件当前的最后一个簇
idx = 0;
int tmp_clus = finode->first_clus;
cluster = tmp_clus;
while (true)
{
tmp_clus = fat32_read_FAT_entry(blk, fsbi, cluster);
if (tmp_clus <= 0x0ffffff7)
cluster = tmp_clus;
else
break;
}
}
// 写入fat表
for (int i = idx; i < num_clusters; ++i)
{
// kdebug("write cluster i=%d : cluster=%d, value= %d", i, cluster, clusters[i]);
fat32_write_FAT_entry(blk, fsbi, cluster, clusters[i]);
cluster = clusters[i];
}
fat32_write_FAT_entry(blk, fsbi, cluster, 0x0ffffff8);
return 0;
}
else // 出现错误
{
kwarn("err in alloc clusters");
if (clus_idx < num_clusters)
fat32_free_clusters(inode, clusters[0]);
return retval;
}
return 0;
}
/**
* @brief 释放从属于inode的从cluster开始的所有簇
*
* @param inode 指定的文件的inode
* @param cluster 指定簇
* @return int 错误码
*/
int fat32_free_clusters(struct vfs_index_node_t *inode, int32_t cluster)
{
// todo: 释放簇
return 0;
}
/**
* @brief 读取指定簇的FAT表项
*
* @param blk 块设备结构体
* @param fsbi fat32超级块私有信息结构体
* @param cluster 指定簇
* @return uint32_t 下一个簇的簇号
*/
uint32_t fat32_read_FAT_entry(struct block_device *blk, fat32_sb_info_t *fsbi, uint32_t cluster)
{
// 计算每个扇区内含有的FAT表项数
// FAT每项4bytes
uint32_t fat_ent_per_sec = (fsbi->bytes_per_sec >> 2); // 该值应为2的n次幂
uint32_t buf[256];
memset(buf, 0, fsbi->bytes_per_sec);
// 读取一个sector的数据
blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT,
fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)&buf);
// 返回下一个fat表项的值也就是下一个cluster
return buf[cluster & (fat_ent_per_sec - 1)] & 0x0fffffff;
}
/**
* @brief 写入指定簇的FAT表项
*
* @param blk 块设备结构体
* @param fsbi fat32超级块私有信息结构体
* @param cluster 指定簇
* @param value 要写入该fat表项的值
* @return uint32_t errcode
*/
int fat32_write_FAT_entry(struct block_device *blk, fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value)
{
// 计算每个扇区内含有的FAT表项数
// FAT每项4bytes
uint32_t fat_ent_per_sec = (fsbi->bytes_per_sec >> 2); // 该值应为2的n次幂
uint32_t *buf = kzalloc(fsbi->bytes_per_sec, 0);
blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT,
fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)buf);
buf[cluster & (fat_ent_per_sec - 1)] = (buf[cluster & (fat_ent_per_sec - 1)] & 0xf0000000) | (value & 0x0fffffff);
// 向FAT1和FAT2写入数据
blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT,
fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)buf);
blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT,
fsbi->FAT2_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)buf);
kfree(buf);
return 0;
}
/**
* @brief 在父亲inode的目录项簇中寻找连续num个空的目录项
*
* @param parent_inode 父inode
* @param num 请求的目录项数量
* @param mode 操作模式
* @param res_sector 返回信息:缓冲区对应的扇区号
* @param res_cluster 返回信息:缓冲区对应的簇号
* @param res_data_buf_base 返回信息:缓冲区的内存基地址(记得要释放缓冲区内存!!!!)
* @return struct fat32_Directory_t*
* 符合要求的entry的指针指向地址高处的空目录项也就是说有连续num个≤这个指针的空目录项
*/
struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *parent_inode, uint32_t num, uint32_t mode,
uint32_t *res_sector, uint64_t *res_cluster,
uint64_t *res_data_buf_base)
{
// kdebug("find empty_dentry");
struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)parent_inode->private_inode_info;
fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info;
uint8_t *buf = kzalloc(fsbi->bytes_per_clus, 0);
struct block_device *blk = parent_inode->sb->blk_device;
// 计算父目录项的起始簇号
uint32_t cluster = finode->first_clus;
struct fat32_Directory_t *tmp_dEntry = NULL;
// 指向最终的有用的dentry的指针
struct fat32_Directory_t *result_dEntry = NULL;
while (true)
{
// 计算父目录项的起始LBA扇区号
uint64_t sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus;
// 读取父目录项的起始簇数据
blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)buf);
tmp_dEntry = (struct fat32_Directory_t *)buf;
// 计数连续的空目录项
uint32_t count_continuity = 0;
// 查找连续num个空闲目录项
for (int i = 0; (i < fsbi->bytes_per_clus) && count_continuity < num; i += 32, ++tmp_dEntry)
{
if (!(tmp_dEntry->DIR_Name[0] == 0xe5 || tmp_dEntry->DIR_Name[0] == 0x00 ||
tmp_dEntry->DIR_Name[0] == 0x05))
{
count_continuity = 0;
continue;
}
if (count_continuity == 0)
result_dEntry = tmp_dEntry;
++count_continuity;
}
// 成功查找到符合要求的目录项
if (count_continuity == num)
{
result_dEntry += (num - 1);
*res_sector = sector;
*res_data_buf_base = (uint64_t)buf;
*res_cluster = cluster;
return result_dEntry;
}
// 当前簇没有发现符合条件的空闲目录项,寻找下一个簇
uint64_t old_cluster = cluster;
cluster = fat32_read_FAT_entry(blk, fsbi, cluster);
if (cluster >= 0x0ffffff7) // 寻找完父目录的所有簇,都没有找到符合要求的空目录项
{
// 新增一个簇
if (fat32_alloc_clusters(parent_inode, &cluster, 1) != 0)
{
kerror("Cannot allocate a new cluster!");
while (1)
pause();
}
// 将这个新的簇清空
sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus;
void *tmp_buf = kzalloc(fsbi->bytes_per_clus, 0);
blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT, sector, fsbi->sec_per_clus,
(uint64_t)tmp_buf);
kfree(tmp_buf);
}
}
}
/**
* @brief 检查文件名是否合法
*
* @param name 文件名
* @param namelen 文件名长度
* @param reserved 保留字段
* @return int 合法0 其他:错误码
*/
int fat32_check_name_available(const char *name, int namelen, int8_t reserved)
{
if (namelen > 255 || namelen <= 0)
return -ENAMETOOLONG;
// 首个字符不能是空格或者'.'
if (name[0] == 0x20 || name[0] == '.')
return -EINVAL;
return 0;
}
/**
* @brief 检查字符在短目录项中是否合法
*
* @param c 给定字符
* @param index 字符在文件名中处于第几位
* @return true 合法
* @return false 不合法
*/
bool fat32_check_char_available_in_short_name(const char c, int index)
{
// todo: 严格按照fat规范完善合法性检查功能
if (index == 0)
{
if (c < 0x20)
{
if (c != 0x05)
return false;
return true;
}
}
for (int i = 0; i < sizeof(unavailable_character_in_short_name) / sizeof(char); ++i)
{
if (c == unavailable_character_in_short_name[i])
return false;
}
return true;
}
/**
* @brief 填充短目录项的函数
*
* @param dEntry 目标dentry
* @param target 目标dentry对应的短目录项
* @param cluster 短目录项对应的文件/文件夹起始簇
*/
void fat32_fill_shortname(struct vfs_dir_entry_t *dEntry, struct fat32_Directory_t *target, uint32_t cluster)
{
memset(target, 0, sizeof(struct fat32_Directory_t));
{
int tmp_index = 0;
// kdebug("dEntry->name_length=%d", dEntry->name_length);
for (tmp_index = 0; tmp_index < min(8, dEntry->name_length); ++tmp_index)
{
if (dEntry->name[tmp_index] == '.')
break;
if (fat32_check_char_available_in_short_name(dEntry->name[tmp_index], tmp_index))
target->DIR_Name[tmp_index] = dEntry->name[tmp_index];
else
target->DIR_Name[tmp_index] = 0x20;
}
// 不满的部分使用0x20填充
while (tmp_index < 8)
{
// kdebug("tmp index = %d", tmp_index);
target->DIR_Name[tmp_index] = 0x20;
++tmp_index;
}
if (dEntry->dir_inode->attribute & VFS_IF_DIR)
{
while (tmp_index < 11)
{
// kdebug("tmp index = %d", tmp_index);
target->DIR_Name[tmp_index] = 0x20;
++tmp_index;
}
}
else
{
for (int j = 8; j < 11; ++j)
{
target->DIR_Name[j] = 'a';
}
}
}
struct vfs_index_node_t *inode = dEntry->dir_inode;
target->DIR_Attr = 0;
if (inode->attribute & VFS_IF_DIR)
target->DIR_Attr |= ATTR_DIRECTORY;
target->DIR_FileSize = dEntry->dir_inode->file_size;
target->DIR_FstClusHI = (uint16_t)((cluster >> 16) & 0x0fff);
target->DIR_FstClusLO = (uint16_t)(cluster & 0xffff);
// todo: 填写短目录项中的时间信息
}
/**
* @brief 填充长目录项的函数
*
* @param dEntry 目标dentry
* @param target 起始长目录项
* @param checksum 短目录项的校验和
* @param cnt_longname 总的长目录项的个数
*/
void fat32_fill_longname(struct vfs_dir_entry_t *dEntry, struct fat32_LongDirectory_t *target, uint8_t checksum,
uint32_t cnt_longname)
{
uint32_t current_name_index = 0;
struct fat32_LongDirectory_t *Ldentry = (struct fat32_LongDirectory_t *)(target + 1);
// kdebug("filling long name, name=%s, namelen=%d", dEntry->name, dEntry->name_length);
int name_length = dEntry->name_length + 1;
for (int i = 1; i <= cnt_longname; ++i)
{
--Ldentry;
Ldentry->LDIR_Ord = i;
for (int j = 0; j < 5; ++j, ++current_name_index)
{
if (current_name_index < name_length)
Ldentry->LDIR_Name1[j] = dEntry->name[current_name_index];
else
Ldentry->LDIR_Name1[j] = 0xffff;
}
for (int j = 0; j < 6; ++j, ++current_name_index)
{
if (current_name_index < name_length)
Ldentry->LDIR_Name2[j] = dEntry->name[current_name_index];
else
Ldentry->LDIR_Name2[j] = 0xffff;
}
for (int j = 0; j < 2; ++j, ++current_name_index)
{
if (current_name_index < name_length)
Ldentry->LDIR_Name3[j] = dEntry->name[current_name_index];
else
Ldentry->LDIR_Name3[j] = 0xffff;
}
Ldentry->LDIR_Attr = ATTR_LONG_NAME;
Ldentry->LDIR_FstClusLO = 0;
Ldentry->LDIR_Type = 0;
Ldentry->LDIR_Chksum = checksum;
}
// 最后一个长目录项的ord要|=0x40
Ldentry->LDIR_Ord |= 0x40;
}
/**
* @brief 删除目录项
*
* @param dir 父目录的inode
* @param sinfo 待删除的dentry的插槽信息
* @return int 错误码
*/
int fat32_remove_entries(struct vfs_index_node_t *dir, struct fat32_slot_info *sinfo)
{
int retval = 0;
struct vfs_superblock_t *sb = dir->sb;
struct fat32_Directory_t *de = sinfo->de;
fat32_sb_info_t *fsbi = (fat32_sb_info_t *)sb->private_sb_info;
int cnt_dentries = sinfo->num_slots;
// 获取文件数据区的起始簇号
int data_cluster = ((((uint32_t)de->DIR_FstClusHI) << 16) | ((uint32_t)de->DIR_FstClusLO)) & 0x0fffffff;
// kdebug("data_cluster=%d, cnt_dentries=%d, offset=%d", data_cluster, cnt_dentries, sinfo->slot_off);
// kdebug("fsbi->first_data_sector=%d, sec per clus=%d, i_pos=%d", fsbi->first_data_sector, fsbi->sec_per_clus,
// sinfo->i_pos);
// === 第一阶段,先删除短目录项
while (cnt_dentries > 0)
{
de->DIR_Name[0] = FAT32_DELETED_FLAG;
--cnt_dentries;
--de;
}
// === 第二阶段:将对目录项的更改写入磁盘
sb->blk_device->bd_disk->fops->transfer(sb->blk_device->bd_disk, AHCI_CMD_WRITE_DMA_EXT, sinfo->i_pos,
fsbi->sec_per_clus, (uint64_t)sinfo->buffer);
// === 第三阶段:清除文件的数据区
uint32_t next_clus;
int js = 0;
// kdebug("data_cluster=%#018lx", data_cluster);
while (data_cluster < 0x0ffffff8 && data_cluster >= 2)
{
// 读取下一个表项
next_clus = fat32_read_FAT_entry(sb->blk_device, fsbi, data_cluster);
// kdebug("data_cluster=%#018lx, next_clus=%#018lx", data_cluster, next_clus);
// 清除当前表项
retval = fat32_write_FAT_entry(sb->blk_device, fsbi, data_cluster, 0);
if (unlikely(retval != 0))
{
kerror("fat32_remove_entries: Failed to mark fat entry as unused for cluster:%d", data_cluster);
goto out;
}
++js;
data_cluster = next_clus;
}
out:;
// kdebug("Successfully remove %d clusters.", js);
return retval;
}

View File

@ -1,99 +0,0 @@
#pragma once
#include "fat32.h"
#include <filesystem/vfs/VFS.h>
#include <stdbool.h>
/**
* @brief 请求分配指定数量的簇
*
* @param inode 要分配簇的inode
* @param clusters 返回的被分配的簇的簇号结构体
* @param num_clusters 要分配的簇的数量
* @return int 错误码
*/
int fat32_alloc_clusters(struct vfs_index_node_t *inode, uint32_t *clusters, int32_t num_clusters);
/**
* @brief 释放从属于inode的从cluster开始的所有簇
*
* @param inode 指定的文件的inode
* @param cluster 指定簇
* @return int 错误码
*/
int fat32_free_clusters(struct vfs_index_node_t *inode, int32_t cluster);
/**
* @brief 读取指定簇的FAT表项
*
* @param blk 块设备结构体
* @param fsbi fat32超级块私有信息结构体
* @param cluster 指定簇
* @return uint32_t 下一个簇的簇号
*/
uint32_t fat32_read_FAT_entry(struct block_device * blk, fat32_sb_info_t *fsbi, uint32_t cluster);
/**
* @brief 写入指定簇的FAT表项
*
* @param blk 块设备结构体
* @param fsbi fat32超级块私有信息结构体
* @param cluster 指定簇
* @param value 要写入该fat表项的值
* @return uint32_t errcode
*/
int fat32_write_FAT_entry(struct block_device * blk, fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value);
/**
* @brief 在父亲inode的目录项簇中寻找连续num个空的目录项
*
* @param parent_inode 父inode
* @param num 请求的目录项数量
* @param mode 操作模式
* @param res_sector 返回信息:缓冲区对应的扇区号
* @param res_cluster 返回信息:缓冲区对应的簇号
* @param res_data_buf_base 返回信息:缓冲区的内存基地址(记得要释放缓冲区内存!!!!)
* @return struct fat32_Directory_t* 符合要求的entry的指针指向地址高处的空目录项也就是说有连续num个≤这个指针的空目录项
*/
struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *parent_inode, uint32_t num, uint32_t mode, uint32_t *res_sector, uint64_t *res_cluster, uint64_t *res_data_buf_base);
/**
* @brief 检查文件名是否合法
*
* @param name 文件名
* @param namelen 文件名长度
* @param reserved 保留字段
* @return int 合法0 其他:错误码
*/
int fat32_check_name_available(const char *name, int namelen, int8_t reserved);
/**
* @brief 检查字符在短目录项中是否合法
*
* @param c 给定字符
* @param index 字符在文件名中处于第几位
* @return true 合法
* @return false 不合法
*/
bool fat32_check_char_available_in_short_name(const char c, int index);
/**
* @brief 填充短目录项的函数
*
* @param dEntry 目标dentry
* @param target 目标dentry对应的短目录项
* @param cluster 短目录项对应的文件/文件夹起始簇
*/
void fat32_fill_shortname(struct vfs_dir_entry_t *dEntry, struct fat32_Directory_t *target, uint32_t cluster);
/**
* @brief 填充长目录项的函数
*
* @param dEntry 目标dentry
* @param target 起始长目录项
* @param checksum 短目录项的校验和
* @param cnt_longname 总的长目录项的个数
*/
void fat32_fill_longname(struct vfs_dir_entry_t *dEntry, struct fat32_LongDirectory_t *target, uint8_t checksum, uint32_t cnt_longname);
int fat32_remove_entries(struct vfs_index_node_t *dir, struct fat32_slot_info *sinfo);

View File

@ -1,28 +0,0 @@
#pragma once
#include <common/sys/types.h>
/**
* @brief 根据簇号计算该簇的起始扇区号LBA地址
*
* @param first_data_sector 数据区的其实扇区号
* @param sec_per_clus 每个簇的扇区数量
* @param cluster 簇号
* @return uint32_t LBA地址
*/
static inline uint32_t __fat32_calculate_LBA(uint32_t first_data_sector, uint32_t sec_per_clus, uint32_t cluster)
{
return first_data_sector + (cluster - 2) * sec_per_clus;
}
/**
* @brief 计算LBA地址所在的簇
*
* @param first_data_sector 数据区的其实扇区号
* @param sec_per_clus 每个簇的扇区数量
* @param LBA LBA地址
* @return uint32_t 所在的簇
*/
static inline uint32_t __fat32_LBA_to_cluster(uint32_t first_data_sector, uint32_t sec_per_clus, uint32_t LBA)
{
return ((LBA - first_data_sector) / sec_per_clus) + 2;
}

View File

@ -1 +0,0 @@

View File

@ -0,0 +1,65 @@
#![allow(dead_code)]
use core::default::Default;
/// @brief MBR硬盘分区表项的结构
#[repr(packed)]
#[derive(Debug, Clone, Copy)]
pub struct MbrDiskPartitionTableEntry {
pub flags: u8, // 引导标志符,标记此分区为活动分区
pub starting_head: u8, // 起始磁头号
pub starting_sector_cylinder: u16, // sector : 低6, cylinder : 高10; 起始扇区号 + 起始柱面号
pub part_type: u8, // 分区类型ID
pub ending_head: u8, // 结束磁头号
pub ending_sector_cylingder: u16, // ending_sector : 低6, ending_cylinder : 高10; 结束扇区号 + 结束柱面号
pub starting_lba: u32, // 起始逻辑扇区
pub total_sectors: u32, // 分区占用的磁盘扇区数
}
impl MbrDiskPartitionTableEntry {
pub fn starting_sector(&self) -> u16 {
return self.starting_sector_cylinder & ((1 << 6) - 1) as u16;
}
pub fn starting_cylinder(&self) -> u16 {
return (self.starting_sector_cylinder >> 6) & ((1 << 10) - 1) as u16;
}
pub fn ending_sector(&self) -> u16 {
return self.ending_sector_cylingder & ((1 << 6) - 1) as u16;
}
pub fn ending_cylinder(&self) -> u16 {
return (self.ending_sector_cylingder >> 6) & ((1 << 10) - 1) as u16;
}
}
/// @brief MBR磁盘分区表结构体
#[repr(packed)]
#[derive(Debug, Clone, Copy)]
pub struct MbrDiskPartionTable {
pub reserved: [u8; 446],
pub dpte: [MbrDiskPartitionTableEntry; 4], // 磁盘分区表项
pub bs_trailsig: u16,
}
impl Default for MbrDiskPartitionTableEntry {
fn default() -> Self {
MbrDiskPartitionTableEntry {
flags: 0,
starting_head: 0,
starting_sector_cylinder: 0,
part_type: 0,
ending_head: 0,
ending_sector_cylingder: 0,
starting_lba: 0,
total_sectors: 0,
}
}
}
impl Default for MbrDiskPartionTable {
fn default() -> Self {
MbrDiskPartionTable {
reserved: [0; 446],
dpte: [Default::default(); 4],
bs_trailsig: Default::default(),
}
}
}

View File

@ -1,5 +1,6 @@
pub mod devfs;
pub mod fat32;
pub mod fat;
pub mod mbr;
pub mod procfs;
pub mod rootfs;
pub mod ramfs;
pub mod vfs;

View File

@ -1,17 +0,0 @@
CFLAGS += -I .
kernel_fs_procfs_objs:= $(shell find ./*.c)
ECHO:
@echo "$@"
$(kernel_fs_procfs_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_fs_procfs_objs)

View File

@ -1 +1,706 @@
use core::intrinsics::size_of;
use alloc::{
borrow::ToOwned,
collections::BTreeMap,
format,
string::{String, ToString},
sync::{Arc, Weak},
vec::Vec,
};
use crate::{
filesystem::vfs::{
core::{generate_inode_id, ROOT_INODE},
FileType,
},
include::bindings::bindings::{
pid_t, process_find_pcb_by_pid, EEXIST, EINVAL, EISDIR, ENOBUFS, ENOENT, ENOTDIR,
ENOTEMPTY, ENOTSUP, EPERM, ESRCH,
},
kerror,
libs::spinlock::{SpinLock, SpinLockGuard},
time::TimeSpec,
};
use super::vfs::{
file::FilePrivateData, FileSystem, FsInfo, IndexNode, InodeId, Metadata, PollStatus,
};
/// @brief 进程文件类型
/// @usage 用于定义进程文件夹下的各类文件类型
#[derive(Debug)]
#[repr(u8)]
pub enum ProcFileType {
///展示进程状态信息
ProcStatus = 0,
//todo: 其他文件类型
///默认文件类型
Default,
}
impl From<u8> for ProcFileType {
fn from(value: u8) -> Self {
match value {
0 => ProcFileType::ProcStatus,
_ => ProcFileType::Default,
}
}
}
/// @brief 节点私有信息结构体
/// @usage 用于传入各类文件所需的信息
#[derive(Debug)]
pub struct InodeInfo {
///进程的pid
pid: i64,
///文件类型
ftype: ProcFileType,
//其他需要传入的信息在此定义
}
/// @brief procfs的inode名称的最大长度
const PROCFS_MAX_NAMELEN: usize = 64;
/// @brief procfs文件系统的Inode结构体
#[derive(Debug)]
pub struct LockedProcFSInode(SpinLock<ProcFSInode>);
/// @brief procfs文件系统结构体
#[derive(Debug)]
pub struct ProcFS {
/// procfs的root inode
root_inode: Arc<LockedProcFSInode>,
}
#[derive(Debug, Clone)]
pub struct ProcfsFilePrivateData {
data: Vec<u8>,
}
impl ProcfsFilePrivateData {
pub fn new() -> Self {
return ProcfsFilePrivateData { data: Vec::new() };
}
}
/// @brief procfs文件系统的Inode结构体(不包含锁)
#[derive(Debug)]
pub struct ProcFSInode {
/// 指向父Inode的弱引用
parent: Weak<LockedProcFSInode>,
/// 指向自身的弱引用
self_ref: Weak<LockedProcFSInode>,
/// 子Inode的B树
children: BTreeMap<String, Arc<LockedProcFSInode>>,
/// 当前inode的数据部分
data: Vec<u8>,
/// 当前inode的元数据
metadata: Metadata,
/// 指向inode所在的文件系统对象的指针
fs: Weak<ProcFS>,
/// 储存私有信息
fdata: InodeInfo,
}
/// 对ProcFSInode实现获取各类文件信息的函数
impl ProcFSInode {
/// @brief 去除Vec中所有的\0,并在结尾添加\0
#[inline]
fn trim_string(&self, data: &mut Vec<u8>) {
data.drain_filter(|x: &mut u8| *x == 0);
data.push(0);
}
// todo:其他数据获取函数实现
/// @brief 打开status文件
///
fn open_status(&self, pdata: &mut ProcfsFilePrivateData) -> Result<i64, i32> {
// 获取该pid对应的pcb结构体
let pid: &i64 = &self.fdata.pid;
let pcb = unsafe { process_find_pcb_by_pid(*pid).as_mut() };
let pcb = if pcb.is_none() {
kerror!(
"ProcFS: Cannot find pcb for pid {} when opening its 'status' file.",
pid
);
return Err(-(ESRCH as i32));
} else {
pcb.unwrap()
};
// 传入数据
let pdata: &mut Vec<u8> = &mut pdata.data;
// 由于目前有bug不能获取到pcb的name因此暂时用'Unknown'代替
let tmp_name: Vec<u8> = "Unknown".as_bytes().to_vec();
// kdebug!("pcb.name={:?}", pcb.name);
// let mut tmp_name: Vec<u8> = Vec::with_capacity(pcb.name.len());
// for val in pcb.name.iter() {
// tmp_name.push(*val as u8);
// }
pdata.append(
&mut format!(
"Name:\t{}",
String::from_utf8(tmp_name).unwrap_or("NULL".to_string())
)
.as_bytes()
.to_owned(),
);
pdata.append(&mut format!("\nstate:\t{}", pcb.state).as_bytes().to_owned());
pdata.append(&mut format!("\npid:\t{}", pcb.pid).as_bytes().to_owned());
pdata.append(
&mut format!("\nPpid:\t{}", unsafe { *pcb.parent_pcb }.pid)
.as_bytes()
.to_owned(),
);
pdata.append(&mut format!("\ncpu_id:\t{}", pcb.cpu_id).as_bytes().to_owned());
pdata.append(
&mut format!("\npriority:\t{}", pcb.priority)
.as_bytes()
.to_owned(),
);
pdata.append(
&mut format!("\npreempt:\t{}", pcb.preempt_count)
.as_bytes()
.to_owned(),
);
pdata.append(
&mut format!("\nvrtime:\t{}", pcb.virtual_runtime)
.as_bytes()
.to_owned(),
);
// 当前进程运行过程中占用内存的峰值
let hiwater_vm: u64 =
unsafe { *(*pcb.mm).vmas }.vm_end - unsafe { *(*pcb.mm).vmas }.vm_start;
// 进程数据段的大小
let text: u64 = unsafe { *pcb.mm }.code_addr_end - unsafe { *pcb.mm }.code_addr_start;
// 进程代码的大小
let data: u64 = unsafe { *pcb.mm }.data_addr_end - unsafe { *pcb.mm }.data_addr_start;
pdata.append(
&mut format!("\nVmPeak:\t{} kB", hiwater_vm)
.as_bytes()
.to_owned(),
);
pdata.append(&mut format!("\nVmData:\t{} kB", data).as_bytes().to_owned());
pdata.append(&mut format!("\nVmExe:\t{} kB\n", text).as_bytes().to_owned());
// 去除多余的\0
self.trim_string(pdata);
return Ok((pdata.len() * size_of::<u8>()) as i64);
}
/// status文件读取函数
fn read_status(
&self,
offset: usize,
len: usize,
buf: &mut [u8],
_pdata: &mut ProcfsFilePrivateData,
) -> Result<usize, i32> {
let start = _pdata.data.len().min(offset);
let end = _pdata.data.len().min(offset + len);
// buffer空间不足
if buf.len() < (end - start) {
return Err(-(ENOBUFS as i32));
}
// 拷贝数据
let src = &_pdata.data[start..end];
buf[0..src.len()].copy_from_slice(src);
return Ok(src.len());
}
}
impl FileSystem for ProcFS {
fn root_inode(&self) -> Arc<dyn super::vfs::IndexNode> {
return self.root_inode.clone();
}
fn info(&self) -> FsInfo {
return FsInfo {
blk_dev_id: 0,
max_name_len: PROCFS_MAX_NAMELEN,
};
}
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
}
impl ProcFS {
pub fn new() -> Arc<Self> {
// 初始化root inode
let root: Arc<LockedProcFSInode> =
Arc::new(LockedProcFSInode(SpinLock::new(ProcFSInode {
parent: Weak::default(),
self_ref: Weak::default(),
children: BTreeMap::new(),
data: Vec::new(),
metadata: Metadata {
dev_id: 0,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: FileType::Dir,
mode: 0o777,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: 0,
},
fs: Weak::default(),
fdata: InodeInfo {
pid: 0,
ftype: ProcFileType::Default,
},
})));
let result: Arc<ProcFS> = Arc::new(ProcFS { root_inode: root });
// 对root inode加锁并继续完成初始化工作
let mut root_guard: SpinLockGuard<ProcFSInode> = result.root_inode.0.lock();
root_guard.parent = Arc::downgrade(&result.root_inode);
root_guard.self_ref = Arc::downgrade(&result.root_inode);
root_guard.fs = Arc::downgrade(&result);
// 释放锁
drop(root_guard);
return result;
}
/// @brief 进程注册函数
/// @usage 在进程中调用并创建进程对应文件
pub fn register_pid(&self, pid: i64) -> Result<(), i32> {
// 获取当前inode
let proc: Arc<dyn IndexNode> = self.root_inode();
// 创建对应进程文件夹
let _pf: Arc<dyn IndexNode> = proc.create(&pid.to_string(), FileType::Dir, 0o777)?;
// 创建相关文件
// status文件
let binding: Arc<dyn IndexNode> = _pf.create("status", FileType::File, 0o777)?;
let _sf: &LockedProcFSInode = binding
.as_any_ref()
.downcast_ref::<LockedProcFSInode>()
.unwrap();
_sf.0.lock().fdata.pid = pid;
_sf.0.lock().fdata.ftype = ProcFileType::ProcStatus;
//todo: 创建其他文件
return Ok(());
}
/// @brief 解除进程注册
///
pub fn unregister_pid(&self, pid: i64) -> Result<(), i32> {
// 获取当前inode
let proc: Arc<dyn IndexNode> = self.root_inode();
// 获取进程文件夹
let pid_dir: Arc<dyn IndexNode> = proc.find(&format!("{}", pid))?;
// 删除进程文件夹下文件
pid_dir.unlink("status")?;
// 查看进程文件是否还存在
// let pf= pid_dir.find("status").expect("Cannot find status");
// 删除进程文件夹
proc.unlink(&format!("{}", pid))?;
return Ok(());
}
}
impl IndexNode for LockedProcFSInode {
fn open(&self, data: &mut FilePrivateData) -> Result<(), i32> {
// 加锁
let mut inode: SpinLockGuard<ProcFSInode> = self.0.lock();
// 如果inode类型为文件夹则直接返回成功
if let FileType::Dir = inode.metadata.file_type {
return Ok(());
}
let mut private_data = ProcfsFilePrivateData::new();
// 根据文件类型获取相应数据
let file_size = match inode.fdata.ftype {
ProcFileType::ProcStatus => inode.open_status(&mut private_data)?,
_ => {
todo!()
}
};
*data = FilePrivateData::Procfs(private_data);
// 更新metadata里面的文件大小数值
inode.metadata.size = file_size;
return Ok(());
}
fn close(&self, data: &mut FilePrivateData) -> Result<(), i32> {
let guard: SpinLockGuard<ProcFSInode> = self.0.lock();
// 如果inode类型为文件夹则直接返回成功
if let FileType::Dir = guard.metadata.file_type {
return Ok(());
}
// 获取数据信息
let private_data = match data {
FilePrivateData::Procfs(p) => p,
_ => {
panic!("ProcFS: FilePrivateData mismatch!");
}
};
// 释放资源
drop(private_data);
return Ok(());
}
fn read_at(
&self,
offset: usize,
len: usize,
buf: &mut [u8],
data: &mut FilePrivateData,
) -> Result<usize, i32> {
if buf.len() < len {
return Err(-(EINVAL as i32));
}
// 加锁
let inode: SpinLockGuard<ProcFSInode> = self.0.lock();
// 检查当前inode是否为一个文件夹如果是的话就返回错误
if inode.metadata.file_type == FileType::Dir {
return Err(-(EISDIR as i32));
}
// 获取数据信息
let private_data = match data {
FilePrivateData::Procfs(p) => p,
_ => {
panic!("ProcFS: FilePrivateData mismatch!");
}
};
// 根据文件类型读取相应数据
match inode.fdata.ftype {
ProcFileType::ProcStatus => return inode.read_status(offset, len, buf, private_data),
ProcFileType::Default => (),
};
// 默认读取
let start = inode.data.len().min(offset);
let end = inode.data.len().min(offset + len);
// buffer空间不足
if buf.len() < (end - start) {
return Err(-(ENOBUFS as i32));
}
// 拷贝数据
let src = &inode.data[start..end];
buf[0..src.len()].copy_from_slice(src);
return Ok(src.len());
}
fn write_at(
&self,
_offset: usize,
_len: usize,
_buf: &[u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32> {
return Err(-(ENOTSUP as i32));
}
fn poll(&self) -> Result<PollStatus, i32> {
// 加锁
let inode: SpinLockGuard<ProcFSInode> = self.0.lock();
// 检查当前inode是否为一个文件夹如果是的话就返回错误
if inode.metadata.file_type == FileType::Dir {
return Err(-(EISDIR as i32));
}
return Ok(PollStatus {
flags: PollStatus::READ_MASK,
});
}
fn fs(&self) -> Arc<dyn FileSystem> {
return self.0.lock().fs.upgrade().unwrap();
}
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
fn metadata(&self) -> Result<Metadata, i32> {
let inode = self.0.lock();
let metadata = inode.metadata.clone();
return Ok(metadata);
}
fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> {
let mut inode = self.0.lock();
inode.metadata.atime = metadata.atime;
inode.metadata.mtime = metadata.mtime;
inode.metadata.ctime = metadata.ctime;
inode.metadata.mode = metadata.mode;
inode.metadata.uid = metadata.uid;
inode.metadata.gid = metadata.gid;
return Ok(());
}
fn resize(&self, len: usize) -> Result<(), i32> {
let mut inode = self.0.lock();
if inode.metadata.file_type == FileType::File {
inode.data.resize(len, 0);
return Ok(());
} else {
return Err(-(EINVAL as i32));
}
}
fn create_with_data(
&self,
name: &str,
file_type: FileType,
mode: u32,
data: usize,
) -> Result<Arc<dyn IndexNode>, i32> {
// 获取当前inode
let mut inode = self.0.lock();
// 如果当前inode不是文件夹则返回
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 如果有重名的,则返回
if inode.children.contains_key(name) {
return Err(-(EEXIST as i32));
}
// 创建inode
let result: Arc<LockedProcFSInode> =
Arc::new(LockedProcFSInode(SpinLock::new(ProcFSInode {
parent: inode.self_ref.clone(),
self_ref: Weak::default(),
children: BTreeMap::new(),
data: Vec::new(),
metadata: Metadata {
dev_id: 0,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: file_type,
mode: mode,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: data,
},
fs: inode.fs.clone(),
fdata: InodeInfo {
pid: 0,
ftype: ProcFileType::Default,
},
})));
// 初始化inode的自引用的weak指针
result.0.lock().self_ref = Arc::downgrade(&result);
// 将子inode插入父inode的B树中
inode.children.insert(String::from(name), result.clone());
return Ok(result);
}
fn link(&self, name: &str, other: &Arc<dyn IndexNode>) -> Result<(), i32> {
let other: &LockedProcFSInode = other
.downcast_ref::<LockedProcFSInode>()
.ok_or(-(EPERM as i32))?;
let mut inode: SpinLockGuard<ProcFSInode> = self.0.lock();
let mut other_locked: SpinLockGuard<ProcFSInode> = other.0.lock();
// 如果当前inode不是文件夹那么报错
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 如果另一个inode是文件夹那么也报错
if other_locked.metadata.file_type == FileType::Dir {
return Err(-(EISDIR as i32));
}
// 如果当前文件夹下已经有同名文件,也报错。
if inode.children.contains_key(name) {
return Err(-(EEXIST as i32));
}
inode
.children
.insert(String::from(name), other_locked.self_ref.upgrade().unwrap());
// 增加硬链接计数
other_locked.metadata.nlinks += 1;
return Ok(());
}
fn unlink(&self, name: &str) -> Result<(), i32> {
let mut inode: SpinLockGuard<ProcFSInode> = self.0.lock();
// 如果当前inode不是目录那么也没有子目录/文件的概念了因此要求当前inode的类型是目录
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 不允许删除当前文件夹,也不允许删除上一个目录
if name == "." || name == ".." {
return Err(-(ENOTEMPTY as i32));
}
// 获得要删除的文件的inode
let to_delete = inode.children.get(name).ok_or(-(ENOENT as i32))?;
// 减少硬链接计数
to_delete.0.lock().metadata.nlinks -= 1;
// 在当前目录中删除这个子目录项
inode.children.remove(name);
return Ok(());
}
fn move_(
&self,
_old_name: &str,
_target: &Arc<dyn IndexNode>,
_new_name: &str,
) -> Result<(), i32> {
return Err(-(ENOTSUP as i32));
}
fn find(&self, name: &str) -> Result<Arc<dyn IndexNode>, i32> {
let inode = self.0.lock();
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
match name {
"" | "." => {
return Ok(inode.self_ref.upgrade().ok_or(-(ENOENT as i32))?);
}
".." => {
return Ok(inode.parent.upgrade().ok_or(-(ENOENT as i32))?);
}
name => {
// 在子目录项中查找
return Ok(inode.children.get(name).ok_or(-(ENOENT as i32))?.clone());
}
}
}
fn get_entry_name(&self, ino: InodeId) -> Result<String, i32> {
let inode: SpinLockGuard<ProcFSInode> = self.0.lock();
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
match ino {
0 => {
return Ok(String::from("."));
}
1 => {
return Ok(String::from(".."));
}
ino => {
// 暴力遍历所有的children判断inode id是否相同
// TODO: 优化这里,这个地方性能很差!
let mut key: Vec<String> = inode
.children
.keys()
.filter(|k| inode.children.get(*k).unwrap().0.lock().metadata.inode_id == ino)
.cloned()
.collect();
match key.len() {
0=>{return Err(-(ENOENT as i32));}
1=>{return Ok(key.remove(0));}
_ => panic!("Procfs get_entry_name: key.len()={key_len}>1, current inode_id={inode_id}, to find={to_find}", key_len=key.len(), inode_id = inode.metadata.inode_id, to_find=ino)
}
}
}
}
fn list(&self) -> Result<Vec<String>, i32> {
let info = self.metadata()?;
if info.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
let mut keys: Vec<String> = Vec::new();
keys.push(String::from("."));
keys.push(String::from(".."));
keys.append(&mut self.0.lock().children.keys().cloned().collect());
return Ok(keys);
}
}
#[no_mangle]
pub extern "C" fn rs_procfs_register_pid(pid: pid_t) -> u64 {
let r = procfs_register_pid(pid);
if r.is_ok() {
return 0;
} else {
return r.unwrap_err() as u64;
}
}
/// @brief 向procfs注册进程
pub fn procfs_register_pid(pid: pid_t) -> Result<(), i32> {
let procfs_inode = ROOT_INODE().find("proc")?;
let procfs_inode = procfs_inode
.downcast_ref::<LockedProcFSInode>()
.expect("Failed to find procfs' root inode");
let fs = procfs_inode.fs();
let procfs: &ProcFS = fs.as_any_ref().downcast_ref::<ProcFS>().unwrap();
// 调用注册函数
procfs.register_pid(pid)?;
return Ok(());
}
#[no_mangle]
pub extern "C" fn rs_procfs_unregister_pid(pid: pid_t) -> u64 {
let r = procfs_unregister_pid(pid);
if r.is_ok() {
return 0;
} else {
return r.unwrap_err() as u64;
}
}
/// @brief 在ProcFS中,解除进程的注册
pub fn procfs_unregister_pid(pid: pid_t) -> Result<(), i32> {
// 获取procfs实例
let procfs_inode: Arc<dyn IndexNode> = ROOT_INODE().find("proc")?;
let procfs_inode: &LockedProcFSInode = procfs_inode
.downcast_ref::<LockedProcFSInode>()
.expect("Failed to find procfs' root inode");
let fs: Arc<dyn FileSystem> = procfs_inode.fs();
let procfs: &ProcFS = fs.as_any_ref().downcast_ref::<ProcFS>().unwrap();
// 调用解除注册函数
return procfs.unregister_pid(pid);
}

View File

@ -1,505 +0,0 @@
#include "procfs.h"
//定义文件类型
#define PROC_STATUS 1
//定义buffer大小
#define FDATA_RBUF_SIZE 1024
struct vfs_super_block_operations_t procfs_sb_ops;
struct vfs_dir_entry_operations_t procfs_dentry_ops;
struct vfs_file_operations_t procfs_file_ops;
struct vfs_inode_operations_t procfs_inode_ops;
struct vfs_superblock_t procfs_sb = {0};
struct vfs_dir_entry_t *procfs_root_dentry; // 根结点的dentry
static spinlock_t procfs_global_lock; // procfs的全局锁
const char __procfs_mount_path[] = "/proc"; // 挂在路径
static int64_t proc_create_file(const char *path, mode_t type, long pid);
static int __check_name_available(const char *name, int namelen, int8_t reserved);
static long simple_procfs_read(void *to, int64_t count, long *position, void *from, int64_t available);
/**
* @brief 文件的私有信息结构
*
*/
struct procfs_file_private_data
{
int readlen;
char *rbuffer;
int writelen;
char *wbuffer;
};
/**
* @brief 创建procfs的super block
*
* @param blk 未使用procfs为伪文件系统不需要物理设备
* @return struct vfs_superblock_t*
*/
struct vfs_superblock_t *procfs_read_superblock(struct block_device *blk)
{
procfs_sb.blk_device = NULL;
procfs_sb.root = procfs_root_dentry;
procfs_sb.sb_ops = &procfs_sb_ops;
procfs_sb.dir_ops = &procfs_dentry_ops;
procfs_sb.private_sb_info = NULL;
kdebug("procfs read superblock done");
return &procfs_sb;
}
static void procfs_write_superblock(struct vfs_superblock_t *sb)
{
return;
}
static void procfs_put_superblock(struct vfs_superblock_t *sb)
{
return;
}
static void procfs_write_inode(struct vfs_index_node_t *inode)
{
return;
}
struct vfs_super_block_operations_t procfs_sb_ops = {
.write_superblock = &procfs_write_superblock,
.put_superblock = &procfs_put_superblock,
.write_inode = &procfs_write_inode,
};
static long procfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename)
{
return 0;
}
static long procfs_hash(struct vfs_dir_entry_t *dEntry, char *filename)
{
return 0;
}
static long procfs_release(struct vfs_dir_entry_t *dEntry)
{
return 0;
}
static long procfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode)
{
return 0;
}
struct vfs_dir_entry_operations_t procfs_dentry_ops = {
.compare = &procfs_compare,
.hash = &procfs_hash,
.release = &procfs_release,
.iput = &procfs_iput,
};
void data_puts(struct procfs_file_private_data *fdata, const char *s)
{
int len = strlen(s);
if(fdata->readlen+len > FDATA_RBUF_SIZE)
{
kerror("out of buffer");
return;
}
strncpy(fdata->rbuffer + fdata->readlen, s, len);
fdata->readlen += len;
}
static long procfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr)
{
if (inode->attribute & VFS_IF_DIR)
{
return 0;
}
struct procfs_inode_info_t *finode = inode->private_inode_info;
if (finode == NULL)
{
return 0;
}
// kdebug("finode=%#018lx", finode);
struct procfs_file_private_data *fdata = kzalloc(sizeof(struct procfs_file_private_data), 0);
struct process_control_block *pcb_t = process_find_pcb_by_pid(finode->pid);
//判断文件类型
int mode = finode->type;
fdata->rbuffer = kzalloc(FDATA_RBUF_SIZE, 0);
int len = 0;
switch (mode)
{
case 1:
data_puts(fdata, "Name:\t");
data_puts(fdata, pcb_t->name);
data_puts(fdata, "\nstate:\t");
data_puts(fdata, ltoa(pcb_t->state));
data_puts(fdata, "\npid:\t");
data_puts(fdata, ltoa(pcb_t->pid));
data_puts(fdata, "\nPpid:\t");
data_puts(fdata, ltoa(pcb_t->parent_pcb->pid));
data_puts(fdata, "\ncpu_id:\t");
data_puts(fdata, ltoa(pcb_t->cpu_id));
data_puts(fdata, "\npriority:\t");
data_puts(fdata, ltoa(pcb_t->priority));
data_puts(fdata, "\npreempt:\t");
data_puts(fdata, ltoa(pcb_t->preempt_count));
data_puts(fdata, "\nvrtime:\t");
data_puts(fdata, ltoa(pcb_t->virtual_runtime));
// data_puts(fdata,"\n");
uint64_t hiwater_vm, text, data;
hiwater_vm = pcb_t->mm->vmas->vm_end - pcb_t->mm->vmas->vm_start;
text = pcb_t->mm->code_addr_end - pcb_t->mm->code_addr_start;
data = pcb_t->mm->data_addr_end - pcb_t->mm->data_addr_start;
data_puts(fdata, "\nVmPeak:");
data_puts(fdata, ltoa(hiwater_vm));
data_puts(fdata, " kB");
data_puts(fdata, "\nVmData:");
data_puts(fdata, ltoa(data));
data_puts(fdata, " kB");
data_puts(fdata, "\nVmExe:");
data_puts(fdata, ltoa(text));
data_puts(fdata, " kB\n");
break;
default:
break;
}
inode->file_size = fdata->readlen;
file_ptr->private_data = fdata;
return 0;
}
static long procfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr)
{
return 0;
}
static long procfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position)
{
// 获取私有信息
struct procfs_file_private_data *priv = (struct procfs_file_private_data *)file_ptr->private_data;
// kdebug("priv=%#018lx", priv);
if (!priv->rbuffer)
return -EINVAL;
return simple_procfs_read(buf, count, position, priv->rbuffer, priv->readlen);
}
/**
* @brief 检查读取并将数据从内核拷贝到用户
*
* @param to: 要读取的用户空间缓冲区
* @param count: 要读取的最大字节数
* @param position: 缓冲区中的当前位置
* @param from: 要读取的缓冲区
* @param available: 读取的缓冲区大小
*
* @return long 读取字节数
*/
static long simple_procfs_read(void *to, int64_t count, long *position, void *from, int64_t available)
{
long pos = *position;
// kdebug("pos:%ld",pos);
// kdebug("count:%ld",count);
// kdebug("available:%ld",available);
int64_t ret = 0;
if (pos < 0)
return -EINVAL;
if (pos >= available || !count)
return 0;
if (count > available - pos)
count = available - pos;
// kdebug("count:%d",count);
ret = copy_to_user(to, from + pos, count);
*position = pos + ret;
return ret;
}
static long procfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position)
{
return 0;
}
/**
* @brief 调整文件的访问位置
*
* @param file_ptr 文件描述符号
* @param offset 偏移量
* @param whence 调整模式
* @return uint64_t 调整结束后的文件访问位置
*/
static long procfs_lseek(struct vfs_file_t *file_ptr, long offset, long whence)
{
struct vfs_index_node_t *inode = file_ptr->dEntry->dir_inode;
long pos = 0;
switch (whence)
{
case SEEK_SET: // 相对于文件头
pos = offset;
break;
case SEEK_CUR: // 相对于当前位置
pos = file_ptr->position + offset;
break;
case SEEK_END: // 相对于文件末尾
pos = file_ptr->dEntry->dir_inode->file_size + offset;
break;
default:
return -EINVAL;
break;
}
if (pos < 0 || pos > file_ptr->dEntry->dir_inode->file_size)
return -EOVERFLOW;
file_ptr->position = pos;
return pos;
}
static long procfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg)
{
return 0;
}
/**
* @brief 读取该目录下的目录项
*
* @param file_ptr 文件结构体的指针
* @param dirent 返回的dirent
* @param filler 填充dirent的函数
*
* @return long 错误码
*/
static long procfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler)
{
struct vfs_dir_entry_t *dentry = file_ptr->dEntry;
struct List *list = &dentry->subdirs_list;
// 先切换到position处
for (int i = 0; i <= file_ptr->position; ++i)
{
list = list_next(list);
if (list == &dentry->subdirs_list) // 找完了
goto failed;
}
// 若存在目录项,则增加偏移量
++file_ptr->position;
// 获取目标dentry由于是子目录项因此是child_node_list
struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list);
char *name = (char *)kzalloc(target_dent->name_length + 1, 0);
strncpy(name, target_dent->name, target_dent->name_length);
uint32_t dentry_type;
if (target_dent->dir_inode->attribute & VFS_IF_DIR)
dentry_type = VFS_IF_DIR;
else
dentry_type = VFS_IF_FILE;
return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1);
failed:;
return 0;
}
struct vfs_file_operations_t procfs_file_ops = {
.open = &procfs_open,
.close = &procfs_close,
.read = &procfs_read,
.write = &procfs_write,
.lseek = &procfs_lseek,
.ioctl = &procfs_ioctl,
.readdir = &procfs_readdir,
};
/**
* @brief 检查文件名是否合法
*
* @param name 文件名
* @param namelen 文件名长度
* @param reserved 保留字段
* @return int 合法0 其他:错误码
*/
static int __check_name_available(const char *name, int namelen, int8_t reserved)
{
if (namelen > 255 || namelen <= 0)
return -ENAMETOOLONG;
// 首个字符不能是空格或者'.'
if (name[0] == 0x20 || name[0] == '.')
return -EINVAL;
return 0;
};
/**
* @brief 在procfs中创建文件
*
* @param parent_inode 父目录的inode
* @param dest_dEntry 目标dentry
* @param mode 创建模式
* @return long 错误码
*/
static long procfs_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode)
{
int64_t retval = 0;
//检验名称和法性
retval = __check_name_available(dest_dEntry->name, dest_dEntry->name_length, 0);
if (retval != 0)
return retval;
if (dest_dEntry->dir_inode != NULL)
return -EEXIST;
struct vfs_index_node_t *inode = vfs_alloc_inode();
dest_dEntry->dir_inode = inode;
dest_dEntry->dir_ops = &procfs_dentry_ops;
inode->attribute = VFS_IF_FILE;
inode->file_ops = &procfs_file_ops;
inode->file_size = 0;
inode->sb = parent_inode->sb;
inode->inode_ops = &procfs_inode_ops;
// kdebug("finode:%#018lx",inode->private_inode_info);
inode->blocks = 0;
return 0;
}
static struct vfs_dir_entry_t *procfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry)
{
return NULL;
}
/**
* @brief 在procfs中创建文件夹(作用是完善子文件夹的inode信息)
*
* @param inode 父目录的inode
* @param dEntry 目标dentry
* @param mode 创建模式
* @return long 错误码
*/
static long procfs_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dEntry, int mode)
{
int64_t retval = 0;
//检验名称和法性
retval = __check_name_available(dEntry->name, dEntry->name_length, 0);
if (retval != 0)
return retval;
struct vfs_index_node_t *inode = vfs_alloc_inode();
dEntry->dir_inode = inode;
dEntry->dir_ops = &procfs_dentry_ops;
//结点信息初始化
struct procfs_inode_info_t *finode = (struct procfs_inode_info_t *)kzalloc(sizeof(struct procfs_inode_info_t), 0);
finode->pid = 0;
finode->type = 0;
inode->attribute = VFS_IF_DIR;
inode->file_ops = &procfs_file_ops;
inode->file_size = 0;
inode->sb = parent_inode->sb;
inode->inode_ops = &procfs_inode_ops;
inode->private_inode_info = (void *)finode;
// kdebug("inode->private_inode_info=%#018lx", inode->private_inode_info);
inode->blocks = 0;
return 0;
}
struct vfs_inode_operations_t procfs_inode_ops = {
.create = &procfs_create,
.lookup = &procfs_lookup,
.mkdir = &procfs_mkdir,
};
struct vfs_filesystem_type_t procfs_fs_type = {
.name = "procfs",
.fs_flags = 0,
.read_superblock = procfs_read_superblock,
.next = NULL,
};
static __always_inline void __procfs_init_root_inode()
{
procfs_root_dentry->dir_inode = vfs_alloc_inode();
procfs_root_dentry->dir_inode->file_ops = &procfs_file_ops;
procfs_root_dentry->dir_inode->inode_ops = &procfs_inode_ops;
procfs_root_dentry->dir_inode->private_inode_info = NULL;
procfs_root_dentry->dir_inode->sb = &procfs_sb;
procfs_root_dentry->dir_inode->attribute = VFS_IF_DIR;
}
/**
* @brief 初始化procfs的根dentry
*/
static __always_inline void __procfs_init_root_dentry()
{
procfs_root_dentry = vfs_alloc_dentry(0);
procfs_root_dentry->dir_ops = &procfs_dentry_ops;
__procfs_init_root_inode();
}
/**
* @brief 创建进程对应文件夹
*
* @param pid 进程号
* @return int64_t 错误码
*/
int64_t procfs_register_pid(long pid)
{
int retval = 0;
//创建文件夹
char tmp[70] = {0};
int len = strlen(ltoa(pid));
// kdebug("len:%d",len);
strcpy(tmp, "/proc/");
strcpy(tmp + 6, ltoa(pid));
// kdebug("tmp:%s",tmp);
retval = vfs_mkdir(tmp, 0, false);
// kdebug("aaaaaaaaaaaaaaa");
//创建各相关文件
strcpy(tmp + 6 + len, "/status");
// kdebug("tmp:%s",tmp);
retval = proc_create_file(tmp, PROC_STATUS, pid);
return retval;
}
/**
* @brief 创建文件
*
* @param path 文件夹路径
* @param type 文件类型
* @param pid pid
* @return int64_t 错误码
*/
static int64_t proc_create_file(const char *path, mode_t type, long pid)
{
kdebug("procfs: Creating: %s", path);
int ret = do_open(path, O_CREAT, false);
// kdebug("ret:%d", ret);
struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0);
// kdebug("dentry=%#018lx", dentry);
//结点信息配置
struct procfs_inode_info_t *finode = (struct procfs_inode_info_t *)kzalloc(sizeof(struct procfs_inode_info_t), 0);
finode->pid = pid;
// kdebug("pid:%d",finode->pid);
finode->type = type;
dentry->dir_inode->private_inode_info = (void *)finode;
ret = vfs_close(ret);
return ret;
}
/**
* @brief 初始化procfs
*
*/
void procfs_init()
{
__procfs_init_root_dentry();
vfs_register_filesystem(&procfs_fs_type);
spin_init(&procfs_global_lock);
vfs_mount_fs(__procfs_mount_path, "procfs", NULL);
}

View File

@ -1,43 +0,0 @@
#pragma once
#include <common/list.h>
#include <common/lockref.h>
#include <common/spinlock.h>
#include <common/stdio.h>
#include <common/stdlib.h>
#include <common/string.h>
#include <filesystem/vfs/VFS.h>
#include <process/process.h>
/**
* @brief 初始化procfs
*
*/
void procfs_init();
/**
* @brief proc文件系统的超级块信息结构体
*
*/
struct procfs_sb_info_t
{
struct lockref lockref; //该lockref包含自旋锁以及引用计数
};
/**
* @brief procfs文件系统的结点私有信息
*
*/
struct procfs_inode_info_t
{
long pid;
int type;
};
/**
* @brief 创建进程对应文件
*
* @param pid 进程号
* @return int64_t 错误码
*/
int64_t procfs_register_pid(long pid);

View File

@ -0,0 +1,444 @@
use core::any::Any;
use alloc::{
collections::BTreeMap,
string::String,
sync::{Arc, Weak},
vec::Vec,
};
use crate::{
filesystem::vfs::{core::generate_inode_id, FileType},
include::bindings::bindings::{
EEXIST, EINVAL, EISDIR, ENOBUFS, ENOENT, ENOTDIR, ENOTEMPTY, EPERM,
},
libs::spinlock::{SpinLock, SpinLockGuard},
time::TimeSpec,
};
use super::vfs::{
file::FilePrivateData, FileSystem, FsInfo, IndexNode, InodeId, Metadata, PollStatus,
};
/// RamFS的inode名称的最大长度
const RAMFS_MAX_NAMELEN: usize = 64;
/// @brief 内存文件系统的Inode结构体
#[derive(Debug)]
struct LockedRamFSInode(SpinLock<RamFSInode>);
/// @brief 内存文件系统结构体
#[derive(Debug)]
pub struct RamFS {
/// RamFS的root inode
root_inode: Arc<LockedRamFSInode>,
}
/// @brief 内存文件系统的Inode结构体(不包含锁)
#[derive(Debug)]
pub struct RamFSInode {
// parent变量目前只在find函数中使用到
// 所以只有当inode是文件夹的时候parent才会生效
// 对于文件来说parent就没什么作用了
// 关于parent的说明: 目录不允许有硬链接
/// 指向父Inode的弱引用
parent: Weak<LockedRamFSInode>,
/// 指向自身的弱引用
self_ref: Weak<LockedRamFSInode>,
/// 子Inode的B树
children: BTreeMap<String, Arc<LockedRamFSInode>>,
/// 当前inode的数据部分
data: Vec<u8>,
/// 当前inode的元数据
metadata: Metadata,
/// 指向inode所在的文件系统对象的指针
fs: Weak<RamFS>,
}
impl FileSystem for RamFS {
fn root_inode(&self) -> Arc<dyn super::vfs::IndexNode> {
return self.root_inode.clone();
}
fn info(&self) -> FsInfo {
return FsInfo {
blk_dev_id: 0,
max_name_len: RAMFS_MAX_NAMELEN,
};
}
/// @brief 本函数用于实现动态转换。
/// 具体的文件系统在实现本函数时最简单的方式就是直接返回self
fn as_any_ref(&self) -> &dyn Any {
self
}
}
impl RamFS {
pub fn new() -> Arc<Self> {
// 初始化root inode
let root: Arc<LockedRamFSInode> = Arc::new(LockedRamFSInode(SpinLock::new(RamFSInode {
parent: Weak::default(),
self_ref: Weak::default(),
children: BTreeMap::new(),
data: Vec::new(),
metadata: Metadata {
dev_id: 0,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: FileType::Dir,
mode: 0o777,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: 0,
},
fs: Weak::default(),
})));
let result: Arc<RamFS> = Arc::new(RamFS { root_inode: root });
// 对root inode加锁并继续完成初始化工作
let mut root_guard: SpinLockGuard<RamFSInode> = result.root_inode.0.lock();
root_guard.parent = Arc::downgrade(&result.root_inode);
root_guard.self_ref = Arc::downgrade(&result.root_inode);
root_guard.fs = Arc::downgrade(&result);
// 释放锁
drop(root_guard);
return result;
}
}
impl IndexNode for LockedRamFSInode {
fn read_at(
&self,
offset: usize,
len: usize,
buf: &mut [u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32> {
if buf.len() < len {
return Err(-(EINVAL as i32));
}
// 加锁
let inode: SpinLockGuard<RamFSInode> = self.0.lock();
// 检查当前inode是否为一个文件夹如果是的话就返回错误
if inode.metadata.file_type == FileType::Dir {
return Err(-(EISDIR as i32));
}
let start = inode.data.len().min(offset);
let end = inode.data.len().min(offset + len);
// buffer空间不足
if buf.len() < (end - start) {
return Err(-(ENOBUFS as i32));
}
// 拷贝数据
let src = &inode.data[start..end];
buf[0..src.len()].copy_from_slice(src);
return Ok(src.len());
}
fn write_at(
&self,
offset: usize,
len: usize,
buf: &[u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32> {
if buf.len() < len {
return Err(-(EINVAL as i32));
}
// 加锁
let mut inode: SpinLockGuard<RamFSInode> = self.0.lock();
// 检查当前inode是否为一个文件夹如果是的话就返回错误
if inode.metadata.file_type == FileType::Dir {
return Err(-(EISDIR as i32));
}
let data: &mut Vec<u8> = &mut inode.data;
// 如果文件大小比原来的大那就resize这个数组
if offset + len > data.len() {
data.resize(offset + len, 0);
}
let target = &mut data[offset..offset + len];
target.copy_from_slice(&buf[0..len]);
return Ok(len);
}
fn poll(&self) -> Result<PollStatus, i32> {
// 加锁
let inode: SpinLockGuard<RamFSInode> = self.0.lock();
// 检查当前inode是否为一个文件夹如果是的话就返回错误
if inode.metadata.file_type == FileType::Dir {
return Err(-(EISDIR as i32));
}
return Ok(PollStatus {
flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK,
});
}
fn fs(&self) -> Arc<dyn FileSystem> {
return self.0.lock().fs.upgrade().unwrap();
}
fn as_any_ref(&self) -> &dyn core::any::Any {
self
}
fn metadata(&self) -> Result<Metadata, i32> {
let inode = self.0.lock();
let mut metadata = inode.metadata.clone();
metadata.size = inode.data.len() as i64;
return Ok(metadata);
}
fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> {
let mut inode = self.0.lock();
inode.metadata.atime = metadata.atime;
inode.metadata.mtime = metadata.mtime;
inode.metadata.ctime = metadata.ctime;
inode.metadata.mode = metadata.mode;
inode.metadata.uid = metadata.uid;
inode.metadata.gid = metadata.gid;
return Ok(());
}
fn resize(&self, len: usize) -> Result<(), i32> {
let mut inode = self.0.lock();
if inode.metadata.file_type == FileType::File {
inode.data.resize(len, 0);
return Ok(());
} else {
return Err(-(EINVAL as i32));
}
}
fn create_with_data(
&self,
name: &str,
file_type: FileType,
mode: u32,
data: usize,
) -> Result<Arc<dyn IndexNode>, i32> {
// 获取当前inode
let mut inode = self.0.lock();
// 如果当前inode不是文件夹则返回
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 如果有重名的,则返回
if inode.children.contains_key(name) {
return Err(-(EEXIST as i32));
}
// 创建inode
let result: Arc<LockedRamFSInode> = Arc::new(LockedRamFSInode(SpinLock::new(RamFSInode {
parent: inode.self_ref.clone(),
self_ref: Weak::default(),
children: BTreeMap::new(),
data: Vec::new(),
metadata: Metadata {
dev_id: 0,
inode_id: generate_inode_id(),
size: 0,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
file_type: file_type,
mode: mode,
nlinks: 1,
uid: 0,
gid: 0,
raw_dev: data,
},
fs: inode.fs.clone(),
})));
// 初始化inode的自引用的weak指针
result.0.lock().self_ref = Arc::downgrade(&result);
// 将子inode插入父inode的B树中
inode.children.insert(String::from(name), result.clone());
return Ok(result);
}
fn link(&self, name: &str, other: &Arc<dyn IndexNode>) -> Result<(), i32> {
let other: &LockedRamFSInode = other
.downcast_ref::<LockedRamFSInode>()
.ok_or(-(EPERM as i32))?;
let mut inode: SpinLockGuard<RamFSInode> = self.0.lock();
let mut other_locked: SpinLockGuard<RamFSInode> = other.0.lock();
// 如果当前inode不是文件夹那么报错
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 如果另一个inode是文件夹那么也报错
if other_locked.metadata.file_type == FileType::Dir {
return Err(-(EISDIR as i32));
}
// 如果当前文件夹下已经有同名文件,也报错。
if inode.children.contains_key(name) {
return Err(-(EEXIST as i32));
}
inode
.children
.insert(String::from(name), other_locked.self_ref.upgrade().unwrap());
// 增加硬链接计数
other_locked.metadata.nlinks += 1;
return Ok(());
}
fn unlink(&self, name: &str) -> Result<(), i32> {
let mut inode: SpinLockGuard<RamFSInode> = self.0.lock();
// 如果当前inode不是目录那么也没有子目录/文件的概念了因此要求当前inode的类型是目录
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 不允许删除当前文件夹,也不允许删除上一个目录
if name == "." || name == ".." {
return Err(-(ENOTEMPTY as i32));
}
// 获得要删除的文件的inode
let to_delete = inode.children.get(name).ok_or(-(ENOENT as i32))?;
if to_delete.0.lock().metadata.file_type == FileType::Dir {
return Err(-(EPERM as i32));
}
// 减少硬链接计数
to_delete.0.lock().metadata.nlinks -= 1;
// 在当前目录中删除这个子目录项
inode.children.remove(name);
return Ok(());
}
fn rmdir(&self, name: &str) -> Result<(), i32> {
let mut inode: SpinLockGuard<RamFSInode> = self.0.lock();
// 如果当前inode不是目录那么也没有子目录/文件的概念了因此要求当前inode的类型是目录
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 获得要删除的文件夹的inode
let to_delete = inode.children.get(name).ok_or(-(ENOENT as i32))?;
if to_delete.0.lock().metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
to_delete.0.lock().metadata.nlinks -= 1;
// 在当前目录中删除这个子目录项
inode.children.remove(name);
return Ok(());
}
fn move_(
&self,
old_name: &str,
target: &Arc<dyn IndexNode>,
new_name: &str,
) -> Result<(), i32> {
let old_inode: Arc<dyn IndexNode> = self.find(old_name)?;
// 在新的目录下创建一个硬链接
target.link(new_name, &old_inode)?;
// 取消现有的目录下的这个硬链接
if let Err(err) = self.unlink(old_name) {
// 如果取消失败,那就取消新的目录下的硬链接
target.unlink(new_name)?;
return Err(err);
}
return Ok(());
}
fn find(&self, name: &str) -> Result<Arc<dyn IndexNode>, i32> {
let inode = self.0.lock();
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
match name {
"" | "." => {
return Ok(inode.self_ref.upgrade().ok_or(-(ENOENT as i32))?);
}
".." => {
return Ok(inode.parent.upgrade().ok_or(-(ENOENT as i32))?);
}
name => {
// 在子目录项中查找
return Ok(inode.children.get(name).ok_or(-(ENOENT as i32))?.clone());
}
}
}
fn get_entry_name(&self, ino: InodeId) -> Result<String, i32> {
let inode: SpinLockGuard<RamFSInode> = self.0.lock();
if inode.metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
match ino {
0 => {
return Ok(String::from("."));
}
1 => {
return Ok(String::from(".."));
}
ino => {
// 暴力遍历所有的children判断inode id是否相同
// TODO: 优化这里,这个地方性能很差!
let mut key: Vec<String> = inode
.children
.keys()
.filter(|k| inode.children.get(*k).unwrap().0.lock().metadata.inode_id == ino)
.cloned()
.collect();
match key.len() {
0=>{return Err(-(ENOENT as i32));}
1=>{return Ok(key.remove(0));}
_ => panic!("Ramfs get_entry_name: key.len()={key_len}>1, current inode_id={inode_id}, to find={to_find}", key_len=key.len(), inode_id = inode.metadata.inode_id, to_find=ino)
}
}
}
}
fn list(&self) -> Result<Vec<String>, i32> {
let info = self.metadata()?;
if info.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
let mut keys: Vec<String> = Vec::new();
keys.push(String::from("."));
keys.push(String::from(".."));
keys.append(&mut self.0.lock().children.keys().cloned().collect());
return Ok(keys);
}
}

View File

@ -1,17 +0,0 @@
CFLAGS += -I .
kernel_fs_rootfs_objs:= $(shell find ./*.c)
ECHO:
@echo "$@"
$(kernel_fs_rootfs_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_fs_rootfs_objs)

View File

@ -1 +0,0 @@

View File

@ -1,228 +0,0 @@
#include "rootfs.h"
#include <filesystem/vfs/VFS.h>
#include <common/string.h>
#include <filesystem/vfs/mount.h>
static struct vfs_superblock_t rootfs_sb = {0};
extern struct vfs_superblock_t *vfs_root_sb;
/**
* @brief 释放dentry本身所占的内存
*
* @param dentry
*/
static inline void __release_dentry(struct vfs_dir_entry_t *dentry)
{
kfree(dentry->name);
kfree(dentry);
}
struct vfs_super_block_operations_t rootfs_sb_ops = {
.put_superblock = NULL,
.write_inode = NULL,
.write_superblock = NULL,
};
static struct vfs_dir_entry_t *rootfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry)
{
return NULL;
}
struct vfs_inode_operations_t rootfs_inode_ops = {
.create = NULL,
.getAttr = NULL,
.lookup = NULL,
.lookup = &rootfs_lookup,
.mkdir = NULL,
.rename = NULL,
.rmdir = NULL,
.setAttr = NULL,
};
static long rootfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr)
{
return 0;
}
static long rootfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) { return 0; }
static long rootfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; }
static long rootfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; }
static long rootfs_lseek(struct vfs_file_t *file_ptr, long offset, long origin) { return 0; }
static long rootfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) { return 0; }
static long rootfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler)
{
// 循环读取目录下的目录项
struct vfs_dir_entry_t *dentry = file_ptr->dEntry;
struct List *list = &dentry->subdirs_list;
// 先切换到position处
for (int i = 0; i <= file_ptr->position; ++i)
{
list = list_next(list);
if (list == &dentry->subdirs_list) // 找完了
goto failed;
}
// 存在目录项
// 增加偏移量
++file_ptr->position;
// 获取目标dentry由于是子目录项因此是child_node_list
struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list);
// kdebug("target name=%s, namelen=%d", target_dent->name, target_dent->name_length);
char *name = (char *)kzalloc(target_dent->name_length + 1, 0);
strncpy(name, target_dent->name, target_dent->name_length);
uint32_t dentry_type = target_dent->dir_inode->attribute;
return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1);
failed:;
return 0;
}
static long rootfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) { return 0; }
static long rootfs_hash(struct vfs_dir_entry_t *dEntry, char *filename) { return 0; }
static long rootfs_release(struct vfs_dir_entry_t *dEntry) { return 0; }
static long rootfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) { return 0; }
struct vfs_dir_entry_operations_t rootfs_dentry_ops =
{
.compare = &rootfs_compare,
.hash = &rootfs_hash,
.release = &rootfs_release,
.iput = &rootfs_iput,
};
struct vfs_file_operations_t rootfs_file_ops = {
.open = &rootfs_open,
.close = &rootfs_close,
.read = &rootfs_read,
.write = &rootfs_write,
.lseek = &rootfs_lseek,
.ioctl = &rootfs_ioctl,
.readdir = &rootfs_readdir,
};
/**
* @brief 为在rootfs下创建目录仅仅是形式上的目录为了支持文件系统挂载
*
* @param name 目录名称
* @return int
*/
static int rootfs_add_dir(const char *name)
{
{
// 检查名称重复
struct List *list = &rootfs_sb.root->subdirs_list;
while (list_next(list) != &rootfs_sb.root->subdirs_list)
{
list = list_next(list);
struct vfs_dir_entry_t *tmp = container_of(list, struct vfs_dir_entry_t, child_node_list);
if (strcmp(tmp->name, name) == 0)
return -EEXIST;
}
}
struct vfs_dir_entry_t *dentry = vfs_alloc_dentry(strlen(name) + 1);
strcpy(dentry->name, name);
dentry->name_length = strlen(name);
dentry->parent = rootfs_sb.root;
list_append(&rootfs_sb.root->subdirs_list, &dentry->child_node_list);
return 0;
}
void rootfs_init()
{
// 初始化超级块
rootfs_sb.blk_device = NULL;
rootfs_sb.private_sb_info = NULL;
rootfs_sb.sb_ops = &rootfs_sb_ops;
rootfs_sb.dir_ops = &rootfs_dentry_ops;
// 初始化dentry
rootfs_sb.root = vfs_alloc_dentry(sizeof("/"));
struct vfs_dir_entry_t *dentry = rootfs_sb.root;
strncpy(dentry->name, "/", 2);
dentry->name_length = 1;
dentry->parent = dentry;
// 初始化root inode
dentry->dir_inode = vfs_alloc_inode();
dentry->dir_inode->sb = &rootfs_sb;
dentry->dir_inode->inode_ops = &rootfs_inode_ops;
dentry->dir_inode->file_ops = &rootfs_file_ops;
dentry->dir_inode->attribute = VFS_IF_DIR;
// 直接将vfs的根superblock设置为rootfs的超级块
vfs_root_sb = &rootfs_sb;
// 创建/dev等目录的dentry以便文件系统的mount
if (rootfs_add_dir("dev") != 0)
kerror("create dir 'dev' in rootfs failed");
// 创建/procfs目录的dentry
if (rootfs_add_dir("proc") != 0)
kerror("create dir 'proc' in rootfs failed");
}
/**
* @brief 当新的根文件系统被挂载后将原有的挂载在rootfs下的文件系统迁移到新的根文件系统上
*
*/
static void rootfs_migrate()
{
kdebug("Migrating rootfs's dentries...");
struct List *list = &rootfs_sb.root->subdirs_list;
if (unlikely(list_empty(list)))
return;
list = list_next(list);
while (list != &rootfs_sb.root->subdirs_list)
{
struct vfs_dir_entry_t *tmp = container_of(list, struct vfs_dir_entry_t, child_node_list);
if (tmp->dir_inode != NULL)
{
list = list_next(list); // 获取下一个列表结点(不然的话下面的几行代码就覆盖掉了正确的值了)
tmp->parent = vfs_root_sb->root;
list_init(&tmp->child_node_list);
list_append(&vfs_root_sb->root->subdirs_list, &tmp->child_node_list);
}
else
{
list = list_next(list); // 不迁移空的dentry直接释放他们
list_del(&tmp->child_node_list);
__release_dentry(tmp);
}
}
}
/**
* @brief 当磁盘文件系统被成功挂载后释放rootfs所占的空间
*
*/
void rootfs_umount()
{
// 将原有的“dev”文件夹等进行迁移
rootfs_migrate();
kinfo("Umounting rootfs...");
// 遍历mount链表删除所有父目录是rootfs的dentry
struct mountpoint *mp = NULL;
while (1)
{
mp = mount_find_mnt_list_by_parent(rootfs_sb.root);
if (mp == NULL)
break;
// 释放dentry由于没有创建inode因此不需要释放
__release_dentry(mp->dentry);
// 释放mountpoint结构体
mount_release_mountpoint(mp);
}
// 释放root dentry及其inode
kfree(rootfs_sb.root->dir_inode);
__release_dentry(rootfs_sb.root);
}

View File

@ -1,9 +0,0 @@
#pragma once
void rootfs_init();
/**
* @brief 当磁盘文件系统被成功挂载后释放rootfs所占的空间
*
*/
void rootfs_umount();

View File

@ -1,17 +0,0 @@
CFLAGS += -I .
kernel_fs_vfs_objs:= $(shell find ./*.c)
ECHO:
@echo "$@"
$(kernel_fs_vfs_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_fs_vfs_objs)

View File

@ -1,898 +0,0 @@
#include "VFS.h"
#include "internal.h"
#include "mount.h"
#include <common/dirent.h>
#include <common/err.h>
#include <common/errno.h>
#include <common/kprint.h>
#include <common/string.h>
#include <debug/bug.h>
#include <filesystem/rootfs/rootfs.h>
#include <mm/mm.h>
#include <mm/slab.h>
#include <process/process.h>
#include <process/ptrace.h>
// 为filesystem_type_t结构体实例化一个链表头
static struct vfs_filesystem_type_t vfs_fs = {"filesystem", 0};
struct vfs_superblock_t *vfs_root_sb = NULL;
struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size);
/**
* @brief 挂载文件系统
*
* @param path 要挂载到的路径
* @param name 文件系统名
* @param blk 块设备结构体
* @return struct vfs_superblock_t* 挂载后,文件系统的超级块
*/
struct vfs_superblock_t *vfs_mount_fs(const char *path, char *name, struct block_device *blk)
{
// 判断挂载点是否存在
struct vfs_dir_entry_t *target_dentry = NULL;
target_dentry = vfs_path_walk(path, 0);
if (target_dentry == NULL)
return NULL;
struct vfs_filesystem_type_t *p = NULL;
for (p = &vfs_fs; p; p = p->next)
{
if (!strcmp(p->name, name)) // 存在符合的文件系统
{
struct vfs_superblock_t *sb = p->read_superblock(blk);
if (strcmp(path, "/") == 0) // 如果挂载到的是'/'挂载点,则让其成为最顶层的文件系统
{
vfs_root_sb = sb;
}
else
{
kdebug("to mount %s", name);
// 调用mount机制挂载文件系统
struct vfs_dir_entry_t *new_dentry = sb->root;
// 注意umount的时候需要释放这些内存
new_dentry->name = kzalloc(target_dentry->name_length + 1, 0);
new_dentry->name_length = target_dentry->name_length;
do_mount(target_dentry, new_dentry);
}
return sb;
}
}
kdebug("unsupported fs: %s", name);
return NULL;
}
/**
* @brief 在VFS中注册文件系统
*
* @param fs 文件系统类型结构体
* @return uint64_t
*/
uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs)
{
struct vfs_filesystem_type_t *p = NULL;
for (p = &vfs_fs; p; p = p->next)
{
if (!strcmp(p->name, fs->name)) // 已经注册相同名称的文件系统
return -EEXIST;
}
fs->next = vfs_fs.next;
vfs_fs.next = fs;
return 0;
}
uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs)
{
struct vfs_filesystem_type_t *p = &vfs_fs;
while (p->next)
{
if (p->next == fs)
{
p->next = p->next->next;
fs->next = NULL;
return 0;
}
else
p = p->next;
}
return -EINVAL;
}
/**
* @brief 在dentry的sub_dir_list中搜索指定名称的dentry
*
* @param dentry 目录项结构体dentry
* @param name 待搜索的dentry名称
* @return struct vfs_dir_entry_t* 目标dentry 无结果则返回NULL
*/
static struct vfs_dir_entry_t *vfs_search_dentry_list(struct vfs_dir_entry_t *dentry, const char *name)
{
if (list_empty(&dentry->subdirs_list))
return NULL;
struct List *ptr = &dentry->subdirs_list;
struct vfs_dir_entry_t *d_ptr = NULL;
do
{
ptr = list_next(ptr);
d_ptr = container_of(ptr, struct vfs_dir_entry_t, child_node_list);
if (strcmp(name, d_ptr->name) == 0)
return d_ptr;
} while (list_next(ptr) != (&dentry->subdirs_list));
return NULL;
}
/**
* @brief 按照路径查找文件
*
* @param path 路径
* @param flags 1返回父目录项 0返回结果目录项
* @return struct vfs_dir_entry_t* 目录项
*/
struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags)
{
struct vfs_dir_entry_t *parent = vfs_root_sb->root;
// 去除路径前的斜杠
while (*path == '/')
++path;
if ((!*path) || (*path == '\0'))
return parent;
struct vfs_dir_entry_t *dentry = NULL;
// kdebug("path before walk:%s", path);
while (true)
{
// 提取出下一级待搜索的目录名或文件名并保存在dEntry_name中
const char *tmp_path = path;
while ((*path && *path != '\0') && (*path != '/'))
++path;
int tmp_path_len = path - tmp_path;
// 搜索是否有dentry缓存
{
char *tmpname = kzalloc(tmp_path_len + 1, 0);
strncpy(tmpname, tmp_path, tmp_path_len);
tmpname[tmp_path_len] = '\0';
// kdebug("tmpname=%s", tmpname);
dentry = vfs_search_dentry_list(parent, tmpname);
kfree(tmpname);
}
// 如果没有找到dentry缓存则申请新的dentry
if (dentry == NULL)
{
dentry = vfs_alloc_dentry(tmp_path_len + 1);
memcpy(dentry->name, (void *)tmp_path, tmp_path_len);
dentry->name[tmp_path_len] = '\0';
// kdebug("tmp_path_len=%d, dentry->name=%s", tmp_path_len, dentry->name);
dentry->name_length = tmp_path_len;
if (parent->dir_inode->inode_ops->lookup(parent->dir_inode, dentry) == NULL)
{
// 搜索失败
// kwarn("cannot find the file/dir : %s", dentry->name);
kfree(dentry->name);
kfree(dentry);
return NULL;
}
// 找到子目录项
dentry->parent = parent;
list_add(&parent->subdirs_list, &dentry->child_node_list);
}
while (*path == '/')
++path;
if ((!*path) || (*path == '\0')) // 已经到达末尾
{
if (flags & 1) // 返回父目录
{
return parent;
}
return dentry;
}
parent = dentry;
}
}
/**
* @brief 填充dentry
*
* @return dirent的总大小
*/
int vfs_fill_dirent(void *buf, ino_t d_ino, char *name, int namelen, unsigned char type, off_t offset)
{
struct dirent *dent = (struct dirent *)buf;
// 如果尝试访问内核空间,则返回错误
if (!(verify_area((uint64_t)buf, sizeof(struct dirent) + namelen)))
return -EFAULT;
// ====== 填充dirent结构体 =====
memset(buf, 0, sizeof(struct dirent) + namelen);
memcpy(dent->d_name, name, namelen);
dent->d_name[namelen] = '\0';
// 暂时不显示目录下的记录数
dent->d_reclen = 0;
dent->d_ino = d_ino;
dent->d_off = offset;
dent->d_type = type;
// 返回dirent的总大小
return sizeof(struct dirent) + namelen;
}
/**
* @brief 创建文件夹
*
* @param path 文件夹路径
* @param mode 创建模式
* @param from_userland 该创建请求是否来自用户态
* @return int64_t 错误码
*/
int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland)
{
uint32_t pathlen;
int retval = 0;
if (from_userland)
pathlen = strnlen_user(path, PAGE_4K_SIZE - 1);
else
pathlen = strnlen(path, PAGE_4K_SIZE - 1);
if (pathlen == 0)
return -ENOENT;
int last_slash = -1;
// 查找最后一个'/',忽略路径末尾的'/'
for (int i = pathlen - 2; i >= 0; --i)
{
if (path[i] == '/')
{
last_slash = i;
break;
}
}
// 路径格式不合法(必须使用绝对路径)
if (last_slash < 0)
return -ENOTDIR;
char *buf = (char *)kzalloc(last_slash + 2, 0);
// 拷贝字符串(不包含要被创建的部分)
if (from_userland)
strncpy_from_user(buf, path, last_slash);
else
strncpy(buf, path, last_slash);
buf[last_slash + 1] = '\0';
// 查找父目录
struct vfs_dir_entry_t *parent_dir = vfs_path_walk(buf, 0);
if (parent_dir == NULL)
{
kwarn("parent dir is NULL.");
kfree(buf);
return -ENOENT;
}
kfree(buf);
// 检查父目录中是否已经有相同的目录项
if (vfs_path_walk((const char *)path, 0) != NULL)
{
// 目录中已有对应的文件夹
kwarn("Dir '%s' aleardy exists.", path);
return -EEXIST;
}
spin_lock(&parent_dir->lockref.lock);
struct vfs_dir_entry_t *subdir_dentry = vfs_alloc_dentry(pathlen - last_slash);
if (path[pathlen - 1] == '/')
subdir_dentry->name_length = pathlen - last_slash - 2;
else
subdir_dentry->name_length = pathlen - last_slash - 1;
for (int i = last_slash + 1, cnt = 0; i < pathlen && cnt < subdir_dentry->name_length; ++i, ++cnt)
subdir_dentry->name[cnt] = path[i];
// 设置subdir的dentry的父路径
subdir_dentry->parent = parent_dir;
// kdebug("to mkdir, parent name=%s", parent_dir->name);
spin_lock(&parent_dir->dir_inode->lockref.lock);
retval = parent_dir->dir_inode->inode_ops->mkdir(parent_dir->dir_inode, subdir_dentry, 0);
spin_unlock(&parent_dir->dir_inode->lockref.lock);
if (retval != 0)
{
if (vfs_dentry_put(parent_dir) != 0) // 释放dentry
spin_unlock(&parent_dir->lockref.lock);
return retval;
}
// 获取append前一个dentry并加锁
struct List *target_list = &parent_dir->subdirs_list;
// kdebug("target_list=%#018lx target_list->prev=%#018lx",target_list,target_list->prev);
if (list_empty(target_list) == false)
{
struct vfs_dir_entry_t *prev_dentry = list_entry(target_list->prev, struct vfs_dir_entry_t, child_node_list);
// kdebug("prev_dentry%#018lx",prev_dentry);
spin_lock(&prev_dentry->lockref.lock);
list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list);
// kdebug("retval = %d", retval);
spin_unlock(&prev_dentry->lockref.lock);
}
else
{
list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list);
goto out;
}
out:;
spin_unlock(&parent_dir->lockref.lock);
return retval;
}
/**
* @brief 创建文件夹
*
* @param path(r8) 路径
* @param mode(r9) 模式
* @return uint64_t
*/
uint64_t sys_mkdir(struct pt_regs *regs)
{
const char *path = (const char *)regs->r8;
// kdebug("path = %s", path);
mode_t mode = (mode_t)regs->r9;
if (user_mode(regs))
return vfs_mkdir(path, mode, true);
else
return vfs_mkdir(path, mode, false);
}
/**
* @brief 打开文件
*
* @param filename 文件路径
* @param flags 标志位
* @param from_user 是否由用户态调用,1为是0为否
* @return uint64_t 错误码
*/
uint64_t do_open(const char *filename, int flags, bool from_user)
{
long path_len = 0;
if (from_user)
path_len = strnlen_user(filename, PAGE_4K_SIZE) + 1;
else
path_len = strnlen(filename, PAGE_4K_SIZE) + 1;
if (path_len <= 0) // 地址空间错误
return -EFAULT;
else if (path_len >= PAGE_4K_SIZE) // 名称过长
return -ENAMETOOLONG;
// 为待拷贝文件路径字符串分配内存空间
char *path = (char *)kzalloc(path_len, 0);
if (path == NULL)
return -ENOMEM;
if (from_user)
strncpy_from_user(path, filename, path_len);
else
strncpy(path, filename, path_len);
// 去除末尾的 '/'
if (path_len >= 2 && path[path_len - 2] == '/')
{
path[path_len - 2] = '\0';
--path_len;
}
// 寻找文件
struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0);
if (dentry == NULL && flags & O_CREAT)
{
// 先找到倒数第二级目录
int tmp_index = -1;
for (int i = path_len - 1; i >= 0; --i)
{
if (path[i] == '/')
{
tmp_index = i;
break;
}
}
struct vfs_dir_entry_t *parent_dentry = NULL;
// kdebug("tmp_index=%d", tmp_index);
if (tmp_index > 0)
{
path[tmp_index] = '\0';
parent_dentry = vfs_path_walk(path, 0);
if (parent_dentry == NULL)
{
kfree(path);
return -ENOENT;
}
}
else
{
parent_dentry = vfs_root_sb->root;
}
// 创建新的文件
dentry = vfs_alloc_dentry(path_len - tmp_index);
dentry->name_length = path_len - tmp_index - 2;
// kdebug("to create new file:%s namelen=%d", dentry->name, dentry->name_length);
strncpy(dentry->name, path + tmp_index + 1, dentry->name_length);
dentry->parent = parent_dentry;
// 对父目录项加锁
spin_lock(&parent_dentry->lockref.lock);
spin_lock(&parent_dentry->dir_inode->lockref.lock);
// 创建子目录项
uint64_t retval = parent_dentry->dir_inode->inode_ops->create(parent_dentry->dir_inode, dentry, 0);
spin_unlock(&parent_dentry->dir_inode->lockref.lock); // 解锁inode
if (retval != 0)
{
if (vfs_dentry_put(dentry) != 0) // 释放dentry
BUG_ON(1);
BUG_ON(1);
kfree(path);
spin_unlock(&parent_dentry->lockref.lock);
return retval;
}
// ==== 将子目录项添加到链表 ====
struct vfs_dir_entry_t *next_dentry = NULL;
// 若list非空则对前一个dentry加锁
if (!list_empty(&parent_dentry->subdirs_list))
{
next_dentry = list_entry(list_next(&parent_dentry->subdirs_list), struct vfs_dir_entry_t, child_node_list);
spin_lock(&next_dentry->lockref.lock);
}
list_add(&parent_dentry->subdirs_list, &dentry->child_node_list);
if (next_dentry != NULL)
spin_unlock(&next_dentry->lockref.lock);
// 新建文件结束,对父目录项解锁
spin_unlock(&parent_dentry->lockref.lock);
// kdebug("created.");
}
kfree(path);
if (dentry == NULL)
{
return -ENOENT;
}
spin_lock(&dentry->lockref.lock);
// 要求打开文件夹而目标不是文件夹
if ((flags & O_DIRECTORY) && (dentry->dir_inode->attribute != VFS_IF_DIR))
{
spin_unlock(&dentry->lockref.lock);
return -ENOTDIR;
}
// 创建文件描述符
struct vfs_file_t *file_ptr = (struct vfs_file_t *)kzalloc(sizeof(struct vfs_file_t), 0);
int errcode = -1;
file_ptr->dEntry = dentry;
file_ptr->mode = flags;
file_ptr->file_ops = dentry->dir_inode->file_ops;
// 如果文件系统实现了打开文件的函数
if (file_ptr->file_ops && file_ptr->file_ops->open)
errcode = file_ptr->file_ops->open(dentry->dir_inode, file_ptr);
if (errcode != 0)
{
kfree(file_ptr);
spin_unlock(&dentry->lockref.lock);
return -EFAULT;
}
if (file_ptr->mode & O_TRUNC) // 清空文件
file_ptr->dEntry->dir_inode->file_size = 0;
if (file_ptr->mode & O_APPEND)
file_ptr->position = file_ptr->dEntry->dir_inode->file_size;
else
file_ptr->position = 0;
int fd_num = process_fd_alloc(file_ptr);
// 指针数组没有空位了
if (fd_num == -1)
{
kfree(file_ptr);
spin_unlock(&dentry->lockref.lock);
return -ENFILE;
}
spin_unlock(&dentry->lockref.lock);
return fd_num;
}
uint64_t sys_open(struct pt_regs *regs)
{
char *filename = (char *)(regs->r8);
int flags = (int)(regs->r9);
return do_open(filename, flags, true);
}
/**
* @brief 关闭文件
*
* @param fd_num 文件描述符
* @return uint64_t 错误码
*/
uint64_t vfs_close(int fd_num)
{
// 校验文件描述符范围
if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM)
return -EBADF;
// 文件描述符不存在
if (current_pcb->fds[fd_num] == NULL)
return -EBADF;
struct vfs_file_t *file_ptr = current_pcb->fds[fd_num];
uint64_t ret;
// If there is a valid close function
if (file_ptr->file_ops && file_ptr->file_ops->close)
ret = file_ptr->file_ops->close(file_ptr->dEntry->dir_inode, file_ptr);
kfree(file_ptr);
current_pcb->fds[fd_num] = NULL;
return 0;
}
/**
* @brief 动态分配dentry以及路径字符串名称
*
* @param name_size 名称字符串大小(字节)(注意考虑字符串最后需要有一个‘\0作为结尾)
* @return struct vfs_dir_entry_t* 创建好的dentry
*/
struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size)
{
if (unlikely(name_size > VFS_MAX_PATHLEN))
return NULL;
struct vfs_dir_entry_t *dentry = (struct vfs_dir_entry_t *)kzalloc(sizeof(struct vfs_dir_entry_t), 0);
if (unlikely(dentry == NULL))
return NULL;
if (name_size != 0)
dentry->name = (char *)kzalloc(name_size, 0);
// 初始化lockref
spin_init(&dentry->lockref.lock);
dentry->lockref.count = 1;
// 初始化链表
list_init(&dentry->child_node_list);
list_init(&dentry->subdirs_list);
return dentry;
}
/**
* @brief 判断是否可以删除指定的dentry
*
* 1、我们不能删除一个只读的dentry
* 2、我们应当对这个dentry的inode拥有写、执行权限暂时还没有实现权限
* 3、如果dentry指向的是文件夹而isdir为false则不能删除
* 3、如果dentry指向的是文件而isdir为true则不能删除
* @param dentry 将要被删除的dentry
* @param isdir 是否要删除文件夹
* @return int 错误码
*/
int vfs_may_delete(struct vfs_dir_entry_t *dentry, bool isdir)
{
// 当dentry没有inode的时候认为是bug
BUG_ON(dentry->dir_inode == NULL);
// todo: 进行权限检查
if (isdir) // 要删除文件夹
{
if (!D_ISDIR(dentry))
return -ENOTDIR;
else if (IS_ROOT(dentry))
return -EBUSY;
}
else if (D_ISDIR(dentry)) // 要删除文件但是当前是文件夹
return -EISDIR;
return 0;
}
/**
* @brief 删除文件夹
*
* @param path 文件夹路径
* @param from_userland 请求是否来自用户态
* @return int64_t 错误码
*/
int64_t vfs_rmdir(const char *path, bool from_userland)
{
uint32_t pathlen;
int retval = 0;
if (from_userland)
pathlen = strnlen_user(path, PAGE_4K_SIZE - 1);
else
pathlen = strnlen(path, PAGE_4K_SIZE - 1);
if (pathlen == 0)
return -ENOENT;
int last_slash = -1;
// 去除末尾的'/'
for (int i = pathlen - 1; i >= 0; --i)
{
if (path[i] != '/')
{
last_slash = i + 1;
break;
}
}
// 路径格式不合法
if (last_slash < 0)
return -ENOTDIR;
else if (path[0] != '/')
return -EINVAL;
char *buf = (char *)kzalloc(last_slash + 2, 0);
// 拷贝字符串(不包含要被创建的部分)
if (from_userland)
strncpy_from_user(buf, path, last_slash);
else
strncpy(buf, path, last_slash);
buf[last_slash + 1] = '\0';
struct vfs_dir_entry_t *dentry = vfs_path_walk(buf, 0);
kfree(buf);
if (dentry == NULL)
{
retval = -ENOENT;
goto out0;
}
// todo: 检查文件夹是否为空
spin_lock(&dentry->lockref.lock);
retval = vfs_may_delete(dentry, true);
if (retval != 0)
goto out1;
// todo: 对dentry和inode加锁
retval = -EBUSY;
if (is_local_mountpoint(dentry))
goto out1;
// todo:
retval = dentry->dir_inode->inode_ops->rmdir(dentry->dir_inode, dentry);
if (retval != 0)
{
BUG_ON(1);
goto out1;
}
dentry->dir_inode->attribute |= VFS_IF_DEAD; // 将当前inode标记为dead
dont_mount(dentry); // 将当前dentry标记为不可被挂载
detach_mounts(dentry); // 清理同样挂载在该路径的所有挂载点的挂载树
// 释放dentry
retval = vfs_dentry_put(dentry);
if (retval != 0)
goto out1;
goto out0;
out2:;
spin_unlock(&dentry->dir_inode->lockref.lock);
out1:;
spin_unlock(&dentry->lockref.lock);
out0:;
return retval;
}
/**
* @brief unlink a filesystem object
*
* 调用者必须持有parent_inode->lockref.lock
*
* @param mnt_userns 暂时未使用 用户命名空间. 请置为NULL
* @param parent_inode 父目录项的inode
* @param dentry 要被删除的目录项
* @param delegated_inode 暂未使用请置为NULL
* @return int
*/
int vfs_unlink(struct user_namespace *mnt_userns, struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dentry,
struct vfs_index_node_t **delegated_inode)
{
// 暂时不支持用户命名空间,因此发出警告
if (unlikely(mnt_userns != NULL))
{
WARN_ON(1);
return -EINVAL;
}
int retval = 0;
struct vfs_index_node_t *target = dentry->dir_inode;
retval = vfs_may_delete(dentry, false);
if (unlikely(retval != 0))
return retval;
// 没有unlink方法则不允许删除
if (!parent_inode->inode_ops->unlink)
return -EPERM;
// 对inode加锁
spin_lock(&target->lockref.lock);
if (is_local_mountpoint(dentry))
retval = -EBUSY;
else
{
retval = parent_inode->inode_ops->unlink(parent_inode, dentry);
if (retval == 0)
{
dont_mount(dentry);
detach_mounts(dentry);
}
}
spin_unlock(&target->lockref.lock);
out:;
return retval;
}
/**
* @brief 取消dentry和inode之间的链接
*
* @param dfd 进程相对路径基准目录的文件描述符(fcntl.h)
* @param pathname 路径
* @param from_userland 请求是否来自用户态
* @return int 错误码
*/
int do_unlink_at(int dfd, const char *pathname, bool from_userland)
{
// 暂时不支持相对路径,只支持绝对路径
if (dfd & AT_FDCWD)
{
kwarn("Not support: AT_FDCWD");
return -EINVAL;
}
uint32_t pathlen;
int retval = 0;
if (from_userland)
pathlen = strnlen_user(pathname, PAGE_4K_SIZE - 1);
else
pathlen = strnlen(pathname, PAGE_4K_SIZE - 1);
if (pathlen == 0)
return -ENOENT;
int last_slash = -1;
// 去除末尾的'/'
for (int i = pathlen - 1; i >= 0; --i)
{
if (pathname[i] != '/')
{
last_slash = i + 1;
break;
}
}
// 路径格式不合法
if (last_slash < 0)
return -ENOTDIR;
else if (pathname[0] != '/')
return -EINVAL;
char *buf = (char *)kzalloc(last_slash + 1, 0);
// 拷贝字符串
if (from_userland)
strncpy_from_user(buf, pathname, last_slash);
else
strncpy(buf, pathname, last_slash);
buf[last_slash] = '\0';
struct vfs_dir_entry_t *dentry = vfs_path_walk(buf, 0);
kfree(buf);
if (dentry == NULL || dentry->parent == NULL)
{
retval = -ENOENT;
goto out;
}
struct vfs_index_node_t *p_inode = dentry->parent->dir_inode;
// 对父inode加锁
spin_lock(&p_inode->lockref.lock);
spin_lock(&dentry->lockref.lock);
retval = vfs_unlink(NULL, dentry->parent->dir_inode, dentry, NULL);
if (unlikely(retval != 0))
{
// kdebug("retval=%d", retval);
spin_unlock(&dentry->lockref.lock);
spin_unlock(&p_inode->lockref.lock);
goto out;
}
// kdebug("vfs_dentry_put=%d", retval);
spin_unlock(&dentry->lockref.lock);
spin_unlock(&p_inode->lockref.lock);
if (IS_ERR_VALUE(retval))
kwarn("In do_unlink_at: dentry put failed; retval=%d", retval);
else
retval = 0;
out:;
return retval;
}
/**
* @brief 删除文件夹、取消文件的链接、删除文件的系统调用
*
* @param regs->r8 dfd 进程相对路径基准目录的文件描述符(见fcntl.h)
* @param regs->r9 路径名称字符串
* @param regs->r10 flag 预留的标志位暂时未使用请置为0。
* @return uint64_t 错误码
*/
uint64_t sys_unlink_at(struct pt_regs *regs)
{
int dfd = regs->r8;
const char *pathname = (const char *)regs->r9;
int flag = regs->r10;
bool from_user = SYSCALL_FROM_USER(regs) ? true : false;
if ((flag & (~AT_REMOVEDIR)) != 0)
return -EINVAL;
if (flag & AT_REMOVEDIR)
return vfs_rmdir(pathname, from_user);
// kdebug("to do_unlink_at, path=%s", pathname);
return do_unlink_at(dfd, pathname, from_user);
}
/**
* @brief 分配inode并将引用计数初始化为1
*
* @return struct vfs_index_node_t * 分配得到的inode
*/
struct vfs_index_node_t *vfs_alloc_inode()
{
struct vfs_index_node_t *inode = kzalloc(sizeof(struct vfs_index_node_t), 0);
spin_init(&inode->lockref.lock);
inode->lockref.count = 1; // 初始化引用计数为1
return inode;
}
/**
* @brief 初始化vfs
*
* @return int 错误码
*/
int vfs_init()
{
mount_init();
rootfs_init();
return 0;
}

View File

@ -16,10 +16,9 @@
#include <common/glib.h>
#include <common/lockref.h>
#include <common/user_namespace.h>
#include <DragonOS/stdint.h>
#include <mm/slab.h>
extern struct vfs_superblock_t *vfs_root_sb;
#define VFS_DPT_MBR 0 // MBR分区表
#define VFS_DPT_GPT 1 // GPT分区表
@ -193,102 +192,9 @@ struct vfs_file_operations_t
long (*readdir)(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler); // 读取文件夹
};
/**
* @brief 在VFS中注册文件系统
*
* @param fs 文件系统类型结构体
* @return uint64_t
*/
uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs);
uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs);
/**
* @brief 挂载文件系统
*
* @param path 要挂载到的路径
* @param name 文件系统名
* @param blk 块设备结构体
* @return struct vfs_superblock_t* 挂载后,文件系统的超级块
*/
struct vfs_superblock_t *vfs_mount_fs(const char *path, char *name, struct block_device *blk);
/**
* @brief 按照路径查找文件
*
* @param path 路径
* @param flags 1返回父目录项 0返回结果目录项
* @return struct vfs_dir_entry_t* 目录项
*/
struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags);
/**
* @brief 填充dentry
*
*/
int vfs_fill_dirent(void *buf, ino_t d_ino, char *name, int namelen, unsigned char type, off_t offset);
/**
* @brief 初始化vfs
*
* @return int 错误码
*/
int vfs_init();
/**
* @brief 动态分配dentry以及路径字符串名称
*
* @param name_size 名称字符串大小(字节)(注意考虑字符串最后需要有一个‘\0作为结尾)
* @return struct vfs_dir_entry_t* 创建好的dentry
*/
struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size);
/**
* @brief 分配inode并将引用计数初始化为1
*
* @return struct vfs_index_node_t * 分配得到的inode
*/
struct vfs_index_node_t *vfs_alloc_inode();
uint64_t do_open(const char *filename, int flags, bool from_user);
/**
* @brief 关闭文件
*
* @param fd_num 文件描述符
* @return uint64_t 错误码
*/
uint64_t vfs_close(int fd_num);
/**
* @brief 创建文件夹
*
* @param path 文件夹路径
* @param mode 创建模式
* @param from_userland 该创建请求是否来自用户态
* @return int64_t 错误码
*/
int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland);
/**
* @brief 删除文件夹
*
* @param path 文件夹路径
* @param from_userland 请求是否来自用户态
* @return int64_t 错误码
*/
int64_t vfs_rmdir(const char *path, bool from_userland);
/**
* @brief 释放dentry并视情况自动释放inode。 在调用该函数前需要将dentry加锁。
*
* @param dentry 目标dentry
*
* @return 错误码
* 注意当dentry指向文件时如果返回值为正数则表示在释放了该dentry后该dentry指向的inode的引用计数。
*/
int vfs_dentry_put(struct vfs_dir_entry_t *dentry);
int vfs_unlink(struct user_namespace *mnt_userns, struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dentry,
struct vfs_index_node_t **delegated_inode);
int do_unlink_at(int dfd, const char *pathname, bool name);
extern int vfs_init();

View File

@ -0,0 +1,392 @@
use core::{
hint::spin_loop,
ptr::null_mut,
sync::atomic::{AtomicUsize, Ordering},
};
use alloc::{boxed::Box, format, string::ToString, sync::Arc};
use crate::{
arch::asm::current::current_pcb,
driver::disk::ahci::{self},
filesystem::{
devfs::DevFS,
fat::fs::FATFileSystem,
procfs::ProcFS,
ramfs::RamFS,
vfs::{file::File, mount::MountFS, FileSystem, FileType},
},
include::bindings::bindings::{EBADF, ENAMETOOLONG, ENOENT, ENOTDIR, EPERM, PAGE_4K_SIZE},
io::SeekFrom,
kerror, kinfo,
};
use super::{file::FileMode, utils::rsplit_path, IndexNode, InodeId};
/// @brief 原子地生成新的Inode号。
/// 请注意所有的inode号都需要通过该函数来生成.全局的inode号除了以下两个特殊的以外都是唯一的
/// 特殊的两个inode号
/// [0]: 对应'.'目录项
/// [1]: 对应'..'目录项
pub fn generate_inode_id() -> InodeId {
static INO: AtomicUsize = AtomicUsize::new(1);
return INO.fetch_add(1, Ordering::SeqCst);
}
static mut __ROOT_INODE: *mut Arc<dyn IndexNode> = null_mut();
/// @brief 获取全局的根节点
#[inline(always)]
#[allow(non_snake_case)]
pub fn ROOT_INODE() -> Arc<dyn IndexNode> {
unsafe {
return __ROOT_INODE.as_ref().unwrap().clone();
}
}
#[no_mangle]
pub extern "C" fn vfs_init() -> i32 {
// 使用Ramfs作为默认的根文件系统
let ramfs = RamFS::new();
let mount_fs = MountFS::new(ramfs, None);
let root_inode = Box::leak(Box::new(mount_fs.root_inode()));
unsafe {
__ROOT_INODE = root_inode;
}
// 创建文件夹
root_inode
.create("proc", FileType::Dir, 0o777)
.expect("Failed to create /proc");
root_inode
.create("dev", FileType::Dir, 0o777)
.expect("Failed to create /dev");
// // 创建procfs实例
let procfs: Arc<ProcFS> = ProcFS::new();
// procfs挂载
let _t = root_inode
.find("proc")
.expect("Cannot find /proc")
.mount(procfs)
.expect("Failed to mount procfs.");
kinfo!("ProcFS mounted.");
// 创建 devfs 实例
let devfs: Arc<DevFS> = DevFS::new();
// devfs 挂载
let _t = root_inode
.find("dev")
.expect("Cannot find /dev")
.mount(devfs)
.expect("Failed to mount devfs");
kinfo!("DevFS mounted.");
let root_inode = ROOT_INODE().list().expect("VFS init failed");
if root_inode.len() > 0 {
kinfo!("Successfully initialized VFS!");
}
return 0;
}
/// @brief 真正执行伪文件系统迁移的过程
///
/// @param mountpoint_name 在根目录下的挂载点的名称
/// @param inode 原本的挂载点的inode
fn do_migrate(
new_root_inode: Arc<dyn IndexNode>,
mountpoint_name: &str,
fs: &MountFS,
) -> Result<(), i32> {
let r = new_root_inode.find(mountpoint_name);
let mountpoint = if r.is_err() {
new_root_inode
.create(mountpoint_name, FileType::Dir, 0o777)
.expect(format!("Failed to create '/{mountpoint_name}'").as_str())
} else {
r.unwrap()
};
// 迁移挂载点
mountpoint
.mount(fs.inner_filesystem())
.expect(format!("Failed to migrate {mountpoint_name}").as_str());
return Ok(());
}
/// @brief 迁移伪文件系统的inode
/// 请注意为了避免删掉了伪文件系统内的信息因此没有在原root inode那里调用unlink.
fn migrate_virtual_filesystem(new_fs: Arc<dyn FileSystem>) -> Result<(), i32> {
kinfo!("VFS: Migrating filesystems...");
// ==== 在这里获取要被迁移的文件系统的inode ===
let binding = ROOT_INODE().find("proc").expect("ProcFS not mounted!").fs();
let proc: &MountFS = binding.as_any_ref().downcast_ref::<MountFS>().unwrap();
let binding = ROOT_INODE().find("dev").expect("DevFS not mounted!").fs();
let dev: &MountFS = binding.as_any_ref().downcast_ref::<MountFS>().unwrap();
let new_fs = MountFS::new(new_fs, None);
// 获取新的根文件系统的根节点的引用
let new_root_inode = Box::leak(Box::new(new_fs.root_inode()));
// 把上述文件系统,迁移到新的文件系统下
do_migrate(new_root_inode.clone(), "proc", proc)?;
do_migrate(new_root_inode.clone(), "dev", dev)?;
unsafe {
// drop旧的Root inode
let old_root_inode: Box<Arc<dyn IndexNode>> = Box::from_raw(__ROOT_INODE);
__ROOT_INODE = null_mut();
drop(old_root_inode);
// 设置全局的新的ROOT Inode
__ROOT_INODE = new_root_inode;
}
kinfo!("VFS: Migrate filesystems done!");
return Ok(());
}
#[no_mangle]
pub extern "C" fn mount_root_fs() -> i32 {
kinfo!("Try to mount FAT32 as root fs...");
let partiton: Arc<crate::io::disk_info::Partition> =
ahci::get_disks_by_name("ahci_disk_0".to_string())
.unwrap()
.0
.lock()
.partitions[0]
.clone();
let fatfs: Result<Arc<FATFileSystem>, i32> = FATFileSystem::new(partiton);
if fatfs.is_err() {
kerror!(
"Failed to initialize fatfs, code={:?}",
fatfs.as_ref().err()
);
loop {
spin_loop();
}
}
let fatfs: Arc<FATFileSystem> = fatfs.unwrap();
let r = migrate_virtual_filesystem(fatfs);
if r.is_err() {
kerror!("Failed to migrate virtual filesystem to FAT32!");
loop {
spin_loop();
}
}
kinfo!("Successfully migrate rootfs to FAT32!");
return 0;
}
/// @brief 为当前进程打开一个文件
pub fn do_open(path: &str, mode: FileMode) -> Result<i32, i32> {
// 文件名过长
if path.len() > PAGE_4K_SIZE as usize {
return Err(-(ENAMETOOLONG as i32));
}
let inode: Result<Arc<dyn IndexNode>, i32> = ROOT_INODE().lookup(path);
let inode: Arc<dyn IndexNode> = if inode.is_err() {
let errno = inode.unwrap_err();
// 文件不存在,且需要创建
if mode.contains(FileMode::O_CREAT)
&& !mode.contains(FileMode::O_DIRECTORY)
&& errno == -(ENOENT as i32)
{
let (filename, parent_path) = rsplit_path(path);
// 查找父目录
let parent_inode: Arc<dyn IndexNode> =
ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
// 创建文件
let inode: Arc<dyn IndexNode> = parent_inode.create(filename, FileType::File, 0o777)?;
inode
} else {
// 不需要创建文件,因此返回错误码
return Err(errno);
}
} else {
inode.unwrap()
};
let file_type: FileType = inode.metadata()?.file_type;
// 如果要打开的是文件夹,而目标不是文件夹
if mode.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 如果O_TRUNC并且打开模式包含O_RDWR或O_WRONLY清空文件
if mode.contains(FileMode::O_TRUNC)
&& (mode.contains(FileMode::O_RDWR) || mode.contains(FileMode::O_WRONLY))
&& file_type == FileType::File
{
inode.truncate(0)?;
}
// 创建文件对象
let mut file: File = File::new(inode, mode)?;
// 打开模式为“追加”
if mode.contains(FileMode::O_APPEND) {
file.lseek(SeekFrom::SeekEnd(0))?;
}
// 把文件对象存入pcb
return current_pcb().alloc_fd(file);
}
/// @brief 根据文件描述符读取文件数据。尝试读取的数据长度与buf的长度相同。
///
/// @param fd 文件描述符编号
/// @param buf 输出缓冲区。
///
/// @return Ok(usize) 成功读取的数据的字节数
/// @return Err(i32) 读取失败返回posix错误码
pub fn do_read(fd: i32, buf: &mut [u8]) -> Result<usize, i32> {
let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
if file.is_none() {
return Err(-(EBADF as i32));
}
let file: &mut File = file.unwrap();
return file.read(buf.len(), buf);
}
/// @brief 根据文件描述符向文件写入数据。尝试写入的数据长度与buf的长度相同。
///
/// @param fd 文件描述符编号
/// @param buf 输入缓冲区。
///
/// @return Ok(usize) 成功写入的数据的字节数
/// @return Err(i32) 写入失败返回posix错误码
pub fn do_write(fd: i32, buf: &[u8]) -> Result<usize, i32> {
let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
if file.is_none() {
return Err(-(EBADF as i32));
}
let file: &mut File = file.unwrap();
return file.write(buf.len(), buf);
}
/// @brief 调整文件操作指针的位置
///
/// @param fd 文件描述符编号
/// @param seek 调整的方式
///
/// @return Ok(usize) 调整后,文件访问指针相对于文件头部的偏移量
/// @return Err(i32) 调整失败返回posix错误码
pub fn do_lseek(fd: i32, seek: SeekFrom) -> Result<usize, i32> {
let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
if file.is_none() {
return Err(-(EBADF as i32));
}
let file: &mut File = file.unwrap();
return file.lseek(seek);
}
/// @brief 创建文件/文件夹
pub fn do_mkdir(path: &str, _mode: FileMode) -> Result<u64, i32> {
// 文件名过长
if path.len() > PAGE_4K_SIZE as usize {
return Err(-(ENAMETOOLONG as i32));
}
let inode: Result<Arc<dyn IndexNode>, i32> = ROOT_INODE().lookup(path);
if inode.is_err() {
let errno = inode.unwrap_err();
// 文件不存在,且需要创建
if errno == -(ENOENT as i32) {
let (filename, parent_path) = rsplit_path(path);
// 查找父目录
let parent_inode: Arc<dyn IndexNode> =
ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
// 创建文件夹
let _create_inode: Arc<dyn IndexNode> =
parent_inode.create(filename, FileType::Dir, 0o777)?;
} else {
// 不需要创建文件,因此返回错误码
return Err(errno);
}
}
return Ok(0);
}
/// @breif 删除文件夹
pub fn do_remove_dir(path: &str) -> Result<u64, i32> {
// 文件名过长
if path.len() > PAGE_4K_SIZE as usize {
return Err(-(ENAMETOOLONG as i32));
}
let inode: Result<Arc<dyn IndexNode>, i32> = ROOT_INODE().lookup(path);
if inode.is_err() {
let errno = inode.unwrap_err();
// 文件不存在
if errno == -(ENOENT as i32) {
return Err(-(ENOENT as i32));
}
}
let (filename, parent_path) = rsplit_path(path);
// 查找父目录
let parent_inode: Arc<dyn IndexNode> = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
if parent_inode.metadata()?.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
let target_inode: Arc<dyn IndexNode> = parent_inode.find(filename)?;
if target_inode.metadata()?.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 删除文件夹
parent_inode.rmdir(filename)?;
return Ok(0);
}
/// @brief 删除文件
pub fn do_unlink_at(path: &str, _mode: FileMode) -> Result<u64, i32> {
// 文件名过长
if path.len() > PAGE_4K_SIZE as usize {
return Err(-(ENAMETOOLONG as i32));
}
let inode: Result<Arc<dyn IndexNode>, i32> = ROOT_INODE().lookup(path);
if inode.is_err() {
let errno = inode.clone().unwrap_err();
// 文件不存在,且需要创建
if errno == -(ENOENT as i32) {
return Err(-(ENOENT as i32));
}
}
// 禁止在目录上unlink
if inode.unwrap().metadata()?.file_type == FileType::Dir {
return Err(-(EPERM as i32));
}
let (filename, parent_path) = rsplit_path(path);
// 查找父目录
let parent_inode: Arc<dyn IndexNode> = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
if parent_inode.metadata()?.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 删除文件
parent_inode.unlink(filename)?;
return Ok(0);
}

View File

@ -1,134 +0,0 @@
#include "internal.h"
#include <common/kfifo.h>
#include <debug/bug.h>
/**
* @brief 释放dentry并视情况自动释放inode. 在调用该函数前需要将dentry加锁。
*
* @param dentry 目标dentry
*
* @return 错误码
* 注意当dentry指向文件时如果返回值为正数则表示在释放了该dentry后该dentry指向的inode的引用计数。
*/
int vfs_dentry_put(struct vfs_dir_entry_t *dentry)
{
int retval = 0;
uint64_t in_value = 0;
struct kfifo_t fifo = {0};
const struct vfs_dir_entry_t *start_dentry = dentry;
// 引用计数大于1时尝试释放dentry的话抛出错误信息
if (unlikely(dentry->lockref.count > 1))
{
BUG_ON(1);
retval = -EBUSY;
goto out;
}
if (D_ISDIR(dentry))
{
// 创建一个用来存放指向dentry的指针的fifo队列
// 暂时假设队列大小为1024个元素
// todo: 实现队列的自动扩容功能
retval = kfifo_alloc(&fifo, 1024 * sizeof(uint64_t), 0);
if (retval != 0)
goto failed;
// 将根dentry加入队列
in_value = (uint64_t)dentry;
kfifo_in(&fifo, &in_value, sizeof(uint64_t));
list_del(&dentry->child_node_list); // 从父dentry中删除
while (!kfifo_empty(&fifo))
{
// 取出队列中的下一个元素
kfifo_out(&fifo, &dentry, sizeof(uint64_t));
BUG_ON(dentry == NULL);
struct List *list = &dentry->subdirs_list;
if (!list_empty(list))
{
// 将当前dentry下的所有dentry加入队列
do
{
list = list_next(list);
in_value = (uint64_t)container_of(list, struct vfs_dir_entry_t, child_node_list);
if (in_value != NULL)
kfifo_in(&fifo, &in_value, sizeof(uint64_t));
} while (list_next(list) != (&dentry->subdirs_list));
}
if (unlikely(dentry != start_dentry))
spin_lock(&dentry->lockref.lock);
if (dentry->lockref.count > 1)
{
if (unlikely(dentry != start_dentry))
spin_unlock(&dentry->lockref.lock);
continue;
}
// 释放inode
spin_lock(&dentry->dir_inode->lockref.lock);
retval = vfs_free_inode(dentry->dir_inode);
if (retval > 0) // 还有其他的dentry引用着这个inode
{
spin_unlock(&dentry->dir_inode->lockref.lock);
retval = 0;
}
// 若当前dentry是否为挂载点则umount
if (is_local_mountpoint(dentry))
do_umount(dentry);
if (dentry->dir_ops->release != NULL)
dentry->dir_ops->release(dentry);
kfree(dentry);
}
kfifo_free_alloc(&fifo);
retval = 0;
goto out;
}
else // 是文件或设备
{
kdebug("to put dentry: file: %s", dentry->name);
list_del(&dentry->child_node_list); // 从父dentry中删除
// 释放inode
spin_lock(&dentry->dir_inode->lockref.lock);
retval = vfs_free_inode(dentry->dir_inode);
kdebug("retval=%d", retval);
if (retval > 0) // 还有其他的dentry引用着这个inode
spin_unlock(&dentry->dir_inode->lockref.lock);
if (dentry->dir_ops->release != NULL)
dentry->dir_ops->release(dentry);
kfree(dentry);
goto out;
}
failed:;
if (fifo.buffer != NULL)
kfifo_free_alloc(&fifo);
kerror("dentry_put failed.");
out:;
// 在这里不用释放dentry的锁因为dentry已经被释放掉了
return retval;
}
/**
* @brief 释放inode要求已经对inode进行加锁后调用该函数
*
* @param inode 待释放的inode
* @return int 错误码
* 当inode还有其他的使用者时返回inode的使用者数量
*/
int vfs_free_inode(struct vfs_index_node_t *inode)
{
--inode->lockref.count;
BUG_ON(inode->lockref.count < 0);
if (inode->lockref.count == 0)
{
kfree(inode->private_inode_info);
kfree(inode);
return 0;
}
else // 如果inode没有被释放
return inode->lockref.count;
}

View File

@ -0,0 +1,330 @@
use core::mem::MaybeUninit;
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
use crate::{
arch::asm::current::current_pcb,
filesystem::procfs::ProcfsFilePrivateData,
include::bindings::bindings::{
process_control_block, EINVAL, ENOBUFS, EOVERFLOW, EPERM, ESPIPE,
},
io::SeekFrom,
kerror,
};
use super::{Dirent, FileType, IndexNode, Metadata};
/// 文件私有信息的枚举类型
#[derive(Debug, Clone)]
pub enum FilePrivateData {
// procfs文件私有信息
Procfs(ProcfsFilePrivateData),
// 不需要文件私有信息
Unused,
}
impl Default for FilePrivateData {
fn default() -> Self {
return Self::Unused;
}
}
bitflags! {
/// @brief 文件打开模式
/// 其中低2bit组合而成的数字的值用于表示访问权限。其他的bit才支持通过按位或的方式来表示参数
///
/// 与Linux 5.19.10的uapi/asm-generic/fcntl.h相同
/// https://opengrok.ringotek.cn/xref/linux-5.19.10/tools/include/uapi/asm-generic/fcntl.h#19
pub struct FileMode: u32{
/* File access modes for `open' and `fcntl'. */
/// Open Read-only
const O_RDONLY = 0;
/// Open Write-only
const O_WRONLY = 1;
/// Open read/write
const O_RDWR = 2;
/// Mask for file access modes
const O_ACCMODE = 00000003;
/* Bits OR'd into the second argument to open. */
/// Create file if it does not exist
const O_CREAT = 00000100;
/// Fail if file already exists
const O_EXCL = 00000200;
/// Do not assign controlling terminal
const O_NOCTTY = 00000400;
/// 文件存在且是普通文件并以O_RDWR或O_WRONLY打开则它会被清空
const O_TRUNC = 00001000;
/// 文件指针会被移动到文件末尾
const O_APPEND = 00002000;
/// 非阻塞式IO模式
const O_NONBLOCK = 00004000;
/// used to be O_SYNC, see below
const O_DSYNC = 00010000;
/// fcntl, for BSD compatibility
const FASYNC = 00020000;
/* direct disk access hint */
const O_DIRECT = 00040000;
const O_LARGEFILE = 00100000;
/// 打开的必须是一个目录
const O_DIRECTORY = 00200000;
/// Do not follow symbolic links
const O_NOFOLLOW = 00400000;
const O_NOATIME = 01000000;
/// set close_on_exec
const O_CLOEXEC = 02000000;
}
}
/// @brief 抽象文件结构体
#[derive(Debug, Clone)]
pub struct File {
inode: Arc<dyn IndexNode>,
/// 对于文件,表示字节偏移量;对于文件夹,表示当前操作的子目录项偏移量
offset: usize,
/// 文件的打开模式
mode: FileMode,
/// 文件类型
file_type: FileType,
/// readdir时候用的暂存的本次循环中所有子目录项的名字的数组
readdir_subdirs_name: Vec<String>,
pub private_data: FilePrivateData,
}
impl File {
/// @brief 创建一个新的文件对象
///
/// @param inode 文件对象对应的inode
/// @param mode 文件的打开模式
pub fn new(inode: Arc<dyn IndexNode>, mode: FileMode) -> Result<Self, i32> {
let file_type: FileType = inode.metadata()?.file_type;
let mut f = File {
inode,
offset: 0,
mode,
file_type,
readdir_subdirs_name: Vec::new(),
private_data: FilePrivateData::default(),
};
// kdebug!("inode:{:?}",f.inode);
f.inode.open(&mut f.private_data)?;
return Ok(f);
}
/// @brief 从文件中读取指定的字节数到buffer中
///
/// @param len 要读取的字节数
/// @param buf 目标buffer
///
/// @return Ok(usize) 成功读取的字节数
/// @return Err(i32) 错误码
pub fn read(&mut self, len: usize, buf: &mut [u8]) -> Result<usize, i32> {
// 先检查本文件在权限等规则下,是否可读取。
self.readable()?;
if buf.len() < len {
return Err(-(ENOBUFS as i32));
}
let len = self
.inode
.read_at(self.offset, len, buf, &mut self.private_data)?;
self.offset += len;
return Ok(len);
}
/// @brief 从buffer向文件写入指定的字节数的数据
///
/// @param len 要写入的字节数
/// @param buf 源数据buffer
///
/// @return Ok(usize) 成功写入的字节数
/// @return Err(i32) 错误码
pub fn write(&mut self, len: usize, buf: &[u8]) -> Result<usize, i32> {
// 先检查本文件在权限等规则下,是否可写入。
self.writeable()?;
if buf.len() < len {
return Err(-(ENOBUFS as i32));
}
let len = self
.inode
.write_at(self.offset, len, buf, &mut FilePrivateData::Unused)?;
self.offset += len;
return Ok(len);
}
/// @brief 获取文件的元数据
pub fn metadata(&self) -> Result<Metadata, i32> {
return self.inode.metadata();
}
/// @brief 根据inode号获取子目录项的名字
pub fn get_entry_name(&self, ino: usize) -> Result<String, i32> {
return self.inode.get_entry_name(ino);
}
/// @brief 调整文件操作指针的位置
///
/// @param origin 调整的起始位置
pub fn lseek(&mut self, origin: SeekFrom) -> Result<usize, i32> {
if self.inode.metadata().unwrap().file_type == FileType::Pipe {
return Err(-(ESPIPE as i32));
}
let pos: i64;
match origin {
SeekFrom::SeekSet(offset) => {
pos = offset;
}
SeekFrom::SeekCurrent(offset) => {
pos = self.offset as i64 + offset;
}
SeekFrom::SeekEnd(offset) => {
let metadata = self.metadata()?;
pos = metadata.size + offset;
}
SeekFrom::Invalid => {
return Err(-(EINVAL as i32));
}
}
if pos < 0 || pos > self.metadata()?.size {
return Err(-(EOVERFLOW as i32));
}
self.offset = pos as usize;
return Ok(self.offset);
}
/// @brief 判断当前文件是否可读
#[inline]
pub fn readable(&self) -> Result<(), i32> {
// 暂时认为只要不是write only, 就可读
if self.mode == FileMode::O_WRONLY {
return Err(-(EPERM as i32));
}
return Ok(());
}
/// @brief 判断当前文件是否可写
#[inline]
pub fn writeable(&self) -> Result<(), i32> {
// 暂时认为只要不是read only, 就可写
if self.mode == FileMode::O_RDONLY {
return Err(-(EPERM as i32));
}
return Ok(());
}
/// @biref 充填dirent结构体
/// @return 返回dirent结构体的大小
pub fn readdir(&mut self, dirent: &mut Dirent) -> Result<u64, i32> {
let inode: &Arc<dyn IndexNode> = &self.inode;
// 如果偏移量为0
if self.offset == 0 {
self.readdir_subdirs_name = inode.list()?;
self.readdir_subdirs_name.sort();
}
// kdebug!("sub_entries={sub_entries:?}");
if self.readdir_subdirs_name.is_empty() {
self.offset = 0;
return Ok(0);
}
let name: String = self.readdir_subdirs_name.remove(0);
let sub_inode: Arc<dyn IndexNode> = match inode.find(&name) {
Ok(i) => i,
Err(e) => {
kerror!("Readdir error: Failed to find sub inode, file={self:?}");
return Err(e);
}
};
let name_bytes: &[u8] = name.as_bytes();
self.offset += 1;
dirent.d_ino = sub_inode.metadata().unwrap().inode_id as u64;
dirent.d_off = 0;
dirent.d_reclen = 0;
dirent.d_type = sub_inode.metadata().unwrap().file_type.get_file_type_num() as u8;
// 根据posix的规定dirent中的d_name是一个不定长的数组因此需要unsafe来拷贝数据
unsafe {
let ptr = &mut dirent.d_name as *mut u8;
let buf: &mut [u8] =
::core::slice::from_raw_parts_mut::<'static, u8>(ptr, name_bytes.len());
buf.copy_from_slice(name_bytes);
}
// 计算dirent结构体的大小
return Ok((name_bytes.len() + ::core::mem::size_of::<Dirent>()
- ::core::mem::size_of_val(&dirent.d_name)) as u64);
}
pub fn inode(&self) -> Arc<dyn IndexNode> {
return self.inode.clone();
}
}
impl Drop for File {
fn drop(&mut self) {
let r: Result<(), i32> = self.inode.close(&mut self.private_data);
// 打印错误信息
if r.is_err() {
kerror!(
"pid: {} failed to close file: {:?}, errno={}",
current_pcb().pid,
self,
r.unwrap_err()
);
}
}
}
/// @brief pcb里面的文件描述符数组
#[derive(Debug, Clone)]
pub struct FileDescriptorVec {
/// 当前进程打开的文件描述符
pub fds: [Option<Box<File>>; FileDescriptorVec::PROCESS_MAX_FD],
}
impl FileDescriptorVec {
pub const PROCESS_MAX_FD: usize = 32;
pub fn new() -> Box<FileDescriptorVec> {
// 先声明一个未初始化的数组
let mut data: [MaybeUninit<Option<Box<File>>>; FileDescriptorVec::PROCESS_MAX_FD] =
unsafe { MaybeUninit::uninit().assume_init() };
// 逐个把每个元素初始化为None
for i in 0..FileDescriptorVec::PROCESS_MAX_FD {
data[i] = MaybeUninit::new(None);
}
// 由于一切都初始化完毕,因此将未初始化的类型强制转换为已经初始化的类型
let data: [Option<Box<File>>; FileDescriptorVec::PROCESS_MAX_FD] = unsafe {
core::mem::transmute::<_, [Option<Box<File>>; FileDescriptorVec::PROCESS_MAX_FD]>(data)
};
// 初始化文件描述符数组结构体
return Box::new(FileDescriptorVec { fds: data });
}
/// @brief 从pcb的fds字段获取文件描述符数组的可变引用
#[inline]
pub fn from_pcb(pcb: &'static process_control_block) -> Option<&'static mut FileDescriptorVec> {
return unsafe { (pcb.fds as usize as *mut FileDescriptorVec).as_mut() };
}
/// @brief 判断文件描述符序号是否合法
///
/// @return true 合法
///
/// @return false 不合法
#[inline]
pub fn validate_fd(fd: i32) -> bool {
if fd < 0 || fd as usize > FileDescriptorVec::PROCESS_MAX_FD {
return false;
} else {
return true;
}
}
}

View File

@ -1,45 +0,0 @@
#pragma once
#include "VFS.h"
#include "mount.h"
/**
* @brief 判断是否可以删除指定的dentry
*
* 1、我们不能删除一个只读的dentry
* 2、我们应当对这个dentry拥有写、执行权限暂时还没有实现权限
* 3、如果dentry指向的是文件夹而isdir为false则不能删除
* 3、如果dentry指向的是文件而isdir为true则不能删除
* @param dentry 将要被删除的dentry
* @param isdir 是否要删除文件夹
* @return int 错误码
*/
int vfs_may_delete(struct vfs_dir_entry_t *dentry, bool isdir);
#define D_ISDIR(dentry) ((dentry)->dir_inode->attribute & VFS_IF_DIR)
// 判断是否为根目录
#define IS_ROOT(x) ((x) == (x)->parent)
/**
* @brief 判断当前dentry是否为挂载点
*
* @param dentry
*/
static inline bool is_local_mountpoint(struct vfs_dir_entry_t *dentry)
{
if (D_MOUNTED(dentry))
return true;
else
return false;
}
/**
* @brief 释放inode要求已经对inode进行加锁后调用该函数
*
* @param inode 待释放的inode
* @return int 错误码
* 当inode还有其他的使用者时返回inode的使用者数量
*/
int vfs_free_inode(struct vfs_index_node_t * inode);

View File

@ -1 +1,517 @@
#![allow(dead_code)]
pub mod core;
pub mod file;
pub mod mount;
mod syscall;
mod utils;
use ::core::{any::Any, fmt::Debug};
use alloc::{string::String, sync::Arc, vec::Vec};
use crate::{
include::bindings::bindings::{ENOTDIR, ENOTSUP},
time::TimeSpec,
};
pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS};
/// vfs容许的最大的路径名称长度
pub const MAX_PATHLEN: u32 = 1024;
/// 定义inode号的类型为usize
pub type InodeId = usize;
/// 文件的类型
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FileType {
/// 文件
File,
/// 文件夹
Dir,
/// 块设备
BlockDevice,
/// 字符设备
CharDevice,
/// 管道文件
Pipe,
/// 符号链接
SymLink,
}
/* these are defined by POSIX and also present in glibc's dirent.h */
/// 完整含义请见 http://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html
pub const DT_UNKNOWN: u16 = 0;
/// 命名管道或者FIFO
pub const DT_FIFO: u16 = 1;
// 字符设备
pub const DT_CHR: u16 = 2;
// 目录
pub const DT_DIR: u16 = 4;
// 块设备
pub const DT_BLK: u16 = 6;
// 常规文件
pub const DT_REG: u16 = 8;
// 符号链接
pub const DT_LNK: u16 = 10;
// 是一个socket
pub const DT_SOCK: u16 = 12;
// 这个是抄Linux的还不知道含义
pub const DT_WHT: u16 = 14;
pub const DT_MAX: u16 = 16;
impl FileType {
pub fn get_file_type_num(&self) -> u16 {
return match self {
FileType::File => DT_REG,
FileType::Dir => DT_DIR,
FileType::BlockDevice => DT_BLK,
FileType::CharDevice => DT_CHR,
FileType::Pipe => DT_FIFO,
FileType::SymLink => DT_LNK,
};
}
}
/// @brief inode的状态由poll方法返回
#[derive(Debug, Default, PartialEq)]
pub struct PollStatus {
pub flags: u8,
}
impl PollStatus {
pub const WRITE_MASK: u8 = (1u8 << 0);
pub const READ_MASK: u8 = (1u8 << 1);
pub const ERR_MASK: u8 = (1u8 << 2);
}
pub trait IndexNode: Any + Sync + Send + Debug {
/// @brief 打开文件
///
/// @return 成功Ok()
/// 失败Err(错误码)
fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 关闭文件
///
/// @return 成功Ok()
/// 失败Err(错误码)
fn close(&self, _data: &mut FilePrivateData) -> Result<(), i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 在inode的指定偏移量开始读取指定大小的数据
///
/// @param offset 起始位置在Inode中的偏移量
/// @param len 要读取的字节数
/// @param buf 缓冲区. 请注意,必须满足@buf.len()>=@len
/// @param _data 各文件系统系统所需私有信息
///
/// @return 成功Ok(读取的字节数)
/// 失败Err(Posix错误码)
fn read_at(
&self,
offset: usize,
len: usize,
buf: &mut [u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32>;
/// @brief 在inode的指定偏移量开始写入指定大小的数据从buf的第0byte开始写入
///
/// @param offset 起始位置在Inode中的偏移量
/// @param len 要写入的字节数
/// @param buf 缓冲区. 请注意,必须满足@buf.len()>=@len
/// @param _data 各文件系统系统所需私有信息
///
/// @return 成功Ok(写入的字节数)
/// 失败Err(Posix错误码)
fn write_at(
&self,
offset: usize,
len: usize,
buf: &[u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32>;
/// @brief 获取当前inode的状态。
///
/// @return PollStatus结构体
fn poll(&self) -> Result<PollStatus, i32>;
/// @brief 获取inode的元数据
///
/// @return 成功Ok(inode的元数据)
/// 失败Err(错误码)
fn metadata(&self) -> Result<Metadata, i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 设置inode的元数据
///
/// @return 成功Ok()
/// 失败Err(错误码)
fn set_metadata(&self, _metadata: &Metadata) -> Result<(), i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 重新设置文件的大小
///
/// @return 成功Ok()
/// 失败Err(错误码)
fn resize(&self, _len: usize) -> Result<(), i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 在当前目录下创建一个新的inode
///
/// @param name 目录项的名字
/// @param file_type 文件类型
/// @param mode 权限
///
/// @return 创建成功返回Ok(新的inode的Arc指针)
/// @return 创建失败返回Err(错误码)
fn create(
&self,
name: &str,
file_type: FileType,
mode: u32,
) -> Result<Arc<dyn IndexNode>, i32> {
// 若文件系统没有实现此方法则默认调用其create_with_data方法。如果仍未实现则会得到一个Err(-ENOTSUP)的返回值
return self.create_with_data(name, file_type, mode, 0);
}
/// @brief 在当前目录下创建一个新的inode并传入一个简单的data字段方便进行初始化。
///
/// @param name 目录项的名字
/// @param file_type 文件类型
/// @param mode 权限
/// @param data 用于初始化该inode的数据。为0则表示忽略此字段对于不同的文件系统来说代表的含义可能不同。
///
/// @return 创建成功返回Ok(新的inode的Arc指针)
/// @return 创建失败返回Err(错误码)
fn create_with_data(
&self,
_name: &str,
_file_type: FileType,
_mode: u32,
_data: usize,
) -> Result<Arc<dyn IndexNode>, i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 在当前目录下创建一个名为Name的硬链接指向另一个IndexNode
///
/// @param name 硬链接的名称
/// @param other 要被指向的IndexNode的Arc指针
///
/// @return 成功Ok()
/// 失败Err(错误码)
fn link(&self, _name: &str, _other: &Arc<dyn IndexNode>) -> Result<(), i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 在当前目录下删除一个名为Name的硬链接
///
/// @param name 硬链接的名称
///
/// @return 成功Ok()
/// 失败Err(错误码)
fn unlink(&self, _name: &str) -> Result<(), i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 删除文件夹
///
/// @param name 文件夹名称
///
/// @return 成功 Ok(())
/// @return 失败 Err(错误码)
fn rmdir(&self, _name: &str) ->Result<(), i32>{
return Err(-(ENOTSUP as i32));
}
/// @brief 将指定名称的子目录项的文件内容移动到target这个目录下。如果_old_name所指向的inode与_target的相同那么则直接执行重命名的操作。
///
/// @param old_name 旧的名字
///
/// @param target 移动到指定的inode
///
/// @param new_name 新的文件名
///
/// @return 成功: Ok()
/// 失败: Err(错误码)
fn move_(
&self,
_old_name: &str,
_target: &Arc<dyn IndexNode>,
_new_name: &str,
) -> Result<(), i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 寻找一个名为Name的inode
///
/// @param name 要寻找的inode的名称
///
/// @return 成功Ok()
/// 失败Err(错误码)
fn find(&self, _name: &str) -> Result<Arc<dyn IndexNode>, i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 根据inode号获取子目录项的名字
///
/// @param ino inode号
///
/// @return 成功Ok()
/// 失败Err(错误码)
fn get_entry_name(&self, _ino: InodeId) -> Result<String, i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 根据inode号获取子目录项的名字和元数据
///
/// @param ino inode号
///
/// @return 成功Ok(String, Metadata)
/// 失败Err(错误码)
fn get_entry_name_and_metadata(&self, ino: InodeId) -> Result<(String, Metadata), i32> {
// 如果有条件,请在文件系统中使用高效的方式实现本接口,而不是依赖这个低效率的默认实现。
let name = self.get_entry_name(ino)?;
let entry = self.find(&name)?;
return Ok((name, entry.metadata()?));
}
/// @brief io control接口
///
/// @param cmd 命令
/// @param data 数据
///
/// @return 成功Ok()
/// 失败Err(错误码)
fn ioctl(&self, _cmd: u32, _data: usize) -> Result<usize, i32> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(-(ENOTSUP as i32));
}
/// @brief 获取inode所在的文件系统的指针
fn fs(&self) -> Arc<dyn FileSystem>;
/// @brief 本函数用于实现动态转换。
/// 具体的文件系统在实现本函数时最简单的方式就是直接返回self
fn as_any_ref(&self) -> &dyn Any;
/// @brief 列出当前inode下的所有目录项的名字
fn list(&self) -> Result<Vec<String>, i32>;
/// @brief 在当前Inode下挂载一个新的文件系统
/// 请注意该函数只能被MountFS实现其他文件系统不应实现这个函数
fn mount(&self, _fs: Arc<dyn FileSystem>) -> Result<Arc<MountFS>, i32> {
return Err(-(ENOTSUP as i32));
}
/// @brief 截断当前inode到指定的长度。如果当前文件长度小于len,则不操作。
///
/// @param len 要被截断到的目标长度
fn truncate(&self, _len: usize) -> Result<(), i32> {
return Err(-(ENOTSUP as i32));
}
}
impl dyn IndexNode {
/// @brief 将当前Inode转换为一个具体的结构体类型由T指定
/// 如果类型正确则返回Some,否则返回None
pub fn downcast_ref<T: IndexNode>(&self) -> Option<&T> {
return self.as_any_ref().downcast_ref::<T>();
}
/// @brief 查找文件(不考虑符号链接)
///
/// @param path 文件路径
///
/// @return Ok(Arc<dyn IndexNode>) 要寻找的目录项的inode
/// @return Err(i32) 错误码
pub fn lookup(&self, path: &str) -> Result<Arc<dyn IndexNode>, i32> {
return self.lookup_follow_symlink(path, 0);
}
/// @brief 查找文件(考虑符号链接)
///
/// @param path 文件路径
/// @param max_follow_times 最大经过的符号链接的大小
///
/// @return Ok(Arc<dyn IndexNode>) 要寻找的目录项的inode
/// @return Err(i32) 错误码
pub fn lookup_follow_symlink(
&self,
path: &str,
max_follow_times: usize,
) -> Result<Arc<dyn IndexNode>, i32> {
if self.metadata()?.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 处理绝对路径
// result: 上一个被找到的inode
// rest_path: 还没有查找的路径
let (mut result, mut rest_path) = if let Some(rest) = path.strip_prefix('/') {
(ROOT_INODE().clone(), String::from(rest))
} else {
// 是相对路径
(self.find(".")?, String::from(path))
};
// 逐级查找文件
while !rest_path.is_empty() {
// 当前这一级不是文件夹
if result.metadata()?.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
let name;
// 寻找“/”
match rest_path.find('/') {
Some(pos) => {
// 找到了,设置下一个要查找的名字
name = String::from(&rest_path[0..pos]);
// 剩余的路径字符串
rest_path = String::from(&rest_path[pos + 1..]);
}
None => {
name = rest_path;
rest_path = String::new();
}
}
// 遇到连续多个"/"的情况
if name.is_empty() {
continue;
}
let inode = result.find(&name)?;
// 处理符号链接的问题
if inode.metadata()?.file_type == FileType::SymLink && max_follow_times > 0 {
let mut content = [0u8; 256];
// 读取符号链接
let len = inode.read_at(0, 256, &mut content, &mut FilePrivateData::Unused)?;
// 将读到的数据转换为utf8字符串先转为str再转为String
let link_path = String::from(
::core::str::from_utf8(&content[..len]).map_err(|_| -(ENOTDIR as i32))?,
);
let new_path = link_path + "/" + &rest_path;
// 继续查找符号链接
return result.lookup_follow_symlink(&new_path, max_follow_times - 1);
} else {
result = inode;
}
}
return Ok(result);
}
}
/// IndexNode的元数据
///
/// 对应Posix2008中的sys/stat.h中的定义 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Metadata {
/// 当前inode所在的文件系统的设备号
pub dev_id: usize,
/// inode号
pub inode_id: InodeId,
/// Inode的大小
/// 文件:文件大小(单位:字节)
/// 目录:目录项中的文件、文件夹数量
pub size: i64,
/// Inode所在的文件系统中每个块的大小
pub blk_size: usize,
/// Inode所占的块的数目
pub blocks: usize,
/// inode最后一次被访问的时间
pub atime: TimeSpec,
/// inode最后一次修改的时间
pub mtime: TimeSpec,
/// inode的创建时间
pub ctime: TimeSpec,
/// 文件类型
pub file_type: FileType,
/// 权限
pub mode: u32,
/// 硬链接的数量
pub nlinks: usize,
/// User ID
pub uid: usize,
/// Group ID
pub gid: usize,
/// 文件指向的设备的id对于设备文件系统来说
pub raw_dev: usize,
}
/// @brief 所有文件系统都应该实现的trait
pub trait FileSystem: Any + Sync + Send + Debug {
/// @brief 获取当前文件系统的root inode的指针
fn root_inode(&self) -> Arc<dyn IndexNode>;
/// @brief 获取当前文件系统的信息
fn info(&self) -> FsInfo;
/// @brief 本函数用于实现动态转换。
/// 具体的文件系统在实现本函数时最简单的方式就是直接返回self
fn as_any_ref(&self) -> &dyn Any;
}
#[derive(Debug)]
pub struct FsInfo {
/// 文件系统所在的块设备的id
pub blk_dev_id: usize,
/// 文件名的最大长度
pub max_name_len: usize,
}
/// @brief 整合主设备号+次设备号
pub fn make_rawdev(major: usize, minor: usize) -> usize {
((major & 0xffffff) << 8) | (minor & 0xff)
}
/// @brief
#[repr(C)]
#[derive(Debug)]
pub struct Dirent {
d_ino: u64, // 文件序列号
d_off: i64, // dir偏移量
d_reclen: u16, // 目录下的记录数
d_type: u8, // entry的类型
d_name: u8, // 文件entry的名字(是一个零长数组) 本字段仅用于占位
}

View File

@ -1,99 +0,0 @@
#include "mount.h"
#include "VFS.h"
#include <common/glib.h>
#include <common/string.h>
static struct List mnt_list_head; // 挂载点链表头
/**
* @brief 初始化mount机制
*
* @return int 错误码
*/
int mount_init()
{
list_init(&mnt_list_head);
return 0;
}
/**
* @brief 将new_dentry挂载
*
* @param old_dentry 挂载点的dentry
* @param new_dentry 待挂载的新的dentry(需使用vfs_alloc_dentry来分配)
* @return int 错误码
*/
int do_mount(struct vfs_dir_entry_t *old_dentry, struct vfs_dir_entry_t *new_dentry)
{
struct mountpoint *mp = (struct mountpoint *)kzalloc(sizeof(struct mountpoint), 0);
list_init(&mp->mnt_list);
mp->dentry = old_dentry;
mp->parent_dentry = old_dentry->parent;
// 拷贝名称
strncpy(new_dentry->name, old_dentry->name, old_dentry->name_length);
kdebug("new_dentry->name=%s, old_dentry->name=%s, old_dentry->name_length=%d", new_dentry->name, old_dentry->name, old_dentry->name_length);
new_dentry->d_flags |= VFS_DF_MOUNTED; // 标记新的dentry是一个挂载点
list_init(&new_dentry->child_node_list);
list_init(&new_dentry->subdirs_list);
new_dentry->parent = old_dentry->parent;
// 将新的dentry的list结点替换掉父dentry的列表中的old_dentry的list结点
list_replace(&old_dentry->child_node_list, &new_dentry->child_node_list);
// 后挂载的dentry在链表的末尾umount恢复的时候需要依赖这个性质
list_append(&mnt_list_head, &mp->mnt_list);
return 0;
}
/**
* @brief 取消某个文件系统的挂载
*
* @param dentry 对应文件系统的根dentry
* @return int 错误码
*/
int do_umount(struct vfs_dir_entry_t *dentry)
{
// todo: 实现umount主要是结点的恢复问题
return 0;
}
/**
* @brief 根据mountpoint的父目录dentry查找第一个符合条件的mountpoint结构体
*
* @param dentry 父dentry
* @return struct mountpoint* 第一个符合条件的mountpoint结构体的指针
*/
struct mountpoint *mount_find_mnt_list_by_parent(struct vfs_dir_entry_t *dentry)
{
struct List *list = &mnt_list_head;
struct mountpoint *ret = NULL;
if (list_empty(list))
return NULL;
while (list_next(list) != &mnt_list_head)
{
list = list_next(list);
struct mountpoint *tmp = container_of(list, struct mountpoint, mnt_list);
if (dentry == tmp->parent_dentry)
return tmp;
}
return NULL;
}
/**
* @brief 将挂载点结构体从链表中删除并释放
*
* @param mp mountpoint结构体
* @return int 错误码
*/
int mount_release_mountpoint(struct mountpoint *mp)
{
list_del(&mp->mnt_list);
return kfree(mp);
}

View File

@ -1,76 +0,0 @@
#pragma once
#include <common/glib.h>
#include "VFS.h"
/**
* @brief 挂载点结构体(用来表示dentry被挂载其他文件系统之后原先存在的数据)
*
*/
struct mountpoint
{
struct List mnt_list; // 挂载点串在一起的链表
struct vfs_dir_entry_t *dentry; // 被挂载前,当前目录项的dentry
struct vfs_dir_entry_t *parent_dentry; // 被挂载前,父目录项的dentry
};
/**
* @brief 初始化mount机制
*
* @return int 错误码
*/
int mount_init();
/**
* @brief 将new_dentry挂载
*
* @param old_dentry 挂载点的dentry
* @param new_dentry 待挂载的新的dentry(需使用vfs_alloc_dentry来分配)
* @return int 错误码
*/
int do_mount(struct vfs_dir_entry_t *old_dentry, struct vfs_dir_entry_t *new_dentry);
/**
* @brief 取消某个文件系统的挂载
*
* @param dentry 对应文件系统的根dentry
* @return int 错误码
*/
int do_umount(struct vfs_dir_entry_t *dentry);
// 判断dentry是否是一个挂载点
#define D_MOUNTED(x) ((x)->d_flags & VFS_DF_MOUNTED)
/**
* @brief 将给定的dentry标记为“不可挂载”
*
* @param dentry 目标dentry
*/
static inline void dont_mount(struct vfs_dir_entry_t *dentry)
{
// todo: 对dentry加锁
dentry->d_flags |= VFS_DF_CANNOT_MOUNT;
}
static inline void detach_mounts(struct vfs_dir_entry_t *dentry)
{
if (!D_MOUNTED(dentry))
return; // 如果当前文件夹不是一个挂载点,则直接返回
// todo:如果当前文件夹是一个挂载点则对同样挂载在当前文件夹下的dentry进行清理。以免造成内存泄露
// 可参考 linux5.17或以上的detach_mounts()函数
}
/**
* @brief 根据mountpoint的父目录dentry查找第一个符合条件的mountpoint结构体
*
* @param dentry 父dentry
* @return struct mountpoint* 第一个符合条件的mountpoint结构体的指针
*/
struct mountpoint *mount_find_mnt_list_by_parent(struct vfs_dir_entry_t *dentry);
/**
* @brief 释放挂载点结构体
*
* @param mp mountpoint结构体
* @return int 错误码
*/
int mount_release_mountpoint(struct mountpoint* mp);

View File

@ -0,0 +1,365 @@
use core::any::Any;
use alloc::{
collections::BTreeMap,
sync::{Arc, Weak},
};
use crate::{
include::bindings::bindings::{EBUSY, ENOTDIR},
libs::spinlock::SpinLock, kdebug,
};
use super::{FilePrivateData, FileSystem, FileType, IndexNode, InodeId};
/// @brief 挂载文件系统
/// 挂载文件系统的时候套了MountFS这一层以实现文件系统的递归挂载
#[derive(Debug)]
pub struct MountFS {
// MountFS内部的文件系统
inner_filesystem: Arc<dyn FileSystem>,
/// 用来存储InodeID->挂载点的MountFS的B树
mountpoints: SpinLock<BTreeMap<InodeId, Arc<MountFS>>>,
/// 当前文件系统挂载到的那个挂载点的Inode
self_mountpoint: Option<Arc<MountFSInode>>,
/// 指向当前MountFS的弱引用
self_ref: Weak<MountFS>,
}
/// @brief MountFS的Index Node 注意这个IndexNode只是一个中间层。它的目的是将具体文件系统的Inode与挂载机制连接在一起。
#[derive(Debug)]
pub struct MountFSInode {
/// 当前挂载点对应到具体的文件系统的Inode
inner_inode: Arc<dyn IndexNode>,
/// 当前Inode对应的MountFS
mount_fs: Arc<MountFS>,
/// 指向自身的弱引用
self_ref: Weak<MountFSInode>,
}
impl MountFS {
pub fn new(
inner_fs: Arc<dyn FileSystem>,
self_mountpoint: Option<Arc<MountFSInode>>,
) -> Arc<Self> {
return MountFS {
inner_filesystem: inner_fs,
mountpoints: SpinLock::new(BTreeMap::new()),
self_mountpoint: self_mountpoint,
self_ref: Weak::default(),
}
.wrap();
}
/// @brief 用Arc指针包裹MountFS对象。
/// 本函数的主要功能为初始化MountFS对象中的自引用Weak指针
/// 本函数只应在构造器中被调用
fn wrap(self) -> Arc<Self> {
// 创建Arc指针
let mount_fs: Arc<MountFS> = Arc::new(self);
// 创建weak指针
let weak: Weak<MountFS> = Arc::downgrade(&mount_fs);
// 将Arc指针转为Raw指针并对其内部的self_ref字段赋值
let ptr: *mut MountFS = Arc::into_raw(mount_fs) as *mut Self;
unsafe {
(*ptr).self_ref = weak;
// 返回初始化好的MountFS对象
return Arc::from_raw(ptr);
}
}
/// @brief 获取挂载点的文件系统的root inode
pub fn mountpoint_root_inode(&self) -> Arc<MountFSInode> {
return MountFSInode {
inner_inode: self.inner_filesystem.root_inode(),
mount_fs: self.self_ref.upgrade().unwrap(),
self_ref: Weak::default(),
}
.wrap();
}
pub fn inner_filesystem(&self) -> Arc<dyn FileSystem> {
return self.inner_filesystem.clone();
}
}
impl MountFSInode {
/// @brief 用Arc指针包裹MountFSInode对象。
/// 本函数的主要功能为初始化MountFSInode对象中的自引用Weak指针
/// 本函数只应在构造器中被调用
fn wrap(self) -> Arc<Self> {
// 创建Arc指针
let inode: Arc<MountFSInode> = Arc::new(self);
// 创建Weak指针
let weak: Weak<MountFSInode> = Arc::downgrade(&inode);
// 将Arc指针转为Raw指针并对其内部的self_ref字段赋值
let ptr: *mut MountFSInode = Arc::into_raw(inode) as *mut Self;
unsafe {
(*ptr).self_ref = weak;
// 返回初始化好的MountFSInode对象
return Arc::from_raw(ptr);
}
}
/// @brief 判断当前inode是否为它所在的文件系统的root inode
fn is_mountpoint_root(&self) -> Result<bool, i32> {
return Ok(self.inner_inode.fs().root_inode().metadata()?.inode_id
== self.inner_inode.metadata()?.inode_id);
}
/// @brief 在挂载树上进行inode替换。
/// 如果当前inode是父MountFS内的一个挂载点那么本函数将会返回挂载到这个挂载点下的文件系统的root inode.
/// 如果当前inode在父MountFS内但不是挂载点那么说明在这里不需要进行inode替换因此直接返回当前inode。
///
/// @return Arc<MountFSInode>
fn overlaid_inode(&self) -> Arc<MountFSInode> {
let inode_id = self.metadata().unwrap().inode_id;
if let Some(sub_mountfs) = self.mount_fs.mountpoints.lock().get(&inode_id) {
return sub_mountfs.mountpoint_root_inode();
} else {
return self.self_ref.upgrade().unwrap();
}
}
}
impl IndexNode for MountFSInode {
fn open(&self, data: &mut FilePrivateData) -> Result<(), i32> {
return self.inner_inode.open(data);
}
fn close(&self, data: &mut FilePrivateData) -> Result<(), i32> {
return self.inner_inode.close(data);
}
fn create_with_data(
&self,
name: &str,
file_type: FileType,
mode: u32,
data: usize,
) -> Result<Arc<dyn IndexNode>, i32> {
return self
.inner_inode
.create_with_data(name, file_type, mode, data);
}
fn truncate(&self, len: usize) -> Result<(), i32> {
return self.inner_inode.truncate(len);
}
fn read_at(
&self,
offset: usize,
len: usize,
buf: &mut [u8],
data: &mut FilePrivateData,
) -> Result<usize, i32> {
return self
.inner_inode
.read_at(offset, len, buf, data);
}
fn write_at(
&self,
offset: usize,
len: usize,
buf: &[u8],
_data: &mut FilePrivateData,
) -> Result<usize, i32> {
return self
.inner_inode
.write_at(offset, len, buf, &mut FilePrivateData::Unused);
}
#[inline]
fn poll(&self) -> Result<super::PollStatus, i32> {
return self.inner_inode.poll();
}
#[inline]
fn fs(&self) -> Arc<dyn FileSystem> {
return self.mount_fs.clone();
}
#[inline]
fn as_any_ref(&self) -> &dyn core::any::Any {
return self.inner_inode.as_any_ref();
}
#[inline]
fn metadata(&self) -> Result<super::Metadata, i32> {
return self.inner_inode.metadata();
}
#[inline]
fn set_metadata(&self, metadata: &super::Metadata) -> Result<(), i32> {
return self.inner_inode.set_metadata(metadata);
}
#[inline]
fn resize(&self, len: usize) -> Result<(), i32> {
return self.inner_inode.resize(len);
}
#[inline]
fn create(
&self,
name: &str,
file_type: FileType,
mode: u32,
) -> Result<Arc<dyn IndexNode>, i32> {
return Ok(MountFSInode {
inner_inode: self.inner_inode.create(name, file_type, mode)?,
mount_fs: self.mount_fs.clone(),
self_ref: Weak::default(),
}
.wrap());
}
fn link(&self, name: &str, other: &Arc<dyn IndexNode>) -> Result<(), i32> {
return self.inner_inode.link(name, other);
}
/// @brief 在挂载文件系统中删除文件/文件夹
#[inline]
fn unlink(&self, name: &str) -> Result<(), i32> {
let inode_id = self.inner_inode.find(name)?.metadata()?.inode_id;
// 先检查这个inode是否为一个挂载点如果当前inode是一个挂载点那么就不能删除这个inode
if self.mount_fs.mountpoints.lock().contains_key(&inode_id) {
return Err(-(EBUSY as i32));
}
// 调用内层的inode的方法来删除这个inode
return self.inner_inode.unlink(name);
}
#[inline]
fn rmdir(&self, name: &str) ->Result<(), i32> {
let inode_id = self.inner_inode.find(name)?.metadata()?.inode_id;
kdebug!("rmdir {name}");
// 先检查这个inode是否为一个挂载点如果当前inode是一个挂载点那么就不能删除这个inode
if self.mount_fs.mountpoints.lock().contains_key(&inode_id) {
return Err(-(EBUSY as i32));
}
// 调用内层的rmdir的方法来删除这个inode
let r = self.inner_inode.rmdir(name);
kdebug!("r={r:?}");
return r;
}
#[inline]
fn move_(
&self,
old_name: &str,
target: &Arc<dyn IndexNode>,
new_name: &str,
) -> Result<(), i32> {
return self.inner_inode.move_(old_name, target, new_name);
}
fn find(&self, name: &str) -> Result<Arc<dyn IndexNode>, i32> {
match name {
// 查找的是当前目录
"" | "." => return Ok(self.self_ref.upgrade().unwrap()),
// 往父级查找
".." => {
if self.is_mountpoint_root()? {
// 当前inode是它所在的文件系统的root inode
match &self.mount_fs.self_mountpoint {
Some(inode) => {
return inode.find(name);
}
None => {
return Ok(self.self_ref.upgrade().unwrap());
}
}
} else {
// 向上查找时不会跨过文件系统的边界因此直接调用当前inode所在的文件系统的find方法进行查找
return Ok(MountFSInode {
inner_inode: self.inner_inode.find(name)?,
mount_fs: self.mount_fs.clone(),
self_ref: Weak::default(),
}
.wrap());
}
}
// 在当前目录下查找
_ => {
// 直接调用当前inode所在的文件系统的find方法进行查找
// 由于向下查找可能会跨越文件系统的边界因此需要尝试替换inode
return Ok(MountFSInode {
inner_inode: self.inner_inode.find(name)?,
mount_fs: self.mount_fs.clone(),
self_ref: Weak::default(),
}
.wrap()
.overlaid_inode());
}
}
}
#[inline]
fn get_entry_name(&self, ino: InodeId) -> Result<alloc::string::String, i32> {
return self.inner_inode.get_entry_name(ino);
}
#[inline]
fn get_entry_name_and_metadata(
&self,
ino: InodeId,
) -> Result<(alloc::string::String, super::Metadata), i32> {
return self.inner_inode.get_entry_name_and_metadata(ino);
}
#[inline]
fn ioctl(&self, cmd: u32, data: usize) -> Result<usize, i32> {
return self.inner_inode.ioctl(cmd, data);
}
#[inline]
fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, i32> {
return self.inner_inode.list();
}
/// @brief 在当前inode下挂载一个文件系统
///
/// @return Ok(Arc<MountFS>) 挂载成功返回指向MountFS的指针
fn mount(&self, fs: Arc<dyn FileSystem>) -> Result<Arc<MountFS>, i32> {
let metadata = self.inner_inode.metadata()?;
if metadata.file_type != FileType::Dir {
return Err(-(ENOTDIR as i32));
}
// 为新的挂载点创建挂载文件系统
let new_mount_fs: Arc<MountFS> = MountFS::new(fs, Some(self.self_ref.upgrade().unwrap()));
// 将新的挂载点-挂载文件系统添加到父级的挂载树
self.mount_fs
.mountpoints
.lock()
.insert(metadata.inode_id, new_mount_fs.clone());
return Ok(new_mount_fs);
}
}
impl FileSystem for MountFS {
fn root_inode(&self) -> Arc<dyn IndexNode> {
match &self.self_mountpoint {
Some(inode) => return inode.mount_fs.root_inode(),
// 当前文件系统是rootfs
None => self.mountpoint_root_inode(),
}
}
fn info(&self) -> super::FsInfo {
return self.inner_filesystem.info();
}
/// @brief 本函数用于实现动态转换。
/// 具体的文件系统在实现本函数时最简单的方式就是直接返回self
fn as_any_ref(&self) -> &dyn Any {
self
}
}

View File

@ -0,0 +1,352 @@
use core::ffi::{c_char, CStr};
use alloc::{
boxed::Box,
string::{String, ToString},
};
use crate::{
arch::asm::{current::current_pcb, ptrace::user_mode},
include::bindings::bindings::{
pt_regs, verify_area, AT_REMOVEDIR, EBADF, EFAULT, EINVAL, ENAMETOOLONG, ENOENT, ENOTDIR,
EPERM, PAGE_2M_SIZE, PAGE_4K_SIZE, PROC_MAX_FD_NUM, SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET,
},
io::SeekFrom,
kdebug, kerror,
};
use super::{
core::{do_lseek, do_mkdir, do_open, do_read, do_remove_dir, do_unlink_at, do_write},
file::{File, FileMode},
Dirent, FileType, ROOT_INODE,
};
/// @brief 打开文件
///
/// @param regs->r8 path 文件路径
/// @param regs->r9 o_flags 打开文件的标志位
///
/// @return u64 文件描述符编号,或者是错误码
#[no_mangle]
pub extern "C" fn sys_open(regs: &pt_regs) -> u64 {
let path: &CStr = unsafe { CStr::from_ptr(regs.r8 as usize as *const c_char) };
let path: Result<&str, core::str::Utf8Error> = path.to_str();
if path.is_err() {
return (-(EINVAL as i32)) as u64;
}
let path: &str = path.unwrap();
let flags = regs.r9;
let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32);
let r: Result<i32, i32> = do_open(path, open_flags);
if r.is_ok() {
return r.unwrap() as u64;
} else {
return r.unwrap_err() as u64;
}
}
/// @brief 关闭文件的系统调用函数
///
/// @param regs->r8 fd文件描述符编号
#[no_mangle]
pub extern "C" fn sys_close(regs: &pt_regs) -> u64 {
let fd = regs.r8 as i32;
let r: Result<(), i32> = current_pcb().drop_fd(fd);
if r.is_ok() {
return 0;
} else {
return r.unwrap_err() as u64;
}
}
/// @brief 读取文件的系统调用函数
///
/// @param regs->r8 文件描述符编号
/// @param regs->r9 输出缓冲区
/// @param regs->r10 要读取的长度
#[no_mangle]
pub extern "C" fn sys_read(regs: &pt_regs) -> u64 {
let fd = regs.r8 as i32;
let buf_vaddr = regs.r9 as usize;
let len = regs.r10 as usize;
// 判断缓冲区是否来自用户态,进行权限校验
if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } {
// 来自用户态而buffer在内核态这样的操作不被允许
return (-(EPERM as i32)) as u64;
}
let buf: &mut [u8] =
unsafe { core::slice::from_raw_parts_mut::<'static, u8>(buf_vaddr as *mut u8, len) };
let r: Result<usize, i32> = do_read(fd, buf);
if r.is_ok() {
return r.unwrap() as u64;
} else {
return r.unwrap_err() as u64;
}
}
/// @brief 向文件写入数据的系统调用函数
///
/// @param regs->r8 文件描述符编号
/// @param regs->r9 输入缓冲区
/// @param regs->r10 要写入的长度
#[no_mangle]
pub extern "C" fn sys_write(regs: &pt_regs) -> u64 {
let fd = regs.r8 as i32;
let buf_vaddr = regs.r9 as usize;
let len = regs.r10 as usize;
// 判断缓冲区是否来自用户态,进行权限校验
if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } {
// 来自用户态而buffer在内核态这样的操作不被允许
return (-(EPERM as i32)) as u64;
}
let buf: &[u8] =
unsafe { core::slice::from_raw_parts::<'static, u8>(buf_vaddr as *mut u8, len) };
let r: Result<usize, i32> = do_write(fd, buf);
if r.is_ok() {
return r.unwrap() as u64;
} else {
return r.unwrap_err() as u64;
}
}
/// @brief 调整文件访问指针位置的系统调用函数
///
/// @param regs->r8 文件描述符编号
/// @param regs->r9 调整偏移量
/// @param regs->r10 调整的模式
#[no_mangle]
pub extern "C" fn sys_lseek(regs: &pt_regs) -> u64 {
let fd = regs.r8 as i32;
let offset = regs.r9 as i64;
let whence = regs.r10 as u32;
let w: SeekFrom = match whence {
SEEK_SET => SeekFrom::SeekSet(offset),
SEEK_CUR => SeekFrom::SeekCurrent(offset),
SEEK_END => SeekFrom::SeekEnd(offset),
SEEK_MAX => SeekFrom::SeekEnd(0),
_ => return (-(EINVAL as i32)) as u64,
};
let r: Result<usize, i32> = do_lseek(fd, w);
if r.is_ok() {
return r.unwrap() as u64;
} else {
return r.unwrap_err() as u64;
}
}
/// @brief 切换工作目录
///
/// @param dest_path 目标路径
///
/// @return 返回码 描述
/// 0 | 成功
///
/// EACCESS | 权限不足
///
/// ELOOP | 解析path时遇到路径循环
///
/// ENAMETOOLONG | 路径名过长
///
/// ENOENT | 目标文件或目录不存在
///
/// ENODIR | 检索期间发现非目录项
///
/// ENOMEM | 系统内存不足
///
/// EFAULT | 错误的地址
///
/// ENAMETOOLONG | 路径过长
#[no_mangle]
pub extern "C" fn sys_chdir(regs: &pt_regs) -> u64 {
if regs.r8 == 0 {
return -(EFAULT as i32) as u64;
}
let ptr = regs.r8 as usize as *const c_char;
// 权限校验
if ptr.is_null()
|| (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
{
return -(EINVAL as i32) as u64;
}
let dest_path: &CStr = unsafe { CStr::from_ptr(ptr) };
let dest_path: Result<&str, core::str::Utf8Error> = dest_path.to_str();
if dest_path.is_err() {
return (-(EINVAL as i32)) as u64;
}
let dest_path: &str = dest_path.unwrap();
kdebug!("chdir: dest_path={dest_path}");
if dest_path.len() == 0 {
return (-(EINVAL as i32)) as u64;
} else if dest_path.len() >= PAGE_4K_SIZE as usize {
return (-(ENAMETOOLONG as i32)) as u64;
}
let path = Box::new(dest_path.clone());
let inode = match ROOT_INODE().lookup(&path) {
Err(e) => {
kerror!("Change Directory Failed, Error = {}", e);
return (-(ENOENT as i32)) as u64;
}
Ok(i) => i,
};
match inode.metadata() {
Err(e) => {
kerror!("INode Get MetaData Failed, Error = {}", e);
return (-(ENOENT as i32)) as u64;
}
Ok(i) => {
if let FileType::Dir = i.file_type {
return 0;
} else {
return (-(ENOTDIR as i32)) as u64;
}
}
}
}
/// @brief 获取目录中的数据
///
/// @param fd 文件描述符号
/// @return uint64_t dirent的总大小
#[no_mangle]
pub extern "C" fn sys_getdents(regs: &pt_regs) -> u64 {
let fd = regs.r8 as i32;
let count = regs.r10 as i64;
let dirent = match unsafe { (regs.r9 as usize as *mut Dirent).as_mut() } {
None => {
return 0;
}
Some(dirent) => dirent,
};
if fd < 0 || fd as u32 > PROC_MAX_FD_NUM {
return (-(EBADF as i32)) as u64;
}
if count < 0 {
return (-(EINVAL as i32)) as u64;
}
// 获取fd
let file: &mut File = match current_pcb().get_file_mut_by_fd(fd) {
None => {
return (-(EBADF as i32)) as u64;
}
Some(file) => file,
};
// kdebug!("file={file:?}");
return match file.readdir(dirent) {
Err(_) => 0,
Ok(len) => len,
};
}
/// @brief 创建文件夹
///
/// @param path(r8) 路径 / mode(r9) 模式
///
/// @return uint64_t 负数错误码 / 0表示成功
#[no_mangle]
pub extern "C" fn sys_mkdir(regs: &pt_regs) -> u64 {
let ptr = regs.r8 as usize as *const c_char;
if ptr.is_null()
|| (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
{
return -(EINVAL as i32) as u64;
}
let path: &CStr = unsafe { CStr::from_ptr(ptr) };
let path: Result<&str, core::str::Utf8Error> = path.to_str();
let mode = regs.r9;
if path.is_err() {
return (-(EINVAL as i32)) as u64;
}
let path = &path.unwrap().to_string();
if path.trim() == "" {
return (-(EINVAL as i32)) as u64;
}
return match do_mkdir(&path, FileMode::from_bits_truncate(mode as u32)) {
Err(err) => {
kerror!("Failed in do_mkdir, Error Code = {}", err);
err as u64
}
Ok(_) => 0,
};
}
///@brief 删除文件夹、取消文件的链接、删除文件的系统调用
///
///@param regs->r8 dfd 进程相对路径基准目录的文件描述符(见fcntl.h)
///
///@param regs->r9 路径名称字符串
///
///@param regs->r10 flag 预留的标志位暂时未使用请置为0。
///
///@return uint64_t 错误码
#[no_mangle]
pub extern "C" fn sys_unlink_at(regs: &pt_regs) -> u64 {
let _dfd = regs.r8;
let ptr = regs.r9 as usize as *const c_char;
if ptr.is_null()
|| (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
{
return -(EINVAL as i32) as u64;
}
let path: &CStr = unsafe { CStr::from_ptr(ptr) };
let path: Result<&str, core::str::Utf8Error> = path.to_str();
let flag = regs.r10;
if path.is_err() {
return (-(EINVAL as i32)) as u64;
}
let path = &path.unwrap().to_string();
// kdebug!("sys_unlink_at={path:?}");
if (flag & (!(AT_REMOVEDIR as u64))) != 0_u64 {
return (-(EINVAL as i32)) as u64;
}
if (flag & (AT_REMOVEDIR as u64)) > 0 {
// kdebug!("rmdir");
match do_remove_dir(&path) {
Err(err) => {
kerror!("Failed to Remove Directory, Error Code = {}", err);
return err as u64;
}
Ok(_) => {
return 0;
}
}
}
// kdebug!("rm");
match do_unlink_at(&path, FileMode::from_bits_truncate(flag as u32)) {
Err(err) => {
kerror!("Failed to Remove Directory, Error Code = {}", err);
return err as u64;
}
Ok(_) => {
return 0;
}
}
}

View File

@ -0,0 +1,21 @@
/// @brief 切分路径字符串,返回最左侧那一级的目录名和剩余的部分。
///
/// 举例:对于 /123/456/789/ 本函数返回的第一个值为123, 第二个值为456/789
pub fn split_path(path: &str) -> (&str, Option<&str>) {
let mut path_split: core::str::SplitN<&str> = path.trim_matches('/').splitn(2, "/");
let comp = path_split.next().unwrap_or("");
let rest_opt = path_split.next();
return (comp, rest_opt);
}
/// @brief 切分路径字符串,返回最右侧那一级的目录名和剩余的部分。
///
/// 举例:对于 /123/456/789/ 本函数返回的第一个值为789, 第二个值为123/456
pub fn rsplit_path(path: &str) -> (&str, Option<&str>) {
let mut path_split: core::str::RSplitN<&str> = path.trim_matches('/').rsplitn(2, "/");
let comp = path_split.next().unwrap_or("");
let rest_opt = path_split.next();
return (comp, rest_opt);
}

View File

@ -25,9 +25,13 @@
#include <common/lz4.h>
#include <common/printk.h>
#include <common/spinlock.h>
#include <common/stdio.h>
#include <common/time.h>
#include <common/unistd.h>
#include <common/string.h>
#include <driver/disk/ahci/ahci.h>
#include <driver/disk/ahci/ahci_rust.h>
#include <driver/pci/pci.h>
#include <include/DragonOS/refcount.h>
#include <include/DragonOS/signal.h>
#include <mm/mm.h>

View File

@ -1,15 +0,0 @@
#include <common/kthread.h>
#include <io/block/block_io_scheduler.h>
#include <sched/sched.h>
#include <smp/smp.h>
/**
* @brief 初始化io调度器
*/
void block_io_scheduler_init()
{
// 使用rust中的函数进行初始化
block_io_scheduler_init_rust();
struct process_control_block *pcb = kthread_run(&block_io_scheduler_address_requests, NULL, "block_io_scheduler", NULL);
if (smp_get_total_cpu() > 1)
sched_migrate_process(pcb, 1);
}

View File

@ -1,9 +0,0 @@
#pragma once
extern void block_io_scheduler_address_requests();
extern void block_io_scheduler_init_rust();
/**
* @brief 初始化io调度器
*/
void block_io_scheduler_init();

View File

@ -1,304 +0,0 @@
use core::{ptr::null_mut, sync::atomic::compiler_fence};
use alloc::{boxed::Box, vec::Vec};
use crate::{
arch::mm::barrier::mfence,
include::bindings::bindings::{
ahci_check_complete, ahci_query_disk, ahci_request_packet_t, block_device_request_packet,
complete, completion, completion_alloc, wait_for_completion,
},
kBUG,
libs::spinlock::RawSpinlock,
};
#[derive(Debug)]
/// achi请求包
pub struct AhciRequestPacket {
pub ahci_ctrl_num: u8,
pub port_num: u8,
pub slot: i8,
}
impl AhciRequestPacket {
pub fn new() -> Self {
return AhciRequestPacket {
..Default::default()
};
}
}
impl Default for AhciRequestPacket {
fn default() -> Self {
AhciRequestPacket {
ahci_ctrl_num: 0,
port_num: Default::default(),
slot: -1,
}
}
}
#[derive(Debug)]
/// io请求包
pub struct BlockDeviceRequestPacket<T> {
pub cmd: u8,
pub lba_start: u64,
pub count: u32,
pub buffer_vaddr: u64,
pub device_type: u8, // 0: ahci
pub end_handler: ::core::option::Option<
unsafe extern "C" fn(num: ::core::ffi::c_ulong, arg: ::core::ffi::c_ulong),
>,
pub private_ahci_request_packet: T,
pub status: *mut completion,
}
impl<AhciRequestPacket> BlockDeviceRequestPacket<AhciRequestPacket> {
pub fn new(
ahci_request_packet: AhciRequestPacket,
) -> BlockDeviceRequestPacket<AhciRequestPacket> {
let cmpl: *mut completion = unsafe { completion_alloc() };
return BlockDeviceRequestPacket {
cmd: Default::default(),
lba_start: Default::default(),
count: Default::default(),
buffer_vaddr: Default::default(),
device_type: Default::default(),
end_handler: Default::default(),
private_ahci_request_packet: ahci_request_packet,
status: cmpl,
};
}
}
struct RequestQueue {
lock: RawSpinlock,
waiting_queue: Vec<BlockDeviceRequestPacket<AhciRequestPacket>>,
processing_queue: Vec<BlockDeviceRequestPacket<AhciRequestPacket>>,
}
impl RequestQueue {
pub fn new() -> RequestQueue {
RequestQueue {
lock: RawSpinlock::INIT,
waiting_queue: Vec::new(),
processing_queue: Vec::new(),
}
}
/// @brief 将请求包插入等待队列中
pub fn push_waiting_queue(
&mut self,
ahci_request_packet: BlockDeviceRequestPacket<AhciRequestPacket>,
) {
self.waiting_queue.push(ahci_request_packet);
}
/// @brief 将请求包从正在执行队列中弹出
pub fn pop_waiting_queue(&mut self) -> Option<BlockDeviceRequestPacket<AhciRequestPacket>> {
let mut res: Option<BlockDeviceRequestPacket<AhciRequestPacket>> = None;
if self.waiting_queue.len() == 0 {
return res;
}
res = Some(self.waiting_queue.remove(0));
return res;
}
/// @brief 将请求包插入正在执行队列中
pub fn push_processing_queue(
&mut self,
ahci_request_packet: BlockDeviceRequestPacket<AhciRequestPacket>,
) {
self.processing_queue.push(ahci_request_packet);
}
/// @brief 将请求包从正在执行队列中弹出
pub fn pop_processing_queue(&mut self) -> Option<BlockDeviceRequestPacket<AhciRequestPacket>> {
let mut res: Option<BlockDeviceRequestPacket<AhciRequestPacket>> = None;
if self.processing_queue.len() == 0 {
return res;
}
res = Some(self.processing_queue.remove(0));
return res;
}
/// @brief 将已完成请求包从执行队列中弹出
pub fn pop_finished_packets(&mut self) {
if self.processing_queue.len() != 0 {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
//将状态设置为完成
mfence();
// 过滤器,过滤已完成的请求包
let filter = |packet: &mut BlockDeviceRequestPacket<AhciRequestPacket>| {
//判断请求是否完成
let res = unsafe {
ahci_check_complete(
packet.private_ahci_request_packet.port_num,
packet.private_ahci_request_packet.ahci_ctrl_num,
packet.private_ahci_request_packet.slot,
null_mut(),
)
};
// 完成则complete请求包
if res == 0 {
unsafe {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
complete(packet.status);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
return true;
}
return false;
};
self.processing_queue.drain_filter(filter);
mfence();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
}
}
pub struct SchedulerIO {
io_queue: Vec<&'static mut RequestQueue>,
}
impl SchedulerIO {
pub fn new() -> SchedulerIO {
return SchedulerIO {
io_queue: Default::default(),
};
}
}
// io调度器全局指针
pub static mut IO_SCHEDULER_PTR: *mut SchedulerIO = null_mut();
#[inline]
pub fn __get_io_scheduler() -> &'static mut SchedulerIO {
return unsafe { IO_SCHEDULER_PTR.as_mut().unwrap() };
}
/// @brief 初始化io调度器
#[no_mangle]
pub unsafe extern "C" fn block_io_scheduler_init_rust() {
if IO_SCHEDULER_PTR.is_null() {
IO_SCHEDULER_PTR = Box::leak(Box::new(SchedulerIO::new()));
create_io_queue();
} else {
kBUG!("Try to init IO Scheduler twice.");
panic!("Try to init IO Scheduler twice.");
}
}
/// @brief 初始化io请求队列
#[no_mangle]
pub extern "C" fn create_io_queue() {
let io_scheduler = __get_io_scheduler();
io_scheduler
.io_queue
.push(Box::leak(Box::new(RequestQueue::new())));
}
#[no_mangle]
/// @brief 处理请求 (守护线程运行)
pub extern "C" fn block_io_scheduler_address_requests() {
let io_scheduler = __get_io_scheduler();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
//FIXME 暂时只考虑了一个io队列的情况
loop {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
//请不要修改下面三个循环的顺序
let size = io_scheduler.io_queue[0].waiting_queue.len();
for i in 0..16 {
// 正在运行队列大小限制为16
if i >= size || io_scheduler.io_queue[0].processing_queue.len() == 16 {
break;
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// if !io_scheduler.io_queue[0].lock.is_locked() {
io_scheduler.io_queue[0].lock.lock();
let mut packet = io_scheduler.io_queue[0].pop_waiting_queue().unwrap();
//将rust中的请求包转成c中的请求包
let mut ahci_packet: ahci_request_packet_t = convert_c_ahci_request(&packet);
let mut ret_slot: i8 = -1;
//分发请求包
unsafe {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
ahci_query_disk(&mut ahci_packet, &mut ret_slot);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
//获取请求运行的插槽
packet.private_ahci_request_packet.slot = ret_slot;
io_scheduler.io_queue[0].push_processing_queue(packet);
io_scheduler.io_queue[0].lock.unlock();
// }
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
//检查是否有完成的请求包
io_scheduler.io_queue[0].lock.lock();
io_scheduler.io_queue[0].pop_finished_packets();
io_scheduler.io_queue[0].lock.unlock();
mfence();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
}
pub fn convert_c_ahci_request(
pakcet: &BlockDeviceRequestPacket<AhciRequestPacket>,
) -> ahci_request_packet_t {
let ahci_packet: ahci_request_packet_t = ahci_request_packet_t {
ahci_ctrl_num: pakcet.private_ahci_request_packet.ahci_ctrl_num,
port_num: pakcet.private_ahci_request_packet.port_num,
blk_pak: block_device_request_packet {
LBA_start: pakcet.lba_start,
cmd: pakcet.cmd,
buffer_vaddr: pakcet.buffer_vaddr,
count: pakcet.count,
device_type: pakcet.device_type,
end_handler: pakcet.end_handler,
},
};
return ahci_packet;
}
/// @brief 将c中的ahci_request_packet_t转换成rust中的BlockDeviceRequestPacket<AhciRequestPacket>
pub fn create_ahci_request(
ahci_request_packet: &ahci_request_packet_t,
) -> BlockDeviceRequestPacket<AhciRequestPacket> {
let cmpl: *mut completion = unsafe { completion_alloc() };
let ahci_packet = AhciRequestPacket {
ahci_ctrl_num: ahci_request_packet.ahci_ctrl_num,
port_num: ahci_request_packet.port_num,
slot: -1,
};
let packet = BlockDeviceRequestPacket {
private_ahci_request_packet: ahci_packet,
buffer_vaddr: ahci_request_packet.blk_pak.buffer_vaddr,
cmd: ahci_request_packet.blk_pak.cmd,
count: ahci_request_packet.blk_pak.count,
device_type: ahci_request_packet.blk_pak.device_type,
end_handler: ahci_request_packet.blk_pak.end_handler,
lba_start: ahci_request_packet.blk_pak.LBA_start,
status: cmpl,
};
return packet;
}
#[no_mangle]
/// @brief 将ahci的io请求插入等待队列中
pub extern "C" fn ahci_push_request(ahci_request_packet: &ahci_request_packet_t) {
let packet = create_ahci_request(ahci_request_packet);
let io_scheduler = __get_io_scheduler();
let status = packet.status;
io_scheduler.io_queue[0].lock.lock();
io_scheduler.io_queue[0].push_waiting_queue(packet);
io_scheduler.io_queue[0].lock.unlock();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
unsafe {
wait_for_completion(status);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}

View File

@ -1 +1 @@
pub mod block_io_scheduler;
// pub mod block_io_scheduler;

323
kernel/src/io/device.rs Normal file
View File

@ -0,0 +1,323 @@
/// 引入Module
use crate::include::bindings::bindings::E2BIG;
use alloc::{sync::Arc, vec::Vec};
use core::{any::Any, fmt::Debug};
use super::disk_info::Partition;
/// 该文件定义了 Device 和 BlockDevice 的接口
/// Notice 设备错误码使用 Posix 规定的 int32_t 的错误码表示而不是自己定义错误enum
// 使用方法:
// 假设 blk_dev 是块设备
// <blk_dev as Device>::read_at() 调用的是Device的函数
// <blk_dev as BlockDevice>::read_at() 调用的是BlockDevice的函数
/// 定义类型
pub type BlockId = usize;
/// 定义常量
const BLK_SIZE_LOG2_LIMIT: u8 = 12; // 设定块设备的块大小不能超过 1 << 12.
/// 在DragonOS中我们认为磁盘的每个LBA大小均为512字节。注意文件系统的1个扇区可能事实上是多个LBA
pub const LBA_SIZE: usize = 512;
/// @brief 设备应该实现的操作
/// @usage Device::read_at()
pub trait Device: Any + Send + Sync + Debug {
/// Notice buffer对应设备按字节划分使用u8类型
/// Notice offset应该从0开始计数
/// @brief: 从设备的第offset个字节开始读取len个byte存放到buf中
/// @parameter offset: 起始字节偏移量
/// @parameter len: 读取字节的数量
/// @parameter buf: 目标数组
/// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
fn read_at(&self, offset: usize, len: usize, buf: &mut [u8]) -> Result<usize, i32>;
/// @brief: 从设备的第offset个字节开始把buf数组的len个byte写入到设备中
/// @parameter offset: 起始字节偏移量
/// @parameter len: 读取字节的数量
/// @parameter buf: 目标数组
/// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
fn write_at(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, i32>;
/// @brief: 同步信息把所有的dirty数据写回设备 - 待实现
fn sync(&self) -> Result<(), i32>;
// TODO: 待实现 open, close
}
/// @brief 块设备应该实现的操作
pub trait BlockDevice: Any + Send + Sync + Debug {
/// @brief: 在块设备中从第lba_id_start个块开始读取count个块数据存放到buf中
///
/// @parameter lba_id_start: 起始块
/// @parameter count: 读取块的数量
/// @parameter buf: 目标数组
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
/// 否则返回Err(错误码),其中错误码为负数;
/// 如果操作异常但是并没有检查出什么错误将返回Err(已操作的长度)
fn read_at(&self, lba_id_start: BlockId, count: usize, buf: &mut [u8]) -> Result<usize, i32>;
/// @brief: 在块设备中从第lba_id_start个块开始把buf中的count个块数据存放到设备中
/// @parameter lba_id_start: 起始块
/// @parameter count: 写入块的数量
/// @parameter buf: 目标数组
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
/// 否则返回Err(错误码),其中错误码为负数;
/// 如果操作异常但是并没有检查出什么错误将返回Err(已操作的长度)
fn write_at(&self, lba_id_start: BlockId, count: usize, buf: &[u8]) -> Result<usize, i32>;
/// @brief: 同步磁盘信息把所有的dirty数据写回硬盘 - 待实现
fn sync(&self) -> Result<(), i32>;
/// @breif: 每个块设备都必须固定自己块大小而且该块大小必须是2的幂次
/// @return: 返回一个固定量,硬编码(编程的时候固定的常量).
fn blk_size_log2(&self) -> u8;
// TODO: 待实现 open, close
/// @brief 本函数用于实现动态转换。
/// 具体的文件系统在实现本函数时最简单的方式就是直接返回self
fn as_any_ref(&self) -> &dyn Any;
/// @brief 本函数用于将BlockDevice转换为Device。
/// 由于实现了BlockDevice的结构体本身也实现了Device Trait, 因此转换是可能的。
/// 思路在BlockDevice的结构体中新增一个self_ref变量返回self_ref.upgrade()即可。
fn device(&self) -> Arc<dyn Device>;
/// @brief 返回块设备的块大小(单位:字节)
fn block_size(&self) -> usize;
/// @brief 返回当前磁盘上的所有分区的Arc指针数组
fn partitions(&self) -> Vec<Arc<Partition>>;
}
/// 对于所有<块设备>自动实现 Device Trait 的 read_at 和 write_at 函数
impl<T: BlockDevice> Device for T {
// 读取设备操作,读取设备内部 [offset, offset + buf.len) 区间内的字符,存放到 buf 中
fn read_at(&self, offset: usize, len: usize, buf: &mut [u8]) -> Result<usize, i32> {
if len > buf.len() {
return Err(-(E2BIG as i32));
}
let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
let multi = iter.multiblock;
// 枚举每一个range
for range in iter {
let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
let buf_end = range.origin_end() - offset;
let buf_slice = &mut buf[buf_begin..buf_end];
let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
let full = multi && range.is_multi() || !multi && range.is_full();
if full {
// 调用 BlockDevice::read_at() 直接把引用传进去不是把整个数组move进去
BlockDevice::read_at(self, range.lba_start, count, buf_slice)?;
} else {
// 判断块的长度不能超过最大值
if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
return Err(-(E2BIG as i32));
}
let mut temp = Vec::new();
temp.resize(1usize << self.blk_size_log2(), 0);
BlockDevice::read_at(self, range.lba_start, 1, &mut temp[..])?;
// 把数据从临时buffer复制到目标buffer
buf_slice.copy_from_slice(&temp[range.begin..range.end]);
}
}
return Ok(len);
}
/// 写入设备操作,把 buf 的数据写入到设备内部 [offset, offset + len) 区间内
fn write_at(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, i32> {
// assert!(len <= buf.len());
if len > buf.len() {
return Err(-(E2BIG as i32));
}
let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
let multi = iter.multiblock;
for range in iter {
let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
let buf_end = range.origin_end() - offset;
let buf_slice = &buf[buf_begin..buf_end];
let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
let full = multi && range.is_multi() || !multi && range.is_full();
if full {
BlockDevice::write_at(self, range.lba_start, count, buf_slice)?;
} else {
if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
return Err(-(E2BIG as i32));
}
let mut temp = Vec::new();
temp.resize(1usize << self.blk_size_log2(), 0);
// 由于块设备每次读写都是整块的,在不完整写入之前,必须把不完整的地方补全
BlockDevice::read_at(self, range.lba_start, 1, &mut temp[..])?;
// 把数据从临时buffer复制到目标buffer
temp[range.begin..range.end].copy_from_slice(&buf_slice);
BlockDevice::write_at(self, range.lba_start, 1, &temp[..])?;
}
}
return Ok(len);
}
/// 数据同步
fn sync(&self) -> Result<(), i32> {
BlockDevice::sync(self)
}
}
/// @brief 块设备的迭代器
/// @usage 某次操作读/写块设备的[L,R]范围内的字节,
/// 那么可以使用此结构体进行迭代遍历每次调用next()返回一个BlockRange
pub struct BlockIter {
pub begin: usize, // 迭代器的起始位置 -> 块设备的地址 (单位是字节)
pub end: usize,
pub blk_size_log2: u8,
pub multiblock: bool, // 是否启用连续整块同时遍历
}
/// @brief Range搭配迭代器BlockIter使用[L,R]区间被分割成多个小的Range
/// Range要么是整块要么是一块的某一部分
/// 细节: range = [begin, end) 左闭右开
pub struct BlockRange {
pub lba_start: usize, // 起始块的lba_id
pub lba_end: usize, // 终止块的lba_id
pub begin: usize, // 起始位置在块内的偏移量, 如果BlockIter启用Multiblock则是多个块的偏移量
pub end: usize, // 结束位置在块内的偏移量,单位是字节
pub blk_size_log2: u8,
}
impl BlockIter {
#[allow(dead_code)]
pub fn new(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter {
return BlockIter {
begin: start_addr,
end: end_addr,
blk_size_log2: blk_size_log2,
multiblock: false,
};
}
pub fn new_multiblock(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter {
return BlockIter {
begin: start_addr,
end: end_addr,
blk_size_log2: blk_size_log2,
multiblock: true,
};
}
/// 获取下一个整块或者不完整的块
pub fn next_block(&mut self) -> BlockRange {
let blk_size_log2 = self.blk_size_log2;
let blk_size = 1usize << self.blk_size_log2;
let lba_id = self.begin / blk_size;
let begin = self.begin % blk_size;
let end = if lba_id == self.end / blk_size {
self.end % blk_size
} else {
blk_size
};
self.begin += end - begin;
return BlockRange {
lba_start: lba_id,
lba_end: lba_id + 1,
begin: begin,
end: end,
blk_size_log2: blk_size_log2,
};
}
/// 如果能返回多个连续的整块则返回否则调用next_block()返回不完整的块
pub fn next_multiblock(&mut self) -> BlockRange {
let blk_size_log2 = self.blk_size_log2;
let blk_size = 1usize << self.blk_size_log2;
let lba_start = self.begin / blk_size;
let lba_end = self.end / blk_size;
// 如果不是整块,先返回非整块的小部分
if __bytes_to_lba(self.begin, blk_size)
!= __bytes_to_lba(self.begin + blk_size - 1, blk_size)
|| lba_start == lba_end
{
return self.next_block();
}
let begin = self.begin % blk_size; // 因为是多个整块这里必然是0
let end = __lba_to_bytes(lba_end, blk_size) - self.begin;
self.begin += end - begin;
return BlockRange {
lba_start: lba_start,
lba_end: lba_end,
begin: begin,
end: end,
blk_size_log2: blk_size_log2,
};
}
}
/// BlockIter 函数实现
impl Iterator for BlockIter {
type Item = BlockRange;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
if self.begin >= self.end {
return None;
}
if self.multiblock {
return Some(self.next_multiblock());
} else {
return Some(self.next_block());
}
}
}
/// BlockRange 函数实现
impl BlockRange {
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
return self.end == self.begin;
}
pub fn len(&self) -> usize {
return self.end - self.begin;
}
/// 判断是不是整块
pub fn is_full(&self) -> bool {
return self.len() == (1usize << self.blk_size_log2);
}
/// 判断是不是多个整块连在一起
pub fn is_multi(&self) -> bool {
return self.len() >= (1usize << self.blk_size_log2)
&& (self.len() % (1usize << self.blk_size_log2) == 0);
}
/// 获取 BlockRange 在块设备内部的起始位置 (单位是字节)
pub fn origin_begin(&self) -> usize {
return (self.lba_start << self.blk_size_log2) + self.begin;
}
/// 获取 BlockRange 在块设备内部的结尾位置 (单位是字节)
pub fn origin_end(&self) -> usize {
return (self.lba_start << self.blk_size_log2) + self.end;
}
}
/// 从字节地址转换到lba id
#[inline]
pub fn __bytes_to_lba(addr: usize, blk_size: usize) -> BlockId {
return addr / blk_size;
}
/// 从lba id转换到字节地址 返回lba_id的最左侧字节
#[inline]
pub fn __lba_to_bytes(lba_id: usize, blk_size: usize) -> BlockId {
return lba_id * blk_size;
}

View File

@ -0,0 +1,49 @@
#![allow(dead_code)]
use super::device::BlockDevice;
use alloc::sync::{Arc, Weak};
pub type SectorT = u64;
pub const BLK_TYPE_AHCI: u64 = 0;
pub const DISK_NAME_LEN: usize = 32; // 磁盘名称的最大长度
pub const BLK_GF_AHCI: u16 = 1 << 0; // 定义blk_gendisk中的标志位
/// @brief: 磁盘的分区信息 - (保留了c版本的数据信息)
#[derive(Debug)]
pub struct Partition {
pub start_sector: SectorT, // 该分区的起始扇区
pub lba_start: u64, // 起始LBA号
pub sectors_num: u64, // 该分区的扇区数
disk: Weak<dyn BlockDevice>, // 当前分区所属的磁盘
pub partno: u16, // 在磁盘上的分区号
// struct block_device_request_queue *bd_queue; // 请求队列
// struct vfs_superblock_t *bd_superblock; // 执行超级块的指针
}
/// @brief: 分区信息 - 成员函数
impl Partition {
/// @brief: 为 disk new 一个分区结构体
pub fn new(
start_sector: SectorT,
lba_start: u64,
sectors_num: u64,
disk: Weak<dyn BlockDevice>,
partno: u16,
) -> Arc<Self> {
return Arc::new(Partition {
start_sector,
lba_start,
sectors_num,
disk,
partno,
});
}
/// @brief 获取当前分区所属的磁盘的Arc指针
#[inline]
pub fn disk(&self) -> Arc<dyn BlockDevice> {
return self.disk.upgrade().unwrap();
}
}

View File

@ -1 +1,12 @@
pub mod block;
pub mod device;
pub mod disk_info;
#[derive(Debug)]
#[allow(dead_code)]
pub enum SeekFrom {
SeekSet(i64),
SeekCurrent(i64),
SeekEnd(i64),
Invalid,
}

View File

@ -1,10 +1,10 @@
all: pipe.o
all:
CFLAGS += -I .
pipe.o: pipe.c
$(CC) $(CFLAGS) -c pipe.c -o pipe.o
# pipe.o: pipe.c
# $(CC) $(CFLAGS) -c pipe.c -o pipe.o
clean:
echo "Done."

View File

@ -1,176 +0,0 @@
#include "pipe.h"
#include <common/spinlock.h>
#include <process/process.h>
#include <process/ptrace.h>
#include <filesystem/vfs/VFS.h>
#include <filesystem/fat32/fat32.h>
#include <common/atomic.h>
#include <mm/slab.h>
struct pipe_data_t
{
volatile unsigned int valid_cnt;
unsigned int read_pos;
unsigned int write_pos;
wait_queue_node_t read_wait_queue;
wait_queue_node_t write_wait_queue;
spinlock_t lock;
} __attribute__((packed));
// 由于kmalloc分配的内存是按照2^n对齐的因此我们需要这样来确定pipe的buffer大小以消除内部碎片
// 我们设定pipe的总大小为1024字节
#define PIPE_BUFF_SIZE (1024 - sizeof(struct pipe_data_t))
struct pipe_t
{
struct pipe_data_t data;
char buf[PIPE_BUFF_SIZE];
};
long pipe_read(struct vfs_file_t *file_ptr, char *buf,
int64_t count, long *position)
{
int i = 0;
struct pipe_t *pipe_ptr = NULL;
kdebug("pipe_read into!\n");
pipe_ptr = (struct pipe_t *)file_ptr->private_data;
spin_lock(&pipe_ptr->data.lock);
while (pipe_ptr->data.valid_cnt == 0)
{
/* pipe 空 */
kdebug("pipe_read empty!\n");
wait_queue_wakeup(&pipe_ptr->data.write_wait_queue, PROC_UNINTERRUPTIBLE);
wait_queue_sleep_on_unlock(&pipe_ptr->data.read_wait_queue, (void *)&pipe_ptr->data.lock);
spin_lock(&pipe_ptr->data.lock);
}
for (i = 0; i < pipe_ptr->data.valid_cnt; i++)
{
if (i == count)
{
break;
}
copy_to_user(buf + i, &pipe_ptr->buf[pipe_ptr->data.read_pos], sizeof(char));
pipe_ptr->data.read_pos = (pipe_ptr->data.read_pos + 1) % PIPE_BUFF_SIZE;
}
pipe_ptr->data.valid_cnt = pipe_ptr->data.valid_cnt - i;
spin_unlock(&pipe_ptr->data.lock);
wait_queue_wakeup(&pipe_ptr->data.write_wait_queue, PROC_UNINTERRUPTIBLE);
kdebug("pipe_read end!\n");
return i;
}
long pipe_write(struct vfs_file_t *file_ptr, char *buf,
int64_t count, long *position)
{
int i = 0;
struct pipe_t *pipe_ptr = NULL;
kdebug("pipe_write into!\n");
pipe_ptr = (struct pipe_t *)file_ptr->private_data;
spin_lock(&pipe_ptr->data.lock);
while (pipe_ptr->data.valid_cnt + count >= PIPE_BUFF_SIZE)
{
/* pipe 满 */
kdebug("pipe_write pipe full!\n");
wait_queue_wakeup(&pipe_ptr->data.read_wait_queue, PROC_UNINTERRUPTIBLE);
wait_queue_sleep_on_unlock(&pipe_ptr->data.write_wait_queue, (void *)&pipe_ptr->data.lock);
spin_lock(&pipe_ptr->data.lock);
}
for (i = pipe_ptr->data.valid_cnt; i < PIPE_BUFF_SIZE; i++)
{
if (i - pipe_ptr->data.valid_cnt == count)
{
break;
}
copy_from_user(&pipe_ptr->buf[pipe_ptr->data.write_pos], buf + i, sizeof(char));
pipe_ptr->data.write_pos = (pipe_ptr->data.write_pos + 1) % PIPE_BUFF_SIZE;
}
pipe_ptr->data.valid_cnt += count;
spin_unlock(&pipe_ptr->data.lock);
wait_queue_wakeup(&pipe_ptr->data.read_wait_queue, PROC_UNINTERRUPTIBLE);
kdebug("pipe_write out!\n");
return count;
}
long pipe_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr)
{
return 0;
}
struct vfs_file_operations_t g_pipe_file_ops = {
.open = NULL,
.close = pipe_close,
.read = pipe_read,
.write = pipe_write,
.lseek = NULL,
.ioctl = NULL,
.readdir = NULL,
};
static struct pipe_t *pipe_alloc()
{
struct pipe_t *pipe_ptr = NULL;
pipe_ptr = (struct pipe_t *)kzalloc(sizeof(struct pipe_t), 0);
spin_init(&pipe_ptr->data.lock);
pipe_ptr->data.read_pos = 0;
pipe_ptr->data.write_pos = 0;
pipe_ptr->data.valid_cnt = 0;
memset(pipe_ptr->buf, 0, PIPE_BUFF_SIZE);
wait_queue_init(&pipe_ptr->data.read_wait_queue, NULL);
wait_queue_init(&pipe_ptr->data.write_wait_queue, NULL);
return pipe_ptr;
}
/**
* @brief 创建管道
*
* @param fd(r8) 文件句柄指针
* @param num(r9) 文件句柄个数
* @return uint64_t
*/
uint64_t sys_pipe(struct pt_regs *regs)
{
int *fd = NULL;
struct pipe_t *pipe_ptr = NULL;
struct vfs_file_t *read_file = NULL;
struct vfs_file_t *write_file = NULL;
fd = (int *)regs->r8;
kdebug("pipe creat into!\n");
/* step1 申请pipe结构体、初始化 */
pipe_ptr = pipe_alloc();
/* step2 申请2个fd文件句柄1个作为读端、1个作为写端 */
read_file = (struct vfs_file_t *)kzalloc(sizeof(struct vfs_file_t), 0);
fd[0] = process_fd_alloc(read_file);
if (fd[0] == -1)
{
kdebug("pipe alloc read fd fail!\n");
kfree(pipe_ptr);
kfree(read_file);
return -1;
}
write_file = (struct vfs_file_t *)kzalloc(sizeof(struct vfs_file_t), 0);
fd[1] = process_fd_alloc(write_file);
if (fd[1] == -1)
{
kdebug("pipe alloc write fd fail!\n");
kfree(pipe_ptr);
kfree(read_file);
kfree(write_file);
return -1;
}
/* step3 绑定pipe和file */
read_file->private_data = (void *)pipe_ptr;
read_file->file_ops = &g_pipe_file_ops;
read_file->mode = VFS_FILE_MODE_READ;
write_file->private_data = (void *)pipe_ptr;
write_file->file_ops = &g_pipe_file_ops;
write_file->mode = VFS_FILE_MODE_WRITE;
kdebug("pipe creat end!\n");
return 0;
}

View File

@ -1,4 +0,0 @@
#ifndef __PIPE_H__
#define __PIPE_H__
#endif

View File

@ -16,26 +16,29 @@ use core::panic::PanicInfo;
#[path = "arch/x86_64/mod.rs"]
#[macro_use]
mod arch;
mod driver;
mod filesystem;
#[macro_use]
mod include;
mod ipc;
#[macro_use]
mod libs;
#[macro_use]
mod include;
mod driver; // 如果driver依赖了libs应该在libs后面导出
mod exception;
pub mod io;
mod filesystem;
mod io;
mod ipc;
mod mm;
mod process;
mod sched;
mod smp;
mod time;
#[macro_use]
extern crate alloc;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;
use mm::allocator::KernelAllocator;
// <3>

View File

@ -10,7 +10,7 @@
* @param fifo 队列结构体
* @param size 缓冲区大小
* @param reserved 暂时保留请置为0
* @return int 错误码成功->0
* @return int 错误码: NOMEM; 成功->0
*/
int kfifo_alloc(struct kfifo_t *fifo, uint32_t size, uint64_t reserved)
{

View File

@ -52,16 +52,20 @@ void lockref_inc(struct lockref *lock_ref)
* @brief 原子地将引用计数加1.如果原来的count≤0则操作失败。
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return int 操作成功=>true
* @return bool 操作成功=>true
* 操作失败=>false
*/
bool lockref_inc_not_zero(struct lockref *lock_ref)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 0) return false;
++new.count;
,
return true;)
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 0)
return false;
++new.count;
},
{ return true; })
bool retval;
spin_lock(&lock_ref->lock);
retval = false;
@ -86,11 +90,14 @@ bool lockref_inc_not_zero(struct lockref *lock_ref)
*/
int lockref_dec(struct lockref *lock_ref)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 0) break;
--new.count;
,
return new.count;);
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 0)
break;
--new.count;
},
{ return new.count; })
// 如果xchg时处于已加锁的状态或者检测到old.count <= 0则采取加锁处理
int retval = -1;
@ -117,11 +124,14 @@ int lockref_dec(struct lockref *lock_ref)
*/
int lockref_dec_return(struct lockref *lock_ref)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 0) return -1;
--new.count;
,
return new.count;);
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 0)
return -1;
--new.count;
},
{ return new.count; })
return -1;
}
@ -138,11 +148,14 @@ int lockref_dec_return(struct lockref *lock_ref)
*/
bool lockref_dec_not_zero(struct lockref *lock_ref)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 1) return false;
--new.count;
,
return true;)
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 1)
return false;
--new.count;
},
{ return true; })
bool retval = false;
spin_lock(&lock_ref->lock);
@ -167,11 +180,14 @@ bool lockref_dec_not_zero(struct lockref *lock_ref)
*/
bool lockref_dec_or_lock_not_zero(struct lockref *lock_ref)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 1) break;
--new.count;
,
return true;);
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 1)
break;
--new.count;
},
{ return true; });
bool retval = false;
spin_lock(&lock_ref->lock);
@ -205,11 +221,14 @@ void lockref_mark_dead(struct lockref *lock_ref)
*/
bool lockref_inc_not_dead(struct lockref *lock_ref)
{
CMPXCHG_LOOP(lock_ref,
if (old.count < 0) return false;
++new.count;
,
return true;)
CMPXCHG_LOOP(
lock_ref,
{
if (old.count < 0)
return false;
++new.count;
},
{ return true; })
bool retval = false;
// 快捷路径操作失败,尝试加锁

View File

@ -7,6 +7,9 @@ pub mod atomic;
pub mod list;
pub mod lockref;
pub mod mutex;
pub mod vec_cursor;
#[macro_use]
pub mod volatile_io;
pub mod rwlock;
pub mod semaphore;
pub mod wait_queue;

View File

@ -0,0 +1,251 @@
#![allow(dead_code)]
use core::mem::size_of;
use alloc::vec::Vec;
use crate::{
include::bindings::bindings::{E2BIG, EINVAL, EOVERFLOW},
io::SeekFrom,
};
/// @brief 本模块用于为数组提供游标的功能,以简化其操作。
#[derive(Debug)]
pub struct VecCursor {
/// 游标管理的数据
data: Vec<u8>,
/// 游标的位置
pos: usize,
}
impl VecCursor {
/// @brief 新建一个游标
pub fn new(data: Vec<u8>) -> Self {
return Self { data: data, pos: 0 };
}
/// @brief 创建一个全0的cursor
pub fn zerod(length: usize) -> Self {
let mut result = VecCursor {
data: Vec::new(),
pos: 0,
};
result.data.resize(length, 0);
return result;
}
/// @brief 获取游标管理的数据的可变引用
pub fn get_mut(&mut self) -> &mut Vec<u8> {
return &mut self.data;
}
/// @brief 获取游标管理的数据的不可变引用
pub fn get_ref(&self) -> &Vec<u8> {
return &self.data;
}
/// @brief 读取一个u8的数据小端对齐
pub fn read_u8(&mut self) -> Result<u8, i32> {
if self.pos >= self.data.len() {
return Err(-(E2BIG as i32));
}
self.pos += 1;
return Ok(self.data[self.pos - 1]);
}
/// @brief 读取一个u16的数据小端对齐
pub fn read_u16(&mut self) -> Result<u16, i32> {
if self.pos + 2 > self.data.len() {
return Err(-(E2BIG as i32));
}
let mut res = 0u16;
res |= (self.data[self.pos] as u16) & 0xff;
self.pos += 1;
res |= ((self.data[self.pos] as u16) & 0xff) << 8;
self.pos += 1;
return Ok(res);
}
/// @brief 读取一个u32的数据小端对齐
pub fn read_u32(&mut self) -> Result<u32, i32> {
if self.pos + 4 > self.data.len() {
return Err(-(E2BIG as i32));
}
let mut res = 0u32;
for i in 0..4 {
res |= ((self.data[self.pos] as u32) & 0xff) << (8 * i);
self.pos += 1;
}
return Ok(res);
}
/// @brief 读取一个u64的数据小端对齐
pub fn read_u64(&mut self) -> Result<u64, i32> {
if self.pos + 8 > self.data.len() {
return Err(-(E2BIG as i32));
}
let mut res = 0u64;
for i in 0..8 {
res |= ((self.data[self.pos] as u64) & 0xff) << (8 * i);
self.pos += 1;
}
return Ok(res);
}
/// @brief 精确读取与buf同样大小的数据。
///
/// @param buf 要读取到的目标缓冲区
///
/// @return Ok(()) 成功读取
/// @retunr Err(-E2BIG) 没有这么多数据,读取失败
pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), i32> {
if self.pos + buf.len() > self.data.len() {
return Err(-(E2BIG as i32));
}
buf.copy_from_slice(&self.data[self.pos..self.pos + buf.len()]);
self.pos += buf.len();
return Ok(());
}
/// @brief 小端对齐读取数据到u16数组.
///
/// @param buf 目标u16数组
pub fn read_u16_into(&mut self, buf: &mut [u16]) -> Result<(), i32> {
if self.pos + buf.len() * size_of::<u16>() > self.data.len() * size_of::<u16>() {
return Err(-(E2BIG as i32));
}
for i in 0..buf.len() {
buf[i] = self.read_u16()?;
}
return Ok(());
}
/// @brief 调整游标的位置
///
/// @param 调整的相对值
///
/// @return Ok(新的游标位置) 调整成功,返回新的游标位置
/// @return Err(-EOVERFLOW) 调整失败,游标超出正确的范围。(失败时游标位置不变)
pub fn seek(&mut self, origin: SeekFrom) -> Result<usize, i32> {
let pos: i64;
match origin {
SeekFrom::SeekSet(offset) => {
pos = offset;
}
SeekFrom::SeekCurrent(offset) => {
pos = self.pos as i64 + offset;
}
SeekFrom::SeekEnd(offset) => {
// 请注意此处的offset应小于等于0否则肯定是不合法的
pos = self.data.len() as i64 + offset;
}
SeekFrom::Invalid => {
return Err(-(EINVAL as i32));
}
}
if pos < 0 || pos > self.data.len() as i64 {
return Err(-(EOVERFLOW as i32));
}
self.pos = pos as usize;
return Ok(self.pos);
}
/// @brief 写入一个u8的数据小端对齐
pub fn write_u8(&mut self, value: u8) -> Result<u8, i32> {
if self.pos >= self.data.len() {
return Err(-(E2BIG as i32));
}
self.data[self.pos] = value;
self.pos += 1;
return Ok(value);
}
/// @brief 写入一个u16的数据小端对齐
pub fn write_u16(&mut self, value: u16) -> Result<u16, i32> {
if self.pos + 2 > self.data.len() {
return Err(-(E2BIG as i32));
}
self.data[self.pos] = (value & 0xff) as u8;
self.pos += 1;
self.data[self.pos] = ((value >> 8) & 0xff) as u8;
self.pos += 1;
return Ok(value);
}
/// @brief 写入一个u32的数据小端对齐
pub fn write_u32(&mut self, value: u32) -> Result<u32, i32> {
if self.pos + 4 > self.data.len() {
return Err(-(E2BIG as i32));
}
for i in 0..4 {
self.data[self.pos] = ((value >> (i * 8)) & 0xff) as u8;
self.pos += 1;
}
return Ok(value);
}
/// @brief 写入一个u64的数据小端对齐
pub fn write_u64(&mut self, value: u64) -> Result<u64, i32> {
if self.pos + 8 > self.data.len() {
return Err(-(E2BIG as i32));
}
for i in 0..8 {
self.data[self.pos] = ((value >> (i * 8)) & 0xff) as u8;
self.pos += 1;
}
return Ok(value);
}
/// @brief 精确写入与buf同样大小的数据。
///
/// @param buf 要写入到的目标缓冲区
///
/// @return Ok(()) 成功写入
/// @retunr Err(-E2BIG) 没有这么多数据,写入失败
pub fn write_exact(&mut self, buf: &[u8]) -> Result<(), i32> {
if self.pos + buf.len() > self.data.len() {
return Err(-(E2BIG as i32));
}
self.data[self.pos..self.pos + buf.len()].copy_from_slice(&buf[..]);
self.pos += buf.len();
return Ok(());
}
/// @brief 获取当前的数据切片
pub fn as_slice(&self) -> &[u8] {
return &self.data[..];
}
/// @brief 获取可变数据切片
pub fn as_mut_slice(&mut self) -> &mut [u8] {
return &mut self.data[..];
}
/// @brief 获取当前游标的位置
#[inline]
pub fn pos(&self) -> usize {
return self.pos;
}
/// @brief 获取缓冲区数据的大小
#[inline]
pub fn len(&self) -> usize {
return self.data.len();
}
}

View File

@ -0,0 +1,37 @@
macro_rules! volatile_read {
($data: expr) => {
unsafe { core::ptr::read_volatile(core::ptr::addr_of!($data)) }
};
}
macro_rules! volatile_write {
($data: expr, $value: expr) => {
unsafe { core::ptr::write_volatile(core::ptr::addr_of_mut!($data), $value) }
};
}
/// @brief: 用于volatile设置某些bits
/// @param val: 设置这些位
/// @param flag: true表示设置这些位为1; false表示设置这些位为0;
macro_rules! volatile_set_bit {
($data: expr, $val: expr, $flag: expr) => {
volatile_write!(
$data,
match $flag {
true => core::ptr::read_volatile(core::ptr::addr_of!($data)) | $val,
false => core::ptr::read_volatile(core::ptr::addr_of!($data)) & (!$val),
}
)
};
}
/// @param data: volatile变量
/// @param bits: 置1的位才有效表示写这些位
/// @param val: 要写的值
/// 比如: 写 x 的 2至8bit 为 10, 可以这么写 volatile_write_bit(x, (1<<8)-(1<<2), 10<<2);
macro_rules! volatile_write_bit {
($data: expr, $bits: expr, $val: expr) => {
volatile_set_bit!($data, $bits, false);
volatile_set_bit!($data, ($val) & ($bits), true);
};
}

View File

@ -20,9 +20,6 @@
#include <smp/ipi.h>
#include <filesystem/vfs/VFS.h>
#include <filesystem/devfs/devfs.h>
#include <filesystem/procfs/procfs.h>
#include <filesystem/fat32/fat32.h>
#include "driver/acpi/acpi.h"
#include "driver/disk/ahci/ahci.h"
@ -52,8 +49,7 @@ void reload_gdt()
gdtp.size = bsp_gdt_size - 1;
gdtp.gdt_vaddr = (ul)phys_2_virt((ul)&GDT_Table);
asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp)
: "memory");
asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp) : "memory");
}
void reload_idt()
@ -64,8 +60,7 @@ void reload_idt()
// kdebug("gdtvaddr=%#018lx", p.gdt_vaddr);
// kdebug("gdt size=%d", p.size);
asm volatile("lidt (%0) \n\t" ::"r"(&idtp)
: "memory");
asm volatile("lidt (%0) \n\t" ::"r"(&idtp) : "memory");
}
// 初始化系统各模块
@ -141,12 +136,10 @@ void system_initialize()
io_mfence();
vfs_init();
devfs_init();
procfs_init();
cpu_init();
ps2_keyboard_init();
tty_init();
// tty_init();
// ps2_mouse_init();
// ata_init();
pci_init();
@ -167,7 +160,7 @@ void system_initialize()
// 启用double buffer
// scm_enable_double_buffer(); // 因为时序问题, 该函数调用被移到 initial_kernel_thread
io_mfence();
HPET_enable();
io_mfence();

View File

@ -1,3 +1,17 @@
use crate::include::bindings::bindings::PAGE_OFFSET;
pub mod allocator;
pub mod gfp;
pub mod mmio_buddy;
/// @brief 将内核空间的虚拟地址转换为物理地址
#[inline(always)]
pub fn virt_2_phys(addr: usize) -> usize {
addr - PAGE_OFFSET as usize
}
/// @brief 将物理地址转换为内核空间的虚拟地址
#[inline(always)]
pub fn phys_2_virt(addr: usize) -> usize {
addr + PAGE_OFFSET as usize
}

View File

@ -2,14 +2,15 @@
#include <common/err.h>
#include <common/kthread.h>
#include <common/spinlock.h>
#include <filesystem/procfs/procfs.h>
extern spinlock_t process_global_pid_write_lock;
extern long process_global_pid;
extern void kernel_thread_func(void);
extern uint64_t rs_procfs_register_pid(uint64_t);
extern uint64_t rs_procfs_unregister_pid(uint64_t);
int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb);
extern int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb);
int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb);
int process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb);
int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start,
@ -137,7 +138,7 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
process_wakeup(tsk);
// 创建对应procfs文件
procfs_register_pid(tsk->pid);
rs_procfs_register_pid(tsk->pid);
return retval;
@ -147,6 +148,7 @@ copy_thread_failed:;
copy_files_failed:;
// 回收文件
process_exit_files(tsk);
rs_procfs_unregister_pid(tsk->pid);
copy_sighand_failed:;
process_exit_sighand(tsk);
copy_signal_failed:;
@ -173,35 +175,6 @@ int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb)
return 0;
}
/**
* @brief 拷贝当前进程的文件描述符等信息
*
* @param clone_flags 克隆标志位
* @param pcb 新的进程的pcb
* @return uint64_t
*/
int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb)
{
int retval = 0;
// 如果CLONE_FS被置位那么子进程与父进程共享文件描述符
// 文件描述符已经在复制pcb时被拷贝
if (clone_flags & CLONE_FS)
return retval;
// TODO: 这里是临时性的特殊处理stdio待文件系统重构及tty设备实现后需要改写这里
process_open_stdio(current_pcb);
// 为新进程拷贝新的文件描述符
for (int i = 3; i < PROC_MAX_FD_NUM; ++i)
{
if (current_pcb->fds[i] == NULL)
continue;
pcb->fds[i] = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0);
memcpy(pcb->fds[i], current_pcb->fds[i], sizeof(struct vfs_file_t));
}
return retval;
}
/**
* @brief 拷贝当前进程的内存空间分布结构体信息

View File

@ -110,9 +110,8 @@ struct process_control_block
int64_t virtual_runtime; // 虚拟运行时间
int64_t rt_time_slice; // 由实时调度器管理的时间片
// 进程拥有的文件描述符的指针数组
// todo: 改用动态指针数组
struct vfs_file_t *fds[PROC_MAX_FD_NUM];
// 进程拥有的文件描述符的指针数组(由Rust进行管理)
void * fds;
// 链表中的下一个pcb
struct process_control_block *prev_pcb, *next_pcb;

View File

@ -20,11 +20,6 @@
#include <driver/usb/usb.h>
#include <driver/video/video.h>
#include <exception/gate.h>
#include <filesystem/devfs/devfs.h>
#include <filesystem/fat32/fat32.h>
#include <filesystem/procfs/procfs.h>
#include <filesystem/rootfs/rootfs.h>
#include <io/block/block_io_scheduler.h>
#include <ktest/ktest.h>
#include <mm/mmio.h>
#include <mm/slab.h>
@ -41,6 +36,7 @@ long process_global_pid = 1; // 系统中最大的pid
extern void system_call(void);
extern void kernel_thread_func(void);
extern void rs_procfs_unregister_pid(uint64_t);
ul _stack_start; // initial proc的栈基地址虚拟地址
extern struct mm_struct initial_mm;
@ -50,6 +46,7 @@ extern struct sighand_struct INITIAL_SIGHAND;
extern void process_exit_sighand(struct process_control_block *pcb);
extern void process_exit_signal(struct process_control_block *pcb);
extern void initial_proc_init_signal(struct process_control_block *pcb);
extern int process_init_files();
// 设置初始进程的PCB
#define INITIAL_PROC(proc) \
@ -86,7 +83,7 @@ struct tss_struct initial_tss[MAX_CPU_NUM] = {[0 ... MAX_CPU_NUM - 1] = INITIAL_
* @param pcb 要被回收的进程的pcb
* @return uint64_t
*/
uint64_t process_exit_files(struct process_control_block *pcb);
extern int process_exit_files(struct process_control_block *pcb);
/**
* @brief 释放进程的页表
@ -139,32 +136,15 @@ void process_switch_fsgs(uint64_t fs, uint64_t gs)
* @brief 打开要执行的程序文件
*
* @param path
* @return struct vfs_file_t*
* @return int 文件描述符编号
*/
struct vfs_file_t *process_open_exec_file(char *path)
int process_open_exec_file(char *path)
{
struct vfs_dir_entry_t *dentry = NULL;
struct vfs_file_t *filp = NULL;
// kdebug("path=%s", path);
dentry = vfs_path_walk(path, 0);
if (dentry == NULL)
return (void *)-ENOENT;
if (dentry->dir_inode->attribute == VFS_IF_DIR)
return (void *)-ENOTDIR;
filp = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0);
if (filp == NULL)
return (void *)-ENOMEM;
filp->position = 0;
filp->mode = 0;
filp->dEntry = dentry;
filp->mode = ATTR_READ_ONLY;
filp->file_ops = dentry->dir_inode->file_ops;
return filp;
struct pt_regs tmp = {0};
tmp.r8 = (uint64_t)path;
tmp.r9 = O_RDONLY;
int fd = sys_open(&tmp);
return fd;
}
/**
@ -177,19 +157,38 @@ struct vfs_file_t *process_open_exec_file(char *path)
static int process_load_elf_file(struct pt_regs *regs, char *path)
{
int retval = 0;
struct vfs_file_t *filp = process_open_exec_file(path);
int fd = process_open_exec_file(path);
if ((long)filp <= 0 && (long)filp >= -255)
if ((long)fd < 0)
{
kdebug("(long)filp=%ld", (long)filp);
return (unsigned long)filp;
kdebug("(long)fd=%ld", (long)fd);
return (unsigned long)fd;
}
void *buf = kmalloc(PAGE_4K_SIZE, 0);
memset(buf, 0, PAGE_4K_SIZE);
void *buf = kzalloc(PAGE_4K_SIZE, 0);
uint64_t pos = 0;
pos = filp->file_ops->lseek(filp, 0, SEEK_SET);
retval = filp->file_ops->read(filp, (char *)buf, sizeof(Elf64_Ehdr), &pos);
struct pt_regs tmp_use_fs = {0};
tmp_use_fs.r8 = fd;
tmp_use_fs.r9 = 0;
tmp_use_fs.r10 = SEEK_SET;
retval = sys_lseek(&tmp_use_fs);
// 读取 Elf64_Ehdr
tmp_use_fs.r8 = fd;
tmp_use_fs.r9 = (uint64_t)buf;
tmp_use_fs.r10 = sizeof(Elf64_Ehdr);
retval = sys_read(&tmp_use_fs);
tmp_use_fs.r8 = fd;
tmp_use_fs.r9 = 0;
tmp_use_fs.r10 = SEEK_CUR;
pos = sys_lseek(&tmp_use_fs);
if (retval != sizeof(Elf64_Ehdr))
{
kerror("retval=%d, not equal to sizeof(Elf64_Ehdr):%d", retval, sizeof(Elf64_Ehdr));
}
retval = 0;
if (!elf_check(buf))
{
@ -229,18 +228,33 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
// kdebug("ehdr.e_phoff=%#018lx\t ehdr.e_phentsize=%d, ehdr.e_phnum=%d", ehdr.e_phoff, ehdr.e_phentsize,
// ehdr.e_phnum); 将指针移动到program header处
pos = ehdr.e_phoff;
// 读取所有的phdr
pos = filp->file_ops->lseek(filp, pos, SEEK_SET);
filp->file_ops->read(filp, (char *)buf, (uint64_t)ehdr.e_phentsize * (uint64_t)ehdr.e_phnum, &pos);
if ((unsigned long)filp <= 0)
pos = ehdr.e_phoff;
tmp_use_fs.r8 = fd;
tmp_use_fs.r9 = pos;
tmp_use_fs.r10 = SEEK_SET;
pos = sys_lseek(&tmp_use_fs);
memset(buf, 0, PAGE_4K_SIZE);
tmp_use_fs.r8 = fd;
tmp_use_fs.r9 = (uint64_t)buf;
tmp_use_fs.r10 = (uint64_t)ehdr.e_phentsize * (uint64_t)ehdr.e_phnum;
sys_read(&tmp_use_fs);
tmp_use_fs.r8 = fd;
tmp_use_fs.r9 = 0;
tmp_use_fs.r10 = SEEK_CUR;
pos = sys_lseek(&tmp_use_fs);
if ((long)retval < 0)
{
kdebug("(unsigned long)filp=%d", (long)filp);
kdebug("(unsigned long)filp=%d", (long)retval);
retval = -ENOEXEC;
goto load_elf_failed;
}
Elf64_Phdr *phdr = buf;
Elf64_Phdr *phdr = buf;
// 将程序加载到内存中
for (int i = 0; i < ehdr.e_phnum; ++i, ++phdr)
{
@ -310,12 +324,38 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
}
}
pos = filp->file_ops->lseek(filp, pos, SEEK_SET);
tmp_use_fs.r8 = fd;
tmp_use_fs.r9 = pos;
tmp_use_fs.r10 = SEEK_SET;
pos = sys_lseek(&tmp_use_fs);
int64_t val = 0;
if (remain_file_size > 0)
{
int64_t to_trans = (remain_file_size > PAGE_2M_SIZE) ? PAGE_2M_SIZE : remain_file_size;
val = filp->file_ops->read(filp, (char *)(virt_base + beginning_offset), to_trans, &pos);
void *buf3 = kzalloc(PAGE_4K_SIZE, 0);
while (to_trans > 0)
{
int64_t x = 0;
tmp_use_fs.r8 = fd;
tmp_use_fs.r9 = (uint64_t)buf3;
tmp_use_fs.r10 = to_trans;
x = sys_read(&tmp_use_fs);
memcpy(virt_base + beginning_offset + val, buf3, x);
val += x;
to_trans -= x;
tmp_use_fs.r8 = fd;
tmp_use_fs.r9 = 0;
tmp_use_fs.r10 = SEEK_CUR;
pos = sys_lseek(&tmp_use_fs);
}
kfree(buf3);
// kdebug("virt_base + beginning_offset=%#018lx, val=%d, to_trans=%d", virt_base + beginning_offset,
// val,
// to_trans);
// kdebug("to_trans=%d", to_trans);
}
if (val < 0)
@ -346,6 +386,12 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
memset((void *)(current_pcb->mm->stack_start - PAGE_2M_SIZE), 0, PAGE_2M_SIZE);
load_elf_failed:;
{
struct pt_regs tmp = {0};
tmp.r8 = fd;
sys_close(&tmp);
}
if (buf != NULL)
kfree(buf);
return retval;
@ -409,8 +455,7 @@ ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[])
// 关闭之前的文件描述符
process_exit_files(current_pcb);
process_open_stdio(current_pcb);
process_init_files();
// 清除进程的vfork标志位
current_pcb->flags &= ~PF_VFORK;
@ -499,18 +544,21 @@ ul initial_kernel_thread(ul arg)
scm_enable_double_buffer();
block_io_scheduler_init();
// block_io_scheduler_init();
ahci_init();
fat32_init();
rootfs_umount();
mount_root_fs();
c_virtio_probe();
// 使用单独的内核线程来初始化usb驱动程序
// 注释由于目前usb驱动程序不完善因此先将其注释掉
// int usb_pid = kernel_thread(usb_init, 0, 0);
kinfo("LZ4 lib Version=%s", LZ4_versionString());
__rust_demo_func();
// while (1)
// {
// /* code */
// }
// 对completion完成量进行测试
// __test_completion();
@ -660,9 +708,9 @@ void process_init()
// 初始化init进程的signal相关的信息
initial_proc_init_signal(current_pcb);
// TODO: 这里是临时性的特殊处理stdio待文件系统重构及tty设备实现后需要改写这里
process_open_stdio(current_pcb);
kdebug("Initial process to init files");
process_init_files();
kdebug("Initial process init files ok");
// 临时设置IDLE进程的的虚拟运行时间为0防止下面的这些内核线程的虚拟运行时间出错
current_pcb->virtual_runtime = 0;
@ -689,7 +737,6 @@ struct process_control_block *process_find_pcb_by_pid(pid_t pid)
{
// todo: 当进程管理模块拥有pcblist_lock之后对其加锁
struct process_control_block *pcb = initial_proc_union.pcb.next_pcb;
// 使用蛮力法搜索指定pid的pcb
// todo: 使用哈希表来管理pcb
for (; pcb != &initial_proc_union.pcb; pcb = pcb->next_pcb)
@ -736,7 +783,7 @@ int process_wakeup_immediately(struct process_control_block *pcb)
if (retval != 0)
return retval;
// 将当前进程标志为需要调度缩短新进程被wakeup的时间
current_pcb->flags |= PF_NEED_SCHED;
current_pcb->flags |= PF_NEED_SCHED;
if (pcb->cpu_id == current_pcb->cpu_id)
sched();
@ -745,31 +792,6 @@ int process_wakeup_immediately(struct process_control_block *pcb)
return 0;
}
/**
* @brief 回收进程的所有文件描述符
*
* @param pcb 要被回收的进程的pcb
* @return uint64_t
*/
uint64_t process_exit_files(struct process_control_block *pcb)
{
// TODO: 当stdio不再被以-1来特殊处理时在这里要释放stdio文件的内存
// 不与父进程共享文件描述符
if (!(pcb->flags & PF_VFORK))
{
for (int i = 3; i < PROC_MAX_FD_NUM; ++i)
{
if (pcb->fds[i] == NULL)
continue;
kfree(pcb->fds[i]);
}
}
// 清空当前进程的文件描述符列表
memset(pcb->fds, 0, sizeof(struct vfs_file_t *) * PROC_MAX_FD_NUM);
}
/**
* @brief 释放进程的页表
*
@ -860,33 +882,12 @@ int process_release_pcb(struct process_control_block *pcb)
pcb->next_pcb->prev_pcb = pcb->prev_pcb;
process_exit_sighand(pcb);
process_exit_signal(pcb);
rs_procfs_unregister_pid(pcb->pid);
// 释放当前pcb
kfree(pcb);
return 0;
}
/**
* @brief 申请可用的文件句柄
*
* @return int
*/
int process_fd_alloc(struct vfs_file_t *file)
{
int fd_num = -1;
for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
{
/* 找到指针数组中的空位 */
if (current_pcb->fds[i] == NULL)
{
fd_num = i;
current_pcb->fds[i] = file;
break;
}
}
return fd_num;
}
/**
* @brief 给pcb设置名字
*
@ -911,14 +912,3 @@ void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_nam
{
__set_pcb_name(pcb, pcb_name);
}
void process_open_stdio(struct process_control_block *pcb)
{
// TODO: 这里是临时性的特殊处理stdio待文件系统重构及tty设备实现后需要改写这里
// stdin
pcb->fds[0] = -1UL;
// stdout
pcb->fds[1] = -1UL;
// stderr
pcb->fds[2] = -1UL;
}

Some files were not shown because too many files have changed in this diff Show More