diff --git a/Makefile b/Makefile index 477aa46b3..137516ee6 100755 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile ARMGNU ?= aarch64-linux-gnu -COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__DEBUG +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG #-D__DEBUG_MM #-D__DEBUG_MM_ALLOC #-D__DEBUG_MM_SCHED ASMOPS = -Iinclude BUILD_DIR = build @@ -36,7 +36,15 @@ run: qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio debug: - qemu-system-aarch64 -M raspi3 -kernel kernel8.img -initrd initramfs.cpio -serial null -display none -S -s + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -initrd initramfs.cpio -serial null -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw -display none -S -s run_cpio: - qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio \ No newline at end of file + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio + +# run with sd card (Lab7) +run_sd: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw + +# run with cpio and sd card +run_all: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw \ No newline at end of file diff --git a/README.md b/README.md index f0c06b9a2..941572b52 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# OSDI 2020 - LAB 06 Virtual File System +# OSDI 2021 - Lab 08 Virtual Memory ## Author @@ -7,30 +7,26 @@ | 0856167 | Yunyung | 許振揚| yungyung7654321@gmail.com | ### Introduction -A file system manages data in storage mediums. Each file system has a specific way to store and retrieve the data. Hence, a virtual file system(VFS) is common in general-purpose OS to provide a unified interface for all file systems. +Virtual memory provides isolated address spaces, so each user process can run in its address space without interfering with others. -In this lab, we’ll implement a memory-based file system(tmpfs) to get familiar with the concept of VFS. In the next lab, we’ll implement the FAT32 file system to access files from an SD card. It’s recommended to do both together. +In this lab, we need to initialize the memory management unit(MMU) and set up the address spaces for the kernel and user processes to achieve process isolation ### Goals of this lab -- Understand how to set up a root file system. +- Understand ARMv8-A virtual memory system architecture. -- Implement temporary file system (tmpfs) as root file system. +- Understand how to design multitasking with virtual memory. -- Understand how to create, open, close, read, and write files. +- Understand how to prevent invalid memory access. -- Implement VFS interface, including create, open, close, read, write, mkdir, chdir, ls , mount/unmount interface. +- Understand how the kernel manages memory for user processes. -- Implement multi-level VFS and absoute/relative pathname lookup. +- Implement simple mmap -- Understand how a user process access files through the virtual file system. +- Understand how demand paging works. -- Implement a user process to access files through VFS. +- Implement demand paging mechanism. -- Understand how to mount a file system and look up a file across file systems. - -- Implement mount/unmount a file system and look up a file across file systems. - -- Understand how to design the procfs. +- Understand how copy-on-write works. ## Directory structure ``` @@ -62,7 +58,12 @@ In this lab, we’ll implement a memory-based file system(tmpfs) to get familiar │ ├── wait.h │ ├── vfs.h │ ├── fs.h -│ └── tmpfs.h +│ ├── tmpfs.h +│ ├── mbr.h # header file of Master boot Record +│ ├── sdhost.h +│ ├── fat32.h +│ ├── base.h +│ └── mmu.h │ ├── src # source files │ ├── command.c # source file to process command @@ -76,6 +77,7 @@ In this lab, we’ll implement a memory-based file system(tmpfs) to get familiar │ ├── uart.c # source file to process uart interface and implement uart asynchronous read/write cooperate with shell in shell.c │ ├── mm.c # Implementation of buudy system and object allocator(slab) for memory allocation │ ├── mm.S +│ ├── utils.c │ ├── utils.S │ ├── entry.S │ ├── exception.c @@ -89,8 +91,14 @@ In this lab, we’ll implement a memory-based file system(tmpfs) to get familiar │ ├── sched.c │ ├── vfs.c │ ├── fs.c -│ └── tmpfs.c +│ ├── tmpfs.c +│ ├── sdhost.c # Implmentation of sd care device driver +│ └── fat32.c │ +├── sdcard # Files for sd card device (Lab7) +│ ├── sfn_nctuos.img # Flash Bootable Image for SD Card with FAT32 file system. FAT32 is Short Filenames(SFN) version. +│ └── ... # Other simple files to test Lab7 +│ ├── rootfs # files and user programs will be made as cpio archive │ └── ... # any file │ @@ -133,12 +141,13 @@ make clean ## Run on QEMU ``` -make run -``` - -## Run on QEMU with cpio -``` +# Run QEMU with initramfs.cpio and sd card +make run_all +# Run QEMU without initramfs.cpio make run_cpio +# Run QEMU without initramfs.cpio and sd card +make run + ``` ## How to interact with Rpi3 diff --git a/include/base.h b/include/base.h index 2532cf28c..5007dbd69 100644 --- a/include/base.h +++ b/include/base.h @@ -1,6 +1,9 @@ #ifndef _BASE_H #define _BASE_H -#define MMIO_BASE 0x3F000000 +#include "mm.h" + +#define DEVICE_BASE 0x3F000000 +#define MMIO_BASE (VA_START + DEVICE_BASE) #endif /*_P_BASE_H */ \ No newline at end of file diff --git a/include/cpio.h b/include/cpio.h index 9247e6b33..60c57eaa6 100755 --- a/include/cpio.h +++ b/include/cpio.h @@ -12,12 +12,14 @@ #ifndef _LIB_CPIO_H_ #define _LIB_CPIO_H_ +#include "base.h" + /* Magic identifiers for the "cpio" file format. */ #define CPIO_HEADER_MAGIC "070701" #define CPIO_FOOTER_MAGIC "TRAILER!!!" #define CPIO_ALIGNMENT 4 -#define INITRAMFS_ADDR 0x8000000 +#define INITRAMFS_ADDR (void *)0x8000000 + VA_START #ifndef NULL #define NULL ((void *)0) @@ -71,9 +73,9 @@ struct cpio_info { * * @param[in] archive The location of the CPIO archive * @param[out] filename ###The name of the file in question. - * @param[out] _filesize ###The name of the file in question. - * @param[out] data ###The name of the file in question. - * @param[out] next ####The name of the file in question. + * @param[out] filesize ###The filesize of the file in question. + * @param[out] data ###The data of the file in question. + * @param[out] next ####The next file in question. */ int cpio_parse_header(struct cpio_header *archive, const char **filename, unsigned long *_filesize, void **data, diff --git a/include/entry.h b/include/entry.h index 20e9b327e..a576d8b48 100644 --- a/include/entry.h +++ b/include/entry.h @@ -26,7 +26,8 @@ #define ERROR_INVALID_EL0_32 15 #define SYNC_ERROR 16 -#define SYSCALL_ERROR 17 +#define SYSCALL_ERROR 17 +#define DATA_ABORT_ERROR 18 #ifndef __ASSEMBLER__ extern void enable_irq_persist(); diff --git a/include/exception.h b/include/exception.h index fe403dac0..694f6579f 100644 --- a/include/exception.h +++ b/include/exception.h @@ -3,7 +3,7 @@ #include -#define CORE0_IRQ_SRC ((volatile unsigned int*)0x40000060) +#define CORE0_IRQ_SRC ((volatile unsigned int*)(MMIO_BASE+0x40000060)) // To identify IRQ interrupt source is from AUX // // GPU pending 1 register, see p.115 in BCM2835 ARM Peripherals docs #define IRQ_PENDING_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B204)) @@ -12,7 +12,7 @@ // See p.116 in BCM2835 ARM Peripherals docs #define ENABLE_IRQS_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B210)) // To Disable second level interrupt controller’s IRQs1(0x3f00b210)’s bit29. -#define DISABLE_IRQS_1 ((volatile unsigned int*)(PBASE+0x0000B21C)) +#define DISABLE_IRQS_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B21C)) // enable/disable/check pending miniUART interrupt bit 29 // See p.113 ARM peripherals interrupts table in BCM2835 docs #define AUX_IRQ (1 << 29) diff --git a/include/fat32.h b/include/fat32.h new file mode 100644 index 000000000..4460f06bc --- /dev/null +++ b/include/fat32.h @@ -0,0 +1,133 @@ +#ifndef _FAT32_H +#define _FAT32_H + +#include "types.h" +#include "vfs.h" +#include "printf.h" + +#define BLOCK_SIZE 512 +#define FAT32_ENTRY_SIZE 4 // FAT table entry size in bytes +#define FAT32_ENTRY_PER_BLOCK (BLOCK_SIZE / FAT32_ENTRY_SIZE) + +#define FAT32_DIRECTORY_ENTRY_SIZE 4 // Regular Directory Entry Size in bytes +#define FAT32_DIRECTORY_ENTRY_PER_BLOCK (BLOCK_SIZE / FAT32_DIRECTORY_ENTRY_SIZE) + +#define DIRECTORY_ENTRY_ATTR_DIRECTORY 0x10 + +#define INVALID_CLUSTER_INDEX 0 // 0 and 1 is not a valid value, We also use it as a error code here. +#define FAT32_ERROR -1 + +// end-of-cluster-chain marker (typically 0x0FFFFFFF or 0x0FFFFFF8 on FAT32) +// For spec, EOC can be 0x?FFFFFF8 -0x?FFFFFFF. In our lab, EOC is 0x0FFFFFFF +#define EOC_FILTER 0x0FFFFFFF + +struct fat32_boot_sector +{ + uint8_t bootjmp[3]; // 0x0 + uint8_t oem_name[8]; // 0x3 + + // BIOS Parameter Block + uint16_t bytes_per_logical_sector; // 0xB-0xC + uint8_t sector_per_cluster; // 0xD + uint16_t nr_reserved_sectors; // 0xE-0xF + uint8_t nr_fat_table; // 0x10 + uint16_t nr_max_root_dir_entries_16; // 0x11-0x12 + uint16_t nr_logical_sectors_16; // 0x13-0x14 + uint8_t media_descriptor; // 0x15 + uint16_t logical_sector_per_fat_16; // 0x16-0x17 + uint16_t physical_sector_per_track; // 0x18-0x19 + uint16_t nr_heads; // 0x1A-0x1B + uint32_t nr_hidden_sectors; // 0x1C-0x1F + uint32_t nr_sectors_32; // 0x20-0x23 + + // FAT32 Extended BIOS Parameter Block (EBPB) + uint32_t nr_sectors_per_fat_32; // 0x24-0x27 + uint16_t mirror_flag; // 0x28-0x29 + uint16_t version; // 0x2A-0x2B + uint32_t root_dir_start_cluster_num; // 0x2C-0x2F + uint16_t fs_info_sector_num; // 0x30-0x31 + uint16_t boot_sector_bak_first_sector_num; // 0x32-0x33 + uint32_t reserved[3]; // 0x34-0x3F + uint8_t physical_drive_num; // 0x40 + uint8_t unused; // 0x41 + uint8_t extended_boot_signature; // 0x42 + uint32_t volume_id; // 0x43-0x46 + uint8_t volume_label[11]; // 0x47-0x51 + uint8_t fat_system_type[8]; // 0x52-0x59 +} __attribute__((packed)); + +/** + * Important metadata for fat32 + * In our lab, block idx is equal to sector idx (Because block size equal to sector size here) + */ +struct fat32_metadata +{ + uint32_t fat_region_blk_idx; // Fat region block idx + uint32_t data_region_blk_idx; // data region block idx + uint32_t rootDir_first_cluster; // block idx of first cluster of root directory, Often this field is set to 2. (Often first cluster number of all cluster) + uint8_t sector_per_cluster; + uint32_t nr_fat; + uint32_t sector_per_fat; +}; + +// Struct of fat32 directory entry. Short Filenames(SFN) version +struct fat32_dirEnt { + uint8_t name[8]; // 0x0-0x7. File name: 8 ASCII characters, padded with spaces. If the file name starts with 0x00, the previous entry was the last entry. + uint8_t ext[3]; // 0x8-0xA. File extension + uint8_t attr; // 0xB. Attributes of the file + uint8_t reserved; // 0xC. Reserved + uint8_t create_time[3]; // 0xD-0xF. + uint16_t create_date; // 0x10-0x11. + uint16_t last_access_date; // 0x12-0x13. + uint16_t cluster_high; // 0x14-0x15. + uint32_t ext_attr; // 0x16-0x19. 0x16 time last write, 0x18 date last write + uint16_t cluster_low; // 0x1A-0x1B. + uint32_t size; // 0x1C-0x1F. The size of the file in bytes. +} __attribute__((packed)); + +/** + * Internal struct for each fat32 vnode (vnode type either directory or regular file) + */ +struct fat32_internal +{ + uint32_t first_cluster; // Idx of first block(sector) of cluster + uint32_t dirEntry_blk_idx; // Idx of block(sector) of direcotry entry + uint32_t size; // The size of the file in bytes. +}; + + +// For sd card fat32 metadata +extern struct fat32_metadata fat32_metadata; + + +int fat32_setup_mount(struct filesystem* fs, struct mount* mount, const char *component_name); +int fat32_register(); +struct dentry* fat32_create_dentry(struct dentry *parent, const char *name, int type); +struct vnode* fat32_create_vnode(struct dentry *dentry, int type); + +int fat32_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fat32_write(struct file *file, const void *buf, size_t len); +int fat32_read(struct file *file, void *buf, size_t len); +int fat32_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fat32_mkdir(struct vnode *parent, const char *component_name); + +static inline void _dump_fat32_metadata(struct fat32_metadata *fat32_meta) +{ + printf("============dump fat32_metadata============\n"); + printf("fat_region_blk_idx : %u\n", fat32_meta->fat_region_blk_idx); // Fat region block idx + printf("data_region_blk_idx : %u\n", fat32_meta->data_region_blk_idx); // data region block idx + printf("rootDir_first_cluster : %u\n", fat32_meta->rootDir_first_cluster); // block idx of first cluster of root directory + printf("sector_per_cluster : %u\n", fat32_meta->sector_per_cluster); + printf("nr_fat : %u\n", fat32_meta->nr_fat); + printf("sector_per_fat : %u\n", fat32_meta->sector_per_fat); +} + +static inline void _dump_fat32_internal(struct fat32_internal *internal) +{ + printf("============dump fat32_internal============\n"); + printf("first_cluster : %u\n", internal->first_cluster); + printf("DirEntry_first_cluster_blk_idx : 0x%x\n", internal->dirEntry_blk_idx); + printf("size : %u\n", internal->size); +} + +#endif \ No newline at end of file diff --git a/include/fork.h b/include/fork.h index 2c077fd14..f2667ba2e 100644 --- a/include/fork.h +++ b/include/fork.h @@ -23,6 +23,8 @@ struct pt_regs { int copy_process(unsigned long clone_flags, unsigned long fn, unsigned long arg, unsigned long stack); int move_to_user_mode(unsigned long pc); +int copy_process_virt(unsigned long clone_flags, unsigned long fn, unsigned long arg); // virtual address +int move_to_user_mode_virt(unsigned long pc, unsigned long user_start_address); struct pt_regs *task_pt_regs(struct task_struct *tsk); void _init_files_struct(struct task_struct *tsk); long assignPID(); diff --git a/include/fs.h b/include/fs.h index e6b445ce8..28752f2e5 100644 --- a/include/fs.h +++ b/include/fs.h @@ -1 +1 @@ -extern struct filesystem tmpfs; \ No newline at end of file +extern struct filesystem tmpfs, fat32; \ No newline at end of file diff --git a/include/mbr.h b/include/mbr.h new file mode 100644 index 000000000..b1a7a609b --- /dev/null +++ b/include/mbr.h @@ -0,0 +1,31 @@ +#ifndef _MBR_H +#define _MBR_H + +#include "printf.h" + +// The struct of partition of Master Boot Record (MBR) for disk +struct mbr_partition +{ + unsigned char status_flag; //0x0 + unsigned char partition_begin_head; //0x1 + unsigned short partition_begin_sector; //0x2-0x3 + unsigned char partition_type; //0x4 + unsigned char partition_end_head; //0x5 + unsigned short partition_end_sector; //0x6-0x7 + unsigned int starting_sector; //0x8-0xB + unsigned int nr_sector; //0xC-0xF +} __attribute__ ((packed)); + +static inline void dump_mbr_partition(struct mbr_partition *mbr_part) +{ + // You can check mbr spec here: + // https://tc.gts3.org/cs3210/2020/spring/r/fat-structs.pdf + printf("============Dump MBR Partition============\n"); + printf("status_flag : 0x%x\n", mbr_part->status_flag); + printf("Partition Type : 0x%x\n", mbr_part->partition_type); + printf("starting_sector : 0x%x\n", mbr_part->starting_sector); + printf("nr_sector : 0x%x\n", mbr_part->nr_sector); + +} + +#endif /* _MBR_H */ \ No newline at end of file diff --git a/include/mm.h b/include/mm.h index b1355cbba..d4281e4e6 100644 --- a/include/mm.h +++ b/include/mm.h @@ -1,24 +1,38 @@ #ifndef _MM_H #define _MM_H -#include "list.h" -#include "types.h" +#include "base.h" + +#define VA_START 0xFFFF000000000000 // Virtual Memory Start +#define PHYS_MEMORY_SIZE 0x40000000 // 1G + +#define PAGE_MASK 0xFFFFFFFFFFFFF000 #define PAGE_SHIFT 12 -#define PAGE_SIZE (1 << PAGE_SHIFT) // 4KB per page frame +#define TABLE_SHIFT 9 +#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) +#define PAGE_SIZE (1 << PAGE_SHIFT) // 4KB per page frame +#define SECTION_SIZE (1 << SECTION_SHIFT) #define PAGE_FRMAME_NUM 4096 #define MAX_ORDER 9 #define MAX_ORDER_SIZE (1 << MAX_ORDER) -#define LOW_MEMORY 0x200000 +#define LOW_MEMORY (2 * SECTION_SIZE) // 2MB +#define HIGH_MEMORY DEVICE_BASE + +#define PTRS_PER_TABLE (1 << TABLE_SHIFT) +#define PGD_SHIFT PAGE_SHIFT + 3*TABLE_SHIFT +#define PUD_SHIFT PAGE_SHIFT + 2*TABLE_SHIFT +#define PMD_SHIFT PAGE_SHIFT + TABLE_SHIFT +#define PG_DIR_SIZE (3 * PAGE_SIZE) // Page dir size (PGD, PUD, PMD) #define FIND_BUDDY_PFN(pfn, order) ((pfn) ^ (1<<(order))) #define FIND_LBUDDY_PFN(pfn, order)((pfn) & (~(1<<(order)))) #define MAX_OBJ_ALLOCTOR_NUM 16 -#define MIN_ALLOCATAED_OBJ_SIZE 8 // At least 8 bytes to store adress(address of next free object ) -#define MAX_ALLOCATAED_OBJ_SIZE 2048 // At most 2048 bytes (half of a page frame) +#define MIN_ALLOCATAED_OBJ_SIZE 8 // At least 8 bytes to store adress(address of next free object ) +#define MAX_ALLOCATAED_OBJ_SIZE 2048 // At most 2048 bytes (half of a page frame) #define MIN_KMALLOC_ORDER 3 #define MAX_KMALLOC_ORDER 11 @@ -27,6 +41,11 @@ #define PHY_ADDR_TO_PFN(addr) (((((unsigned long)(addr)) - LOW_MEMORY) & PFN_MASK) >> PAGE_SHIFT) +#ifndef __ASSEMBLER__ + +#include "list.h" +#include "types.h" +#include "sched.h" /** * "used" property of struct of page */ @@ -133,20 +152,78 @@ void dump_obj_alloc(obj_allocator_t *); */ void __init_kmalloc(); void *kmalloc(int size); -void kfree(void *addr) ; +void kfree(void *addr); /** * mm_init - Initialize system of memory management */ void mm_init(); +/* Functions after MMU enable*/ +void *get_free_page(); +void free_page(void *p); +void *alloacte_kernel_page(); +void *alloacte_user_page(struct task_struct *task, unsigned long va); +void map_table_entry(unsigned long *pte, unsigned long va, unsigned long page); +unsigned long map_table (unsigned long *table, unsigned long shift, unsigned long va, int *new_table); +void map_page(struct task_struct *task, unsigned long va, unsigned long page); + +/** + * copy_virt_memory. It iterates over user_pages array, which contains all pages, allocated by the current process. + * Note, that in user_pages array we store only pages that are actually available to the process and contain its source code or data; + * we don't include here page table pages, which are stored in kernel_pages array. + * Next, for each page, we allocate another empty page and copy the original page content there + * We also map the new page using the same virtual address, that is used by the original one. + * This is how we get the exact copy of the original process address space. + * + * With virtual memory, each task has its address space and can refer to different physical address with the same virtual address. + * Therefore, each user task can use the same virtual address to their own user stack. + * + */ +int copy_virt_memory(struct task_struct *dst); + +/** + * mem_map is kernel function used to support of mmap syscall + * It's a Simplified version of mmap in linux + * @param[in] addr // The starting address for the new mapping is specified in addr. + * @param[in] len // The length argument specifies the length of the mapping (which must be greater than 0). + * @param[in] prot // prot is the region’s access protection + * @param[in] flags // MAP_FIXED, MAP_ANONYMOUS and MAP_POPULATE are acceptable + * @param[in] fd // not used + * @param[in] file_offset // not used + * @return The address of the new mapping is returned as the result of the call. + */ +void *mem_map(void *addr, size_t len, int prot, int flags, int fd, int file_offset); + +/** + * page fault exception (or, which is the same, data access exception) + * @param[in] addr The memory address which we tried to access. This address is taken from far_el1 register (Fault address register) + * @param[in] esr The content of the esr_el1 (Exception syndrome register) + * @return 0 if success, otherwise return non zero value + * + * + * data abort (or Page fault) exception, + * I. segmentation fault + * If the fault address is not part of any region in the process’s address space, + * a segmentation fault is generated, and the kernel terminates the process. + * II. damand paging + * Map one page frame for the fault address. + * + * esr register - + * Bits [32:26] of this register are called "Exception Class". + * We check those bits in the el0_sync handler to determine whether it is a syscall, or a data abort exception or potentially something else. + * Exception class determines the meaning of bits [24:0] - those bits are usually used to provide additional information about the exception. + * The meaning of [24:0] bits in case of the data abort exception is described on the page 2460 of the AArch64-Reference-Manual + */ +int do_mem_abort(unsigned long addr, unsigned long esr); -#ifndef __ASSEMBLER__ +void *mem_map(void *addr, size_t len, int prot, int flags, int fd, int file_offset); +/* mm.S */ void memcpy(unsigned long dst, unsigned long src, unsigned long n); void memzero(unsigned long src, unsigned long n); -#endif +#endif /* __ASSEMBLER__ */ #endif /* _MM_H */ diff --git a/include/mmu.h b/include/mmu.h new file mode 100644 index 000000000..61cb39ce1 --- /dev/null +++ b/include/mmu.h @@ -0,0 +1,46 @@ +#ifndef _MMU_H +#define _MMU_H + +/* Page descriptor attributes */ +#define MM_TYPE_PAGE_TABLE 0b11 +#define MM_TYPE_PAGE 0b11 +#define MM_TYPE_BLOCK 0b01 +#define MM_ACCESS (0x1 << 10) +#define MM_ACCESS_PERMISSION (0x01 << 6) +#define MM_UESR_KERNEL_ACCESS (0x01 << 6) // same as MM_ACCESS_PERMISSION +/* mmap */ +#define MM_READ_ONLY (0x1 << 7) // readable (readonly) +#define MM_EXEC_NONE (0x1L << 54) // non-executable + +#define MMAP_PTE_DEFAULT (MM_TYPE_PAGE | MM_READ_ONLY | MM_ACCESS | MM_EXEC_NONE | MM_UESR_KERNEL_ACCESS) // Page, Readonly, accessible and non-executable +/* + * Memory region attributes: + * + * n = AttrIndx[2:0] + * n MAIR + * DEVICE_nGnRnE 000 00000000 + * NORMAL_NOCACHE 001 01000100 + */ +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 + +#define MMU_FLAGS (MM_TYPE_BLOCK | (MAIR_IDX_NORMAL_NOCACHE << 2) | MM_ACCESS) +#define MMU_DEVICE_FLAGS (MM_TYPE_BLOCK | (MAIR_IDX_DEVICE_nGnRnE << 2) | MM_ACCESS) +#define MMU_PTE_FLAGS (MM_TYPE_PAGE | (MAIR_IDX_NORMAL_NOCACHE << 2) | MM_ACCESS | MM_ACCESS_PERMISSION) + +#define MAIR_VALUE ((MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))) + +/** + * For TCR_EL1 system register3 + **/ +#define TCR_T0SZ (64 - 48) // T0SZ field of tcr_el1 register is used for Lower VA subrange +#define TCR_T1SZ ((64 - 48) << 16) // T1SZ field of tcr_el1 register is used for Lower VA subrange Upper VA subrange +#define TCR_TG0_4K (0b00 << 14) // Page size(granule size) for user space (or for TG0 is more accurate) +#define TCR_TG1_4K (0b10 << 30) // Page size(granule size) for kernel (or for TG1 is more accurate) +#define TCR_CONFIG_REGION_48bit (TCR_T0SZ | TCR_T1SZ) +#define TCR_CONFIG_4KB (TCR_TG0_4K | TCR_TG1_4K) +#define TCR_VALUE (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#endif \ No newline at end of file diff --git a/include/sched.h b/include/sched.h index bc5e75bbe..d136e15d0 100644 --- a/include/sched.h +++ b/include/sched.h @@ -27,6 +27,7 @@ extern struct task_struct *current; // current executing task extern struct task_struct *task[NR_TASKS]; extern int nr_tasks; +extern unsigned long pg_dir; // Each runqueue have corresponding prority(array number) // The lower number is more significant than higher one // TODO: @@ -48,6 +49,23 @@ struct cpu_context { unsigned long pc; }; +// map physical and virtual address +struct user_page { + unsigned long phys_addr; + unsigned long virt_addr; +}; + +#define MAX_PROCESS_PAGES 16 +#define MAX_PROCESS_ADDRESS_SPACE (MAX_PROCESS_PAGES * PAGE_SIZE) +struct mm_struct { + unsigned long pgd; + int user_pages_count; + struct user_page user_pages[MAX_PROCESS_PAGES]; // phys and virt address mapping, used for fork syscall + int kernel_pages_count; + unsigned long kernel_pages[MAX_PROCESS_PAGES]; // page table +}; + + /** * @stack: User stack * @flags: Some flags such as Kernel/User thread @@ -58,12 +76,17 @@ struct task_struct { long counter; long priority; long preempt_count; - unsigned long stack; + unsigned long stack; unsigned long flags; long pid; - struct list_head run_list; // TODO + struct list_head run_list; // TODO: runnable processes + + /* Virtual File system */ struct files_struct files; // file descriptor table for each process struct dentry *cwd; // Current Working Directory + + /* Memory Management */ + struct mm_struct mm; }; extern void schedule(void); @@ -75,13 +98,17 @@ extern void cpu_switch_to(struct task_struct* prev, struct task_struct* next); extern void task_preemption(); extern void exit_process(void); extern void kill_zombies(void); +extern void sched_init(); extern void dumpTasksState(void); #define INIT_TASK \ /*cpu_context*/ { {0,0,0,0,0,0,0,0,0,0,0,0,0}, \ /* state etc */ 0, 0, 1, 0, 0, PF_KTHREAD, \ -/* task id */ 0 \ +/* task id */ 0, \ +/* run_list */ {0, 0}, \ +/* VFS */ {0, 0, {0}}, 0, \ +/* mm */ {0, 0, {{0}}, 0, {0}} \ } #endif /* __ASSEMBLER__ */ diff --git a/include/sdhost.h b/include/sdhost.h new file mode 100644 index 000000000..9c62e6eb5 --- /dev/null +++ b/include/sdhost.h @@ -0,0 +1,77 @@ +// mmio +#include "base.h" + +// 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 + +// gpio +#define GPIO_BASE (MMIO_BASE + 0x200000) +#define GPIO_GPFSEL4 (GPIO_BASE + 0x10) +#define GPIO_GPFSEL5 (GPIO_BASE + 0x14) +#define GPIO_GPPUD (GPIO_BASE + 0x94) +#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9c) + +// sdhost +#define SDHOST_BASE (MMIO_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) + +// helper +#define set(io_addr, val) \ + asm volatile("str %w1, [%0]" ::"r"(io_addr), "r"(val) : "memory"); + +#define get(io_addr, val) \ + asm volatile("ldr %w0, [%1]" : "=r"(val) : "r"(io_addr) : "memory"); + +void readblock(int block_idx, void* buf); +void writeblock(int block_idx, void* buf); + +void sd_init(); +void sd_mount(); \ No newline at end of file diff --git a/include/sys.h b/include/sys.h index 93b546e21..4836035b5 100644 --- a/include/sys.h +++ b/include/sys.h @@ -3,7 +3,7 @@ #include "types.h" -#define __NR_syscalls 20 +#define __NR_syscalls 21 #define SYS_PRINT_NUMBER 0 // syscal numbers #define SYS_UARTWRITE_NUMBER 1 @@ -25,10 +25,20 @@ #define SYS_CHDIR 17 #define SYS_MOUNT 18 #define SYS_UNMOUNT 19 - +#define SYS_MMAP 20 #ifndef __ASSEMBLER__ +/* mmap */ +#define PROT_NONE 0b0001 // not accessible +#define PROT_READ 0b0010 // readable +#define PROT_WRITE 0b0100 // writable. PROT_WRITE implies PROT_READ due to hardware architectures. +#define PROT_EXEC 0b1000 // executable +#define MAP_FIXED 0 // New region’s start should be addr, otherwise the mmap() fails. +#define MAP_ANONYMOUS 1 // New region is mapped to anonymous page. It’s usually used for stack and heap. +#define MAP_POPULATE 2 // Not used + +/* VFS */ #define SYS_OPEN_FILE_ERROR -1 #define SYS_WRITE_FILE_ERROR -1 #define SYS_READ_FILE_ERROR -1 @@ -53,6 +63,7 @@ int sys_mkdir(const char *pathname); int sys_chdir(const char *pathname); int sys_mount(const char* device, const char* mountpoint, const char* filesystem); int sys_unmount(const char* mountpoint); +void *sys_mmap(void *addr, size_t len, int prot, int flags, int fd, int file_offset); void call_sys_print(char * buf); int call_sys_uart_write(char buf[], size_t size); @@ -73,6 +84,7 @@ int call_sys_mkdir(const char *pathname); int call_sys_chdir(const char *pathname); int call_sys_mount(const char* device, const char* mountpoint, const char* filesystem); int call_sys_unmount(const char* mountpoint); +void *call_sys_mmap(void *addr, size_t len, int prot, int flags, int fd, int file_offset); #endif /* __ASSEMBLER__ */ #endif /*_SYS_H */ \ No newline at end of file diff --git a/include/sysregs.h b/include/sysregs.h index cf1111c96..8c970a893 100644 --- a/include/sysregs.h +++ b/include/sysregs.h @@ -52,7 +52,8 @@ // ESR_EL1, Exception Syndrome Register (EL1). Page 2431 of AArch64-Reference-Manual. // *************************************** -#define ESR_ELx_EC_SHIFT 26 -#define ESR_ELx_EC_SVC64 0x15 - +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 +#define ESR_ELx_EC_DABT_LOW 0x24 // Data Abort from a lower Exception level. +#define ESR_ELx_EC_DABT_SAME_LEVEL 0b100101 // Data Abort taken without a change in Exception level. #endif \ No newline at end of file diff --git a/include/tmpfs.h b/include/tmpfs.h index 6dda1cffb..0adb7702d 100644 --- a/include/tmpfs.h +++ b/include/tmpfs.h @@ -11,7 +11,7 @@ struct tmpfs_internal { char *buf; }; -int tmpfs_setup_mount(); +int tmpfs_setup_mount(struct filesystem* fs, struct mount* mount, const char *component_name); int tmpfs_register(); struct dentry* tmpfs_create_dentry(struct dentry *parent, const char *name, int type); struct vnode* tmpfs_create_vnode(struct dentry *dentry, int type); diff --git a/include/utils.h b/include/utils.h index 471739160..6c9adc53f 100644 --- a/include/utils.h +++ b/include/utils.h @@ -2,6 +2,17 @@ #define _BOOT_H extern int get_el ( void ); -extern void delay ( unsigned long); + +static inline void delay(unsigned long tick) { + while (tick--) { + asm volatile("nop"); + } +} + +extern void set_pgd(unsigned long pgd); + +// Because printf.c in our printf source code not support 64bit, +// we design a special function to print 64bit value +void print_0x_64bit(void *p); #endif /*_BOOT_H */ \ No newline at end of file diff --git a/include/vfs.h b/include/vfs.h index ab2874237..459154d5b 100644 --- a/include/vfs.h +++ b/include/vfs.h @@ -29,8 +29,8 @@ struct vnode { struct dentry *dentry; - struct vnode_operations* v_ops; - struct file_operations* f_ops; + struct vnode_operations *v_ops; + struct file_operations *f_ops; int v_type; void *internal; // internal representation of a vnode }; @@ -46,14 +46,14 @@ struct dentry // If it's directory and mounted by mount() function, // it will point to specific mount struct. otherwise it's NULL - struct mount* mount; + struct mount *mount; }; struct file { struct vnode *vnode; size_t f_pos; // The next read/write position of this opened file - struct file_operations* f_ops; + struct file_operations *f_ops; int flags; // unused int nr_internal_moemory_page_allocated; }; @@ -61,13 +61,15 @@ struct file struct mount { struct dentry *root; // root directory - struct filesystem *fs; + struct filesystem *fs; + + char *device_name; }; struct filesystem { char *name; - int (*setup_mount)(struct filesystem* fs, struct mount* mount, const char *component_name); + int (*setup_mount)(struct filesystem *fs, struct mount *mount, const char *component_name); }; struct vnode_operations @@ -97,20 +99,20 @@ struct files_struct void rootfs_init(); -int _vnode_path_traversal(struct vnode *rootnode, const char* pathname, struct vnode **target_file, char *target_component_name); -int _lookUp_pathname(const char* pathname, struct vnode **target_file, char *target_component_name); +int _vnode_path_traversal(struct vnode *rootnode, const char *pathname, struct vnode **target_file, char *target_component_name); +int _lookUp_pathname(const char *pathname, struct vnode **target_file, char *target_component_name); /* VFS API */ int register_filesystem(struct filesystem* fs); struct file *vfs_open(const char *pathname, int flags); -int vfs_close(struct file* file); +int vfs_close(struct file *file); 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_chdir(const char *pathname); -int vfs_mount(const char* device, const char* mountpoint, const char* filesystem); -int vfs_unmount(const char* mountpoint); +int vfs_mount(const char *device, const char *mountpoint, const char *filesystem); +int vfs_unmount(const char *mountpoint); char *vfs_read_directory(struct file *file); void vfs_print_directory_by_pathname(const char *pathname); @@ -122,7 +124,7 @@ void _vfs_dump_vnode(); void _vfs_dump_dentry(); void _vfs_dump_file_struct(); -/* Test case for vfs */ +/* Test case for Lab6 - vfs */ void vfs_test(); void vfs_requirement1_test(); void vfs_requirement1_read_file_populated_in_cpio(); @@ -130,4 +132,8 @@ void user_ls_process(const char *pathname); void vfs_user_process_test(); void vfs_elective2_user_process_test(); void vfs_ls_print_test(const char *pathname); + +/* Test cases for Lab7 - fat32 */ +void Lab7_fat32_test(); + #endif \ No newline at end of file diff --git a/initramfs.cpio b/initramfs.cpio index de782f5b9..184853c40 100755 Binary files a/initramfs.cpio and b/initramfs.cpio differ diff --git a/linker.ld b/linker.ld index 76f447b99..165eb4aba 100755 --- a/linker.ld +++ b/linker.ld @@ -1,7 +1,9 @@ SECTIONS { - . = 0x80000; + . = 0xFFFF000000000000; /* Upper Virtaul Address (kernel space) */ + . += 0x80000; /* kernel load address */ + __kernel_start = .; .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } PROVIDE(_data = .); @@ -13,8 +15,9 @@ SECTIONS *(COMMON) __bss_end = .; } - _end = .; - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} -__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file + . = ALIGN(0x00001000); /* Page table should be align */ + pg_dir = .; /* Page table starting address */ + .data.pgd : { . += (3 * (1 << 12)); } /* Add Size of 3 Page table (PGD, PUD, PMD) */ + . = ALIGN(0x00001000); + __kernel_end = .; +} \ No newline at end of file diff --git a/rootfs/Lab8_mmap/Makefile b/rootfs/Lab8_mmap/Makefile new file mode 100644 index 000000000..09e29cab8 --- /dev/null +++ b/rootfs/Lab8_mmap/Makefile @@ -0,0 +1,50 @@ +# Modify from +# https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary Lab8_mmap.img + +run: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio + +debug: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -initrd initramfs.cpio -serial null -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw -display none -S -s + +run_cpio: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio + +# run with sd card (Lab7) +run_sd: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw + +# run with cpio and sd card +run_all: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw \ No newline at end of file diff --git a/rootfs/Lab8_mmap/include/printf.h b/rootfs/Lab8_mmap/include/printf.h new file mode 100644 index 000000000..22b125489 --- /dev/null +++ b/rootfs/Lab8_mmap/include/printf.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); +void printf(char *fmt, ...); \ No newline at end of file diff --git a/rootfs/Lab8_mmap/include/sys.h b/rootfs/Lab8_mmap/include/sys.h new file mode 100644 index 000000000..4836035b5 --- /dev/null +++ b/rootfs/Lab8_mmap/include/sys.h @@ -0,0 +1,90 @@ +#ifndef _SYS_H +#define _SYS_H + +#include "types.h" + +#define __NR_syscalls 21 + +#define SYS_PRINT_NUMBER 0 // syscal numbers +#define SYS_UARTWRITE_NUMBER 1 +#define SYS_UARTREAD_NUMBER 2 +#define SYS_GETPID_NUMBER 3 +#define SYS_FORK_NUMBER 4 +#define SYS_EXEC_NUMBER 5 +#define SYS_EXIT_NUMBER 6 +#define SYS_MALLOC_NUMBER 7 +#define SYS_CLONE_NUMBER 8 +#define SYS_CORETIMER_On 9 +#define SYS_CORETIMER_OFF 10 +#define SYS_OPEN 11 +#define SYS_CLOSE 12 +#define SYS_WRITE 13 +#define SYS_READ 14 +#define SYS_READ_DIRECTORY 15 +#define SYS_MKDIR 16 +#define SYS_CHDIR 17 +#define SYS_MOUNT 18 +#define SYS_UNMOUNT 19 +#define SYS_MMAP 20 + +#ifndef __ASSEMBLER__ + +/* mmap */ +#define PROT_NONE 0b0001 // not accessible +#define PROT_READ 0b0010 // readable +#define PROT_WRITE 0b0100 // writable. PROT_WRITE implies PROT_READ due to hardware architectures. +#define PROT_EXEC 0b1000 // executable +#define MAP_FIXED 0 // New region’s start should be addr, otherwise the mmap() fails. +#define MAP_ANONYMOUS 1 // New region is mapped to anonymous page. It’s usually used for stack and heap. +#define MAP_POPULATE 2 // Not used + +/* VFS */ +#define SYS_OPEN_FILE_ERROR -1 +#define SYS_WRITE_FILE_ERROR -1 +#define SYS_READ_FILE_ERROR -1 + +void sys_print(char * buf); +int sys_uart_write(char buf[], size_t size); +int sys_uart_read(char buf[], size_t size); +int sys_gitPID(); +int sys_fork(); +int sys_exec(const char* name, char* const argv[]); +void sys_exit(); +void *sys_malloc(int bytes); +int sys_clone(); +void sys_coreTimer_on(); +void sys_coreTimer_off(); +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +int sys_write(int fd, const void *buf, size_t len); +int sys_read(int fd, void *buf, size_t len); +char *sys_read_directory(int fd); +int sys_mkdir(const char *pathname); +int sys_chdir(const char *pathname); +int sys_mount(const char* device, const char* mountpoint, const char* filesystem); +int sys_unmount(const char* mountpoint); +void *sys_mmap(void *addr, size_t len, int prot, int flags, int fd, int file_offset); + +void call_sys_print(char * buf); +int call_sys_uart_write(char buf[], size_t size); +int call_sys_uart_read(char buf[], size_t size); +int call_sys_gitPID(); +int call_sys_fork(); +int call_sys_exec(const char* name, char* const argv[]); +void call_sys_exit(); +void* call_sys_malloc(); +void call_sys_coreTimer_on(); +void call_sys_coreTimer_off(); +int call_sys_open(const char *pathname, int flags); +int call_sys_close(int fd); +int call_sys_write(int fd, const void *buf, size_t len); +int call_sys_read(int fd, void *buf, size_t len); +char *call_sys_read_directory(int fd); +int call_sys_mkdir(const char *pathname); +int call_sys_chdir(const char *pathname); +int call_sys_mount(const char* device, const char* mountpoint, const char* filesystem); +int call_sys_unmount(const char* mountpoint); +void *call_sys_mmap(void *addr, size_t len, int prot, int flags, int fd, int file_offset); + +#endif /* __ASSEMBLER__ */ +#endif /*_SYS_H */ \ No newline at end of file diff --git a/rootfs/Lab8_mmap/include/types.h b/rootfs/Lab8_mmap/include/types.h new file mode 100644 index 000000000..7a6720fbc --- /dev/null +++ b/rootfs/Lab8_mmap/include/types.h @@ -0,0 +1,30 @@ +#ifndef _KERNEL_TYPES_H +#define _KERNEL_TYPES_H + +#ifndef __ASSEMBLER__ + +typedef signed char int8_t; +typedef signed short int int16_t; +typedef signed int int32_t; +typedef signed long int int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long int uint64_t; + +typedef unsigned int size_t; + +typedef long pid_t; // task pid + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define TRUE 1 +#define FALSE 0 + +#define EOF -1 + +#endif /* __ASSEMBLER__ */ +#endif \ No newline at end of file diff --git a/rootfs/Lab8_mmap/linker.ld b/rootfs/Lab8_mmap/linker.ld new file mode 100644 index 000000000..32aac14c5 --- /dev/null +++ b/rootfs/Lab8_mmap/linker.ld @@ -0,0 +1,20 @@ + +SECTIONS +{ + . = 0x0; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file diff --git a/rootfs/Lab8_mmap/src/illegal_write.c b/rootfs/Lab8_mmap/src/illegal_write.c new file mode 100644 index 000000000..a4bf7d378 --- /dev/null +++ b/rootfs/Lab8_mmap/src/illegal_write.c @@ -0,0 +1,12 @@ +#include "printf.h" +#include "sys.h" + +int main(int argc, char **argv) { + printf("[mmap - illegal_wrtie]\n"); + char *ptr2 = call_sys_mmap(NULL, 4096, PROT_READ, MAP_ANONYMOUS, -1, 0); + printf("mmap allocated address: 0x%x\n", ptr2); + printf("%d\n", ptr2[1000]); // should be 0 + ptr2[0] = 1; // illegal_write. (Should be seg fault, if no writable flag in mmap) + printf("%d\n", ptr2[0]); // not reached + return 0; +} \ No newline at end of file diff --git a/rootfs/Lab8_mmap/src/printf.c b/rootfs/Lab8_mmap/src/printf.c new file mode 100644 index 000000000..3a0272847 --- /dev/null +++ b/rootfs/Lab8_mmap/src/printf.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "printf.h" +#include "sys.h" +/** + * minimal sprintf implementation + */ +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} + +/** + * Display a string + */ +void printf(char *fmt, ...) { + __builtin_va_list args; + __builtin_va_start(args, fmt); + // we don't have memory allocation yet, so we + // simply place our string after our code + char s[200]; + // use sprintf to format our string + vsprintf(s,fmt,args); + // print out as usual + call_sys_print(s); +} diff --git a/rootfs/Lab8_mmap/src/start.S b/rootfs/Lab8_mmap/src/start.S new file mode 100644 index 000000000..52914aa50 --- /dev/null +++ b/rootfs/Lab8_mmap/src/start.S @@ -0,0 +1,11 @@ +.section ".text.boot" + +.global _start +_start: + bl main // jump to main functoin in C code, should not return + b proc_hang // for failsafe, halt this core too (Should never do this instruction) + +proc_hang: + wfe // hang for all noo-primary CPU and enter low power mode + b proc_hang + diff --git a/rootfs/Lab8_mmap/src/sys.S b/rootfs/Lab8_mmap/src/sys.S new file mode 100644 index 000000000..bc72dbacd --- /dev/null +++ b/rootfs/Lab8_mmap/src/sys.S @@ -0,0 +1,122 @@ +#include "sys.h" + +.globl call_sys_print +call_sys_print: + mov w8, #SYS_PRINT_NUMBER + svc #0 + ret + +.globl call_sys_uart_write +call_sys_uart_write: + mov w8, #SYS_UARTWRITE_NUMBER + svc #0 + ret + +.globl call_sys_uart_read +call_sys_uart_read: + mov w8, #SYS_UARTREAD_NUMBER + svc #0 + ret + +.globl call_sys_gitPID +call_sys_gitPID: + mov w8, #SYS_GETPID_NUMBER + svc #0 + ret + +.globl call_sys_fork +call_sys_fork: + mov w8, #SYS_FORK_NUMBER + svc #0 + ret + +.globl call_sys_exec +call_sys_exec: + mov w8, #SYS_EXEC_NUMBER + svc #0 + ret + +.globl call_sys_exit +call_sys_exit: + mov w8, #SYS_EXIT_NUMBER + svc #0 + ret + +.globl call_sys_malloc +call_sys_malloc: + mov w8, #SYS_MALLOC_NUMBER + svc #0 + ret + +.globl call_sys_coreTimer_on +call_sys_coreTimer_on: + mov w8, #SYS_CORETIMER_On + svc #0 + ret + +.globl call_sys_coreTimer_off +call_sys_coreTimer_off: + mov w8, #SYS_CORETIMER_OFF + svc #0 + ret + +.globl call_sys_open +call_sys_open: + mov w8, #SYS_OPEN + svc #0 + ret + +.globl call_sys_close +call_sys_close: + mov w8, #SYS_CLOSE + svc #0 + ret + +.globl call_sys_write +call_sys_write: + mov w8, #SYS_WRITE + svc #0 + ret + +.globl call_sys_read +call_sys_read: + mov w8, #SYS_READ + svc #0 + ret + +.globl call_sys_read_directory +call_sys_read_directory: + mov w8, #SYS_READ_DIRECTORY + svc #0 + ret + +.globl call_sys_mkdir +call_sys_mkdir: + mov w8, #SYS_MKDIR + svc #0 + ret + +.globl call_sys_chdir +call_sys_chdir: + mov w8, #SYS_CHDIR + svc #0 + ret + +.globl call_sys_mount +call_sys_mount: + mov w8, #SYS_MOUNT + svc #0 + ret + +.globl call_sys_unmount +call_sys_unmount: + mov w8, #SYS_UNMOUNT + svc #0 + ret + +.globl call_sys_mmap +call_sys_mmap: + mov w8, #SYS_MMAP + svc #0 + ret + diff --git a/rootfs/Lab8_mmap_2/Makefile b/rootfs/Lab8_mmap_2/Makefile new file mode 100644 index 000000000..9c4752e3e --- /dev/null +++ b/rootfs/Lab8_mmap_2/Makefile @@ -0,0 +1,50 @@ +# Modify from +# https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary Lab8_mmap_2.img + +run: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio + +debug: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -initrd initramfs.cpio -serial null -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw -display none -S -s + +run_cpio: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio + +# run with sd card (Lab7) +run_sd: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw + +# run with cpio and sd card +run_all: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw \ No newline at end of file diff --git a/rootfs/Lab8_mmap_2/include/printf.h b/rootfs/Lab8_mmap_2/include/printf.h new file mode 100644 index 000000000..22b125489 --- /dev/null +++ b/rootfs/Lab8_mmap_2/include/printf.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); +void printf(char *fmt, ...); \ No newline at end of file diff --git a/rootfs/Lab8_mmap_2/include/sys.h b/rootfs/Lab8_mmap_2/include/sys.h new file mode 100644 index 000000000..4836035b5 --- /dev/null +++ b/rootfs/Lab8_mmap_2/include/sys.h @@ -0,0 +1,90 @@ +#ifndef _SYS_H +#define _SYS_H + +#include "types.h" + +#define __NR_syscalls 21 + +#define SYS_PRINT_NUMBER 0 // syscal numbers +#define SYS_UARTWRITE_NUMBER 1 +#define SYS_UARTREAD_NUMBER 2 +#define SYS_GETPID_NUMBER 3 +#define SYS_FORK_NUMBER 4 +#define SYS_EXEC_NUMBER 5 +#define SYS_EXIT_NUMBER 6 +#define SYS_MALLOC_NUMBER 7 +#define SYS_CLONE_NUMBER 8 +#define SYS_CORETIMER_On 9 +#define SYS_CORETIMER_OFF 10 +#define SYS_OPEN 11 +#define SYS_CLOSE 12 +#define SYS_WRITE 13 +#define SYS_READ 14 +#define SYS_READ_DIRECTORY 15 +#define SYS_MKDIR 16 +#define SYS_CHDIR 17 +#define SYS_MOUNT 18 +#define SYS_UNMOUNT 19 +#define SYS_MMAP 20 + +#ifndef __ASSEMBLER__ + +/* mmap */ +#define PROT_NONE 0b0001 // not accessible +#define PROT_READ 0b0010 // readable +#define PROT_WRITE 0b0100 // writable. PROT_WRITE implies PROT_READ due to hardware architectures. +#define PROT_EXEC 0b1000 // executable +#define MAP_FIXED 0 // New region’s start should be addr, otherwise the mmap() fails. +#define MAP_ANONYMOUS 1 // New region is mapped to anonymous page. It’s usually used for stack and heap. +#define MAP_POPULATE 2 // Not used + +/* VFS */ +#define SYS_OPEN_FILE_ERROR -1 +#define SYS_WRITE_FILE_ERROR -1 +#define SYS_READ_FILE_ERROR -1 + +void sys_print(char * buf); +int sys_uart_write(char buf[], size_t size); +int sys_uart_read(char buf[], size_t size); +int sys_gitPID(); +int sys_fork(); +int sys_exec(const char* name, char* const argv[]); +void sys_exit(); +void *sys_malloc(int bytes); +int sys_clone(); +void sys_coreTimer_on(); +void sys_coreTimer_off(); +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +int sys_write(int fd, const void *buf, size_t len); +int sys_read(int fd, void *buf, size_t len); +char *sys_read_directory(int fd); +int sys_mkdir(const char *pathname); +int sys_chdir(const char *pathname); +int sys_mount(const char* device, const char* mountpoint, const char* filesystem); +int sys_unmount(const char* mountpoint); +void *sys_mmap(void *addr, size_t len, int prot, int flags, int fd, int file_offset); + +void call_sys_print(char * buf); +int call_sys_uart_write(char buf[], size_t size); +int call_sys_uart_read(char buf[], size_t size); +int call_sys_gitPID(); +int call_sys_fork(); +int call_sys_exec(const char* name, char* const argv[]); +void call_sys_exit(); +void* call_sys_malloc(); +void call_sys_coreTimer_on(); +void call_sys_coreTimer_off(); +int call_sys_open(const char *pathname, int flags); +int call_sys_close(int fd); +int call_sys_write(int fd, const void *buf, size_t len); +int call_sys_read(int fd, void *buf, size_t len); +char *call_sys_read_directory(int fd); +int call_sys_mkdir(const char *pathname); +int call_sys_chdir(const char *pathname); +int call_sys_mount(const char* device, const char* mountpoint, const char* filesystem); +int call_sys_unmount(const char* mountpoint); +void *call_sys_mmap(void *addr, size_t len, int prot, int flags, int fd, int file_offset); + +#endif /* __ASSEMBLER__ */ +#endif /*_SYS_H */ \ No newline at end of file diff --git a/rootfs/Lab8_mmap_2/include/types.h b/rootfs/Lab8_mmap_2/include/types.h new file mode 100644 index 000000000..7a6720fbc --- /dev/null +++ b/rootfs/Lab8_mmap_2/include/types.h @@ -0,0 +1,30 @@ +#ifndef _KERNEL_TYPES_H +#define _KERNEL_TYPES_H + +#ifndef __ASSEMBLER__ + +typedef signed char int8_t; +typedef signed short int int16_t; +typedef signed int int32_t; +typedef signed long int int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long int uint64_t; + +typedef unsigned int size_t; + +typedef long pid_t; // task pid + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define TRUE 1 +#define FALSE 0 + +#define EOF -1 + +#endif /* __ASSEMBLER__ */ +#endif \ No newline at end of file diff --git a/rootfs/Lab8_mmap_2/linker.ld b/rootfs/Lab8_mmap_2/linker.ld new file mode 100644 index 000000000..32aac14c5 --- /dev/null +++ b/rootfs/Lab8_mmap_2/linker.ld @@ -0,0 +1,20 @@ + +SECTIONS +{ + . = 0x0; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file diff --git a/rootfs/Lab8_mmap_2/src/illegal_read.c b/rootfs/Lab8_mmap_2/src/illegal_read.c new file mode 100644 index 000000000..abedc7e0e --- /dev/null +++ b/rootfs/Lab8_mmap_2/src/illegal_read.c @@ -0,0 +1,13 @@ +#include "printf.h" +#include "sys.h" + +int main(int argc, char **argv) { + printf("[mmap - illegal_read]\n"); + char* ptr1 = call_sys_mmap((void *)0x1000, 4096, PROT_READ, MAP_ANONYMOUS, -1, 0); + printf("mmap allocated address: %x\n", ptr1); + printf("%d\n", ptr1[1000]); // should be 0 + printf("%d\n", ptr1[4097]); // should be segfault + + call_sys_exit(); + return 0; +} \ No newline at end of file diff --git a/rootfs/Lab8_mmap_2/src/printf.c b/rootfs/Lab8_mmap_2/src/printf.c new file mode 100644 index 000000000..3a0272847 --- /dev/null +++ b/rootfs/Lab8_mmap_2/src/printf.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "printf.h" +#include "sys.h" +/** + * minimal sprintf implementation + */ +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} + +/** + * Display a string + */ +void printf(char *fmt, ...) { + __builtin_va_list args; + __builtin_va_start(args, fmt); + // we don't have memory allocation yet, so we + // simply place our string after our code + char s[200]; + // use sprintf to format our string + vsprintf(s,fmt,args); + // print out as usual + call_sys_print(s); +} diff --git a/rootfs/Lab8_mmap_2/src/start.S b/rootfs/Lab8_mmap_2/src/start.S new file mode 100644 index 000000000..52914aa50 --- /dev/null +++ b/rootfs/Lab8_mmap_2/src/start.S @@ -0,0 +1,11 @@ +.section ".text.boot" + +.global _start +_start: + bl main // jump to main functoin in C code, should not return + b proc_hang // for failsafe, halt this core too (Should never do this instruction) + +proc_hang: + wfe // hang for all noo-primary CPU and enter low power mode + b proc_hang + diff --git a/rootfs/Lab8_mmap_2/src/sys.S b/rootfs/Lab8_mmap_2/src/sys.S new file mode 100644 index 000000000..bc72dbacd --- /dev/null +++ b/rootfs/Lab8_mmap_2/src/sys.S @@ -0,0 +1,122 @@ +#include "sys.h" + +.globl call_sys_print +call_sys_print: + mov w8, #SYS_PRINT_NUMBER + svc #0 + ret + +.globl call_sys_uart_write +call_sys_uart_write: + mov w8, #SYS_UARTWRITE_NUMBER + svc #0 + ret + +.globl call_sys_uart_read +call_sys_uart_read: + mov w8, #SYS_UARTREAD_NUMBER + svc #0 + ret + +.globl call_sys_gitPID +call_sys_gitPID: + mov w8, #SYS_GETPID_NUMBER + svc #0 + ret + +.globl call_sys_fork +call_sys_fork: + mov w8, #SYS_FORK_NUMBER + svc #0 + ret + +.globl call_sys_exec +call_sys_exec: + mov w8, #SYS_EXEC_NUMBER + svc #0 + ret + +.globl call_sys_exit +call_sys_exit: + mov w8, #SYS_EXIT_NUMBER + svc #0 + ret + +.globl call_sys_malloc +call_sys_malloc: + mov w8, #SYS_MALLOC_NUMBER + svc #0 + ret + +.globl call_sys_coreTimer_on +call_sys_coreTimer_on: + mov w8, #SYS_CORETIMER_On + svc #0 + ret + +.globl call_sys_coreTimer_off +call_sys_coreTimer_off: + mov w8, #SYS_CORETIMER_OFF + svc #0 + ret + +.globl call_sys_open +call_sys_open: + mov w8, #SYS_OPEN + svc #0 + ret + +.globl call_sys_close +call_sys_close: + mov w8, #SYS_CLOSE + svc #0 + ret + +.globl call_sys_write +call_sys_write: + mov w8, #SYS_WRITE + svc #0 + ret + +.globl call_sys_read +call_sys_read: + mov w8, #SYS_READ + svc #0 + ret + +.globl call_sys_read_directory +call_sys_read_directory: + mov w8, #SYS_READ_DIRECTORY + svc #0 + ret + +.globl call_sys_mkdir +call_sys_mkdir: + mov w8, #SYS_MKDIR + svc #0 + ret + +.globl call_sys_chdir +call_sys_chdir: + mov w8, #SYS_CHDIR + svc #0 + ret + +.globl call_sys_mount +call_sys_mount: + mov w8, #SYS_MOUNT + svc #0 + ret + +.globl call_sys_unmount +call_sys_unmount: + mov w8, #SYS_UNMOUNT + svc #0 + ret + +.globl call_sys_mmap +call_sys_mmap: + mov w8, #SYS_MMAP + svc #0 + ret + diff --git a/rootfs/virtual_memory_Lab8/Makefile b/rootfs/virtual_memory_Lab8/Makefile new file mode 100644 index 000000000..f5cb33bdf --- /dev/null +++ b/rootfs/virtual_memory_Lab8/Makefile @@ -0,0 +1,50 @@ +# Modify from +# https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary Lab8.img + +run: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio + +debug: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -initrd initramfs.cpio -serial null -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw -display none -S -s + +run_cpio: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio + +# run with sd card (Lab7) +run_sd: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw + +# run with cpio and sd card +run_all: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8/include/printf.h b/rootfs/virtual_memory_Lab8/include/printf.h new file mode 100644 index 000000000..22b125489 --- /dev/null +++ b/rootfs/virtual_memory_Lab8/include/printf.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); +void printf(char *fmt, ...); \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8/include/sys.h b/rootfs/virtual_memory_Lab8/include/sys.h new file mode 100644 index 000000000..93b546e21 --- /dev/null +++ b/rootfs/virtual_memory_Lab8/include/sys.h @@ -0,0 +1,78 @@ +#ifndef _SYS_H +#define _SYS_H + +#include "types.h" + +#define __NR_syscalls 20 + +#define SYS_PRINT_NUMBER 0 // syscal numbers +#define SYS_UARTWRITE_NUMBER 1 +#define SYS_UARTREAD_NUMBER 2 +#define SYS_GETPID_NUMBER 3 +#define SYS_FORK_NUMBER 4 +#define SYS_EXEC_NUMBER 5 +#define SYS_EXIT_NUMBER 6 +#define SYS_MALLOC_NUMBER 7 +#define SYS_CLONE_NUMBER 8 +#define SYS_CORETIMER_On 9 +#define SYS_CORETIMER_OFF 10 +#define SYS_OPEN 11 +#define SYS_CLOSE 12 +#define SYS_WRITE 13 +#define SYS_READ 14 +#define SYS_READ_DIRECTORY 15 +#define SYS_MKDIR 16 +#define SYS_CHDIR 17 +#define SYS_MOUNT 18 +#define SYS_UNMOUNT 19 + + +#ifndef __ASSEMBLER__ + +#define SYS_OPEN_FILE_ERROR -1 +#define SYS_WRITE_FILE_ERROR -1 +#define SYS_READ_FILE_ERROR -1 + +void sys_print(char * buf); +int sys_uart_write(char buf[], size_t size); +int sys_uart_read(char buf[], size_t size); +int sys_gitPID(); +int sys_fork(); +int sys_exec(const char* name, char* const argv[]); +void sys_exit(); +void *sys_malloc(int bytes); +int sys_clone(); +void sys_coreTimer_on(); +void sys_coreTimer_off(); +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +int sys_write(int fd, const void *buf, size_t len); +int sys_read(int fd, void *buf, size_t len); +char *sys_read_directory(int fd); +int sys_mkdir(const char *pathname); +int sys_chdir(const char *pathname); +int sys_mount(const char* device, const char* mountpoint, const char* filesystem); +int sys_unmount(const char* mountpoint); + +void call_sys_print(char * buf); +int call_sys_uart_write(char buf[], size_t size); +int call_sys_uart_read(char buf[], size_t size); +int call_sys_gitPID(); +int call_sys_fork(); +int call_sys_exec(const char* name, char* const argv[]); +void call_sys_exit(); +void* call_sys_malloc(); +void call_sys_coreTimer_on(); +void call_sys_coreTimer_off(); +int call_sys_open(const char *pathname, int flags); +int call_sys_close(int fd); +int call_sys_write(int fd, const void *buf, size_t len); +int call_sys_read(int fd, void *buf, size_t len); +char *call_sys_read_directory(int fd); +int call_sys_mkdir(const char *pathname); +int call_sys_chdir(const char *pathname); +int call_sys_mount(const char* device, const char* mountpoint, const char* filesystem); +int call_sys_unmount(const char* mountpoint); + +#endif /* __ASSEMBLER__ */ +#endif /*_SYS_H */ \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8/include/types.h b/rootfs/virtual_memory_Lab8/include/types.h new file mode 100644 index 000000000..7a6720fbc --- /dev/null +++ b/rootfs/virtual_memory_Lab8/include/types.h @@ -0,0 +1,30 @@ +#ifndef _KERNEL_TYPES_H +#define _KERNEL_TYPES_H + +#ifndef __ASSEMBLER__ + +typedef signed char int8_t; +typedef signed short int int16_t; +typedef signed int int32_t; +typedef signed long int int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long int uint64_t; + +typedef unsigned int size_t; + +typedef long pid_t; // task pid + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define TRUE 1 +#define FALSE 0 + +#define EOF -1 + +#endif /* __ASSEMBLER__ */ +#endif \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8/linker.ld b/rootfs/virtual_memory_Lab8/linker.ld new file mode 100644 index 000000000..32aac14c5 --- /dev/null +++ b/rootfs/virtual_memory_Lab8/linker.ld @@ -0,0 +1,20 @@ + +SECTIONS +{ + . = 0x0; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8/src/Lab8.c b/rootfs/virtual_memory_Lab8/src/Lab8.c new file mode 100644 index 000000000..04bb0cad1 --- /dev/null +++ b/rootfs/virtual_memory_Lab8/src/Lab8.c @@ -0,0 +1,30 @@ +#include "printf.h" +#include "sys.h" + +int main(void) { + printf("[Lab8.c] User program here!\n"); + + int cnt = 0; + if(call_sys_fork() == 0) { + printf("[Lab8.c] Child here, pid: %d!\n", call_sys_gitPID()); + call_sys_fork(); + call_sys_fork(); + while(cnt < 10) { + printf("pid: %d, sp: 0x%x cnt: %d\n", call_sys_gitPID(), &cnt, cnt++); // address should be the same, but the cnt should be increased indepndently + } + if (call_sys_gitPID() == 2) { + printf("[Lab8.c] Call exec syscall...\n"); + char *fork_argv[] = {"Lab8_2.img", "87", 0}; + call_sys_exec("Lab8_2", fork_argv); + printf("[Lab8.c] After exec, should not be printed\n"); + } + call_sys_exit(); + } else { + printf("[Lab8.c] Parent here, pid: %d!\n", call_sys_gitPID()); + int *a = (int *)(0x1000 * 16); // a non-mapped address. + printf("%d\n", *a); // trigger simple page fault. + printf("[Lab8.c] Should not be printed\n"); + } + + return 0; +} \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8/src/printf.c b/rootfs/virtual_memory_Lab8/src/printf.c new file mode 100644 index 000000000..3a0272847 --- /dev/null +++ b/rootfs/virtual_memory_Lab8/src/printf.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "printf.h" +#include "sys.h" +/** + * minimal sprintf implementation + */ +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} + +/** + * Display a string + */ +void printf(char *fmt, ...) { + __builtin_va_list args; + __builtin_va_start(args, fmt); + // we don't have memory allocation yet, so we + // simply place our string after our code + char s[200]; + // use sprintf to format our string + vsprintf(s,fmt,args); + // print out as usual + call_sys_print(s); +} diff --git a/rootfs/virtual_memory_Lab8/src/start.S b/rootfs/virtual_memory_Lab8/src/start.S new file mode 100644 index 000000000..52914aa50 --- /dev/null +++ b/rootfs/virtual_memory_Lab8/src/start.S @@ -0,0 +1,11 @@ +.section ".text.boot" + +.global _start +_start: + bl main // jump to main functoin in C code, should not return + b proc_hang // for failsafe, halt this core too (Should never do this instruction) + +proc_hang: + wfe // hang for all noo-primary CPU and enter low power mode + b proc_hang + diff --git a/rootfs/virtual_memory_Lab8/src/sys.S b/rootfs/virtual_memory_Lab8/src/sys.S new file mode 100644 index 000000000..10b841201 --- /dev/null +++ b/rootfs/virtual_memory_Lab8/src/sys.S @@ -0,0 +1,116 @@ +#include "sys.h" + +.globl call_sys_print +call_sys_print: + mov w8, #SYS_PRINT_NUMBER + svc #0 + ret + +.globl call_sys_uart_write +call_sys_uart_write: + mov w8, #SYS_UARTWRITE_NUMBER + svc #0 + ret + +.globl call_sys_uart_read +call_sys_uart_read: + mov w8, #SYS_UARTREAD_NUMBER + svc #0 + ret + +.globl call_sys_gitPID +call_sys_gitPID: + mov w8, #SYS_GETPID_NUMBER + svc #0 + ret + +.globl call_sys_fork +call_sys_fork: + mov w8, #SYS_FORK_NUMBER + svc #0 + ret + +.globl call_sys_exec +call_sys_exec: + mov w8, #SYS_EXEC_NUMBER + svc #0 + ret + +.globl call_sys_exit +call_sys_exit: + mov w8, #SYS_EXIT_NUMBER + svc #0 + ret + +.globl call_sys_malloc +call_sys_malloc: + mov w8, #SYS_MALLOC_NUMBER + svc #0 + ret + +.globl call_sys_coreTimer_on +call_sys_coreTimer_on: + mov w8, #SYS_CORETIMER_On + svc #0 + ret + +.globl call_sys_coreTimer_off +call_sys_coreTimer_off: + mov w8, #SYS_CORETIMER_OFF + svc #0 + ret + +.globl call_sys_open +call_sys_open: + mov w8, #SYS_OPEN + svc #0 + ret + +.globl call_sys_close +call_sys_close: + mov w8, #SYS_CLOSE + svc #0 + ret + +.globl call_sys_write +call_sys_write: + mov w8, #SYS_WRITE + svc #0 + ret + +.globl call_sys_read +call_sys_read: + mov w8, #SYS_READ + svc #0 + ret + +.globl call_sys_read_directory +call_sys_read_directory: + mov w8, #SYS_READ_DIRECTORY + svc #0 + ret + +.globl call_sys_mkdir +call_sys_mkdir: + mov w8, #SYS_MKDIR + svc #0 + ret + +.globl call_sys_chdir +call_sys_chdir: + mov w8, #SYS_CHDIR + svc #0 + ret + +.globl call_sys_mount +call_sys_mount: + mov w8, #SYS_MOUNT + svc #0 + ret + +.globl call_sys_unmount +call_sys_unmount: + mov w8, #SYS_UNMOUNT + svc #0 + ret + diff --git a/rootfs/virtual_memory_Lab8_2/Makefile b/rootfs/virtual_memory_Lab8_2/Makefile new file mode 100644 index 000000000..9321f6ea1 --- /dev/null +++ b/rootfs/virtual_memory_Lab8_2/Makefile @@ -0,0 +1,50 @@ +# Modify from +# https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary Lab8_2.img + +run: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio + +debug: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -initrd initramfs.cpio -serial null -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw -display none -S -s + +run_cpio: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio + +# run with sd card (Lab7) +run_sd: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw + +# run with cpio and sd card +run_all: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -drive if=sd,file=./sdcard/sfn_nctuos.img,format=raw \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8_2/include/printf.h b/rootfs/virtual_memory_Lab8_2/include/printf.h new file mode 100644 index 000000000..22b125489 --- /dev/null +++ b/rootfs/virtual_memory_Lab8_2/include/printf.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); +void printf(char *fmt, ...); \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8_2/include/sys.h b/rootfs/virtual_memory_Lab8_2/include/sys.h new file mode 100644 index 000000000..93b546e21 --- /dev/null +++ b/rootfs/virtual_memory_Lab8_2/include/sys.h @@ -0,0 +1,78 @@ +#ifndef _SYS_H +#define _SYS_H + +#include "types.h" + +#define __NR_syscalls 20 + +#define SYS_PRINT_NUMBER 0 // syscal numbers +#define SYS_UARTWRITE_NUMBER 1 +#define SYS_UARTREAD_NUMBER 2 +#define SYS_GETPID_NUMBER 3 +#define SYS_FORK_NUMBER 4 +#define SYS_EXEC_NUMBER 5 +#define SYS_EXIT_NUMBER 6 +#define SYS_MALLOC_NUMBER 7 +#define SYS_CLONE_NUMBER 8 +#define SYS_CORETIMER_On 9 +#define SYS_CORETIMER_OFF 10 +#define SYS_OPEN 11 +#define SYS_CLOSE 12 +#define SYS_WRITE 13 +#define SYS_READ 14 +#define SYS_READ_DIRECTORY 15 +#define SYS_MKDIR 16 +#define SYS_CHDIR 17 +#define SYS_MOUNT 18 +#define SYS_UNMOUNT 19 + + +#ifndef __ASSEMBLER__ + +#define SYS_OPEN_FILE_ERROR -1 +#define SYS_WRITE_FILE_ERROR -1 +#define SYS_READ_FILE_ERROR -1 + +void sys_print(char * buf); +int sys_uart_write(char buf[], size_t size); +int sys_uart_read(char buf[], size_t size); +int sys_gitPID(); +int sys_fork(); +int sys_exec(const char* name, char* const argv[]); +void sys_exit(); +void *sys_malloc(int bytes); +int sys_clone(); +void sys_coreTimer_on(); +void sys_coreTimer_off(); +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +int sys_write(int fd, const void *buf, size_t len); +int sys_read(int fd, void *buf, size_t len); +char *sys_read_directory(int fd); +int sys_mkdir(const char *pathname); +int sys_chdir(const char *pathname); +int sys_mount(const char* device, const char* mountpoint, const char* filesystem); +int sys_unmount(const char* mountpoint); + +void call_sys_print(char * buf); +int call_sys_uart_write(char buf[], size_t size); +int call_sys_uart_read(char buf[], size_t size); +int call_sys_gitPID(); +int call_sys_fork(); +int call_sys_exec(const char* name, char* const argv[]); +void call_sys_exit(); +void* call_sys_malloc(); +void call_sys_coreTimer_on(); +void call_sys_coreTimer_off(); +int call_sys_open(const char *pathname, int flags); +int call_sys_close(int fd); +int call_sys_write(int fd, const void *buf, size_t len); +int call_sys_read(int fd, void *buf, size_t len); +char *call_sys_read_directory(int fd); +int call_sys_mkdir(const char *pathname); +int call_sys_chdir(const char *pathname); +int call_sys_mount(const char* device, const char* mountpoint, const char* filesystem); +int call_sys_unmount(const char* mountpoint); + +#endif /* __ASSEMBLER__ */ +#endif /*_SYS_H */ \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8_2/include/types.h b/rootfs/virtual_memory_Lab8_2/include/types.h new file mode 100644 index 000000000..7a6720fbc --- /dev/null +++ b/rootfs/virtual_memory_Lab8_2/include/types.h @@ -0,0 +1,30 @@ +#ifndef _KERNEL_TYPES_H +#define _KERNEL_TYPES_H + +#ifndef __ASSEMBLER__ + +typedef signed char int8_t; +typedef signed short int int16_t; +typedef signed int int32_t; +typedef signed long int int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long int uint64_t; + +typedef unsigned int size_t; + +typedef long pid_t; // task pid + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define TRUE 1 +#define FALSE 0 + +#define EOF -1 + +#endif /* __ASSEMBLER__ */ +#endif \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8_2/linker.ld b/rootfs/virtual_memory_Lab8_2/linker.ld new file mode 100644 index 000000000..32aac14c5 --- /dev/null +++ b/rootfs/virtual_memory_Lab8_2/linker.ld @@ -0,0 +1,20 @@ + +SECTIONS +{ + . = 0x0; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8_2/src/Lab8_2.c b/rootfs/virtual_memory_Lab8_2/src/Lab8_2.c new file mode 100644 index 000000000..5531ecd0c --- /dev/null +++ b/rootfs/virtual_memory_Lab8_2/src/Lab8_2.c @@ -0,0 +1,10 @@ +#include "printf.h" +#include "sys.h" + +int main(int argc, char **argv) { + printf("[Lab8_2.c] Here exec syscall success!\n"); + + call_sys_exit(); + + return -1; +} \ No newline at end of file diff --git a/rootfs/virtual_memory_Lab8_2/src/printf.c b/rootfs/virtual_memory_Lab8_2/src/printf.c new file mode 100644 index 000000000..3a0272847 --- /dev/null +++ b/rootfs/virtual_memory_Lab8_2/src/printf.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "printf.h" +#include "sys.h" +/** + * minimal sprintf implementation + */ +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} + +/** + * Display a string + */ +void printf(char *fmt, ...) { + __builtin_va_list args; + __builtin_va_start(args, fmt); + // we don't have memory allocation yet, so we + // simply place our string after our code + char s[200]; + // use sprintf to format our string + vsprintf(s,fmt,args); + // print out as usual + call_sys_print(s); +} diff --git a/rootfs/virtual_memory_Lab8_2/src/start.S b/rootfs/virtual_memory_Lab8_2/src/start.S new file mode 100644 index 000000000..52914aa50 --- /dev/null +++ b/rootfs/virtual_memory_Lab8_2/src/start.S @@ -0,0 +1,11 @@ +.section ".text.boot" + +.global _start +_start: + bl main // jump to main functoin in C code, should not return + b proc_hang // for failsafe, halt this core too (Should never do this instruction) + +proc_hang: + wfe // hang for all noo-primary CPU and enter low power mode + b proc_hang + diff --git a/rootfs/virtual_memory_Lab8_2/src/sys.S b/rootfs/virtual_memory_Lab8_2/src/sys.S new file mode 100644 index 000000000..10b841201 --- /dev/null +++ b/rootfs/virtual_memory_Lab8_2/src/sys.S @@ -0,0 +1,116 @@ +#include "sys.h" + +.globl call_sys_print +call_sys_print: + mov w8, #SYS_PRINT_NUMBER + svc #0 + ret + +.globl call_sys_uart_write +call_sys_uart_write: + mov w8, #SYS_UARTWRITE_NUMBER + svc #0 + ret + +.globl call_sys_uart_read +call_sys_uart_read: + mov w8, #SYS_UARTREAD_NUMBER + svc #0 + ret + +.globl call_sys_gitPID +call_sys_gitPID: + mov w8, #SYS_GETPID_NUMBER + svc #0 + ret + +.globl call_sys_fork +call_sys_fork: + mov w8, #SYS_FORK_NUMBER + svc #0 + ret + +.globl call_sys_exec +call_sys_exec: + mov w8, #SYS_EXEC_NUMBER + svc #0 + ret + +.globl call_sys_exit +call_sys_exit: + mov w8, #SYS_EXIT_NUMBER + svc #0 + ret + +.globl call_sys_malloc +call_sys_malloc: + mov w8, #SYS_MALLOC_NUMBER + svc #0 + ret + +.globl call_sys_coreTimer_on +call_sys_coreTimer_on: + mov w8, #SYS_CORETIMER_On + svc #0 + ret + +.globl call_sys_coreTimer_off +call_sys_coreTimer_off: + mov w8, #SYS_CORETIMER_OFF + svc #0 + ret + +.globl call_sys_open +call_sys_open: + mov w8, #SYS_OPEN + svc #0 + ret + +.globl call_sys_close +call_sys_close: + mov w8, #SYS_CLOSE + svc #0 + ret + +.globl call_sys_write +call_sys_write: + mov w8, #SYS_WRITE + svc #0 + ret + +.globl call_sys_read +call_sys_read: + mov w8, #SYS_READ + svc #0 + ret + +.globl call_sys_read_directory +call_sys_read_directory: + mov w8, #SYS_READ_DIRECTORY + svc #0 + ret + +.globl call_sys_mkdir +call_sys_mkdir: + mov w8, #SYS_MKDIR + svc #0 + ret + +.globl call_sys_chdir +call_sys_chdir: + mov w8, #SYS_CHDIR + svc #0 + ret + +.globl call_sys_mount +call_sys_mount: + mov w8, #SYS_MOUNT + svc #0 + ret + +.globl call_sys_unmount +call_sys_unmount: + mov w8, #SYS_UNMOUNT + svc #0 + ret + diff --git a/sdcard/BIG1518.TXT b/sdcard/BIG1518.TXT new file mode 100644 index 000000000..4c78a8c67 --- /dev/null +++ b/sdcard/BIG1518.TXT @@ -0,0 +1 @@ +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 diff --git a/sdcard/FATTEST.TXT b/sdcard/FATTEST.TXT new file mode 100644 index 000000000..9856e81ba --- /dev/null +++ b/sdcard/FATTEST.TXT @@ -0,0 +1 @@ +Fat32 Test file Content. diff --git a/sdcard/sfn_nctuos.img b/sdcard/sfn_nctuos.img new file mode 100644 index 000000000..0f87a3963 Binary files /dev/null and b/sdcard/sfn_nctuos.img differ diff --git a/src/command.c b/src/command.c index e617ba297..031faaef2 100755 --- a/src/command.c +++ b/src/command.c @@ -98,7 +98,7 @@ void command_getCpioFile(void *initramfs_addr, char *buf) void command_cpio_svc() { unsigned long fileSize; - char *result = cpio_get_file((void *) INITRAMFS_ADDR, "test_svc.elf", &fileSize); + char *result = cpio_get_file(INITRAMFS_ADDR, "test_svc.elf", &fileSize); char *program_address = result + 120; printf("cpio starting addres0x{%x}\n", result); diff --git a/src/entry.S b/src/entry.S index faadf1b70..b1a7480b2 100644 --- a/src/entry.S +++ b/src/entry.S @@ -158,62 +158,90 @@ error_invalid_el0_32: /* Synchronous and IRQ handler */ el1_sync_exc_handler: kernel_entry 1 - mrs x25, esr_el1 // read the syndrome register - lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class - cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state + mrs x25, esr_el1 // read the syndrome register + lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class + cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state b.eq el1_svc + cmp x24, #ESR_ELx_EC_DABT_SAME_LEVEL // Data Abort taken without a change in Exception level. (or page fault exception in our OS want to handle) + b.eq el1_da handle_invalid_entry 1, SYNC_ERROR -sc_nr .req x25 // number of system calls -scno .req x26 // syscall number -stbl .req x27 // syscall table pointer +sc_nr .req x25 // number of system calls +scno .req x26 // syscall number +stbl .req x27 // syscall table pointer el1_svc: - adr stbl, sys_call_table // load syscall table pointer - uxtw scno, w8 // syscall number in w8 + adr stbl, sys_call_table // load syscall table pointer + uxtw scno, w8 // syscall number in w8 mov sc_nr, #__NR_syscalls bl enable_irq - cmp scno, sc_nr // check upper syscall limit + cmp scno, sc_nr // check upper syscall limit b.hs ni_sys - ldr x16, [stbl, scno, lsl #3] // address in the syscall table - blr x16 // call sys_* routine + ldr x16, [stbl, scno, lsl #3] // address in the syscall table + blr x16 // call sys_* routine b el1_ret_from_syscall el1_ni_sys: // non-existent syscall handle_invalid_entry 1, SYSCALL_ERROR el1_ret_from_syscall: bl disable_irq - str x0, [sp, #S_X0] // save returned x0 + str x0, [sp, #S_X0] // save returned x0 + kernel_exit 1 + +el1_da: + bl enable_irq + mrs x0, far_el1 + mrs x1, esr_el1 + bl do_mem_abort + cmp x0, 0 + b.eq 1f + handle_invalid_entry 1, DATA_ABORT_ERROR +1: + bl disable_irq kernel_exit 1 el0_sync_exc_handler: kernel_entry 0 - mrs x25, esr_el1 // read the syndrome register - lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class - cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state + mrs x25, esr_el1 // read the syndrome register + lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class + cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state b.eq el0_svc + cmp x24, #ESR_ELx_EC_DABT_LOW // Data Abort from a lower Exception level. (or page fault exception in our OS want to handle) + b.eq el0_da handle_invalid_entry 0, SYNC_ERROR - -sc_nr .req x25 // number of system calls -scno .req x26 // syscall number -stbl .req x27 // syscall table pointer + +sc_nr .req x25 // number of system calls +scno .req x26 // syscall number +stbl .req x27 // syscall table pointer el0_svc: - adr stbl, sys_call_table // load syscall table pointer - uxtw scno, w8 // syscall number in w8 + adr stbl, sys_call_table // load syscall table pointer + uxtw scno, w8 // syscall number in w8 mov sc_nr, #__NR_syscalls bl enable_irq - cmp scno, sc_nr // check upper syscall limit + cmp scno, sc_nr // check upper syscall limit b.hs ni_sys - ldr x16, [stbl, scno, lsl #3] // address in the syscall table - blr x16 // call sys_* routine + ldr x16, [stbl, scno, lsl #3] // address in the syscall table + blr x16 // call sys_* routine b ret_from_syscall ni_sys: // non-existent syscall handle_invalid_entry 0, SYSCALL_ERROR ret_from_syscall: bl disable_irq - str x0, [sp, #S_X0] // save returned x0 + str x0, [sp, #S_X0] // save returned x0 + kernel_exit 0 + +el0_da: + bl enable_irq + mrs x0, far_el1 + mrs x1, esr_el1 + bl do_mem_abort + cmp x0, 0 + b.eq 1f + handle_invalid_entry 0, DATA_ABORT_ERROR +1: + bl disable_irq kernel_exit 0 irq_exc_handler: @@ -224,8 +252,8 @@ irq_exc_handler: .globl ret_from_fork ret_from_fork: - bl schedule_tail // enabled preemption - cbz x19, ret_to_user // not a kernel thread + bl schedule_tail // enabled preemption + cbz x19, ret_to_user // not a kernel thread mov x0, x20 blr x19 ret_to_user: @@ -234,31 +262,31 @@ ret_to_user: .globl enable_irq_persist enable_irq_persist: - mov x2, x30 // store return address + mov x2, x30 // store return address bl enable_irq mov x30, x2 mrs x0, spsr_el1 mov x1, 0b01111111 and x0, x0, x1 - msr spsr_el1, x0 // set irq bit enable + msr spsr_el1, x0 // set irq bit enable ret .globl disable_irq_persist disable_irq_persist: - mov x2, x30 // store return address + mov x2, x30 // store return address bl disable_irq mov x30, x2 mrs x0, spsr_el1 mov x1, 0b10000000 orr x0, x0, x1 - msr spsr_el1, x0 // set irq bit disable + msr spsr_el1, x0 // set irq bit disable ret .globl enable_irq enable_irq: - msr daifclr, #2 // enable irq to current processor state + msr daifclr, #2 // enable irq to current processor state ret .globl disable_irq diff --git a/src/fat32.c b/src/fat32.c new file mode 100644 index 000000000..82439f5b4 --- /dev/null +++ b/src/fat32.c @@ -0,0 +1,617 @@ +#include "fat32.h" +#include "vfs.h" +#include "printf.h" +#include "list.h" +#include "string.h" +#include "mm.h" +#include "types.h" +#include "sdhost.h" + +struct vnode_operations *fat32_v_ops = NULL; +struct file_operations *fat32_f_ops = NULL; + +struct fat32_metadata fat32_metadata; // For sd card fat32 metadata + +static inline uint32_t _get_cluster_blk_idx(unsigned int cluster_index) +{ + return fat32_metadata.data_region_blk_idx + + (cluster_index - fat32_metadata.rootDir_first_cluster) * fat32_metadata.sector_per_cluster; +} + +// Given cluster idx, return block(sector) idx of FAT table entry +static inline uint32_t _get_FAT_entry_blk_idx(unsigned int cluster_index) +{ + return fat32_metadata.fat_region_blk_idx + (cluster_index / FAT32_ENTRY_PER_BLOCK); +} + +// Given fat entry(blk idx and entry idx) then return corresponding cluster num +static inline uint32_t _get_cluster_num_by_fat_entry(int *free_FAT_entry_blk_idx, int *entry_idx) +{ + return fat32_metadata.rootDir_first_cluster + + (*free_FAT_entry_blk_idx - fat32_metadata.fat_region_blk_idx)*FAT32_ENTRY_PER_BLOCK + + *entry_idx; +} + +int _find_next_cluster_blk_idx(uint32_t cur_cluster_num) +{ + int FAT_table[FAT32_ENTRY_PER_BLOCK]; + uint32_t next_cluster_num = 0; + uint32_t target_FAT_block_idx = _get_FAT_entry_blk_idx(cur_cluster_num); + readblock(target_FAT_block_idx, (void *)FAT_table); + next_cluster_num = FAT_table[cur_cluster_num % FAT32_ENTRY_PER_BLOCK]; + + #ifdef __FS_DEBUG + for (int i = 0;i < FAT32_ENTRY_PER_BLOCK;i++) { + printf("%d |", FAT_table[i]); + } + printf("\n"); + printf("[_find_next_cluster_blk_idx] fat32_metadata.fat_region_blk_idx = %d\n", fat32_metadata.fat_region_blk_idx); + printf("[_find_next_cluster_blk_idx] cur_cluster_num = %d\n", cur_cluster_num); + printf("[_find_next_cluster_blk_idx] target_FAT_block_idx = %u\n", target_FAT_block_idx); + printf("[_find_next_cluster_blk_idx] next_cluster_num = 0x%x\n", next_cluster_num); + #endif //__DEBUG + + return next_cluster_num; +} + +int _get_empty_FAT_table_entry(int *free_FAT_entry_blk_idx, int *entry_idx) +{ + int isFound = FALSE; + int FAT_table[FAT32_ENTRY_PER_BLOCK]; + + // Iteratively search FAT table + // Here only search first FAT table + uint32_t fat_region_blk_idx = fat32_metadata.fat_region_blk_idx; + for (int i = 0;i < fat32_metadata.sector_per_fat;i++) { + int cur_fat_blk_idx = fat_region_blk_idx + i; + readblock(fat_region_blk_idx + i, (void *)FAT_table); + + // Find if there are free fat entry in this block (sector) + for (int j = 0;j < FAT32_ENTRY_PER_BLOCK;j++) { + if (FAT_table[j] == 0x00) { + isFound = TRUE; + *free_FAT_entry_blk_idx = cur_fat_blk_idx; + *entry_idx = j; + + printf("[_get_empty_FAT_table_entry] Find out empty FAT table entry\n"); + printf("[_get_empty_FAT_table_entry] free_FAT_entry_blk_idx = %d\n", *free_FAT_entry_blk_idx); + printf("[_get_empty_FAT_table_entry] entry_idx = %d\n", *entry_idx); + + break; + } + } + + if (isFound) break; + } + + return isFound; +} + +int _set_FAT_table_entry(int *free_FAT_entry_blk_idx, int *entry_idx, uint32_t val) +{ + int FAT_table[FAT32_ENTRY_PER_BLOCK]; + readblock(*free_FAT_entry_blk_idx, (void *)FAT_table); + + FAT_table[*entry_idx] = val; + + return TRUE; +} + +int _get_empty_FAT_dir_entry_by_clusterNum(uint32_t cluster_num, int *free_FAT_dir_entry_blk_idx, int *entry_idx) +{ + int isFound = FALSE; + char sector_buf[BLOCK_SIZE]; + + // Iteratively search FAT Directory block(secotr) + // Here we only search free directory first cluster for easy. + *free_FAT_dir_entry_blk_idx = _get_cluster_blk_idx(cluster_num); + readblock(*free_FAT_dir_entry_blk_idx, sector_buf); + struct fat32_dirEnt *sector_dirEnt = (struct fat32_dirEnt *)sector_buf; + for (int i = 0;i < FAT32_DIRECTORY_ENTRY_PER_BLOCK;i++) { + // Special value, it's a empty entry + printf("[_get_empty_FAT_dir_entry_by_clusterNum] sector_dirEnt[%d].name[0] = 0x%x\n", i, sector_dirEnt[i].name[0] ); + if (sector_dirEnt[i].name[0] == 0x00) { + isFound = TRUE; + *entry_idx = i; + break; + } + } + + printf("[_get_empty_FAT_dir_entry_by_clusterNum] free_FAT_dir_entry_blk_idx = %d\n", *free_FAT_dir_entry_blk_idx); + return isFound; +} + +int _set_FAT_dir_entry(int *free_FAT_dir_entry_blk_idx, int *dir_entry_idx, struct fat32_dirEnt *new_fat_dirEnt) +{ + char sector_buf[BLOCK_SIZE]; + readblock(*free_FAT_dir_entry_blk_idx, sector_buf); + struct fat32_dirEnt *sector_dirEnt = (struct fat32_dirEnt *)sector_buf; + sector_dirEnt[*dir_entry_idx] = *new_fat_dirEnt; + + // write back to sd card + writeblock(*free_FAT_dir_entry_blk_idx, sector_buf); + + return TRUE; +} + +struct fat32_dirEnt *_create_fat32_dirEnt(const char *filename, uint8_t FileAttributes, uint32_t new_first_cluster_num, uint32_t fileSize) +{ + struct fat32_dirEnt *new_fat_dirEnt = (struct fat32_dirEnt *) kmalloc(sizeof(struct fat32_dirEnt)); + memzero((unsigned long)new_fat_dirEnt, sizeof(struct fat32_dirEnt)); + + /* Config directory entry */ + // parse Short file name (padded with spaces) + int filename_len = strlen(filename); + int cur_f_idx = 0; + for (int i = 0;i < 8;i++) { + if (filename[cur_f_idx] == '.') + new_fat_dirEnt->name[i] = ' '; + else { + new_fat_dirEnt->name[i] = filename[cur_f_idx++]; + } + } + cur_f_idx++; // skip dot + // Short file extension (padded with spaces) + for (int i = 8;i < 11;i++) { + if (i > filename_len) { + new_fat_dirEnt->name[i] = ' '; + } + new_fat_dirEnt->name[i] = filename[cur_f_idx++]; + } + // Other field + new_fat_dirEnt->attr = FileAttributes; + new_fat_dirEnt->cluster_high = new_first_cluster_num >> 16; + new_fat_dirEnt->cluster_low = new_first_cluster_num & 0xFFFF; + new_fat_dirEnt->size = fileSize; + + return new_fat_dirEnt; +} + +struct dentry* fat32_create_dentry(struct dentry *parent, const char *name, int type) +{ + //printf("[fat32_create_dentry]\n"); + + struct dentry *d = (struct dentry *) kmalloc(sizeof(struct dentry)); + + strcpy(d->name, name); + d->parent = parent; + d->vnode = fat32_create_vnode(d, type); + INIT_LIST_HEAD(&d->list); + INIT_LIST_HEAD(&d->sub_dirs); + // set parent's child list point to this new created dentry + if (parent != NULL) { + list_add(&d->list, &parent->sub_dirs); + } + + d->mount = NULL; + + return d; +} + +struct vnode* fat32_create_vnode(struct dentry *dentry, int type) +{ + //printf("[tmpfs_create_vnode]\n"); + struct vnode *vnode = (struct vnode*) kmalloc(sizeof(struct vnode)); + vnode->dentry = dentry; + vnode->v_type = type; + vnode->v_ops = fat32_v_ops; + vnode->f_ops = fat32_f_ops; + vnode->internal = NULL; + + return vnode; +} + + +int fat32_register() +{ + if (fat32_v_ops != NULL && fat32_f_ops != NULL) { + return FAT32_ERROR; // Register error + } + + // vnode operations + fat32_v_ops = (struct vnode_operations *) kmalloc(sizeof(struct vnode_operations)); + fat32_v_ops->lookup = fat32_lookup; + fat32_v_ops->create = fat32_create; + fat32_v_ops->mkdir = fat32_mkdir; + + // file operations + fat32_f_ops = (struct file_operations *) kmalloc(sizeof(struct file_operations)); + fat32_f_ops->write = fat32_write; + fat32_f_ops->read = fat32_read; + + return 0; +} + +int fat32_setup_mount(struct filesystem* fs, struct mount* mount, const char *component_name) +{ + // printf("[fat32_setup_mount]\n"); + mount->fs = fs; + mount->root = fat32_create_dentry(NULL, component_name, DIRECTORY); + + printf("[fat32_setup_mount] Setup tmpfs, New created dentry name = %s\n", mount->root->name); + + return TRUE; +} + +/** + * load all subdirectory under specified directory(dir_node) from sdcard device + */ +void _fat32_load_dentry_from_device(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + printf("[_fat32_try_load_dentry_from_device]\n"); + + // Read first block of first cluster + uint8_t sector_buf[BLOCK_SIZE]; + struct fat32_internal *dir_internal= (struct fat32_internal *) dir_node->internal; + uint32_t dirEntry_blk_idx = _get_cluster_blk_idx(dir_internal->first_cluster); + readblock(dirEntry_blk_idx, sector_buf); + + #ifdef __FS_DEBUG + _dump_fat32_internal(dir_internal); + #endif + + struct fat32_dirEnt *sector_dirEnt = (struct fat32_dirEnt *)sector_buf; + for (int i = 0;sector_dirEnt[i].name[0] != 0x00 && i < FAT32_DIRECTORY_ENTRY_PER_BLOCK;i++) { // Search until special value (0x00 for first byte) as fat23 spec + // Special value, it's a deleted/unused entry + if (sector_dirEnt[i].name[0] == 0xE5) { + continue; + } + + // Extract filename + char filename[13 + 1]; // 13 (SFN) + 1 ('\0') + int f_len = 0; + for (int j = 0;j < 8;j++) { + char c = sector_dirEnt[i].name[j]; + if (c == ' ') { // end + break; + } + filename[f_len++] = c; + } + filename[f_len++] = '.'; + for (int j = 0;j < 3;j++) { + char c = sector_dirEnt[i].ext[j]; + if (c == ' ') { + break; + } + filename[f_len++] = c; + } + filename[f_len++] = '\0'; + + // Check if file (dentry) have been loaded in memory + struct dentry *dir_dentry = dir_node->dentry; + struct dentry *pos; + int isDentryExist = FALSE; + list_for_each_entry(pos, &dir_dentry->sub_dirs, list) { + #ifdef __FS_DEBUG + printf("[fat32_lookup] pos->name = %s\n", pos->name); + #endif //__DEBUG + if (!strcmp(pos->name, filename)) { + *target = pos->vnode; + isDentryExist = TRUE; + break; + } + } + if (isDentryExist) { + #ifdef __FS_DEBUG + printf("[_fat32_load_dentry_from_device] '%s' exist!\n", filename); + #endif //__DEBUG + continue; + } + + // If file(directory or regular file) not exist, create a new one in memory + struct dentry *new_dentry = NULL; + if (sector_dirEnt[i].attr == DIRECTORY_ENTRY_ATTR_DIRECTORY) + new_dentry = fat32_create_dentry(dir_node->dentry, filename, DIRECTORY); + else + new_dentry = fat32_create_dentry(dir_node->dentry, filename, REGULAR_FILE); + + #ifdef __FS_DEBUG + printf("Seach directory entry in sector | i = %d, filename = %s\n", i, filename); + #endif + + // assign fat32 internal info for the new child dentry + struct fat32_internal *internal = (struct fat32_internal *) kmalloc(sizeof(struct fat32_internal)); + internal->first_cluster = (sector_dirEnt[i].cluster_high << 16) | (sector_dirEnt[i].cluster_low); + internal->dirEntry_blk_idx = dirEntry_blk_idx; + internal->size = sector_dirEnt[i].size; + + new_dentry->vnode->internal = internal; + + #ifdef __FS_DEBUG + _dump_fat32_internal(internal); + #endif + } + + return; +} + +int fat32_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + #ifdef __FS_DEBUG + printf("[fat32_lookup]\n"); + #endif //__DEBUG + + int isNextVnodeFound = FALSE; + struct dentry *dir_dentry = dir_node->dentry; + struct dentry *pos; + + list_for_each_entry(pos, &dir_dentry->sub_dirs, list) { + #ifdef __FS_DEBUG + printf("[fat32_lookup] pos->name = %s\n", pos->name); + #endif //__DEBUG + if (!strcmp(pos->name, component_name)) { + *target = pos->vnode; + isNextVnodeFound = TRUE; + break; + } + } + + if (!isNextVnodeFound) // If next vnode not found + { + // load all subdirectory under specify directory from sdcard device + _fat32_load_dentry_from_device(dir_node, target, component_name); + + // retry to find the next vnode + list_for_each_entry(pos, &dir_dentry->sub_dirs, list) { + #ifdef __FS_DEBUG + printf("[fat32_lookup] pos->name = %s\n", pos->name); + #endif //__FS_DEBUG + if (!strcmp(pos->name, component_name)) { + *target = pos->vnode; + isNextVnodeFound = TRUE; + break; + } + } + } + + return isNextVnodeFound; + +} + +int fat32_read(struct file *file, void *buf, size_t len) +{ + #ifdef __FS_DEBUG + printf("[fat32_read] file->f_pos = %d\n", file->f_pos); + #endif //__DEBUG + + char *dest = (char *)buf; + + char sector_buf[BLOCK_SIZE]; + struct fat32_internal *internal = file->vnode->internal; + uint32_t contentSize = internal->size; + size_t cur_read_count = 0; // record how many bytes have been read + + uint32_t current_cluster_num = internal->first_cluster; + for (int i = 0;i < file->f_pos / BLOCK_SIZE;i++) { // get the right cluster to start with for file read + current_cluster_num = _find_next_cluster_blk_idx(current_cluster_num); + } + + // read until meet len needed to write, reach file's content size, or reach end-of-cluster-chain marker + int isMeetReadLen = (cur_read_count >= len); + int isReachContentSize = file->f_pos >= contentSize; + int isReachEndOfCluster = FALSE; // Maybe it's redundant. Same logic as isReachContentSize here? + while (!isMeetReadLen && !isReachContentSize && !isReachEndOfCluster) { + + // read data from sd carddevice + readblock(_get_cluster_blk_idx(current_cluster_num), sector_buf); + + // Calculate how many char this iteration we needed to read + // We need to determine how many bytes we still can read in this iteration, choose the smallest one in following: + // 1. How many char we still want to read + // 2. How many char we still can read from this block (sector) + // 3. How many byte left in entire file. + uint32_t charStillNeedReadSize = len - cur_read_count; // 1. + uint32_t contentLeftInCurBlock = BLOCK_SIZE - (file->f_pos % BLOCK_SIZE); // 2. + uint32_t remainingContectSize = contentSize - file->f_pos; // 3. + uint32_t charNeeded = (charStillNeedReadSize < contentLeftInCurBlock) ? charStillNeedReadSize : contentLeftInCurBlock; + charNeeded = (charNeeded > remainingContectSize) ? remainingContectSize: charNeeded; + + #ifdef __FS_DEBUG + printf("[fat32_read] contentSize= %d\n", contentSize); + printf("[fat32_read] charNeeded = %d\n", charNeeded); + #endif + + // copy content to buf + int sector_buf_start_idx = file->f_pos % BLOCK_SIZE; + for (int i = 0;i < charNeeded;i++) { + #ifdef __FS_DEBUG + if (i % 10 == 0) + printf("[fat32_read] i = %d, ch = %c\n", i, sector_buf[sector_buf_start_idx + i]); + #endif + dest[cur_read_count++] = sector_buf[sector_buf_start_idx + i]; + } + + // update to next cluster + current_cluster_num = _find_next_cluster_blk_idx(current_cluster_num); + // update file position + file->f_pos += charNeeded; + + // Check if read next block needed + isMeetReadLen = cur_read_count >= len; + isReachContentSize = (file->f_pos) >= contentSize; + isReachEndOfCluster = (current_cluster_num == EOC_FILTER); + #ifdef __FS_DEBUG + printf("cur_read_count = %d\n", cur_read_count); + printf("isMeetReadLen = %d\n", isMeetReadLen); + printf("isMeetisReachEndOfClusterReadLen = %d\n", isReachEndOfCluster); + printf("isReachContentSize = %d\n", isReachContentSize); + #endif + } + + // After experiment, Linux append '\0' to file in device, so we don't need to add '\0' manully + dest[cur_read_count] = '\0'; + + return cur_read_count; +} + +int fat32_write(struct file *file, const void *buf, size_t len) +{ + // TODO: Lab7 - Requirement2 + #ifdef __FS_DEBUG + printf("[fat32_write] Content in buf : %s\n", buf); + #endif //__DEBUG + + char *src = (char *)buf; + char sector_buf[BLOCK_SIZE]; + + struct fat32_internal *internal = file->vnode->internal; + uint32_t contentSize = internal->size; + int cur_write_count = 0; // record how many bytes have been written + + uint32_t current_cluster_num = internal->first_cluster; + for (int i = 0;i < file->f_pos / BLOCK_SIZE;i++) { // get the right cluster to start with + current_cluster_num = _find_next_cluster_blk_idx(current_cluster_num); + } + + // write until meet len needed to write + int isMeetWriteLen = (cur_write_count >= len); + while (!isMeetWriteLen) { + // read data from sd card device + readblock(_get_cluster_blk_idx(current_cluster_num), sector_buf); + + // Calculate how many char this iteration we needed to write + // We need to determine how many bytes we still can write in this iteration, choose the smallest one in following: + // 1. How many char we still want to write + // 2. How many char we still can write into this block (sector) + uint32_t charStillNeedWriteSize = len - cur_write_count; // 1. + uint32_t contentLeftInCurBlock = BLOCK_SIZE - (file->f_pos % BLOCK_SIZE); // 2. + uint32_t charNeeded = (charStillNeedWriteSize < contentLeftInCurBlock) ? charStillNeedWriteSize : contentLeftInCurBlock; + + // write content + int sector_buf_start_idx = file->f_pos % BLOCK_SIZE; + #ifdef __FS_DEBUG + printf("[fat32_write] current_cluster_num= %d\n", current_cluster_num); + printf("[fat32_write] contentSize= %d\n", contentSize); + printf("[fat32_write] charNeeded = %d\n", charNeeded); + printf("[fat32_write] sector_buf_start_idx = %d\n", sector_buf_start_idx); + #endif + for (int i = 0;i < charNeeded;i++) { + sector_buf[sector_buf_start_idx + i] = src[cur_write_count++]; + } + + // sector content write back + writeblock(_get_cluster_blk_idx(current_cluster_num), sector_buf); + + // update to next cluster + uint32_t prev_cluster_num = current_cluster_num; // save prev for later uses + current_cluster_num = _find_next_cluster_blk_idx(current_cluster_num); + // update file position + file->f_pos += charNeeded; + + // Check if write next block needed + isMeetWriteLen = cur_write_count >= len; + #ifdef __FS_DEBUG + printf("isMeetReadLen = %d\n", isMeetWriteLen); + #endif + + // If reach EOC but still chars needed to write, we need extra cluster to store remaining file content + int isReachEndOfCluster = (current_cluster_num == EOC_FILTER); + if (isReachEndOfCluster && !isMeetWriteLen) { + printf("[fat32_write] Extend new cluster not implementd. Write procedure terminate.\n"); + return -1; + + printf("prev_cluster_num = %d\n", prev_cluster_num); + // TODO: + // int free_FAT_entry_blk_idx; + // int entry_idx; + // int isFound = _get_empty_FAT_table_entry(&free_FAT_entry_blk_idx, &entry_idx); + // if (isFound == FALSE) { + // printf("[fat32_write] Error, no free FAT table entry.\n"); + // } + } + + } + + // File's content size is change (larger), update file size in direcotry dentry in file internal struct and device + int isChangeContentSize = (file->f_pos) > contentSize; + if (isChangeContentSize) { + internal->size = file->f_pos; // update file size in memory + + // find dir entry and update file size of directory entry in sd card + readblock(internal->dirEntry_blk_idx, sector_buf); + struct fat32_dirEnt *sector_dirEnt = (struct fat32_dirEnt *)sector_buf; + for (int i = 0;sector_dirEnt[i].name[0] != 0x00 && i < FAT32_DIRECTORY_ENTRY_PER_BLOCK;i++) { + // Special value, it's a deleted/unused entry + if (sector_dirEnt[i].name[0] == 0xE5) + continue; + + // find target file directory entry + uint32_t first_cluster = (sector_dirEnt[i].cluster_high) << 16 | sector_dirEnt[i].cluster_low; + if (first_cluster == internal->first_cluster) { + sector_dirEnt[i].size = file->f_pos; + } + } + writeblock(internal->dirEntry_blk_idx, sector_buf); // write back + } + + #ifdef __FS_DEBUG + printf("isChangeContentSize = %d\n", isChangeContentSize); + printf("file->f_pos = %d\n", file->f_pos); + #endif + + return cur_write_count; +} + +// Lab7 - Elective1, Create a File in FAT32 +int fat32_create(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + struct dentry *new_dentry = fat32_create_dentry(dir_node->dentry, component_name, REGULAR_FILE); + *target = new_dentry->vnode; + + /* Find free FAT table entry (first cluster) and free directory entry in sd card */ + // 1. Find an empty entry in the FAT table . + int free_FAT_entry_blk_idx; + int entry_idx; + int isFound = _get_empty_FAT_table_entry(&free_FAT_entry_blk_idx, &entry_idx); + if (isFound == FALSE) { + printf("[fat32_write] Error, no free FAT table entry.\n"); + return FALSE; + } + + // 2. Find an empty directory entry in the target directory. + // find empty directory entry in directory's first cluster + struct fat32_internal *internal = (struct fat32_internal *) dir_node->internal; + int free_FAT_dir_entry_blk_idx; + int dir_entry_idx = -1; + isFound = _get_empty_FAT_dir_entry_by_clusterNum(internal->first_cluster, &free_FAT_dir_entry_blk_idx, &dir_entry_idx); + if (isFound == FALSE) { + printf("[fat32_create] Error, no free FAT direcotry entry (Here only search first cluster for easy).\n"); + return FALSE; + } + #ifdef __FS_DEBUG + printf("[fat32_create] free_FAT_dir_entry_blk_idx = %d\n", free_FAT_dir_entry_blk_idx); + printf("[fat32_create] dir_entry_idx = %d\n", dir_entry_idx); + #endif + + // Create new directory entry + uint32_t new_first_cluster_num = _get_cluster_num_by_fat_entry(&free_FAT_entry_blk_idx, &entry_idx); // Calculate new file's first cluster num + struct fat32_dirEnt *new_fat_dirEnt = _create_fat32_dirEnt(component_name, 0x00, new_first_cluster_num, 0); + printf("[fat32_create] new_first_cluster = %d\n", new_first_cluster_num); + #ifdef __FS_DEBUG + printf("[fat32_create] new_first_cluster = %d\n", new_first_cluster_num); + #endif + + // 3. Save them to sd card. Also set vnode internal info in memory + // set fat table entry in sdcard + _set_FAT_table_entry(&free_FAT_entry_blk_idx, &entry_idx, EOC_FILTER); // Set to EOC_FILTER, because there are one cluster initially. + // set directory entry in sd card + _set_FAT_dir_entry(&free_FAT_dir_entry_blk_idx, &dir_entry_idx, new_fat_dirEnt); + + // set new file vnode with fat32 internal info (In memory) + struct fat32_internal *new_internal = (struct fat32_internal *) kmalloc(sizeof(struct fat32_internal)); + new_internal->first_cluster = new_first_cluster_num; + new_internal->dirEntry_blk_idx = free_FAT_dir_entry_blk_idx; + new_internal->size = 0; + new_dentry->vnode->internal = new_internal; + + return TRUE; +} + +int fat32_mkdir(struct vnode *parent, const char *component_name) +{ + // TODO: Not needed for Lab7 + // printf("[fat32_mkdir] dir name: %s\n", component_name); + // fat32_create_dentry(parent->dentry, component_name, DIRECTORY); + + return TRUE; +} diff --git a/src/fork.c b/src/fork.c index 08e7fe145..cf2ba6209 100644 --- a/src/fork.c +++ b/src/fork.c @@ -12,7 +12,10 @@ #include "printf.h" #include "sched.h" #include "types.h" +#include "utils.h" +// no virtual memory version +// TODO: fork and exec syscall is change, so it may not acceptable int copy_process(unsigned long clone_flags, unsigned long fn, unsigned long arg, unsigned long stack) { preempt_disable(); struct task_struct *p; @@ -69,6 +72,8 @@ int copy_process(unsigned long clone_flags, unsigned long fn, unsigned long arg, return pid; } +// no virtual memory version +// TODO: fork and exec syscall is change, so it may not acceptable int move_to_user_mode(unsigned long pc) { struct pt_regs *regs = task_pt_regs(current); @@ -86,6 +91,75 @@ int move_to_user_mode(unsigned long pc) return 0; } +// virtual memory version +int copy_process_virt(unsigned long clone_flags, unsigned long fn, unsigned long arg) { + + preempt_disable(); + struct task_struct *p; + p = (struct task_struct *) alloacte_kernel_page(); // get a free and clean(init zero val) page + if (!p) { // NULL + printf("[copy_process_virt] Fail to allocate memory"); + return -1; + } + struct pt_regs *childregs = task_pt_regs(p); + if (clone_flags & PF_KTHREAD) { + // Kernel thread + p->cpu_context.x19 = fn; + p->cpu_context.x20 = arg; + } else { + // Sysclone and fork, initalize stage for clone and fork user process + #ifdef __DEBUG_MM + printf("[copy_process_virt] Fork!\n"); + #endif + struct pt_regs * cur_regs = task_pt_regs(current); + *childregs = *cur_regs; + childregs->regs[0] = 0; // To distinguish it as new child process + copy_virt_memory(p); + } + + p->flags = clone_flags; + p->priority = current->priority; + p->state = TASK_RUNNING; + p->counter = p->priority; + // disable preemption until schedule_tail, + // meaning that after the task is executed it should not be rescheduled + // until it completes some initialization work. + p->preempt_count = 1; + // Init file descriptor table(file struct) + _init_files_struct(p); + // process current working directory for filesystem + p->cwd = rootfs->root; + + p->cpu_context.pc = (unsigned long)ret_from_fork; + p->cpu_context.sp = (unsigned long)childregs; + + int pid = assignPID(); + task[pid] = p; + task[pid]->pid = pid; + + preempt_enable(); + + return pid; +} + +// virtual memory version +int move_to_user_mode_virt(unsigned long pc, unsigned long user_start_address) +{ + struct pt_regs *regs = task_pt_regs(current); + //memzero((unsigned long)regs, sizeof(* regs)); + regs->pstate = PSR_MODE_EL0t; + regs->sp = MAX_PROCESS_ADDRESS_SPACE; // sp increase from high memory + void *code_page = alloacte_user_page(current, 0); + regs->pc = 0; // Becuase virtual memory enable, so user code can always start at 0 + if (code_page == 0) { + printf("[move_to_user_mode_virt] Fail to allocate memory"); + return -1; + } + memcpy((unsigned long)code_page, user_start_address, PAGE_SIZE); + set_pgd(current->mm.pgd); + return 0; +} + struct pt_regs *task_pt_regs(struct task_struct *tsk) { unsigned long p = (unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs); return (struct pt_regs *)p; diff --git a/src/fs.c b/src/fs.c index 45a42f2bc..dbc60665b 100644 --- a/src/fs.c +++ b/src/fs.c @@ -1,7 +1,13 @@ #include "vfs.h" #include "tmpfs.h" +#include "fat32.h" struct filesystem tmpfs = { .name = "tmpfs", .setup_mount = tmpfs_setup_mount +}; + +struct filesystem fat32 = { + .name = "fat32", + .setup_mount = fat32_setup_mount }; \ No newline at end of file diff --git a/src/main.c b/src/main.c index 4b5843918..9f78ce0b0 100755 --- a/src/main.c +++ b/src/main.c @@ -10,7 +10,8 @@ #include "sys.h" #include "cpio.h" #include "vfs.h" - +#include "sdhost.h" +#include "mmu.h" /* Initial Logo */ // ___ ____ ____ ___ ____ ___ ____ _ __ __ // / _ \/ ___|| _ \_ _| |___ \ / _ \___ \/ | \ \ / / _ _ __ __ _ @@ -181,6 +182,56 @@ void Lab6_vfs_eletive2_demo() schedule(); } +void Lab8_virtual_memory_requirement_demo() +{ + // Find starting address of user program in cpio + unsigned long file_size = 0; + void *addr = cpio_get_file(INITRAMFS_ADDR, "Lab8.img", &file_size); + int err = move_to_user_mode_virt((unsigned long) addr, (unsigned long) addr); + if (err < 0){ + printf("Error while moving process to user mode\n\r"); + } + #ifdef __DEBUG_MM + printf("Size: %d\n", file_size); + printf("Addr: "); + print_0x_64bit(addr); + #endif // __DEBUG_MM +} + +void Lab8_virtual_memory_elective1_demo() +{ + // [mmap - illegal_write] + // Find starting address of user program in cpio + unsigned long file_size = 0; + void *addr = cpio_get_file(INITRAMFS_ADDR, "Lab8_mmap.img", &file_size); + int err = move_to_user_mode_virt((unsigned long) addr, (unsigned long) addr); + if (err < 0){ + printf("Error while moving process to user mode\n\r"); + } + #ifdef __DEBUG_MM + printf("Size: %d\n", file_size); + printf("Addr: "); + print_0x_64bit(addr); + #endif // __DEBUG_MM +} + +void Lab8_virtual_memory_elective1_demo_2() +{ + // [mmap - illegal_read] + // Find starting address of user program in cpio + unsigned long file_size = 0; + void *addr = cpio_get_file(INITRAMFS_ADDR, "Lab8_mmap_2.img", &file_size); + int err = move_to_user_mode_virt((unsigned long) addr, (unsigned long) addr); + if (err < 0){ + printf("Error while moving process to user mode\n\r"); + } + #ifdef __DEBUG_MM + printf("Size: %d\n", file_size); + printf("Addr: "); + print_0x_64bit(addr); + #endif // __DEBUG_MM +} + int main() { // set up serial console @@ -189,6 +240,9 @@ int main() // Initialize printf init_printf(0, putc); + // sched init + sched_init(); + // Initialize memory allcoator mm_init(); @@ -197,18 +251,47 @@ int main() // enable IRQ interrupt enable_irq(); - - enable_uart_interrupt(); + + // TODO: This uart interrupt might cause bug, because uart read interrupt might be triggered continously + // (In rpi3 hardware) And when we inital rpi3 hardware, sometimes there are a random char are generated for no reason (We can't find the reason) + //enable_uart_interrupt(); // say hello printf(init_logo); - + + + // Lab8 - Virtual Memory Test cases, requirment and elective3 + int res = copy_process_virt(PF_KTHREAD, (unsigned long)&Lab8_virtual_memory_requirement_demo, 0); + if (res < 0) { + printf("error while starting kernel process"); + } + schedule(); + + // Lab8 - Elective1 + res = copy_process_virt(PF_KTHREAD, (unsigned long)&Lab8_virtual_memory_elective1_demo, 0); + if (res < 0) { + printf("error while starting kernel process"); + } + schedule(); + + res = copy_process_virt(PF_KTHREAD, (unsigned long)&Lab8_virtual_memory_elective1_demo_2, 0); + if (res < 0) { + printf("error while starting kernel process"); + } + // Initialize root file system - rootfs_init(); + // rootfs_init(); + + // sd card device init + // sd_init(); + // sd_mount(); + + /* Lab7 Test cases */ + // Lab7_fat32_test(); - // vfs test cases - Lab6_vfs_test_demo(); - Lab6_vfs_eletive2_demo(); + // Lab6 - vfs test cases + // Lab6_vfs_test_demo(); + // Lab6_vfs_eletive2_demo(); /* Lab5 Test cases */ // Requirement 1 - Implement the thread mechanism. diff --git a/src/mm.c b/src/mm.c index 013dcf978..0f6922913 100644 --- a/src/mm.c +++ b/src/mm.c @@ -1,7 +1,11 @@ #include "mm.h" #include "uart.h" #include "printf.h" - +#include "sched.h" +#include "mmu.h" +#include "utils.h" +#include "types.h" +#include "sys.h" page_t bookkeep[PAGE_FRMAME_NUM]; free_area_t free_area[MAX_ORDER + 1]; @@ -45,11 +49,11 @@ void pop_block_from_free_area(page_t *poped_block, free_area_t *fa) { struct page *buddy_block_alloc(int order) { - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC // printf("\n[buddy_block_alloc]Before allocate buddy memory:"); // dump_buddy(); printf("[buddy_block_alloc] Requested Order: %d, Size: %d\n\n", order, 1 << order); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC if ( (order<0) | (order>MAX_ORDER) ) { printf("[buddy_block_alloc] %d is invalid order!\n", order); @@ -75,20 +79,20 @@ struct page *buddy_block_alloc(int order) struct page *bottom_half_block = &bookkeep[buddy_pfn]; push_block_to_free_area(bottom_half_block, &free_area[downward_order], downward_order); - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("Push back -> Redundant block(bottom half) { pfn(%d), order(%d) }\n", bottom_half_block->pfn, bottom_half_block->order); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC } - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("\n[buddy_block_alloc]After allocate buddy memory:"); dump_buddy(); printf("[buddy_block_alloc] Result - Allocated block{ pfn(%d), order(%d), phy_addr_16(0x%x) }\n", target_block->pfn, target_block->order, target_block->phy_addr); printf("[buddy_block_alloc] **Done**\n\n"); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC return target_block; @@ -99,23 +103,23 @@ struct page *buddy_block_alloc(int order) return 0; } -void buddy_block_free(struct page* block) +void buddy_block_free(struct page *block) { - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("\n[buddy_block_free] **Start free block{ pfn(%d), order(%d) }**\n", block->pfn, block->order); // printf("\n[buddy_block_free]Before free memory:"); // dump_buddy(); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC // Coalesce free buddy int buddy_pfn = FIND_BUDDY_PFN(block->pfn, block->order); page_t *buddy_block = &bookkeep[buddy_pfn]; while (block->order < MAX_ORDER && block->order == buddy_block->order && buddy_block->used == Free) { - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("Buddy{ pfn(%d), order(%d) }\n", buddy_block->pfn, buddy_block->order); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC // Pop buddy block from frealist pop_block_from_free_area(buddy_block, &free_area[buddy_block->order]); @@ -133,17 +137,16 @@ void buddy_block_free(struct page* block) // Push merged block to freelist push_block_to_free_area(block, &free_area[block->order], block->order); - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("\n[buddy_block_free]After free memory:"); dump_buddy(); printf("[buddy_block_free] **Done**\n\n"); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC } -#ifdef __DEBUG void dump_buddy() { printf("\n---------Buddy Debug---------\n"); @@ -161,7 +164,6 @@ void dump_buddy() printf("\n---------End Buddy Debug---------\n\n"); } -#endif void __init_obj_alloc(obj_allocator_t *obj_allocator_p, int objsize) { @@ -202,10 +204,10 @@ int register_obj_allocator(int objsize) __init_obj_alloc(&obj_alloc_pool[token], objsize); - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[register_obj_allocator] Successfully Register object allocator! {objsize(%d), token(%d)}\n" ,objsize, token); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC return token; } @@ -223,11 +225,11 @@ void *obj_allocate(int token) { obj_allocator_t *obj_allocator_p = &obj_alloc_pool[token]; void *allocated_addr = NULL; // address of allocated object - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[obj_allocate] Requested token: %d, size: %d\n",token, obj_allocator_p->objsize); // printf("[obj_allocate] Before allocation:"); // dump_obj_alloc(obj_allocator_p); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC if (obj_allocator_p->curr_page == NULL) { page_t *page_p; @@ -254,10 +256,10 @@ void *obj_allocate(int token) { struct list_head *obj_freelist = obj_allocator_p->curr_page->free; if (obj_freelist != NULL) { // Allocate memory by free list in current page - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[obj_allocate] Use object freelist\n"); printf("[obj_allocate] obj_freelist->next = 0x%x\n", obj_freelist->next); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC allocated_addr = obj_freelist; obj_allocator_p->curr_page->free = obj_freelist->next; // Point to next address of free object; } @@ -277,12 +279,12 @@ void *obj_allocate(int token) { } - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[obj_allocate] Allocated address: {phy_addr_16(%x)}\n", allocated_addr); printf("[obj_allocate] After allocation:"); dump_obj_alloc(obj_allocator_p); printf("[obj_allocate] **Done**\n\n"); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC return allocated_addr; @@ -296,13 +298,13 @@ void obj_free(void *obj_addr) { page_t *page_p = &bookkeep[obj_pfn]; obj_allocator_t *obj_allocator_p = page_p->obj_alloc; - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("\n[obj_free] Free object procedure!\n"); printf("[obj_free] Page info: 0x%x {pfn=(%d), obj_used(%d))\n", obj_addr, obj_pfn, page_p->obj_used); printf("[obj_free] object free list point to {0x%x}\n", page_p->free); // printf("[obj_free] Before free:"); // dump_obj_alloc(obj_allocator_p); - #endif // __DEBUG + #endif // __DEBUG_MM_ALLOC // Make page's object freelist point to address of new first free object. // And the contect of released object should record the orginal address @@ -332,9 +334,9 @@ void obj_free(void *obj_addr) { // Return empty page to free page pool(free_area) // otherwise, add it to empty list if (obj_allocator_p->page_used >= 10) { // TODO: Return empty page only if memory becomes tight - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[obj_free] Free empty page bacause memory is tight"); - #endif // __DEBUG + #endif // __DEBUG_MM_ALLOC obj_allocator_p->page_used -= 1; page_p->free = NULL; @@ -347,14 +349,14 @@ void obj_free(void *obj_addr) { } } - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[obj_free] After free:"); dump_obj_alloc(obj_allocator_p); printf("[obj_free] **Done**\n\n"); - #endif // __DEBUG + #endif // __DEBUG_MM_ALLOC } -#ifdef __DEBUG +#ifdef __DEBUG_MM_ALLOC void dump_obj_alloc(obj_allocator_t *obj_allocator_p) { printf("\n---------Object Allocator Debug---------\n"); @@ -398,7 +400,7 @@ void dump_obj_alloc(obj_allocator_t *obj_allocator_p) printf("\n---------End Object Allocator Debug---------\n\n"); } -#endif +#endif // __DEBUG_MM_ALLOC void __init_kmalloc() { @@ -409,9 +411,9 @@ void __init_kmalloc() void *kmalloc(int size) { - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[kmalloc] Requested Size: %d\n", size); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC void *allocated_addr; @@ -420,10 +422,10 @@ void *kmalloc(int size) if (size <= (1<phy_addr; - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[kmlloc] Allocated address: 0x%x\n", allocated_addr); printf("[kmlloc] **Done**\n\n"); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC return allocated_addr; } @@ -448,9 +450,9 @@ void *kmalloc(int size) void kfree(void *addr) { - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[kfree] Free Memory Address: 0x%x\n", addr); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC int pfn = PHY_ADDR_TO_PFN(addr); page_t *page_p = &bookkeep[pfn]; @@ -463,9 +465,280 @@ void kfree(void *addr) buddy_block_free(page_p); } - #ifdef __DEBUG + #ifdef __DEBUG_MM_ALLOC printf("[kfree] **Done**\n\n"); - #endif //__DEBUG + #endif // __DEBUG_MM_ALLOC +} + + + +/* Page allocate and free after MMU enable */ + +void *get_free_page() +{ + void *page = (void *) buddy_block_alloc(0)->phy_addr; // alloacte one page + memzero((unsigned long) page + VA_START, PAGE_SIZE); // clear page + return page; +} + +void free_page(void *pg_addr) +{ + #ifdef __DEBUG_MM + printf("[free_page] Free Memory Address(Physical address): 0x%x\n", pg_addr); + #endif //__DEBUG_MM + + int pfn = PHY_ADDR_TO_PFN(pg_addr); + page_t *page_p = &bookkeep[pfn]; + + buddy_block_free(page_p); +} + +void *alloacte_kernel_page() +{ + void *page = (void *) get_free_page(); // alloacte one page + if (page == 0) { + // fail + return 0; + } + return page + VA_START; +} + +void *alloacte_user_page(struct task_struct *task, unsigned long va) +{ + void *page = (void *) get_free_page(); // alloacte one page + if (page == 0) { + // fail + return 0; + } + map_page(task, va, (unsigned long)page); // map page and use normal page mapping, it may allocate and populate new page tables + return page + VA_START; +} + +void map_table_entry(unsigned long *pte, unsigned long va, unsigned long page) +{ + unsigned long index = va >> PAGE_SHIFT; + index = index & (PTRS_PER_TABLE - 1); + unsigned long entry = page | MMU_PTE_FLAGS; + pte[index] = entry; +} + +unsigned long map_table(unsigned long *table, unsigned long shift, unsigned long va, int *new_table) +{ + unsigned long index = va >> shift; + index = index & (PTRS_PER_TABLE - 1); + if (!table[index]) { + *new_table = 1; + unsigned long next_level_table = (unsigned long) get_free_page(); + unsigned long entry = next_level_table | MM_TYPE_PAGE_TABLE; + table[index] = entry; + return next_level_table; + } else { + *new_table = 0; + } + + return table[index] & PAGE_MASK; +} + +void map_page(struct task_struct *task, unsigned long va, unsigned long page) +{ + unsigned long pgd; + if (!task->mm.pgd) { + task->mm.pgd = (unsigned long) get_free_page(); + task->mm.kernel_pages[++task->mm.kernel_pages_count] = task->mm.pgd; + } + pgd = task->mm.pgd; + int new_table; + unsigned long pud = map_table((unsigned long *)(pgd + VA_START), PGD_SHIFT, va, &new_table); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pud; + } + unsigned long pmd = map_table((unsigned long *)(pud + VA_START), PUD_SHIFT, va, &new_table); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pmd; + } + unsigned long pte = map_table((unsigned long *)(pmd + VA_START), PMD_SHIFT, va, &new_table); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pte; + } + map_table_entry((unsigned long *)(pte + VA_START), va, page); + struct user_page p = {page, va}; + task->mm.user_pages[task->mm.user_pages_count++] = p; +} + +int copy_virt_memory(struct task_struct *dst) +{ + #ifdef __DEBUG_MM + printf("[copy_virt_memory]\n"); + #endif + struct task_struct *src = current; + + #ifdef __DEBUG_MM + printf("[copy_virt_memory] src->mm.user_pages_count = %d\n", src->mm.user_pages_count); + #endif + for (int i = 0;i < src->mm.user_pages_count;i++) { + #ifdef __DEBUG_MM + printf("[copy_virt_memory] src->mm.user_pages[%d].phys_addr = 0x%x\n", i, src->mm.user_pages[i].phys_addr); + printf("[copy_virt_memory] src->mm.user_pages[%d].virt_addr = 0x%x\n", i, src->mm.user_pages[i].virt_addr); + #endif + void *kernel_va = alloacte_user_page(dst, src->mm.user_pages[i].virt_addr); + if (kernel_va == 0) { + // fail + printf("[copy_virt_moemory] Error."); + return -1; + } + memcpy((unsigned long) kernel_va, src->mm.user_pages[i].virt_addr, PAGE_SIZE); + } + + #ifdef __DEBUG_MM + printf("[copy_virt_memory] End virtual memory copy\n"); + #endif + return 0; +} + +unsigned long _find_pte(struct task_struct *task, unsigned long va) +{ + unsigned long pgd; + if (!task->mm.pgd) { + task->mm.pgd = (unsigned long) get_free_page(); + task->mm.kernel_pages[++task->mm.kernel_pages_count] = task->mm.pgd; + } + pgd = task->mm.pgd; + int new_table; + unsigned long pud = map_table((unsigned long *)(pgd + VA_START), PGD_SHIFT, va, &new_table); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pud; + } + unsigned long pmd = map_table((unsigned long *)(pud + VA_START), PUD_SHIFT, va, &new_table); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pmd; + } + unsigned long pte = map_table((unsigned long *)(pmd + VA_START), PMD_SHIFT, va, &new_table); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pte; + } + + return pte; +} + +void _map_table_entry_with_prot(unsigned long *pte, unsigned long va, unsigned long page, uint64_t entry_prot) +{ + unsigned long index = va >> PAGE_SHIFT; + index = index & (PTRS_PER_TABLE - 1); + unsigned long entry = page | entry_prot; + pte[index] = entry; + + printf("[mem_map] entry: "); + print_0x_64bit((void *)entry); + +} + +/** mmap kernel function + * For simplicity, we always allocate one page regardless of "len" value and "fd", "file_offset" not used + **/ +void *mem_map(void *addr, size_t len, int prot, int flags, int fd, int file_offset) +{ + if (len <= 0) { // requested size must be greater than 0 + printf("[mem_map] Requested size must be greater than 0\n"); + } + + // region’s access protection + uint64_t pte_entry_prot = MMAP_PTE_DEFAULT; + if ((prot & PROT_NONE) == PROT_NONE) pte_entry_prot = pte_entry_prot & (~MM_ACCESS); + if ((prot & PROT_READ) == PROT_READ) pte_entry_prot = pte_entry_prot | MM_READ_ONLY; + if ((prot & PROT_WRITE) == PROT_WRITE) pte_entry_prot = pte_entry_prot & (~MM_READ_ONLY); // PROT_WRITE implies PROT_READ. + if ((prot & PROT_EXEC) == PROT_EXEC) pte_entry_prot = pte_entry_prot & (~MM_EXEC_NONE); + + unsigned long new_region_addr = 0; + int idx_unused_pte_entry = 0; + printf("[mem_map] current->mm.kernel_pages_count = %d\n", current->mm.kernel_pages_count); + if (addr == NULL) { // Allocate a new page, + // find the first unused page descriptor in pte. + unsigned long *pte; + for (int i = 0;i < MAX_PROCESS_PAGES;i++) { + pte = (unsigned long *) _find_pte(current, i * PAGE_SIZE); + pte = (unsigned long *)((unsigned long)pte + VA_START); + printf("[mem_map] pte[%d]: ", i); + print_0x_64bit((void *)pte[i]); + if (pte[i] == 0) { // unused page entry + if (pte[i] == 0) { + printf("[mem_map] Find first unused virtual memory of the process. index = %d\n", i); + idx_unused_pte_entry = i; + break; + } + } + } + if (pte == 0) { + printf("[mem_map] No avaliable memory for the process.\n"); + return NULL; + } + + // fill in new page entry + new_region_addr = (unsigned long)(PAGE_SIZE * idx_unused_pte_entry); + unsigned long page = (unsigned long) get_free_page(); + _map_table_entry_with_prot(pte, new_region_addr, page, pte_entry_prot); + } + else { // if addr is specified + int isPageAligned = ((unsigned long)addr & 0x0FFF) > 0; + printf("[mem_map] isPageAligned = %d\n", isPageAligned); + if (flags == MAP_FIXED && isPageAligned) { + printf("[mem_map] MAP_FIXED is set but addr is not page-aligned, mmap() failed.\n"); + return NULL; + } + + new_region_addr = (unsigned long)addr & ~(0x0FFF); // The memory region created by mmap() should be page-aligned, + unsigned long *pte; + pte = (unsigned long *) _find_pte(current, new_region_addr); + pte = (unsigned long *)((unsigned long)pte + VA_START); + // fill in new page entry + unsigned long page = (unsigned long) get_free_page(); + _map_table_entry_with_prot(pte, new_region_addr, page, pte_entry_prot); + printf("[mem_map] pte: "); + print_0x_64bit((void *)pte); + printf("[mem_map] new_region_addr: ", new_region_addr); + print_0x_64bit((void *)new_region_addr); + } + + return (void *)new_region_addr; +} + +int do_mem_abort(unsigned long addr, unsigned long esr) +{ + printf("[do_mem_abort] Here!\n"); + printf("[do_mem_abort] ESR: 0x%x\n", esr); + printf("[do_mem_abort] Page Fault address: "); + print_0x_64bit((void *)addr); + + unsigned long dfs = (esr & 0b111111); + if ((dfs & 0b111100) == 0b100) { // Translation fault + printf("[do_mem_abort] Is translation fault!\n"); + if (addr >= MAX_PROCESS_ADDRESS_SPACE) { + printf("[do_mem_abort] *segmentation fault* Addrss exceed process’s address space, terminate process!\n"); + exit_process(); // terminate current process + } + void *page = get_free_page(); + if (page == 0) { + // fail + printf("[do_mem_abort] Fail to alloacte free page\n"); + return -1; + } + + map_page(current, addr & PAGE_MASK, (unsigned long)page); + + return 0; + } + + if ((dfs & 0b111100) == 0b1100) { // Permission fault + printf("[do_mem_abort] Is Permission fault!\n"); + printf("[do_mem_abort] *segmentation fault*, terminate process!\n"); + exit_process(); // terminate current process + } + + if ((dfs & 0b111100) == 0b1000) { // Access flag fault + printf("[do_mem_abort] Is Access flag fault!\n"); + printf("[do_mem_abort] *segmentation fault*, terminate process!\n"); + exit_process(); // terminate current process + } + return -1; } void mm_init() diff --git a/src/sched.c b/src/sched.c index bedf879d3..e822c8868 100644 --- a/src/sched.c +++ b/src/sched.c @@ -2,6 +2,7 @@ #include "entry.h" #include "printf.h" #include "mm.h" +#include "utils.h" static struct task_struct init_task = INIT_TASK; struct task_struct *current = &(init_task); @@ -70,6 +71,7 @@ void switch_to(struct task_struct *next, int index) struct task_struct *prev = current; current = next; + set_pgd(next->mm.pgd); /* Switch page table for user space */ cpu_switch_to(prev, next); } @@ -97,13 +99,20 @@ void task_preemption() } void exit_process(void) { + printf("[exit_process] Process exit, pid = %d\n", current->pid); preempt_disable(); current->state = TASK_ZOMBIE; - // if user stack allocated, free stack. - if (current->stack) { - kfree((void *)current->stack); + // free all alloacted user page + for (int i = 0;i < current->mm.user_pages_count;i++) { + #ifdef __DEBUG_MM + printf("[exit_process] Free page: current->mm.user_pages[%d].phys_addr = 0x%x\n", i, current->mm.user_pages[i].phys_addr); + #endif + free_page((void *)current->mm.user_pages[i].phys_addr); } + #ifdef __DEBUG_MM + dump_buddy(); // dump boddy system + #endif preempt_enable(); schedule(); @@ -111,15 +120,21 @@ void exit_process(void) { void kill_zombies(void) { // reclaim threads marked as DEAD - // for (int i = 0;i < NR_TASKS;i++) { if (task[i]->state == TASK_ZOMBIE) { + // TODO: + // free all allocated kernel page // kfree(task[i]); // task[i] = NULL; } } } +void sched_init() +{ + task[0]->mm.pgd = pg_dir; +} + void dumpTasksState() { printf("=========Tasks state=========\n"); for (int i = 0;i < nr_tasks;i++) { diff --git a/src/sdhost.c b/src/sdhost.c new file mode 100644 index 000000000..45b3232e7 --- /dev/null +++ b/src/sdhost.c @@ -0,0 +1,228 @@ +#include "sdhost.h" + +#include "vfs.h" +#include "mbr.h" +#include "fat32.h" +#include "string.h" +#include "mm.h" +#include "utils.h" +#include "printf.h" + +static int is_hcs; // high capcacity(SDHC) + +static void pin_setup() { + set(GPIO_GPFSEL4, 0x24000000); + set(GPIO_GPFSEL5, 0x924); + set(GPIO_GPPUD, 0); + delay(15000); + set(GPIO_GPPUDCLK1, 0xffffffff); + delay(15000); + set(GPIO_GPPUDCLK1, 0); +} + +static void sdhost_setup() { + unsigned int tmp; + set(SDHOST_PWR, 0); + set(SDHOST_CMD, 0); + set(SDHOST_ARG, 0); + set(SDHOST_TOUT, SDHOST_TOUT_DEFAULT); + set(SDHOST_CDIV, 0); + set(SDHOST_HSTS, SDHOST_HSTS_MASK); + set(SDHOST_CFG, 0); + set(SDHOST_CNT, 0); + set(SDHOST_SIZE, 0); + get(SDHOST_DBG, tmp); + tmp &= ~SDHOST_DBG_MASK; + tmp |= SDHOST_DBG_FIFO; + set(SDHOST_DBG, tmp); + delay(250000); + set(SDHOST_PWR, 1); + delay(250000); + set(SDHOST_CFG, SDHOST_CFG_SLOW | SDHOST_CFG_INTBUS | SDHOST_CFG_DATA_EN); + set(SDHOST_CDIV, SDHOST_CDIV_DEFAULT); +} + +static int wait_sd() { + int cnt = 1000000; + unsigned int cmd; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_CMD, cmd); + --cnt; + } while (cmd & SDHOST_NEW_CMD); + return 0; +} + +static int sd_cmd(unsigned cmd, unsigned int arg) { + set(SDHOST_ARG, arg); + set(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); + get(SDHOST_RESP0, tmp); + 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); + get(SDHOST_RESP0, tmp); + 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); + get(SDHOST_RESP0, tmp); + sd_cmd(SELECT_CARD, tmp); + sd_cmd(SET_BLOCKLEN, 512); + return 0; +} + +static int wait_fifo() { + int cnt = 1000000; + unsigned int hsts; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_HSTS, hsts); + --cnt; + } while ((hsts & SDHOST_HSTS_DATA) == 0); + return 0; +} + +static void set_block(int size, int cnt) { + set(SDHOST_SIZE, size); + set(SDHOST_CNT, cnt); +} + +static void wait_finish() { + unsigned int dbg; + do { + get(SDHOST_DBG, dbg); + } while ((dbg & SDHOST_DBG_FSM_MASK) != SDHOST_HSTS_DATA); +} + +void 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(512, 1); + sd_cmd(READ_SINGLE_BLOCK | SDHOST_READ, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + get(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void writeblock(int block_idx, void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(512, 1); + sd_cmd(WRITE_SINGLE_BLOCK | SDHOST_WRITE, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + set(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void sd_init() { + pin_setup(); + sdhost_setup(); + sdcard_setup(); +} + +/** + * Mount Fat32 file system in SD card + * Fat32 file system is in first partition of sd card + */ +void sd_mount() +{ + // read MBR + // MBR is located in first sector of sd card + char sector_buf[BLOCK_SIZE]; + readblock(0, sector_buf); + if (sector_buf[510] != 0x55 || sector_buf[511] != 0xAA) { + printf("[sd_mount] Read MBR Error"); + return; + } + + // parse first partition from MBR + struct mbr_partition p1; + memcpy((unsigned long)&p1, (unsigned long) sector_buf+446, sizeof(p1)); + // If first partition not fat32 + if (p1.partition_type != 0xB && p1.partition_type != 0xC) { + printf("[sd_mount] Error, not FAT32, mount fat32 fs from sd card."); + dump_mbr_partition(&p1); // For debug + return; + } + + // Read fat32 bootsector from first partition of MBR + readblock(p1.starting_sector, sector_buf); + struct fat32_boot_sector *fat32_bs = (struct fat32_boot_sector*) sector_buf; + // fill out fat32 metadata for sd card + fat32_metadata.fat_region_blk_idx = p1.starting_sector + fat32_bs->nr_reserved_sectors; + fat32_metadata.data_region_blk_idx = p1.starting_sector + + fat32_bs->nr_reserved_sectors + + fat32_bs->nr_sectors_per_fat_32 * fat32_bs->nr_fat_table; + fat32_metadata.rootDir_first_cluster = fat32_bs->root_dir_start_cluster_num; + fat32_metadata.sector_per_cluster = fat32_bs->sector_per_cluster; + fat32_metadata.nr_fat = fat32_bs->nr_fat_table; + fat32_metadata.sector_per_fat = fat32_bs->nr_sectors_per_fat_32; + + // Mount fat32 + char mountpoint[8] = "/sdp1"; + vfs_mkdir(mountpoint); + vfs_mount("sdcard", mountpoint, "fat32"); + + // Get mount vnode + // and then assgin corresponding internal struct info to fat32 mount + struct vnode *mountRootDir_vnode; + char target_component_name[DNAME_INLINE_LEN]; // The component name of target file + _lookUp_pathname(mountpoint, &mountRootDir_vnode, target_component_name); + + struct fat32_internal *mountRootDir_vnode_internal = (struct fat32_internal *) kmalloc(sizeof(struct fat32_internal)); + mountRootDir_vnode_internal->first_cluster = fat32_bs->root_dir_start_cluster_num; + mountRootDir_vnode->internal = mountRootDir_vnode_internal; +} \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index f7acb7a42..633195492 100755 --- a/src/shell.c +++ b/src/shell.c @@ -131,8 +131,8 @@ void command_controller ( enum SPECIAL_CHARACTER input_parse, char c, char buffe else if ( !strcmp(buffer, "hello" ) ) command_hello(); else if ( !strcmp(buffer, "timestamp" ) ) command_timestamp(); else if ( !strcmp(buffer, "reboot" ) ) command_reboot(); - else if ( !strcmp(buffer, "ls" ) ) command_cpio_ls((void *) INITRAMFS_ADDR); - else if ( !strncmp(buffer, "cat ", 3 ) ) command_getCpioFile((void *) INITRAMFS_ADDR, buffer + 4); + else if ( !strcmp(buffer, "ls" ) ) command_cpio_ls(INITRAMFS_ADDR); + else if ( !strncmp(buffer, "cat ", 3 ) ) command_getCpioFile(INITRAMFS_ADDR, buffer + 4); else if ( !strcmp(buffer, "ma" ) ) mm_init(); else if ( !strcmp(buffer, "cpio_svc" ) ) command_cpio_svc(); // eret jump to cpio assemlby file(user program), and svc return to kernel else if ( !strcmp(buffer, "currentEL" ) ) command_current_el(); diff --git a/src/start.S b/src/start.S index 6c008d4bb..48699bc0c 100755 --- a/src/start.S +++ b/src/start.S @@ -1,4 +1,7 @@ #include "sysregs.h" +#include "mm.h" +#include "base.h" +#include "mmu.h" .section ".text.boot" @@ -7,25 +10,15 @@ _start: // read cpu id, stop slave cores mrs x1, mpidr_el1 and x1, x1, #3 // get CPU ID and mask reserved bits - cbz x1, clear_bss + cbz x1, el2_entry // cpu id > 0, stop proc_hang: wfe // hang for all noo-primary CPU and enter low power mode b proc_hang - -clear_bss: - // clear bss - ldr x1, =__bss_start - ldr w2, =__bss_size -clear_loop: - cbz w2, master - str xzr, [x1], #8 - sub w2, w2, #1 - cbnz w2, clear_loop // Whether bss section is not all set to zero - -master: - // cpu id == 0, is primary CPU - ldr x0, =SCTLR_VALUE_MMU_DISABLED + + // jump into master label. cpu id == 0, is primary CPU +el2_entry: + ldr x0, =SCTLR_VALUE_MMU_DISABLED // disable MMU msr sctlr_el1, x0 ldr x0, =HCR_EL2_VALUE // set EL1 aarch as aarch 64 @@ -40,30 +33,122 @@ master: eret // from el2 to el1 el1_entry: - ldr x1, =CPACR_EL1_VALUE // Make el0, el1 can use Floating point and Advanced SIMD - msr CPACR_EL1, x1 - - ldr x1, =_start // set EL1 stack before our code - mov sp, x1 + ldr x0, =CPACR_EL1_VALUE // let el0, el1 can use Floating point and Advanced SIMD + msr CPACR_EL1, x0 ldr x0, =exception_vector_table // set up el1 exception table msr vbar_el1, x0 - //ldr x0, =SPSR_EL1_VALUE - //msr spsr_el1, x0 - ldr x0, =0x3c5 // set processor restore state after calling eret msr spsr_el1, x0 // kernel should be running in EL1 - ldr x1, =0x40000 // set EL0 stack pointer - msr sp_el0, x1 + adr x0, master // eret return address + msr elr_el1, x0 + + eret + +master: + // clear bss + adr x0, __bss_start + adr x1, __bss_end + sub x1, x1, x0 + bl memzero + + /* Prepare MMU config */ + bl __create_page_tables // Create Kernel's Page table + + adrp x0, pg_dir // starting address of page table(PUD) defined in ld + msr ttbr0_el1, x0 // load PGD to the bottom translation based register. + msr ttbr1_el1, x0 // load PGD to the upper translation based register. + + ldr x0, =(TCR_VALUE) + msr tcr_el1, x0 + + ldr x0, =(MAIR_VALUE) + msr mair_el1, x0 + + ldr x0, =__kernel_start // set EL1 stack pointer (virtual address) before our code + mov sp, x0 + + ldr x2, =main // save absolute address for jumping to main functoin in C code after enable MMU + + ldr x1, =SCTLR_MMU_ENABLED // Enable MMU + mrs x0, sctlr_el1 + orr x0 , x0, x1 + msr sctlr_el1, x0 + // Jump to main functoin in C code, should not return + br x2 + + .macro create_pgd_entry, tbl, virt, tmp1, tmp2 + create_table_entry \tbl, \virt, PGD_SHIFT, \tmp1, \tmp2 + create_table_entry \tbl, \virt, PUD_SHIFT, \tmp1, \tmp2 + .endm + + .macro create_table_entry, tbl, virt, shift, tmp1, tmp2 + lsr \tmp1, \virt, #\shift + and \tmp1, \tmp1, #PTRS_PER_TABLE - 1 // table index + add \tmp2, \tbl, #PAGE_SIZE + orr \tmp2, \tmp2, #MM_TYPE_PAGE_TABLE + str \tmp2, [\tbl, \tmp1, lsl #3] + add \tbl, \tbl, #PAGE_SIZE // next level table page + .endm + + .macro create_block_map, tbl, phys, start, end, flags, tmp1 + lsr \start, \start, #SECTION_SHIFT + and \start, \start, #PTRS_PER_TABLE - 1 // table index + lsr \end, \end, #SECTION_SHIFT + and \end, \end, #PTRS_PER_TABLE - 1 // table end index + lsr \phys, \phys, #SECTION_SHIFT + mov \tmp1, #\flags + orr \phys, \tmp1, \phys, lsl #SECTION_SHIFT // table entry +9999: + str \phys, [\tbl, \start, lsl #3] // store the entry + add \start, \start, #1 // next entry + add \phys, \phys, #SECTION_SIZE // next block + cmp \start, \end + b.ls 9999b + .endm + + /* Ready jump to c code */ + /* adr x0, pseudo_main msr elr_el1, x0 - eret + eret + */ /* Now kernel should be running in EL1 and jump to main function*/ +/* pseudo_main: bl main // jump to main functoin in C code, should not return - b proc_hang // for failsafe, halt this core too (Should never do this instruction) \ No newline at end of file + b proc_hang // for failsafe, halt this core too (Should never do this instruction) +*/ + + +__create_page_tables: + mov x29, x30 // save return address + + /* clear page tables */ + adrp x0, pg_dir // starting address of page table(PUD) defined in ld + mov x1, #PG_DIR_SIZE + bl memzero + + adrp x0, pg_dir + mov x1, #VA_START + create_pgd_entry x0, x1, x2, x3 + + /* Mapping kernel and init stack*/ + mov x1, xzr // start mapping from physical offset 0 + mov x2, #VA_START // first virtual address + ldr x3, =(VA_START + DEVICE_BASE - SECTION_SIZE) // last virtual address + create_block_map x0, x1, x2, x3, MMU_FLAGS, x4 + + /* Mapping device memory*/ + mov x1, #DEVICE_BASE // start mapping from device base address + ldr x2, =(VA_START + DEVICE_BASE) // first virtual address + ldr x3, =(VA_START + PHYS_MEMORY_SIZE - SECTION_SIZE) // last virtual address + create_block_map x0, x1, x2, x3, MMU_DEVICE_FLAGS, x4 + + mov x30, x29 + ret \ No newline at end of file diff --git a/src/sys.S b/src/sys.S index 10b841201..bc72dbacd 100644 --- a/src/sys.S +++ b/src/sys.S @@ -114,3 +114,9 @@ call_sys_unmount: svc #0 ret +.globl call_sys_mmap +call_sys_mmap: + mov w8, #SYS_MMAP + svc #0 + ret + diff --git a/src/sys.c b/src/sys.c index fa0579473..002412b8d 100644 --- a/src/sys.c +++ b/src/sys.c @@ -47,23 +47,17 @@ int sys_gitPID() int sys_fork() { preempt_disable(); + #ifdef __DEBUG_MM + printf("[sys_fork]\n"); + #endif - unsigned long user_stack = (unsigned long) kmalloc(PAGE_SIZE); - int pid = copy_process(0, 0, 0, user_stack); - //printf("[sys_fork] New child process pid = %d\n", pid); - - // full copy user stack - memcpy(task[pid]->stack, current->stack, PAGE_SIZE); - - // Set proper user stack sp to new user process - // New user stack sp should have same offset as parent process sp - struct pt_regs * cur_regs = task_pt_regs(current); - int copiedTask_sp_offset = cur_regs->sp - current->stack; - struct pt_regs *childregs = task_pt_regs(task[pid]); - childregs->sp = task[pid]->stack + copiedTask_sp_offset; - + int pid = copy_process_virt(0, 0, 0); + preempt_enable(); + #ifdef __DEBUG_MM + printf("[sys_fork] New child process pid = %d\n", pid); + #endif return pid; } @@ -78,7 +72,7 @@ int sys_exec(const char *name, char* const argv[]) char filename_buf[30]; char extension[] = ".img"; int i; - unsigned long move_address = 0x10A0000; + unsigned long move_address = 0x0; // program code will start at 0 (virutal address) for (i = 0;i < strlen((char *)name);i ++) { filename_buf[i] = name[i]; } @@ -86,8 +80,8 @@ int sys_exec(const char *name, char* const argv[]) filename_buf[i] = extension[i - temp]; } filename_buf[i] = '\0'; - - void *target_addr = cpio_move_file((void *) INITRAMFS_ADDR, filename_buf, move_address); + + cpio_move_file(INITRAMFS_ADDR, filename_buf, move_address); //void *target_addr = cpio_get_file((void *) INITRAMFS_ADDR, "fork_test.img", &unused); // why cause error? // count argv[] until terminated by a null pointer @@ -99,22 +93,23 @@ int sys_exec(const char *name, char* const argv[]) // Reset user sp and move argv to user stack(for argument passing) // Note that sp must 16 byte alignment struct pt_regs *regs = task_pt_regs(current); - char **backup = kmalloc(PAGE_SIZE); + char **backup = alloacte_kernel_page(); for (int i = 0;i < argc_count;i++) { *(backup + i) = argv[i]; } - regs->sp = current->stack + PAGE_SIZE; + // sp increase from high memory to low memory + // And insert all argv + regs->sp = MAX_PROCESS_ADDRESS_SPACE; regs->sp = regs->sp - ((argc_count + argc_count % 2) * 8); char **temp = (char **)regs->sp; for (int i = 0;i < argc_count;i++) { *(temp + i) = *(backup + i); } - //kfree(backup); + free_page(backup); // set pc(elr_el) to new function(user program), and starting address of argv[] - regs->pc = (unsigned long)target_addr; + regs->pc = 0; // Becuase virtual memory enable, so user code can always start at 0 regs->regs[1] = (unsigned long)regs->sp; - preempt_enable(); return argc_count; @@ -124,6 +119,7 @@ void sys_exit() { exit_process(); } + void *sys_malloc(int bytes) { // Just call kmalloc for easy @@ -133,7 +129,7 @@ void *sys_malloc(int bytes) int sys_clone() { // TODO: - // Not required in lab + // Not required in lab 5 return 0; } @@ -283,6 +279,10 @@ int sys_unmount(const char* mountpoint) return vfs_unmount(mountpoint); } +void *sys_mmap(void *addr, size_t len, int prot, int flags, int fd, int file_offset) +{ + return mem_map(addr, len, prot, flags, fd, file_offset); +} void * const sys_call_table[] = {sys_print, sys_uart_write, sys_uart_read, @@ -291,4 +291,5 @@ void * const sys_call_table[] = sys_coreTimer_on, sys_coreTimer_off, sys_open, sys_close, sys_write, sys_read, sys_read_directory, sys_mkdir, - sys_chdir, sys_mount, sys_unmount}; \ No newline at end of file + sys_chdir, sys_mount, sys_unmount, + sys_mmap}; \ No newline at end of file diff --git a/src/tmpfs.c b/src/tmpfs.c index 4525bfe82..6cedce6bc 100644 --- a/src/tmpfs.c +++ b/src/tmpfs.c @@ -45,7 +45,7 @@ struct vnode* tmpfs_create_vnode(struct dentry *dentry, int type) int tmpfs_register() { if (tmpfs_v_ops != NULL && tmpfs_f_ops != NULL) { - return TMPFS_ERROR; + return TMPFS_ERROR; // Register error } // vnode operations @@ -58,19 +58,19 @@ int tmpfs_register() tmpfs_f_ops = (struct file_operations *) kmalloc(sizeof(struct file_operations)); tmpfs_f_ops->write = tmpfs_write; tmpfs_f_ops->read = tmpfs_read; - // Register error + return 0; } int tmpfs_setup_mount(struct filesystem* fs, struct mount* mount, const char *component_name) { - //printf("[tmpfs_setup_mount]\n"); + // printf("[tmpfs_setup_mount]\n"); mount->fs = fs; mount->root = tmpfs_create_dentry(NULL, component_name, DIRECTORY); - printf("[tmpfs_setup_mount] New created dentry name = %s\n", mount->root->name); + printf("[tmpfs_setup_mount] Setup tmpfs, New created dentry name = %s\n", mount->root->name); - return TMPFS_ERROR; + return TRUE; } int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) @@ -176,7 +176,7 @@ int tmpfs_read(struct file *file, void *buf, size_t len) int tmpfs_mkdir(struct vnode *parent, const char *component_name) { - printf("[tmpfs_mkdir] dir name: %s%\n", component_name); + printf("[tmpfs_mkdir] dir name: %s\n", component_name); tmpfs_create_dentry(parent->dentry, component_name, DIRECTORY); return 1; diff --git a/src/utils.S b/src/utils.S index 3f5d6ef78..7802fa9c2 100644 --- a/src/utils.S +++ b/src/utils.S @@ -1,12 +1,23 @@ // get current exception level .globl get_el get_el: - mrs x0, CurrentEL - lsr x0, x0, #2 + mrs x0, CurrentEL + lsr x0, x0, #2 ret +/* .globl delay delay: subs x0, x0, #1 bne delay + ret +*/ + +.globl set_pgd +set_pgd: + DSB ISH // ensure write has completed (Memory barrier) + msr ttbr0_el1, x0 // set pgd at user space + tlbi vmalle1is // invalidate all TLB entries + DSB ISH // ensure completion of TLB invalidation (Memory barrier) + isb // clear pipeline ret \ No newline at end of file diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 000000000..5e0ab9bdd --- /dev/null +++ b/src/utils.c @@ -0,0 +1,7 @@ +#include "printf.h" +#include "utils.h" + +void print_0x_64bit(void *p) +{ + printf("0x%x%x\n", (unsigned long)p >> 32, p); +} \ No newline at end of file diff --git a/src/vfs.c b/src/vfs.c index ff2e6035a..e7eb4dd8c 100644 --- a/src/vfs.c +++ b/src/vfs.c @@ -8,6 +8,7 @@ #include "utils.h" #include "sched.h" #include "cpio.h" +#include "fat32.h" struct mount *rootfs; @@ -27,7 +28,7 @@ int register_filesystem(struct filesystem* fs) { if (!strcmp(fs->name, "tmpfs")) { int res = tmpfs_register(); if (res == TMPFS_ERROR) { - printf("[register_filesystem] Register error"); + printf("[register_filesystem] Register tmpfs error"); return VFS_ERROR; } @@ -35,6 +36,12 @@ int register_filesystem(struct filesystem* fs) { } if (!strcmp(fs->name, "fat32")) { + int res = fat32_register(); + if (res == TMPFS_ERROR) { + printf("[register_filesystem] Register fat32 error"); + return VFS_ERROR; + } + printf("[register_filesystem] Register fat32 filesystem\n"); } @@ -81,6 +88,7 @@ void _finalComponentName(const char *pathname, char *target_component_name) int _vnode_path_traversal(struct vnode *rootnode, const char *pathname, struct vnode **target_file, char *target_component_name) { + // TODO: explain how this function work, this function is most important but quite complex int path_idx = 0; int isNextVnodeFound = 0; char temp_component_name[DNAME_INLINE_LEN]; @@ -180,7 +188,7 @@ int _vnode_path_traversal(struct vnode *rootnode, const char *pathname, struct v return FALSE; } -int _lookUp_pathname(const char* pathname, struct vnode **target_file, char *target_component_name) +int _lookUp_pathname(const char *pathname, struct vnode **target_file, char *target_component_name) { struct vnode *rootnode; int loopUp_result; @@ -195,13 +203,16 @@ int _lookUp_pathname(const char* pathname, struct vnode **target_file, char *tar loopUp_result = _vnode_path_traversal(rootnode, pathname, target_file, target_component_name); - printf("[_lookUp_pathname] (*target_file)->dentry->name: %s\n", (*target_file)->dentry->name); - // if target_file is found + if (loopUp_result) + printf("[_lookUp_pathname] Found Target: (*target_file)->dentry->name: %s\n", (*target_file)->dentry->name); + else + printf("[_lookUp_pathname] Parent: (*target_file)->dentry->name: %s\n", (*target_file)->dentry->name); + return loopUp_result; } -struct file* vfs_open(const char* pathname, int flags) { +struct file* vfs_open(const char *pathname, int flags) { if (flags == O_CREAT) { printf("\n==========> vfs_open(%s, %s) <==========\n", pathname, "O_CREAT"); } else { @@ -257,7 +268,7 @@ int vfs_write(struct file* file, const void* buf, size_t len) { return nr_byte_written; } -int vfs_read(struct file* file, void* buf, size_t len) { +int vfs_read(struct file *file, void *buf, size_t len) { if (file->vnode->v_type != REGULAR_FILE){ printf("Read a non regular file\n"); return VFS_READ_FILE_ERROR; @@ -387,7 +398,7 @@ int vfs_chdir(const char *pathname) return TRUE; } -int vfs_mount(const char* device, const char* mountpoint, const char* filesystem) +int vfs_mount(const char *device, const char *mountpoint, const char *filesystem) { printf("================== vfs_mount ==================\n"); struct vnode *target_file; @@ -400,28 +411,31 @@ int vfs_mount(const char* device, const char* mountpoint, const char* filesystem } struct mount *mt = (struct mount *) kmalloc(sizeof(struct mount)); - struct filesystem *fs = (struct filesystem *) kmalloc(sizeof(struct filesystem)); + mt->device_name = (char *) kmalloc(sizeof(char) * (strlen(device) + 1)); + strcpy(mt->device_name, device); + if (!strcmp(filesystem, "tmpfs")) { printf("[vfs_mount] tmpfs filesystem mount\n"); - fs->name = (char *) kmalloc(sizeof(char) * strlen(filesystem)); - strcpy(fs->name, filesystem); - fs->setup_mount = tmpfs_setup_mount; - fs->setup_mount(fs, mt, target_component_name); - - target_file->dentry->mount = mt; // Say this directory is mount by other device/fs - // We don't need to register tmpfs filesystem again, because tmpfs is kernel rot file system - //register_filesystem(fs); - - // Assign parent of this mountpoint as original dentry for go back to original fs - mt->root->parent = target_file->dentry; - //printf("mt->root->parent->name = %s\n", mt->root->parent->name); - return TRUE; + tmpfs.setup_mount(&tmpfs, mt, target_component_name); + // We don't need to register tmpfs filesystem again, because tmpfs is kernel root file system + //register_filesystem(&tmpfs); } - - - return FALSE; + if (!strcmp(filesystem, "fat32")) { + printf("[vfs_mount] fat32 filesystem mount\n"); + register_filesystem(&fat32); + fat32.setup_mount(&fat32, mt, target_component_name); // TODO: Should modify target_component_name to "/" ? + } + + target_file->dentry->mount = mt; // Say this directory is mount by other device/fs + mt->root->parent = target_file->dentry; // Assign parent of this mountpoint as original dentry for go back to original fs + #ifdef __FS_DEBUG + printf("mt->root->parent->name = %s\n", mt->root->parent->name); + printf("mt->device_name = %s\n", mt->device_name); + #endif + + return TRUE; } int vfs_unmount(const char* mountpoint) @@ -499,8 +513,44 @@ void _vfs_dump_file_struct() } +void vfs_ls_print_test(const char *pathname) +{ + printf("\n--------------------> vfs ls <----------------------\n"); + printf("Requested pathname : %s", pathname); + vfs_print_directory_by_pathname(pathname); + printf("-------------------------------------------------------\n"); +} + +/** + * Test cases for Lab7 + */ +void Lab7_fat32_test() +{ + printf("\n--------------> Lab7 fat32 test | Lab7_fat32_test() <--------------\n"); + //vfs_ls_print_test("/sdp1"); // TODO: Find out sdp1 dentry, but child directory not loaded from SDCARD + // Rquirement1 - Get the FAT32 partition. + _dump_fat32_metadata(&fat32_metadata); + + // Requirement 2 - Look up and open a file in FAT32. Read / Write a file in FAT32. + // Read + char buf[BLOCK_SIZE]; + struct file *f1 = vfs_open("/sdp1/FATTEST.TXT", 0); + int sz = vfs_read(f1, buf, 100); + printf("[Lab7_fat32_test] Read size: %d, content: %s\n", sz, buf); // Should be "Fat32 Test file Content."" + vfs_close(f1); + // Write + f1 = vfs_open("/sdp1/FATTEST.TXT", 0); + int sz2 = vfs_write(f1, "Hello World! This is Lab7 - FAT32 with SD card device", 53); + printf("[Lab7_fat32_test] Write size: %d\n", sz2); // Should be 53. + + // Elective 1, Create a Fat32 file + vfs_open("/sdp1/NEW.TXT", O_CREAT); + + vfs_ls_print_test("/sdp1"); +} + /** - * Test cases for VFS + * Test cases for Lab6 - VFS */ void vfs_test() { @@ -628,6 +678,7 @@ void vfs_elective2_user_process_test() sz = call_sys_read(fd, buf, 2); printf("size = %d, content = %s\n", sz, buf); + call_sys_exit(); // call_sys_mkdir("newDir"); // call_sys_open("newDir/newFile", O_CREAT); // call_sys_open("newDir/newFile87", O_CREAT); @@ -676,13 +727,5 @@ void vfs_elective2_user_process_test() // printf("Open file error\n"); // } - call_sys_exit(); } -void vfs_ls_print_test(const char *pathname) -{ - printf("\n--------------------> vfs ls <----------------------\n"); - printf("Requested pathname : %s", pathname); - vfs_print_directory_by_pathname(pathname); - printf("-------------------------------------------------------\n"); -}