diff --git a/.gitignore b/.gitignore index 19d8aa640..1be6a19fb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.img obj/ img/ +core .vscode initramfs.cpio \ No newline at end of file diff --git a/Makefile b/Makefile index 03c48347f..eec37122f 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ KERNEL_IMG := $(IMG_DIR)/kernel8.img KERNEL_ELF := $(OBJ_DIR)/$(KERNEL_DIR)/kernel8.elf BOOTLOADER_IMG := $(IMG_DIR)/bootloader.img BOOTLOADER_ELF := $(OBJ_DIR)/$(BOOT_DIR)/bootloader.elf +IMG_NAME := sdcard.img RPI3_DTB := $(IMG_DIR)/bcm2710-rpi-3-b-plus.dtb INITRAMFS_CPIO := $(IMG_DIR)/initramfs.cpio @@ -47,7 +48,6 @@ endif # @$(ECHO) "lib object file is $(LIB_OBJ_FILE)" all:$(KERNEL_IMG) $(BOOTLOADER_IMG) - cd rootfs && make $(KERNEL_IMG): $(KERNEL_ELF) $(CROSS_COMPILER)objcopy -O binary $^ $(KERNEL_IMG) @@ -88,34 +88,30 @@ $(OBJ_DIR)/$(LIB_DIR)/%_c.o: $(SRC_DIR)/$(LIB_DIR)/%.c $(INITRAMFS_CPIO): $(INITRAMFS_FILE) cd rootfs; find . | cpio -o -H newc > ../$(INITRAMFS_CPIO) +$(IMG_NAME): + ./createimg.sh $(IMG_NAME) + qemub: all $(INITRAMFS_CPIO) $(RPI3_DTB) qemu-system-aarch64 -M raspi3 -kernel $(BOOTLOADER_IMG) -display none \ - -dtb $(RPI3_DTB) \ - -initrd $(INITRAMFS_CPIO) \ - -serial null -serial pty -qemuk: all $(INITRAMFS_CPIO) $(RPI3_DTB) - qemu-system-aarch64 -M raspi3 -kernel $(KERNEL_IMG) -display none \ -dtb $(RPI3_DTB) \ -initrd $(INITRAMFS_CPIO) \ -serial null -serial stdio - -qemutest: all $(INITRAMFS_CPIO) $(RPI3_DTB) + +qemuk: all $(INITRAMFS_CPIO) $(RPI3_DTB) $(IMG_NAME) qemu-system-aarch64 -M raspi3 -kernel $(KERNEL_IMG) -display none \ -dtb $(RPI3_DTB) \ - -initrd test/initramfs.cpio \ + -initrd $(INITRAMFS_CPIO) \ + -drive if=sd,file=$(IMG_NAME),format=raw \ -serial null -serial stdio - qemutty: $(KERNEL_IMG) qemu-system-aarch64 -M raspi3 -kernel $(KERNEL_IMG) -display none \ -serial null -serial pty .PHONY: clean clean: - cd rootfs && make clean rm -f $(KERNEL_OBJ_FILE) $(KERNEL_ELF) $(BOOTLOADER_OBJ_FILE) $(BOOTLOADER_ELF) $(LIB_OBJ_FILE) $(INITRAMFS_CPIO) .PHONY: clean-all clean-all: clean - cd rootfs && make clean-all - rm -f $(KERNEL_IMG) $(BOOTLOADER_IMG) \ No newline at end of file + rm -f $(KERNEL_IMG) $(BOOTLOADER_IMG) $(IMG_NAME) \ No newline at end of file diff --git a/createimg.sh b/createimg.sh new file mode 100755 index 000000000..c29258f6b --- /dev/null +++ b/createimg.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +IMG_NAME=sdcard.img + +truncate -s 64M $IMG_NAME + +( +echo o # Create a new empty DOS partition table +echo n # Add a new partition +echo p # Primary partition +echo 1 # Partition number +echo # First sector (Accept default: 1) +echo # Last sector (Accept default: varies) +echo t # Change partition type +echo c # Master Boot Record primary partitions type:LBA +echo w # Write changes +) | sudo fdisk $IMG_NAME + +LOOPBACK=`sudo losetup --partscan --show --find $IMG_NAME` + +echo ${LOOPBACK} | grep --quiet "/dev/loop" + +if [ $? = 1 ] +then + echo "[!] losetup failed!" + exit 1 +fi + +sudo mkfs.vfat -F 32 ${LOOPBACK}p1 + +mkdir -p mnt + +sudo mount -t vfat ${LOOPBACK}p1 mnt + +sudo cp -r img/* mnt + +sudo umount mnt + +sudo losetup -d ${LOOPBACK} +# dd if=./sdcard.img of=/dev/ \ No newline at end of file diff --git a/inc/arm.h b/inc/arm.h new file mode 100644 index 000000000..8b8f4c239 --- /dev/null +++ b/inc/arm.h @@ -0,0 +1,32 @@ +#ifndef _ARM_H +#define _ARM_H + +/* ==== PAR_EL1 related ==== */ +#define PAR_FAILED(par) (par & 1) +#define PAR_PA(par) (par & 0x0000fffffffff000) + +/* ==== ESR_EL1 related ==== */ +#define EC_SVC_64 0x15 +// instruction abort +#define EC_IA_LE 0x20 +// data abort +#define EC_DA_LE 0x24 + +#define ISS_FSC(esr) (esr->iss & 0x3f) + +// Translation faults +#define FSC_TF_L0 0b000100 +#define FSC_TF_L1 0b000101 +#define FSC_TF_L2 0b000110 +#define FSC_TF_L3 0b000111 + +// write abort +#define ISS_WnR(esr) (esr->iss & 0x40) + +typedef struct{ + unsigned int iss:25, + il:1, + ec:6; +} esr_el1_t; + +#endif \ No newline at end of file diff --git a/inc/builtin.h b/inc/builtin.h index f31ef56e6..78244b46a 100644 --- a/inc/builtin.h +++ b/inc/builtin.h @@ -6,11 +6,11 @@ void _hello(void); void _hwinfo(void); void _reboot(void); void _echo(char *shell_buf); -void _ls(uint64 _initramfs_addr); -void _cat(uint64 _initramfs_addr, char *filename); +void _ls(void); +void _cat(char *filename); void _parsedtb(char *fdt_base); void *_malloc(char *size); -void _exec(uint64 _initramfs_addr, char *filename); +void _exec(char *filename); void _chmod_uart(); int _setTimeout(char *shell_buf); void _thread_test(); diff --git a/inc/cpio.h b/inc/cpio.h index 1d1e87468..721103e70 100644 --- a/inc/cpio.h +++ b/inc/cpio.h @@ -28,5 +28,6 @@ void cpio_cat(char *cpio, char *filename); * Return the size of the file, return 0 if no such file. */ uint32 cpio_load_prog(char *cpio, const char *filename, char **output_data); +uint32 cpio_read_hex(char *p); #endif \ No newline at end of file diff --git a/inc/cpiofs.h b/inc/cpiofs.h new file mode 100644 index 000000000..bd2a75ee3 --- /dev/null +++ b/inc/cpiofs.h @@ -0,0 +1,56 @@ +#ifndef _CPIOFS_H +#define _CPIOFS_H + +#include +#include + +#define CPIO_TYPE_MASK 0060000 +#define CPIO_TYPE_DIR 0040000 +#define CPIO_TYPE_FILE 0000000 + +#define CPIOFS_TYPE_UNDEFINE 0x0 +#define CPIOFS_TYPE_FILE 0x1 +#define CPIOFS_TYPE_DIR 0x2 + +struct cpiofs_file_t { + const char *data; + int size; +}; + +struct cpiofs_dir_t { + /* Link cpiofs_internal */ + struct list_head list; +}; + +struct cpiofs_internal { + const char *name; + int type; + union { + struct cpiofs_file_t file; + struct cpiofs_dir_t dir; + }; + struct vnode *node; + struct list_head list; +}; + +int cpiofs_mount(struct filesystem *fs, struct mount *mount); +int cpiofs_sync(struct filesystem *fs); +int cpiofs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name); +int cpiofs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name); +int cpiofs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name); +int cpiofs_isdir(struct vnode *dir_node); +int cpiofs_getname(struct vnode *dir_node, const char **name); +int cpiofs_getsize(struct vnode *dir_node); +int cpiofs_write(struct file *file, const void *buf, size_t len); +int cpiofs_read(struct file *file, void *buf, size_t len); +int cpiofs_open(struct vnode *file_node, struct file *target); +int cpiofs_close(struct file *file); +long cpiofs_lseek64(struct file *file, long offset, int whence); +int cpiofs_ioctl(struct file *file, uint64 request, va_list args); + +struct filesystem *cpiofs_init(void); + +#endif \ No newline at end of file diff --git a/inc/dt17.h b/inc/dt17.h index e952d5b91..291b8ef0d 100644 --- a/inc/dt17.h +++ b/inc/dt17.h @@ -11,8 +11,8 @@ int initramfs_parse_fdt(int level, char *cur, char *dt_strings); void initramfs_init(char *fdt_base); void dtb_traverse(char *fdt_base); -uint64 _initramfs_addr; -uint64 _initramfs_end; +void *_initramfs_addr; +void *_initramfs_end; #define FDT_MAGIC_NUM 0xd00dfeed #define FDT_BEGIN_NODE 0x00000001 diff --git a/inc/entry.h b/inc/entry.h new file mode 100644 index 000000000..e73598294 --- /dev/null +++ b/inc/entry.h @@ -0,0 +1,9 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#include +#include + +void el0_sync_handler(trapframe *regs, uint32 syn); + +#endif \ No newline at end of file diff --git a/inc/exec.h b/inc/exec.h index 539a729d7..a084523b0 100644 --- a/inc/exec.h +++ b/inc/exec.h @@ -4,7 +4,7 @@ void user_prog_start(void); // pass the user stack pointer and process memory location (program loaded) -void sched_new_user_prog(char *cpio, char *file_name); +void sched_new_user_prog(char *file_name); void exit_user_prog(void); diff --git a/inc/fat32fs.h b/inc/fat32fs.h new file mode 100644 index 000000000..d786977a6 --- /dev/null +++ b/inc/fat32fs.h @@ -0,0 +1,177 @@ +#ifndef _FAT32FS_H +#define _FAT32FS_H + +#include +#include + +#define BLOCK_SIZE 512 +#define CLUSTER_ENTRY_PER_BLOCK (BLOCK_SIZE / sizeof(struct cluster_entry_t)) +#define DIR_PER_BLOCK (BLOCK_SIZE / sizeof(struct dir_t)) +#define FAT_DIR 1 +#define FAT_FILE 2 +#define INVALID_CID 0x0ffffff8 + +#define ATTR_READ_ONLY 0x01 +#define ATTR_HIDDEN 0x02 +#define ATTR_SYSTEM 0x04 +#define ATTR_VOLUME_ID 0x08 +#define ATTR_LFN 0x0f +#define ATTR_DIRECTORY 0x10 +#define ATTR_ARCHIVE 0x20 +#define ATTR_FILE_DIR_MASK (ATTR_DIRECTORY | ATTR_ARCHIVE) + +struct partition_t { + uint8 status; + uint8 chss_head; + uint8 chss_sector; + uint8 chss_cylinder; + uint8 type; + uint8 chse_head; + uint8 chse_sector; + uint8 chse_cylinder; + uint32 lba; + uint32 sectors; +} __attribute__((packed)); + +struct boot_sector_t { + uint8 jmpboot[3]; + uint8 oemname[8]; + uint16 bytes_per_sector; + uint8 sector_per_cluster; + uint16 reserved_sector_cnt; + uint8 fat_cnt; + uint16 root_entry_cnt; + uint16 old_sector_cnt; + uint8 media; + uint16 sector_per_fat16; + uint16 sector_per_track; + uint16 head_cnt; + uint32 hidden_sector_cnt; + uint32 sector_cnt; + uint32 sector_per_fat32; + uint16 extflags; + uint16 ver; + uint32 root_cluster; + uint16 info; + uint16 bkbooksec; + uint8 reserved[12]; + uint8 drvnum; + uint8 reserved1; + uint8 bootsig; + uint32 volid; + uint8 vollab[11]; + uint8 fstype[8]; +} __attribute__((packed)); + +struct dir_t { + uint8 name[11]; + uint8 attr; + uint8 ntres; + uint8 crttimetenth; + uint16 crttime; + uint16 crtdate; + uint16 lstaccdate; + uint16 ch; + uint16 wrttime; + uint16 wrtdate; + uint16 cl; + uint32 size; +} __attribute__((packed)); + +struct long_dir_t { + uint8 order; + uint8 name1[10]; + uint8 attr; + uint8 type; + uint8 checksum; + uint8 name2[12]; + uint16 fstcluslo; + uint8 name3[4]; +} __attribute__((packed)); + +struct cluster_entry_t{ + union + { + uint32 val; + struct { + uint32 idx:28; + uint32 reserved: 4; + }; + }; +}; + +struct filename_t{ + union { + uint8 fullname[256]; + struct{ + uint8 name[13]; + } part[20]; + }; +} __attribute__((packed)); + + +struct fat_file_block_t{ + struct list_head list; + uint32 oid; + uint32 cid; + /* Already read the data into buf*/ + uint32 read; + uint32 dirty; + uint8 buf[BLOCK_SIZE]; +}; + +struct fat_file_t{ + /* Head of fat_file_block_t chain */ + struct list_head list; + uint32 size; +}; + +struct fat_dir_t { + /* Head of fat_internal chain */ + struct list_head list; +}; + +struct fat_info_t{ + struct boot_sector_t bs; + uint32 fat_lba; + uint32 cluster_lba; +}; + +struct fat_internal{ + const char *name; + struct vnode *node; + struct fat_info_t *fat; + struct list_head list; + uint32 cid; + uint32 type; + union { + struct fat_dir_t *dir; + struct fat_file_t *file; + }; +}; + +struct fat_mount_t { + /* Link fat_mount_t */ + struct list_head list; + struct mount *mount; +}; + +int fat32fs_mount(struct filesystem *fs, struct mount *mount); + +int fat32fs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fat32fs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fat32fs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fat32fs_isdir(struct vnode *dir_node); +int fat32fs_getname(struct vnode *dir_node, const char **name); +int fat32fs_getsize(struct vnode *dir_node); + +int fat32fs_write(struct file *file, const void *buf, size_t len); +int fat32fs_read(struct file *file, void *buf, size_t len); +int fat32fs_open(struct vnode *file_node, struct file *target); +int fat32fs_close(struct file *file); +long fat32fs_lseek64(struct file *file, long offset, int whence); +int fat32fs_ioctl(struct file *file, uint64 request, va_list args); +int fat32fs_sync(struct filesystem *fs); +struct filesystem *fat32fs_init(void); + +#endif \ No newline at end of file diff --git a/inc/framebufferfs.h b/inc/framebufferfs.h new file mode 100644 index 000000000..e50ba0e4c --- /dev/null +++ b/inc/framebufferfs.h @@ -0,0 +1,40 @@ +#ifndef _FRAMEBUFFERFS_H +#define _FRAMEBUFFERFS_H + +#include +#include + +struct fb_info{ + uint32 width; + uint32 height; + uint32 pitch; + uint32 isrgb; +}; + +struct fbfs_internal{ + const char *name; + struct vnode oldnode; + uint8 *lfb; + uint32 lfbsize; + int isopened; + int isinit; +}; + +int fbfs_mount(struct filesystem *fs, struct mount *mount); +int fbfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fbfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fbfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fbfs_isdir(struct vnode *dir_node); +int fbfs_getname(struct vnode *dir_node, const char **name); +int fbfs_getsize(struct vnode *dir_node); +int fbfs_write(struct file *file, const void *buf, size_t len); +int fbfs_read(struct file *file, void *buf, size_t len); +int fbfs_open(struct vnode *file_node, struct file *target); +int fbfs_close(struct file *file); +long fbfs_lseek64(struct file *file, long offset, int whence); +int fbfs_ioctl(struct file *file, uint64 request, va_list args); +int fbfs_sync(struct filesystem *fs); + +struct filesystem *framebufferfs_init(void); + +#endif \ No newline at end of file diff --git a/inc/fsinit.h b/inc/fsinit.h new file mode 100644 index 000000000..f283a3fbe --- /dev/null +++ b/inc/fsinit.h @@ -0,0 +1,9 @@ +#ifndef _FSINIT_H +#define _FSINIT_H + +#include +#include + +void fs_early_init(void); + +#endif \ No newline at end of file diff --git a/inc/kthread.h b/inc/kthread.h index 927fed04a..4d7c303dc 100644 --- a/inc/kthread.h +++ b/inc/kthread.h @@ -9,6 +9,8 @@ void kthread_create(void (*start)(void)); void kthread_fini(void); +void kthread_early_init(void); + void kthread_add_wait_queue(task_struct *task); void kthread_kill_zombies(void); diff --git a/inc/list.h b/inc/list.h index b84117a7e..60aeea8e4 100644 --- a/inc/list.h +++ b/inc/list.h @@ -399,6 +399,22 @@ static inline void list_move_tail(struct list_head *node, entry = list_entry(entry->member.next, __typeof__(*entry), member)) #endif +/** + * iter_for_each_entry - iterate over list entries from @iter + * @entry: pointer used as iterator + * @iter: pointer to the start of this iteration + * @head: pointer to the head of the list + * @member: name of the list_head member variable in struct type of @entry + * + * FIXME: remove dependency of __typeof__ extension + */ +#ifdef __LIST_HAVE_TYPEOF +#define iter_for_each_entry(entry, iter, head, member) \ + for (entry = list_entry(iter, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) +#endif /* __LIST_HAVE_TYPEOF */ + /** * list_for_each_safe - Iterate over list nodes and allow deletions * @node: list_head pointer used as iterator diff --git a/inc/mbox.h b/inc/mbox.h index de3910d83..1d8e46040 100644 --- a/inc/mbox.h +++ b/inc/mbox.h @@ -17,6 +17,27 @@ extern volatile unsigned int mbox[36]; #define MBOX_CH_COUNT 7 #define MBOX_CH_PROP 8 +/* MMIO */ +#define MMIO_BASE 0x3F000000 +#define VIDEOCORE_MBOX PA2VA(MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +/* Mailbox tags */ +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 + +#define REQUEST_CODE 0x00000000 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + /* tags */ #define MBOX_TAG_GETSERIAL 0x10004 #define MBOX_TAG_LAST 0 diff --git a/inc/mem.h b/inc/mem.h index 6478d5846..629a0f76e 100644 --- a/inc/mem.h +++ b/inc/mem.h @@ -3,11 +3,11 @@ #include -extern char start_mem; -extern char end_mem; +extern char _early_mem_base; +extern char _early_mem_end; -#define SMEM (&start_mem) -#define EMEM (&end_mem) +#define SMEM (&_early_mem_base) +#define EMEM (&_early_mem_end) void *simple_malloc(uint32 size); diff --git a/inc/mini_uart.h b/inc/mini_uart.h index d6340690d..85534fdbb 100644 --- a/inc/mini_uart.h +++ b/inc/mini_uart.h @@ -1,19 +1,21 @@ #ifndef _MINI_UART_H #define _MINI_UART_H #include +#include char uart_recv (void); void uart_recvn(char *buff, int n); void uart_send (char c); -void uart_send_string(char *str); -void uart_send_hex(unsigned int d); +void uart_printf(const char *fmt, ...); +void uart_sync_printf(const char *fmt, ...); +void uart_sync_vprintf(const char *fmt, va_list args); + int uart_recv_line(char *buf, int maxline); uint32 uart_recv_uint(); -void uart_printf(const char *fmt, ...); + void uart_sendn(const char *str, int n); void uart_init (void); int uart_irq_add(void); -void uart_irq_handler(void); int uart_switch_mode(void); #endif /*_MINI_UART_H */ \ No newline at end of file diff --git a/inc/mm.h b/inc/mm.h index 317fe6bcd..ad31d9dbb 100644 --- a/inc/mm.h +++ b/inc/mm.h @@ -2,8 +2,11 @@ #define _MM_H #ifndef __ASSEMBLER__ -void memzero(unsigned long src, unsigned long n); -void memncpy(char *dst, char *src, unsigned long n); + +#include +void memzero(char* src, unsigned long n); +void memncpy(char *dst, const char *src, unsigned long n); +void memset(void *ptr, uint8 value, uint64 bum); void mm_init(char *fdt_base); void *kmalloc(int size); diff --git a/inc/mmu.h b/inc/mmu.h new file mode 100644 index 000000000..8a1943363 --- /dev/null +++ b/inc/mmu.h @@ -0,0 +1,61 @@ +#ifndef _MMU_H +#define _MMU_H + +#include +#include +#include +#include + +#define PAGE_TABLE_SIZE 0x1000 + +#define PT_R 0x0001 +#define PT_W 0x0002 +#define PT_X 0x0004 + +#define VMA_R PT_R +#define VMA_W PT_W +#define VMA_X PT_X + +#define VMA_PA 0x0008 +#define VMA_KVA 0x0010 +#define VMA_ANON 0x0020 + +typedef uint64 pd_t; + +typedef struct _vm_area_t{ + struct list_head list; + uint64 va_begin; + uint64 va_end; + uint64 flag; + uint64 kva; +} vm_area_t; + +typedef struct{ + struct list_head vma; +} vm_area_meta_t; + +// the file is not accessible +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 + +#define MAP_ANONYMOUS 0x0020 +#define MAP_POPULATE 0x8000 + +void mmu_init(void); + +pd_t *pt_create(void); +void pt_free(pd_t *pt); + +void pt_map(pd_t *pt, void *va, uint64 size, void *pa, uint64 flag); + +vm_area_meta_t *vma_meta_create(void); +void vma_meta_free(vm_area_meta_t *vma_mata, pd_t *page_table); +void vma_meta_copy(vm_area_meta_t *to, vm_area_meta_t *from, pd_t *page_table); +void vma_map(vm_area_meta_t *vma_meta, void *va, uint64 size, uint64 flag, void *addr); +void mem_abort(esr_el1_t *esr); + +void syscall_mmap(trapframe *frame, void *addr, size_t len, int prot, int flags, int fd, int file_offset); + +#endif \ No newline at end of file diff --git a/inc/panic.h b/inc/panic.h new file mode 100644 index 000000000..9f4ec5a2d --- /dev/null +++ b/inc/panic.h @@ -0,0 +1,6 @@ +#ifndef _PANIC_H +#define _PANIC_H + +void panic(const char *fmt, ...); + +#endif \ No newline at end of file diff --git a/inc/sched.h b/inc/sched.h index df0355681..d0162f37c 100644 --- a/inc/sched.h +++ b/inc/sched.h @@ -3,6 +3,10 @@ #include #include +#include +#include + +#define TASK_MAX_FD 0x10 struct pt_regs { void *x19; @@ -23,13 +27,15 @@ struct pt_regs { struct signal_head_t; struct sighand_t; typedef struct _task_struct { - /* This must be the first element */ struct pt_regs regs; + pd_t *page_table; + /* The order of the above elements cannot be changed*/ + vm_area_meta_t *address_space; void *kernel_stack; - void *user_stack; + // void *user_stack; /* TODO: Update to address_space*/ - void *data; - uint32 datalen; + // void *data; + // uint32 datalen; struct list_head list; struct list_head task_list; uint16 status; @@ -39,6 +45,10 @@ typedef struct _task_struct { /* Signal */ struct signal_head_t *signal; struct sighand_t *sighand; + /*files*/ + int maxfd; + struct file fds[TASK_MAX_FD]; + struct vnode *work_dir; } task_struct; void switch_to(task_struct *from, task_struct *to); diff --git a/inc/sdhost.h b/inc/sdhost.h new file mode 100644 index 000000000..839599257 --- /dev/null +++ b/inc/sdhost.h @@ -0,0 +1,66 @@ +#ifndef _SDHOST_H +#define _SDHOST_H + +#include +#define BLOCK_SIZE 512 + +// SD card command +#define GO_IDLE_STATE 0 +#define SEND_OP_CMD 1 +#define ALL_SEND_CID 2 +#define SEND_RELATIVE_ADDR 3 +#define SELECT_CARD 7 +#define SEND_IF_COND 8 +#define VOLTAGE_CHECK_PATTERN 0x1aa +#define STOP_TRANSMISSION 12 +#define SET_BLOCKLEN 16 +#define READ_SINGLE_BLOCK 17 +#define WRITE_SINGLE_BLOCK 24 +#define SD_APP_OP_COND 41 +#define SDCARD_3_3V (1 << 21) +#define SDCARD_ISHCS (1 << 30) +#define SDCARD_READY (1 << 31) +#define APP_CMD 55 + +// sdhost +#define SDHOST_BASE PA2VA(PERIPHERALS_BASE + 0x202000) +#define SDHOST_CMD (SDHOST_BASE + 0) +#define SDHOST_READ 0x40 +#define SDHOST_WRITE 0x80 +#define SDHOST_LONG_RESPONSE 0x200 +#define SDHOST_NO_REPONSE 0x400 +#define SDHOST_BUSY 0x800 +#define SDHOST_NEW_CMD 0x8000 +#define SDHOST_ARG (SDHOST_BASE + 0x4) +#define SDHOST_TOUT (SDHOST_BASE + 0x8) +#define SDHOST_TOUT_DEFAULT 0xf00000 +#define SDHOST_CDIV (SDHOST_BASE + 0xc) +#define SDHOST_CDIV_MAXDIV 0x7ff +#define SDHOST_CDIV_DEFAULT 0x148 +#define SDHOST_RESP0 (SDHOST_BASE + 0x10) +#define SDHOST_RESP1 (SDHOST_BASE + 0x14) +#define SDHOST_RESP2 (SDHOST_BASE + 0x18) +#define SDHOST_RESP3 (SDHOST_BASE + 0x1c) +#define SDHOST_HSTS (SDHOST_BASE + 0x20) +#define SDHOST_HSTS_MASK (0x7f8) +#define SDHOST_HSTS_ERR_MASK (0xf8) +#define SDHOST_HSTS_DATA (1 << 0) +#define SDHOST_PWR (SDHOST_BASE + 0x30) +#define SDHOST_DBG (SDHOST_BASE + 0x34) +#define SDHOST_DBG_FSM_DATA 1 +#define SDHOST_DBG_FSM_MASK 0xf +#define SDHOST_DBG_MASK (0x1f << 14 | 0x1f << 9) +#define SDHOST_DBG_FIFO (0x4 << 14 | 0x4 << 9) +#define SDHOST_CFG (SDHOST_BASE + 0x38) +#define SDHOST_CFG_DATA_EN (1 << 4) +#define SDHOST_CFG_SLOW (1 << 3) +#define SDHOST_CFG_INTBUS (1 << 1) +#define SDHOST_SIZE (SDHOST_BASE + 0x3c) +#define SDHOST_DATA (SDHOST_BASE + 0x40) +#define SDHOST_CNT (SDHOST_BASE + 0x50) + +void sd_init(void); +void sd_readblock(int block_idx, void *buf); +void sd_writeblock(int block_idx, const void *buf); + +#endif \ No newline at end of file diff --git a/inc/signal.h b/inc/signal.h index 028439f5a..a5cecba47 100644 --- a/inc/signal.h +++ b/inc/signal.h @@ -69,7 +69,7 @@ void handle_signal(trapframe *_); struct sighand_t *sighand_create(void); void sighand_free(struct sighand_t *sighand); void sighand_reset(struct sighand_t *sighand); -void sighand_copy(struct sighand_t *sighand, void *addrbase); +void sighand_copy(struct sighand_t *sighand); void syscall_signal(trapframe *_, uint32 signal, void (*handler)(int)); void syscall_kill(trapframe *_, int pid, int signal); void syscall_sigreturn(trapframe *_); diff --git a/inc/string.h b/inc/string.h index fe84b2523..ce3533dbb 100644 --- a/inc/string.h +++ b/inc/string.h @@ -2,8 +2,12 @@ #define _STRING_H int strcmp(const char *X, const char *Y); +int strcasecmp(const char *X, const char *Y); int strncmp(const char *X, const char *Y, int n); int strlen(const char *str); +int strcpy(char *dst, const char *src); +char *strcat(char *dest, const char *src); +char *strncat(char *dest, const char *src, int n); int atoi(const char *str); #endif /* _STRING_H */ \ No newline at end of file diff --git a/inc/syscall.h b/inc/syscall.h index 90939d93a..ca6c7cf64 100644 --- a/inc/syscall.h +++ b/inc/syscall.h @@ -2,12 +2,6 @@ #define _SYSCALL_H #include -typedef struct { - unsigned int iss:25, // Instruction specific syndrome - il:1, // Instruction length bit - ec:6; // Exception class -} esr_el1; - #define KSTACK_VARIABLE(x) \ (void *)((uint64)x - \ (uint64)current->kernel_stack + \ @@ -25,7 +19,7 @@ typedef struct { typedef void *(*syscall_funcp)(); -void syscall_handler(trapframe regs, uint32 syn); +void syscall_handler(trapframe *regs); void syscall_getpid(trapframe *frame); void syscall_uart_read(trapframe *_, char buf[], size_t size); diff --git a/inc/task.h b/inc/task.h index 87184d40a..c74998e92 100644 --- a/inc/task.h +++ b/inc/task.h @@ -4,8 +4,9 @@ #include #include #include +#include -#define STACK_SIZE ( 2 * PAGE_SIZE) +#define STACK_SIZE ( 4 * PAGE_SIZE) /* Task status */ @@ -32,4 +33,15 @@ task_struct *task_create(void); void task_free(task_struct *task); task_struct *task_get_by_tid(uint32 tid); +/* + * Create initial mapping for user program + * + * 0x00003c000000 ~ 0x00003f000000: rw-: Mailbox address + * 0x7f0000000000 ~ : r-x: Kernel functions exposed to users + * 0xffffffffb000 ~ : rw-: Stack + */ +void task_init_map(task_struct *task); + +void task_reset_mm(task_struct *task); + #endif \ No newline at end of file diff --git a/inc/text_user_shared.h b/inc/text_user_shared.h new file mode 100644 index 000000000..3be42d0ed --- /dev/null +++ b/inc/text_user_shared.h @@ -0,0 +1,25 @@ +#ifndef _TEXT_USER_SHARED_H +#define _TEXT_USER_SHARED_H + +/* + * See the comment of task_init_map in task.h: + * + * 0x7f0000000000 ~ : r-x: Kernel functions exposed to users + * + * The kernel functions with the SECTION_TUS attribute will be mapped into + * this user address space. + */ + +#define SECTION_TUS __attribute__ ((section (".text.user.shared"))) + +#define TUS2VA(x) ((((uint64)x) - TEXT_USER_SHARED_BASE) + 0x7f0000000000) + +/* From linker.ld */ +extern char _stext_user_shared; +extern char _etext_user_shared; + +#define TEXT_USER_SHARED_BASE (uint64)(&_stext_user_shared) +#define TEXT_USER_SHARED_END (uint64)(&_etext_user_shared) +#define TEXT_USER_SHARED_LEN (TEXT_USER_SHARED_END - TEXT_USER_SHARED_BASE) + +#endif /* _TEXT_USER_SHARED_H */ \ No newline at end of file diff --git a/inc/tmpfs.h b/inc/tmpfs.h new file mode 100644 index 000000000..ca090f18c --- /dev/null +++ b/inc/tmpfs.h @@ -0,0 +1,52 @@ +#ifndef _TMPFS_H +#define _TMPFS_H + +#include + +#define TMPFS_FILE_MAXSIZE PAGE_SIZE +#define TMPFS_DIR_MAXSIZE 0x10 +#define TMPFS_TYPE_UNDEFINE 0x0 +#define TMPFS_TYPE_FILE 0x1 +#define TMPFS_TYPE_DIR 0x2 +#define TMPFS_NAME_MAXLEN 0x10 + +struct tmpfs_file_t{ + char *data; + int size; + int capacity; +}; + +struct tmpfs_dir_t{ + int size; + struct vnode *entries[TMPFS_DIR_MAXSIZE]; +}; + +struct tmpfs_internal{ + char name[TMPFS_NAME_MAXLEN]; + int type; + union { + struct tmpfs_file_t *file; + struct tmpfs_dir_t *dir; + }; + struct vnode *oldnode; +}; + +int tmpfs_mount(struct filesystem *fs, struct mount *mount); +int tmpfs_alloc_vnode(struct filesystem *fs, struct vnode **target); +int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_isdir(struct vnode *dir_node); +int tmpfs_getname(struct vnode *dir_node, const char **name); +int tmpfs_getsize(struct vnode *dir_node); +int tmpfs_write(struct file *file, const void *buf, size_t len); +int tmpfs_read(struct file *file, void *buf, size_t len); +int tmpfs_open(struct vnode *file_node, struct file *target); +int tmpfs_close(struct file *file); +long tmpfs_lseek64(struct file *file, long offset, int whence); +int tmpfs_ioctl(struct file *file, uint64 request, va_list args); +int tmpfs_sync(struct filesystem *fs); + +struct filesystem *tmpfs_init(void); + +#endif \ No newline at end of file diff --git a/inc/trapframe.h b/inc/trapframe.h index f72d99e50..3542ea157 100644 --- a/inc/trapframe.h +++ b/inc/trapframe.h @@ -2,7 +2,7 @@ #define _TRAPFRAME_H #include - +#include typedef struct { uint64 x0; uint64 x1; @@ -40,4 +40,43 @@ typedef struct { void *spsr_el1; } trapframe; +static inline void show_trapframe(trapframe *regs) +{ + uart_sync_printf("\r\n[*] Trapframe:\r\n"); + uart_sync_printf("\tx0: %llx\r\n", regs->x0); + uart_sync_printf("\tx1: %llx\r\n", regs->x1); + uart_sync_printf("\tx2: %llx\r\n", regs->x2); + uart_sync_printf("\tx3: %llx\r\n", regs->x3); + uart_sync_printf("\tx4: %llx\r\n", regs->x4); + uart_sync_printf("\tx5: %llx\r\n", regs->x5); + uart_sync_printf("\tx6: %llx\r\n", regs->x6); + uart_sync_printf("\tx7: %llx\r\n", regs->x7); + uart_sync_printf("\tx8: %llx\r\n", regs->x8); + uart_sync_printf("\tx9: %llx\r\n", regs->x9); + uart_sync_printf("\tx10: %llx\r\n", regs->x10); + uart_sync_printf("\tx11: %llx\r\n", regs->x11); + uart_sync_printf("\tx12: %llx\r\n", regs->x12); + uart_sync_printf("\tx13: %llx\r\n", regs->x13); + uart_sync_printf("\tx14: %llx\r\n", regs->x14); + uart_sync_printf("\tx15: %llx\r\n", regs->x15); + uart_sync_printf("\tx16: %llx\r\n", regs->x16); + uart_sync_printf("\tx17: %llx\r\n", regs->x17); + uart_sync_printf("\tx18: %llx\r\n", regs->x18); + uart_sync_printf("\tx19: %llx\r\n", regs->x19); + uart_sync_printf("\tx20: %llx\r\n", regs->x20); + uart_sync_printf("\tx21: %llx\r\n", regs->x21); + uart_sync_printf("\tx22: %llx\r\n", regs->x22); + uart_sync_printf("\tx23: %llx\r\n", regs->x23); + uart_sync_printf("\tx24: %llx\r\n", regs->x24); + uart_sync_printf("\tx25: %llx\r\n", regs->x25); + uart_sync_printf("\tx26: %llx\r\n", regs->x26); + uart_sync_printf("\tx27: %llx\r\n", regs->x27); + uart_sync_printf("\tx28: %llx\r\n", regs->x28); + uart_sync_printf("\tx29: %llx\r\n", regs->x29); + uart_sync_printf("\tx30: %llx\r\n", regs->x30); + uart_sync_printf("\tsp_el0 : %llx\r\n", regs->sp_el0); + uart_sync_printf("\telr_el1 : %llx\r\n", regs->elr_el1); + uart_sync_printf("\tspsr_el1: %llx\r\n", regs->spsr_el1); +} + #endif /* _TRAPFRAME_H */ \ No newline at end of file diff --git a/inc/uartfs.h b/inc/uartfs.h new file mode 100644 index 000000000..c881b5c77 --- /dev/null +++ b/inc/uartfs.h @@ -0,0 +1,28 @@ +#ifndef _UARTFS_H +#define _UARTFS_H + +#include + +struct uartfs_internal{ + const char *name; + struct vnode oldnode; +}; + +int uartfs_mount(struct filesystem *fs, struct mount *mount); +int uartfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +int uartfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int uartfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int uartfs_isdir(struct vnode *dir_node); +int uartfs_getname(struct vnode *dir_node, const char **name); +int uartfs_getsize(struct vnode *dir_node); +int uartfs_write(struct file *file, const void *buf, size_t len); +int uartfs_read(struct file *file, void *buf, size_t len); +int uartfs_open(struct vnode *file_node, struct file *target); +int uartfs_close(struct file *file); +long uartfs_lseek64(struct file *file, long offset, int whence); +int uartfs_ioctl(struct file *file, uint64 request, va_list args); +int uartfs_sync(struct filesystem *fs); + +struct filesystem *uartfs_init(void); + +#endif \ No newline at end of file diff --git a/inc/utils.h b/inc/utils.h index 684b41d8e..868d81f7e 100644 --- a/inc/utils.h +++ b/inc/utils.h @@ -3,6 +3,8 @@ #include +#define PA2VA(x) (((uint64)(x)) | 0xffff000000000000) +#define VA2PA(x) (((uint64)(x)) & 0x0000ffffffffffff) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #define enable_interrupt(){ \ @@ -13,6 +15,30 @@ asm volatile("msr DAIFSet, 0xf"); \ } + +// ttbr0_el1 only uses the lower 48 bits of register +// dsb: data synchronization barrier +// ttbr0_el1: holds the base address of the translation table for stage 1 memory management for exception level1 +// tlbi vmalle1is: This invalidates all entries in the TLB corresponding to the current value of TTBR0_EL1. +#define set_page_table(page_table) do { \ + asm volatile( \ + "mov x9, %0\n" \ + "and x9, x9, #0x0000ffffffffffff\n" \ + "dsb ish\n" \ + "msr ttbr0_el1, x9\n" \ + "tlbi vmalle1is\n" \ + "dsb ish\n" \ + "isb\n" \ + :: "r" (page_table) \ + ); \ +} while (0) + +#define get_page_table() ({ \ + uint64 __val; \ + __val = PA2VA(read_sysreg(TTBR0_EL1)); \ + __val; \ +}) + #define get_elem_idx(elem, array) \ (((char *)elem - (char *)array) / sizeof(array[0])) diff --git a/inc/vfs.h b/inc/vfs.h new file mode 100644 index 000000000..9c3f30f1c --- /dev/null +++ b/inc/vfs.h @@ -0,0 +1,93 @@ +#ifndef _VFS_H +#define _VFS_H + +#include +#include +#include +#include + +#define O_CREATE 00000100 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +struct vnode { + struct mount *mount; + struct vnode_operations *v_ops; + struct file_operations *f_ops; + struct vnode *parent; + void *internal; +}; + +struct mount { + struct vnode *root; + struct filesystem *fs; +}; + +struct filesystem { + const char *name; + /* Link all filesystems */ + struct list_head fs_list; + int (*mount)(struct filesystem *fs, struct mount *mount); + int (*alloc_vnode)(struct filesystem *fs, struct vnode **target); + int (*sync)(struct filesystem *fs); +}; + +struct vnode_operations { + int (*lookup)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*create)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*mkdir)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*isdir)(struct vnode *dir_node); + int (*getname)(struct vnode *dir_node, const char **name); + int (*getsize)(struct vnode *dir_node); +}; + +struct file { + struct vnode *vnode; + size_t f_pos; // RW position of this file handle + struct file_operations *f_ops; + int flags; +}; + +struct file_operations { + int (*write)(struct file *file, const void *buf, size_t len); + int (*read)(struct file *file, void *buf, size_t len); + int (*open)(struct vnode *file_node, struct file *target); + int (*close)(struct file *file); + long (*lseek64)(struct file *file, long offset, int whence); + int (*ioctl)(struct file *file, uint64 request, va_list args); +}; + +extern struct mount *rootmount; + +void vfs_init(void); +void vfs_init_rootmount(struct filesystem *fs); + +int register_filesystem(struct filesystem *fs); +int vfs_open(const char *pathname, int flags, struct file *target); +int vfs_close(struct file *target); +int vfs_write(struct file *file, const void *buf, size_t len); +int vfs_read(struct file *file, void *buf, size_t len); +int vfs_mkdir(const char *pathname); +int vfs_mount(const char *mountpath, const char *filesystem); +int vfs_lookup(const char *pathname, struct vnode **target); +int vfs_sync(struct filesystem *fs); +long vfs_lseek64(struct file *file, long offset, int whence); +int vfs_ioctl(struct file *file, uint64 request, va_list args); + +void syscall_open(trapframe *frame, const char *pathname, int flags); +void syscall_close(trapframe *frame, int fd); +void syscall_write(trapframe *frame, int fd, const void *buf, uint64 count); +void syscall_read(trapframe *frame, int fd, void *buf, uint64 count); +void syscall_mkdir(trapframe *frame, const char *pathname, uint32 mode); +void syscall_mount(trapframe *frame, const char *src, const char *target, const char *filesystem, uint64 flags, const void *data); +void syscall_chdir(trapframe *frame, const char *path); +void syscall_lseek64(trapframe *frame, int fd, int64 offset, int whence); +void syscall_ioctl(trapframe *frame, int fd, uint64 request, ...); +void syscall_sync(trapframe *frame); + +#endif \ No newline at end of file diff --git a/rootfs/Makefile b/rootfs/Makefile deleted file mode 100644 index 3d9b5cb83..000000000 --- a/rootfs/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -CROSS_COMPILE ?= aarch64-linux-gnu- -CC := $(CROSS_COMPILE)gcc -LD := $(CROSS_COMPILE)ld -CFLAGS := -Wall -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only -all: userprog2 - -# userprog1: userprog1.elf -# $(CROSS_COMPILE)objcopy -O binary $^ $@ - -# userprog1.elf: linker.ld userprog1.o -# $(LD) $(LDFLAGS) -T -Iinc $< -o $@ userprog1.o - -# userprog1.o: userprog1.c -# $(CC) $(CFLAGS) -c $< -o $@ - -userprog2: userprog2.elf - $(CROSS_COMPILE)objcopy -O binary $^ $@ - -userprog2.elf: linker.ld userprog2.o - $(LD) $(LDFLAGS) -T $< -o $@ userprog2.o - -userprog2.o: userprog2.s - $(CC) $(CFLAGS) -c $< -o $@ - -.PHONY: clean -clean: - rm -f *.o *.elf - -.PHONY: clean-all -clean-all: clean - rm -f userprog1 userprog2 \ No newline at end of file diff --git a/rootfs/key.txt b/rootfs/key.txt deleted file mode 100644 index adbfe0be4..000000000 --- a/rootfs/key.txt +++ /dev/null @@ -1 +0,0 @@ -fdsafhdjsklafhdjkslahnmer,.wqbnjtvuicx8734y7 \ No newline at end of file diff --git a/rootfs/linker.ld b/rootfs/linker.ld deleted file mode 100644 index ac633d555..000000000 --- a/rootfs/linker.ld +++ /dev/null @@ -1,26 +0,0 @@ -SECTIONS -{ - .start :{ - *(.start) - } - - .text : { - *(.text) - } - - .rodata : { - *(.rodata) - } - - .data : { - *(.got) - *(.got.plt) - *(.data*) - } - - _sbss = .; - .bss : { - *(.bss*) - } - _ebss = .; -} \ No newline at end of file diff --git a/rootfs/test.txt b/rootfs/test.txt deleted file mode 100644 index 329c63806..000000000 --- a/rootfs/test.txt +++ /dev/null @@ -1 +0,0 @@ -hello test \ No newline at end of file diff --git a/rootfs/test1.txt b/rootfs/test1.txt deleted file mode 100644 index f5fc2e3bf..000000000 --- a/rootfs/test1.txt +++ /dev/null @@ -1,4 +0,0 @@ -AAA -BBB -CCC -EndOfTest \ No newline at end of file diff --git a/rootfs/userprog2 b/rootfs/userprog2 deleted file mode 100755 index 237765563..000000000 Binary files a/rootfs/userprog2 and /dev/null differ diff --git a/rootfs/userprog2.s b/rootfs/userprog2.s deleted file mode 100644 index 4e8787985..000000000 --- a/rootfs/userprog2.s +++ /dev/null @@ -1,19 +0,0 @@ -.section ".text" -.global _start -_start: - mov x0, 0 -1: - add x0, x0, 1 - - // syscall_test - mov x8, 10 - svc 0 - - cmp x0, 5 - blt 1b -1: - // syscall exit - mov x8, 5 - svc 0 - - b 1b \ No newline at end of file diff --git a/src/bootloader/linker.ld b/src/bootloader/linker.ld index 9b27a72b1..08c3e55a1 100644 --- a/src/bootloader/linker.ld +++ b/src/bootloader/linker.ld @@ -1,8 +1,13 @@ _bootloader = 0x60000; _kernel = 0x80000; _stack_top = 0x400000; -start_mem = 0x7000000; -end_mem = 0x7ffffff; + +/* Define these just to prevent the linker from complaining */ +_etext_user_shared = 0; +_stext_user_shared = 0; +_early_mem_base = 0x7000000; +_early_mem_end = 0x7ffffff; + SECTIONS { . = _bootloader; diff --git a/src/bootloader/main.c b/src/bootloader/main.c index 8edc8b848..ca78c6727 100644 --- a/src/bootloader/main.c +++ b/src/bootloader/main.c @@ -9,34 +9,31 @@ char *dtp_pass; extern char _kernel[]; void _load(void){ - uart_send_string("[*] Loading kernel...\r\n"); + uart_printf("[*] Loading kernel...\r\n"); unsigned int len; char *p = _kernel; len = uart_recv_uint(); - uart_send_string("[*] Receiving kernel with len:"); - uart_send_hex(len); - uart_send_string("\r\n"); + uart_printf("[*] Receiving kernel with len: 0x%x\r\n", len); - // uart_send_hex(p); while(len--) { *p++= uart_recv(); } - uart_send_string("[*] Jumping to the kernel\r\n"); + uart_printf("[*] Jumping to the kernel\r\n"); delay(5000); // Jump to the kernel and execute typedef void (*func_ptr)(char*); func_ptr ptr = (func_ptr)_kernel; - // uart_send_hex(ptr); + ptr(dtp_pass); } void shell_interact(void){ - uart_send_string("# "); + uart_printf("# "); unsigned int cnt = uart_recv_line(shell_buf, BUFSIZE); - uart_send_string("\r\n"); + uart_printf("\r\n"); if (!strcmp("help", shell_buf)) _help(1); else if (!strcmp("hello", shell_buf)) @@ -50,13 +47,13 @@ void shell_interact(void){ else { _echo(shell_buf); if(cnt) - uart_send_string("\r\n"); + uart_printf("\r\n"); } } void bootloader_main(char *dtp){ uart_init(); - uart_send_string("[*] Running the bootloader...\r\n"); + uart_printf("[*] Running the bootloader...\r\n"); dtp_pass = dtp; while(1) diff --git a/src/kernel/boot.S b/src/kernel/boot.S index bef93a13c..6d71d9c3b 100644 --- a/src/kernel/boot.S +++ b/src/kernel/boot.S @@ -18,6 +18,17 @@ master: bl from_el2_to_el1 // the next instruction runs in EL1 + // Set booting stack + ldr x0, =_PA_stack_top + mov sp, x0 + bl mmu_init + + // Use virtual address after mmu_init + ldr x0, =_va_trampoline + br x0 + +_va_trampoline: + bl set_exception_vector_table bl core_timer_enable @@ -185,7 +196,7 @@ l64_syn_eh: mov x0, sp // Get exception class ({EC[31:26]}) mrs x1, esr_el1 - bl syscall_handler + bl el0_sync_handler mov x0, sp bl exit_to_user_mode diff --git a/src/kernel/linker.ld b/src/kernel/linker.ld index 086fbcd3d..5f2366d55 100644 --- a/src/kernel/linker.ld +++ b/src/kernel/linker.ld @@ -1,9 +1,11 @@ -_stack_top = 0x400000; -start_mem = 0x7000000; -end_mem = 0x7ffffff; +_stack_top = 0xffff000000400000; +_PA_stack_top = 0x0000000000400000; +_early_mem_base = 0xffff000007000000; +_early_mem_end = 0xffff000007ffffff; + SECTIONS { - . = 0x80000; + . = 0xffff000000080000; .text.boot :{ *(text.boot) @@ -13,6 +15,16 @@ SECTIONS *(.text) } + . = ALIGN(0x1000); + + _stext_user_shared = .; + .text.user.shared : { + *(.text.user.shared) + } + + . = ALIGN(0x1000); + _etext_user_shared = .; + .rodata : { *(.rodata) } diff --git a/src/kernel/main.c b/src/kernel/main.c index 005eac936..934beb3b4 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -11,6 +11,7 @@ #include #include #include +#include #define BUFSIZE 0x100 char shell_buf[BUFSIZE]; @@ -38,10 +39,10 @@ void shell_interact(void){ else if (!strcmp("hwinfo", shell_buf)) _hwinfo(); else if (!strcmp("ls", shell_buf)) - _ls(_initramfs_addr); + _ls(); else if (!strncmp("cat", shell_buf, 3)){ if(cnt >= 5) - _cat(_initramfs_addr, &shell_buf[4]); + _cat(&shell_buf[4]); else uart_printf("usage: cat \r\n"); } @@ -58,7 +59,7 @@ void shell_interact(void){ _parsedtb(fdt_base); else if (!strncmp("exec",shell_buf,4)){ if(cnt >= 6 && shell_buf[4]==' ') - _exec(_initramfs_addr,&shell_buf[5]); + _exec(&shell_buf[5]); else uart_printf("usage: exec \r\n"); } @@ -92,14 +93,19 @@ void kernel_main(char *fdt){ mm_init(fdt); timer_init(); task_init(); + scheduler_init(); + + kthread_early_init(); + fs_early_init(); kthread_init(); + uart_printf("[*] Kernel start running!\r\n"); uart_printf("[*] fdt base: %x\r\n", fdt); - kthread_create(shell_interact); - // sched_new_user_prog(fdt, "syscall.img"); + // kthread_create(shell_interact); + sched_new_user_prog("/initramfs/vfs2.img"); enable_irqs1(); enable_interrupt(); diff --git a/src/lib/builtin.c b/src/lib/builtin.c index fcae038cb..c930bb2d1 100644 --- a/src/lib/builtin.c +++ b/src/lib/builtin.c @@ -65,7 +65,7 @@ void _hwinfo(void){ void _reboot(void){ uart_printf("Rebooting...\r\n\r\n"); - // delay(10000); + delay(10000); reset(10); // while(1); } @@ -74,11 +74,11 @@ void _echo(char *shell_buf){ uart_printf(shell_buf); } -void _ls(uint64 _initramfs_addr){ +void _ls(void){ cpio_ls((char*)_initramfs_addr); } -void _cat(uint64 _initramfs_addr, char *filename){ +void _cat(char *filename){ cpio_cat((char*)_initramfs_addr, filename); } @@ -96,7 +96,7 @@ void *_malloc(char *size){ return kmalloc(int_size); } -void _exec(uint64 _initramfs_addr,char *filename){ +void _exec(char *filename){ void *data; uint32 datalen; @@ -104,18 +104,17 @@ void _exec(uint64 _initramfs_addr,char *filename){ if(datalen == 0) return; - current->user_stack = kmalloc(STACK_SIZE); - current->data = data; - current->datalen = datalen; + task_init_map(current); + vma_map(current->address_space, (void *)0, datalen, VMA_R | VMA_W | VMA_X | VMA_KVA, data); user_prog_start(); } void _chmod_uart(){ int mode = uart_switch_mode(); if(mode==0) - uart_printf("[*] Use synchronous uart now!\r\n"); + uart_sync_printf("[*] Use synchronous uart now!\r\n"); else - uart_printf("[*] Use asynchronous uart now!\r\n"); + uart_sync_printf("[*] Use asynchronous uart now!\r\n"); } int _setTimeout(char *shell_buf){ @@ -152,7 +151,7 @@ int _setTimeout(char *shell_buf){ static void foo(){ for (int i = 0; i < 10; ++i) { - uart_printf("Thread id: %d %d\r\n", current->tid, i); + uart_sync_printf("Thread id: %d %d\r\n", current->tid, i); delay(1000000); schedule(); } diff --git a/src/lib/cpio.c b/src/lib/cpio.c index 0385242cb..af1f973ca 100644 --- a/src/lib/cpio.c +++ b/src/lib/cpio.c @@ -4,7 +4,7 @@ #include #include -static uint32 cpio_read_hex(char *p){ +uint32 cpio_read_hex(char *p){ uint32 result = 0; for(int i = 0 ; i < 8 ; i++){ @@ -28,7 +28,7 @@ void cpio_ls(char *cpio){ while(1){ struct cpio_newc_header *pheader = (struct cpio_newc_header *)cur; cur += sizeof(struct cpio_newc_header); - if(!strcmp(pheader->c_magic, "070701")){ + if(strncmp(pheader->c_magic, "070701", 6)){ uart_printf("Only support new ASCII format for cpio. \r\n"); return; } @@ -59,7 +59,7 @@ void cpio_cat(char *cpio, char *filename){ while(1){ struct cpio_newc_header *pheader = (struct cpio_newc_header *) cur; cur += sizeof(struct cpio_newc_header); - if(!strcmp(pheader->c_magic, "070701")){ + if(strncmp(pheader->c_magic, "070701", 6)){ uart_printf("Only support new ASCII format for cpio. \r\n"); return; } @@ -97,7 +97,7 @@ uint32 cpio_load_prog(char *cpio, const char *filename, char **output_data){ while(1){ struct cpio_newc_header *pheader = (struct cpio_newc_header *) cur; cur += sizeof(struct cpio_newc_header); - if(!strcmp(pheader->c_magic, "070701")){ + if(strncmp(pheader->c_magic, "070701", 6)){ uart_printf("Only support new ASCII format for cpio. \r\n"); return 0; } diff --git a/src/lib/cpiofs.c b/src/lib/cpiofs.c new file mode 100644 index 000000000..0399e5941 --- /dev/null +++ b/src/lib/cpiofs.c @@ -0,0 +1,355 @@ +#include +#include +#include +#include +#include +#include +#include + +static struct vnode cpio_root_node; +static struct vnode mount_old_node; +static int cpio_mounted; + +static struct filesystem cpiofs = { + .name = "cpiofs", + .mount = cpiofs_mount, + .sync = cpiofs_sync +}; + +static struct vnode_operations cpiofs_v_ops = { + .lookup = cpiofs_lookup, + .create = cpiofs_create, + .mkdir = cpiofs_mkdir, + .isdir = cpiofs_isdir, + .getname = cpiofs_getname, + .getsize = cpiofs_getsize +}; + +static struct file_operations cpiofs_f_ops = { + .write = cpiofs_write, + .read = cpiofs_read, + .open = cpiofs_open, + .close = cpiofs_close, + .lseek64 = cpiofs_lseek64, + .ioctl = cpiofs_ioctl +}; + +static struct vnode *get_dir_vnode(struct vnode *dir_node, const char **pathname){ + struct vnode *result; + const char *start; + const char *end; + char buf[0x100]; + + start = end = *pathname; + + if(*start == '/') + result = &cpio_root_node; + else + result = dir_node; + + while(1){ + if(!strncmp("./", start, 2)){ + start += 2; + end = start; + continue; + } + else if(!strncmp("../", start, 3)){ + if(result->parent){ + result = result->parent; + } + + start += 3; + end = start; + continue; + } + while(*end != '\0' && *end != '/') + end++; + if(*end == '/'){ + int ret; + if(start == end){ + end++; + start = end; + continue; + } + + // TODO: Check if the length is less than 0x100 + memncpy(buf, start, end - start); + buf[end - start] = 0; + ret = result->v_ops->lookup(result, &result, buf); + if(ret < 0) + return NULL; + end++; + start = end; + } + else{ + break; + } + } + *pathname = *start ? start : NULL; + return result; +} + +static void cpio_init_mkdir(const char *pathname){ + const char *curname; + struct vnode *dir_node; + struct vnode *newdir_node; + struct cpiofs_internal *internal, *dirint; + + curname = pathname; + dir_node = get_dir_vnode(&cpio_root_node, &curname); + + if(!dir_node) + return; + if(!curname) + return; + dirint = dir_node->internal; + if(dirint->type != CPIOFS_TYPE_DIR) + return; + internal = kmalloc(sizeof(struct cpiofs_internal)); + newdir_node = kmalloc(sizeof(struct vnode)); + + internal->name = curname; + internal->type = CPIOFS_TYPE_DIR; + INIT_LIST_HEAD(&internal->dir.list); + internal->node = newdir_node; + list_add_tail(&internal->list, &dirint->dir.list); + + newdir_node->mount = NULL; + newdir_node->v_ops = &cpiofs_v_ops; + newdir_node->f_ops = &cpiofs_f_ops; + newdir_node->parent = dir_node; + newdir_node->internal = internal; + return; +} + +static void cpio_init_create(const char *pathname, const char *data, uint64 size){ + const char *curname; + struct vnode *dir_node; + struct vnode *newdir_node; + struct cpiofs_internal *internal, *dirint; + + curname = pathname; + dir_node = get_dir_vnode(&cpio_root_node, &curname); + + if(!dir_node) + return; + if(!curname) + return; + dirint = dir_node->internal; + if(dirint->type != CPIOFS_TYPE_DIR) + return; + internal = kmalloc(sizeof(struct cpiofs_internal)); + newdir_node = kmalloc(sizeof(struct vnode)); + + internal->name = curname; + internal->type = CPIOFS_TYPE_FILE; + internal->file.data = data; + internal->file.size = size; + internal->node = newdir_node; + list_add_tail(&internal->list, &dirint->dir.list); + + newdir_node->mount = NULL; + newdir_node->v_ops = &cpiofs_v_ops; + newdir_node->f_ops = &cpiofs_f_ops; + newdir_node->parent = dir_node; + newdir_node->internal = internal; + return; +} + +struct filesystem *cpiofs_init(void){ + char *cur; + struct cpiofs_internal *internal = kmalloc(sizeof(struct cpiofs_internal)); + internal->name = NULL; + internal->type = CPIOFS_TYPE_DIR; + INIT_LIST_HEAD(&internal->dir.list); + internal->node = &cpio_root_node; + INIT_LIST_HEAD(&internal->list); + + cpio_root_node.mount = NULL; + cpio_root_node.v_ops = &cpiofs_v_ops; + cpio_root_node.f_ops = &cpiofs_f_ops; + cpio_root_node.parent = NULL; + cpio_root_node.internal = internal; + + cur = _initramfs_addr; + while(1){ + char *component_name, *content; + + struct cpio_newc_header *pheader = (struct cpio_newc_header *)cur; + cur += sizeof(struct cpio_newc_header); + if(strncmp(pheader->c_magic, "070701", 6)){ + panic("[*] Only support new ASCII format for cpio. \r\n"); + } + + uint32 namesize = cpio_read_hex(pheader->c_namesize); + uint32 filesize = cpio_read_hex(pheader->c_filesize); + uint32 type = cpio_read_hex(pheader->c_mode) & CPIO_TYPE_MASK; + + uint32 adj_namesize = ALIGN(namesize + sizeof(struct cpio_newc_header), 4) -sizeof(struct cpio_newc_header); + uint32 adj_filesize = ALIGN(filesize, 4); + + component_name = cur; + cur += adj_namesize; + content = cur; + cur += adj_filesize; + + if(type == CPIO_TYPE_DIR) + cpio_init_mkdir(component_name); + else if(type == CPIO_TYPE_FILE) + cpio_init_create(component_name, content, filesize); + + if(namesize == 0xb && !strcmp(component_name, "TRAILER!!!")) + break; + } + return &cpiofs; +} + +int cpiofs_mount(struct filesystem *fs, struct mount *mount){ + struct vnode *oldnode; + struct cpiofs_internal *internal; + const char *name; + preempt_disable(); + + if(cpio_mounted){ + preempt_enable(); + return -1; + } + + cpio_mounted = 1; + preempt_enable(); + + oldnode = mount->root; + oldnode->v_ops->getname(oldnode, &name); + internal = cpio_root_node.internal; + internal->name = name; + + mount_old_node.mount = oldnode->mount; + mount_old_node.v_ops = oldnode->v_ops; + mount_old_node.f_ops = oldnode->f_ops; + mount_old_node.parent = oldnode->parent; + mount_old_node.internal = oldnode->internal; + + oldnode->mount = mount; + oldnode->v_ops = cpio_root_node.v_ops; + oldnode->f_ops = cpio_root_node.f_ops; + oldnode->internal = internal; + + return 0; +} +int cpiofs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name){ + struct cpiofs_internal *internal, *entry; + internal = dir_node->internal; + + if (internal->type != CPIOFS_TYPE_DIR) { + return -1; + } + + list_for_each_entry(entry, &internal->dir.list, list) { + if (!strcmp(entry->name, component_name)) { + break; + } + } + + if (&entry->list == &internal->dir.list) { + return -1; + } + + *target = entry->node; + return 0; +} + +int cpiofs_create(struct vnode *dir_node, struct vnode **target, const char *component_name){ + // TODO + return -1; +} +int cpiofs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name){ + // TODO + return -1; +} +int cpiofs_isdir(struct vnode *dir_node){ + struct cpiofs_internal *internal = dir_node->internal; + if(internal->type != CPIOFS_TYPE_DIR) + return 0; + + return 1; +} +int cpiofs_getname(struct vnode *dir_node, const char **name){ + struct cpiofs_internal *internal = dir_node->internal; + *name = internal->name; + return 0; +} +int cpiofs_getsize(struct vnode *dir_node){ + struct cpiofs_internal *internal = dir_node->internal; + if(internal->type != CPIOFS_TYPE_FILE) + return -1; + + return internal->file.size; +} +int cpiofs_write(struct file *file, const void *buf, size_t len){ + // TODO + return -1; +} +int cpiofs_read(struct file *file, void *buf, size_t len){ + struct cpiofs_internal *internal = file->vnode->internal; + if(internal->type != CPIOFS_TYPE_FILE) + return -1; + + if(len > internal->file.size - file->f_pos) + len = internal->file.size - file->f_pos; + + if(!len) + return 0; + memncpy(buf, &internal->file.data[file->f_pos], len); + file->f_pos += len; + return len; +} +int cpiofs_open(struct vnode *file_node, struct file *target){ + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} +int cpiofs_close(struct file *file){ + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + return 0; +} +long cpiofs_lseek64(struct file *file, long offset, int whence){ + int filesize; + int base; + + filesize = file->vnode->v_ops->getsize(file->vnode); + if(filesize < 0) + return -1; + + switch(whence){ + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = file->f_pos; + break; + case SEEK_END: + base = filesize; + break; + default: + return -1; + } + + if(base + offset > filesize) + return -1; + + file->f_pos = base + offset; + return 0; +} + +int cpiofs_ioctl(struct file *file, uint64 request, va_list args){ + return -1; +} + +int cpiofs_sync(struct filesystem *fs){ + return 0; +} \ No newline at end of file diff --git a/src/lib/dt17.c b/src/lib/dt17.c index 5c0c33ca4..ded139cfe 100644 --- a/src/lib/dt17.c +++ b/src/lib/dt17.c @@ -2,6 +2,7 @@ #include #include #include +#include uint32 initramfs_check_cnt = 0; @@ -91,12 +92,12 @@ int initramfs_parse_fdt(int level, char *cur, char *dt_strings){ struct fdt_property *prop =(struct fdt_property *) cur; cur += sizeof(struct fdt_property); if(!strcmp("linux,initrd-start", dt_strings + fdtp_nameoff(prop))){ - _initramfs_addr = fdt32_ld((fdt32_t*)cur); + _initramfs_addr = (void*)PA2VA(fdt32_ld((fdt32_t*)cur)); uart_printf("[*] initrd addr: %x\r\n", _initramfs_addr); initramfs_check_cnt++; } else if(!strcmp("linux,initrd-end", dt_strings + fdtp_nameoff(prop))){ - _initramfs_end = fdt32_ld((fdt32_t*)cur); + _initramfs_end = (void*)PA2VA(fdt32_ld((fdt32_t*)cur)); uart_printf("[*] initrd end: %x\r\n", _initramfs_end); initramfs_check_cnt++; } @@ -107,7 +108,7 @@ int initramfs_parse_fdt(int level, char *cur, char *dt_strings){ } void initramfs_init(char *fdt_base){ - _initramfs_addr = 0; + _initramfs_addr = NULL; parse_dtb(fdt_base, initramfs_parse_fdt); if(!_initramfs_addr) uart_printf("[x] Cannot find initrd address in dtb!\r\n"); diff --git a/src/lib/entry.c b/src/lib/entry.c new file mode 100644 index 000000000..ed93a54a8 --- /dev/null +++ b/src/lib/entry.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +void el0_sync_handler(trapframe *regs, uint32 syn){ + esr_el1_t *esr; + + esr = (esr_el1_t *)&syn; + + switch(esr->ec){ + case EC_SVC_64: + syscall_handler(regs); + break; + // instruction abort + case EC_IA_LE: + // data abort + case EC_DA_LE: + mem_abort(esr); + break; + default: + show_trapframe(regs); + panic("esr->ec: %x", esr->ec); + } +} \ No newline at end of file diff --git a/src/lib/exec.S b/src/lib/exec.S index bdd23303d..0fbc8a517 100644 --- a/src/lib/exec.S +++ b/src/lib/exec.S @@ -2,14 +2,14 @@ .global enter_el0_run_user_prog enter_el0_run_user_prog: + // set elr_el1 to the program start address // Set sp_el0 to the user program's stack pointer - msr sp_el0, x0 - + msr elr_el1, x0 + msr sp_el0, x1 // set spsr_el1 to 0 to enable interrupt set to 0x3c0 to disable interrupt mov x0, 0x0 msr spsr_el1, x0 - // set elr_el1 to the program start address - msr elr_el1, x1 + // return to EL0 eret diff --git a/src/lib/exec.c b/src/lib/exec.c index d47401708..2ce405e5a 100644 --- a/src/lib/exec.c +++ b/src/lib/exec.c @@ -5,15 +5,17 @@ #include #include #include +#include +#include void enter_el0_run_user_prog(void *entry, void *user_sp); void user_prog_start(void){ - char *user_sp; + // char *user_sp; - user_sp = (char *)current->user_stack + STACK_SIZE - 0x10; + // user_sp = (char *)current->user_stack + STACK_SIZE - 0x10; - enter_el0_run_user_prog(user_sp, current->data); + enter_el0_run_user_prog((void *)0, (char*)0xffffffffeff0); // User program should call exit() to terminate } @@ -33,30 +35,38 @@ static inline void pt_regs_init(struct pt_regs *regs){ regs->lr = user_prog_start; } -void sched_new_user_prog(char* cpio, char *filename){ +void sched_new_user_prog(char *pathname){ task_struct *task; + struct file f; void *data; - uint32 datalen; - - datalen = cpio_load_prog(cpio, filename, (char **)&data); - - if(datalen == 0) - goto EXEC_USER_PROG_END; - + int datalen, adj_datalen, ret; + + ret = vfs_open(pathname, 0, &f); + if(ret < 0) + return; + + datalen = f.vnode->v_ops->getsize(f.vnode); + if(datalen<0) + return; + adj_datalen = ALIGN(datalen, PAGE_SIZE); + data = kmalloc(adj_datalen); + memzero(data, adj_datalen); + ret = vfs_read(&f, data, datalen); + if(ret < 0){ + kfree(data); + return; + } + vfs_close(&f); task = task_create(); - task->kernel_stack = kmalloc(STACK_SIZE); - task->user_stack = kmalloc(STACK_SIZE); - task->data = data; - task->datalen = datalen; - task->regs.sp = (char *)task->kernel_stack + STACK_SIZE -0x10; pt_regs_init(&task->regs); + task_init_map(task); + + // 0x000000000000 ~ : rwx: Code + vma_map(task->address_space, (void *)0, adj_datalen, VMA_R | VMA_W | VMA_X | VMA_KVA, data); sched_add_task(task); - -EXEC_USER_PROG_END: - return; } diff --git a/src/lib/fat32fs.c b/src/lib/fat32fs.c new file mode 100644 index 000000000..ed5d9dc42 --- /dev/null +++ b/src/lib/fat32fs.c @@ -0,0 +1,1235 @@ +#include +#include +#include +#include +#include +#include +#include + +static struct list_head mounts; + +static struct filesystem fat32fs = { + .name = "fat32fs", + .mount = fat32fs_mount, + .sync = fat32fs_sync +}; + +static struct vnode_operations fat32fs_v_ops = { + .lookup = fat32fs_lookup, + .create = fat32fs_create, + .mkdir = fat32fs_mkdir, + .isdir = fat32fs_isdir, + .getname = fat32fs_getname, + .getsize = fat32fs_getsize +}; + +static struct file_operations fat32fs_f_ops = { + .write = fat32fs_write, + .read = fat32fs_read, + .open = fat32fs_open, + .close = fat32fs_close, + .lseek64 = fat32fs_lseek64, + .ioctl = fat32fs_ioctl +}; + +static int invalid_cid(uint32 cid){ + if (cid >= INVALID_CID) { + return 1; + } + + return 0; +} + +static uint32 alloc_cluster(struct fat_info_t *fat, uint32 prev_cid){ + struct cluster_entry_t *ce; + uint32 fat_lba; + uint32 cid; + int found; + uint8 buf[BLOCK_SIZE]; + + fat_lba = fat->fat_lba; + cid = 0; + + while (fat_lba < fat->cluster_lba) { + found = 0; + + // TODO: Cache FAT + sd_readblock(fat_lba, buf); + + for (int i = 0; i < CLUSTER_ENTRY_PER_BLOCK; ++i) { + ce = &(((struct cluster_entry_t *)buf)[i]); + + if (!ce->val) { + found = 1; + break; + } + + ++cid; + } + + if (found) { + break; + } + + fat_lba += 1; + } + + if (found && prev_cid) { + uint32 target_lba; + uint32 target_idx; + + target_lba = fat_lba + prev_cid / CLUSTER_ENTRY_PER_BLOCK; + target_idx = prev_cid % CLUSTER_ENTRY_PER_BLOCK; + + // TODO: Cache FAT + sd_readblock(target_lba, buf); + + ce = &(((struct cluster_entry_t *)buf)[target_idx]); + + ce->val = cid; + + sd_writeblock(target_lba, buf); + } + + if (!found) { + panic("fat32 alloc_cluster: No space!"); + return -1; + } + + return cid; +} + +static struct vnode *create_vnode(struct vnode *parent, const char *name, uint32 type, uint32 cid, uint32 size){ + struct vnode *node; + struct fat_internal *info, *data; + char *buf; + int len; + + info = parent->internal; + len = strlen(name); + buf = kmalloc(len+1); + node = kmalloc(sizeof(struct vnode)); + data = kmalloc(sizeof(struct fat_internal)); + + strcpy(buf, name); + data->name = buf; + data->node = node; + data->fat = info->fat; + data->cid = cid; + data->type = type; + + if(type == FAT_DIR){ + struct fat_dir_t *dir; + dir = kmalloc(sizeof(struct fat_dir_t)); + INIT_LIST_HEAD(&dir->list); + data->dir = dir; + } + else{ + struct fat_file_t *file; + file = kmalloc(sizeof(struct fat_file_t)); + INIT_LIST_HEAD(&file->list); + file->size = size; + data->file = file; + } + + node->mount = parent->mount; + node->v_ops = &fat32fs_v_ops; + node->f_ops = &fat32fs_f_ops; + node->parent = parent; + node->internal = data; + + list_add(&data->list, &info->dir->list); + + return node; +} + +static uint32 get_next_cluster(uint32 fat_lba, uint32 cluster_id) +{ + struct cluster_entry_t *ce; + uint32 idx; + uint8 buf[BLOCK_SIZE]; + + if (invalid_cid(cluster_id)) { + return cluster_id; + } + + fat_lba += cluster_id / CLUSTER_ENTRY_PER_BLOCK; + idx = cluster_id % CLUSTER_ENTRY_PER_BLOCK; + + // TODO: Cache FAT + sd_readblock(fat_lba, buf); + + ce = &(((struct cluster_entry_t *)buf)[idx]); + + return ce->val; +} + +static int lookup_cache(struct vnode *dir_node, struct vnode **target, const char *component_name){ + struct fat_internal *data, *entry; + struct fat_dir_t *dir; + int found = 0; + + data = dir_node->internal; + dir = data->dir; + list_for_each_entry(entry, &dir->list, list){ + if(!strcasecmp(component_name, entry->name)){ + found = 1; + break; + } + } + if(!found) + return -1; + + *target = entry->node; + return 0; +} + +static struct dir_t *lookup_fat32(struct vnode *dir_node, const char *component_name, uint8 *buf, int *buflba){ + struct dir_t *dir; + struct fat_internal *data; + struct fat_info_t *fat; + struct filename_t name; + uint32 cid; + int found, dirend, lfn; + + data = dir_node->internal; + fat = data->fat; + cid = data->cid; + + found = 0; + dirend = 0; + memset(&name, 0, sizeof(struct filename_t)); + + while(1){ + int lba; + lba = fat->cluster_lba + (cid-2) * fat->bs.sector_per_cluster; + + sd_readblock(lba, buf); + if (buflba) { + *buflba = lba; + } + for(int i = 0; i < DIR_PER_BLOCK; ++i){ + uint8 len; + dir = (struct dir_t *)(&buf[sizeof(struct dir_t) * i]); + if(dir->name[0] == 0){ + dirend = 1; + break; + } + if((dir->attr & ATTR_LFN) == ATTR_LFN){ + struct long_dir_t *ldir; + int n; + lfn = 1; + ldir = (struct long_dir_t *)dir; + n = (dir->name[0] & 0x3f) - 1; + for(int i = 0 ; ldir->name1[i] != 0xff && i < 10 ; i+=2){ + name.part[n].name[i/2] = ldir->name1[i]; + } + for(int i = 0 ; ldir->name2[i] != 0xff && i < 12 ; i+=2){ + name.part[n].name[5 + i/2] = ldir->name2[i]; + } + for(int i = 0 ; ldir->name3[i] != 0xff && i < 4 ; i+=2){ + name.part[n].name[11 + i/2] = ldir->name3[i]; + } + continue; + } + + if(lfn == 1){ + if(!strcasecmp(component_name, (void *)name.fullname)){ + found = 1; + break; + } + lfn = 0; + memset(&name, 0, sizeof(struct filename_t)); + continue; + } + + lfn = 0; + len = 8; + while(len){ + if(dir->name[len-1] != 0x20) + break; + len -= 1; + } + + memncpy((void *)name.fullname, (void *)dir->name, len); + name.fullname[len] = 0; + + len = 3; + while(len){ + if(dir->name[8+len-1] != 0x20) + break; + len -= 1; + } + + if(len >= 0){ + strcat((void *)name.fullname,"."); + strncat((void *)name.fullname, (void *)&dir->name[8], len); + } + + if(!strcasecmp(component_name, (void *)name.fullname)){ + found = 1; + break; + } + + memset(&name, 0, sizeof(struct filename_t)); + } + if(found || dirend) + break; + + cid = get_next_cluster(fat->fat_lba, cid); + if(invalid_cid(cid)) + break; + } + if(!found) + return NULL; + return dir; +} + +static int lookup__fat32(struct vnode *dir_node,struct vnode **target, const char *component_name){ + struct vnode *node; + struct dir_t *dir; + // struct fat_internal *data, *nodedata; + uint32 type, cid; + uint8 buf[BLOCK_SIZE]; + + dir = lookup_fat32(dir_node, component_name, buf, NULL); + if(!dir) + return -1; + if(!(dir->attr & ATTR_FILE_DIR_MASK)) + return -1; + cid = (dir->ch << 16) | dir->cl; + if(dir->attr & ATTR_ARCHIVE) + type = FAT_FILE; + else + type = FAT_DIR; + node = create_vnode(dir_node, component_name, type, cid, dir->size); + + *target = node; + return 0; +} + +static int readfile_seek_cache(struct fat_internal *data, uint32 foid, + struct fat_file_block_t **block){ + struct fat_file_block_t *entry; + struct list_head *head; + + head = &data->file->list; + + if (list_empty(head)) { + return -1; + } + + list_for_each_entry(entry, head, list) { + *block = entry; + + if (foid == entry->oid) { + return 0; + } + } + + return -1; +} + +static int readfile_seek_fat32(struct fat_internal *data, + uint32 foid, uint32 fcid, + struct fat_file_block_t **block){ + struct fat_info_t *info; + uint32 curoid, curcid; + + info = data->fat; + + if (*block) { + curoid = (*block)->oid; + curcid = (*block)->cid; + + if (curoid == foid) { + return 0; + } + + curoid++; + curcid = get_next_cluster(info->fat_lba, curcid); + + if (invalid_cid(curcid)) { + return -1; + } + } else { + curoid = 0; + curcid = fcid; + } + + while (1) { + struct fat_file_block_t *newblock; + + newblock = kmalloc(sizeof(struct fat_file_block_t)); + + newblock->oid = curoid; + newblock->cid = curcid; + newblock->read = 0; + newblock->dirty = 0; + + list_add_tail(&newblock->list, &data->file->list); + + *block = newblock; + + if (curoid == foid) { + return 0; + } + + curoid++; + curcid = get_next_cluster(info->fat_lba, curcid); + + if (invalid_cid(curcid)) { + return -1; + } + } +} + +static int readfile_cache(struct fat_internal *data, uint64 bckoff, uint8 *buf, uint64 bufoff, uint32 size, struct fat_file_block_t *block){ + int rsize; + + if (!block->read) { + // read the data from sdcard + struct fat_info_t *info; + int lba; + + info = data->fat; + lba = info->cluster_lba + + (block->cid - 2) * info->bs.sector_per_cluster; + + sd_readblock(lba, block->buf); + + block->read = 1; + } + + rsize = size > BLOCK_SIZE - bckoff ? BLOCK_SIZE - bckoff : size; + + memncpy((void *)&buf[bufoff], (void *)&block->buf[bckoff], rsize); + + return rsize; +} + +static int readfile_fat32(struct fat_internal *data, uint64 bckoff, uint8 *buf, uint32 bufoff, uint32 size, uint32 oid, uint32 cid){ + struct list_head *head; + struct fat_info_t *info; + struct fat_file_block_t *block; + int lba; + int rsize; + + head = &data->file->list; + info = data->fat; + + block = kmalloc(sizeof(struct fat_file_block_t)); + + rsize = size > BLOCK_SIZE - bckoff ? BLOCK_SIZE - bckoff : size; + lba = info->cluster_lba + (cid - 2) * info->bs.sector_per_cluster; + + sd_readblock(lba, block->buf); + + memncpy((void *)&buf[bufoff], (void *)&block->buf[bckoff], rsize); + + block->oid = oid; + block->cid = cid; + block->read = 1; + block->dirty = 0; + + list_add_tail(&block->list, head); + + return rsize; +} + +static int readfile(void *buf, struct fat_internal *data, uint64 fileoff, uint64 len){ + struct fat_file_block_t *block; + struct list_head *head; + uint32 foid; // first block id + uint32 coid; // current block id + uint32 cid; // target cluster id + uint64 bufoff, result; + int ret; + + block = NULL; + head = &data->file->list; + foid = fileoff / BLOCK_SIZE; + coid = 0; + cid = data->cid; + bufoff = 0; + result = 0; + + // Seek + + ret = readfile_seek_cache(data, foid, &block); + + if (ret < 0) { + ret = readfile_seek_fat32(data, foid, cid, &block); + } + + if (ret < 0) { + return 0; + } + + // if (block->oid != foid) error! + + // Read + + while (len) { + uint64 bckoff; + + bckoff = (fileoff + result) % BLOCK_SIZE; + + if (&block->list != head) { + ret = readfile_cache(data, bckoff, buf, bufoff, len, block); + + cid = block->cid; + block = list_first_entry(&block->list, + struct fat_file_block_t, list); + } else { + // Read block from sdcard, create cache + cid = get_next_cluster(data->fat->fat_lba, cid); + + if (invalid_cid(cid)) { + break; + } + + ret = readfile_fat32(data, bckoff, buf, bufoff, len, coid, cid); + } + + if (ret < 0) { + break; + } + + bufoff += ret; + result += ret; + coid += 1; + len -= ret; + } + + return result; +} + +static int writefile_seek_cache(struct fat_internal *data, uint32 foid, struct fat_file_block_t **block){ + struct fat_file_block_t *entry; + struct list_head *head; + head = &data->file->list; + + if(list_empty(head)) + return -1; + list_for_each_entry(entry, head, list){ + *block = entry; + if(foid == entry->oid) + return 0; + } + return -1; +} + +static int writefile_seek_fat32(struct fat_internal *data, uint32 foid, uint32 fcid, struct fat_file_block_t **block){ + struct fat_info_t *info; + uint32 curoid, curcid; + info = data->fat; + if(*block){ + curoid = (*block)->oid; + curcid = (*block)->cid; + if(curoid == foid) + return 0; + curoid ++; + curcid = get_next_cluster(info->fat_lba, curcid); + } + else{ + curoid = 0; + curcid = fcid; + } + while(1){ + struct fat_file_block_t *newblock; + newblock = kmalloc(sizeof(struct fat_file_block_t)); + newblock->oid = curoid; + newblock->cid = curcid; + newblock->read = 0; + newblock->dirty = 1; + + list_add_tail(&newblock->list, &data->file->list); + *block = newblock; + if(curoid == foid) + return 0; + curoid++; + curcid = get_next_cluster(info->fat_lba, curcid); + } +} + +static int writefile_cache(struct fat_internal *data, uint64 bckoff, const uint8 *buf, uint64 bufoff, uint32 size, struct fat_file_block_t *block){ + int wsize; + if(!block->read){ + struct fat_info_t *info; + int lba; + info = data->fat; + lba = info->cluster_lba + (block->cid -2 ) * info->bs.sector_per_cluster; + sd_readblock(lba, block->buf); + block->read = 1; + } + wsize = size > BLOCK_SIZE - bckoff ? BLOCK_SIZE - bckoff : size; + memncpy((void *)&block->buf[bckoff], (void *)&buf[bufoff], wsize); + return wsize; +} + +static int writefile_fat32(struct fat_internal *data, uint64 bckoff, const uint8 *buf, uint32 bufoff, uint32 size, uint32 oid, uint32 cid){ + struct list_head *head; + struct fat_info_t *info; + struct fat_file_block_t *block; + int lba; + int wsize; + head = &data->file->list; + info = data->fat; + block = kmalloc(sizeof(struct fat_file_block_t)); + + wsize = size > BLOCK_SIZE - bckoff ? BLOCK_SIZE - bckoff : size; + if(invalid_cid(cid)) + memset(block->buf, 0 , BLOCK_SIZE); + else{ + lba = info->cluster_lba + (cid -2) * info->bs.sector_per_cluster; + sd_readblock(lba, block->buf); + } + memncpy((void *)&block->buf[bufoff], (void *)&buf[bufoff], wsize); + block->oid = oid; + block->cid = cid; + block->read = 1; + block->dirty = 1; + + list_add_tail(&block->list, head); + + return wsize; +} + +static int writefile(const void *buf, struct fat_internal *data, uint64 fileoff, uint64 len){ + struct fat_file_block_t *block; + struct list_head *head; + uint32 foid, coid, cid; + uint64 bufoff, result; + int ret; + + block = NULL; + head = &data->file->list; + foid = fileoff / BLOCK_SIZE; + coid = 0; + cid = data->cid; + bufoff = 0; + result = 0; + + ret = writefile_seek_cache(data, foid, &block); + if(ret < 0) + ret = writefile_seek_fat32(data, foid, cid, &block); + if(ret < 0) + return 0; + + while(len){ + uint64 bckoff; + bckoff = (fileoff + result)%BLOCK_SIZE; + if(&block->list != head){ + ret = writefile_cache(data, bckoff, buf, bufoff, len, block); + cid = block->cid; + block = list_first_entry(&block->list, struct fat_file_block_t, list); + } + else{ + cid = get_next_cluster(data->fat->fat_lba, cid); + ret = writefile_fat32(data, bckoff, buf, bufoff, len, coid, cid); + } + if(ret < 0) + break; + bufoff += ret; + result += ret; + coid += 1; + len -= ret; + } + return result; +} + +static void _do_sync_dir(struct vnode *dirnode) +{ + struct fat_internal *data, *entry; + struct list_head *head; + struct dir_t *dir; + struct long_dir_t *ldir; + uint32 cid; + int lba, idx, lfnidx; + uint8 buf[BLOCK_SIZE]; + + data = dirnode->internal; + head = &data->dir->list; + cid = data->cid; + idx = 0; + lfnidx = 1; + + if (invalid_cid(cid)) { + panic("fat32 _do_sync_dir: invalid dirnode->data->cid"); + } + + lba = data->fat->cluster_lba + + (cid - 2) * data->fat->bs.sector_per_cluster; + + // TODO: Cache data block of directory + sd_readblock(lba, buf); + + list_for_each_entry(entry, head, list) { + struct dir_t *origindir; + const char *name; + const char *ext; + int lfn, namelen, extpos, i, buflba; + uint8 lookupbuf[BLOCK_SIZE]; + + name = entry->name; + + // If entry is a old file, update its size + origindir = lookup_fat32(dirnode, name, lookupbuf, &buflba); + + if (origindir) { + if (entry->type == FAT_FILE) { + origindir->size = entry->file->size; + sd_writeblock(buflba, lookupbuf); + } + + continue; + } + + // Else if entry is a new file + ext = NULL; + extpos = -1; + + do { + namelen = strlen(name); + + if (namelen >= 13) { + lfn = 1; + break; + } + + for (i = 0; i < namelen; ++i) { + if (name[namelen - 1 - i] == '.') { + break; + } + } + + if (i < namelen) { + ext = &name[namelen - i]; + extpos = namelen - 1 - i; + } + + if (i >= 4) { + lfn = 1; + break; + } + + if (namelen - 1 - i > 8) { + lfn = 1; + break; + } + + lfn = 0; + } while(0); + + // Seek idx to the end of dir + while (1) { + dir = (struct dir_t *)(&buf[sizeof(struct dir_t) * idx]); + + if (dir->name[0] == 0) { + break; + } + + idx += 1; + + if (idx >= 16) { + uint32 newcid; + + sd_writeblock(lba, buf); + + newcid = get_next_cluster(data->fat->fat_lba, cid); + if (invalid_cid(newcid)) { + newcid = alloc_cluster(data->fat, cid); + } + + cid = newcid; + + lba = data->fat->cluster_lba + + (cid - 2) * data->fat->bs.sector_per_cluster; + + // TODO: Cache data block of directory + sd_readblock(lba, buf); + + idx = 0; + } + } + + // Write LFN + if (lfn) { + int ord; + int first; + + ord = ((namelen - 1) / 13) + 1; + first = 0x40; + + for (; ord > 0; --ord) { + int end; + + ldir = (struct long_dir_t *) + (&buf[sizeof(struct long_dir_t) * idx]); + + ldir->order = first | ord; + ldir->attr = ATTR_LFN; + ldir->type = 0; + // TODO: Calculate checksum + ldir->checksum = 0; + ldir->fstcluslo = 0; + + first = 0; + end = 0; + + for (i = 0; i < 10; i += 2) { + if (end) { + ldir->name1[i] = 0xff; + ldir->name1[i + 1] = 0xff; + } else { + ldir->name1[i] = name[(ord - 1) * 13 + i / 2]; + ldir->name1[i + 1] = 0; + if (ldir->name1[i] == 0) { + end = 1; + } + } + } + for (i = 0; i < 12; i += 2) { + if (end) { + ldir->name2[i] = 0xff; + ldir->name2[i + 1] = 0xff; + } else { + ldir->name2[i] = name[(ord - 1) * 13 + 5 + i / 2]; + ldir->name2[i + 1] = 0; + if (ldir->name2[i] == 0) { + end = 1; + } + } + } + for (i = 0; i < 4; i += 2) { + if (end) { + ldir->name3[i] = 0xff; + ldir->name3[i + 1] = 0xff; + } else { + ldir->name3[i] = name[(ord - 1) * 13 + 11 + i / 2]; + ldir->name3[i + 1] = 0; + if (ldir->name3[i] == 0) { + end = 1; + } + } + } + + idx += 1; + + if (idx >= 16) { + uint32 newcid; + + sd_writeblock(lba, buf); + + newcid = get_next_cluster(data->fat->fat_lba, cid); + if (invalid_cid(newcid)) { + newcid = alloc_cluster(data->fat, cid); + } + + cid = newcid; + + lba = data->fat->cluster_lba + + (cid - 2) * data->fat->bs.sector_per_cluster; + + // TODO: Cache data block of directory + sd_readblock(lba, buf); + + idx = 0; + } + } + } + + // Write SFN + dir = (struct dir_t *)(&buf[sizeof(struct dir_t) * idx]); + + // TODO: Set these properties properly + dir->ntres = 0; + dir->crttimetenth = 0; + dir->crttime = 0; + dir->crtdate = 0; + dir->lstaccdate = 0; + dir->wrttime = 0; + dir->wrtdate = 0; + + if (entry->type == FAT_DIR) { + dir->attr = ATTR_DIRECTORY; + dir->size = 0; + } else { + dir->attr = ATTR_ARCHIVE; + dir->size = entry->file->size; + } + + if (invalid_cid(entry->cid)) { + entry->cid = alloc_cluster(data->fat, 0); + } + + dir->ch = (entry->cid >> 16) & 0xffff; + dir->cl = entry->cid & 0xffff; + + if (lfn) { + int lfni; + + // TODO: handle lfnidx + for (i = 7, lfni = lfnidx; i >= 0 && lfni;) { + dir->name[i--] = '0' + lfni % 10; + lfni /= 10; + } + + lfnidx++; + + dir->name[i--] = '~'; + + // TODO: handle letter case + memncpy((void *)dir->name, name, i + 1); + } else { + // TODO: handle letter case + for (i = 0; i != extpos && name[i]; ++i) { + dir->name[i] = name[i]; + } + + for (; i < 8; ++i) { + dir->name[i] = ' '; + } + } + + // TODO: handle letter case + for (i = 0; i < 3 && ext[i]; ++i) { + dir->name[8 + i] = ext[i]; + } + + for (; i < 3; ++i) { + dir->name[8 + i] = ' '; + } + + idx += 1; + + if (idx >= 16) { + int newcid; + + sd_writeblock(lba, buf); + + newcid = get_next_cluster(data->fat->fat_lba, cid); + if (invalid_cid(newcid)) { + newcid = alloc_cluster(data->fat, cid); + } + + cid = newcid; + + lba = data->fat->cluster_lba + + (cid - 2) * data->fat->bs.sector_per_cluster; + + // TODO: Cache data block of directory + sd_readblock(lba, buf); + + idx = 0; + } + } + + if (idx) { + sd_writeblock(lba, buf); + } +} + +static void _do_sync_file(struct vnode *filenode) +{ + struct fat_file_block_t *entry; + struct fat_internal *data; + struct list_head *head; + uint32 cid; + + data = filenode->internal; + head = &data->file->list; + cid = data->cid; + + if (invalid_cid(cid)) { + panic("fat32 _do_sync_file: invalid cid"); + } + + list_for_each_entry(entry, head, list) { + int lba; + + if (entry->oid == 0) { + if (!invalid_cid(entry->cid) && data->cid != entry->cid) { + panic("_do_sync_file: cid isn't sync"); + } + + entry->cid = data->cid; + } + + if (invalid_cid(entry->cid)) { + entry->cid = alloc_cluster(data->fat, cid); + } + + if (!entry->dirty) { + continue; + } + + if (!entry->read) { + memset(entry->buf, 0, BLOCK_SIZE); + entry->read = 1; + } + + lba = data->fat->cluster_lba + + (entry->cid - 2) * data->fat->bs.sector_per_cluster; + + sd_writeblock(lba, entry->buf); + + entry->dirty = 0; + + cid = entry->cid; + } +} + +static void _sync_dir(struct vnode *dirnode) +{ + struct fat_internal *data, *entry; + struct list_head *head; + + data = dirnode->internal; + head = &data->dir->list; + + _do_sync_dir(dirnode); + + list_for_each_entry(entry, head, list) { + if (entry->type == FAT_DIR) { + _sync_dir(entry->node); + } else { + _do_sync_file(entry->node); + } + } +} + +int fat32fs_mount(struct filesystem *fs, struct mount *mount){ + struct partition_t *partition; + struct fat_info_t *fat; + struct fat_dir_t *dir; + struct fat_internal *data; + struct vnode *oldnode, *node; + struct fat_mount_t *newmount; + const char *name; + uint32 lba; + uint8 buf[BLOCK_SIZE]; + + sd_readblock(0, buf); + partition = (struct partition_t *)&buf[0x1be]; + if(buf[510] != 0x55 || buf[511] != 0xaa) + return -1; + if(partition[0].type != 0xb && partition[0].type != 0xc) + return -1; + lba = partition[0].lba; + + sd_readblock(partition[0].lba, buf); + + node = kmalloc(sizeof(struct vnode)); + data = kmalloc(sizeof(struct fat_internal)); + fat = kmalloc(sizeof(struct fat_info_t)); + dir = kmalloc(sizeof(struct fat_dir_t)); + newmount = kmalloc(sizeof(struct fat_mount_t)); + + memncpy((void *)&fat->bs,(void *)buf,sizeof(fat->bs)); + fat->fat_lba = lba + fat->bs.reserved_sector_cnt; + fat->cluster_lba = fat->fat_lba + fat->bs.fat_cnt * fat->bs.sector_per_fat32; + INIT_LIST_HEAD(&dir->list); + + oldnode = mount->root; + oldnode->v_ops->getname(oldnode, &name); + + node->mount = oldnode->mount; + node->v_ops = oldnode->v_ops; + node->f_ops = oldnode->f_ops; + node->parent = oldnode->parent; + node->internal = oldnode->internal; + + data->name = name; + data->node = node; + data->fat = fat; + data->cid = 2; + data->type = FAT_DIR; + data->dir = dir; + + oldnode->mount = mount; + oldnode->v_ops = &fat32fs_v_ops; + oldnode->f_ops = &fat32fs_f_ops; + oldnode->internal = data; + + preempt_disable(); + + list_add(&newmount->list, &mounts); + + preempt_enable(); + + newmount->mount = mount; + + return 0; +} +int fat32fs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name){ + struct fat_internal *data; + int ret; + + data = dir_node->internal; + if(data->type != FAT_DIR) + return -1; + ret = lookup_cache(dir_node, target, component_name); + if(ret >= 0) + return ret; + return lookup__fat32(dir_node, target, component_name); +} +int fat32fs_create(struct vnode *dir_node, struct vnode **target, const char *component_name){ + struct vnode *node; + struct fat_internal *internal; + int ret; + + internal = dir_node->internal; + if(internal->type != FAT_DIR) + return -1; + ret = fat32fs_lookup(dir_node, target, component_name); + + if(!ret) + return -1; + + node = create_vnode(dir_node, component_name, FAT_FILE, -1 , 0); + *target = node; + return 0; +} +int fat32fs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name){ + struct vnode *node; + struct fat_internal *internal; + int ret; + internal = dir_node->internal; + if(internal->type != FAT_DIR) + return -1; + ret = fat32fs_lookup(dir_node, target, component_name); + if(!ret) + return -1; + + node = create_vnode(dir_node, component_name, FAT_DIR, -1, 0); + *target = node; + return 0; +} +int fat32fs_isdir(struct vnode *dir_node){ + struct fat_internal *internal; + internal = dir_node->internal; + if(internal->type != FAT_DIR) + return 0; + return 1; +} +int fat32fs_getname(struct vnode *dir_node, const char **name){ + struct fat_internal *internal; + internal = dir_node->internal; + *name = internal->name; + return 0; +} +int fat32fs_getsize(struct vnode *dir_node){ + struct fat_internal *internal; + internal = dir_node->internal; + if(internal->type == FAT_DIR) + return 0; + return internal->file->size; +} +int fat32fs_write(struct file *file, const void *buf, size_t len){ + struct fat_internal *data; + int filesize, ret; + if(fat32fs_isdir(file->vnode)) + return -1; + if(!len) + return len; + filesize = fat32fs_getsize(file->vnode); + data = file->vnode->internal; + ret = writefile(buf, data, file->f_pos, len); + if(ret <= 0) + return ret; + file->f_pos += ret; + if(file->f_pos > filesize) + data->file->size = file->f_pos; + return ret; +} +int fat32fs_read(struct file *file, void *buf, size_t len){ + struct fat_internal *data; + int filesize; + int ret; + + if(fat32fs_isdir(file->vnode)) + return -1; + + filesize = fat32fs_getsize(file->vnode); + data = file->vnode->internal; + if(file->f_pos + len > filesize) + len = filesize - file->f_pos; + + if(!len) + return len; + ret = readfile(buf, data, file->f_pos, len); + if(ret <= 0) + return ret; + file->f_pos += ret; + return ret; +} +int fat32fs_open(struct vnode *file_node, struct file *target){ + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} +int fat32fs_close(struct file *file){ + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + return 0; +} +long fat32fs_lseek64(struct file *file, long offset, int whence){ + int filesize; + int base; + + if (!fat32fs_isdir(file->vnode)) { + return -1; + } + + filesize = fat32fs_getsize(file->vnode); + + if (filesize < 0) { + return -1; + } + + switch (whence) { + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = file->f_pos; + break; + case SEEK_END: + base = filesize; + break; + default: + return -1; + } + + if (base + offset > filesize) { + return -1; + } + + file->f_pos = base + offset; + + return 0; +} +int fat32fs_ioctl(struct file *file, uint64 request, va_list args){ + return -1; +} + +int fat32fs_sync(struct filesystem *fs){ + struct fat_mount_t *entry; + + list_for_each_entry(entry, &mounts, list) { + _sync_dir(entry->mount->root); + } + + return 0; +} + +struct filesystem *fat32fs_init(void){ + INIT_LIST_HEAD(&mounts); + return &fat32fs; +} \ No newline at end of file diff --git a/src/lib/framebufferfs.c b/src/lib/framebufferfs.c new file mode 100644 index 000000000..fe9ceeee4 --- /dev/null +++ b/src/lib/framebufferfs.c @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct filesystem fbfs = { + .name = "framebufferfs", + .mount = fbfs_mount, + .sync = fbfs_sync, +}; + +static struct vnode_operations fbfs_v_ops = { + .lookup = fbfs_lookup, + .create = fbfs_create, + .mkdir = fbfs_mkdir, + .isdir = fbfs_isdir, + .getname = fbfs_getname, + .getsize = fbfs_getsize +}; + +static struct file_operations fbfs_f_ops = { + .write = fbfs_write, + .read = fbfs_read, + .open = fbfs_open, + .close = fbfs_close, + .lseek64 = fbfs_lseek64, + .ioctl = fbfs_ioctl +}; + + +int fbfs_mount(struct filesystem *fs, struct mount *mount){ + struct vnode *oldnode; + struct fbfs_internal *internal; + const char *name; + + internal = kmalloc(sizeof(struct fbfs_internal)); + + oldnode = mount->root; + + oldnode->v_ops->getname(oldnode, &name); + + internal->name = name; + internal->oldnode.mount = oldnode->mount; + internal->oldnode.v_ops = oldnode->v_ops; + internal->oldnode.f_ops = oldnode->f_ops; + internal->oldnode.parent = oldnode->parent; + internal->oldnode.internal = oldnode->internal; + internal->lfb = NULL; + internal->isopened = 0; + internal->isinit = 0; + + oldnode->mount = mount; + oldnode->v_ops = &fbfs_v_ops; + oldnode->f_ops = &fbfs_f_ops; + oldnode->internal = internal; + + return 0; +} +int fbfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name){ + return -1; +} +int fbfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name){ + return -1; +} +int fbfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name){ + return -1; +} +int fbfs_isdir(struct vnode *dir_node){ + return 0; +} +int fbfs_getname(struct vnode *dir_node, const char **name){ + struct fbfs_internal *internal = dir_node->internal; + *name = internal->name; + return 0; +} +int fbfs_getsize(struct vnode *dir_node){ + return -1; +} +int fbfs_write(struct file *file, const void *buf, size_t len){ + struct fbfs_internal *internal = file->vnode->internal; + if(!internal->isinit) + return -1; + + if(file->f_pos + len > internal->lfbsize) + return -1; + + memncpy((void *)(internal->lfb + file->f_pos), buf, len); + file->f_pos += len; + + return len; +} +int fbfs_read(struct file *file, void *buf, size_t len){ + return -1; +} +int fbfs_open(struct vnode *file_node, struct file *target){ + struct fbfs_internal *internal; + preempt_disable(); + internal = file_node->internal; + if(internal->isopened){ + preempt_enable(); + return -1; + } + internal->isopened = 1; + preempt_enable(); + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} +int fbfs_close(struct file *file){ + struct fbfs_internal *internal = file->vnode->internal; + + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + internal->isopened = 0; + return 0; +} +long fbfs_lseek64(struct file *file, long offset, int whence){ + struct fbfs_internal *internal = file->vnode->internal; + int base; + switch(whence){ + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = file->f_pos; + break; + case SEEK_END: + base = internal->lfbsize; + default: + return -1; + } + + if(base + offset > internal->lfbsize) + return -1; + file->f_pos = base + offset; + return 0; +} + +int fbfs_ioctl(struct file *file, uint64 request, va_list args) +{ + struct fb_info *user_fb_info; + struct fbfs_internal *internal; + /* dimensions and channel order */ + uint32 width, height, pitch, isrgb; + + if (request != 0) { + return -1; + } + + internal = file->vnode->internal; + + mbox[0] = 35 * 4; + mbox[1] = REQUEST_CODE; + + mbox[2] = 0x48003; // set phy wh + mbox[3] = 8; + mbox[4] = 8; + mbox[5] = 1024; // FrameBufferInfo.width + mbox[6] = 768; // FrameBufferInfo.height + + mbox[7] = 0x48004; // set virt wh + mbox[8] = 8; + mbox[9] = 8; + mbox[10] = 1024; // FrameBufferInfo.virtual_width + mbox[11] = 768; // FrameBufferInfo.virtual_height + + mbox[12] = 0x48009; // set virt offset + mbox[13] = 8; + mbox[14] = 8; + mbox[15] = 0; // FrameBufferInfo.x_offset + mbox[16] = 0; // FrameBufferInfo.y.offset + + mbox[17] = 0x48005; // set depth + mbox[18] = 4; + mbox[19] = 4; + mbox[20] = 32; // FrameBufferInfo.depth + + mbox[21] = 0x48006; // set pixel order + mbox[22] = 4; + mbox[23] = 4; + mbox[24] = 1; // RGB, not BGR preferably + + mbox[25] = 0x40001; // get framebuffer, gets alignment on request + mbox[26] = 8; + mbox[27] = 8; + mbox[28] = 4096; // FrameBufferInfo.pointer + mbox[29] = 0; // FrameBufferInfo.size + + mbox[30] = 0x40008; // get pitch + mbox[31] = 4; + mbox[32] = 4; + mbox[33] = 0; // FrameBufferInfo.pitch + + mbox[34] = END_TAG; + + // this might not return exactly what we asked for, could be + // the closest supported resolution instead + + mbox_call(MBOX_CH_PROP, mbox); + + if (mbox[20] == 32 && mbox[28] != 0) { + mbox[28] &= 0x3FFFFFFF; // convert GPU address to ARM address + width = mbox[5]; // get actual physical width + height = mbox[6]; // get actual physical height + pitch = mbox[33]; // get number of bytes per line + isrgb = mbox[24]; // get the actual channel order + internal->lfb = (void *)PA2VA(mbox[28]); + internal->lfbsize = mbox[29]; + } else { + // Unable to set screen resolution to 1024x768x32 + return -1; + } + + user_fb_info = va_arg(args, void *); + + user_fb_info->width = width; + user_fb_info->height = height; + user_fb_info->pitch = pitch; + user_fb_info->isrgb = isrgb; + + internal->isinit = 1; + + return 0; +} + +int fbfs_sync(struct filesystem *fs){ + return 0; +} + +struct filesystem *framebufferfs_init(void){ + return &fbfs; +} \ No newline at end of file diff --git a/src/lib/fsinit.c b/src/lib/fsinit.c new file mode 100644 index 000000000..7e196be6c --- /dev/null +++ b/src/lib/fsinit.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +void fs_early_init(void){ + struct filesystem *tmpfs, *cpiofs, *uartfs, *fbfs, *fat32fs; + + vfs_init(); + sd_init(); + + tmpfs = tmpfs_init(); + cpiofs = cpiofs_init(); + uartfs = uartfs_init(); + fbfs = framebufferfs_init(); + fat32fs = fat32fs_init(); + register_filesystem(tmpfs); + register_filesystem(cpiofs); + register_filesystem(uartfs); + register_filesystem(fbfs); + register_filesystem(fat32fs); + + vfs_init_rootmount(tmpfs); + + vfs_mkdir("/initramfs"); + vfs_mount("/initramfs", "cpiofs"); + + vfs_mkdir("/dev"); + + vfs_mkdir("/dev/uart"); + vfs_mount("/dev/uart", "uartfs"); + + vfs_mkdir("/dev/framebuffer"); + vfs_mount("/dev/framebuffer", "framebufferfs"); + + vfs_mkdir("/boot"); + vfs_mount("/boot", "fat32fs"); +} \ No newline at end of file diff --git a/src/lib/irq.c b/src/lib/irq.c index 0f3265bac..f90512d11 100644 --- a/src/lib/irq.c +++ b/src/lib/irq.c @@ -132,6 +132,8 @@ void irq_init(){ void default_exception_handler(uint32 n){ uart_printf("[exception] %d\r\n", n); + // never reach + while(1){} } void irq_handler(){ @@ -155,5 +157,5 @@ void irq_handler(){ } void enable_irqs1(){ - put32(ENABLE_IRQS1, 1 << 29); // Enable UART1 IRQ + put32(PA2VA(ENABLE_IRQS1), 1 << 29); // Enable UART1 IRQ } \ No newline at end of file diff --git a/src/lib/kthread.c b/src/lib/kthread.c index 061efa4cf..189c8ff5c 100644 --- a/src/lib/kthread.c +++ b/src/lib/kthread.c @@ -73,6 +73,10 @@ void kthread_fini(void) schedule(); } +void kthread_early_init(void){ + set_current(NULL); +} + void kthread_add_wait_queue(task_struct *task){ wq_add_task(task, wait_queue); } diff --git a/src/lib/mbox.c b/src/lib/mbox.c index 84a3c0683..6a4002a87 100644 --- a/src/lib/mbox.c +++ b/src/lib/mbox.c @@ -1,30 +1,10 @@ #include #include - -#define MMIO_BASE 0x3F000000 +#include /* mailbox message buffer */ volatile unsigned int __attribute__((aligned(16))) mbox[36]; -#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) -#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) -#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) -#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) -#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) -#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) -#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) -#define MBOX_RESPONSE 0x80000000 -#define MBOX_FULL 0x80000000 -#define MBOX_EMPTY 0x40000000 - -/* Mailbox tags */ -#define GET_BOARD_REVISION 0x00010002 -#define GET_ARM_MEMORY 0x00010005 - -#define REQUEST_CODE 0x00000000 -#define TAG_REQUEST_CODE 0x00000000 -#define END_TAG 0x00000000 - /** * Make a mailbox call. Returns 0 on failure, non-zero on success */ @@ -60,7 +40,7 @@ void get_board_revision(unsigned int *revision){ if(mbox_call(MBOX_CH_PROP, mbox)!=0) *revision = mbox[5]; else{ - uart_send_string("Unable to get borad revision!"); + uart_printf("Unable to get borad revision!"); *revision = 0; } } @@ -80,5 +60,5 @@ void get_arm_memory(arm_info *arm_mem){ arm_mem->size = mbox[6]; } else - uart_send_string("Unable to get arm memory information!"); + uart_printf("Unable to get arm memory information!"); } \ No newline at end of file diff --git a/src/lib/mini_uart.c b/src/lib/mini_uart.c index 6eb3dd03b..e975bdd1b 100644 --- a/src/lib/mini_uart.c +++ b/src/lib/mini_uart.c @@ -21,40 +21,29 @@ static char w_buffer[BUFSIZE]; static char r_buffer[BUFSIZE]; static int w_head, w_tail, r_head, r_tail; - -char uart_recv(void){ - return (uart_recv_fp)(); -} - -void uart_recvn(char *buff, int n){ - while(n--) - *buff++ = (uart_recv_fp)(); -} - -void uart_send(char c){ - (uart_send_fp)(c); -} static inline void enable_R_interrupt(){ - uint32 ier = get32(AUX_MU_IER_REG); + uint32 ier = get32(PA2VA(AUX_MU_IER_REG)); ier |= 0x01; - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); } static inline void enable_W_interrupt(){ - uint32 ier = get32(AUX_MU_IER_REG); + uint32 ier = get32(PA2VA(AUX_MU_IER_REG)); ier |= 0x02; - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); } static inline void disable_RW_interrupt(){ - put32(AUX_MU_IER_REG, 0); + put32(PA2VA(AUX_MU_IER_REG), 0); } static inline void enable_RW_interrupt(){ - put32(AUX_MU_IER_REG, 3); + put32(PA2VA(AUX_MU_IER_REG), 3); } static char uart_async_recv(void){ + // Enable R interrupt + enable_R_interrupt(); while(1){ if(r_head != r_tail) break; @@ -76,78 +65,32 @@ static void uart_async_send(char c) w_buffer[w_tail] = c; w_tail = (w_tail + 1) % BUFSIZE; - // Enable transmit interrupt - uint32 ier = get32(AUX_MU_IER_REG); - ier = ier | 0x02; - put32(AUX_MU_IER_REG, ier); - - enable_interrupt(); + // Enable W interrupt + enable_W_interrupt(); } static char uart_sync_recv (void){ while(1) { - if(get32(AUX_MU_LSR_REG)&0x01) + if(get32(PA2VA(AUX_MU_LSR_REG))&0x01) break; } - return(get32(AUX_MU_IO_REG)&0xFF); + return(get32(PA2VA(AUX_MU_IO_REG))&0xFF); } static void uart_sync_send (char c){ while(1) { - if(get32(AUX_MU_LSR_REG)&0x20) // hang until can read + if(get32(PA2VA(AUX_MU_LSR_REG))&0x20) // hang until can read break; } - put32(AUX_MU_IO_REG,c); + put32(PA2VA(AUX_MU_IO_REG),c); } -void uart_send_string(char *str){ +static void uart_send_string(sendfp _send_fp, char *str){ for (int i = 0; str[i] != '\0'; i ++) - uart_send(str[i]); -} - -void uart_send_hex(unsigned int d) { - unsigned int n; - int c; - uart_send_string("0x"); - for(c=28;c>=0;c-=4) { - // get highest tetrad - n=(d>>c)&0xF; - // 0-9 => '0'-'9', 10-15 => 'A'-'F' - n+=n>9?0x37:0x30; - uart_send(n); - } -} - -int uart_recv_line(char *buf, int maxline){ - int cnt = 0; - maxline--; - - while(maxline){ - char c = uart_recv(); - if(c == '\r') - break; - uart_send(c); - *buf = c; - buf++; - cnt++; - maxline--; - } - - *buf = 0; - return cnt; -} - -uint32 uart_recv_uint(void){ - char buf[4]; - - for (int i = 0; i < 4; ++i) { - buf[i] = uart_recv(); - } - - return *((uint32*)buf); + (_send_fp)(str[i]); } -static void uart_send_num(int32 num, int base, int type) +static void uart_send_num(sendfp _send_fp, int64 num, int base, int type) { static const char digits[16] = "0123456789ABCDEF"; char tmp[66]; @@ -155,7 +98,7 @@ static void uart_send_num(int32 num, int base, int type) if (type & 1) { if (num < 0) { - uart_send('-'); + (_send_fp)('-'); } } @@ -165,30 +108,27 @@ static void uart_send_num(int32 num, int base, int type) tmp[i++] = '0'; } else { while (num != 0) { - uint8 r = (uint32)num % base; - num = (uint32)num / base; + uint8 r = (uint64)num % base; + num = (uint64)num / base; tmp[i++] = digits[r]; } } while (--i >= 0) { - uart_send(tmp[i]); + (_send_fp)(tmp[i]); } } -void uart_printf(const char *fmt, ...){ +static void _uart_printf(sendfp _send_fp, const char *fmt, va_list args){ const char *s; char c; uint32 num; - char width; - - va_list args; - va_start(args, fmt); + char width; for (; *fmt; ++fmt) { if (*fmt != '%') { - uart_send(*fmt); + (_send_fp)(*fmt); continue; } @@ -203,80 +143,32 @@ void uart_printf(const char *fmt, ...){ switch (*fmt) { case 'c': c = va_arg(args, uint32) & 0xff; - uart_send(c); + (_send_fp)(c); continue; case 'd': if(width) num = va_arg(args, int64); else num = va_arg(args, int32); - uart_send_num(num, 10, 1); + uart_send_num(_send_fp, num, 10, 1); continue; case 's': s = va_arg(args, char *); - uart_send_string((char*)s); + uart_send_string(_send_fp,(char*)s); continue; case 'x': if (width) num = va_arg(args, uint64); else num = va_arg(args, uint32); - uart_send_num(num, 16, 0); + uart_send_num(_send_fp, num, 16, 0); continue; } } } -void uart_sendn(const char *str, int n){ - while (n--) - uart_send(*str++); -} - -void uart_init (void) -{ - unsigned int selector; - - selector = get32(GPFSEL1); - selector &= ~(7<<12); // clean gpio14 (rx) - selector |= 2<<12; // set alt5 for gpio14 - selector &= ~(7<<15); // clean gpio15 (tx) - selector |= 2<<15; // set alt5 for gpio15 - put32(GPFSEL1,selector); - - put32(GPPUD,0); //Disable pull up/down, floating input pin - delay(150); - put32(GPPUDCLK0,(1<<14)|(1<<15)); - delay(150); - put32(GPPUDCLK0,0); - - put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to its registers) - put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) - put32(AUX_MU_IER_REG,0); //Disable receive and transmit interrupts - put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode - put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high - put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 - put32(AUX_MU_IIR_REG, 6); //Clear the Rx/Tx FIFO - put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver - - // UART start from synchronous mode - uart_sync_mode = 0; - uart_recv_fp = uart_sync_recv; - uart_send_fp = uart_sync_send; -} -int uart_irq_add(){ - uint32 iir = get32(AUX_MU_IIR_REG); - // No interrupt - if(iir & 0x01) - return 0; - - disable_RW_interrupt(); - if(irq_add_task((void (*)(void *))uart_irq_handler, NULL,uart_irq_fini, UART_PRIO)) - enable_RW_interrupt(); - - return 1; -} -void uart_irq_handler(void){ - uint32 iir = get32(AUX_MU_IIR_REG), ier = 0; +static void uart_irq_handler(void *_){ + uint32 iir = get32(PA2VA(AUX_MU_IIR_REG)); // Transmit holding register empty if(iir & 0x02){ @@ -285,7 +177,7 @@ void uart_irq_handler(void){ /* if head not equals to tail ==> means write buffer is not empty Then we need to write the buffer to IO register and move the buffer pointer backward*/ if(w_head != w_tail){ - put32(AUX_MU_IO_REG, w_buffer[w_head]); + put32(PA2VA(AUX_MU_IO_REG), w_buffer[w_head]); w_head = (w_head+1)%BUFSIZE; } } @@ -294,12 +186,17 @@ void uart_irq_handler(void){ else if(iir & 0x04){ // if head not equals to tail+1 ==> means read buffer still have some place if(r_head != (r_tail+1)%BUFSIZE){ - r_buffer[r_tail] = get32(AUX_MU_IO_REG) & 0xff; + r_buffer[r_tail] = get32(PA2VA(AUX_MU_IO_REG)) & 0xff; r_tail = (r_tail+1)%BUFSIZE; } } +} - if (r_head != (r_tail + 1) % BUFSIZE) { +static void uart_irq_fini(){ + uint32 ier = get32(PA2VA(AUX_MU_IER_REG)); + ier &= ~(0x03); + + if (r_head != (r_tail + 1) % BUFSIZE) { ier = ier | 0x01; } @@ -307,27 +204,125 @@ void uart_irq_handler(void){ ier = ier | 0x02; } - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); } -static void uart_irq_fini(){ - uint32 ier = get32(AUX_MU_IER_REG); - ier &= ~(0x03); +char uart_recv(void){ + return (uart_recv_fp)(); +} - if (r_head != (r_tail + 1) % BUFSIZE) { - ier = ier | 0x01; - } +void uart_recvn(char *buff, int n){ + while(n--) + *buff++ = (uart_recv_fp)(); +} - if (w_head != w_tail) { - ier = ier | 0x02; +void uart_send(char c){ + (uart_send_fp)(c); +} + +void uart_printf(const char *fmt, ...){ + va_list args; + va_start(args, fmt); + + _uart_printf(uart_send_fp, fmt, args); + + va_end(args); +} + +void uart_sync_printf(const char *fmt, ...){ + va_list args; + va_start(args, fmt); + + _uart_printf(uart_sync_send, fmt, args); + + va_end(args); +} + +void uart_sync_vprintf(const char *fmt, va_list args){ + _uart_printf(uart_sync_send, fmt, args); +} + +int uart_recv_line(char *buf, int maxline){ + int cnt = 0; + maxline--; + + while(maxline){ + char c = uart_recv(); + if(c == '\r') + break; + uart_send(c); + *buf = c; + buf++; + cnt++; + maxline--; + } + + *buf = 0; + return cnt; +} + +uint32 uart_recv_uint(void){ + char buf[4]; + + for (int i = 0; i < 4; ++i) { + buf[i] = uart_recv(); } - put32(AUX_MU_IER_REG, ier); + return *((uint32*)buf); +} + +void uart_sendn(const char *str, int n){ + while (n--) + uart_send(*str++); +} + +void uart_init (void) +{ + unsigned int selector; + + selector = get32(PA2VA(GPFSEL1)); + selector &= ~(7<<12); // clean gpio14 (rx) + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 (tx) + selector |= 2<<15; // set alt5 for gpio15 + put32(PA2VA(GPFSEL1),selector); + + put32(PA2VA(GPPUD),0); //Disable pull up/down, floating input pin + delay(150); + put32(PA2VA(GPPUDCLK0),(1<<14)|(1<<15)); + delay(150); + put32(PA2VA(GPPUDCLK0),0); + + put32(PA2VA(AUX_ENABLES),1); //Enable mini uart (this also enables access to its registers) + put32(PA2VA(AUX_MU_CNTL_REG),0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(PA2VA(AUX_MU_IER_REG),0); //Disable receive and transmit interrupts + put32(PA2VA(AUX_MU_LCR_REG),3); //Enable 8 bit mode + put32(PA2VA(AUX_MU_MCR_REG),0); //Set RTS line to be always high + put32(PA2VA(AUX_MU_BAUD_REG),270); //Set baud rate to 115200 + put32(PA2VA(AUX_MU_IIR_REG), 6); //Clear the Rx/Tx FIFO + put32(PA2VA(AUX_MU_CNTL_REG),3); //Finally, enable transmitter and receiver + + // UART start from synchronous mode + uart_sync_mode = 0; + uart_recv_fp = uart_sync_recv; + uart_send_fp = uart_sync_send; +} +int uart_irq_add(){ + uint32 iir = get32(PA2VA(AUX_MU_IIR_REG)); + // No interrupt + if(iir & 0x01) + return 0; + + disable_RW_interrupt(); + if(irq_add_task(uart_irq_handler, NULL,uart_irq_fini, UART_PRIO)) + enable_RW_interrupt(); + + return 1; } int uart_switch_mode(void){ uart_sync_mode = !uart_sync_mode; - uint32 ier = get32(AUX_MU_IER_REG); + uint32 ier = get32(PA2VA(AUX_MU_IER_REG)); // set bit 0 and bit 1 to zero ier &= ~(0x03); @@ -337,7 +332,7 @@ int uart_switch_mode(void){ uart_send_fp = uart_sync_send; // disable interrupt; - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); } else{ // asynchronous mode @@ -345,12 +340,12 @@ int uart_switch_mode(void){ uart_send_fp = uart_async_send; // clear Rx/Tx FIFO - put32(AUX_MU_IIR_REG, 6); + put32(PA2VA(AUX_MU_IIR_REG), 6); // enable receive interrupt ier |= 0x01; - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); } return uart_sync_mode; diff --git a/src/lib/mm.S b/src/lib/mm.S index aba5d83f4..1e8e035f6 100644 --- a/src/lib/mm.S +++ b/src/lib/mm.S @@ -12,4 +12,11 @@ memncpy: strb w3, [x0], #1 subs x2, x2, #1 b.gt memncpy + ret + +.globl memset +memset: + strb w1, [x0], #1 + subs x2, x2, #1 + b.gt memset ret \ No newline at end of file diff --git a/src/lib/mm.c b/src/lib/mm.c index fefb747e3..5a26e19d3 100644 --- a/src/lib/mm.c +++ b/src/lib/mm.c @@ -70,17 +70,17 @@ void mm_init(char *fdt_base){ if(!memory_end) uart_printf("[x] Cannot find memory end addr in fdt.\r\n"); - page_allocator_early_init((void *) 0,(void *) memory_end); + page_allocator_early_init((void *)PA2VA(0),(void *)PA2VA(memory_end)); sc_early_init(); // Spin tables for multicore boot - mem_reserve((void *)0, (void *)0x1000); + mem_reserve((void *)PA2VA(0), (void *)PA2VA(0x4000)); // Kernel image in the physical memory mem_reserve(_start, (void *)&_stack_top); // Initramfs - mem_reserve((void *)_initramfs_addr, (void *)_initramfs_end); + mem_reserve(_initramfs_addr, _initramfs_end); // Simple malloc mem_reserve(SMEM, EMEM); diff --git a/src/lib/mmu.c b/src/lib/mmu.c new file mode 100644 index 000000000..961292a91 --- /dev/null +++ b/src/lib/mmu.c @@ -0,0 +1,551 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// translation control register +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 + +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PD_ACCESS (1 << 10) +#define PD_PXN ((uint64)1 << 53) +// none secure +#define PD_NSTABLE ((uint64)1 << 63) + +// unprivileged access will never execute the code +#define PD_UXNTABLE ((uint64)1 << 60) +#define PD_MAIR_DEVICE_IDX (MAIR_IDX_DEVICE_nGnRnE << 2) +#define PD_MAIR_NORMAL_IDX (MAIR_IDX_NORMAL_NOCACHE << 2) +// Block Entry +#define PD_BE PD_ACCESS | PD_BLOCK +// Level 3 Block Entry +#define PD_L3BE PD_ACCESS | PD_TABLE + +#define BOOT_PGD ((pd_t *)0x1000) +#define BOOT_PUD ((pd_t *)0x2000) +#define BOOT_PMD ((pd_t *)0x3000) + +static void segmentation_fault(void) +{ + uart_sync_printf("[Segmentation fault]: Kill Process\r\n"); + exit_user_prog(); + + // Never reach +} + +static vm_area_t *vma_create(void *va, uint64 size, uint64 flag, void *addr) +{ + vm_area_t *vma; + + vma = kmalloc(sizeof(vm_area_t)); + size = ALIGN(size, PAGE_SIZE); + + vma->va_begin = (uint64)va; + vma->va_end = (uint64)va + size; + vma->flag = flag; + + if (vma->flag & VMA_ANON) { + vma->kva = 0; + } else if (vma->flag & VMA_PA) { + vma->kva = PA2VA(addr); + } else if (vma->flag & VMA_KVA) { + vma->kva = (uint64)addr; + } else { + // Unexpected + panic("vma_create flag error"); + } + + return vma; +} + +static void clone_uva_region(uint64 uva_begin, uint64 uva_end, + pd_t *pt, uint64 flag) +{ + for (uint64 addr = uva_begin; addr < uva_end; addr += PAGE_SIZE) { + void *new_kva; + uint64 par; + + // try to get the PA of UVA + asm volatile ( + "at s1e0r, %0" + :: "r" (addr) + ); + + par = read_sysreg(PAR_EL1); + + if (PAR_FAILED(par)) { + // VA to PA conversion aborted + continue; + } + + // convert PA to KVA + par = PA2VA(PAR_PA(par)); + + // Allocate a page and copy content to this page + new_kva = kmalloc(PAGE_SIZE); + memncpy(new_kva, (void *)par, PAGE_SIZE); + + // map @new_kva into @pt + pt_map(pt, (void *)addr, PAGE_SIZE, (void *)VA2PA(new_kva), flag); + } +} + +static vm_area_t *vma_clone(vm_area_t *vma, pd_t *page_table) +{ + vm_area_t *new_vma; + + new_vma = kmalloc(sizeof(vm_area_t)); + + new_vma->va_begin = vma->va_begin; + new_vma->va_end = vma->va_end; + new_vma->flag = vma->flag; + + if (vma->flag & VMA_ANON) { + clone_uva_region(vma->va_begin, vma->va_end, page_table, vma->flag); + new_vma->kva = 0; + } else if (vma->flag & VMA_PA) { + new_vma->kva = vma->kva; + } else if (vma->flag & VMA_KVA) { + void *new_kva; + + new_kva = kmalloc(vma->va_end - vma->va_begin); + memncpy(new_kva, (void *)vma->kva, vma->va_end - vma->va_begin); + + new_vma->kva = (uint64)new_kva; + } else { + // Unexpected + panic("vma_clone flag error"); + } + + return new_vma; +} + +static void free_uva_region(uint64 uva_begin, uint64 uva_end) +{ + for (uint64 addr = uva_begin; addr < uva_end; addr += PAGE_SIZE) { + uint64 par; + + // try to get the PA of UVA, address translation, stage1, el0 read translation of a virtual address + asm volatile ( + "at s1e0r, %0" + :: "r" (addr) + ); + + par = read_sysreg(PAR_EL1); + + if (PAR_FAILED(par)) { + // VA to PA conversion aborted + continue; + } + + // convert PA to KVA + par = PA2VA(PAR_PA(par)); + + // free KVA + kfree((void *)par); + } +} + +static void vma_free(vm_area_t *vma) +{ + if (vma->kva && vma->flag & VMA_KVA) { + kfree((void *)vma->kva); + } else if (vma->flag & VMA_ANON) { + free_uva_region(vma->va_begin, vma->va_end); + } else if (!(vma->flag & VMA_PA)){ + // Unexpected + panic("vma_free flag error"); + } + + kfree(vma); +} + +static vm_area_t *vma_find(vm_area_meta_t *vma_meta, uint64 addr) +{ + vm_area_t *vma; + + list_for_each_entry(vma, &vma_meta->vma, list) { + if (vma->va_begin <= addr && addr < vma->va_end) { + return vma; + } + } + + return NULL; +} + +void mmu_init(void) +{ + uint32 sctlr_el1; + + // Set Translation Control Register + write_sysreg(TCR_EL1, TCR_CONFIG_DEFAULT); + + // Set Memory Attribute Indirection Register + write_sysreg(MAIR_EL1, + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))); + + // Set Identity Paging + // 0x00000000 ~ 0x3f000000: Normal + // 0x3f000000 ~ 0x40000000: Device + // 0x40000000 ~ 0x80000000: Device + BOOT_PGD[0] = (uint64)BOOT_PUD | PD_NSTABLE | PD_UXNTABLE | PD_TABLE; + + BOOT_PUD[0] = (uint64)BOOT_PMD | PD_TABLE; + BOOT_PUD[1] = 0x40000000 | PD_MAIR_DEVICE_IDX | PD_BE; + + for (int i = 0; i < 504; ++i) { + BOOT_PMD[i] = (i * (1 << 21)) | PD_MAIR_NORMAL_IDX | PD_BE; + } + + // 0x3F000000 to 0x3FFFFFFF for peripherals + for (int i = 504; i < 512; ++i) { + BOOT_PMD[i] = (i * (1 << 21)) | PD_MAIR_DEVICE_IDX | PD_BE; + } + + write_sysreg(TTBR0_EL1, BOOT_PGD); + write_sysreg(TTBR1_EL1, BOOT_PGD); + + // Enable MMU, sctlr: system control register + sctlr_el1 = read_sysreg(SCTLR_EL1); + write_sysreg(SCTLR_EL1, sctlr_el1 | 1); +} + +pd_t *pt_create(void) +{ + pd_t *pt = kmalloc(PAGE_TABLE_SIZE); + + for (int i = 0; i < PAGE_TABLE_SIZE / sizeof(pt[0]); ++i) { + pt[i] = 0; + } + + return pt; +} + +void pt_free(pd_t *pt) +{ + // TODO +} + +static void _pt_map(pd_t *pt, void *va, void *pa, uint64 flag) +{ + pd_t pd; + int idx; + + // 47 ~ 39, 38 ~ 30, 29 ~ 21, 20 ~ 12 + for (int layer = 3; layer > 0; --layer) { + idx = ((uint64)va >> (12 + 9 * layer)) & 0b111111111; + pd = pt[idx]; + + if (!(pd & 1)) { + // Invalid entry + pd_t *tmp = pt_create(); + pt[idx] = VA2PA(tmp) | PD_TABLE; + pt = tmp; + continue; + } + + // Must be a table entry + pt = (pd_t *)PA2VA(pd & ~((uint64)0xfff)); + } + + idx = ((uint64)va >> 12) & 0b111111111; + pd = pt[idx]; + + if (!(pd & 1)) { + // Invalid entry + // Access permissions + uint64 ap; + uint64 uxn; + + if (flag & PT_R) { + if (flag & PT_W) { + ap = 0b01; + } else { + ap = 0b11; + } + } else { + ap = 0b00; + } + + if (flag & PT_X) { + uxn = 0; + } else { + uxn = 1; + } + + pt[idx] = (uint64)pa | (uxn << 54) | PD_PXN | + PD_MAIR_NORMAL_IDX | (ap << 6) | PD_L3BE; + } + + // TODO: Already mapping, do nothing? +} + +void pt_map(pd_t *pt, void *va, uint64 size, void *pa, uint64 flag) +{ + if ((uint64)va & (PAGE_SIZE - 1)) { + return; + } + + if ((uint64)pa & (PAGE_SIZE - 1)) { + return; + } + + size = ALIGN(size, PAGE_SIZE); + + for (uint64 i = 0; i < size; i += PAGE_SIZE) { + _pt_map(pt, (void *)((uint64)va + i), (void *)((uint64)pa + i), flag); + } +} + +vm_area_meta_t *vma_meta_create(void) +{ + vm_area_meta_t *vma_meta; + + vma_meta = kmalloc(sizeof(vm_area_meta_t)); + INIT_LIST_HEAD(&vma_meta->vma); + + return vma_meta; +} + +void vma_meta_free(vm_area_meta_t *vma_meta, pd_t *page_table) +{ + uint64 old_page_table; + vm_area_t *vma, *safe; + + old_page_table = get_page_table(); + set_page_table(page_table); + + preempt_disable(); + + list_for_each_entry_safe(vma, safe, &vma_meta->vma, list) { + vma_free(vma); + } + + preempt_enable(); + + kfree(vma_meta); + + set_page_table(old_page_table); +} + +void vma_meta_copy(vm_area_meta_t *to, vm_area_meta_t *from, pd_t *page_table) +{ + uint64 old_page_table; + vm_area_t *vma, *new_vma; + + old_page_table = get_page_table(); + set_page_table(page_table); + + preempt_disable(); + + list_for_each_entry(vma, &from->vma, list) { + new_vma = vma_clone(vma, (pd_t *)old_page_table); + + list_add_tail(&new_vma->list, &to->vma); + } + + preempt_enable(); + + set_page_table(old_page_table); +} + +void vma_map(vm_area_meta_t *vma_meta, void *va, uint64 size, + uint64 flag, void *addr) +{ + vm_area_t *vma; + int cnt = 0; + + if (flag & VMA_PA) cnt++; + if (flag & VMA_KVA) cnt++; + if (flag & VMA_ANON) cnt++; + + if (cnt != 1) { + return; + } + + if ((uint64)va & (PAGE_SIZE - 1)) { + return; + } + + vma = vma_find(vma_meta, (uint64)va); + if (vma) { + return; + } + + vma = vma_find(vma_meta, (uint64)va + size - 1); + if (vma) { + return; + } + + vma = vma_create(va, size, flag, addr); + + list_add_tail(&vma->list, &vma_meta->vma); +} + +static void do_page_fault(esr_el1_t *esr) +{ + uint64 far; + uint64 va; + uint64 fault_perm; + vm_area_t *vma; + // fault address register + far = read_sysreg(FAR_EL1); + + vma = vma_find(current->address_space, far); + + if (!vma) { + segmentation_fault(); + // Never reach + } + + // Check permission + if (esr->ec == EC_IA_LE) { + // Execute abort + fault_perm = VMA_X; + } else if (ISS_WnR(esr)) { + // Write abort + fault_perm = VMA_W; + } else { + // Read abort + fault_perm = VMA_R; + } + + if (!(vma->flag & fault_perm)) { + goto PAGE_FAULT_INVALID; + } + + va = far & ~(PAGE_SIZE - 1); + + if (vma->kva) { + uint64 offset; + + offset = va - vma->va_begin; + + pt_map(current->page_table, (void *)va, PAGE_SIZE, + (void *)VA2PA(vma->kva + offset), vma->flag); + } else if (vma->flag & VMA_ANON) { + void *kva = kmalloc(PAGE_SIZE); + + memzero(kva, PAGE_SIZE); + + pt_map(current->page_table, (void *)va, PAGE_SIZE, + (void *)VA2PA(kva), vma->flag); + } else { + // Unexpected result + goto PAGE_FAULT_INVALID; + } + + return; + +PAGE_FAULT_INVALID: + segmentation_fault(); + + // Never reach +} + +void mem_abort(esr_el1_t *esr) +{ + int fsc; +#ifdef DEMANDING_PAGE_DEBUG + uint64 addr; + + addr = read_sysreg(FAR_EL1); +#endif + + fsc = ISS_FSC(esr); + + switch (fsc) { + case FSC_TF_L0: + case FSC_TF_L1: + case FSC_TF_L2: + case FSC_TF_L3: +#ifdef DEMANDING_PAGE_DEBUG + uart_sync_printf("[Translation fault]: 0x%llx\r\n", addr); +#endif + do_page_fault(esr); + break; + default: + segmentation_fault(); + + // Never reach + } +} + +void syscall_mmap(trapframe *frame, void *addr, size_t len, int prot, + int flags, int fd, int file_offset) +{ + vm_area_t *vma; + int mapflag; + + // do some initial work + len = ALIGN(len, PAGE_SIZE); + + if (addr == NULL) { + addr = (void *)0x550000000000; + } + + while (1) { + if ((uint64)addr > 0x0000ffffffffffff) { + frame->x0 = 0; + return; + } + + vma = vma_find(current->address_space, (uint64)addr); + if (vma) { + addr = (void *)((uint64)addr + 0x10000000); + continue; + } + + vma = vma_find(current->address_space, (uint64)addr + len - 1); + if (vma) { + addr = (void *)((uint64)addr + 0x10000000); + continue; + } + + break; + } + + mapflag = 0; + + if (prot & PROT_READ) mapflag |= VMA_R; + if (prot & PROT_WRITE) mapflag |= VMA_W; + if (prot & PROT_EXEC) mapflag |= VMA_X; + + if (flags & MAP_POPULATE) { + void *kva; + + mapflag |= VMA_KVA; + + kva = kmalloc(len); + memzero(kva, len); + + vma_map(current->address_space, addr, len, mapflag, kva); + + pt_map(current->page_table, addr, len, (void *)VA2PA(kva), mapflag); + } else if (flags & MAP_ANONYMOUS) { + mapflag |= VMA_ANON; + + vma_map(current->address_space, addr, len, mapflag, NULL); + } else { + // Unexpected. + frame->x0 = 0; + return; + } + + frame->x0 = (uint64)addr; +} \ No newline at end of file diff --git a/src/lib/panic.c b/src/lib/panic.c new file mode 100644 index 000000000..a4298a845 --- /dev/null +++ b/src/lib/panic.c @@ -0,0 +1,18 @@ +#include +#include + +void panic(const char* fmt, ...){ + va_list args; + va_start(args, fmt); + + uart_sync_printf("\r\n[Kernel Panic] \r\n"); + uart_sync_vprintf(fmt, args); + + va_end(args); + uart_sync_printf("\r\n"); + + // TODO: Show more information + + // Never return + while(1){} +} \ No newline at end of file diff --git a/src/lib/reboot.c b/src/lib/reboot.c index edb02b67d..92d7d3790 100644 --- a/src/lib/reboot.c +++ b/src/lib/reboot.c @@ -1,4 +1,5 @@ #include +#include void set(long addr, unsigned int value) { volatile unsigned int *point = (unsigned int*)addr; @@ -6,11 +7,14 @@ void set(long addr, unsigned int value) { } void reset(int tick) { // reboot after watchdog timer expire - set(PM_RSTC, PM_PASSWORD | 0x20); // full reset - set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + set(PA2VA(PM_RSTC), PM_PASSWORD | 0x20); // full reset + set(PA2VA(PM_WDOG), PM_PASSWORD | tick); // number of watchdog tick + + // Never return + while(1) {} } void cancel_reset() { - set(PM_RSTC, PM_PASSWORD | 0); // full reset - set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick + set(PA2VA(PM_RSTC), PM_PASSWORD | 0); // full reset + set(PA2VA(PM_WDOG), PM_PASSWORD | 0); // number of watchdog tick } \ No newline at end of file diff --git a/src/lib/sched.S b/src/lib/sched.S index 0fd3da883..17572a71d 100644 --- a/src/lib/sched.S +++ b/src/lib/sched.S @@ -21,4 +21,13 @@ switch_to: // set_current msr tpidr_el1, x1 + // Switch page table 0 + ldr x9, [x1, 8*13] + and x9, x9, #0x0000ffffffffffff + dsb ish // ensure write has completed + msr ttbr0_el1, x9 // switch translation based address + tlbi vmalle1is // invalidate all TLB entries + dsb ish // ensure completion of TLB invalidatation + isb // clear pipeline + ret diff --git a/src/lib/sdhost.c b/src/lib/sdhost.c new file mode 100644 index 000000000..7ee4bb116 --- /dev/null +++ b/src/lib/sdhost.c @@ -0,0 +1,164 @@ +#include +#include +#include +static int is_hcs; // high capcacity(SDHC) + +static void pin_setup() { + put32(PA2VA(GPFSEL4), 0x24000000); + put32(PA2VA(GPFSEL5), 0x924); + put32(PA2VA(GPPUD), 0); + delay(15000); + put32(PA2VA(GPPUDCLK1), 0xffffffff); + delay(15000); + put32(PA2VA(GPPUDCLK1), 0); +} + +static void sdhost_setup() { + unsigned int tmp; + put32(SDHOST_PWR, 0); + put32(SDHOST_CMD, 0); + put32(SDHOST_ARG, 0); + put32(SDHOST_TOUT, SDHOST_TOUT_DEFAULT); + put32(SDHOST_CDIV, 0); + put32(SDHOST_HSTS, SDHOST_HSTS_MASK); + put32(SDHOST_CFG, 0); + put32(SDHOST_CNT, 0); + put32(SDHOST_SIZE, 0); + tmp = get32(SDHOST_DBG); + tmp &= ~SDHOST_DBG_MASK; + tmp |= SDHOST_DBG_FIFO; + put32(SDHOST_DBG, tmp); + delay(250000); + put32(SDHOST_PWR, 1); + delay(250000); + put32(SDHOST_CFG, SDHOST_CFG_SLOW | SDHOST_CFG_INTBUS | SDHOST_CFG_DATA_EN); + put32(SDHOST_CDIV, SDHOST_CDIV_DEFAULT); +} + +static int wait_sd(void){ + int cnt = 1000000; + unsigned int cmd; + do{ + if(cnt == 0) + return -1; + cmd = get32(SDHOST_CMD); + --cnt; + }while(cmd & SDHOST_NEW_CMD); + return 0; +} + +static int sd_cmd(unsigned cmd, unsigned int arg){ + put32(SDHOST_ARG, arg); + put32(SDHOST_CMD, cmd | SDHOST_NEW_CMD); + return wait_sd(); +} + +static int sdcard_setup() { + unsigned int tmp; + sd_cmd(GO_IDLE_STATE | SDHOST_NO_REPONSE, 0); + sd_cmd(SEND_IF_COND, VOLTAGE_CHECK_PATTERN); + tmp = get32(SDHOST_RESP0); + if (tmp != VOLTAGE_CHECK_PATTERN) { + return -1; + } + while (1){ + if (sd_cmd(APP_CMD, 0) == -1) { + // MMC card or invalid card status + // currently not support + continue; + } + sd_cmd(SD_APP_OP_COND, SDCARD_3_3V | SDCARD_ISHCS); + tmp = get32(SDHOST_RESP0); + if (tmp & SDCARD_READY) { + break; + } + delay(1000000); + } + + is_hcs = tmp & SDCARD_ISHCS; + sd_cmd(ALL_SEND_CID | SDHOST_LONG_RESPONSE, 0); + sd_cmd(SEND_RELATIVE_ADDR, 0); + tmp = get32(SDHOST_RESP0); + sd_cmd(SELECT_CARD, tmp); + sd_cmd(SET_BLOCKLEN, BLOCK_SIZE); + return 0; +} + +static int wait_fifo() { + int cnt = 1000000; + unsigned int hsts; + do { + if (cnt == 0) { + return -1; + } + hsts = get32(SDHOST_HSTS); + --cnt; + } while ((hsts & SDHOST_HSTS_DATA) == 0); + return 0; +} + +static void set_block(int size, int cnt) { + put32(SDHOST_SIZE, size); + put32(SDHOST_CNT, cnt); +} + +static void wait_finish() { + unsigned int dbg; + do { + dbg = get32(SDHOST_DBG); + } while ((dbg & SDHOST_DBG_FSM_MASK) != SDHOST_HSTS_DATA); +} + +void sd_init(void){ + pin_setup(); + sdhost_setup(); + sdcard_setup(); +} + +void sd_readblock(int block_idx, void *buf){ + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(BLOCK_SIZE, 1); + sd_cmd(READ_SINGLE_BLOCK | SDHOST_READ, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + buf_u[i] = get32(SDHOST_DATA); + } + unsigned int hsts = get32(SDHOST_HSTS); + if (hsts & SDHOST_HSTS_ERR_MASK) { + put32(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void sd_writeblock(int block_idx, const void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(BLOCK_SIZE, 1); + sd_cmd(WRITE_SINGLE_BLOCK | SDHOST_WRITE, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + put32(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts = get32(SDHOST_HSTS); + if (hsts & SDHOST_HSTS_ERR_MASK) { + put32(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} \ No newline at end of file diff --git a/src/lib/signal.c b/src/lib/signal.c index 6267da1ac..5be9546ad 100644 --- a/src/lib/signal.c +++ b/src/lib/signal.c @@ -5,8 +5,7 @@ #include #include #include - -#define DATA_OFF(x) ((uint64)current->data - (uint64)x) +#include #define SIG_DFL (sighandler_t)0 #define SIG_IGN (sighandler_t)1 @@ -21,9 +20,10 @@ static void sig_ignore(int _){ return; } +void sig_return(void) SECTION_TUS; void sig_return(void){ asm volatile( - "mov x8, 11\n" + "mov x8, 20\n" "svc 0\n" ); } @@ -100,7 +100,8 @@ void handle_signal(trapframe *frame){ frame->sp_el0 = user_sp; frame->x0 = signal->signum; frame->elr_el1 = sigaction->sighand; - frame->x30 = (uint64)sig_return; + // TODO: Map sigreturn to user address space and allow user to execute + frame->x30 = TUS2VA(sig_return); } signal_del(signal); @@ -133,26 +134,18 @@ void sighand_reset(struct sighand_t *sighand) sighand->sigactions[SIGKILL].sighand = sig_terminate; } -static inline void kernel_sighand_copy(struct sigaction_t *from, struct sigaction_t *to){ - to->kernel_hand = 1; +static inline void _sighand_copy(struct sigaction_t *to, struct sigaction_t *from){ + to->kernel_hand = from->kernel_hand; to->sighand = from->sighand; } -static inline void user_sighand_copy(struct sigaction_t *from, struct sigaction_t *to, uint64 offset){ - to->kernel_hand = 0; - to->sighand = (sighandler_t)((char *)from->sighand - offset); -} - -void sighand_copy(struct sighand_t *sighand, void *addrbase) +/* Copy current signal handler to @sighand*/ +void sighand_copy(struct sighand_t *sighand) { struct sighand_t *currhand; currhand = current->sighand; for (int i = 1; i < MAX_SIG_NUM; ++i) { - if (currhand->sigactions[i].kernel_hand) { - kernel_sighand_copy(&currhand->sigactions[i], &sighand->sigactions[i]); - } else { - user_sighand_copy(&currhand->sigactions[i], &sighand->sigactions[i], DATA_OFF(addrbase)); - } + _sighand_copy(&sighand->sigactions[i], &currhand->sigactions[i]); } } diff --git a/src/lib/string.c b/src/lib/string.c index 0d5a0405c..6199ff50d 100644 --- a/src/lib/string.c +++ b/src/lib/string.c @@ -9,6 +9,34 @@ int strcmp(const char *X,const char *Y){ return *(const unsigned char*)X - *(const unsigned char*)Y; } +int strcasecmp(const char *X, const char *Y) +{ + char c1, c2; + + while (1) { + c1 = *X++; + c2 = *Y++; + + if (!c1 || !c2) { + break; + } + + if ('A' <= c1 && c1 <= 'Z') { + c1 |= 0x20; + } + + if ('A' <= c2 && c2 <= 'Z') { + c2 |= 0x20; + } + + if (c1 != c2) { + break; + } + } + + return c1 - c2; +} + int strncmp(const char *X, const char *Y, int n){ while(n && *X && (*X == *Y)){ X++; @@ -26,6 +54,52 @@ int strlen(const char *str){ return ret; } +int strcpy(char *dst, const char *src) +{ + int ret = 0; + + while (*src) { + *dst = *src; + dst++; + src++; + ret++; + } + + *dst = '\0'; + + return ret; +} + +char *strcat(char *dest, const char *src){ + char *t; + t = dest; + while(*t){ + t++; + } + while(*src){ + *t = *src; + t++; + src++; + } + *t = '\0'; + return dest; +} + +char *strncat(char *dest, const char *src, int n){ + char *t; + t = dest; + while(*t) + t++; + while(n > 0 && *src){ + *t = *src; + t++; + src++; + n--; + } + *t = '\0'; + return dest; +} + int atoi(const char *str){ int i = 0 , j = 0; while(*str){ diff --git a/src/lib/syscall.c b/src/lib/syscall.c index 4003568c8..2b2dc1488 100644 --- a/src/lib/syscall.c +++ b/src/lib/syscall.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include syscall_funcp syscall_table[] = { (syscall_funcp) syscall_getpid, // 0 @@ -23,8 +25,19 @@ syscall_funcp syscall_table[] = { (syscall_funcp) syscall_kill_pid, // 7 (syscall_funcp) syscall_signal, // 8 (syscall_funcp) syscall_kill, // 9 - (syscall_funcp) syscall_test, // 10 - (syscall_funcp) syscall_sigreturn, // 11 + (syscall_funcp) syscall_mmap, // 10 + (syscall_funcp) syscall_open, // 11 + (syscall_funcp) syscall_close, // 12 + (syscall_funcp) syscall_write, // 13 + (syscall_funcp) syscall_read, // 14 + (syscall_funcp) syscall_mkdir, // 15 + (syscall_funcp) syscall_mount, // 16 + (syscall_funcp) syscall_chdir, // 17 + (syscall_funcp) syscall_lseek64, // 18 + (syscall_funcp) syscall_ioctl, // 19 + (syscall_funcp) syscall_sync, // 20 + (syscall_funcp) syscall_sigreturn, // 21 + (syscall_funcp) syscall_test, // 22 }; static inline void copy_regs(struct pt_regs *regs) @@ -41,16 +54,14 @@ static inline void copy_regs(struct pt_regs *regs) regs->x28 = current->regs.x28; } -void syscall_handler(trapframe regs, uint32 syn) +void syscall_handler(trapframe *regs) { - esr_el1 *esr = (esr_el1 *)&syn; uint64 syscall_num; - // SVC instruction execution - if(esr->ec != 0x15) - return; + syscall_num = regs->x8; - syscall_num = regs.x8; + // if(syscall_num > 2) + // uart_sync_printf("syscall number:%d\n", syscall_num); if (syscall_num >= ARRAY_SIZE(syscall_table)) { // Invalid syscall @@ -60,13 +71,13 @@ void syscall_handler(trapframe regs, uint32 syn) enable_interrupt(); // TODO: bring the arguments to syscall (syscall_table[syscall_num])( - ®s, - regs.x0, - regs.x1, - regs.x2, - regs.x3, - regs.x4, - regs.x5 + regs, + regs->x0, + regs->x1, + regs->x2, + regs->x3, + regs->x4, + regs->x5 ); disable_interrupt(); } @@ -85,27 +96,40 @@ void syscall_uart_write(trapframe *_, const char buf[], size_t size){ } void syscall_exec(trapframe *_, const char* name, char *const argv[]){ + struct file f; void *data; char *kernel_sp; - char *user_sp; - uint32 datalen; - - datalen = cpio_load_prog((char *)_initramfs_addr, name, (char **)&data); + int datalen, adj_datalen, ret; - if(datalen == 0) + ret = vfs_open(name, 0, &f); + if(ret < 0) return; - - kfree(current->data); - current->data = data; - current->datalen = datalen; - + datalen = f.vnode->v_ops->getsize(f.vnode); + if(datalen < 0) + return; + adj_datalen = ALIGN(datalen, PAGE_SIZE); + data = kmalloc(adj_datalen); + memzero(data, adj_datalen); + ret = vfs_read(&f, data, datalen); + if(ret < 0){ + kfree(data); + return; + } + vfs_close(&f); kernel_sp = (char *)current->kernel_stack + STACK_SIZE - 0x10; - user_sp = (char *)current->user_stack + STACK_SIZE - 0x10; // Reset signal signal_head_reset(current->signal); sighand_reset(current->sighand); - exec_user_prog(current->data, user_sp, kernel_sp); + //Rest addr space & page table + task_reset_mm(current); + task_init_map(current); + + // 0x000000000000 ~ : rwx: Code + vma_map(current->address_space, (void *)0, adj_datalen, VMA_R | VMA_W | VMA_X | VMA_KVA, data); + + set_page_table(current->page_table); + exec_user_prog((void *)0, (char *)0xffffffffeff0, kernel_sp); } void syscall_fork(trapframe *frame){ @@ -115,16 +139,15 @@ void syscall_fork(trapframe *frame){ child = task_create(); child->kernel_stack = kmalloc(STACK_SIZE); - child->user_stack = kmalloc(STACK_SIZE); - child->data = kmalloc(current->datalen); - child->datalen = current->datalen; memncpy(child->kernel_stack, current->kernel_stack, STACK_SIZE); - memncpy(child->user_stack, current->user_stack, STACK_SIZE); - memncpy(child->data, current->data, current->datalen); + + // TODO: Implement copy on write + + vma_meta_copy(child->address_space, current->address_space, current->page_table); // Copy the signal handler - sighand_copy(child->sighand, child->data); + sighand_copy(child->sighand); // Save regs SAVE_REGS(current); @@ -142,14 +165,15 @@ void syscall_fork(trapframe *frame){ // Adjust child trapframe child_frame = KSTACK_VARIABLE(frame); + // return value of fork for child process is 0 child_frame->x0 = 0; - child_frame->x30 = (uint64)DATA_VARIABLE(frame->x30); - child_frame->sp_el0 = USTACK_VARIABLE(frame->sp_el0); - child_frame->elr_el1 = DATA_VARIABLE(frame->elr_el1); + // child_frame->x30 = (uint64)DATA_VARIABLE(frame->x30); + // child_frame->sp_el0 = USTACK_VARIABLE(frame->sp_el0); + // child_frame->elr_el1 = DATA_VARIABLE(frame->elr_el1); sched_add_task(child); - // Set return value + // Set return value of parent process frame->x0 = child->tid; SYSCALL_FORK_END: @@ -165,7 +189,15 @@ void syscall_exit(trapframe *_) void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox) { - mbox_call(ch, mbox); + // copy data to kernel since mbox can't access the user space memory + int mbox_size = (int)mbox[0]; + if(mbox_size <= 0) + return; + char *kmbox = kmalloc(mbox_size); + memncpy(kmbox, (char *)mbox, mbox_size); + mbox_call(ch, (unsigned int*)kmbox); + memncpy((char *)mbox, kmbox, mbox_size); + kfree(kmbox); } void syscall_kill_pid(trapframe *_, int pid) diff --git a/src/lib/task.c b/src/lib/task.c index 334f66d72..9e3583145 100644 --- a/src/lib/task.c +++ b/src/lib/task.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include static struct list_head task_queue; @@ -23,14 +25,18 @@ task_struct *task_create(void){ task_struct *task; struct signal_head_t *signal; struct sighand_t *sighand; + pd_t *page_table; + vm_area_meta_t *as; task = kmalloc(sizeof(task_struct)); signal = signal_head_create(); sighand = sighand_create(); + page_table = pt_create(); + as = vma_meta_create(); task->kernel_stack = NULL; - task->user_stack = NULL; - task->data = NULL; + task->address_space = as; + task->page_table = page_table; INIT_LIST_HEAD(&task->list); list_add_tail(&task->task_list, &task_queue); task->status = TASK_NEW; @@ -41,27 +47,58 @@ task_struct *task_create(void){ task->signal = signal; task->sighand = sighand; + task->work_dir = rootmount->root; + + vfs_open("/dev/uart", 0, &task->fds[0]); + vfs_open("/dev/uart", 0, &task->fds[1]); + vfs_open("/dev/uart", 0, &task->fds[2]); + + task->maxfd = 2; + return task; } void task_free(task_struct *task){ if(task->kernel_stack) kfree(task->kernel_stack); - - if (task->user_stack) - kfree(task->user_stack); - - if (task->data) - kfree(task->data); list_del(&task->task_list); signal_head_free(task->signal); sighand_free(task->sighand); + vma_meta_free(task->address_space, task->page_table); + pt_free(task->page_table); + + for(int i = 0 ; i <= task->maxfd ;++i){ + if(task->fds[i].vnode != NULL){ + vfs_close(&task->fds[i]); + } + } + kfree(task); } +void task_init_map(task_struct *task){ + // TODO: map the return addres of mailbox_call + vma_map(task->address_space, (void *)0x3c000000, 0x03000000, + VMA_R | VMA_W | VMA_PA, (void *)0x3c000000); + + vma_map(task->address_space, (void *)0x7f0000000000, TEXT_USER_SHARED_LEN, + VMA_R | VMA_X | VMA_PA, (void *)VA2PA(TEXT_USER_SHARED_BASE)); + + vma_map(task->address_space, (void *)0xffffffffb000, STACK_SIZE, + VMA_R | VMA_W | VMA_ANON, NULL); +} + +void task_reset_mm(task_struct *task){ + vma_meta_free(task->address_space, task->page_table); + pt_free(task->page_table); + + task->page_table = pt_create(); + task->address_space = vma_meta_create(); +} + task_struct *task_get_by_tid(uint32 tid){ task_struct *task; diff --git a/src/lib/timer.c b/src/lib/timer.c index 418c76472..06b70f016 100644 --- a/src/lib/timer.c +++ b/src/lib/timer.c @@ -20,12 +20,12 @@ int timer_show_enable; static void timer_enable(){ // Enable core0 cntp timer - put32(CORE0_TIMER_IRQ_CTRL,2); + put32(PA2VA(CORE0_TIMER_IRQ_CTRL),2); } static void timer_disable(){ // Disable core0 cntp timer - put32(CORE0_TIMER_IRQ_CTRL,0); + put32(PA2VA(CORE0_TIMER_IRQ_CTRL),0); } static void timer_set_boot_cnt(){ @@ -143,7 +143,7 @@ static void add_timer(timer_node *tn){ } } int timer_irq_add(){ - uint32 core0_irq_src = get32(CORE0_IRQ_SOURCE); + uint32 core0_irq_src = get32(PA2VA(CORE0_IRQ_SOURCE)); if (!(core0_irq_src & 0x02)) { return 0; diff --git a/src/lib/tmpfs.c b/src/lib/tmpfs.c new file mode 100644 index 000000000..4d2c1a8ba --- /dev/null +++ b/src/lib/tmpfs.c @@ -0,0 +1,292 @@ +#include +#include +#include + +static struct filesystem tmpfs = { + .name = "tmpfs", + .mount = tmpfs_mount, + .alloc_vnode = tmpfs_alloc_vnode, + .sync = tmpfs_sync +}; + +static struct vnode_operations tmpfs_v_ops = { + .lookup = tmpfs_lookup, + .create = tmpfs_create, + .mkdir = tmpfs_mkdir, + .isdir = tmpfs_isdir, + .getname = tmpfs_getname, + .getsize = tmpfs_getsize +}; + +static struct file_operations tmpfs_f_ops = { + .write = tmpfs_write, + .read = tmpfs_read, + .open = tmpfs_open, + .close = tmpfs_close, + .lseek64 = tmpfs_lseek64, + .ioctl = tmpfs_ioctl +}; + +int tmpfs_mount(struct filesystem *fs, struct mount *mount){ + struct vnode *node, *oldnode; + struct tmpfs_internal *internal; + struct tmpfs_dir_t *dir; + const char *name; + + oldnode = mount->root; + oldnode->v_ops->getname(oldnode, &name); + if(strlen(name) >= TMPFS_NAME_MAXLEN) + return -1; + + node = kmalloc(sizeof(struct vnode)); + internal = kmalloc(sizeof(struct tmpfs_internal)); + dir = kmalloc(sizeof(struct tmpfs_dir_t)); + + dir->size = 0; + node->mount = oldnode->mount; + node->v_ops = oldnode->v_ops; + node->f_ops = oldnode->f_ops; + node->internal =oldnode->internal; + + strcpy(internal->name, name); + internal->type = TMPFS_TYPE_DIR; + internal->dir = dir; + internal->oldnode = node; + + oldnode->mount = mount; + oldnode->v_ops = &tmpfs_v_ops; + oldnode->f_ops = &tmpfs_f_ops; + oldnode->internal = internal; + + return 0; +} +int tmpfs_alloc_vnode(struct filesystem *fs, struct vnode **target){ + struct vnode *node; + struct tmpfs_internal *internal; + struct tmpfs_dir_t *dir; + node = kmalloc(sizeof(struct vnode)); + internal = kmalloc(sizeof(struct tmpfs_internal)); + dir = kmalloc(sizeof(struct tmpfs_dir_t)); + + dir->size = 0; + + internal->name[0] = '\0'; + internal->type = TMPFS_TYPE_DIR; + internal->dir = dir; + internal->oldnode = NULL; + + node->mount = NULL; + node->v_ops = &tmpfs_v_ops; + node->f_ops = &tmpfs_f_ops; + node->internal = internal; + *target = node; + + return 0; +} +int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name){ + struct tmpfs_internal *internal; + struct tmpfs_dir_t *dir; + int i; + + internal = dir_node->internal; + if(internal->type != TMPFS_TYPE_DIR) + return -1; + + dir = internal->dir; + for(i = 0; i < dir->size ;++i){ + struct vnode *node; + const char *name; + int ret; + node = dir->entries[i]; + ret = node->v_ops->getname(node, &name); + if(ret < 0) + continue; + if(!strcmp(name, component_name)) + break; + } + + if(i >= dir->size) + return -1; + *target = dir->entries[i]; + return 0; +} +int tmpfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name){ + struct tmpfs_internal *internal, *newint; + struct tmpfs_file_t *file; + struct tmpfs_dir_t *dir; + struct vnode *node; + int ret; + if(strlen(component_name) >= 0x10) + return -1; + internal = dir_node->internal; + if(internal->type != TMPFS_TYPE_DIR) + return -1; + dir = internal->dir; + if(dir->size >= TMPFS_DIR_MAXSIZE) + return -1; + ret = tmpfs_lookup(dir_node, &node, component_name); + if(!ret) + return -1; + node = kmalloc(sizeof(struct vnode)); + newint = kmalloc(sizeof(struct tmpfs_internal)); + file = kmalloc(sizeof(struct tmpfs_file_t)); + + file->data = kmalloc(TMPFS_FILE_MAXSIZE); + file->size = 0; + file->capacity = TMPFS_FILE_MAXSIZE; + + strcpy(newint->name, component_name); + newint->type = TMPFS_TYPE_FILE; + newint->file = file; + newint->oldnode = NULL; + + node->mount = dir_node->mount; + node->v_ops = &tmpfs_v_ops; + node->f_ops = &tmpfs_f_ops; + node->parent = dir_node; + node->internal = newint; + + dir->entries[dir->size] = node; + dir->size++; + *target = node; + return 0; +} +int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name){ + struct tmpfs_internal *internal, *newint; + struct tmpfs_dir_t *dir, *newdir; + struct vnode *node; + int ret; + if(strlen(component_name) >= 0x10) + return -1; + internal = dir_node->internal; + if(internal->type != TMPFS_TYPE_DIR) + return -1; + + dir = internal->dir; + if(dir->size >= TMPFS_DIR_MAXSIZE) + return -1; + ret = tmpfs_lookup(dir_node, &node, component_name); + if(!ret) + return -1; + node = kmalloc(sizeof(struct vnode)); + newint = kmalloc(sizeof(struct tmpfs_internal)); + newdir = kmalloc(sizeof(struct tmpfs_dir_t)); + + newdir->size = 0; + strcpy(newint->name, component_name); + newint->type = TMPFS_TYPE_DIR; + newint->dir = newdir; + newint->oldnode = NULL; + + node->mount = dir_node->mount; + node->v_ops = &tmpfs_v_ops; + node->f_ops = &tmpfs_f_ops; + node->parent = dir_node; + node->internal = newint; + + dir->entries[dir->size] = node; + dir->size++; + + *target = node; + return 0; +} +int tmpfs_isdir(struct vnode *dir_node){ + struct tmpfs_internal *internal = dir_node->internal; + if(internal->type != TMPFS_TYPE_DIR) + return 0; + return 1; +} +int tmpfs_getname(struct vnode *dir_node, const char **name){ + struct tmpfs_internal *internal = dir_node->internal; + *name = internal->name; + return 0; +} +int tmpfs_getsize(struct vnode *dir_node){ + struct tmpfs_internal *internal = dir_node->internal; + if(internal->type != TMPFS_TYPE_FILE) + return -1; + return internal->file->size; +} +int tmpfs_write(struct file *file, const void *buf, size_t len){ + struct tmpfs_internal *internal = file->vnode->internal; + struct tmpfs_file_t *f; + if(internal->type != TMPFS_TYPE_FILE) + return -1; + f = internal->file; + if(len > f->capacity - file->f_pos) + len = f->capacity - file->f_pos; + + if(!len) + return 0; + memncpy(&f->data[file->f_pos], buf, len); + file->f_pos += len; + if(file->f_pos > f->size) + f->size = file->f_pos; + + return len; +} +int tmpfs_read(struct file *file, void *buf, size_t len){ + struct tmpfs_internal *internal = file->vnode->internal; + struct tmpfs_file_t *f; + if(internal->type != TMPFS_TYPE_FILE) + return -1; + f = internal->file; + if(len > f->size - file->f_pos) + len = f->size - file->f_pos; + if(!len) + return 0; + memncpy(buf, &f->data[file->f_pos], len); + file->f_pos += len; + return len; +} +int tmpfs_open(struct vnode *file_node, struct file *target){ + // TODO: verify file access permission + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} +int tmpfs_close(struct file *file){ + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + return 0; +} +long tmpfs_lseek64(struct file *file, long offset, int whence){ + int filesize, base; + filesize = file->vnode->v_ops->getsize(file->vnode); + if(filesize < 0) + return -1; + switch(whence){ + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = file->f_pos; + break; + case SEEK_END: + base = filesize; + break; + default: + return -1; + } + + if(base + offset > filesize) + return -1; + file->f_pos = base + offset; + return 0; +} + +int tmpfs_ioctl(struct file *file, uint64 request, va_list args){ + return -1; +} + +int tmpfs_sync(struct filesystem *fs){ + return 0; +} + +struct filesystem *tmpfs_init(void){ + return &tmpfs; +} \ No newline at end of file diff --git a/src/lib/uartfs.c b/src/lib/uartfs.c new file mode 100644 index 000000000..26b3ab5df --- /dev/null +++ b/src/lib/uartfs.c @@ -0,0 +1,135 @@ +#include +#include +#include + +static struct filesystem uartfs = { + .name = "uartfs", + .mount = uartfs_mount, + .sync = uartfs_sync +}; + +static struct vnode_operations uartfs_v_ops = { + .lookup = uartfs_lookup, + .create = uartfs_create, + .mkdir = uartfs_mkdir, + .isdir = uartfs_isdir, + .getname = uartfs_getname, + .getsize = uartfs_getsize +}; + +static struct file_operations uartfs_f_ops = { + .write = uartfs_write, + .read = uartfs_read, + .open = uartfs_open, + .close = uartfs_close, + .lseek64 = uartfs_lseek64, + .ioctl = uartfs_ioctl +}; + +/* filesystem methods */ + +int uartfs_mount(struct filesystem *fs, struct mount *mount){ + struct vnode *oldnode; + struct uartfs_internal *internal; + const char *name; + + internal = kmalloc(sizeof(struct uartfs_internal)); + + oldnode = mount->root; + + oldnode->v_ops->getname(oldnode, &name); + + internal->name = name; + internal->oldnode.mount = oldnode->mount; + internal->oldnode.v_ops = oldnode->v_ops; + internal->oldnode.f_ops = oldnode->f_ops; + internal->oldnode.parent = oldnode->parent; + internal->oldnode.internal = oldnode->internal; + + oldnode->mount = mount; + oldnode->v_ops = &uartfs_v_ops; + oldnode->f_ops = &uartfs_f_ops; + oldnode->internal = internal; + + return 0; +} + +/* vnode_operations methods */ + +int uartfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name){ + return -1; +} + +int uartfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name){ + return -1; +} + +int uartfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name){ + return -1; +} + +int uartfs_isdir(struct vnode *dir_node){ + return 0; +} + +int uartfs_getname(struct vnode *dir_node, const char **name){ + struct uartfs_internal *internal; + + internal = dir_node->internal; + + *name = internal->name; + + return 0; +} + +int uartfs_getsize(struct vnode *dir_node){ + return -1; +} + +/* file_operations methods */ + +int uartfs_write(struct file *file, const void *buf, size_t len){ + uart_sendn(buf, len); + + return len; +} + +int uartfs_read(struct file *file, void *buf, size_t len){ + uart_recvn(buf, len); + + return len; +} + +int uartfs_open(struct vnode *file_node, struct file *target){ + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} + +int uartfs_close(struct file *file){ + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + return 0; +} + +long uartfs_lseek64(struct file *file, long offset, int whence){ + return -1; +} + +int uartfs_ioctl(struct file *file, uint64 request, va_list args){ + return -1; +} + +int uartfs_sync(struct filesystem *fs){ + return 0; +} + +/* Others */ + +struct filesystem *uartfs_init(void){ + return &uartfs; +} \ No newline at end of file diff --git a/src/lib/vfs.c b/src/lib/vfs.c new file mode 100644 index 000000000..01e66c839 --- /dev/null +++ b/src/lib/vfs.c @@ -0,0 +1,430 @@ +#include +#include +#include +#include +#include +#include +#include + +struct mount *rootmount; + +static struct list_head filesystems; + +static struct vnode *get_dir_vnode(struct vnode *dir_node, const char **pathname){ + struct vnode *result; + const char *start; + const char *end; + char buf[0x100]; + + start = end = *pathname; + + if(*start == '/') + result = rootmount->root; + else + result = dir_node; + + while(1){ + if(!strncmp("./", start, 2)){ + start += 2; + end = start; + continue; + } + else if(!strncmp("../", start, 3)){ + if(result->parent){ + result = result->parent; + } + + start += 3; + end = start; + continue; + } + while(*end != '\0' && *end != '/') + end++; + if(*end == '/'){ + int ret; + if(start == end){ + end++; + start = end; + continue; + } + + // TODO: Check if the length is less than 0x100 + memncpy(buf, start, end - start); + buf[end - start] = 0; + ret = result->v_ops->lookup(result, &result, buf); + if(ret < 0) + return NULL; + end++; + start = end; + } + else{ + break; + } + } + *pathname = *start ? start : NULL; + return result; +} + +static struct filesystem *find_filesystem(const char *filesystem){ + struct filesystem *fs; + list_for_each_entry(fs, &filesystems, fs_list){ + if(!strcmp(fs->name, filesystem)) + return fs; + } + return NULL; +} + +void vfs_init(void){ + INIT_LIST_HEAD(&filesystems); +} + +void vfs_init_rootmount(struct filesystem *fs){ + struct vnode *n; + int ret; + + ret = fs->alloc_vnode(fs, &n); + if(ret < 0) + panic("vfs_init_rootmount failed"); + + rootmount = kmalloc(sizeof(struct mount)); + rootmount->root = n; + rootmount->fs = fs; + n->mount = rootmount; + n->parent = NULL; +} + +int register_filesystem(struct filesystem *fs){ + list_add_tail(&fs->fs_list, &filesystems); + return 0; +} + +int vfs_sync(struct filesystem *fs){ + return fs->sync(fs); +} + +int vfs_open(const char *pathname, int flags, struct file *target){ + const char *curname; + struct vnode *dir_node; + struct vnode *file_node; + int ret; + curname = pathname; + dir_node = get_dir_vnode(current->work_dir, &curname); + if(!dir_node) + return -1; + if(!curname) + return -1; + ret = dir_node->v_ops->lookup(dir_node, &file_node, curname); + if(flags & O_CREATE){ + if(ret == 0) + return -1; + + ret = dir_node->v_ops->create(dir_node, &file_node, curname); + } + if(ret<0) + return ret; + if(!file_node) + return -1; + ret = file_node->f_ops->open(file_node, target); + if(ret < 0) + return ret; + target->flags = 0; + return 0; +} + +int vfs_close(struct file *file){ + return file->f_ops->close(file); +} + +int vfs_write(struct file *file, const void *buf, size_t len){ + return file->f_ops->write(file, buf, len); +} + +int vfs_read(struct file *file, void *buf, size_t len){ + return file->f_ops->read(file, buf, len); +} + +int vfs_mkdir(const char *pathname){ + const char *curname; + struct vnode *dir_node; + struct vnode *newdir_node; + int ret; + + curname = pathname; + + if (current) + dir_node = get_dir_vnode(current->work_dir, &curname); + else + dir_node = get_dir_vnode(rootmount->root, &curname); + + if(!dir_node) + return -1; + if(!curname) + return -1; + + ret = dir_node->v_ops->mkdir(dir_node, &newdir_node, curname); + return ret; +} + +int vfs_mount(const char *mountpath, const char *filesystem){ + const char *curname; + struct vnode *dir_node; + struct filesystem *fs; + struct mount *mo; + int ret; + + curname = mountpath; + if (current) + dir_node = get_dir_vnode(current->work_dir, &curname); + else + dir_node = get_dir_vnode(rootmount->root, &curname); + if(!dir_node) + return -1; + + if(curname){ + ret = dir_node->v_ops->lookup(dir_node, &dir_node, curname); + if(ret < 0) + return ret; + } + + if(!dir_node->v_ops->isdir(dir_node)) + return -1; + fs = find_filesystem(filesystem); + if(!fs) + return -1; + mo = kmalloc(sizeof(struct mount)); + mo->root = dir_node; + mo->fs = fs; + ret = fs->mount(fs, mo); + + if(ret < 0){ + kfree(mo); + return ret; + } + + return 0; +} + +int vfs_lookup(const char *pathname, struct vnode **target){ + const char *curname; + struct vnode *dir_node; + struct vnode *file_node; + int ret; + curname = pathname; + dir_node = get_dir_vnode(current->work_dir, &curname); + if(!dir_node) + return -1; + if(!curname){ + *target = dir_node; + return 0; + } + ret = dir_node->v_ops->lookup(dir_node, &file_node, curname); + if(ret < 0) + return ret; + *target = file_node; + return 0; +} + +long vfs_lseek64(struct file *file, long offset, int whence){ + return file->f_ops->lseek64(file, offset, whence); +} +int vfs_ioctl(struct file *file, uint64 request, va_list args){ + return file->f_ops->ioctl(file, request, args); +} + +static int do_open(const char *pathname, int flags){ + int i, ret; + for(i = 0 ; i <= current->maxfd ;++i){ + if(current->fds[i].vnode == NULL) + break; + } + if(i > current->maxfd){ + if(current->maxfd >= TASK_MAX_FD){ + return -1; + } + current->maxfd += 1; + i = current->maxfd; + } + ret = vfs_open(pathname, flags, ¤t->fds[i]); + if(ret < 0){ + current->fds[i].vnode = NULL; + return ret; + } + return i; +} + +static int do_close(int fd){ + int ret; + if(fd < 0 || current->maxfd < fd) + return -1; + if(current->fds[fd].vnode == NULL) + return -1; + ret = vfs_close(¤t->fds[fd]); + if(ret < 0) + return ret; + return 0; +} + +static int do_write(int fd, const void *buf, uint64 count){ + int ret; + if(fd < 0 || current->maxfd < fd) + return -1; + if(current->fds[fd].vnode == NULL) + return -1; + ret = vfs_write(¤t->fds[fd], buf, count); + return ret; +} + +static int do_read(int fd, void *buf, uint64 count){ + int ret; + if(fd < 0 || current->maxfd < fd) + return -1; + if(current->fds[fd].vnode == NULL) + return -1; + ret = vfs_read(¤t->fds[fd], buf, count); + return ret; +} + +static int do_mkdir(const char *pathname, uint32 mode){ + int ret; + ret = vfs_mkdir(pathname); + return ret; +} + +static int do_mount(const char *target, const char *filesystem){ + int ret; + ret = vfs_mount(target, filesystem); + return ret; +} + +static int do_chdir(const char *path){ + struct vnode *result; + int ret; + + ret = vfs_lookup(path, &result); + if(ret < 0) + return ret; + if(!result->v_ops->isdir(result)) + return -1; + current->work_dir = result; + return 0; +} + +static long do_lseek64(int fd, int64 offset, int whence){ + long ret; + if(fd < 0 || current->maxfd < fd) + return -1; + if(current->fds[fd].vnode == NULL) + return -1; + ret = vfs_lseek64(¤t->fds[fd], offset, whence); + return ret; +} + +static int do_ioctl(int fd, uint64 request, va_list args){ + int ret; + if(fd < 0 || current->maxfd < fd) + return -1; + if(current->fds[fd].vnode == NULL) + return -1; + ret = vfs_ioctl(¤t->fds[fd], request, args); + return ret; +} + +static int do_sync(void){ + struct filesystem *entry; + + list_for_each_entry(entry, &filesystems, fs_list) { + vfs_sync(entry); + } + + return 0; +} + +void syscall_open(trapframe *frame, const char *pathname, int flags) +{ + int fd = do_open(pathname, flags); + + frame->x0 = fd; + + uart_sync_printf("[open] (\"%s\", 0x%x) = %d\r\n", pathname, flags, fd); +} + +void syscall_close(trapframe *frame, int fd) +{ + int ret = do_close(fd); + + frame->x0 = ret; + + uart_sync_printf("[close] (%d) = %d\r\n", fd, ret); +} + +void syscall_write(trapframe *frame, int fd, const void *buf, uint64 count) +{ + int ret = do_write(fd, buf, count); + + frame->x0 = ret; + + uart_sync_printf("[write] (%d, \"%s\", 0x%x) = %d\r\n", fd, buf, count, ret); +} + +void syscall_read(trapframe *frame, int fd, void *buf, uint64 count) +{ + int ret = do_read(fd, buf, count); + + frame->x0 = ret; + + uart_sync_printf("[read] (%d, \"%s\", 0x%x) = %d\r\n", fd, buf, count, ret); +} + +void syscall_mkdir(trapframe *frame, const char *pathname, uint32 mode) +{ + int ret = do_mkdir(pathname, mode); + + frame->x0 = ret; +} + +void syscall_mount(trapframe *frame, const char *src, const char *target, + const char *filesystem, uint64 flags, const void *data) +{ + int ret = do_mount(target, filesystem); + + frame->x0 = ret; +} + +void syscall_chdir(trapframe *frame, const char *path) +{ + int ret = do_chdir(path); + + frame->x0 = ret; +} + +void syscall_lseek64(trapframe *frame, int fd, int64 offset, int whence) +{ + long ret = do_lseek64(fd, offset, whence); + + frame->x0 = ret; + + uart_sync_printf("[lseek64] (%d, 0x%x, 0x%x) = %d\r\n", fd, offset, whence, ret); +} + +void syscall_ioctl(trapframe *frame, int fd, uint64 request, ...) +{ + int ret; + va_list args; + + va_start(args, request); + + ret = do_ioctl(fd, request, args); + + va_end(args); + + frame->x0 = ret; +} + +void syscall_sync(trapframe *frame) +{ + int ret = do_sync(); + + frame->x0 = ret; + + uart_sync_printf("[sync] = %d\r\n", ret); +} \ No newline at end of file diff --git a/test/initramfs_lab5.cpio b/test/initramfs_lab5.cpio new file mode 100755 index 000000000..0676fb158 Binary files /dev/null and b/test/initramfs_lab5.cpio differ