mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 16:26:31 +00:00
新版文件系统重构完成 (#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:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -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",
|
||||
|
@ -1,24 +0,0 @@
|
||||
# devFS 设备文件系统
|
||||
|
||||
  devfs是一种基于内存的伪文件系统,设备可注册到devfs中。对上层模块及应用程序而言,每个设备都是可操作的文件。
|
||||
|
||||
## 原理
|
||||
|
||||
  由于每个设备被抽象为文件,因此对于驱动程序而言,只需实现文件的操作接口,上层的应用程序以及其他系统组件即可操作文件操作接口来控制硬件设备。
|
||||
|
||||
## 目录结构
|
||||
|
||||
  按照设备的主类型的不同,将多种设备放置在devfs的不同文件夹下.请注意,同一设备可以出现在不同的文件夹下。
|
||||
|
||||
- `char` 字符设备
|
||||
- `block` 块设备
|
||||
- `usb` usb设备
|
||||
- stdio等设备放置在devfs的根目录下
|
||||
|
||||
## 设备注册
|
||||
|
||||
  驱动程序可使用`devfs_register_device()`函数将设备注册到devfs之中。
|
||||
|
||||
## 设备卸载
|
||||
|
||||
  【尚未实现】
|
@ -1,216 +0,0 @@
|
||||
# FAT32文件系统
|
||||
|
||||
## 简介
|
||||
|
||||
  FAT32文件系统是一种相对简单的文件系统。
|
||||
|
||||
  FAT32文件系统实现在`kernel/filesystem/fat32/`中。
|
||||
|
||||
---
|
||||
|
||||
## 相关数据结构
|
||||
|
||||
### struct fat32_BootSector_t
|
||||
|
||||
  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
|
||||
|
||||
   该扇区存储了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**
|
||||
|
||||
  FS info扇区标志符 数值为0x41615252
|
||||
|
||||
**FSI_Reserved1**
|
||||
|
||||
  保留使用,全部置为0
|
||||
|
||||
**FSI_StrucSig**
|
||||
|
||||
  FS_Info扇区的另一个标志符,数值为0x61417272
|
||||
|
||||
**FSI_Free_Count**
|
||||
|
||||
  上一次记录的空闲簇数量,这是一个参考值
|
||||
|
||||
**FSI_Nxt_Free**
|
||||
|
||||
  空闲簇的起始搜索位置,这是为驱动程序提供的参考值.
|
||||
|
||||
**FSI_Reserved2**
|
||||
  保留使用,全部置为0
|
||||
|
||||
**FSI_TrailSig**
|
||||
|
||||
  FS_Info扇区结束标志,数值为0xaa550000
|
||||
|
||||
### struct fat32_Directory_t
|
||||
|
||||
  短目录项结构体。
|
||||
|
||||
```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**
|
||||
|
||||
  目录项名称。前8bytes为基础名,后3bytes为扩展名
|
||||
|
||||
**DIRAttr**
|
||||
|
||||
  目录项属性。可选值有如下:
|
||||
|
||||
> - ATTR_READ_ONLY
|
||||
>
|
||||
> - ATTR_HIDDEN
|
||||
>
|
||||
> - ATTR_SYSTEM
|
||||
>
|
||||
> - ATTR_VOLUME_ID
|
||||
>
|
||||
> - ATTR_DIRECTORY
|
||||
>
|
||||
> - ATTR_ARCHIVE
|
||||
>
|
||||
> - ATTR_LONG_NAME
|
||||
|
||||
**DIR_NTRes**
|
||||
|
||||
  该项为Windows下特有的表示区域,通过该项的值,表示基础名和扩展名的大小写情况。该项的值为`EXT|BASE`组合而成,其中,具有以下定义:
|
||||
|
||||
> BASE:LowerCase(8),UpperCase(0)
|
||||
> EXT:LowerCase(16),UpperCase(0)
|
||||
|
||||
**DIR_CrtTimeTenth**
|
||||
|
||||
  文件创建的毫秒级时间戳
|
||||
|
||||
**DIR_CrtTime**
|
||||
|
||||
  文件创建时间
|
||||
|
||||
**DIR_CrtDate**
|
||||
|
||||
文件创建日期
|
||||
|
||||
**DIR_LastAccDate**
|
||||
|
||||
  文件的最后访问日期
|
||||
|
||||
**DIR_FstClusHI**
|
||||
|
||||
   文件起始簇号(高16bit)
|
||||
|
||||
**DIR_WrtTime**
|
||||
|
||||
  最后写入时间
|
||||
|
||||
**DIR_WrtDate**
|
||||
|
||||
  最后写入日期
|
||||
|
||||
**DIR_FstClusLO**
|
||||
|
||||
   文件起始簇号(低16bit)
|
||||
|
||||
**DIR_FileSize**
|
||||
  文件大小
|
||||
|
||||
### struct fat32_partition_info_t
|
||||
|
||||
  该数据结构为FAT32分区的信息结构体,并不实际存在于物理磁盘上。这个结构体在挂载文件系统时被创建,作为文件系统的超级块的私有信息的一部分。
|
||||
|
||||
### struct fat32_inode_info_t
|
||||
|
||||
  该结构体是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)
|
@ -3,11 +3,11 @@
|
||||
|
||||
DragonOS的文件系统模块由VFS(虚拟文件系统)及具体的文件系统组成。
|
||||
|
||||
todo: 由于文件系统模块重构,文档暂时不可用,预计在2023年4月10日前补齐。
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: 目录
|
||||
|
||||
vfs/index
|
||||
fat32/index
|
||||
rootfs/index
|
||||
devfs/index
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
# rootFS 根文件系统
|
||||
|
||||
  rootFS是DragonOS开启后挂载的第一个文件系统,它是一个基于内存的伪文件系统。rootfs的功能主要是在具体的磁盘文件系统被挂载之前,为其他的伪文件系统提供挂载点,使得系统能被正确的初始化。
|
||||
|
||||
  rootfs的初始化将与VFS一同初始化。rootfs将为系统的各项文件系统的挂载创建dentry,使得其他的文件系统如`devfs`等,能在磁盘文件系统被挂载之前被正确的初始化。
|
||||
|
||||
  当磁盘根文件系统被挂载后,将调用`rootfs_umount()`函数。该函数将会把原本挂载在rootfs上的各种伪文件系统迁移到磁盘根文件系统上。当迁移完成后,将会释放rootfs所占用的资源。
|
@ -6,242 +6,6 @@
|
||||
|
||||
  与VFS相关的系统调用有open(), read(), write(), create()等。
|
||||
|
||||
### dentry对象
|
||||
## **TODO**
|
||||
|
||||
  dentry的全称为directory entry,是VFS中对于目录项的一种抽象数据结构。当读取具体文件系统时,将会由创建dentry对象。dentry对象中包含了指向inode的指针。
|
||||
|
||||
  dentry对象为真实文件系统上的目录结构建立了缓存,一旦内存中存在对应路径的dentry对象,我们就能直接获取其中的信息,而不需要进行费时的磁盘操作。请注意,dentry只是为提高文件系统性能而创建的一个缓存,它并不会被写入到磁盘之中。
|
||||
|
||||
### inode对象
|
||||
|
||||
  inode的全称叫做index node,即索引节点。一般来说,每个dentry都应当包含指向其inode的指针。inode是VFS提供的对文件对象的抽象。inode中的信息是从具体文件系统中读取而来,也可以被刷回具体的文件系统之中。并且,一个inode也可以被多个dentry所引用。
|
||||
|
||||
  要查找某个路径下的inode,我们需要调用父目录的inode的lookup()方法。请注意,该方法与具体文件系统有关,需要在具体文件系统之中实现。
|
||||
|
||||
### 文件描述符对象
|
||||
|
||||
  当一个进程试图通过VFS打开某个文件时,我们需要为这个进程创建文件描述符对象。每个文件对象都会绑定文件的dentry和文件操作方法结构体,还有文件对象的私有信息。
|
||||
|
||||
  文件描述符对象中还包含了诸如权限控制、当前访问位置信息等内容,以便VFS对文件进行操作。
|
||||
|
||||
  我们对文件进行操作都会使用到文件描述符,具体来说,就是要调用文件描述符之中的file_ops所包含的各种方法。
|
||||
|
||||
---
|
||||
|
||||
## 注册文件系统到VFS
|
||||
|
||||
  如果需要注册或取消注册某个具体文件系统到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);
|
||||
```
|
||||
|
||||
  这里需要通过`struct vfs_filesystem_type_t`来描述具体的文件系统。
|
||||
|
||||
### struct vfs_filesystem_type_t
|
||||
|
||||
  这个数据结构描述了具体文件系统的一些信息。当我们挂载具体文件系统的时候,将会调用它的read_superblock方法,以确定要被挂载的文件系统的具体信息。
|
||||
|
||||
  该数据结构的定义在`kernel/filesystem/vfs/VFS.h`中,结构如下:
|
||||
|
||||
```c
|
||||
struct vfs_filesystem_type_t
|
||||
{
|
||||
char *name;
|
||||
int fs_flags;
|
||||
// 解析文件系统引导扇区的函数,为文件系统创建超级块结构。其中DPTE为磁盘分区表entry(MBR、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**
|
||||
|
||||
  文件系统名称字符串
|
||||
|
||||
**fs_flags**
|
||||
|
||||
  文件系统的一些标志位。目前,DragonOS尚未实现相关功能。
|
||||
|
||||
**read_superblock**
|
||||
|
||||
  当新的文件系统实例将要被挂载时,将会调用此方法,以读取具体的实例的信息。
|
||||
|
||||
**next**
|
||||
|
||||
  指向链表中下一个`struct vfs_filesystem_type_t`的指针。
|
||||
|
||||
---
|
||||
|
||||
## 超级块(superblock)对象
|
||||
|
||||
  一个超级块对象代表了一个被挂载到VFS中的具体文件系统。
|
||||
|
||||
### struct vfs_superblock_t
|
||||
|
||||
  该数据结构为超级块结构体。
|
||||
|
||||
  该数据结构定义在`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**
|
||||
|
||||
  该具体文件系统的根目录的dentry
|
||||
|
||||
**sb_ops**
|
||||
|
||||
  该超级块对象的操作方法。
|
||||
|
||||
**private_sb_info**
|
||||
|
||||
  超级块的私有信息。包含了具体文件系统的私有的、全局性的信息。
|
||||
|
||||
### struct vfs_super_block_operations_t
|
||||
|
||||
  该数据结构为超级块的操作接口。VFS通过这些接口来操作具体的文件系统的超级块。
|
||||
|
||||
  该数据结构定义在`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**
|
||||
|
||||
  将superblock中的信息写入磁盘
|
||||
|
||||
**put_superblock**
|
||||
|
||||
  释放超级块
|
||||
|
||||
**write_inode**
|
||||
|
||||
  将inode的信息写入磁盘
|
||||
|
||||
---
|
||||
|
||||
## 索引结点(inode)对象
|
||||
|
||||
  每个inode对象代表了具体的文件系统之中的一个对象(目录项)。
|
||||
|
||||
### struct vfs_index_node_t
|
||||
|
||||
  该数据结构为inode对象的数据结构,与文件系统中的具体的文件结点对象具有一对一映射的关系。
|
||||
|
||||
  该数据结构定义在`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**
|
||||
|
||||
  文件的大小。若为文件夹,则该值为文件夹内所有文件的大小总和(估计值)。
|
||||
|
||||
**blocks**
|
||||
|
||||
  文件占用的磁盘块数(扇区数)
|
||||
|
||||
**attribute**
|
||||
|
||||
  inode的属性。可选值如下:
|
||||
|
||||
> - VFS_IF_FILE
|
||||
>
|
||||
> - VFS_IF_DIR
|
||||
>
|
||||
> - VFS_IF_DEVICE
|
||||
|
||||
**sb**
|
||||
|
||||
  指向文件系统超级块的指针
|
||||
|
||||
**file_ops**
|
||||
|
||||
  当前文件的操作接口
|
||||
|
||||
**inode_ops**
|
||||
|
||||
  当前inode的操作接口
|
||||
|
||||
**private_inode_info**
|
||||
|
||||
  与具体文件系统相关的inode信息。该部分由具体文件系统实现,包含该inode在具体文件系统之中的特定格式信息。
|
||||
|
||||
### struct vfs_inode_operations_t
|
||||
|
||||
  该接口为inode的操作方法接口,由具体文件系统实现。并与具体文件系统之中的inode相互绑定。
|
||||
|
||||
  该接口定义于`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**
|
||||
|
||||
  在父节点下,创建一个新的inode,并绑定到dest_dEntry上。
|
||||
|
||||
  该函数的应当被`sys_open()`系统调用在使用了`O_CREAT`选项打开文件时调用,从而创建一个新的文件。请注意,传递给create()函数的`dest_dEntry`参数不应包含一个inode,也就是说,inode对象应当被具体文件系统所创建。
|
||||
|
||||
**lookup**
|
||||
|
||||
  当VFS需要在父目录中查找一个inode的时候,将会调用lookup方法。被查找的目录项的名称将会通过dest_dEntry传给lookup方法。
|
||||
|
||||
  若lookup方法找到对应的目录项,将填充完善dest_dEntry对象。否则,返回NULL。
|
||||
|
||||
**mkdir**
|
||||
|
||||
  该函数被mkdir()系统调用所调用,用于在inode下创建子目录,并将子目录的inode绑定到dEntry对象之中。
|
||||
|
||||
**rmdir**
|
||||
|
||||
  该函数被rmdir()系统调用所调用,用于删除给定inode下的子目录项。
|
||||
|
||||
**rename**
|
||||
|
||||
  该函数被rename系统调用(尚未实现)所调用,用于将给定的目录项重命名。
|
||||
|
||||
**getAttr**
|
||||
|
||||
  用来获取目录项的属性。
|
||||
|
||||
**setAttr**
|
||||
|
||||
  用来设置目录项的属性
|
||||
  VFS的设计与实现讲解
|
@ -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]
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -24,8 +24,8 @@ struct tm
|
||||
|
||||
struct timespec
|
||||
{
|
||||
long int tv_sec; // 秒
|
||||
long long tv_nsec; // 纳秒
|
||||
int64_t tv_sec; // 秒
|
||||
int64_t tv_nsec; // 纳秒
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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!");
|
||||
}
|
||||
|
@ -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();
|
||||
|
155
kernel/src/driver/disk/ahci/ahci_inode.rs
Normal file
155
kernel/src/driver/disk/ahci/ahci_inode.rs
Normal 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));
|
||||
}
|
||||
}
|
19
kernel/src/driver/disk/ahci/ahci_rust.h
Normal file
19
kernel/src/driver/disk/ahci/ahci_rust.h
Normal 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]);
|
441
kernel/src/driver/disk/ahci/ahcidisk.rs
Normal file
441
kernel/src/driver/disk/ahci/ahcidisk.rs
Normal 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();
|
||||
}
|
||||
}
|
408
kernel/src/driver/disk/ahci/hba.rs
Normal file
408
kernel/src/driver/disk/ahci/hba.rs
Normal 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
|
||||
}
|
215
kernel/src/driver/disk/ahci/mod.rs
Normal file
215
kernel/src/driver/disk/ahci/mod.rs
Normal 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();
|
||||
}
|
1
kernel/src/driver/disk/mod.rs
Normal file
1
kernel/src/driver/disk/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod ahci;
|
2
kernel/src/driver/keyboard/mod.rs
Normal file
2
kernel/src/driver/keyboard/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod ps2_keyboard;
|
||||
// pub mod ps2_keyboard_inode;
|
@ -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.");
|
||||
}
|
||||
|
||||
|
155
kernel/src/driver/keyboard/ps2_keyboard.rs
Normal file
155
kernel/src/driver/keyboard/ps2_keyboard.rs
Normal 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));
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
pub mod disk;
|
||||
pub mod keyboard;
|
||||
pub mod pci;
|
||||
pub mod timers;
|
||||
pub mod uart;
|
||||
|
@ -7,7 +7,6 @@ use bitflags::bitflags;
|
||||
use core::{
|
||||
convert::TryFrom,
|
||||
fmt::{self, Display, Formatter},
|
||||
ptr::NonNull,
|
||||
};
|
||||
//Bar0寄存器的offset
|
||||
const BAR0_OFFSET: u8 = 0x10;
|
||||
|
@ -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);
|
||||
// }
|
@ -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();
|
||||
|
@ -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到设备
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
@ -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)
|
||||
|
@ -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");
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "devfs.h"
|
||||
|
||||
|
@ -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
|
||||
};
|
@ -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();
|
||||
}
|
@ -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);
|
@ -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)); \
|
||||
})
|
@ -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);
|
||||
}
|
||||
|
146
kernel/src/filesystem/devfs/null_dev.rs
Normal file
146
kernel/src/filesystem/devfs/null_dev.rs
Normal 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)
|
||||
}
|
||||
}
|
146
kernel/src/filesystem/devfs/zero_dev.rs
Normal file
146
kernel/src/filesystem/devfs/zero_dev.rs
Normal 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)
|
||||
}
|
||||
}
|
380
kernel/src/filesystem/fat/bpb.rs
Normal file
380
kernel/src/filesystem/fat/bpb.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2404
kernel/src/filesystem/fat/entry.rs
Normal file
2404
kernel/src/filesystem/fat/entry.rs
Normal file
File diff suppressed because it is too large
Load Diff
1668
kernel/src/filesystem/fat/fs.rs
Normal file
1668
kernel/src/filesystem/fat/fs.rs
Normal file
File diff suppressed because it is too large
Load Diff
4
kernel/src/filesystem/fat/mod.rs
Normal file
4
kernel/src/filesystem/fat/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod bpb;
|
||||
pub mod entry;
|
||||
pub mod fs;
|
||||
pub mod utils;
|
15
kernel/src/filesystem/fat/utils.rs
Normal file
15
kernel/src/filesystem/fat/utils.rs
Normal 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;
|
||||
}
|
||||
}
|
@ -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
@ -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);
|
@ -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;
|
||||
}
|
@ -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);
|
@ -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;
|
||||
}
|
@ -1 +0,0 @@
|
||||
|
65
kernel/src/filesystem/mbr.rs
Normal file
65
kernel/src/filesystem/mbr.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
444
kernel/src/filesystem/ramfs/mod.rs
Normal file
444
kernel/src/filesystem/ramfs/mod.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -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);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void rootfs_init();
|
||||
|
||||
/**
|
||||
* @brief 当磁盘文件系统被成功挂载后,释放rootfs所占的空间
|
||||
*
|
||||
*/
|
||||
void rootfs_umount();
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
@ -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();
|
||||
|
392
kernel/src/filesystem/vfs/core.rs
Normal file
392
kernel/src/filesystem/vfs/core.rs
Normal 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);
|
||||
}
|
@ -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;
|
||||
}
|
330
kernel/src/filesystem/vfs/file.rs
Normal file
330
kernel/src/filesystem/vfs/file.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
@ -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的名字(是一个零长数组), 本字段仅用于占位
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
365
kernel/src/filesystem/vfs/mount.rs
Normal file
365
kernel/src/filesystem/vfs/mount.rs
Normal 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
|
||||
}
|
||||
}
|
352
kernel/src/filesystem/vfs/syscall.rs
Normal file
352
kernel/src/filesystem/vfs/syscall.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
21
kernel/src/filesystem/vfs/utils.rs
Normal file
21
kernel/src/filesystem/vfs/utils.rs
Normal 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);
|
||||
}
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
@ -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();
|
@ -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);
|
||||
}
|
@ -1 +1 @@
|
||||
pub mod block_io_scheduler;
|
||||
// pub mod block_io_scheduler;
|
||||
|
323
kernel/src/io/device.rs
Normal file
323
kernel/src/io/device.rs
Normal 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;
|
||||
}
|
49
kernel/src/io/disk_info.rs
Normal file
49
kernel/src/io/disk_info.rs
Normal 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();
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
@ -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."
|
@ -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;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
#ifndef __PIPE_H__
|
||||
#define __PIPE_H__
|
||||
|
||||
#endif
|
@ -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>
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
// 快捷路径操作失败,尝试加锁
|
||||
|
@ -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;
|
||||
|
251
kernel/src/libs/vec_cursor.rs
Normal file
251
kernel/src/libs/vec_cursor.rs
Normal 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();
|
||||
}
|
||||
}
|
37
kernel/src/libs/volatile_io.rs
Normal file
37
kernel/src/libs/volatile_io.rs
Normal 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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 拷贝当前进程的内存空间分布结构体信息
|
||||
|
@ -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;
|
||||
|
@ -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
Reference in New Issue
Block a user