Support XiZi_AIoT

This commit is contained in:
TXuian
2024-01-31 10:30:34 +08:00
parent f6cf46027d
commit 494312183b
351 changed files with 46408 additions and 450091 deletions
@@ -0,0 +1,3 @@
SRC_DIR := fs
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,17 @@
toolchain ?= arm-none-eabi-
cc = ${toolchain}gcc
ld = ${toolchain}g++
objdump = ${toolchain}objdump
user_ldflags = -N -Ttext 0
cflags = -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie -no-pie
c_useropts = -O0
INC_DIR = -I$(KERNEL_ROOT)/services/fs/include -I$(KERNEL_ROOT)/services/lib/ipc -I$(KERNEL_ROOT)/services/boards/imx6q-sabrelite
fs_server: fs_server.o fs_service.o fs.o block_io.o
@mv $^ ../../boards/imx6q-sabrelite
%.o: %.c
@echo "cc $^"
@${cc} ${cflags} ${c_useropts} ${INC_DIR} -o $@ -c $^
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <string.h>
#include "block_io.h"
#include "libserial.h"
#include "fs.h"
#include "list.h"
static void Error(char* s)
{
printf("Error: %s\n", s);
for (;;)
;
}
// Locate the data block using block_num
uint8_t* BlockRead(int block_num)
{
uint8_t* data = (uint8_t*)MemFsRange.memfs_start + block_num * BLOCK_SIZE;
return data;
}
// Zero a block.
static void BlockClear(int block_num)
{
uint8_t* data = BlockRead(block_num);
memset(data, 0, BLOCK_SIZE);
}
// Allocate a zeroed disk block.
uint32_t BlockAlloc()
{
int bit_index, block_index, bit_mark;
struct SuperBlock sb;
ReadSuperBlock(&sb);
for (bit_index = 0; bit_index < sb.size; bit_index += BITMAP_SIZE) {
uint8_t* data = BlockRead(BLOCK_BIT_INDEX(bit_index, sb.ninodes));
for (block_index = 0; block_index < BITMAP_SIZE && bit_index + block_index < sb.size; block_index++) {
bit_mark = 1 << (block_index % 8);
if ((data[block_index / 8] & bit_mark) == 0) {
data[block_index / 8] |= bit_mark;
BlockClear(bit_index + block_index);
return bit_index + block_index;
}
}
}
Error("BlockAlloc: out of blocks");
return 0;
}
// Free a disk block.
void BlockFree(int block_num)
{
struct SuperBlock sb;
int block_index, bit_mark;
ReadSuperBlock(&sb);
uint8_t* data = BlockRead(BLOCK_BIT_INDEX(block_num, sb.ninodes));
block_index = block_num % BITMAP_SIZE;
bit_mark = 1 << (block_index % 8);
if ((data[block_index / 8] & bit_mark) == 0) {
Error("freeing free block");
}
data[block_index / 8] &= ~bit_mark;
}
+482
View File
@@ -0,0 +1,482 @@
// Copyright (c) 2006-2018 Frans Kaashoek, Robert Morris, Russ Cox, Massachusetts Institute of Technology
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* @file fs.c
* @brief support read and write the fs.img
* @version 1.0
* @author AIIT XUOS Lab
* @date 2024-01-25
*/
/*************************************************
File name: fs.c
Description: support read and write the fs.img
Others: take ARM_XV6 kernel/fs.c for references
https://github.com/KingofHamyang/ARM_xv6
History:
1. Date: 2024-01-25
Author: AIIT XUOS Lab
Modification:
1. support inode create and delete
3. remove inode lock and unlock
4. remove inode cache
*************************************************/
#include <string.h>
#include "block_io.h"
#include "libserial.h"
#include "fs.h"
static void Error(char* s)
{
printf("Error: %s\n", s);
for (;;)
;
}
#define min(a, b) ((a) < (b) ? (a) : (b))
static int DirInodeAddEntry(struct Inode* dp, char* name, uint32_t inum);
static struct Inode* DirInodeLookup(struct Inode* dp, char* name, uint32_t* poff);
static struct Inode* InodeAlloc(short type);
static int InodeFree(struct Inode* ip);
static int InodeFreeRecursive(struct Inode* dp);
static char* PathElementExtract(char* path, char* name);
static uint32_t InodeBlockMapping(struct Inode* ip, uint32_t block_num);
#define MAX_SUPPORT_FD 1024
static struct FileDescriptor fd_table[MAX_SUPPORT_FD];
struct MemFsRange MemFsRange;
/// @brief Using syscall to get fs.img real location in the memory
void MemFsInit(uintptr_t _binary_fs_img_start, uint32_t fs_img_len)
{
MemFsRange.memfs_start = _binary_fs_img_start;
MemFsRange.memfs_nr_blocks = fs_img_len / BLOCK_SIZE;
}
/// @brief Read the super block.
void ReadSuperBlock(struct SuperBlock* sb)
{
uint8_t* data = BlockRead(ROOT_INUM);
memmove(sb, data, sizeof(*sb));
}
/// @brief Get a existed Inode by inum
struct Inode* InodeGet(uint32_t inum)
{
struct Inode* ip;
uint8_t* data = BlockRead(BLOCK_INDEX(inum));
ip = (struct Inode*)data + INODE_INDEX(inum);
return ip;
}
/// @brief Alloc a new Inode using type
static struct Inode* InodeAlloc(short type)
{
int inum;
struct Inode* ip;
struct SuperBlock sb;
ReadSuperBlock(&sb);
for (inum = 1; inum < sb.ninodes; inum++) {
uint8_t* data = BlockRead(BLOCK_INDEX(inum));
ip = (struct Inode*)data + INODE_INDEX(inum);
if (ip->type == 0) {
memset(ip, 0, sizeof(*ip));
ip->inum = inum;
ip->type = type;
ip->nlink = 1;
ip->size = 0;
return ip;
}
}
Error("InodeAlloc: no inodes");
return NULL;
}
/// @brief Free the existed Inode
static int InodeFree(struct Inode* ip)
{
uint8_t* data = BlockRead(BLOCK_INDEX(ip->inum));
struct Inode* dip = (struct Inode*)data + INODE_INDEX(ip->inum);
dip->type = 0;
return 0;
}
/// @brief Delete the dir and all files or dirs under the dir.
static int InodeFreeRecursive(struct Inode* dp)
{
uint32_t off;
struct Inode* ip;
struct DirectEntry de;
for (off = 0; off < dp->size; off += sizeof(de)) {
if (InodeRead(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
Error("inode_delete_dir failed: read directory entry failed");
}
// unlink dir
if (de.inum == 0 || strcmp(de.name, "..") == 0 || strcmp(de.name, ".") == 0) {
continue;
}
ip = InodeGet(de.inum);
if (ip->type == T_DIR) {
if (InodeFreeRecursive(ip) < 0) {
return -1;
}
} else if (ip->type == T_FILE) {
InodeFree(ip);
}
// delete the dir entry
de.inum = 0;
if (InodeWrite(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
printf("InodeDelete failed: clear directory entry failed");
return -1;
}
}
return 0;
}
/// @brief Delete a file Inode or a dir Inode
int InodeDelete(struct Inode* dp, char* name)
{
uint32_t off;
struct Inode* ip;
struct DirectEntry de;
if ((ip = DirInodeLookup(dp, name, &off)) == 0) {
Error("Inode delete failed, file not exsit");
return -1;
}
InodeFree(ip);
if (ip->type == T_DIR) {
// recursive free alloced Inode
if (InodeFreeRecursive(ip) < 0) {
return -1;
}
}
// delete the dir entry
de.inum = 0;
if (InodeWrite(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
printf("InodeDelete failed: clear directory entry failed");
return -1;
}
return 0;
}
/// @brief Create a new Inode under the parent Inode
struct Inode* InodeCreate(struct Inode* dp, char* name, short type, short major, short minor)
{
uint32_t off;
struct Inode* ip;
if ((ip = DirInodeLookup(dp, name, &off)) != 0) {
if (type == T_FILE && ip->type == T_FILE) {
return ip;
}
return 0;
}
if ((ip = InodeAlloc(type)) == 0) {
Error("InodeCreate: create Inode failed\n");
}
if (type == T_DIR) {
dp->nlink++;
if (DirInodeAddEntry(ip, ".", ip->inum) < 0 || DirInodeAddEntry(ip, "..", dp->inum) < 0) {
Error("InodeCreate: create dots");
}
}
if (DirInodeAddEntry(dp, name, ip->inum) < 0) {
Error("InodeCreate: DirInodeAddEntry failed");
}
return ip;
}
/// @brief Mapping the direct block addrs or indirect block addrs of the Inode using the block_num
static uint32_t InodeBlockMapping(struct Inode* ip, uint32_t block_num)
{
uint32_t addr;
// block is in range of direct mapping
if (block_num < NR_DIRECT_BLOCKS) {
if ((addr = ip->addrs[block_num]) == 0) {
ip->addrs[block_num] = addr = BlockAlloc();
}
return addr;
}
// alloc a new indirect indexing block
block_num -= NR_DIRECT_BLOCKS;
int indirect_block_id = block_num / MAX_INDIRECT_BLOCKS;
if (indirect_block_id < NR_INDIRECT_BLOCKS) {
if ((addr = ip->addrs[NR_DIRECT_BLOCKS + indirect_block_id]) == 0) {
ip->addrs[NR_DIRECT_BLOCKS + indirect_block_id] = addr = BlockAlloc();
}
block_num -= indirect_block_id * MAX_INDIRECT_BLOCKS;
} else {
Error("InodeBlockMapping: out of range");
return 0;
}
// alloc a new indirect block
uint32_t* indirect_block = (uint32_t*)BlockRead(addr);
if ((addr = indirect_block[block_num]) == 0) {
indirect_block[block_num] = addr = BlockAlloc();
}
return addr;
}
/// @brief Look up the directory Inode for searching the target Inode
static struct Inode* DirInodeLookup(struct Inode* dp, char* name, uint32_t* poff)
{
uint32_t off, inum;
struct DirectEntry de;
if (dp->type != T_DIR) {
Error("DirInodeLookup not DIR");
}
for (off = 0; off < dp->size; off += sizeof(de)) {
if (InodeRead(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
Error("DirInodeAddEntry read");
}
if (de.inum == 0) {
continue;
}
if (strncmp((const char*)name, (const char*)de.name, DIR_NAME_SIZE) == 0) {
if (poff) {
*poff = off;
}
inum = de.inum;
return InodeGet(inum);
}
}
return 0;
}
/// @brief Add a new directory entry for dir Inode
static int DirInodeAddEntry(struct Inode* dp, char* name, uint32_t inum)
{
int off;
struct DirectEntry de;
struct Inode* ip;
// Check that direct entry is existed.
if ((ip = DirInodeLookup(dp, name, 0)) != 0) {
return -1;
}
// Look for an empty dir entry.
for (off = 0; off < dp->size; off += sizeof(de)) {
if (InodeRead(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
Error("DirInodeAddEntry: read failed");
}
if (de.inum == 0) {
break;
}
}
// build a new direct entry.
strncpy(de.name, name, DIR_NAME_SIZE);
de.inum = inum;
if (InodeWrite(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
Error("DirInodeAddEntry: write failed");
}
return 0;
}
static struct Inode* Seek(struct Inode* ip, char* path, int nameiparent, char* name)
{
if (ip->size == 0) {
Error("Inode is not sync\n");
}
struct Inode* next;
while ((path = PathElementExtract(path, name)) != 0) {
if (ip->type != T_DIR) {
return NULL;
}
if (nameiparent && *path == '\0') {
return ip;
}
if ((next = DirInodeLookup(ip, name, 0)) == 0) {
return NULL;
}
ip = next;
}
if (nameiparent) {
return NULL;
}
return ip;
}
/// @brief Find target Inode from source Inode
struct Inode* InodeSeek(struct Inode* source, char* path)
{
char name[DIR_NAME_SIZE] = { 0 };
return Seek(source, path, 0, name);
}
/// @brief Find target parent Inode from source Inode
struct Inode* InodeParentSeek(struct Inode* source, char* path, char* name)
{
return Seek(source, path, 1, name);
}
/// @brief Copy State information from Inode.
void InodeStateGet(struct Inode* ip, struct State* st)
{
st->ino = ip->inum;
st->type = ip->type;
st->nlink = ip->nlink;
st->size = ip->size;
}
/// @brief Read data from the Inode to the dst buffer.
int InodeRead(struct Inode* ip, char* dst, int off, int n)
{
uint32_t tot, m;
if (off > ip->size || off + n < off) {
return -1;
}
if (off + n > ip->size) {
n = ip->size - off;
}
for (tot = 0; tot < n; tot += m, off += m, dst += m) {
uint8_t* data = BlockRead(InodeBlockMapping(ip, off / BLOCK_SIZE));
m = min(n - tot, BLOCK_SIZE - off % BLOCK_SIZE);
memmove(dst, data + off % BLOCK_SIZE, m);
}
return n;
}
/// @brief Write data from src buffer to the Inode, then increase the Inode size if neccessary.
int InodeWrite(struct Inode* ip, char* src, uint32_t off, uint32_t n)
{
uint32_t tot, m;
if (off > ip->size || off + n < off) {
return -1;
}
if (off + n > MAX_FILE_SIZE * BLOCK_SIZE) {
return -1;
}
for (tot = 0; tot < n; tot += m, off += m, src += m) {
uint8_t* data = BlockRead(InodeBlockMapping(ip, off / BLOCK_SIZE));
m = min(n - tot, BLOCK_SIZE - off % BLOCK_SIZE);
memmove(data + off % BLOCK_SIZE, src, m);
}
if (n > 0 && off > ip->size) {
ip->size = off;
}
return n;
}
// Paths process
static char* PathElementExtract(char* path, char* name)
{
// Skip leading slashes
while (*path == '/')
path++;
// Check for end of path
if (*path == 0)
return NULL;
// Extract element
char* start = path;
while (*path != '/' && *path != 0)
path++;
// Calculate length and copy to 'name'
int len = path - start;
if (len >= DIR_NAME_SIZE)
len = DIR_NAME_SIZE - 1;
strncpy(name, start, len);
name[len] = 0;
// Skip trailing slashes
while (*path == '/')
path++;
return path;
}
struct FileDescriptor* GetFileDescriptor(int fd)
{
if (fd < 0 || fd > MAX_SUPPORT_FD) {
printf("fd invlid.\n");
return NULL;
}
return &fd_table[fd];
}
void FreeFileDescriptor(int fd)
{
if (fd < 0 || fd > MAX_SUPPORT_FD) {
printf("fd invlid.\n");
return;
}
fd_table[fd].data = 0;
return;
}
int AllocFileDescriptor(void)
{
int free_idx = -1;
for (int i = 0; i < MAX_SUPPORT_FD; i++) {
// found free fd
if (free_idx == -1 && fd_table[i].data == 0) {
free_idx = i;
}
}
if (free_idx == -1) {
return -1;
}
return free_idx;
}
@@ -0,0 +1,351 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <stdbool.h>
#include <string.h>
#include "block_io.h"
#include "fs.h"
#include "fs_service.h"
#include "libserial.h"
#include "usyscall.h"
struct CwdPair {
int session_id;
struct Inode* Inode;
};
#define MAX_SUPPORT_SESSION 1024
static struct CwdPair session_cwd[MAX_SUPPORT_SESSION];
static struct CwdPair* get_session_cwd(void)
{
int free_idx = -1;
for (int i = 0; i < MAX_SUPPORT_SESSION; i++) {
// found session cwd
if (session_cwd[i].session_id == cur_session_id()) {
return &session_cwd[i];
}
if (free_idx == -1 && session_cwd[i].session_id == 0) {
free_idx = i;
}
}
// new a cwd pair for session
if (free_idx == -1) {
printf("Connect Session reaches max value.\n");
return NULL;
}
session_cwd[free_idx].session_id = cur_session_id();
session_cwd[free_idx].Inode = InodeGet(ROOT_INUM);
return &session_cwd[free_idx];
}
int IPC_DO_SERVE_FUNC(Ipc_ls)(char* path)
{
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("ls:find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
if (!(ip = InodeSeek(dp, path))) {
printf("ls:find target Inode failed\n");
return -1;
}
if (ip->type != T_DIR) {
printf("ls:not a dir\n");
return -1;
}
uint32_t off;
struct DirectEntry de;
for (off = 0; off < ip->size; off += sizeof(de)) {
if (InodeRead(ip, (char*)&de, off, sizeof(de)) != sizeof(de)) {
printf("ls:read dir entry failed\n");
return -1;
}
if (de.inum == 0) {
continue;
}
printf("%s\n", de.name);
}
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_cd)(char* path)
{
struct CwdPair* cwd;
struct Inode *dp, *ip;
cwd = get_session_cwd();
if (!cwd) {
printf("cd:find current work dir failed\n");
return -1;
}
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
dp = cwd->Inode;
}
if (!(ip = InodeSeek(dp, path))) {
/// @todo Is need to create the Inode when the dir is node existed?
printf("cd:find target Inode failed\n");
return -1;
}
if (ip->type != T_DIR) {
printf("cd:not a dir\n");
return -1;
}
cwd->Inode = ip;
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_mkdir)(char* path)
{
// printf("Create a new directory: %s\n", path);
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
if ((ip = InodeSeek(dp, path)) != NULL) {
/// @todo Is need to return target Inode?
printf("target Inode existed\n");
return -1;
}
char name[DIR_NAME_SIZE] = { 0 };
if (!(ip = InodeParentSeek(dp, path, name))) {
/// @todo Is need to return target Inode?
printf("target parent Inode is not existed\n");
return -1;
}
if (InodeCreate(ip, name, T_DIR, 0, 0) == 0) {
printf("create target Inode %s failed\n", path);
return -1;
}
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_delete)(char* path)
{
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("delete:find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
char name[DIR_NAME_SIZE] = { 0 };
if (!(ip = InodeParentSeek(dp, path, name))) {
printf("delete:target file parent not existed\n");
return -1;
}
if (InodeDelete(ip, name) < 0) {
printf("delete:target file not existed\n");
return -1;
}
return 0;
}
/// @todo Support malloc for user
int IPC_DO_SERVE_FUNC(Ipc_cat)(char* path)
{
static char buffer[BLOCK_SIZE + 1] = { 0 };
buffer[BLOCK_SIZE] = '\0';
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("delete:find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
if (!(ip = InodeSeek(dp, path))) {
printf("delete:target file not existed\n");
return -1;
}
if (ip->type != T_FILE) {
printf("cat: %s Is not a file\n", path);
return -1;
}
uint32_t off;
for (off = 0; off < ip->size; off += BLOCK_SIZE) {
if (InodeRead(ip, buffer, off, BLOCK_SIZE) < 0) {
printf("cat: read file data failed\n");
break;
}
printf("%s", buffer);
}
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_open)(char* path)
{
// printf("Ipc_open: %s\n", path);
int fd;
struct FileDescriptor* fdp;
fd = AllocFileDescriptor();
if (fd < 0) {
printf("open: alloc a new fd failed\n");
return -1;
}
fdp = GetFileDescriptor(fd);
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("ls:find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
if ((ip = InodeSeek(dp, path)) == NULL) {
printf("open: find target Inode failed, path is %s\n", path);
return -1;
}
/// @todo record absolute path
strncpy(fdp->path, path, strlen(path) + 1);
ip->nlink++;
fdp->data = ip;
InodeStateGet(ip, &fdp->st);
return fd;
}
int IPC_DO_SERVE_FUNC(Ipc_close)(int* fd)
{
struct FileDescriptor* fdp = GetFileDescriptor(*fd);
if (!fdp) {
printf("read: fd invalid\n");
return -1;
}
struct Inode* ip = fdp->data;
ip->nlink--;
FreeFileDescriptor(*fd);
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_read)(int* fd, char* dst, int* offset, int* len)
{
// printf("Ipc_read, fd is %d, dst: %x, offset: %d, len: %d\n", *fd, dst, *offset, *len);
struct FileDescriptor* fdp = GetFileDescriptor(*fd);
if (!fdp) {
printf("read: fd invalid\n");
return -1;
}
struct Inode* ip = fdp->data;
if (ip->type != T_FILE) {
printf("read: %s Is not a file\n", fdp->path);
return -1;
}
int cur_read_len = InodeRead(ip, dst, *offset, *len);
return *len;
}
int IPC_DO_SERVE_FUNC(Ipc_write)(int* fd, char* src, int* offset, int* len)
{
// printf("Ipc_write, fd is %d\n", *fd);
struct FileDescriptor* fdp = GetFileDescriptor(*fd);
if (!fdp) {
printf("read: fd invalid\n");
return -1;
}
struct Inode* ip = fdp->data;
if (ip->type != T_FILE) {
printf("read: %s Is not a file\n", fdp->path);
return -1;
}
int cur_write_len = InodeWrite(ip, src, *offset, *len);
return cur_write_len;
}
IPC_SERVER_INTERFACE(Ipc_ls, 1);
IPC_SERVER_INTERFACE(Ipc_cd, 1);
IPC_SERVER_INTERFACE(Ipc_mkdir, 1);
IPC_SERVER_INTERFACE(Ipc_delete, 1);
IPC_SERVER_INTERFACE(Ipc_cat, 1);
IPC_SERVER_INTERFACE(Ipc_open, 1);
IPC_SERVER_INTERFACE(Ipc_close, 1);
IPC_SERVER_INTERFACE(Ipc_read, 4);
IPC_SERVER_INTERFACE(Ipc_write, 4);
IPC_SERVER_REGISTER_INTERFACES(IpcFsServer, 9, Ipc_ls, Ipc_cd, Ipc_mkdir, Ipc_delete, Ipc_cat,
Ipc_open, Ipc_close, Ipc_read, Ipc_write);
int main(int argc, char* argv[])
{
sys_state_info info;
get_memblock_info(&info);
int len = info.memblock_info.memblock_end - info.memblock_info.memblock_start;
mmap(FS_IMG_ADDR, info.memblock_info.memblock_start, len, false);
MemFsInit((uintptr_t)FS_IMG_ADDR, (uint32_t)len);
if (register_server("MemFS") < 0) {
printf("register server name: %s failed.\n", "SimpleServer");
exit();
}
ipc_server_loop(&IpcFsServer);
// never reached
exit();
}
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "fs_service.h"
#include "fs.h"
IPC_INTERFACE(Ipc_ls, 1, path, strlen(path) + 1);
int ls(struct Session* session, char* path)
{
return IPC_CALL(Ipc_ls)(session, path);
}
IPC_INTERFACE(Ipc_cd, 1, path, strlen(path) + 1);
int cd(struct Session* session, char* path)
{
return IPC_CALL(Ipc_cd)(session, path);
}
IPC_INTERFACE(Ipc_mkdir, 1, path, strlen(path) + 1);
int mkdir(struct Session* session, char* path)
{
return IPC_CALL(Ipc_mkdir)(session, path);
}
IPC_INTERFACE(Ipc_delete, 1, path, strlen(path) + 1);
int rm(struct Session* session, char* path)
{
return IPC_CALL(Ipc_delete)(session, path);
}
IPC_INTERFACE(Ipc_cat, 1, path, strlen(path) + 1);
int cat(struct Session* session, char* path)
{
return IPC_CALL(Ipc_cat)(session, path);
}
IPC_INTERFACE(Ipc_open, 1, path, strlen(path) + 1);
int open(struct Session* session, char* path)
{
return IPC_CALL(Ipc_open)(session, path);
}
IPC_INTERFACE(Ipc_close, 1, fd, sizeof(int));
int close(struct Session* session, int fd)
{
return IPC_CALL(Ipc_close)(session, &fd);
}
IPC_INTERFACE(Ipc_read, 4, fd, dst, offset, len, sizeof(int), *(int*)len, sizeof(int), sizeof(int));
int read(struct Session* session, int fd, char* dst, int offset, int len)
{
return IPC_CALL(Ipc_read)(session, &fd, dst, &offset, &len);
}
IPC_INTERFACE(Ipc_write, 4, fd, src, offset, len, sizeof(int), *(int*)len, sizeof(int), sizeof(int));
int write(struct Session* session, int fd, char* src, int offset, int len)
{
return IPC_CALL(Ipc_write)(session, &fd, src, &offset, &len);
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#pragma once
#include <stdint.h>
#include "fs.h"
// Block size
#define BLOCK_SIZE 512
// bits size
#define BITS 8
// Bitmap size of one block
#define BITMAP_SIZE (BLOCK_SIZE * BITS)
// Inode size of one block
#define INODE_SIZE (BLOCK_SIZE / sizeof(struct Inode))
// Caculate block bit index
#define BLOCK_BIT_INDEX(b, ninodes) ((b / BITMAP_SIZE) + (ninodes / INODE_SIZE) + 3)
// Caculate block index by inode number
#define BLOCK_INDEX(inum) ((inum / INODE_SIZE) + 2)
// Caculate inode index in the block
#define INODE_INDEX(inum) (inum % INODE_SIZE)
uint8_t* BlockRead(int block_num);
void BlockFree(int block_num);
uint32_t BlockAlloc();
@@ -0,0 +1,110 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#pragma once
#include <stdint.h>
#include "block_io.h"
// memory file system memlayout.
// [ block 0 ] [ block 1 ] [block 2] [...] [ block 28 ] [ ... ]
// [ unused ] [super block] [Inode bit map] [block bit map] [data blocks]
#define NR_DIRECT_BLOCKS 5 // direct block number
#define NR_INDIRECT_BLOCKS 8 // indirect block number
#define ROOT_INUM 1 // root inode number
#define MAX_INDIRECT_BLOCKS (BLOCK_SIZE / sizeof(uint32_t)) // Mmaximum number of indirect blocks mapped per block
#define MAX_FILE_SIZE (NR_DIRECT_BLOCKS + (NR_INDIRECT_BLOCKS * MAX_INDIRECT_BLOCKS)) // maximum size of a file
// memory fs range
struct MemFsRange {
uintptr_t memfs_start;
uint32_t memfs_nr_blocks;
};
// current state of the Inode
enum INODE_STATE {
I_RESERVED = 0,
I_BUSY,
I_VALID
};
// memfs file type
enum FILE_TYPE {
T_RESERVED = 0,
T_DIR, // Directory
T_FILE, // File
T_DEV, // Device
};
// File system super block
struct SuperBlock {
uint32_t size; // Number of total blocks of file system image
uint32_t nblocks; // Number of data blocks
uint32_t ninodes; // Number of inodes.
};
// state of the Inode
struct State {
short type; // Type of file
int dev; // File system's disk device
uint32_t ino; // Inode number
short nlink; // Number of links to file
uint32_t size; // Size of file in bytes
};
// Inode structure
struct Inode {
uint32_t inum; // Inode number
short type; // File type
short nlink; // Number of links to Inode in file system
uint32_t size; // Size of file (bytes)
uint32_t addrs[NR_DIRECT_BLOCKS + NR_INDIRECT_BLOCKS]; // Data block addresses
};
// directory entry
#define DIR_NAME_SIZE 14
struct DirectEntry {
uint16_t inum;
char name[DIR_NAME_SIZE];
};
// file descriptor definition
#define MAX_PATH_LEN 128
struct FileDescriptor {
char path[MAX_PATH_LEN];
void* data;
struct State st;
};
// range of memory fs
extern struct MemFsRange MemFsRange;
void MemFsInit(uintptr_t _binary_fs_img_start, uint32_t fs_img_len);
void ReadSuperBlock(struct SuperBlock*);
// fs Inode ops
struct Inode* InodeGet(uint32_t inum);
struct Inode* InodeCreate(struct Inode*, char*, short, short, short);
int InodeDelete(struct Inode*, char*);
int InodeRead(struct Inode*, char*, int, int);
int InodeWrite(struct Inode*, char*, uint32_t, uint32_t);
struct Inode* InodeSeek(struct Inode*, char*);
struct Inode* InodeParentSeek(struct Inode*, char*, char*);
void InodeStateGet(struct Inode*, struct State*);
// fs fd ops
struct FileDescriptor* GetFileDescriptor(int fd);
void FreeFileDescriptor(int fd);
int AllocFileDescriptor(void);
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <stdbool.h>
#include <string.h>
#include "fs.h"
#include "libipc.h"
IPC_SERVICES(IpcFsServer, Ipc_ls, Ipc_cd, Ipc_mkdir, Ipc_delete, Ipc_cat,
Ipc_open, Ipc_close, Ipc_read, Ipc_write);
int ls(struct Session* session, char* path);
int cd(struct Session* session, char* path);
int mkdir(struct Session* session, char* path);
int rm(struct Session* session, char* path);
int cat(struct Session* session, char* path);
int open(struct Session* session, char* path);
int close(struct Session* session, int fd);
int read(struct Session* session, int fd, char* dst, int offset, int len);
int write(struct Session* session, int fd, char* src, int offset, int len);
#define FS_IMG_ADDR 0x60000000
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#pragma once
struct double_list_node {
struct double_list_node* next;
struct double_list_node* prev;
};
#define CONTAINER_OF(item, type, member) \
((type*)((char*)(item) - (unsigned long)(&((type*)0)->member)))
#define IS_DOUBLE_LIST_EMPTY(head) \
((head)->next == (head))
/*********************************************
*
* Double linked list operation functions
*
*********************************************/
#define DOUBLE_LIST_ENTRY(item, type, member) \
CONTAINER_OF(item, type, member)
#define DOUBLE_LIST_FOR_EACH_ENTRY(item, head, member) \
for (item = DOUBLE_LIST_ENTRY((head)->next, typeof(*item), member); \
&item->member != (head); \
item = DOUBLE_LIST_ENTRY(item->member.next, typeof(*item), member))
#define DOUBLE_LIST_FOR_EACH_ENTRY_REVERSE(item, head, member) \
for (item = DOUBLE_LIST_ENTRY((head)->prev, typeof(*item), member); \
&item->member != (head); \
item = DOUBLE_LIST_ENTRY(item->member.prev, typeof(*item), member))
__attribute__((always_inline)) static void inline doubleListNodeInit(struct double_list_node* list)
{
list->next = list;
list->prev = list;
}
__attribute__((always_inline)) static void inline _double_list_add(struct double_list_node* new_node, struct double_list_node* prev, struct double_list_node* next)
{
next->prev = new_node;
new_node->next = next;
new_node->prev = prev;
prev->next = new_node;
}
__attribute__((always_inline)) static void inline _double_list_del(struct double_list_node* prev, struct double_list_node* next)
{
next->prev = prev;
prev->next = next;
}
__attribute__((always_inline)) static void inline doubleListAddOnHead(struct double_list_node* new_node, struct double_list_node* head)
{
_double_list_add(new_node, head, head->next);
}
__attribute__((always_inline)) static void inline doubleListAddOnBack(struct double_list_node* new_node, struct double_list_node* head)
{
_double_list_add(new_node, head->prev, head);
}
__attribute__((always_inline)) static void inline doubleListDel(struct double_list_node* entry)
{
_double_list_del(entry->prev, entry->next);
entry->next = entry;
entry->prev = entry;
}