diff --git a/build.py b/build.py index 1c35589..b98113a 100644 --- a/build.py +++ b/build.py @@ -92,5 +92,5 @@ def linker(): #交叉编译链接 if a != 0: exit(-1) -os.system("qemu-system-i386 -kernel isodir\\sys\\kernel.elf") +os.system("qemu-system-i386 -kernel isodir\\sys\\kernel.elf -drive format=qcow2,file=cpos.qcow2") diff --git a/cpos.qcow2 b/cpos.qcow2 new file mode 100644 index 0000000..9907ff2 Binary files /dev/null and b/cpos.qcow2 differ diff --git a/driver/disk.c b/driver/disk.c new file mode 100644 index 0000000..c9551cd --- /dev/null +++ b/driver/disk.c @@ -0,0 +1,73 @@ +#include "../include/disk.h" +#include "../include/io.h" + +void wait_disk_ready() +{ + while (1) + { + int data = io_in8(0x1f7); + if ((data & 0x88) == 0x08) // 第3位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙。 + { + return; + } + } +} + +void select_sector(int lba) +{ + io_out8(0x1f2, 1); + io_out8(0x1f3, lba); + io_out8(0x1f4, lba >> 8); + io_out8(0x1f5, lba >> 16); + io_out8(0x1f6, (((lba >> 24) & 0x0f) | 0xe0)); +} + +void read_disk_one_sector(int lba, unsigned int memory_addrress) +{ + while (io_in8(0x1f7) & 0x80) + ; + select_sector(lba); + io_out8(0x1f7, 0x20); + wait_disk_ready(); + for (int i = 0; i < 256; i++) + { + short data = (short)io_in16(0x1f0); + *((short *)memory_addrress) = data; + memory_addrress += 2; + } +} + +void write_disk_one_sertor(int lba, unsigned int memory_addrress) +{ + while (io_in8(0x1f7) & 0x80) + ; + select_sector(lba); + io_out8(0x1f7, 0x30); + wait_disk_ready(); + for (int i = 0; i < 256; i++) + { + short data = *((short *)memory_addrress); + io_out16(0x1f0, data); + memory_addrress += 2; + } +} + +void read_disk(int lba, int sector_count, unsigned int memory_addrress) +{ + for (int i = 0; i < sector_count; i++) + { + read_disk_one_sector(lba, memory_addrress); + lba++; + memory_addrress += 512; + } +} + +void write_disk(int lba, int sector_count, unsigned int memory_addrress) +{ + for (int i = 0; i < sector_count; i++) + { + write_disk_one_sertor(lba, memory_addrress); + lba++; + memory_addrress += 512; + } +} \ No newline at end of file diff --git a/include/disk.h b/include/disk.h new file mode 100644 index 0000000..0350aef --- /dev/null +++ b/include/disk.h @@ -0,0 +1,11 @@ +#ifndef CPOS_DISK_H +#define CPOS_DISK_H + +void wait_disk_ready(); //不适用于SATA硬盘 +void select_sector(int lba); +void read_disk_one_sector(int lba, unsigned int memory_addrress); +void write_disk_one_sertor(int lba, unsigned int memory_addrress); +void read_disk(int lba, int sector_count, unsigned int memory_addrress); +void write_disk(int lba, int sector_count, unsigned int memory_addrress); + +#endif \ No newline at end of file diff --git a/include/fat16.h b/include/fat16.h new file mode 100644 index 0000000..b842703 --- /dev/null +++ b/include/fat16.h @@ -0,0 +1,48 @@ +#ifndef CPOS_FAT16_H +#define CPOS_FAT16_H + +#define SECTOR_SIZE 512 +#define FAT1_SECTORS 32 //FAT1占用扇区数 +#define ROOT_DIR_SECTORS 32 //根目录占用扇区数 +#define SECTOR_NUM_OF_FAT1_START 1 //FAT1起始扇区号 +#define SECTOR_NUM_OF_ROOT_DIR_START 33 //根目录起始扇区号 +#define SECTOR_NUM_OF_DATA_START 65 //数据区起始扇区号,对应簇号为2。 +#define SECTOR_CLUSTER_BALANCE SECTOR_NUM_OF_DATA_START - 2 //簇号加上该值正好对应扇区号。 +#define MAX_FILE_NUM 16 //最大文件数 + +// FAT16目录项结构(32B); +struct File { + // 文件名 如果第一个字节为0xe5,代表这个文件已经被删除;如果第一个字节为0x00,代表这一段不包含任何文件名信息。 + unsigned char name[8]; + unsigned char ext[3]; // 扩展名 + // 属性:bit0只读文件,bit1隐藏文件,bit2系统文件,bit3非文件信息(比如磁盘名称),bit4目录,bit5文件。 + unsigned char type; // 0x20 文件 | 0x10 目录 + unsigned char reserve[10]; // 保留 + unsigned short time; // 最后一次写入时间 + unsigned short date; // 最后一次写入日期 + unsigned short clustno; // 起始簇号 + unsigned int size; // 文件大小 +}; + +void read_root_dir_sector1(struct File *root_entries); +void save_root_dir_sector1(struct File *root_entries); +void read_one_cluster(unsigned short clustno, unsigned int memory_addrress); +int read_root_dir(struct File *file_infos); +void get_fat1(unsigned short *fat1); +void save_fat1(unsigned short *fat1); +void get_file_all_clustnos(unsigned short first_clustno, unsigned short *clustnos); +void get_file_all_clustnos(unsigned short first_clustno, unsigned short *clustnos); +void read_file(struct File *file, void *file_addr); +void check_name_or_ext(char *str, int len); +void check_name_and_ext(char *name, char *ext); +void analyse_fullname(char *fullname, char *name, char *ext); +int find_file(char *name, char *ext, struct File *const file); +struct File *create_file(char *fullname); +struct File *create_dir(char *fullname); +struct File *open_file(char *fullname); +void alter_file_name(struct File *file, char *new_fullname); +void alter_dir_entry(struct File *file); +void save_file(struct File *file, char *content); +void delete_file(struct File *file); + +#endif \ No newline at end of file diff --git a/include/multiboot.h b/include/multiboot.h index 89a7131..0b6abcd 100644 --- a/include/multiboot.h +++ b/include/multiboot.h @@ -3,7 +3,7 @@ #include -#define VERSION "0.0.1" +#define VERSION "0.0.2" #define LOADER_SAVE_GRAPHICS_ADDRESS 0xB8000 // loader中保存显存地址的地址 #define VARTUAL_GRAPHICS_ADDRESS 0xe0000000 diff --git a/include/shell.h b/include/shell.h index e47feff..bbd0594 100644 --- a/include/shell.h +++ b/include/shell.h @@ -10,5 +10,8 @@ void setup_shell(); //内置命令 void end_echo(int argc,char **argv); +void cmd_ls(); +void cmd_cat(int argc,char **argv); +void cmd_read(int argc,char **argv); #endif \ No newline at end of file diff --git a/isodir/sys/kernel.elf b/isodir/sys/kernel.elf index 5357678..0205b33 100644 Binary files a/isodir/sys/kernel.elf and b/isodir/sys/kernel.elf differ diff --git a/kernel/fat16.c b/kernel/fat16.c new file mode 100644 index 0000000..1098416 --- /dev/null +++ b/kernel/fat16.c @@ -0,0 +1,357 @@ +#include "../include/fat16.h" +#include "../include/memory.h" +#include "../include/disk.h" + +void read_root_dir_sector1(struct File *root_entries) +{ + read_disk(SECTOR_NUM_OF_ROOT_DIR_START, 1, (unsigned int)root_entries); +} + +void save_root_dir_sector1(struct File *root_entries) +{ + write_disk(SECTOR_NUM_OF_ROOT_DIR_START, 1, (unsigned int)root_entries); +} + +void read_one_cluster(unsigned short clustno, unsigned int memory_addrress) +{ + read_disk(clustno + SECTOR_CLUSTER_BALANCE, 1, memory_addrress); +} + +int read_root_dir(struct File *file_infos) +{ + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + int n = 0; // 记录文件数 + for (int i = 0; i < MAX_FILE_NUM; i++) + { + if (root_entries[i].name[0] == 0) + { + break; + } + if (root_entries[i].name[0] != 0xe5) + { + file_infos[n] = root_entries[i]; + n++; + } + } + kfree(root_entries); + return n; +} + +void get_fat1(unsigned short *fat1) +{ + read_disk(SECTOR_NUM_OF_FAT1_START, FAT1_SECTORS, (unsigned int)fat1); // 将FAT1全部读取到内存中。 +} + +void save_fat1(unsigned short *fat1) +{ + write_disk(SECTOR_NUM_OF_FAT1_START, FAT1_SECTORS, (unsigned int)fat1); // 将FAT1全部写回到内存中。 +} + +void get_file_all_clustnos(unsigned short first_clustno, unsigned short *clustnos) +{ + unsigned short *fat1 = kmalloc(FAT1_SECTORS * SECTOR_SIZE); + get_fat1(fat1); + *clustnos = first_clustno; + while (1) + { + unsigned short clustno = *(fat1 + *clustnos); + clustnos++; + *clustnos = clustno; + if (clustno >= 0xfff8) // 大于等于0xfff8表示文件的最后一个簇 + { + break; + } + } + kfree(fat1); +} + +void read_file(struct File *file, void *file_addr) +{ + if (file->size == 0) + { + return; + } + int cluster_count = (file->size + 511) / 512; + unsigned short *clustnos = kmalloc(cluster_count * 2); + get_file_all_clustnos(file->clustno, clustnos); + for (int i = 0; i < cluster_count; i++) + { + read_one_cluster(clustnos[i], (unsigned int)file_addr); + file_addr += 512; + } + kfree(clustnos); +} + +void check_name_or_ext(char *str, int len) +{ + for (int i = 0; i < len; i++) + { + if (str[i] == 0) + { + str[i] = ' '; + } + else if ('a' <= str[i] && str[i] <= 'z') + { + str[i] -= 0x20; + } + } +} + +void check_name_and_ext(char *name, char *ext) +{ + check_name_or_ext(name, 8); + check_name_or_ext(ext, 3); +} + +void analyse_fullname(char *fullname, char *name, char *ext) +{ + int ext_dot_index = -1; + for (int i = 11; i >= 0; i--) + { + if (fullname[i] == '.') + { + ext_dot_index = i; + } + } + if (ext_dot_index == -1) // 没有后缀名的情况 + { + memcpy(name, fullname, 8); + memset(ext, ' ', 3); + } + else if (ext_dot_index == 0) // 没有文件名的情况 + { + memset(name, ' ', 8); + memcpy(ext, fullname + 1, 3); + } + else + { + memcpy(name, fullname, ext_dot_index); + memcpy(ext, fullname + ext_dot_index + 1, 3); + } + check_name_and_ext(name, ext); +} + +int find_file(char *name, char *ext, struct File *const file) +{ + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + int isfind = 0; + for (int i = 0; i < MAX_FILE_NUM; i++) + { + if (memcmp(root_entries[i].name, name, 8) == 0 && memcmp(root_entries[i].ext, ext, 3) == 0) + { + if (file != 0) + { + *file = root_entries[i]; + } + isfind = 1; + } + } + kfree(root_entries); + return isfind; +} + +struct File *create_dir(char *fullname){ + char name[8] = {0}; + char ext[3] = {0}; + analyse_fullname(fullname, name, ext); + int isfind = find_file(name, ext, 0); + if (isfind) { + return 0; //文件已存在。 + } + + struct File *file = (struct File *) kmalloc(32); + memcpy(file->name, name, 8); + memcpy(file->ext, " ", 3); + file->type = 0x10; + file->time = 0; + file->date = 0; + file->clustno = 0; + file->size = 0; + + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (root_entries[i].name[0] == 0 || root_entries[i].name[0] == 0xe5) { //找一个空闲的文件项存放。 + root_entries[i] = *file; + break; + } + } + save_root_dir_sector1(root_entries); + kfree(root_entries); + return file; +} + +struct File *create_file(char *fullname) { + char name[8] = {0}; + char ext[3] = {0}; + analyse_fullname(fullname, name, ext); + int isfind = find_file(name, ext, 0); + if (isfind) { + return 0; //文件已存在。 + } + + struct File *file = (struct File *) kmalloc(32); + memcpy(file->name, name, 8); + memcpy(file->ext, ext, 3); + file->type = 0x20; + file->time = 0; + file->date = 0; + file->clustno = 0; + file->size = 0; + + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (root_entries[i].name[0] == 0 || root_entries[i].name[0] == 0xe5) { //找一个空闲的文件项存放。 + root_entries[i] = *file; + break; + } + } + save_root_dir_sector1(root_entries); + + kfree(root_entries); + //open_file_task(file); + kfree(name); + kfree(ext); + return file; +} + +struct File *open_file(char *fullname) { + char name[8] = {0}; + char ext[3] = {0}; + analyse_fullname(fullname, name, ext); + struct File *file = (struct File *) kmalloc(32); + int isfind = find_file(name, ext, file); + if (!isfind) { + kfree(file); + file = 0; + } else { + //set_opened_file(file); + } + return file; +} + +void alter_file_name(struct File *file, char *new_fullname) { + char new_name[8] = {0}; + char new_ext[3] = {0}; + analyse_fullname(new_fullname, new_name, new_ext); + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (memcmp(root_entries[i].name, file->name, 8) == 0 && memcmp(root_entries[i].ext, file->ext, 3) == 0) { + memcpy(root_entries[i].name, new_name, 8); + memcpy(root_entries[i].ext, new_ext, 3); + } + } + save_root_dir_sector1(root_entries); + kfree(root_entries); +} + +void alter_dir_entry(struct File *file) { + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (memcmp(root_entries[i].name, file->name, 8) == 0 && memcmp(root_entries[i].ext, file->ext, 3) == 0) { + root_entries[i] = *file; + } + } + save_root_dir_sector1(root_entries); + kfree(root_entries); +} + +void save_file(struct File *file, char *content) { + unsigned int file_size = strlen(content); //内容大小 + if (file_size == 0 && file->size == 0) { + return; + } + file->size = file_size; + int sector_num = (file_size + 511) / 512; //将要占用的扇区数 + unsigned short *fat1 = kmalloc(FAT1_SECTORS * SECTOR_SIZE); + get_fat1(fat1); + unsigned short clustno = file->clustno; + unsigned short next_clustno; + if (file->clustno == 0) //第一次写入 + { + clustno = 2; //可用簇号从2开始 + while (1) { + if (*(fat1 + clustno) == 0) //空闲簇号 + { + file->clustno = clustno; //分配起始簇号 + break; + } else { + clustno++; + } + } + } + int i = 0; + while (1) { + write_disk(SECTOR_CLUSTER_BALANCE + clustno, 1, (unsigned int) content); + if (i == sector_num - 1) { //已写完最后一扇区。 + break; + } + i++; + content += 512; + next_clustno = *(fat1 + clustno); + if (next_clustno == 0 || next_clustno >= 0xfff8) { //寻找下一个可用簇号 + next_clustno = clustno + 1; + while (1) { + if (*(fat1 + next_clustno) == 0) { + *(fat1 + clustno) = next_clustno; + break; + } else { + next_clustno++; + } + } + } + clustno = next_clustno; + } + next_clustno = *(fat1 + clustno); + *(fat1 + clustno) = 0xffff; //0xfff8~0xffff表示文件结束,没有下一个簇了。 + //如果本次写入的内容比上次的少,上次用过的簇号本次用不完,以下将剩下的簇号清零处理。 + if (1 < next_clustno && next_clustno < 0xfff0) { + while (1) { + clustno = next_clustno; + next_clustno = *(fat1 + clustno); + *(fat1 + clustno) = 0; + if (next_clustno >= 0xfff8) { + break; + } + } + } + alter_dir_entry(file); + save_fat1(fat1); + kfree(fat1); +} + +void delete_file(struct File *file) { + //1.标记目录项为已删除。 + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (memcmp(root_entries[i].name, file->name, 8) == 0 && memcmp(root_entries[i].ext, file->ext, 3) == 0) { + root_entries[i].name[0] = 0xe5; + break; + } + } + save_root_dir_sector1(root_entries); + kfree(root_entries); + if (file->clustno == 0) { + return; + } + unsigned short *fat1 = kmalloc(FAT1_SECTORS * SECTOR_SIZE); + get_fat1(fat1); + unsigned short clustno = file->clustno; + unsigned short next_clustno = 0; + while (1) { + next_clustno = *(fat1 + clustno); + *(fat1 + clustno) = 0; + if (next_clustno >= 0xfff8) { + break; + } + clustno = next_clustno; + } + save_fat1(fat1); + kfree(fat1); +} \ No newline at end of file diff --git a/sysapp/shell.c b/sysapp/shell.c index f61251b..cf18628 100644 --- a/sysapp/shell.c +++ b/sysapp/shell.c @@ -5,6 +5,8 @@ #include "../include/keyboard.h" #include "../include/io.h" #include "../include/common.h" +#include "../include/fat16.h" +#include "../include/memory.h" extern Queue *key_char_queue; @@ -78,6 +80,59 @@ void cmd_echo(int argc,char **argv) vga_putchar('\n'); } +void cmd_ls() +{ + struct File *root = (struct File*) kmalloc(sizeof(struct File) * MAX_FILE_NUM); + int files = read_root_dir(root); + int index = 0,size = 0; + + for (int i = 0; i < files; ++i) + { + struct File file = root[i]; + if(!strcmp(file.name,"\0")) continue; + printf("%s %s %d\n",file.name,file.type == 0x20 ? "" : " ",file.size); + index++; + size += file.size; + } + printf(" All File: %d | All Size: %d\n",index,size); + kfree(root); +} + +void cmd_cat(int argc,char **argv) +{ + if(argc <= 2) { + printf("[Shell-CAT]: If there are too few parameters, please specify the filename and data."); + return; + } + struct File *file = open_file(argv[1]); + if(file == NULL){ + printf("[Shell-CAT]: Not found [%s] \n",argv[1]); + return; + } + + save_file(file,argv[2]); + kfree(file); +} + +void cmd_read(int argc,char **argv) +{ + if(argc == 1) { + printf("[Shell-READ]: If there are too few parameters, please specify the filename"); + return; + } + struct File *file = open_file(argv[1]); + char* buffer = (char*) kmalloc(4096); + if(file == NULL){ + printf("[Shell-READ]: Not found [%s] \n",argv[1]); + return; + } + + read_file(file,buffer); + printf("%s\n",buffer); + kfree(buffer); + kfree(file); +} + void setup_shell() { vga_clear(); @@ -106,12 +161,21 @@ void setup_shell() cmd_echo(argc,argv); else if(!strcmp("clear",argv[0])) vga_clear(); + else if(!strcmp("ls",argv[0])) + cmd_ls(); + else if(!strcmp("cat",argv[0])) + cmd_cat(argc,argv); + else if(!strcmp("read",argv[0])) + cmd_read(argc,argv); else if(!strcmp("help",argv[0])||!strcmp("?",argv[0])||!strcmp("h",argv[0])) { vga_writestring("-=[CrashPowerShell Helper]=-\n"); - vga_writestring("help ? h empty Print shell help info.\n"); - vga_writestring("version empty Print os version.\n"); + vga_writestring("help ? h |empty Print shell help info.\n"); + vga_writestring("version |empty Print os version.\n"); vga_writestring("echo Print message.\n"); + vga_writestring("ls |empty List all files.\n"); + vga_writestring("cat Edit a file\n"); + vga_writestring("read Read a file\n"); } else printf("[Shell]: Unknown command '%s'.\n",argv[0]); } diff --git a/target/disk.o b/target/disk.o new file mode 100644 index 0000000..1157e27 Binary files /dev/null and b/target/disk.o differ diff --git a/target/fat16.o b/target/fat16.o new file mode 100644 index 0000000..75ba598 Binary files /dev/null and b/target/fat16.o differ diff --git a/target/shell.o b/target/shell.o index 209c228..fa15757 100644 Binary files a/target/shell.o and b/target/shell.o differ