diff --git a/kernel/bio.c b/kernel/bio.c
new file mode 100644
index 0000000000000000000000000000000000000000..e3558f5370ba3ea2434a5d3f8bc0d44b428713f1
--- /dev/null
+++ b/kernel/bio.c
@@ -0,0 +1,230 @@
+// Buffer cache.
+//
+// The buffer cache is a linked list of buf structures holding
+// cached copies of disk block contents.  Caching disk blocks
+// in memory reduces the number of disk reads and also provides
+// a synchronization point for disk blocks used by multiple processes.
+//
+// Interface:
+// * To get a buffer for a particular disk block, call bread.
+// * After changing buffer data, call bwrite to write it to disk.
+// * When done with the buffer, call brelse.
+// * Do not use the buffer after calling brelse.
+// * Only one process at a time can use a buffer,
+//     so do not keep them longer than necessary.
+
+
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/spinlock.h"
+#include "include/sleeplock.h"
+#include "include/riscv.h"
+#include "include/buf.h"
+#include "include/sdcard.h"
+#include "include/printf.h"
+#include "include/disk.h"
+#include "include/proc.h"
+
+struct buf buf[NBUF];
+
+int listhash(uint dev, uint sectorno){
+  return (dev+sectorno) & (NBUFLIST - 1);
+}
+
+struct {
+  struct spinlock lock;
+  struct buf head;
+} listcache[NBUFLIST];
+
+struct {
+  struct spinlock lock;
+  struct buf head;
+} freecache;
+
+void
+binit(void)
+{
+  struct buf *b;
+
+  initlock(&freecache.lock, "freecache");
+  freecache.head.freeprev = &freecache.head;
+  freecache.head.freenext = &freecache.head;
+
+  for(int i = 0; i < NBUFLIST; i++){
+    initlock(&listcache[i].lock, "listcache");
+    listcache[i].head.prev = &listcache[i].head;
+    listcache[i].head.next = &listcache[i].head;
+  }
+  int i;
+  for(b = buf, i = 2; b < buf+NBUF; b++, i++){
+    // b->refcnt = 0;
+    b->busy = 0;
+    b->dev = 0;
+    b->sectorno = i;
+    b->vaild = 0;
+    initsleeplock(&b->lock, "buffer");
+    b->freenext = freecache.head.freenext;
+    b->freeprev = &freecache.head;
+    freecache.head.freenext->freeprev = b;
+    freecache.head.freenext = b;
+    int n = listhash(b->dev, b->sectorno);
+    b->next = listcache[n].head.next;
+    b->prev = &listcache[n].head;
+    listcache[n].head.next->prev = b;
+    listcache[n].head.next = b;
+  }
+
+  // __DEBUG("binit\n");
+
+}
+
+// Look through buffer cache for block on device dev.
+// If not found, allocate a buffer.
+// In either case, return locked buffer.
+static struct buf*
+bget(uint dev, uint sectorno)
+{
+  struct proc *p = myproc();
+  while(1){
+    struct buf *b;
+    int n = listhash(dev, sectorno);
+    acquire(&listcache[n].lock);
+    for(b = listcache[n].head.next; b != &listcache[n].head; b = b->next){
+      if(b->sectorno == sectorno && b->dev == dev){
+        if(b->busy == 1){
+          release(&listcache[n].lock);
+          // slepp
+          acquire(&p->lock);
+          sleep(b, &p->lock);
+          release(&p->lock);
+          goto next;
+        }
+        else{
+          b->busy = 1;
+          release(&listcache[n].lock);
+          acquire(&freecache.lock);
+          if(b->freenext){
+            b->freenext->freeprev = b->freeprev;
+            b->freeprev->freenext = b->freenext;
+            b->freenext = NULL;
+            b->freeprev = NULL;
+          }
+          release(&freecache.lock);
+          acquiresleep(&b->lock);
+          return b;
+        }
+      }
+    }
+    release(&listcache[n].lock);
+    acquire(&freecache.lock);
+    for(b = freecache.head.freenext; b != &freecache.head; b = b->freenext){
+      b->busy = 1;
+      b->vaild = 0;
+      b->freenext->freeprev = b->freeprev;
+      b->freeprev->freenext = b->freenext;
+      b->freenext = NULL;
+      b->freeprev = NULL;
+      release(&freecache.lock);
+      n = listhash(b->dev, b->sectorno);
+      acquire(&listcache[n].lock);
+      b->next->prev = b->prev;
+      b->prev->next = b->next;
+      release(&listcache[n].lock);
+      n = listhash(dev, sectorno);
+      acquire(&listcache[n].lock);
+      b->next = listcache[n].head.next;
+      b->prev = &listcache[n].head;
+      listcache[n].head.next->prev = b;
+      listcache[n].head.next = b;
+      b->dev = dev;
+      b->sectorno = sectorno;
+      release(&listcache[n].lock);
+      acquiresleep(&b->lock);
+      return b;
+    }
+
+    release(&freecache.lock);
+    // sleep
+    acquire(&p->lock);
+    sleep(&freecache, &p->lock);
+    release(&p->lock);
+    goto next;
+
+    next:
+      continue;
+    
+  }
+}
+
+
+struct buf* 
+bread(uint dev, uint sectorno) {
+  struct buf *b;
+  b = bget(dev, sectorno);
+
+  if (!b->vaild) {
+    disk_read(b);
+    b->vaild = 1;
+  }
+
+  return b;
+}
+
+// Write b's contents to disk.  Must be locked.
+void 
+bwrite(struct buf *b) {
+  if(!holdingsleep(&b->lock))
+    panic("bwrite");
+  disk_write(b);
+  b->vaild = 1;
+}
+
+
+void
+brelse(struct buf *b)
+{
+
+  if(!holdingsleep(&b->lock))
+    panic("brelse");
+
+  releasesleep(&b->lock);
+
+  acquire(&freecache.lock);
+  b->busy = 0;
+  if(b->vaild){
+    b->freenext = &freecache.head;
+    b->freeprev = freecache.head.freeprev;
+    freecache.head.freeprev->freenext = b;
+    freecache.head.freeprev = b;
+  }
+  else{
+    b->freenext = freecache.head.freenext;
+    b->freeprev = &freecache.head;
+    freecache.head.freenext->freeprev = b;
+    freecache.head.freenext = b;
+  }
+  release(&freecache.lock);
+
+  // wakeup sleeping processes because of b is busy
+  wakeup(b);
+
+  // wakeup sleeping processes because of NOFREEBUF
+  wakeup(&freecache);
+}
+
+// void
+// bpin(struct buf *b) {
+//   acquire(&freecache.lock);
+//   // b->refcnt++;
+//   release(&freecache.lock);
+// }
+
+// void
+// bunpin(struct buf *b) {
+//   acquire(&freecache.lock);
+//   // b->refcnt--;
+//   release(&freecache.lock);
+// }
+
+
diff --git a/kernel/console.c b/kernel/console.c
new file mode 100644
index 0000000000000000000000000000000000000000..73402ea5a8095a0e780fb811b0e94be4076a4324
--- /dev/null
+++ b/kernel/console.c
@@ -0,0 +1,191 @@
+//
+// Console input and output, to the uart.
+// Reads are line at a time.
+// Implements special input characters:
+//   newline -- end of line
+//   control-h -- backspace
+//   control-u -- kill line
+//   control-d -- end of file
+//   control-p -- print process list
+//
+#include <stdarg.h>
+
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/spinlock.h"
+#include "include/sleeplock.h"
+#include "include/file.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+#include "include/proc.h"
+#include "include/sbi.h"
+
+#define BACKSPACE 0x100
+#define C(x)  ((x)-'@')  // Control-x
+
+
+void consputc(int c) {
+  if(c == BACKSPACE){
+    // if the user typed backspace, overwrite with a space.
+    sbi_console_putchar('\b');
+    sbi_console_putchar(' ');
+    sbi_console_putchar('\b');
+  } else {
+    sbi_console_putchar(c);
+  }
+}
+struct {
+  struct spinlock lock;
+  
+  // input
+#define INPUT_BUF 128
+  char buf[INPUT_BUF];
+  uint r;  // Read index
+  uint w;  // Write index
+  uint e;  // Edit index
+} cons;
+
+//
+// user write()s to the console go here.
+//
+int
+consolewrite(int user_src, uint64 src, int n)
+{
+  int i;
+
+  acquire(&cons.lock);
+  for(i = 0; i < n; i++){
+    char c;
+    if(either_copyin(&c, user_src, src+i, 1) == -1)
+      break;
+    sbi_console_putchar(c);
+  }
+  release(&cons.lock);
+
+  return i;
+}
+
+//
+// user read()s from the console go here.
+// copy (up to) a whole input line to dst.
+// user_dist indicates whether dst is a user
+// or kernel address.
+//
+int
+consoleread(int user_dst, uint64 dst, int n)
+{
+  uint target;
+  int c;
+  char cbuf;
+
+  target = n;
+  acquire(&cons.lock);
+  while(n > 0){
+    // wait until interrupt handler has put some
+    // input into cons.buffer.
+    while(cons.r == cons.w){
+      if(myproc()->killed){
+        release(&cons.lock);
+        return -1;
+      }
+      sleep(&cons.r, &cons.lock);
+    }
+
+    c = cons.buf[cons.r++ % INPUT_BUF];
+
+    if(c == C('D')){  // end-of-file
+      if(n < target){
+        // Save ^D for next time, to make sure
+        // caller gets a 0-byte result.
+        cons.r--;
+      }
+      break;
+    }
+
+    // copy the input byte to the user-space buffer.
+    cbuf = c;
+    if(either_copyout(user_dst, dst, &cbuf, 1) == -1)
+      break;
+
+    dst++;
+    --n;
+
+    if(c == '\n'){
+      // a whole line has arrived, return to
+      // the user-level read().
+      break;
+    }
+  }
+  release(&cons.lock);
+
+  return target - n;
+}
+
+//
+// the console input interrupt handler.
+// uartintr() calls this for input character.
+// do erase/kill processing, append to cons.buf,
+// wake up consoleread() if a whole line has arrived.
+//
+void
+consoleintr(int c)
+{
+  acquire(&cons.lock);
+
+  switch(c){
+  case C('P'):  // Print process list.
+    procdump();
+    break;
+  case C('U'):  // Kill line.
+    while(cons.e != cons.w &&
+          cons.buf[(cons.e-1) % INPUT_BUF] != '\n'){
+      cons.e--;
+      consputc(BACKSPACE);
+    }
+    break;
+  case C('H'): // Backspace
+  case '\x7f':
+    if(cons.e != cons.w){
+      cons.e--;
+      consputc(BACKSPACE);
+    }
+    break;
+  default:
+    if(c != 0 && cons.e-cons.r < INPUT_BUF){
+      #ifndef QEMU
+      if (c == '\r') break;     // on k210, "enter" will input \n and \r
+      #else
+      c = (c == '\r') ? '\n' : c;
+      #endif
+      // echo back to the user.
+      consputc(c);
+
+      // store for consumption by consoleread().
+      cons.buf[cons.e++ % INPUT_BUF] = c;
+
+      if(c == '\n' || c == C('D') || cons.e == cons.r+INPUT_BUF){
+        // wake up consoleread() if a whole line (or end-of-file)
+        // has arrived.
+        cons.w = cons.e;
+        wakeup(&cons.r);
+      }
+    }
+    break;
+  }
+  
+  release(&cons.lock);
+}
+
+void
+consoleinit(void)
+{
+  initlock(&cons.lock, "cons");
+
+  cons.e = cons.w = cons.r = 0;
+  
+  // connect read and write system calls
+  // to consoleread and consolewrite.
+  devsw[CONSOLE].read = consoleread;
+  devsw[CONSOLE].write = consolewrite;
+}
diff --git a/kernel/disk.c b/kernel/disk.c
new file mode 100644
index 0000000000000000000000000000000000000000..46bc9ccc0b413fb65a422a60399c9320931a6c39
--- /dev/null
+++ b/kernel/disk.c
@@ -0,0 +1,49 @@
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+
+#include "include/buf.h"
+
+#ifndef QEMU
+#include "include/sdcard.h"
+#include "include/dmac.h"
+#else
+#include "include/virtio.h"
+#endif 
+
+void disk_init(void)
+{
+    #ifdef QEMU
+    virtio_disk_init();
+	#else 
+	sdcard_init();
+    #endif
+}
+
+void disk_read(struct buf *b)
+{
+    #ifdef QEMU
+	virtio_disk_rw(b, 0);
+    #else 
+	sdcard_read_sector(b->data, b->sectorno);
+	#endif
+}
+
+void disk_write(struct buf *b)
+{
+    #ifdef QEMU
+	virtio_disk_rw(b, 1);
+    #else 
+	sdcard_write_sector(b->data, b->sectorno);
+	#endif
+}
+
+void disk_intr(void)
+{
+    #ifdef QEMU
+    virtio_disk_intr();
+    #else 
+    dmac_intr(DMAC_CHANNEL0);
+    #endif
+}
diff --git a/kernel/dmac.c b/kernel/dmac.c
new file mode 100644
index 0000000000000000000000000000000000000000..97a4fe39f0903ccc64ffc8f395c48f4fb9492617
--- /dev/null
+++ b/kernel/dmac.c
@@ -0,0 +1,354 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/types.h"
+#include "include/dmac.h"
+#include "include/fpioa.h"
+#include "include/plic.h"
+#include "include/sysctl.h"
+#include "include/utils.h"
+#include "include/printf.h"
+#include "include/memlayout.h"
+#include "include/sleeplock.h"
+#include "include/proc.h"
+
+volatile dmac_t *const dmac = (dmac_t *)DMAC_V;
+
+static int is_memory(uintptr_t address)
+{
+    enum
+    {
+        mem_len = 6 * 1024 * 1024,
+        mem_no_cache_len = 8 * 1024 * 1024,
+    };
+    return ((address >= 0x80000000) && (address < 0x80000000 + mem_len)) || ((address >= 0x40000000) && (address < 0x40000000 + mem_no_cache_len)) || (address == 0x50450040);
+}
+
+uint64 dmac_read_id(void)
+{
+    return dmac->id;
+}
+
+uint64 dmac_read_version(void)
+{
+    return dmac->compver;
+}
+
+uint64 dmac_read_channel_id(dmac_channel_number_t channel_num)
+{
+    return dmac->channel[channel_num].axi_id;
+}
+
+static void dmac_enable(void)
+{
+    dmac_cfg_u_t dmac_cfg;
+
+    dmac_cfg.data = readq(&dmac->cfg);
+    dmac_cfg.cfg.dmac_en = 1;
+    dmac_cfg.cfg.int_en = 1;
+    writeq(dmac_cfg.data, &dmac->cfg);
+}
+
+void dmac_disable(void)
+{
+    dmac_cfg_u_t dmac_cfg;
+
+    dmac_cfg.data = readq(&dmac->cfg);
+    dmac_cfg.cfg.dmac_en = 0;
+    dmac_cfg.cfg.int_en = 0;
+    writeq(dmac_cfg.data, &dmac->cfg);
+}
+
+void dmac_channel_enable(dmac_channel_number_t channel_num)
+{
+    dmac_chen_u_t chen;
+
+    chen.data = readq(&dmac->chen);
+
+    switch(channel_num)
+    {
+        case DMAC_CHANNEL0:
+            chen.dmac_chen.ch1_en = 1;
+            chen.dmac_chen.ch1_en_we = 1;
+            break;
+        case DMAC_CHANNEL1:
+            chen.dmac_chen.ch2_en = 1;
+            chen.dmac_chen.ch2_en_we = 1;
+            break;
+        case DMAC_CHANNEL2:
+            chen.dmac_chen.ch3_en = 1;
+            chen.dmac_chen.ch3_en_we = 1;
+            break;
+        case DMAC_CHANNEL3:
+            chen.dmac_chen.ch4_en = 1;
+            chen.dmac_chen.ch4_en_we = 1;
+            break;
+        case DMAC_CHANNEL4:
+            chen.dmac_chen.ch5_en = 1;
+            chen.dmac_chen.ch5_en_we = 1;
+            break;
+        case DMAC_CHANNEL5:
+            chen.dmac_chen.ch6_en = 1;
+            chen.dmac_chen.ch6_en_we = 1;
+            break;
+        default:
+            break;
+    }
+
+    writeq(chen.data, &dmac->chen);
+}
+
+void dmac_channel_disable(dmac_channel_number_t channel_num)
+{
+    dmac_chen_u_t chen;
+
+    chen.data = readq(&dmac->chen);
+
+    switch(channel_num)
+    {
+        case DMAC_CHANNEL0:
+            chen.dmac_chen.ch1_en = 0;
+            chen.dmac_chen.ch1_en_we = 1;
+            break;
+        case DMAC_CHANNEL1:
+            chen.dmac_chen.ch2_en = 0;
+            chen.dmac_chen.ch2_en_we = 1;
+            break;
+        case DMAC_CHANNEL2:
+            chen.dmac_chen.ch3_en = 0;
+            chen.dmac_chen.ch3_en_we = 1;
+            break;
+        case DMAC_CHANNEL3:
+            chen.dmac_chen.ch4_en = 0;
+            chen.dmac_chen.ch4_en_we = 1;
+            break;
+        case DMAC_CHANNEL4:
+            chen.dmac_chen.ch5_en = 0;
+            chen.dmac_chen.ch5_en_we = 1;
+            break;
+        case DMAC_CHANNEL5:
+            chen.dmac_chen.ch6_en = 0;
+            chen.dmac_chen.ch6_en_we = 1;
+            break;
+        default:
+            break;
+    }
+
+    writeq(chen.data, &dmac->chen);
+}
+
+void dmac_enable_common_interrupt_status(void)
+{
+    dmac_commonreg_intstatus_enable_u_t intstatus;
+
+    intstatus.data = readq(&dmac->com_intstatus_en);
+    intstatus.intstatus_enable.enable_slvif_dec_err_intstat = 1;
+    intstatus.intstatus_enable.enable_slvif_wr2ro_err_intstat = 1;
+    intstatus.intstatus_enable.enable_slvif_rd2wo_err_intstat = 1;
+    intstatus.intstatus_enable.enable_slvif_wronhold_err_intstat = 1;
+    intstatus.intstatus_enable.enable_slvif_undefinedreg_dec_err_intstat = 1;
+
+    writeq(intstatus.data, &dmac->com_intstatus_en);
+}
+
+void dmac_enable_common_interrupt_signal(void)
+{
+    dmac_commonreg_intsignal_enable_u_t intsignal;
+
+    intsignal.data = readq(&dmac->com_intsignal_en);
+    intsignal.intsignal_enable.enable_slvif_dec_err_intsignal = 1;
+    intsignal.intsignal_enable.enable_slvif_wr2ro_err_intsignal = 1;
+    intsignal.intsignal_enable.enable_slvif_rd2wo_err_intsignal = 1;
+    intsignal.intsignal_enable.enable_slvif_wronhold_err_intsignal = 1;
+    intsignal.intsignal_enable.enable_slvif_undefinedreg_dec_err_intsignal = 1;
+
+    writeq(intsignal.data, &dmac->com_intsignal_en);
+}
+
+static void dmac_enable_channel_interrupt(dmac_channel_number_t channel_num)
+{
+    writeq(0xffffffff, &dmac->channel[channel_num].intclear);
+    writeq(0x2, &dmac->channel[channel_num].intstatus_en);
+}
+
+void dmac_disable_channel_interrupt(dmac_channel_number_t channel_num)
+{
+    writeq(0, &dmac->channel[channel_num].intstatus_en);
+}
+
+static void dmac_chanel_interrupt_clear(dmac_channel_number_t channel_num)
+{
+    writeq(0xffffffff, &dmac->channel[channel_num].intclear);
+}
+
+int dmac_set_channel_param(dmac_channel_number_t channel_num,
+                           const void *src, void *dest, dmac_address_increment_t src_inc, dmac_address_increment_t dest_inc,
+                           dmac_burst_trans_length_t dmac_burst_size,
+                           dmac_transfer_width_t dmac_trans_width,
+                           uint32 blockSize)
+{
+    dmac_ch_ctl_u_t ctl;
+    dmac_ch_cfg_u_t cfg_u;
+
+    int mem_type_src = is_memory((uintptr_t)src), mem_type_dest = is_memory((uintptr_t)dest);
+    dmac_transfer_flow_t flow_control;
+    if(mem_type_src == 0 && mem_type_dest == 0)
+    {
+        flow_control = DMAC_PRF2PRF_DMA;
+    } else if(mem_type_src == 1 && mem_type_dest == 0)
+        flow_control = DMAC_MEM2PRF_DMA;
+    else if(mem_type_src == 0 && mem_type_dest == 1)
+        flow_control = DMAC_PRF2MEM_DMA;
+    else
+        flow_control = DMAC_MEM2MEM_DMA;
+
+    /**
+     * cfg register must configure before ts_block and
+     * sar dar register
+     */
+    cfg_u.data = readq(&dmac->channel[channel_num].cfg);
+
+    cfg_u.ch_cfg.tt_fc = flow_control;
+    cfg_u.ch_cfg.hs_sel_src = mem_type_src ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE;
+    cfg_u.ch_cfg.hs_sel_dst = mem_type_dest ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE;
+    cfg_u.ch_cfg.src_per = channel_num;
+    cfg_u.ch_cfg.dst_per = channel_num;
+    cfg_u.ch_cfg.src_multblk_type = 0;
+    cfg_u.ch_cfg.dst_multblk_type = 0;
+
+    writeq(cfg_u.data, &dmac->channel[channel_num].cfg);
+
+    dmac->channel[channel_num].sar = (uint64)src;
+    dmac->channel[channel_num].dar = (uint64)dest;
+
+    ctl.data = readq(&dmac->channel[channel_num].ctl);
+    ctl.ch_ctl.sms = DMAC_MASTER1;
+    ctl.ch_ctl.dms = DMAC_MASTER2;
+    /* master select */
+    ctl.ch_ctl.sinc = src_inc;
+    ctl.ch_ctl.dinc = dest_inc;
+    /* address incrememt */
+    ctl.ch_ctl.src_tr_width = dmac_trans_width;
+    ctl.ch_ctl.dst_tr_width = dmac_trans_width;
+    /* transfer width */
+    ctl.ch_ctl.src_msize = dmac_burst_size;
+    ctl.ch_ctl.dst_msize = dmac_burst_size;
+
+    writeq(ctl.data, &dmac->channel[channel_num].ctl);
+
+    writeq(blockSize - 1, &dmac->channel[channel_num].block_ts);
+    /*the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */
+    /* transferred in a dma block transfer */
+    return 0;
+}
+
+void dmac_init(void)
+{
+    uint64 tmp;
+    dmac_commonreg_intclear_u_t intclear;
+    dmac_cfg_u_t dmac_cfg;
+    dmac_reset_u_t dmac_reset;
+
+    sysctl_clock_enable(SYSCTL_CLOCK_DMA);
+    // __DEBUG("[dmac_init] dma clk=%d\n", sysctl_clock_get_freq(SYSCTL_CLOCK_DMA));
+
+    dmac_reset.data = readq(&dmac->reset);
+    dmac_reset.reset.rst = 1;
+    writeq(dmac_reset.data, &dmac->reset);
+    while(dmac_reset.reset.rst)
+        dmac_reset.data = readq(&dmac->reset);
+
+    /*reset dmac */
+
+    intclear.data = readq(&dmac->com_intclear);
+    intclear.com_intclear.clear_slvif_dec_err_intstat = 1;
+    intclear.com_intclear.clear_slvif_wr2ro_err_intstat = 1;
+    intclear.com_intclear.clear_slvif_rd2wo_err_intstat = 1;
+    intclear.com_intclear.clear_slvif_wronhold_err_intstat = 1;
+    intclear.com_intclear.clear_slvif_undefinedreg_dec_err_intstat = 1;
+    writeq(intclear.data, &dmac->com_intclear);
+    /* clear common register interrupt */
+
+    dmac_cfg.data = readq(&dmac->cfg);
+    dmac_cfg.cfg.dmac_en = 0;
+    dmac_cfg.cfg.int_en = 0;
+    writeq(dmac_cfg.data, &dmac->cfg);
+    /* disable dmac and disable interrupt */
+
+    while(readq(&dmac->cfg))
+        ;
+    tmp = readq(&dmac->chen);
+    tmp &= ~0xf;
+    writeq(tmp, &dmac->chen);
+    /* disable all channel before configure */
+    dmac_enable();
+}
+
+void dmac_set_single_mode(dmac_channel_number_t channel_num,
+                          const void *src, void *dest, dmac_address_increment_t src_inc,
+                          dmac_address_increment_t dest_inc,
+                          dmac_burst_trans_length_t dmac_burst_size,
+                          dmac_transfer_width_t dmac_trans_width,
+                          uint64 block_size)
+{
+    dmac_chanel_interrupt_clear(channel_num);
+    dmac_channel_disable(channel_num);
+    dmac_wait_idle(channel_num);
+    dmac_set_channel_param(channel_num, src, dest, src_inc, dest_inc,
+                           dmac_burst_size, dmac_trans_width, block_size);
+    dmac_enable();
+    dmac_enable_channel_interrupt(channel_num);
+    dmac_channel_enable(channel_num);
+}
+
+int dmac_is_done(dmac_channel_number_t channel_num)
+{
+    if(readq(&dmac->channel[channel_num].intstatus) & 0x2)
+        return 1;
+    else
+        return 0;
+}
+
+void dmac_wait_done(dmac_channel_number_t channel_num)
+{
+    dmac_wait_idle(channel_num);
+}
+
+int dmac_is_idle(dmac_channel_number_t channel_num)
+{
+    dmac_chen_u_t chen;
+    chen.data = readq(&dmac->chen);
+    if((chen.data >> channel_num) & 0x1UL)
+        return 0;
+    else
+        return 1;
+}
+
+static void *dmac_chan = (void *) DMAC_V;
+
+void dmac_wait_idle(dmac_channel_number_t channel_num)
+{
+    while(!dmac_is_idle(channel_num)) {
+        acquire(&myproc()->lock);
+        sleep(dmac_chan, &myproc()->lock);
+        release(&myproc()->lock);
+    }
+}
+
+void dmac_intr(dmac_channel_number_t channel_num)
+{
+    dmac_chanel_interrupt_clear(channel_num);
+    wakeup(dmac_chan);
+}
\ No newline at end of file
diff --git a/kernel/entry_k210.S b/kernel/entry_k210.S
new file mode 100644
index 0000000000000000000000000000000000000000..f5d23788d9a2ee9f71df45db9bcd97c576944cd7
--- /dev/null
+++ b/kernel/entry_k210.S
@@ -0,0 +1,28 @@
+    .section .text.entry
+    .globl _start
+_start:
+    add t0, a0, 1
+    slli t0, t0, 14
+    // lui sp, %hi(boot_stack)
+	la sp, boot_stack
+    add sp, sp, t0
+
+    // add by retrhelo, write tp reg 
+    // csrr t1, mhartid 
+    // mv tp, t1
+
+    // lui t0, %hi(main)
+    // addi t0, t0, %lo(main)
+    // jr t0
+    call main
+
+loop:
+    j loop
+
+    .section .bss.stack
+    .align 12
+    .globl boot_stack
+boot_stack:
+    .space 4096 * 4 * 2
+    .globl boot_stack_top
+boot_stack_top:
diff --git a/kernel/entry_qemu.S b/kernel/entry_qemu.S
new file mode 100644
index 0000000000000000000000000000000000000000..5ea9027105a09d16cad37942ac9df933678a0037
--- /dev/null
+++ b/kernel/entry_qemu.S
@@ -0,0 +1,19 @@
+    .section .text
+    .globl _entry
+_entry:
+    add t0, a0, 1
+    slli t0, t0, 14
+    la sp, boot_stack
+    add sp, sp, t0
+    call main
+
+loop:
+    j loop
+
+    .section .bss.stack
+    .align 12
+    .globl boot_stack
+boot_stack:
+    .space 4096 * 4 * 2
+    .globl boot_stack_top
+boot_stack_top:
diff --git a/kernel/exec.c b/kernel/exec.c
new file mode 100644
index 0000000000000000000000000000000000000000..bd4192595ff1ee1fb0267eaace9f0051fc50aec2
--- /dev/null
+++ b/kernel/exec.c
@@ -0,0 +1,661 @@
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+#include "include/spinlock.h"
+#include "include/sleeplock.h"
+#include "include/proc.h"
+#include "include/elf.h"
+#include "include/fat32.h"
+#include "include/kalloc.h"
+#include "include/vm.h"
+#include "include/printf.h"
+#include "include/string.h"
+
+// Load a program segment into pagetable at virtual address va.
+// va must be page-aligned
+// and the pages from va to va+sz must already be mapped.
+// Returns 0 on success, -1 on failure.static inline __attribute__((const))
+
+#define ELF_PAGEALIGN(_v) (((_v) + PGSIZE - 1) & ~(PGSIZE - 1))
+#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(PGSIZE-1))
+
+int is_power_of_2(unsigned long n)
+{
+	return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+
+
+void init_free_mem(struct proc *p,uint64 sz){
+  p->free_seg->start=sz+0x10000000;
+  p->free_seg->type=1;
+  p->free_seg->len=TRAPFRAME-sz;
+  
+}
+int
+loadseg(pagetable_t pagetable, uint64 va, struct dirent *ep, uint offset, uint sz)
+{
+  uint i, n;
+  uint64 off;
+  uint64 pa;
+  off = va-PGROUNDDOWN(va);
+  va=PGROUNDDOWN(va);
+  for(i = 0; i < sz; i += PGSIZE){
+    // __DEBUG("va = %p",va);
+    pa = walkaddr(pagetable, va + i);
+    if(pa == NULL)
+      panic("loadseg: address should exist");
+    if(sz - i < PGSIZE)
+      n = sz - i;
+    else
+      n = PGSIZE;
+    if(eread(ep, 0, (uint64)pa+off, offset+i, n) != n){
+      __ERROR("");
+      return -1;
+    }
+    off=0;
+  }
+
+  return 0;
+}
+
+int
+loadseg2(pagetable_t pagetable, uint64 va, struct dirent *ep, uint offset, uint sz)
+{
+  uint i, n;
+  uint64 off;
+  uint64 pa;
+  off = va-PGROUNDDOWN(va);
+  va=PGROUNDDOWN(va);
+  for(i = 0; i < sz; i += PGSIZE){
+    pa = walkaddr2(pagetable, va + i);
+    if(pa == NULL)
+      panic("loadseg: address should exist");
+    if(sz - i < PGSIZE)
+      n = sz - i;
+    else
+      n = PGSIZE;
+    if(eread(ep, 0, (uint64)pa+off, offset+i, n) != n){
+      return -1;
+    }
+    off=0;
+  }
+  return 0;
+}
+uint64 load_dy_file(struct elfhdr elf,struct dirent *ep,pagetable_t pagetable,pagetable_t kpagetable,uint64 *sz){
+  int i, off;
+  uint64 load_addr =PGROUNDUP(*sz),sz1;
+  struct proghdr ph;
+  int load_addr_set=0;
+  for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
+    if(eread(ep, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
+      goto bad;
+    if(ph.type != PT_LOAD)
+      continue;
+    if(ph.memsz < ph.filesz)
+      goto bad;
+    if(ph.vaddr + ph.memsz < ph.vaddr)
+      goto bad;
+    uint64 addr;
+
+    if((sz1=uvmalloc(pagetable, kpagetable, load_addr+PGROUNDDOWN(ph.vaddr), load_addr+ph.vaddr+ph.memsz)) == 0)
+      goto bad;
+    *sz = sz1;
+    uint64 size = ph.filesz + PAGE_OFFSET(ph.vaddr, PGSIZE);
+    uint64 off = ph.off - PAGE_OFFSET(ph.vaddr, PGSIZE);
+    addr = DOWN_ALIGN(load_addr+ph.vaddr, PGSIZE);
+    if(loadseg2(pagetable, addr, ep, off, size) < 0)
+      goto bad;
+    if (!load_addr_set &&
+			    elf.type == ET_DYN) {
+				load_addr = addr - PAGE_OFFSET(ph.vaddr, PGSIZE);
+				load_addr_set = 1;
+		}
+  }
+  return load_addr;
+bad:
+  return -1;
+}
+
+unsigned long max(unsigned long a,unsigned long b){
+  if(a>b){
+    return a;
+  }else{
+    return b;
+  }
+  return -1;
+}
+
+int exec(char *path, char **argv,char **envp)
+{
+  char *s, *last;
+  int phnum=0,i, off,frist_ph=0;//load_addr_set=0,
+  uint64 argc=0,envc=1, sz = 0, sp, argv_stack[MAXARG+1],envp_stack[MAXARG+1],
+          phdr_addr=0,auxv_stack[AT_VECTOR_SIZE+1], stackbase,interp_load_addr=0,dy_entry=0;
+  struct elfhdr elf,interp_elf;
+  struct dirent *ep,*newep,*interp_ep=0;
+  struct proghdr ph;
+  pagetable_t pagetable = 0, oldpagetable;
+  pagetable_t kpagetable = 0, oldkpagetable;
+  struct proc *p = myproc();
+  unsigned long load_bias = 0,total_size = 0;//,vaddr;
+  stackbase = VUSTACK;
+  if ((kpagetable = (pagetable_t)kalloc()) == NULL) {
+    return -1;
+  }
+  memmove(kpagetable, p->kpagetable, PGSIZE);
+  for (int i = 0; i < PX(2, MAXUVA); i++) {
+    kpagetable[i] = 0;
+  }
+  if((ep = ename(path)) == NULL) {
+    #ifdef DEBUG
+    __DEBUG("[exec] %s not found\n", path);
+    #endif
+    goto bad;
+  }
+  elock(ep);
+  // Check ELF header
+  if(eread(ep, 0, (uint64) &elf, 0, sizeof(elf)) != sizeof(elf))
+    goto bad;
+  if(elf.magic != ELF_MAGIC)
+    goto bad;
+  if((pagetable = proc_pagetable(p)) == NULL)
+    goto bad;
+  for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
+    if(eread(ep, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
+      goto bad;
+    if(ph.type == PT_INTERP){
+      char *elf_interpreter;
+      if (ph.filesz > PATH_MAX || ph.filesz < 2)
+			  goto bad;
+
+      elf_interpreter = kalloc();
+      if (!elf_interpreter)
+			  goto bad;
+      
+      if(eread(ep, 0, (uint64)elf_interpreter, ph.off, ph.filesz) != ph.filesz)
+        goto out;
+
+      if (elf_interpreter[ph.filesz - 1] != '\0')
+			  goto out;
+      __DEBUG("IN DY LINK------->%s\n",elf_interpreter);
+
+      if(strncmp(elf_interpreter,"/lib/ld-musl-riscv64-sf.so.1",25)==0){
+        if((interp_ep = ename("/libc.so")) == NULL) {
+          __DEBUG("NO SUCH FILE!\n");
+          goto out;
+        }
+      }
+      else{
+        if((interp_ep = ename(elf_interpreter)) == NULL) {
+          __DEBUG("NO SUCH FILE!\n");
+          goto out;
+        }
+      }
+      kfree(elf_interpreter);
+	    if (interp_ep) {
+      }
+      sz=ph.vaddr + ph.memsz;
+      continue;
+    out:
+      kfree(elf_interpreter);
+      goto bad;
+    }
+    if(ph.type != PT_LOAD)
+      continue;
+    if(!frist_ph){
+      frist_ph=1;
+    }
+    if(ph.memsz < ph.filesz)
+      goto bad;
+    if(ph.vaddr + ph.memsz < ph.vaddr)
+      goto bad;
+    // __DEBUG("ph.vaddr = %p ph.memsz = %p",ph.vaddr,ph.memsz);
+    int flags = 0;
+		flags |= (ph.flags & ELF_PROG_FLAG_EXEC) ? PTE_X : 0;
+		flags |= (ph.flags & ELF_PROG_FLAG_WRITE) ? PTE_W : 0;
+		flags |= (ph.flags & ELF_PROG_FLAG_READ) ? PTE_R : 0;
+    if(apply_bvmem2(pagetable,kpagetable,ph.vaddr,ph.memsz,flags) < 0){
+      __ERROR("sz = %p",sz);
+      goto bad;
+    }
+    sz=ph.vaddr + ph.memsz;
+    total_size+=ph.memsz;
+  }
+  if(interp_ep){
+  }
+  p->my_seg.prosize=sz;
+  sz = PGROUNDUP(sz);
+  if(uvmallocpage2(pagetable, kpagetable, stackbase - PGSIZE, PTE_V|PTE_W|PTE_R) < 0){
+    __ERROR("error");
+    goto bad;
+  }
+  stackbase = VUSTACK - PGSIZE;
+  sp = VUSTACK;
+  
+  if(interp_ep){
+    if(eread(interp_ep, 0, (uint64) &interp_elf, 0, sizeof(interp_elf)) != sizeof(interp_elf))
+      goto bad;
+    dy_entry=load_dy_file(interp_elf,interp_ep,pagetable,kpagetable,&sz);
+    
+    interp_load_addr = dy_entry;
+    dy_entry += interp_elf.entry;
+    if(dy_entry==-1){
+      __DEBUG("load dy file fail!\n");
+      goto bad;
+    }
+  }
+  sz = PGROUNDUP(sz);
+  for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
+    if(eread(ep, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
+      goto bad;
+    if(ph.type != PT_LOAD)
+      continue;
+    if(ph.memsz < ph.filesz)
+      goto bad;
+    if(ph.vaddr + ph.memsz < ph.vaddr)
+      goto bad;
+    sp-=sizeof(struct elf_seg);
+    sp-= sp % 16;
+    struct elf_seg file_seg;
+    file_seg.filesz=ph.filesz;
+    file_seg.memsz=ph.memsz;
+    file_seg.off=ph.off;
+    file_seg.vaddr=load_bias + ph.vaddr;
+    if(copyout(pagetable, sp, (char *)&file_seg, sizeof(struct elf_seg)) < 0)
+      goto bad;
+    
+    ++phnum;
+    if (ph.off <= elf.phoff && elf.phoff < ph.off + ph.filesz) {
+      phdr_addr = elf.phoff - ph.off + ph.vaddr;
+    }
+  }
+  uint64  new_my_seg = sp;
+  newep=ep;
+  eunlock(ep);
+  eput(ep);
+  ep = 0;
+  p = myproc();
+  uint64 oldsz = p->sz;
+  uint64 oldustack_base = p->ustack_base;
+  uint64 oldmmap_size = p->mmap_size;
+  if(argv!=0){
+    for(; argv[argc]; argc++) {
+      if(argc >= MAXARG)
+        goto bad;
+      sp -= strlen(argv[argc]) + 1;
+      sp -= sp % 16; // riscv sp must be 16-byte aligned
+      if(sp < stackbase)
+        goto bad;
+      // __DEBUG("sp = %p",sp);
+      //printf("exec--------------------------------->%s\n",argv[argc]);
+      if(copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
+        goto bad;
+      argv_stack[argc + 1] = sp;
+    }
+  }
+  argv_stack[argc + 1] = 0;
+  argv_stack[0] = argc;
+  char *envVariable[1] = {"LD_LIBRARY_PATH=/"};
+  for (i = 0; i < envc; i++) {
+      sp -= strlen(envVariable[i]) + 1;
+      sp -= sp % 16;  // riscv sp must be 16-byte aligned
+      if (sp < stackbase)
+          goto bad;
+      if (copyout(pagetable, sp, envVariable[i], strlen(envVariable[i]) + 1) < 0)
+          goto bad;
+      envp_stack[i] = sp;
+  }
+  envp_stack[envc] = 0;
+  static char k_rand_bytes[] = {0, 1, 2,  3,  4,  5,  6,  7,
+                                8, 9, 10, 11, 12, 13, 14, 15};
+  sp -= 32;
+  sp -= sp % 16;
+  uint64 u_rand_bytes = sp;
+
+  if(copyout(pagetable, sp, (char *)k_rand_bytes, sizeof(k_rand_bytes)) < 0)
+    goto bad;
+
+  uint64* elf_info = auxv_stack;
+#define NEW_AUX_ENT(id, val) \
+	do { \
+		*elf_info++ = id; \
+		*elf_info++ = val; \
+	} while (0)
+
+    #define ELF_HWCAP 0  /* we assume this risc-v cpu have no extensions */
+	#define ELF_EXEC_PAGESIZE PGSIZE
+
+    /* these function always return 0 */
+	#define from_kuid_munged(x, y) (0)
+	#define from_kgid_munged(x,y) (0)
+
+  uint64 secureexec = 0;
+	NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); //CPU的extension信息
+	NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); //PAGE_SIZE
+	NEW_AUX_ENT(AT_PHDR, phdr_addr);// Phdr * phdr_addr; 指向用户态。
+	NEW_AUX_ENT(AT_PHENT, sizeof(struct proghdr)); //每个 Phdr 的大小
+	NEW_AUX_ENT(AT_PHNUM, elf.phnum); //phdr的数量
+	NEW_AUX_ENT(AT_BASE, interp_load_addr);
+	NEW_AUX_ENT(AT_ENTRY, elf.entry);//源程序的入口
+	NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid));// 0
+	NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid));// 0
+	NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid));// 0
+	NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid));// 0
+	NEW_AUX_ENT(AT_SECURE, secureexec);//安全,默认1。该模式下不会启用LD_LIBRARY_PATH等
+	NEW_AUX_ENT(AT_RANDOM, u_rand_bytes);//16byte随机数的地址。
+#ifdef ELF_HWCAP2
+	NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2);
+  #endif
+	NEW_AUX_ENT(AT_EXECFN, argv_stack[1]/*用户态地址*/); /* 传递给动态连接器该程序的名称 */
+    NEW_AUX_ENT(0, 0);
+#undef NEW_AUX_ENT
+  
+  uint64 copy_size = (elf_info - auxv_stack) * sizeof(uint64);
+  
+  sp -= copy_size; /* now elf_info is the stack top */
+  sp -= sp % 16;
+  if (sp < stackbase)
+    goto bad;
+  if (copyout(pagetable, sp, (char*)auxv_stack, copy_size) < 0)
+      goto bad;
+  
+  sp -= (envc+1) * sizeof(uint64);
+  sp -= sp % 16;
+  if(sp < stackbase)
+    goto bad;
+  // __DEBUG("sp = %p",sp);
+  if(copyout(pagetable, sp, (char *)envp_stack, (envc)*sizeof(uint64)) < 0)
+    goto bad;
+  p->trapframe->a2 = sp;
+  // push the array of argv[] pointers.
+  sp -= (argc+2) * sizeof(uint64);
+  sp -= sp % 16;
+  if(sp < stackbase)
+    goto bad;
+  if(copyout(pagetable, sp, (char *)argv_stack, (argc+2)*sizeof(uint64)) < 0)
+    goto bad;
+  p->trapframe->a1 =sp;
+  for(last=s=path; *s; s++)
+    if(*s == '/')
+      last = s+1;
+  safestrcpy(p->name, last, sizeof(p->name));
+    
+  // Commit to the user image.
+  // recycle_seg(p);
+  oldpagetable = p->pagetable;
+  oldkpagetable = p->kpagetable;
+  p->pagetable = pagetable;
+  p->kpagetable = kpagetable;
+  sz = PGROUNDUP(sz);
+  p->sz = sz;
+  if(apply_bvmem(0,sz,PTE_R|PTE_W) < 0){
+    __ERROR("sz = %p",sz);
+    goto bad;
+  }
+  p->static_sz=sz;
+  p->sbrk_base = sz;
+  p->sbrk_size = 0;
+  p->mmap_size = 0;
+  p->myep=newep;
+  p->my_seg.baseaddr=new_my_seg;
+  p->my_seg.num=phnum;
+  p->ustack_base = stackbase;
+  if(interp_ep){
+    if(dy_entry==-1){
+      __DEBUG("load dy file fail!\n");
+      goto bad;
+    }
+    p->trapframe->epc=dy_entry;
+    // printf("dy_entry----------------------->%d\n",dy_entry);
+  }else{
+    p->trapframe->epc = elf.entry;  // initial program counter = main
+  }
+  p->trapframe->sp = sp; // initial stack pointer
+  // __DEBUG("argc = %d",argv_stack[0]);
+  // for(int i = 0;i<argc;i++){
+  //   __DEBUG("%s",argv_stack[i + 1]);
+  // }
+  proc_freepagetable(oldpagetable, oldsz, oldustack_base, oldmmap_size);
+  w_satp(MAKE_SATP(p->kpagetable));
+  sfence_vma();
+  kvmfree(oldkpagetable, 0);
+  // initfreeseg(p);
+  // initseg(p);
+  // init_free_mem(p,sz);
+  return argc; // this ends up in a0, the first argument to main(argc, argv)
+
+ bad:
+  #ifdef DEBUG
+  __DEBUG("[exec] reach bad\n");
+  #endif
+  if(pagetable)
+    proc_freepagetable(pagetable, sz, stackbase, 0);
+  if(kpagetable)
+    kvmfree(kpagetable, 0);
+  if(ep){
+    eunlock(ep);
+    eput(ep);
+  }
+  return -1;
+}
+int count(char **array,struct binprm *bprm){
+   int n;
+
+  for(n = 0; array[n]; n++)
+    ;
+  return n;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// int binary_handler(struct binprm *bprm){
+//   uint64  sz = 0, sp, argvstack[MAXARG+1],argpstack[MAXARG+1], stackbase;
+//   struct elfhdr elf;
+//   struct proc *p = myproc();
+//   struct proghdr ph;
+//   pagetable_t pagetable = 0, oldpagetable;
+//   pagetable_t kpagetable = 0, oldkpagetable;
+//   int off,i;
+//   if ((kpagetable = (pagetable_t)kalloc()) == NULL) {
+//     return -1;
+//   }
+//   // __DEBUG("4\n");
+//   memmove(kpagetable, p->kpagetable, PGSIZE);
+//   for (int i = 0; i < PX(2, MAXUVA); i++) {
+//     kpagetable[i] = 0;
+//   }
+//   elock(bprm->file);
+//   if(eread(bprm->file, 0, (uint64) &elf, 0, sizeof(elf)) != sizeof(elf)){
+//     goto bad;
+//   }
+//   if(elf.magic != ELF_MAGIC){
+//     goto bad; 
+//   }
+//   if((pagetable = proc_pagetable(p)) == NULL)
+//     goto bad;
+//   // Load program into memory.
+//   for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
+//     if(eread(bprm->file, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
+//       goto bad;
+//     if(ph.type != PT_LOAD)
+//       continue;
+//     if(ph.memsz < ph.filesz)
+//       goto bad;
+//     if(ph.vaddr + ph.memsz < ph.vaddr)
+//       goto bad;
+//     uint64 sz1;
+//     if((sz1 = uvmalloc(pagetable, kpagetable, sz, ph.vaddr + ph.memsz)) == 0)
+//       goto bad;
+//     sz = sz1;
+//     if(ph.vaddr % PGSIZE != 0)
+//       goto bad;
+//     if(loadseg(pagetable, ph.vaddr, bprm->file, ph.off, ph.filesz) < 0)
+//       goto bad;
+//   }
+//   // __DEBUG("5\n");
+//   eunlock(bprm->file);
+//   eput(bprm->file);
+//   bprm->file = 0;
+
+//   uint64 oldsz = p->sz;
+
+//   // Allocate two pages at the next page boundary.
+//   // Use the second as the user stack.
+//   sz = PGROUNDUP(sz);
+//   uint64 sz1;
+//   if((sz1 = uvmalloc(pagetable, kpagetable, sz, sz + 2*PGSIZE)) == 0)
+//     goto bad;
+//   sz = sz1;
+//   uvmclear(pagetable, sz-2*PGSIZE);
+//   sp = sz;
+//   stackbase = sp - PGSIZE;
+//   int argvc;
+//   int argpc;
+//   // Push argument strings, prepare rest of stack in ustack.
+
+//   for(argvc = 0; argvc<bprm->argvn; argvc++) {
+//     if(argvc >= MAXARG)
+//       goto bad;
+//     sp -= strlen(bprm->argv[argvc]) + 1;
+//     sp -= sp % 16; // riscv sp must be 16-byte aligned
+//     if(sp < stackbase)
+//       goto bad;
+//     // __DEBUG("sp = %p",sp);
+//     if(copyout(pagetable, sp, bprm->argv[argvc], strlen(bprm->argv[argvc]) + 1) < 0)
+//       goto bad;
+//     argvstack[argvc] = sp;
+//   }
+//   argvstack[argvc] = 0;
+//   sp -= (argvc+1) * sizeof(uint64);
+//   sp -= sp % 16;
+//   if(sp < stackbase)
+//     goto bad;
+//   // __DEBUG("sp = %p",sp);
+//   if(copyout(pagetable, sp, (char *)argvstack, (argvc+1)*sizeof(uint64)) < 0)
+//     goto bad;
+//   // __DEBUG("6\n");
+//   p->trapframe->a1 = sp;
+//   if(bprm->argp){
+//     for(argpc = 0; argpc<bprm->argpn; argpc++) {
+//       if(argpc >= MAXARG)
+//         goto bad;
+//       sp -= strlen(bprm->argp[argpc]) + 1;
+//       sp -= sp % 16; // riscv sp must be 16-byte aligned
+//       if(sp < stackbase)
+//         goto bad;
+//       // __DEBUG("sp = %p",sp);
+//       if(copyout(pagetable, sp, bprm->argp[argpc], strlen(bprm->argp[argpc]) + 1) < 0)
+//         goto bad;
+//       argpstack[argpc] = sp;
+//     }
+//     argpstack[argpc] = 0;
+//     // push the array of argv[] pointers.
+//     sp -= (argpc+1) * sizeof(uint64);
+//     sp -= sp % 16;
+//     if(sp < stackbase)
+//        goto bad;
+//     // __DEBUG("sp = %p",sp);
+//     if(copyout(pagetable, sp, (char *)argpstack, (argpc+1)*sizeof(uint64)) < 0)
+//        goto bad;
+//   }
+
+//   // arguments to user main(argc, argv)
+//   // argc is returned via the system call return
+//   // value, which goes in a0.
+//   p->trapframe->a2 = sp;
+
+//   // __DEBUG("7\n");
+//   char *s, *last;
+//   // Save program name for debugging.
+//   for(last=s=bprm->filename; *s; s++)
+//     if(*s == '/')
+//       last = s+1;
+//   safestrcpy(p->name, last, sizeof(p->name));
+    
+//   // Commit to the user image.
+//   oldpagetable = p->pagetable;
+//   oldkpagetable = p->kpagetable;
+//   p->pagetable = pagetable;
+//   p->kpagetable = kpagetable;
+//   p->sz = sz;
+//   p->trapframe->epc = elf.entry;        // initial program counter = main
+//   p->trapframe->sp = sp;        // initial stack pointer
+  
+//   proc_freepagetable(oldpagetable, oldsz);
+//   w_satp(MAKE_SATP(p->kpagetable));
+//   sfence_vma();
+//   kvmfree(oldkpagetable, 0);
+//   return argvc;            // this ends up in a0, the first argument to main(argc, argv)
+
+//  bad:
+//   #ifdef DEBUG
+//   __DEBUG("[exec] reach bad\n");
+//   #endif
+//   if(pagetable)
+//     proc_freepagetable(pagetable, sz);
+//   if(kpagetable)
+//     kvmfree(kpagetable, 0);
+//   if(bprm->file){
+//     eunlock(bprm->file);
+//   }
+//   return -1;
+// }
+
+// int do_execve(char *filename, char **argv,char **argp){
+//   // __DEBUG("1\n");
+//   struct binprm bprm;
+//   bprm.filename=filename;
+//   if((bprm.file=ename(filename)) == NULL){
+//     goto out;
+//   }
+//   if(argv!=0){
+//     bprm.argvn=count(argv,&bprm);
+//   }
+//   else{
+//     bprm.argvn=0;
+//   }
+//   if(argp!=0){
+//     bprm.argpn=count(argp,&bprm);
+//   }
+//   else{
+//     bprm.argpn=0;
+//   }
+//   // __DEBUG("2\n");
+//   if(bprm.argvn>MAXARG||bprm.argpn>MAXARG){
+//     goto out;
+//   }
+//   bprm.argv=argv;
+//   bprm.argp=argp;
+
+//   if(bprm.file==NULL){
+//     goto out;
+//   }
+// 	int ret = binary_handler(&bprm);
+//   // __DEBUG("3\n");
+//   if(ret > 0){
+//     return ret;
+//   }
+// out:
+//   if(bprm.file){
+//      eput(bprm.file);
+//   }
+//   return -1;
+// }
\ No newline at end of file
diff --git a/kernel/fat32.c b/kernel/fat32.c
new file mode 100644
index 0000000000000000000000000000000000000000..43882087fd9e22782b996d9e343338ce63ba750c
--- /dev/null
+++ b/kernel/fat32.c
@@ -0,0 +1,1546 @@
+#include "include/param.h"
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/spinlock.h"
+#include "include/sleeplock.h"
+#include "include/buf.h"
+#include "include/proc.h"
+#include "include/stat.h"
+#include "include/fat32.h"
+#include "include/string.h"
+#include "include/printf.h"
+#include "include/vm.h"
+#include "include/kalloc.h"
+#include "include/fcntl.h"
+
+static struct {
+    uint32  first_data_sec; // data所在的第一个扇区
+    uint32  data_sec_cnt; // 数据扇区数
+    uint32  data_clus_cnt; // 数据簇数
+    uint32  byts_per_clus; // 每簇字节数
+
+    struct {
+        uint16  byts_per_sec;  // 扇区字节数
+        uint8   sec_per_clus;  // 每簇扇区数
+        uint16  rsvd_sec_cnt;  // 保留扇区数
+        uint8   fat_cnt;  // fatæ•°          
+        uint32  hidd_sec;  // 隐藏扇区数         
+        uint32  tot_sec;  // 总扇区数          
+        uint32  fat_sz;   // 一个fat所占扇区数           
+        uint32  root_clus; // 根目录簇号 
+    } bpb; 
+
+} fat; 
+
+// 目录缓冲区
+static struct entry_cache {
+    struct spinlock lock;
+    struct dirent entries[ENTRY_CACHE_NUM];
+} ecache; 
+
+// 根目录
+static struct dirent root;  
+//挂载设备的集合
+//其中设备0表示主存的文件系统
+ struct fstype dev_fat[8] ;
+//表示寻找在挂载集合的下标
+int  mount_num=0;
+/**
+ * 读取bpb 初始化根目录 初始化目录缓冲区 
+ * Read the Boot Parameter Block.  
+ * @return  0       if success  
+ *          -1      if fail  
+ */
+int fat32_init() 
+{
+    #ifdef DEBUG
+    __DEBUG("[fat32_init] enter!\n");
+    #endif
+    struct buf *b = bread(0, 0);
+    if (strncmp((char const*)(b->data + 82), "FAT32", 5)){
+        panic("not FAT32 volume");
+    }
+    // fat.bpb.byts_per_sec = *(uint16 *)(b->data + 11);
+    memmove(&fat.bpb.byts_per_sec, b->data + 11, 2);            // avoid misaligned load on k210
+    fat.bpb.sec_per_clus = *(b->data + 13);  
+    fat.bpb.rsvd_sec_cnt = *(uint16 *)(b->data + 14);
+    fat.bpb.fat_cnt = *(b->data + 16);
+    fat.bpb.hidd_sec = *(uint32 *)(b->data + 28);
+    fat.bpb.tot_sec = *(uint32 *)(b->data + 32);
+    fat.bpb.fat_sz = *(uint32 *)(b->data + 36);
+    fat.bpb.root_clus = *(uint32 *)(b->data + 44);
+    fat.first_data_sec = fat.bpb.rsvd_sec_cnt + fat.bpb.fat_cnt * fat.bpb.fat_sz;
+    fat.data_sec_cnt = fat.bpb.tot_sec - fat.first_data_sec;
+    fat.data_clus_cnt = fat.data_sec_cnt / fat.bpb.sec_per_clus;
+    fat.byts_per_clus = fat.bpb.sec_per_clus * fat.bpb.byts_per_sec;
+    brelse(b);
+
+    #ifdef DEBUG
+    __DEBUG("[FAT32 init]byts_per_sec: %d\n", fat.bpb.byts_per_sec);
+    __DEBUG("[FAT32 init]root_clus: %d\n", fat.bpb.root_clus);
+    __DEBUG("[FAT32 init]sec_per_clus: %d\n", fat.bpb.sec_per_clus);
+    __DEBUG("[FAT32 init]fat_cnt: %d\n", fat.bpb.fat_cnt);
+    __DEBUG("[FAT32 init]fat_sz: %d\n", fat.bpb.fat_sz);
+    __DEBUG("[FAT32 init]first_data_sec: %d\n", fat.first_data_sec);
+    #endif
+
+    // make sure that byts_per_sec has the same value with BSIZE 
+    if (BSIZE != fat.bpb.byts_per_sec) 
+        panic("byts_per_sec != BSIZE");
+    initlock(&ecache.lock, "ecache");
+    memset(&root, 0, sizeof(root));
+    initsleeplock(&root.lock, "entry");
+    root.attribute = (ATTR_DIRECTORY | ATTR_SYSTEM); 
+    root.first_clus = root.cur_clus = fat.bpb.root_clus;
+    root.valid = 1; 
+    root.prev = &root;
+    root.next = &root;
+    root.filename[0] = '/';
+    root.filename[1] = '\0';
+    for(struct dirent *de = ecache.entries; de < ecache.entries + ENTRY_CACHE_NUM; de++) {
+        de->dev = 0;
+        de->valid = 0;
+        de->ref = 0;
+        de->dirty = 0;
+        de->parent = 0;
+        de->next = root.next;
+        de->prev = &root;
+        initsleeplock(&de->lock, "entry");
+        root.next->prev = de;
+        root.next = de;
+    }
+     //将主存的系统存入设备管理
+    dev_fat[0].byts_per_clus=fat.byts_per_clus;
+    dev_fat[0].data_clus_cnt=fat.data_clus_cnt;
+    dev_fat[0].data_sec_cnt=fat.data_sec_cnt;
+    dev_fat[0].first_data_sec=fat.first_data_sec;
+    dev_fat[0].bpb.byts_per_sec=fat.bpb.byts_per_sec;
+    dev_fat[0].bpb.fat_cnt=fat.bpb.fat_cnt;
+    dev_fat[0].bpb.fat_sz=fat.bpb.fat_sz;
+    dev_fat[0].bpb.hidd_sec=fat.bpb.hidd_sec;
+    dev_fat[0].bpb.root_clus=fat.bpb.root_clus;
+    dev_fat[0].bpb.rsvd_sec_cnt=fat.bpb.rsvd_sec_cnt;
+    dev_fat[0].bpb.sec_per_clus=fat.bpb.sec_per_clus;
+    dev_fat[0].bpb.tot_sec=dev_fat->bpb.tot_sec;
+    dev_fat[0].mount_mode=0;
+    dev_fat[0].root=root;
+    dev_fat[0].vaild=1;
+    return 0;
+}
+
+// void dirtreeinit(){
+    // char name[FAT32_MAX_FILENAME + 1];
+    // strncpy(name, "/mnt", 5);
+    // create("/mnt", T_DIR, 0);
+    // create("/dev", T_DIR, 0);
+    // create("/dev/zero", T_DIR, 0);
+    // create("/dev/console", T_DIR, 0);
+    // create("/bin", T_DIR, 0);
+    // create("/tmp", T_DIR, 0);
+// }
+
+int get_major(char *path){
+    if(strncmp("/dev/zero",path,9) == 0){
+        return ZERO_DEV;
+    }else if(strncmp("/dev/console",path,12) == 0){
+        return CONSOLE;
+    }else if(strncmp("/dev/null",path,9)==0){
+        return NULL_DEV;
+    }
+     else if(strncmp("/dev/rtc",path,8)==0)
+    {
+        return RTC_DEV;
+    }
+    else return -1;
+}
+
+uint32
+get_byts_per_clus(){
+    return fat.byts_per_clus;
+}
+/**
+ * @param   cluster   cluster number starts from 2, which means no 0 and 1
+ */
+// 根据簇号得到起始扇区号
+static inline uint32 first_sec_of_clus(uint32 cluster)
+{
+    return ((cluster - 2) * fat.bpb.sec_per_clus) + fat.first_data_sec;
+}
+
+/**
+ * For the given number of a data cluster, return the number of the sector in a FAT table.
+ * @param   cluster     number of a data cluster
+ * @param   fat_num     number of FAT table from 1, shouldn't be larger than bpb::fat_cnt
+ */
+// 根据簇号得到在第fat_num个FAT表中的扇区号
+static inline uint32 fat_sec_of_clus(uint32 cluster, uint8 fat_num)
+{
+    return fat.bpb.rsvd_sec_cnt + (cluster << 2) / fat.bpb.byts_per_sec + fat.bpb.fat_sz * (fat_num - 1);
+}
+
+/**
+ * For the given number of a data cluster, return the offest in the corresponding sector in a FAT table.
+ * @param   cluster   number of a data cluster
+ */
+// 根据簇号得到在FAT中的扇区偏移
+static inline uint32 fat_offset_of_clus(uint32 cluster)
+{
+    return (cluster << 2) % fat.bpb.byts_per_sec;
+}
+
+/**
+ * Read the FAT table content corresponded to the given cluster number.
+ * @param   cluster     the number of cluster which you want to read its content in FAT table
+ */
+// 根据簇号读取fat1中的信息
+static uint32 read_fat(uint32 cluster)
+{
+    if (cluster >= FAT32_EOC) {
+        return cluster;
+    }
+    if (cluster > fat.data_clus_cnt + 1) {     // because cluster number starts at 2, not 0
+        return 0;
+    }
+    uint32 fat_sec = fat_sec_of_clus(cluster, 1);
+    // here should be a cache layer for FAT table, but not implemented yet.
+    struct buf *b = bread(0, fat_sec);
+    uint32 next_clus = *(uint32 *)(b->data + fat_offset_of_clus(cluster));
+    brelse(b);
+    return next_clus;
+}
+
+/**
+ * Write the FAT region content corresponded to the given cluster number.
+ * @param   cluster     the number of cluster to write its content in FAT table
+ * @param   content     the content which should be the next cluster number of FAT end of chain flag
+ */
+// 根据簇号将内容写入fat1
+// return 0 成功 1 失败
+static int write_fat(uint32 cluster, uint32 content)
+{
+    if (cluster > fat.data_clus_cnt + 1) {
+        return -1;
+    }
+    uint32 fat_sec = fat_sec_of_clus(cluster, 1);
+    struct buf *b = bread(0, fat_sec);
+    uint off = fat_offset_of_clus(cluster);
+    *(uint32 *)(b->data + off) = content;
+    bwrite(b);
+    brelse(b);
+    return 0;
+}
+
+// 根据簇号将该簇清空
+static void zero_clus(uint32 cluster)
+{
+    uint32 sec = first_sec_of_clus(cluster);
+    struct buf *b;
+    for (int i = 0; i < fat.bpb.sec_per_clus; i++) {
+        b = bread(0, sec++);
+        memset(b->data, 0, BSIZE);
+        bwrite(b);
+        brelse(b);
+    }
+}
+
+// 分配空闲簇 
+// 返回分配的簇号
+static uint32 alloc_clus(uint8 dev)
+{
+    // should we keep a free cluster list? instead of searching fat every time.
+    struct buf *b;
+    uint32 sec = fat.bpb.rsvd_sec_cnt;
+    uint32 const ent_per_sec = fat.bpb.byts_per_sec / sizeof(uint32);
+    for (uint32 i = 0; i < fat.bpb.fat_sz; i++, sec++) {
+        b = bread(dev, sec);
+        for (uint32 j = 0; j < ent_per_sec; j++) {
+            if (((uint32 *)(b->data))[j] == 0) {
+                ((uint32 *)(b->data))[j] = FAT32_EOC + 7;
+                bwrite(b);
+                brelse(b);
+                uint32 clus = i * ent_per_sec + j;
+                zero_clus(clus);
+                return clus;
+            }
+        }
+        brelse(b);
+    }
+    panic("no clusters");
+}
+
+// 释放簇
+static void free_clus(uint32 cluster)
+{
+    write_fat(cluster, 0);
+}
+
+// 当write为1:将首地址为data、长为n的数据写入簇号为cluster、偏移为off处
+// 当write为0:将簇号为cluster、偏移为off处、长为n的数据读到data
+// 返回写入数据的长度
+static uint rw_clus(uint32 cluster, int write, int user, uint64 data, uint off, uint n)
+{
+    if (off + n > fat.byts_per_clus)
+        panic("offset out of range");
+    uint tot, m;
+    struct buf *bp;
+    uint sec = first_sec_of_clus(cluster) + off / fat.bpb.byts_per_sec;
+    off = off % fat.bpb.byts_per_sec;
+
+    int bad = 0;
+    for (tot = 0; tot < n; tot += m, off += m, data += m, sec++) {
+        bp = bread(0, sec);
+        m = BSIZE - off % BSIZE;
+        if (n - tot < m) {
+            m = n - tot;
+        }
+        if (write) {
+            if ((bad = either_copyin(bp->data + (off % BSIZE), user, data, m)) != -1) {
+                bwrite(bp);
+            }
+        } else {
+            bad = either_copyout(user, data, bp->data + (off % BSIZE), m);
+        }
+        brelse(bp);
+        if (bad == -1) {
+            break;
+        }
+    }
+    return tot;
+}
+
+/**
+ * for the given entry, relocate the cur_clus field based on the off
+ * @param   entry       modify its cur_clus field
+ * @param   off         the offset from the beginning of the relative file
+ * @param   alloc       whether alloc new cluster when meeting end of FAT chains
+ * @return              the offset from the new cur_clus
+ */
+// 将entry->cur_clus移动到off(off文件中的偏移)所在的簇
+// 如果cur_clus<off所在的簇且不包含off所在的簇
+//      1.当alloc为1,则为该文件分配簇,直到到达off所在的簇
+//      2.当alloc为0,则将cur_clus置为first_clus
+// 返回off在该簇的偏移(off % fat.byts_per_clus)
+static int reloc_clus(struct dirent *entry, uint off, int alloc)
+{
+    int clus_num = off / fat.byts_per_clus;
+    while (clus_num > entry->clus_cnt) {
+        int clus = read_fat(entry->cur_clus);
+        if (clus >= FAT32_EOC) {
+            if (alloc) {
+                clus = alloc_clus(entry->dev);
+                write_fat(entry->cur_clus, clus);
+            } else {
+                entry->cur_clus = entry->first_clus;
+                entry->clus_cnt = 0;
+                return -1;
+            }
+        }
+        entry->cur_clus = clus;
+        entry->clus_cnt++;
+    }
+    if (clus_num < entry->clus_cnt) {
+        entry->cur_clus = entry->first_clus;
+        entry->clus_cnt = 0;
+        while (entry->clus_cnt < clus_num) {
+            entry->cur_clus = read_fat(entry->cur_clus);
+            if (entry->cur_clus >= FAT32_EOC) {
+                panic("reloc_clus");
+            }
+            entry->clus_cnt++;
+        }
+    }
+    return off % fat.byts_per_clus;
+}
+
+/* like the original readi, but "reade" is odd, let alone "writee" */
+// Caller must hold entry->lock.
+// 读取偏移为off,长为n的数据到dst处,并将cur_clus移动到结束处所在的簇(off是相对于数据区起始位置的偏移)
+int eread(struct dirent *entry, int user_dst, uint64 dst, uint off, uint n)
+{
+    if (off > entry->file_size || off + n < off || (entry->attribute & ATTR_DIRECTORY)) {
+        return 0;
+    }
+    if (entry->attribute & ATTR_LINK){
+        struct link li;
+        rw_clus(entry->first_clus, 0, 0, (uint64)&li, 0, 36);
+        entry->first_clus = ((uint32)(li.de.sne.fst_clus_hi)<<16) + li.de.sne.fst_clus_lo;
+        entry->attribute = li.de.sne.attr;
+    }
+    if (off + n > entry->file_size) {
+        n = entry->file_size - off;
+    }
+
+    uint tot, m;
+    for (tot = 0; entry->cur_clus < FAT32_EOC && tot < n; tot += m, off += m, dst += m) {
+        reloc_clus(entry, off, 0);
+        m = fat.byts_per_clus - off % fat.byts_per_clus;
+        if (n - tot < m) {
+            m = n - tot;
+        }
+        if (rw_clus(entry->cur_clus, 0, user_dst, dst, off % fat.byts_per_clus, m) != m) {
+            break;
+        }
+    }
+    return tot;
+}
+
+// Caller must hold entry->lock.
+// 将首地址为src,长为n的数据写入偏移为off处,并将cur_clus移动到结束处所在的簇(off是相对于数据区起始位置的偏移)
+int ewrite(struct dirent *entry, int user_src, uint64 src, uint off, uint n)
+{
+    if (off > entry->file_size || off + n < off || (uint64)off + n > 0xffffffff
+        || (entry->attribute & ATTR_READ_ONLY)) {
+        __ERROR("entry->attribute = %d",entry->attribute);
+        __ERROR("error");
+        return -1;
+    }
+    if (entry->attribute & ATTR_LINK){
+        struct link li;
+        rw_clus(entry->first_clus, 0, 0, (uint64)&li, 0, 36);
+        entry->first_clus = ((uint32)(li.de.sne.fst_clus_hi)<<16) + li.de.sne.fst_clus_lo;
+        entry->attribute = li.de.sne.attr;
+    }
+    if (entry->first_clus == 0) {   // so file_size if 0 too, which requests off == 0
+        entry->cur_clus = entry->first_clus = alloc_clus(entry->dev);
+        entry->clus_cnt = 0;
+        entry->dirty = 1;
+    }
+    uint tot, m;
+    for (tot = 0; tot < n; tot += m, off += m, src += m) {
+        reloc_clus(entry, off, 1);
+        m = fat.byts_per_clus - off % fat.byts_per_clus;
+        if (n - tot < m) {
+            m = n - tot;
+        }
+        if (rw_clus(entry->cur_clus, 1, user_src, src, off % fat.byts_per_clus, m) != m) {
+            __ERROR("m = %d",m);
+            break;
+        }
+    }
+    if(n > 0) {
+        if(off > entry->file_size) {
+            entry->file_size = off;
+            entry->dirty = 1;
+        }
+    }
+    return tot;
+}
+
+// Returns a dirent struct. If name is given, check ecache. It is difficult to cache entries
+// by their whole path. But when parsing a path, we open all the directories through it, 
+// which forms a linked list from the final file to the root. Thus, we use the "parent" pointer 
+// to recognize whether an entry with the "name" as given is really the file we want in the right path.
+// Should never get root by eget, it's easy to understand.
+// 在目录缓冲区中根据parent和name寻找目录
+// 如果没有找到则将其放到缓冲区,并将vaild设为0(如果缓冲区有空余的话)(没有置换算法)
+static struct dirent *eget(struct dirent *parent, char *name)
+{
+    struct dirent *ep;
+    acquire(&ecache.lock);
+    if (name) {
+        for (ep = root.next; ep != &root; ep = ep->next) {          // LRU algo
+            if (ep->valid == 1 && ep->parent == parent
+                && strncmp(ep->filename, name, FAT32_MAX_FILENAME) == 0) {
+                if (ep->ref++ == 0) {
+                    ep->parent->ref++;
+                }
+                release(&ecache.lock);
+                // edup(ep->parent);
+                return ep;
+            }
+        }
+    }
+
+    for (ep = root.prev; ep != &root; ep = ep->prev) {              // LRU algo
+        if (ep->ref == 0) {
+            ep->ref = 1;
+            ep->dev = parent->dev;
+            ep->off = 0;
+            ep->valid = 0;
+            ep->dirty = 0;
+            release(&ecache.lock);
+            return ep;
+        }
+    }
+    panic("eget: insufficient ecache");
+    return 0;
+}
+
+// trim ' ' in the head and tail, '.' in head, and test legality
+// 去除开头和结尾的' '以及开头的'.'  对于非法名字,返回0
+char *formatname(char *name)
+{
+    static char illegal[] = { '\"', '*', '/', ':', '<', '>', '?', '\\', '|', 0 };
+    char *p;
+    while (*name == ' ' || *name == '.') { name++; }
+    for (p = name; *p; p++) {
+        char c = *p;
+        if (c < 0x20 || strchr(illegal, c)) {
+            return 0;
+        }
+    }
+    while (p-- > name) {
+        if (*p != ' ') {
+            p[1] = '\0';
+            break;
+        }
+    }
+    return name;
+}
+
+// 将name转化为短名(小写字母转大写,非法字符变成'_')
+static void generate_shortname(char *shortname, char *name)
+{
+    static char illegal[] = { '+', ',', ';', '=', '[', ']', 0 };   // these are legal in l-n-e but not s-n-e
+    int i = 0;
+    char c, *p = name;
+    for (int j = strlen(name) - 1; j >= 0; j--) {
+        if (name[j] == '.') {
+            p = name + j; // 最后一个'.'
+            break;
+        }
+    }
+    while (i < CHAR_SHORT_NAME && (c = *name++)) {
+        // 
+        if (i == 8 && p) {  
+            if (p + 1 < name) { break; }            // no '.'
+            else {
+                name = p + 1, p = 0;
+                continue;
+            }
+        }
+        
+        if (c == ' ') { continue; }
+        if (c == '.') {
+            if (name > p) {                    // last '.'
+                memset(shortname + i, ' ', 8 - i);
+                i = 8, p = 0;
+            }
+            continue;
+        }
+        if (c >= 'a' && c <= 'z') {
+            c += 'A' - 'a';
+        } else {
+            if (strchr(illegal, c) != NULL) {
+                c = '_';
+            }
+        }
+        shortname[i++] = c;
+    }
+    while (i < CHAR_SHORT_NAME) {
+        shortname[i++] = ' ';
+    }
+}
+
+// 根据shortname计算校验和
+uint8 cal_checksum(uchar* shortname)
+{
+    uint8 sum = 0;
+    for (int i = CHAR_SHORT_NAME; i != 0; i--) {
+        sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + *shortname++;
+    }
+    return sum;
+}
+
+/**
+ * Generate an on disk format entry and write to the disk. Caller must hold dp->lock
+ * @param   dp          the directory
+ * @param   ep          entry to write on disk
+ * @param   off         offset int the dp, should be calculated via dirlookup before calling this
+ */
+// 在dp中生成一个目录并写入磁盘,如果off==0,生成'.'目录,如果0<off<=32,生成'..'目录,如果off>32,生成长名目录,长名保存自ep中
+// 将ep->first_clus设为目录的起始簇
+void emake(struct dirent *dp, struct dirent *ep, uint off)
+{
+    if (!(dp->attribute & ATTR_DIRECTORY))
+        panic("emake: not dir");
+    if (off % sizeof(union dentry))
+        panic("emake: not aligned");
+    
+    union dentry de;
+    memset(&de, 0, sizeof(de));
+    if (off <= 32) {  // 短名
+        if (off == 0) {
+            strncpy(de.sne.name, ".          ", sizeof(de.sne.name));
+        } else {
+            strncpy(de.sne.name, "..         ", sizeof(de.sne.name));
+        }
+        de.sne.attr = ATTR_DIRECTORY;
+        de.sne.fst_clus_hi = (uint16)(ep->first_clus >> 16);        // first clus high 16 bits
+        de.sne.fst_clus_lo = (uint16)(ep->first_clus & 0xffff);       // low 16 bits
+        de.sne.file_size = 0;                                       // filesize is updated in eupdate()
+        off = reloc_clus(dp, off, 1);
+        rw_clus(dp->cur_clus, 1, 0, (uint64)&de, off, sizeof(de));
+    } else {  // 长名
+        int entcnt = (strlen(ep->filename) + CHAR_LONG_NAME - 1) / CHAR_LONG_NAME;   // count of l-n-entries, rounds up
+        char shortname[CHAR_SHORT_NAME + 1];
+        memset(shortname, 0, sizeof(shortname));
+        generate_shortname(shortname, ep->filename);
+        de.lne.checksum = cal_checksum((uchar *)shortname);
+        de.lne.attr = ATTR_LONG_NAME;
+        for (int i = entcnt; i > 0; i--) {
+            if ((de.lne.order = i) == entcnt) {
+                de.lne.order |= LAST_LONG_ENTRY;
+            }
+            char *p = ep->filename + (i - 1) * CHAR_LONG_NAME;
+            uint8 *w = (uint8 *)de.lne.name1;
+            int end = 0;
+            for (int j = 1; j <= CHAR_LONG_NAME; j++) {
+                if (end) {
+                    *w++ = 0xff;            // on k210, unaligned reading is illegal
+                    *w++ = 0xff;
+                } else { 
+                    if ((*w++ = *p++) == 0) {
+                        end = 1;
+                    }
+                    *w++ = 0;
+                }
+                switch (j) {
+                    case 5:     w = (uint8 *)de.lne.name2; break;
+                    case 11:    w = (uint8 *)de.lne.name3; break;
+                }
+            }
+            uint off2 = reloc_clus(dp, off, 1);
+            rw_clus(dp->cur_clus, 1, 0, (uint64)&de, off2, sizeof(de));
+            off += sizeof(de);
+        }
+        memset(&de, 0, sizeof(de));
+        strncpy(de.sne.name, shortname, sizeof(de.sne.name));
+        de.sne.attr = ep->attribute;
+        de.sne.fst_clus_hi = (uint16)(ep->first_clus >> 16);      // first clus high 16 bits
+        de.sne.fst_clus_lo = (uint16)(ep->first_clus & 0xffff);     // low 16 bits
+        de.sne.file_size = ep->file_size;                         // filesize is updated in eupdate()
+        off = reloc_clus(dp, off, 1);
+        rw_clus(dp->cur_clus, 1, 0, (uint64)&de, off, sizeof(de));
+    }
+}
+
+/**
+ * Allocate an entry on disk. Caller must hold dp->lock.
+ */
+// 在dp目录下创建一个文件/目录
+// 返回创建的文件/目录
+struct dirent *ealloc(struct dirent *dp, char *name, int attr)
+{
+    if (!(dp->attribute & ATTR_DIRECTORY)) {
+        panic("ealloc not dir");
+    }
+    if (dp->valid != 1 || !(name = formatname(name))) {        // detect illegal character
+        return NULL;
+    }
+    struct dirent *ep;
+    uint off = 0;
+    if ((ep = dirlookup(dp, name, &off)) != 0) {      // entry exists
+        return ep;
+    }
+    ep = eget(dp, name);
+    elock(ep);
+    ep->attribute = attr;
+    ep->file_size = 0;
+    ep->first_clus = 0;
+    ep->parent = edup(dp);
+    ep->off = off;
+    ep->clus_cnt = 0;
+    ep->cur_clus = 0;
+    ep->dirty = 0;
+    strncpy(ep->filename, name, FAT32_MAX_FILENAME);
+    ep->filename[FAT32_MAX_FILENAME] = '\0';
+    if (attr == ATTR_DIRECTORY) {    // generate "." and ".." for ep
+        ep->attribute |= ATTR_DIRECTORY;
+        ep->cur_clus = ep->first_clus = alloc_clus(dp->dev);
+        emake(ep, ep, 0);
+        emake(ep, dp, 32);
+    } else {
+        ep->attribute |= ATTR_ARCHIVE;
+    }
+    emake(dp, ep, off);
+    ep->valid = 1;
+    eunlock(ep);
+    return ep;
+}
+
+// entry引用数加一
+struct dirent *edup(struct dirent *entry)
+{
+    if (entry != 0) {
+        acquire(&ecache.lock);
+        entry->ref++;
+        release(&ecache.lock);
+    }
+    return entry;
+}
+
+// Only update filesize and first cluster in this case.
+// caller must hold entry->parent->lock
+// 在entry的父目录中更新entry的目录项
+void eupdate(struct dirent *entry)
+{
+    if (!entry->dirty || entry->valid != 1) { return; }
+    uint entcnt = 0;
+    uint32 off = reloc_clus(entry->parent, entry->off, 0);
+    rw_clus(entry->parent->cur_clus, 0, 0, (uint64) &entcnt, off, 1);
+    entcnt &= ~LAST_LONG_ENTRY;
+    off = reloc_clus(entry->parent, entry->off + (entcnt << 5), 0);
+    union dentry de;
+    rw_clus(entry->parent->cur_clus, 0, 0, (uint64)&de, off, sizeof(de));
+    de.sne.fst_clus_hi = (uint16)(entry->first_clus >> 16);
+    de.sne.fst_clus_lo = (uint16)(entry->first_clus & 0xffff);
+    de.sne.file_size = entry->file_size;
+    rw_clus(entry->parent->cur_clus, 1, 0, (uint64)&de, off, sizeof(de));
+    entry->dirty = 0;
+}
+
+// caller must hold entry->lock
+// caller must hold entry->parent->lock
+// remove the entry in its parent directory
+// 将entry从它的父目录中移除
+// 被移除后entry的valid被置为-1
+void eremove(struct dirent *entry)
+{
+    if (entry->valid != 1) { return; }
+    uint entcnt = 0;
+    uint32 off = entry->off;
+    uint32 off2 = reloc_clus(entry->parent, off, 0);
+    rw_clus(entry->parent->cur_clus, 0, 0, (uint64) &entcnt, off2, 1);
+    entcnt &= ~LAST_LONG_ENTRY;
+    uint8 flag = EMPTY_ENTRY;
+    for (int i = 0; i <= entcnt; i++) {
+      rw_clus(entry->parent->cur_clus, 1, 0, (uint64) &flag, off2, 1);
+      off += 32;
+      off2 = reloc_clus(entry->parent, off, 0);
+    }
+    entry->valid = -1;
+}
+
+// truncate a file
+// caller must hold entry->lock
+// 在数据区清空文件/目录
+void etrunc(struct dirent *entry)
+{
+    if(!(entry->attribute & ATTR_LINK)){
+        for (uint32 clus = entry->first_clus; clus >= 2 && clus < FAT32_EOC; ) {
+            uint32 next = read_fat(clus);
+            free_clus(clus);
+            clus = next;
+        }
+    }
+    entry->file_size = 0;
+    entry->first_clus = 0;
+    entry->dirty = 1;
+}
+
+// 请求睡眠锁,要求引用数大于0
+void elock(struct dirent *entry)
+{
+    if (entry == 0 || entry->ref < 1)
+        panic("elock");
+    acquiresleep(&entry->lock);
+}
+
+// 释放睡眠锁
+void eunlock(struct dirent *entry)
+{
+    if (entry == 0 || !holdingsleep(&entry->lock) || entry->ref < 1)
+        panic("eunlock");
+    releasesleep(&entry->lock);
+}
+
+// 将entry引用数减少1
+// 如果entry的引用数减少为0,则将entry放置缓冲区最前面,并执行eput(entry->parent)
+void eput(struct dirent *entry)
+{
+    acquire(&ecache.lock);
+    if (entry != &root && entry->valid != 0 && entry->ref == 1) {
+        // ref == 1 means no other process can have entry locked,
+        // so this acquiresleep() won't block (or deadlock).
+        acquiresleep(&entry->lock);
+        entry->next->prev = entry->prev;
+        entry->prev->next = entry->next;
+        entry->next = root.next;
+        entry->prev = &root;
+        root.next->prev = entry;
+        root.next = entry;
+        release(&ecache.lock);
+        if (entry->valid == -1) {       // this means some one has called eremove()
+            etrunc(entry);
+        } else {
+            elock(entry->parent);
+            eupdate(entry);
+            eunlock(entry->parent);
+        }
+        releasesleep(&entry->lock);
+        
+        // Once entry->ref decreases down to 0, we can't guarantee the entry->parent field remains unchanged.
+        // Because eget() may take the entry away and write it.
+        struct dirent *eparent = entry->parent;
+        acquire(&ecache.lock);
+        entry->ref--;
+        release(&ecache.lock);
+        if (entry->ref == 0) {
+            eput(eparent);
+        }
+        return;
+    }
+    entry->ref--;
+    release(&ecache.lock);
+}
+
+// 将dirent的信息copy到stat中
+// 包括文件名、文件类型、所在设备号、文件大小
+void estat(struct dirent *de, struct stat *st)
+{
+    strncpy(st->name, de->filename, STAT_MAX_NAME);
+    st->type = (de->attribute & ATTR_DIRECTORY) ? T_DIR : T_FILE;
+    st->dev = de->dev;
+    st->size = de->file_size;
+}
+
+/**
+ * Read filename from directory entry.
+ * @param   buffer      pointer to the array that stores the name
+ * @param   raw_entry   pointer to the entry in a sector buffer
+ * @param   islong      if non-zero, read as l-n-e, otherwise s-n-e.
+ */
+// 对于给定的目录项读取文件名,放在buffer中
+static void read_entry_name(char *buffer, union dentry *d)
+{
+    if (d->lne.attr == ATTR_LONG_NAME) {                       // long entry branch
+        wchar temp[NELEM(d->lne.name1)];
+        memmove(temp, d->lne.name1, sizeof(temp));
+        snstr(buffer, temp, NELEM(d->lne.name1));
+        buffer += NELEM(d->lne.name1);
+        snstr(buffer, d->lne.name2, NELEM(d->lne.name2));
+        buffer += NELEM(d->lne.name2);
+        snstr(buffer, d->lne.name3, NELEM(d->lne.name3));
+    } else {
+        // assert: only "." and ".." will enter this branch
+        memset(buffer, 0, CHAR_SHORT_NAME + 2); // plus '.' and '\0'
+        int i;
+        for (i = 0; d->sne.name[i] != ' ' && i < 8; i++) {
+            buffer[i] = d->sne.name[i];
+        }
+        if (d->sne.name[8] != ' ') {
+            buffer[i++] = '.';
+        }
+        for (int j = 8; j < CHAR_SHORT_NAME; j++, i++) {
+            if (d->sne.name[j] == ' ') { break; }
+            buffer[i] = d->sne.name[j];
+        }
+    }
+}
+
+/**
+ * Read entry_info from directory entry.
+ * @param   entry       pointer to the structure that stores the entry info
+ * @param   raw_entry   pointer to the entry in a sector buffer
+ */
+// 将目录项d的信息读取到entry
+static void read_entry_info(struct dirent *entry, union dentry *d)
+{
+    entry->attribute = d->sne.attr;
+    entry->first_clus = ((uint32)d->sne.fst_clus_hi << 16) | d->sne.fst_clus_lo;
+    entry->file_size = d->sne.file_size;
+    entry->cur_clus = entry->first_clus;
+    entry->clus_cnt = 0;
+}
+
+/**
+ * Read a directory from off, parse the next entry(ies) associated with one file, or find empty entry slots.
+ * Caller must hold dp->lock.
+ * @param   dp      the directory
+ * @param   ep      the struct to be written with info
+ * @param   off     offset off the directory
+ * @param   count   to write the count of entries
+ * @return  -1      meet the end of dir
+ *          0       find empty slots
+ *          1       find a file with all its entries
+ */
+// 在dp目录中找的off后的下一个文件(off = n*32),文件名放到ep中
+// 找到返回1,文件被删除返回0,后面没有文件了返回-1
+// count记录了向后遍历了几个目录项
+int enext(struct dirent *dp, struct dirent *ep, uint off, int *count)
+{
+    if (!(dp->attribute & ATTR_DIRECTORY))
+        panic("enext not dir");
+    if (ep->valid)
+        panic("enext ep valid");
+    if (off % 32)
+        panic("enext not align");
+    if (dp->valid != 1) { return -1; }
+
+    if (dp->attribute & ATTR_LINK){
+        struct link li;
+        rw_clus(dp->first_clus, 0, 0, (uint64)&li, 0, 36);
+        dp->first_clus = ((uint32)(li.de.sne.fst_clus_hi)<<16) + li.de.sne.fst_clus_lo;
+        dp->attribute = li.de.sne.attr;
+    }
+    union dentry de;
+    int cnt = 0;
+    memset(ep->filename, 0, FAT32_MAX_FILENAME + 1);
+    for (int off2; (off2 = reloc_clus(dp, off, 0)) != -1; off += 32) {
+        if (rw_clus(dp->cur_clus, 0, 0, (uint64)&de, off2, 32) != 32 || de.lne.order == END_OF_ENTRY) {
+            return -1;
+        }
+        if (de.lne.order == EMPTY_ENTRY) {
+            cnt++;
+            continue;
+        } else if (cnt) {
+            *count = cnt;
+            return 0;
+        }
+        if (de.lne.attr == ATTR_LONG_NAME) {
+            int lcnt = de.lne.order & ~LAST_LONG_ENTRY;
+            if (de.lne.order & LAST_LONG_ENTRY) {
+                *count = lcnt + 1;                              // plus the s-n-e;
+                count = 0;
+            }
+            read_entry_name(ep->filename + (lcnt - 1) * CHAR_LONG_NAME, &de);
+        } else {
+            if (count) {
+                *count = 1;
+                read_entry_name(ep->filename, &de);
+            }
+            read_entry_info(ep, &de);
+            return 1;
+        }
+    }
+    return -1;
+}
+
+/**
+ * Seacher for the entry in a directory and return a structure. Besides, record the offset of
+ * some continuous empty slots that can fit the length of filename.
+ * Caller must hold entry->lock.
+ * @param   dp          entry of a directory file
+ * @param   filename    target filename
+ * @param   poff        offset of proper empty entry slots from the beginning of the dir
+ */
+// 在dp目录中搜索文件名为filename的文件
+// poff记录了偏移
+// 返回找到的文件
+struct dirent *dirlookup(struct dirent *dp, char *filename, uint *poff)
+{
+     if(dp->mount_flag==1)
+        {
+            fat.bpb.byts_per_sec=dev_fat[dp->dev].bpb.byts_per_sec;
+            fat.bpb.fat_cnt=dev_fat[dp->dev].bpb.fat_cnt;
+            fat.bpb.fat_sz=dev_fat[dp->dev].bpb.fat_sz;
+            fat.bpb.hidd_sec=dev_fat[dp->dev].bpb.hidd_sec;
+            fat.bpb.root_clus=dev_fat[dp->dev].bpb.root_clus;
+            fat.bpb.rsvd_sec_cnt=dev_fat[dp->dev].bpb.rsvd_sec_cnt;
+            fat.bpb.sec_per_clus=dev_fat[dp->dev].bpb.sec_per_clus;
+            fat.bpb.tot_sec=dev_fat[dp->dev].bpb.tot_sec;
+            fat.byts_per_clus=dev_fat[dp->dev].byts_per_clus;
+            fat.data_clus_cnt=dev_fat[dp->dev].data_clus_cnt;
+            fat.data_sec_cnt=dev_fat[dp->dev].data_sec_cnt;
+            fat.first_data_sec=dev_fat[dp->dev].data_sec_cnt;
+            root=dev_fat[dp->dev].root;
+            dp=&root;
+        }
+    if (!(dp->attribute & ATTR_DIRECTORY))
+        panic("dirlookup not DIR");
+    if (dp->attribute & ATTR_LINK){
+        struct link li;
+        rw_clus(dp->first_clus, 0, 0, (uint64)&li, 0, 36);
+        dp->first_clus = ((uint32)(li.de.sne.fst_clus_hi)<<16) + li.de.sne.fst_clus_lo;
+        dp->attribute = li.de.sne.attr;
+    }
+    if (strncmp(filename, ".", FAT32_MAX_FILENAME) == 0) {
+        return edup(dp);
+    } else if (strncmp(filename, "..", FAT32_MAX_FILENAME) == 0) {
+        if (dp == &root) {
+            return edup(&root);
+        }
+        return edup(dp->parent);
+    }
+    if (dp->valid != 1) {
+        __ERROR("valid is not 1\n");
+        return NULL;
+    }
+    struct dirent *ep = eget(dp, filename);
+    if (ep->valid == 1) { return ep; }                               // ecache hits
+
+    int len = strlen(filename);
+    int entcnt = (len + CHAR_LONG_NAME - 1) / CHAR_LONG_NAME + 1;   // count of l-n-entries, rounds up. plus s-n-e
+    int count = 0; 
+    int type;
+    uint off = 0;
+    reloc_clus(dp, 0, 0);
+    while ((type = enext(dp, ep, off, &count) != -1)) {
+        // __DEBUG("find %s\n", ep->filename);
+        if (type == 0) {
+            __INF("%s has been deleted\n", ep->filename);
+            if (poff && count >= entcnt) {
+                *poff = off;
+                poff = 0;
+            }
+        } else if (strncmp(filename, ep->filename, FAT32_MAX_FILENAME) == 0) {
+            ep->parent = edup(dp);
+            ep->off = off;
+            ep->valid = 1;
+            return ep;
+        }
+        off += count << 5;
+    }
+    if (poff) {
+        *poff = off;
+    }
+    eput(ep);
+    // __DEBUG("can't find %s\n", filename);
+    return NULL;
+}
+
+// 对于给定的path,读取路径的开头文件名,返回去掉了开头文件名的路径
+static char *skipelem(char *path, char *name)
+{
+    while (*path == '/') {
+        path++;
+    }
+    if (*path == 0) { return NULL; }
+    char *s = path;
+    while (*path != '/' && *path != 0) {
+        path++;
+    }
+    int len = path - s;
+    if (len > FAT32_MAX_FILENAME) {
+        len = FAT32_MAX_FILENAME;
+    }
+    name[len] = 0;
+    memmove(name, s, len);
+    while (*path == '/') {
+        path++;
+    }
+    return path;
+}
+
+// FAT32 version of namex in xv6's original file system.
+// 根据路径找到目录,name记录了最后找到的目录名
+// 对于/a/b/c/d
+// 1. 如果parent=1,返回d
+// 2. 如果parent=0,返回d/
+static struct dirent *lookup_path(char *path, int parent, char *name)
+{
+    struct dirent *entry, *next;
+     if (*path == '/' || *path == 0) {
+        entry = edup(&root);
+    } else if (*path != '\0') {
+        entry = edup(myproc()->cwd);
+    } else {
+        return NULL;
+    }
+    while ((path = skipelem(path, name)) != 0) {
+        elock(entry);
+        if (!(entry->attribute & ATTR_DIRECTORY)) {
+            eunlock(entry);
+            eput(entry);
+            return NULL;
+        }
+        if (parent && *path == '\0') {
+            eunlock(entry);
+            return entry;
+        }
+        if ((next = dirlookup(entry, name, 0)) == 0) {
+            eunlock(entry);
+            eput(entry);
+            return NULL;
+        }
+        eunlock(entry);
+        eput(entry);
+        entry = next;
+    }
+    if (parent) {
+        eput(entry);
+        return NULL;
+    }
+    return entry;
+}
+
+
+// 根据路径寻找目录(进入该目录)
+struct dirent *ename(char *path)
+{
+    char name[FAT32_MAX_FILENAME + 1];
+    return lookup_path(path, 0, name);
+}
+
+
+// 根据路径寻找目录(不进入该目录)
+struct dirent *enameparent(char *path, char *name)
+{
+    return lookup_path(path, 1, name);
+}
+
+
+static struct dirent *lookup_path2(char *path, int parent, struct file *f ,char *name)
+{
+    struct dirent *entry, *next;
+    if (*path == '\0'){
+        __ERROR("no thing in path\n");
+        return NULL;
+    }else if(*path == '/'){
+        entry = edup(&root);
+    }else if(!f){
+        entry = edup(myproc()->cwd);
+    }else{
+        entry = edup(f->ep);
+    }
+    while ((path = skipelem(path, name)) != 0) {
+        elock(entry);
+        if (!(entry->attribute & ATTR_DIRECTORY)) {
+            __ERROR("not dir\n");
+            eunlock(entry);
+            eput(entry);
+            return NULL;
+        }
+        if (parent && *path == '\0') {
+            eunlock(entry);
+            return entry;
+        }
+        if ((next = dirlookup(entry, name, 0)) == 0) {
+            // __DEBUG("can't find %s in %s\n", name, entry->filename);
+            eunlock(entry);
+            eput(entry);
+            return NULL;
+        }
+        eunlock(entry);
+        eput(entry);
+        entry = next;
+    }
+    if (parent) {
+        __ERROR("path is wrong\n");
+        eput(entry);
+        return NULL;
+    }
+    return entry;
+}
+
+// 根据路径寻找目录(进入该文件/目录)
+struct dirent *ename2(char *path, struct file *f)
+{
+    char name[FAT32_MAX_FILENAME + 1];
+    return lookup_path2(path, 0, f, name);
+}
+
+// 根据路径寻找目录(不进入该文件/目录)
+struct dirent *enameparent2(char *path, char *name, struct file *f)
+{
+    return lookup_path2(path, 1, f, name);
+}
+
+int link(char* oldpath, struct file *f1, char* newpath, struct file *f2){
+  struct dirent *dp1, *dp2;
+  if((dp1 = ename2(oldpath, f1)) == NULL){
+    __ERROR("can't find dir\n");
+    return -1;
+  }
+  struct dirent *parent1;
+  parent1 = dp1->parent;
+  int off2;
+  off2 = reloc_clus(parent1, dp1->off, 0);
+  union dentry de;
+  if (rw_clus(parent1->cur_clus, 0, 0, (uint64)&de, off2, 32) != 32 || de.lne.order == END_OF_ENTRY) {
+    __ERROR("can't read dentry\n");
+    return -1;
+  }
+//   if((de.sne.attr & ATTR_LONG_NAME) == ATTR_LONG_NAME){
+//     __DEBUG("long name!\n");
+//     return -1;   
+//   }
+  struct link li;
+  int clus;
+  if(!(de.sne.attr & ATTR_LINK)){
+    clus = alloc_clus(dp1->dev);
+    li.de = de;
+    li.link_count = 2;
+    if(rw_clus(clus, 1, 0, (uint64)&li, 0, 36) != 36){
+        __ERROR("write li wrong\n");
+        return -1;
+    }
+    de.sne.attr = ATTR_DIRECTORY | ATTR_LINK;
+    de.sne.fst_clus_hi = (uint16)(clus >> 16);       
+    de.sne.fst_clus_lo = (uint16)(clus & 0xffff);
+    de.sne.file_size = 36;
+    elock(parent1);
+    if(rw_clus(parent1->cur_clus, 1, 0, (uint64)&de, off2, 32) != 32){
+        __ERROR("write parent1 wrong\n");
+        eunlock(parent1);
+        return -1;
+    }
+    eunlock(parent1);
+  }
+  else{
+    clus = ((uint32)(de.sne.fst_clus_hi) << 16) + (uint32)(de.sne.fst_clus_lo);
+    rw_clus(clus, 0, 0, (uint64)&li, 0, 36);
+    li.link_count++;
+    if(rw_clus(clus, 1, 0, (uint64)&li, 0, 36) != 36){
+        __ERROR("write li wrong\n");
+        return -1;
+    }
+  }
+  char name[FAT32_MAX_FILENAME + 1];
+  if((dp2 = enameparent2(newpath, name, f2)) == NULL){
+    // __DEBUG("can't find dir\n");
+    return NULL;
+  }
+  struct dirent *ep;
+  elock(dp2);
+  uint off = 0;
+  if((ep = dirlookup(dp2, name, &off)) != 0) {
+    __ERROR("%s exits",name);
+    return -1;
+  }
+  off = reloc_clus(dp2, off, 1);
+  if(rw_clus(dp2->cur_clus, 1, 0, (uint64)&de, off, 32) != 32){
+    __ERROR("write de into %s wrong",dp2->filename);
+    eunlock(dp2);
+    return -1;
+  }
+  eunlock(dp2);
+  return 0;
+}
+
+int unlink(char *path, struct file *f){
+  struct dirent *dp;
+  if((dp = ename2(path, f)) == NULL){
+    __ERROR("can't find dir");
+    return -1;
+  }
+  struct dirent *parent;
+  parent = dp->parent;
+  int off;
+  off = reloc_clus(parent, dp->off, 0);
+  union dentry de;
+  if (rw_clus(parent->cur_clus, 0, 0, (uint64)&de, off, 32) != 32 || de.lne.order == END_OF_ENTRY) {
+    __ERROR("can't read dentry");
+    return -1;
+  }
+//   if((de.sne.attr & ATTR_LONG_NAME) == ATTR_LONG_NAME){
+//     __DEBUG("dp->attr: %d\n",dp->attribute);
+//     __DEBUG("long name!\n");
+//     return -1;   
+//   }
+  
+  if(de.sne.attr & ATTR_LINK){
+    int clus;
+    struct link li;
+    clus = ((uint32)(de.sne.fst_clus_hi) << 16) + (uint32)(de.sne.fst_clus_lo);
+    if(rw_clus(clus, 0, 0, (uint64)&li, 0, 36) != 36){
+      __ERROR("read li wrong");
+      return -1;
+    }
+    if(--li.link_count == 0){
+        free_clus(clus);
+        de = li.de;
+        if(rw_clus(parent->cur_clus, 1, 0, (uint64)&de, off, 32) != 32){
+            __ERROR("write de into %s wrong",parent->filename);
+            return -1;
+        }
+    }
+  }
+  return remove2(path, f);
+}
+
+// 目录是否为空
+// Is the directory dp empty except for "." and ".." ?
+int isdirempty(struct dirent *dp)
+{
+  struct dirent ep;
+  int count;
+  int ret;
+  ep.valid = 0;
+  ret = enext(dp, &ep, 2 * 32, &count);   // skip the "." and ".."
+  return ret == -1;
+}
+
+int remove(char *path){
+  char *s = path + strlen(path) - 1;
+  while (s >= path && *s == '/') {
+    s--;
+  }
+  if (s >= path && *s == '.' && (s == path || *--s == '/')) {
+    return -1;
+  }
+  struct dirent *ep;
+  if((ep = ename(path)) == NULL){
+    return -1;
+  }
+  elock(ep);
+  if((ep->attribute & ATTR_DIRECTORY) && !isdirempty(ep)){
+    eunlock(ep);
+    eput(ep);
+    return -1;
+  }
+  elock(ep->parent);      // Will this lead to deadlock?
+  eremove(ep);
+  eunlock(ep->parent);
+  eunlock(ep);
+  eput(ep);
+  
+  return 0;
+}
+
+int remove2(char *path, struct file *f){
+//   char *s = path + strlen(path) - 1;
+//   while (s >= path && *s == '/') {
+//     s--;
+//   }
+//   if (s >= path && *s == '.' && (s == path || *--s == '/')) {
+//     return -1;
+//   }
+  struct dirent *ep;
+  if((ep = ename2(path, f)) == NULL){
+    return -1;
+  }
+  elock(ep);
+  if((ep->attribute & ATTR_DIRECTORY) && !isdirempty(ep)){
+    eunlock(ep);
+    eput(ep);
+    return -1;
+  }
+  elock(ep->parent);      // Will this lead to deadlock?
+  eremove(ep);
+  eunlock(ep->parent);
+  eunlock(ep);
+  eput(ep);
+  return 0;
+}
+
+int syn_disk(uint64 start,long len){
+    uint i, n;
+    pte_t *pte;
+    uint64 pa,va;
+    long off;
+    struct proc*p=myproc();
+    struct dirent *ep=p->mfile.mfile->ep;
+    pagetable_t pagetable = p->pagetable;
+    if(start>p->mfile.baseaddr){
+        off=p->mfile.off+start-p->mfile.baseaddr;
+    }
+    else{
+        off=p->mfile.off;
+    }
+    va=start;
+    elock(ep);
+    for(i = 0; i < (int)len; i += PGSIZE){
+        pte = walk(pagetable, va+i, 0);
+        if(pte == 0)
+            return 0;
+        if((*pte & PTE_V) == 0)
+            return 0;
+        if((*pte & PTE_U) == 0)
+            return 0;
+        if((*pte & PTE_D) == 0)
+            continue;
+        pa = PTE2PA(*pte);
+
+        if(pa == NULL)
+            panic("start_map: address should exist");
+        if(len - i < PGSIZE)
+            n = len - i;
+        else
+            n = PGSIZE;
+        // __DEBUG("write\n");
+        if(ewrite(ep, 0, (uint64)pa, off+i, n) != n)
+            return -1;
+    }
+    eunlock(ep);
+    return 1;
+}
+
+
+int 
+do_mount(struct dirent*mountpoint,struct dirent*dev)
+{
+
+    while(dev_fat[mount_num].vaild!=0)
+   {
+        mount_num++;
+        mount_num=mount_num%8;
+   }
+
+    struct buf *b = bread(dev->dev, 0);
+    if (strncmp((char const*)(b->data + 82), "FAT32", 5))
+        panic("not FAT32 volume");
+    // fat.bpb.byts_per_sec = *(uint16 *)(b->data + 11);
+    memmove(&dev_fat[mount_num].bpb.byts_per_sec, b->data + 11, 2);            // avoid misaligned load on k210
+    dev_fat[mount_num].bpb.sec_per_clus = *(b->data + 13);  
+    dev_fat[mount_num].bpb.rsvd_sec_cnt = *(uint16 *)(b->data + 14);
+    dev_fat[mount_num].bpb.fat_cnt = *(b->data + 16);
+    dev_fat[mount_num].bpb.hidd_sec = *(uint32 *)(b->data + 28);
+    dev_fat[mount_num].bpb.tot_sec = *(uint32 *)(b->data + 32);
+    dev_fat[mount_num].bpb.fat_sz = *(uint32 *)(b->data + 36);
+    dev_fat[mount_num].bpb.root_clus = *(uint32 *)(b->data + 44);
+    dev_fat[mount_num].first_data_sec = fat.bpb.rsvd_sec_cnt + fat.bpb.fat_cnt * fat.bpb.fat_sz;
+    dev_fat[mount_num].data_sec_cnt = fat.bpb.tot_sec - fat.first_data_sec;
+    dev_fat[mount_num].data_clus_cnt = fat.data_sec_cnt / fat.bpb.sec_per_clus;
+    dev_fat[mount_num].byts_per_clus = fat.bpb.sec_per_clus * fat.bpb.byts_per_sec;
+    brelse(b);
+
+    // make sure that byts_per_sec has the same value with BSIZE 
+    if (BSIZE != dev_fat[mount_num].bpb.byts_per_sec) 
+        panic("byts_per_sec != BSIZE");
+    initlock(&ecache.lock, "ecache");
+    memset(&dev_fat[mount_num].root, 0, sizeof(dev_fat[mount_num].root));
+    initsleeplock(&root.lock, "entry");
+   dev_fat[mount_num]. root.attribute = (ATTR_DIRECTORY | ATTR_SYSTEM); 
+    dev_fat[mount_num].root.first_clus =dev_fat[mount_num]. root.cur_clus = dev_fat[mount_num].bpb.root_clus;
+    dev_fat[mount_num].root.valid = 1; 
+    dev_fat[mount_num].root.prev = &dev_fat[mount_num].root;
+    dev_fat[mount_num].root.next = &dev_fat[mount_num].root;
+    dev_fat[mount_num].root.filename[0] = '/';
+    dev_fat[mount_num].root.filename[1] = '\0';
+    dev_fat[mount_num].mount_mode=1;
+    mountpoint->mount_flag=1;
+    mountpoint->dev=mount_num;
+    
+    return 0;
+}
+
+
+int 
+do_umount(struct dirent*mountpoint)
+{
+  
+   mountpoint->mount_flag=0;
+   memset(&dev_fat[mountpoint->dev],0,sizeof(dev_fat[0]));
+   mountpoint->dev=0;
+   return 0;
+}
+
+struct dirent* create(char *path, short type, int mode)
+{
+  struct dirent *ep, *dp;
+  char name[FAT32_MAX_FILENAME + 1];
+
+  if((dp = enameparent(path, name)) == NULL)
+    return NULL;
+
+  if (type == T_DIR) {
+    mode = ATTR_DIRECTORY;
+  } else if (mode & O_RDONLY) {
+    mode = ATTR_READ_ONLY;
+  } else {
+    mode = 0;  
+  }
+
+  elock(dp);
+  if ((ep = ealloc(dp, name, mode)) == NULL) {
+    eunlock(dp);
+    eput(dp);
+    return NULL;
+  }
+  
+  if ((type == T_DIR && !(ep->attribute & ATTR_DIRECTORY)) ||
+      (type == T_FILE && (ep->attribute & ATTR_DIRECTORY))) {
+    eunlock(dp);
+    eput(ep);
+    eput(dp);
+    return NULL;
+  }
+
+  eunlock(dp);
+  eput(dp);
+
+  elock(ep);
+  return ep;
+}
+
+struct dirent* create2(char *path, short type, int flags, struct file *f)
+{
+  struct dirent *ep, *dp;
+  char name[FAT32_MAX_FILENAME + 1];
+  if(path[0] == '/' && path[1] == 0){
+    edup(&root);
+    elock(&root);
+    return &root;
+  }
+  if((dp = enameparent2(path, name, f)) == NULL){
+    __ERROR("can't find dir");
+    return NULL;
+  }
+  int mode = 0;
+  if (type == T_DIR) {
+    mode |= ATTR_DIRECTORY;
+  }else{
+    mode |= ATTR_ARCHIVE;
+  }
+
+  if (!(flags & O_RDWR) && !(flags & O_WRONLY)) {
+    mode |= ATTR_READ_ONLY;
+  }
+  
+  elock(dp);
+  if ((ep = ealloc(dp, name, mode)) == NULL) {
+    eunlock(dp);
+    eput(dp);
+    return NULL;
+  }
+  
+  if ((type == T_DIR && !(ep->attribute & ATTR_DIRECTORY)) ||
+      (type == T_FILE && (ep->attribute & ATTR_DIRECTORY))) {
+    eunlock(dp);
+    eput(ep);
+    eput(dp);
+    return NULL;
+  }
+
+  eunlock(dp);
+  eput(dp);
+
+  elock(ep);
+  return ep;
+}
+
+int do_statfs(struct statvfs* stat,struct dirent*dp)
+{
+stat->f_bsize=20;
+stat->f_namemax=15;
+ stat->f_bavail=dev_fat[dp->dev].data_clus_cnt;
+ stat->f_bfree=dev_fat[dp->dev].data_clus_cnt;
+ stat->f_blocks=dev_fat[dp->dev].data_clus_cnt;
+ 
+ stat->f_favail=2589864;
+stat->f_ffree=2589864;
+stat->f_files=3948544;
+
+return 0;
+}
+
+void getdstat(struct dirent *de, struct dstat *st)
+{
+  strncpy(st->d_name, de->filename, FAT32_MAX_FILENAME);
+  st->d_type = (de->attribute & ATTR_DIRECTORY) ? S_IFDIR : S_IFREG;
+  st->d_ino = de->first_clus;
+  st->d_off = 0;
+  st->d_reclen = sizeof(struct dstat);
+}
+
+
+int  namepath(struct dirent*dp,char*path,int max_len)
+{
+    char*p=path+max_len-1;
+    int  len;
+    *p='\0';
+    for(; ;)
+    {
+        if(dp==NULL)
+        {
+            break;
+        }
+        len=strlen(dp->filename);
+        if((p-=len)<path)
+        {
+            __DEBUG("path too long");
+            return -1;
+        }
+      //  __DEBUG("dp_filename=%s",dp->filename);
+        memmove(p,dp->filename,len);
+        if(dp->parent!=NULL)
+        *--p='/';
+        dp=dp->parent;
+    }
+
+    len=max_len-(p-path);
+    memmove(path,p,len);
+    return len;
+}
\ No newline at end of file
diff --git a/kernel/file.c b/kernel/file.c
new file mode 100644
index 0000000000000000000000000000000000000000..b68808df245c1dba8e16309af81f891e906f978d
--- /dev/null
+++ b/kernel/file.c
@@ -0,0 +1,520 @@
+//
+// Support functions for system calls that involve file descriptors.
+//
+
+
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/param.h"
+#include "include/spinlock.h"
+#include "include/sleeplock.h"
+#include "include/fat32.h"
+#include "include/file.h"
+#include "include/pipe.h"
+#include "include/stat.h"
+#include "include/proc.h"
+#include "include/printf.h"
+#include "include/string.h"
+#include "include/vm.h"
+#include "include/errno.h"
+
+struct devsw devsw[NDEV];
+struct {
+  struct spinlock lock;
+  struct file file[NFILE];
+} ftable;
+
+ // 初始化文件表
+void
+fileinit(void)
+{
+  initlock(&ftable.lock, "ftable");
+  struct file *f;
+  for(f = ftable.file; f < ftable.file + NFILE; f++){  
+    memset(f, 0, sizeof(struct file));
+    initlock(&f->lock,"filelock");
+  }
+  #ifdef DEBUG
+  printf("fileinit\n");
+  #endif
+}
+
+// Allocate a file structure.
+// 在文件表中分配一个文件
+struct file*
+filealloc(void)   
+{
+  struct file *f;
+
+  acquire(&ftable.lock);
+  for(f = ftable.file; f < ftable.file + NFILE; f++){
+    if(f->ref == 0){
+      f->ref = 1;
+      release(&ftable.lock);
+      return f;
+    }
+  }
+  release(&ftable.lock);
+  return NULL;
+}
+
+// Increment ref count for file f.
+// 文件的引用数加一,但必须是已经分配的文件,即该文件的引用数>0
+struct file*
+filedup(struct file *f)   
+{
+  acquire(&ftable.lock);
+  if(f->ref < 1)
+    panic("filedup");
+  f->ref++;
+  release(&ftable.lock);
+  return f;
+}
+
+// Close file f.  (Decrement ref count, close when reaches 0.)
+// 减少一个文件引用,如果文件的引用变为0,将该文件的类型设为空,如果该文件的文件类型为管道则关闭管道,如果该文件类型为entry,则执行eput
+void
+fileclose(struct file *f)
+{
+  struct file ff;
+
+  acquire(&ftable.lock);
+  if(f->ref < 1){
+    __ERROR("%s",f->ep->filename);
+    panic("fileclose");
+  }
+  if(--f->ref > 0){
+    release(&ftable.lock);
+    return;
+  }
+  ff = *f;
+  f->ref = 0;
+  f->type = FD_NONE;
+  release(&ftable.lock);
+
+  if(ff.type == FD_PIPE){ 
+    pipeclose(ff.pipe, ff.writable);
+  } else if(ff.type == FD_ENTRY){
+    eput(ff.ep);
+  } else if (ff.type == FD_DEVICE) {
+
+  }
+}
+
+// Get metadata about file f.
+// addr is a user virtual address, pointing to a struct stat.
+//将f的元信息复制到addr处,包括文件名、所属设备、文件类型(目录/文件)、文件大小
+int
+filestat(struct file *f, uint64 addr)
+{
+  struct proc *p = myproc();
+  struct stat st;
+  // __DEBUG("entry filestat");
+  if(f->type == FD_ENTRY){
+    elock(f->ep);
+    estat(f->ep, &st);
+    eunlock(f->ep);
+    // __DEBUG("%p",addr);
+    // if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
+    if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
+      return -1;
+    // __DEBUG("fstat ok");
+    return 0;
+  }
+  __DEBUG("return wrong");
+  return -1;
+}
+// 读文件
+// 根据文件的类型执行对应的读操作
+// Read from file f.
+// addr is a user virtual address.
+int
+fileread(struct file *f, uint64 addr, int n)
+{
+  int r = 0;
+  // __DEBUG("read");
+  if(f->readable == 0){
+    __ERROR("error!");
+    return -1;
+  }
+
+  switch (f->type) {
+    case FD_PIPE:
+        // __DEBUG("%p %d",addr,n);
+        r = piperead(f->pipe, addr, n);
+        break;
+    case FD_DEVICE:
+        if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read){
+          __ERROR("error!,f->major = %d, NDEV = %d, devsw[f->major].read = %p",f->major,NDEV,devsw[f->major].read);
+          return -1;
+        }
+        r = devsw[f->major].read(1, addr, n); 
+        break;
+    case FD_ENTRY:
+        elock(f->ep);
+          if((r = eread(f->ep, 1, addr, f->off, n)) > 0)
+            f->off += r;
+        eunlock(f->ep);
+        break;
+    default:
+      panic("fileread");
+  }
+
+  return r;
+}
+
+int filereadv(struct file *f, struct iovec *ioarr, int count)
+{
+  int r = 0;
+  // __DEBUG("read");
+  if(f->readable == 0){
+    __ERROR("error!");
+    return -1;
+  }
+  int n = 0;
+  switch (f->type) {
+    case FD_PIPE:
+        for(;n<count;n++){
+          int k = piperead(f->pipe, (uint64)ioarr->iov_base, (int)ioarr->iov_len);
+          r += k;
+          if(k < (int)ioarr->iov_len)
+            break;
+          ioarr++;
+        }
+        break;
+    case FD_DEVICE:
+        if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read){
+          __ERROR("error!,f->major = %d, NDEV = %d, devsw[f->major].read = %p",f->major,NDEV,devsw[f->major].read);
+          return -1;
+        }
+        for(;n<count;n++){
+          int k = devsw[f->major].read(1, (uint64)ioarr->iov_base, (int)ioarr->iov_len);
+          r += k;
+          if(k < (int)ioarr->iov_len)
+            break;
+          ioarr++;
+        }
+        break;
+    case FD_ENTRY:
+        for(;n<count;n++){
+          elock(f->ep);
+          int k = 0;
+          if((k = eread(f->ep, 1, (uint64)ioarr->iov_base, f->off, (int)ioarr->iov_len)) > 0)
+            f->off += k;
+          eunlock(f->ep); 
+          r += k;
+          if(k < (int)ioarr->iov_len)
+            break;
+          ioarr++;
+        }
+        break;
+    default:
+      panic("filereadv");
+  }
+  return r;
+}
+
+int
+fileread2(struct file *f, uint64 addr, int n)
+{
+  int r = 0;
+  // __DEBUG("read");
+  if(f->readable == 0){
+    __ERROR("error!");
+    return -1;
+  }
+
+  switch (f->type) {
+    case FD_PIPE:
+        r = piperead2(f->pipe, addr, n);
+        break;
+    case FD_DEVICE:
+        if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read){
+          __ERROR("error!,f->major = %d, NDEV = %d, devsw[f->major].read = %p",f->major,NDEV,devsw[f->major].read);
+          return -1;
+        }
+        r = devsw[f->major].read(0, addr, n);  
+        break;
+    case FD_ENTRY:
+        elock(f->ep);
+        if((r = eread(f->ep, 0, addr, f->off, n)) > 0)
+          f->off += r;
+        eunlock(f->ep);
+        break;
+    default:
+      panic("fileread2");
+  }
+
+  return r;
+}
+
+// 写文件
+// 根据文件的类型执行对应的读操作
+// Write to file f.
+// addr is a user virtual address.
+int
+filewrite(struct file *f, uint64 addr, int n)
+{
+  int ret = 0;
+
+  if(f->writable == 0){
+    int i = 1;
+    __ERROR("can't write %d",i);
+    return -1;
+  }
+
+  if(f->type == FD_PIPE){
+    // __DEBUG("%p %d",addr,n);
+    ret = pipewrite(f->pipe, addr, n);
+  } 
+  else if(f->type == FD_DEVICE){
+    if(f->major < 0 || f->major >= NDEV || !devsw[f->major].write){
+      __DEBUG("%d",f->major);
+      __ERROR("error!");
+      return -1;
+    }
+    ret = devsw[f->major].write(1, addr, n);
+  } 
+  else if(f->type == FD_ENTRY){
+    // __DEBUG("");
+    elock(f->ep);
+    if (ewrite(f->ep, 1, addr, f->off, n) == n) {
+      ret = n;
+      f->off += n;
+    } else {
+      __ERROR("error!");
+      ret = -1;
+    }
+    eunlock(f->ep);
+  } 
+  else {
+    panic("filewrite");
+  }
+  if(ret == 0){
+    // __DEBUG("return 0");
+  }
+  return ret;
+}
+
+int filewritev(struct file *f, struct iovec *ioarr, int count)
+{
+  int r = 0;
+  // __DEBUG("read");
+  if(f->readable == 0){
+    __ERROR("error!");
+    return -1;
+  }
+  int n = 0;
+  switch (f->type) {
+    case FD_PIPE:
+        for(;n<count;n++){
+          int k = pipewrite(f->pipe, (uint64)ioarr->iov_base, (int)ioarr->iov_len);
+          r += k;
+          if(k < (int)ioarr->iov_len)
+            break;
+          ioarr++;
+        }
+        break;
+    case FD_DEVICE:
+        if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read){
+          __ERROR("error!,f->major = %d, NDEV = %d, devsw[f->major].read = %p",f->major,NDEV,devsw[f->major].read);
+          return -1;
+        }
+        for(;n<count;n++){
+          int k = devsw[f->major].write(1, (uint64)ioarr->iov_base, (int)ioarr->iov_len);
+          r += k;
+          if(k < (int)ioarr->iov_len)
+            break;
+          ioarr++;
+        }
+        break;
+    case FD_ENTRY:
+        for(;n<count;n++){
+          elock(f->ep);
+          int k = 0;
+          if((k = ewrite(f->ep, 1, (uint64)ioarr->iov_base, f->off, (int)ioarr->iov_len)) > 0)
+            f->off += k;
+          eunlock(f->ep); 
+          r += k;
+          if(k < (int)ioarr->iov_len)
+            break;
+          ioarr++;
+        }
+        break;
+    default:
+      panic("filewritev");
+  }
+  return r;
+}
+
+int
+filewrite2(struct file *f, uint64 addr, int n)
+{
+  int ret = 0;
+
+  if(f->writable == 0){
+    int i = 1;
+    __ERROR("can't write %d",i);
+    return -1;
+  }
+
+  if(f->type == FD_PIPE){
+    ret = pipewrite2(f->pipe, addr, n);
+  } 
+  else if(f->type == FD_DEVICE){
+    if(f->major < 0 || f->major >= NDEV || !devsw[f->major].write){
+      __DEBUG("%d",f->major);
+      __ERROR("error!");
+      return -1;
+    }
+    ret = devsw[f->major].write(0, addr, n);
+  } 
+  else if(f->type == FD_ENTRY){
+    // __DEBUG("");
+    elock(f->ep);
+    if (ewrite(f->ep, 0, addr, f->off, n) == n) {
+      ret = n;
+      f->off += n;
+    } else {
+      __ERROR("n == %d, f->off == %d, f->size = %d",n,f->off,f->ep->file_size);
+      ret = -1;
+    }
+    eunlock(f->ep);
+  } 
+  else {
+    panic("filewrite2");
+  }
+  if(ret == 0){
+    // __DEBUG("return 0");
+  }
+  return ret;
+}
+
+// Read from dir f.
+// addr is a user virtual address.
+// 找到下一个目录项
+int
+dirnext(struct file *f, uint64 addr)
+{
+  struct proc *p = myproc();
+
+  if(f->readable == 0 || !(f->ep->attribute & ATTR_DIRECTORY)) // 如果不是目录就返回-1  
+    return -1;
+
+  struct dirent de;
+  struct stat st;
+  int count = 0;
+  int ret;
+  elock(f->ep);
+  while ((ret = enext(f->ep, &de, f->off, &count)) == 0) {  // skip empty entry
+    f->off += count * 32;
+  }
+  eunlock(f->ep);
+  if (ret == -1)
+    return 0;
+
+  f->off += count * 32;
+  estat(&de, &st);
+  // __DEBUG("%p",addr);
+  if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
+    return -1;
+
+  return 1;
+}
+
+// 读取目录信息
+int dirnext2(struct file *f, uint64 buf, uint64 len)
+{
+  struct proc *p = myproc();
+
+  if(f->readable == 0)
+    return -1;
+
+  struct dirent de;
+  struct dstat st;
+  int count = 0;
+  int ret;
+  uint64 off = 0;
+  while(1){
+    elock(f->ep);
+    while ((ret = enext(f->ep, &de, f->off, &count)) == 0) {  // skip empty entry
+      f->off += count * 32;
+    }
+    eunlock(f->ep);
+    if (ret == -1)
+      return off;
+    f->off += count * 32;
+    if(off + sizeof(st) > len){
+      return off;
+    }
+    getdstat(&de, &st);
+    if(copyout(p->pagetable, buf + off, (char *)&st, sizeof(st)) < 0)
+      return off;
+    off += sizeof(st);
+  }
+}
+
+ int do_utimes_path(int dfd,  char  *filename,
+		struct timespec64 *times, int flags)
+{
+	int lookup_flags = 0;
+  struct dirent*ep;
+	if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
+		{
+      return -1;
+    }
+
+	if (!(flags & AT_SYMLINK_NOFOLLOW))
+		lookup_flags |= LOOKUP_FOLLOW;
+	if (flags & AT_EMPTY_PATH)
+		lookup_flags |= LOOKUP_EMPTY;
+  if((ep=ename(filename))==NULL)
+  {
+    return -ENOENT;
+  }
+  ep->last_access_date=times[0].tv_nsec;
+  ep->last_write_date=times[1].tv_nsec;
+	return 0;
+}
+
+ int do_utimes_fd(int fd, struct timespec64 *times, int flags)
+{
+	struct file* f;
+
+	if (flags)
+		return -1;
+
+	f=myproc()->ofile[fd];
+  
+	if (!f)
+  {
+    printf("file is null");
+    	return -1;
+  } 
+
+	if(times[0].tv_nsec==UTIME_NOW)
+  {
+    times[0].tv_sec=2147483647;
+     f->ep->last_access_date=times[0].tv_sec;
+  }
+  else{
+    if(times[0].tv_nsec!=UTIME_OMIT)
+    {
+        f->ep->last_access_date=times[0].tv_sec;
+    }
+  }
+  if(times[1].tv_nsec==UTIME_NOW)
+  {
+    times[1].tv_sec=2147483647;
+     f->ep->last_write_date=times[1].tv_sec;
+  }
+  else{
+      if(times[1].tv_nsec!=UTIME_OMIT)
+    {
+        f->ep->last_write_date=times[1].tv_sec;
+    }
+  }  
+	return 0;
+}
+
+
diff --git a/kernel/fpioa.c b/kernel/fpioa.c
new file mode 100644
index 0000000000000000000000000000000000000000..6a06f0604e71a5981cada1c3841395c711fcb450
--- /dev/null
+++ b/kernel/fpioa.c
@@ -0,0 +1,4944 @@
+// FPIOA Implementation
+
+#include "include/types.h"
+#include "include/fpioa.h"
+#include "include/riscv.h"
+#include "include/sysctl.h"
+#include "include/memlayout.h"
+
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+volatile fpioa_t *const fpioa = (volatile fpioa_t *)FPIOA_V;
+
+/**
+ * @brief      Internal used FPIOA function initialize cell
+ *
+ *             This is NOT fpioa_io_config_t, can't assign directly
+ *
+ */
+typedef struct _fpioa_assign_t
+{
+    uint32 ch_sel : 8;
+    /* Channel select from 256 input. */
+    uint32 ds : 4;
+    /* Driving selector. */
+    uint32 oe_en : 1;
+    /* Static output enable, will AND with OE_INV. */
+    uint32 oe_inv : 1;
+    /* Invert output enable. */
+    uint32 do_sel : 1;
+    /* Data output select: 0 for DO, 1 for OE. */
+    uint32 do_inv : 1;
+    /* Invert the result of data output select (DO_SEL). */
+    uint32 pu : 1;
+    /* Pull up enable. 0 for nothing, 1 for pull up. */
+    uint32 pd : 1;
+    /* Pull down enable. 0 for nothing, 1 for pull down. */
+    uint32 resv0 : 1;
+    /* Reserved bits. */
+    uint32 sl : 1;
+    /* Slew rate control enable. */
+    uint32 ie_en : 1;
+    /* Static input enable, will AND with IE_INV. */
+    uint32 ie_inv : 1;
+    /* Invert input enable. */
+    uint32 di_inv : 1;
+    /* Invert Data input. */
+    uint32 st : 1;
+    /* Schmitt trigger. */
+    uint32 tie_en : 1;
+    /* Input tie enable, 1 for enable, 0 for disable. */
+    uint32 tie_val : 1;
+    /* Input tie value, 1 for high, 0 for low. */
+    uint32 resv1 : 5;
+    /* Reserved bits. */
+    uint32 pad_di : 1;
+    /* Read current PAD's data input. */
+} __attribute__((packed, aligned(4))) fpioa_assign_t;
+
+/* Function list */
+static const fpioa_assign_t function_config[FUNC_MAX] =
+    {
+        {.ch_sel = FUNC_JTAG_TCLK,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_JTAG_TDI,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_JTAG_TMS,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_JTAG_TDO,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_D0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_D1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_D2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_D3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_D4,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_D5,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_D6,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_D7,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_SS0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_SS1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_SS2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_SS3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_ARB,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 1,
+         .tie_val = 1,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI0_SCLK,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UARTHS_RX,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UARTHS_TX,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_RESV6,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_RESV7,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CLK_SPI1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CLK_I2C1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS4,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS5,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS6,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS7,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS8,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS9,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS10,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS11,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS12,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS13,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS14,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS15,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS16,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS17,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS18,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS19,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS20,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS21,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS22,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS23,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS24,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS25,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS26,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS27,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS28,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS29,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS30,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIOHS31,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIO0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIO1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIO2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIO3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIO4,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIO5,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIO6,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_GPIO7,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_RX,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_TX,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_RX,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_TX,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_RX,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_TX,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_D0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_D1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_D2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_D3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_D4,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_D5,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_D6,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_D7,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_SS0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_SS1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_SS2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_SS3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_ARB,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 1,
+         .tie_val = 1,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI1_SCLK,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI_SLAVE_D0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 1,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI_SLAVE_SS,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SPI_SLAVE_SCLK,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_MCLK,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_SCLK,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_WS,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_IN_D0,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_IN_D1,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_IN_D2,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_IN_D3,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_OUT_D0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_OUT_D1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_OUT_D2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S0_OUT_D3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_MCLK,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_SCLK,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_WS,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_IN_D0,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_IN_D1,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_IN_D2,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_IN_D3,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_OUT_D0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_OUT_D1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_OUT_D2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S1_OUT_D3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_MCLK,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_SCLK,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_WS,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_IN_D0,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_IN_D1,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_IN_D2,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_IN_D3,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_OUT_D0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_OUT_D1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_OUT_D2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2S2_OUT_D3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_RESV0,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_RESV1,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_RESV2,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_RESV3,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_RESV4,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_RESV5,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2C0_SCLK,
+         .ds = 0x0,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 1,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2C0_SDA,
+         .ds = 0x0,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 1,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2C1_SCLK,
+         .ds = 0x0,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 1,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2C1_SDA,
+         .ds = 0x0,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 1,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2C2_SCLK,
+         .ds = 0x0,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 1,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_I2C2_SDA,
+         .ds = 0x0,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 1,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_XCLK,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_RST,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_PWDN,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_VSYNC,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_HREF,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_PCLK,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_D0,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_D1,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_D2,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_D3,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_D4,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_D5,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_D6,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CMOS_D7,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SCCB_SCLK,
+         .ds = 0x0,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 1,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_SCCB_SDA,
+         .ds = 0x0,
+         .oe_en = 1,
+         .oe_inv = 1,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 1,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_CTS,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_DSR,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_DCD,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_RI,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_SIR_IN,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_DTR,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_RTS,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_OUT2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_OUT1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_SIR_OUT,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_BAUD,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_RE,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_DE,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART1_RS485_EN,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_CTS,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_DSR,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_DCD,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_RI,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_SIR_IN,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_DTR,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_RTS,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_OUT2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_OUT1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_SIR_OUT,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_BAUD,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_RE,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_DE,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART2_RS485_EN,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_CTS,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_DSR,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_DCD,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_RI,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_SIR_IN,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_DTR,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_RTS,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_OUT2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_OUT1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_SIR_OUT,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_BAUD,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_RE,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_DE,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_UART3_RS485_EN,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER0_TOGGLE1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER0_TOGGLE2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER0_TOGGLE3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER0_TOGGLE4,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER1_TOGGLE1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER1_TOGGLE2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER1_TOGGLE3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER1_TOGGLE4,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER2_TOGGLE1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER2_TOGGLE2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER2_TOGGLE3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_TIMER2_TOGGLE4,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CLK_SPI2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CLK_I2C2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL4,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL5,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL6,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL7,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL8,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL9,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL10,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL11,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL12,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL13,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL14,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 1,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 1,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL15,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL16,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL17,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_CONSTANT,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_INTERNAL18,
+         .ds = 0x0,
+         .oe_en = 0,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 1,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 1,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG0,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG1,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG2,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG3,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG4,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG5,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG6,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG7,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG8,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG9,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG10,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG11,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG12,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG13,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG14,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG15,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG16,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG17,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG18,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG19,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG20,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG21,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG22,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG23,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG24,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG25,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG26,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG27,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG28,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG29,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG30,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+        {.ch_sel = FUNC_DEBUG31,
+         .ds = 0xf,
+         .oe_en = 1,
+         .oe_inv = 0,
+         .do_sel = 0,
+         .do_inv = 0,
+         .pu = 0,
+         .pd = 0,
+         .resv1 = 0,
+         .sl = 0,
+         .ie_en = 0,
+         .ie_inv = 0,
+         .di_inv = 0,
+         .st = 0,
+         .tie_en = 0,
+         .tie_val = 0,
+         .resv0 = 0,
+         .pad_di = 0},
+};
+
+// int fpioa_init(void)
+// {
+//     int i = 0;
+
+//     /* Enable fpioa clock in system controller */
+//     sysctl_clock_enable(SYSCTL_CLOCK_FPIOA);
+
+//     /* Initialize tie */
+//     fpioa_tie_t tie = {0};
+
+//     /* Set tie enable and tie value */
+//     for(i = 0; i < FUNC_MAX; i++)
+//     {
+//         tie.en[i / 32] |= (function_config[i].tie_en << (i % 32));
+//         tie.val[i / 32] |= (function_config[i].tie_val << (i % 32));
+//     }
+
+//     /* Atomic write every 32bit register to fpioa function */
+//     for(i = 0; i < FUNC_MAX / 32; i++)
+//     {
+//         /* Set value before enable */
+//         fpioa->tie.val[i] = tie.val[i];
+//         fpioa->tie.en[i] = tie.en[i];
+//     }
+
+//     return 0;
+// }
+
+// int fpioa_get_io(int number, fpioa_io_config_t *cfg)
+// {
+//     /* Check parameters */
+//     if(number < 0 || number >= FPIOA_NUM_IO || cfg == NULL)
+//         return -1;
+//     /* Atomic read register */
+//     *cfg = fpioa->io[number];
+//     return 0;
+// }
+
+// int fpioa_set_io(int number, fpioa_io_config_t *cfg)
+// {
+//     /* Check parameters */
+//     if(number < 0 || number >= FPIOA_NUM_IO || cfg == NULL)
+//         return -1;
+//     /* Atomic write register */
+//     fpioa->io[number] = *cfg;
+//     return 0;
+// }
+
+int fpioa_set_io_pull(int number, fpioa_pull_t pull)
+{
+    /* Check parameters */
+    if(number < 0 || number >= FPIOA_NUM_IO || pull >= FPIOA_PULL_MAX)
+        return -1;
+
+    /* Atomic read register */
+    fpioa_io_config_t cfg = fpioa->io[number];
+
+    switch(pull)
+    {
+        case FPIOA_PULL_NONE:
+            cfg.pu = 0;
+            cfg.pd = 0;
+            break;
+        case FPIOA_PULL_DOWN:
+            cfg.pu = 0;
+            cfg.pd = 1;
+            break;
+        case FPIOA_PULL_UP:
+            cfg.pu = 1;
+            cfg.pd = 0;
+            break;
+        default:
+            break;
+    }
+    /* Atomic write register */
+    fpioa->io[number] = cfg;
+    return 0;
+}
+
+// int fpioa_get_io_pull(int number)
+// {
+//     /* Check parameters */
+//     if(number < 0 || number >= FPIOA_NUM_IO)
+//         return -1;
+
+//     fpioa_pull_t pull;
+//     /* Atomic read register */
+//     fpioa_io_config_t cfg = fpioa->io[number];
+
+//     if(cfg.pu == 0 && cfg.pd == 1)
+//         pull = FPIOA_PULL_DOWN;
+//     else if(cfg.pu == 1 && cfg.pd == 0)
+//         pull = FPIOA_PULL_UP;
+//     else
+//         pull = FPIOA_PULL_NONE;
+//     return pull;
+// }
+
+// int fpioa_set_io_driving(int number, fpioa_driving_t driving)
+// {
+//     /* Check parameters */
+//     if(number < 0 || number >= FPIOA_NUM_IO || driving >= FPIOA_DRIVING_MAX)
+//         return -1;
+
+//     /* Atomic read register */
+//     fpioa_io_config_t cfg = fpioa->io[number];
+//     /* Set IO driving */
+//     cfg.ds = driving;
+//     /* Atomic write register */
+//     fpioa->io[number] = cfg;
+//     return 0;
+// }
+
+// int fpioa_set_sl(int number, uint8 sl_enable)
+// {
+//     /* Check parameters */
+//     if(number < 0 || number >= FPIOA_NUM_IO)
+//         return -1;
+
+//     /* Atomic read register */
+//     fpioa_io_config_t cfg = fpioa->io[number];
+//     /* Set IO slew rate */
+//     cfg.sl = sl_enable;
+//     /* Atomic write register */
+//     fpioa->io[number] = cfg;
+//     return 0;
+// }
+
+// int fpioa_set_st(int number, uint8 st_enable)
+// {
+//     /* Check parameters */
+//     if(number < 0 || number >= FPIOA_NUM_IO)
+//         return -1;
+
+//     /* Atomic read register */
+//     fpioa_io_config_t cfg = fpioa->io[number];
+//     /* Set IO schmitt trigger */
+//     cfg.st = st_enable;
+//     /* Atomic write register */
+//     fpioa->io[number] = cfg;
+//     return 0;
+// }
+
+// int fpioa_set_oe_inv(int number, uint8 inv_enable)
+// {
+//     /* Check parameters */
+//     if(number < 0 || number >= FPIOA_NUM_IO)
+//         return -1;
+
+//     /* Atomic read register */
+//     fpioa_io_config_t cfg = fpioa->io[number];
+//     /* Set IO schmitt trigger */
+//     cfg.oe_inv = inv_enable;
+//     /* Atomic write register */
+//     fpioa->io[number] = cfg;
+//     return 0;
+// }
+
+// int fpioa_get_io_driving(int number)
+// {
+//     /* Check parameters */
+//     if(number < 0 || number >= FPIOA_NUM_IO)
+//         return -1;
+
+//     return fpioa->io[number].ds;
+// }
+
+int fpioa_set_function_raw(int number, fpioa_function_t function)
+{
+    /* Check parameters */
+    if(number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX)
+        return -1;
+    /* Atomic write register */
+    fpioa->io[number] = (const fpioa_io_config_t){
+        .ch_sel = function_config[function].ch_sel,
+        .ds = function_config[function].ds,
+        .oe_en = function_config[function].oe_en,
+        .oe_inv = function_config[function].oe_inv,
+        .do_sel = function_config[function].do_sel,
+        .do_inv = function_config[function].do_inv,
+        .pu = function_config[function].pu,
+        .pd = function_config[function].pd,
+        .sl = function_config[function].sl,
+        .ie_en = function_config[function].ie_en,
+        .ie_inv = function_config[function].ie_inv,
+        .di_inv = function_config[function].di_inv,
+        .st = function_config[function].st,
+        /* resv and pad_di do not need initialization */
+    };
+    return 0;
+}
+
+int fpioa_set_function(int number, fpioa_function_t function)
+{
+    uint8 index = 0;
+    /* Check parameters */
+    if(number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX)
+        return -1;
+    if(function == FUNC_RESV0)
+    {
+        fpioa_set_function_raw(number, FUNC_RESV0);
+        return 0;
+    }
+    /* Compare all IO */
+    for(index = 0; index < FPIOA_NUM_IO; index++)
+    {
+        if((fpioa->io[index].ch_sel == function) && (index != number))
+            fpioa_set_function_raw(index, FUNC_RESV0);
+    }
+    fpioa_set_function_raw(number, function);
+    return 0;
+}
+
+// int fpioa_set_tie_enable(fpioa_function_t function, int enable)
+// {
+//     /* Check parameters */
+//     if(function < 0 || function >= FUNC_MAX)
+//         return -1;
+//     /* Set tie enable */
+//     if(enable)
+//         fpioa->tie.en[function / 32] |= (1UL << (function % 32));
+//     else
+//         fpioa->tie.en[function / 32] &= (~(1UL << (function % 32)));
+//     return 0;
+// }
+
+// int fpioa_set_tie_value(fpioa_function_t function, int value)
+// {
+//     /* Check parameters */
+//     if(function < 0 || function >= FUNC_MAX)
+//         return -1;
+//     /* Set tie value */
+//     if(value)
+//         fpioa->tie.val[function / 32] |= (1UL << (function % 32));
+//     else
+//         fpioa->tie.val[function / 32] &= (~(1UL << (function % 32)));
+//     return 0;
+// }
+
+int fpioa_get_io_by_function(fpioa_function_t function)
+{
+    int index = 0;
+    for(index = 0; index < FPIOA_NUM_IO; index++)
+    {
+        if(fpioa->io[index].ch_sel == function)
+            return index;
+    }
+
+    return -1;
+}
+
+void fpioa_pin_init() {
+    fpioa_set_function(27, FUNC_SPI0_SCLK);
+    fpioa_set_function(28, FUNC_SPI0_D0);
+    fpioa_set_function(26, FUNC_SPI0_D1);
+	fpioa_set_function(32, FUNC_GPIOHS7);
+    fpioa_set_function(29, FUNC_SPI0_SS3);
+    #ifdef DEBUG
+    printf("fpioa_pin_init\n");
+    #endif
+}
\ No newline at end of file
diff --git a/kernel/gpiohs.c b/kernel/gpiohs.c
new file mode 100644
index 0000000000000000000000000000000000000000..9f76a3e2d00f4d9c6bda56c8016d0be1c29a08ae
--- /dev/null
+++ b/kernel/gpiohs.c
@@ -0,0 +1,204 @@
+// GPIOHS Protocol Implementation
+
+#include "include/types.h"
+#include "include/gpiohs.h"
+#include "include/fpioa.h"
+#include "include/utils.h"
+#include "include/memlayout.h"
+
+#define GPIOHS_MAX_PINNO 32
+
+volatile gpiohs_t *const gpiohs = (volatile gpiohs_t *)GPIOHS_V;
+
+// typedef struct _gpiohs_pin_instance
+// {
+//     uint64 pin;
+//     gpio_pin_edge_t edge;
+//     void (*callback)();
+//     plic_irq_callback_t gpiohs_callback;
+//     void *context;
+// } gpiohs_pin_instance_t;
+
+// static gpiohs_pin_instance_t pin_instance[32];
+
+void gpiohs_set_drive_mode(uint8 pin, gpio_drive_mode_t mode)
+{
+    // configASSERT(pin < GPIOHS_MAX_PINNO);
+    int io_number = fpioa_get_io_by_function(FUNC_GPIOHS0 + pin);
+    // configASSERT(io_number >= 0);
+
+    fpioa_pull_t pull = FPIOA_PULL_NONE;
+    uint32 dir = 0;
+
+    switch(mode)
+    {
+        case GPIO_DM_INPUT:
+            pull = FPIOA_PULL_NONE;
+            dir = 0;
+            break;
+        case GPIO_DM_INPUT_PULL_DOWN:
+            pull = FPIOA_PULL_DOWN;
+            dir = 0;
+            break;
+        case GPIO_DM_INPUT_PULL_UP:
+            pull = FPIOA_PULL_UP;
+            dir = 0;
+            break;
+        case GPIO_DM_OUTPUT:
+            pull = FPIOA_PULL_DOWN;
+            dir = 1;
+            break;
+        default:
+            // configASSERT(!"GPIO drive mode is not supported.") 
+            break;
+    }
+
+    fpioa_set_io_pull(io_number, pull);
+    volatile uint32 *reg = dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32;
+    volatile uint32 *reg_d = !dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32;
+    set_gpio_bit(reg_d, pin, 0);
+    set_gpio_bit(reg, pin, 1);
+}
+
+// gpio_pin_value_t gpiohs_get_pin(uint8 pin)
+// {
+//     // configASSERT(pin < GPIOHS_MAX_PINNO);
+//     return get_gpio_bit(gpiohs->input_val.u32, pin);
+// }
+
+void gpiohs_set_pin(uint8 pin, gpio_pin_value_t value)
+{
+    // configASSERT(pin < GPIOHS_MAX_PINNO);
+    set_gpio_bit(gpiohs->output_val.u32, pin, value);
+}
+
+// void gpiohs_set_pin_edge(uint8 pin, gpio_pin_edge_t edge)
+// {
+//     set_gpio_bit(gpiohs->rise_ie.u32, pin, 0);
+//     set_gpio_bit(gpiohs->rise_ip.u32, pin, 1);
+
+//     set_gpio_bit(gpiohs->fall_ie.u32, pin, 0);
+//     set_gpio_bit(gpiohs->fall_ip.u32, pin, 1);
+
+//     set_gpio_bit(gpiohs->low_ie.u32, pin, 0);
+//     set_gpio_bit(gpiohs->low_ip.u32, pin, 1);
+
+//     set_gpio_bit(gpiohs->high_ie.u32, pin, 0);
+//     set_gpio_bit(gpiohs->high_ip.u32, pin, 1);
+
+//     if(edge & GPIO_PE_FALLING)
+//     {
+//         set_gpio_bit(gpiohs->fall_ie.u32, pin, 1);
+//     } else
+//     {
+//         set_gpio_bit(gpiohs->fall_ie.u32, pin, 0);
+//     }
+
+//     if(edge & GPIO_PE_RISING)
+//     {
+//         set_gpio_bit(gpiohs->rise_ie.u32, pin, 1);
+//     } else
+//     {
+//         set_gpio_bit(gpiohs->rise_ie.u32, pin, 0);
+//     }
+
+//     if(edge & GPIO_PE_LOW)
+//     {
+//         set_gpio_bit(gpiohs->low_ie.u32, pin, 1);
+//     } else
+//     {
+//         set_gpio_bit(gpiohs->low_ie.u32, pin, 0);
+//     }
+
+//     if(edge & GPIO_PE_HIGH)
+//     {
+//         set_gpio_bit(gpiohs->high_ie.u32, pin, 1);
+//     } else
+//     {
+//         set_gpio_bit(gpiohs->high_ie.u32, pin, 0);
+//     }
+
+//     pin_instance[pin].edge = edge;
+// }
+
+// int gpiohs_pin_onchange_isr(void *userdata)
+// {
+//     gpiohs_pin_instance_t *ctx = (gpiohs_pin_instance_t *)userdata;
+//     uint64 pin = ctx->pin;
+
+//     if(ctx->edge & GPIO_PE_FALLING)
+//     {
+//         set_gpio_bit(gpiohs->fall_ie.u32, pin, 0);
+//         set_gpio_bit(gpiohs->fall_ip.u32, pin, 1);
+//         set_gpio_bit(gpiohs->fall_ie.u32, pin, 1);
+//     }
+
+//     if(ctx->edge & GPIO_PE_RISING)
+//     {
+//         set_gpio_bit(gpiohs->rise_ie.u32, pin, 0);
+//         set_gpio_bit(gpiohs->rise_ip.u32, pin, 1);
+//         set_gpio_bit(gpiohs->rise_ie.u32, pin, 1);
+//     }
+
+//     if(ctx->edge & GPIO_PE_LOW)
+//     {
+//         set_gpio_bit(gpiohs->low_ie.u32, pin, 0);
+//         set_gpio_bit(gpiohs->low_ip.u32, pin, 1);
+//         set_gpio_bit(gpiohs->low_ie.u32, pin, 1);
+//     }
+
+//     if(ctx->edge & GPIO_PE_HIGH)
+//     {
+//         set_gpio_bit(gpiohs->high_ie.u32, pin, 0);
+//         set_gpio_bit(gpiohs->high_ip.u32, pin, 1);
+//         set_gpio_bit(gpiohs->high_ie.u32, pin, 1);
+//     }
+
+//     if(ctx->callback)
+//         ctx->callback();
+//     if(ctx->gpiohs_callback)
+//         ctx->gpiohs_callback(ctx->context);
+
+//     return 0;
+// }
+
+// void gpiohs_set_irq(uint8 pin, uint32 priority, void (*func)())
+// {
+
+//     pin_instance[pin].pin = pin;
+//     pin_instance[pin].callback = func;
+
+//     // plic_set_priority(IRQN_GPIOHS0_INTERRUPT + pin, priority);
+//     // plic_irq_register(IRQN_GPIOHS0_INTERRUPT + pin, gpiohs_pin_onchange_isr, &(pin_instance[pin]));
+//     // plic_irq_enable(IRQN_GPIOHS0_INTERRUPT + pin);
+// }
+
+// void gpiohs_irq_register(uint8 pin, uint32 priority, plic_irq_callback_t callback, void *ctx)
+// {
+//     pin_instance[pin].pin = pin;
+//     pin_instance[pin].gpiohs_callback = callback;
+//     pin_instance[pin].context = ctx;
+
+//     // plic_set_priority(IRQN_GPIOHS0_INTERRUPT + pin, priority);
+//     // plic_irq_register(IRQN_GPIOHS0_INTERRUPT + pin, gpiohs_pin_onchange_isr, &(pin_instance[pin]));
+//     // plic_irq_enable(IRQN_GPIOHS0_INTERRUPT + pin);
+// }
+
+// void gpiohs_irq_unregister(uint8 pin)
+// {
+//     pin_instance[pin] = (gpiohs_pin_instance_t){
+//         .callback = NULL,
+//         .gpiohs_callback = NULL,
+//         .context = NULL,
+//     };
+//     set_gpio_bit(gpiohs->rise_ie.u32, pin, 0);
+//     set_gpio_bit(gpiohs->fall_ie.u32, pin, 0);
+//     set_gpio_bit(gpiohs->low_ie.u32, pin, 0);
+//     set_gpio_bit(gpiohs->high_ie.u32, pin, 0);
+//     // plic_irq_unregister(IRQN_GPIOHS0_INTERRUPT + pin);
+// }
+
+// void gpiohs_irq_disable(uint64 pin)
+// {
+//     // plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + pin);
+// }
\ No newline at end of file
diff --git a/kernel/include/buf.h b/kernel/include/buf.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f645653f4e3a88cbbe67591451e8877b97c33ac
--- /dev/null
+++ b/kernel/include/buf.h
@@ -0,0 +1,31 @@
+#ifndef __BUF_H
+#define __BUF_H
+
+#define BSIZE 512
+
+#include "sleeplock.h"
+
+
+
+
+struct buf {
+  uint8 busy;
+  uint8 vaild;
+  int disk;		// does disk "own" buf? 
+  uint dev;
+  uint sectorno;	// sector number 
+  struct sleeplock lock;
+  // uint refcnt;
+  struct buf *freeprev;
+  struct buf *freenext;
+  struct buf *prev;
+  struct buf *next;
+  uchar data[BSIZE];
+};
+
+void            binit(void);
+struct buf*     bread(uint, uint);
+void            brelse(struct buf*);
+void            bwrite(struct buf*);
+
+#endif
diff --git a/kernel/include/console.h b/kernel/include/console.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8e5252bb6d75a9bbdb463acd20422df53628d57
--- /dev/null
+++ b/kernel/include/console.h
@@ -0,0 +1,8 @@
+#ifndef __CONSOLE_H
+#define __CONSOLE_H
+
+void consoleinit(void);
+void consputc(int c);
+void consoleintr(int c);
+
+#endif
diff --git a/kernel/include/defs.h b/kernel/include/defs.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e7f9042a2f8a3e9884559c74a870f83ffa4397a
--- /dev/null
+++ b/kernel/include/defs.h
@@ -0,0 +1,242 @@
+struct buf;
+struct context;
+struct dirent;
+struct file;
+struct inode;
+struct pipe;
+struct proc;
+struct spinlock;
+struct sleeplock;
+struct stat;
+struct superblock;
+// enum spi_device_num_t;
+// enum spi_work_mode_t;
+// enum spi_frame_format_t;
+// bio.c
+void            binit(void);
+struct buf*     bread(uint, uint);
+void            brelse(struct buf*);
+void            bwrite(struct buf*);
+// void            bpin(struct buf*);
+// void            bunpin(struct buf*);
+
+// console.c
+void            consoleinit(void);
+void            consoleintr(int);
+void            consputc(int);
+
+// timer.c
+void timerinit();
+void set_next_timeout();
+void timer_tick(int cpl);
+
+// disk.c
+void            disk_init(void);
+void            disk_read(struct buf *b);
+void            disk_write(struct buf *b);
+void            disk_intr(void);
+
+// exec.c
+int             exec(char*, char**,char**);
+
+// fat32.c
+int             fat32_init(void);
+struct dirent*  dirlookup(struct dirent *entry, char *filename, uint *poff);
+struct dirent*  ealloc(struct dirent *dp, char *name, int dir);
+struct dirent*  edup(struct dirent *entry);
+void            eupdate(struct dirent *entry);
+void            etrunc(struct dirent *entry);
+void            eput(struct dirent *entry);
+void            estat(struct dirent *ep, struct stat *st);
+void            elock(struct dirent *entry);
+void            eunlock(struct dirent *entry);
+int             enext(struct dirent *dp, struct dirent *ep, uint off, int *count);
+struct dirent*  ename(char *path);
+struct dirent*  enameparent(char *path, char *name);
+int             eread(struct dirent *entry, int user_dst, uint64 dst, uint off, uint n);
+int             ewrite(struct dirent *entry, int user_src, uint64 src, uint off, uint n);
+
+// file.c
+struct file*    filealloc(void);
+void            fileclose(struct file*);
+struct file*    filedup(struct file*);
+void            fileinit(void);
+int             fileread(struct file*, uint64, int n);
+int             filestat(struct file*, uint64 addr);
+int             filewrite(struct file*, uint64, int n);
+int             dirnext(struct file *f, uint64 addr);
+
+// fs.c
+// void            fsinit(int);
+// int             dirlink(struct inode*, char*, uint);
+// struct inode*   dirlookup(struct inode*, char*, uint*);
+// struct inode*   ialloc(uint, short);
+// struct inode*   idup(struct inode*);
+// void            iinit();
+// void            ilock(struct inode*);
+// void            iput(struct inode*);
+// void            iunlock(struct inode*);
+// void            iunlockput(struct inode*);
+// void            iupdate(struct inode*);
+// int             namecmp(const char*, const char*);
+// struct inode*   namei(char*);
+// struct inode*   nameiparent(char*, char*);
+// int             readi(struct inode*, int, uint64, uint, uint);
+// void            stati(struct inode*, struct stat*);
+// int             writei(struct inode*, int, uint64, uint, uint);
+// void            itrunc(struct inode*);
+
+// kalloc.c
+void*           kalloc(void);
+void            kfree(void *);
+void            kinit(void);
+uint64          freemem_amount(void);
+
+// log.c
+// void            initlog(int, struct superblock*);
+// void            log_write(struct buf*);
+// void            begin_op(void);
+// void            end_op(void);
+
+// pipe.c
+int             pipealloc(struct file**, struct file**);
+void            pipeclose(struct pipe*, int);
+int             piperead(struct pipe*, uint64, int);
+int             pipewrite(struct pipe*, uint64, int);
+
+// printf.c
+void            printstring(const char* s);
+void            printf(char*, ...);
+void            panic(char*) __attribute__((noreturn));
+void            printfinit(void);
+
+// proc.c
+void            reg_info(void);
+int             cpuid(void);
+void            exit(int);
+int             fork(void);
+int             growproc(int);
+pagetable_t     proc_pagetable(struct proc *);
+void            proc_freepagetable(pagetable_t, uint64);
+int             kill(int);
+struct cpu*     mycpu(void);
+struct cpu*     getmycpu(void);
+struct proc*    myproc();
+void            procinit(void);
+void            scheduler(void) __attribute__((noreturn));
+void            sched(void);
+void            setproc(struct proc*);
+void            sleep(void*, struct spinlock*);
+void            userinit(void);
+int             wait(uint64);
+void            wakeup(void*);
+void            yield(void);
+int             either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
+int             either_copyin(void *dst, int user_src, uint64 src, uint64 len);
+void            procdump(void);
+void            test_proc_init(int);
+
+// swtch.S
+void            swtch(struct context*, struct context*);
+
+// spinlock.c
+void            acquire(struct spinlock*);
+int             holding(struct spinlock*);
+void            initlock(struct spinlock*, char*);
+void            release(struct spinlock*);
+
+// intr.c
+void            push_off(void);
+void            pop_off(void);
+
+// sleeplock.c
+void            acquiresleep(struct sleeplock*);
+void            releasesleep(struct sleeplock*);
+int             holdingsleep(struct sleeplock*);
+void            initsleeplock(struct sleeplock*, char*);
+
+// string.c
+int             memcmp(const void*, const void*, uint);
+void*           memmove(void*, const void*, uint);
+void*           memset(void*, int, uint);
+char*           safestrcpy(char*, const char*, int);
+int             strlen(const char*);
+int             strncmp(const char*, const char*, uint);
+char*           strncpy(char*, const char*, int);
+void            wnstr(wchar *dst, char const *src, int len);
+void            snstr(char *dst, wchar const *src, int len);
+int             wcsncmp(wchar const *s1, wchar const *s2, int len);
+
+// syscall.c
+int             argint(int, int*);
+int             argstr(int, char*, int);
+int             argaddr(int, uint64 *);
+int             fetchstr(uint64, char*, int);
+int             fetchaddr(uint64, uint64*);
+void            syscall();
+
+// trap.c
+extern uint     ticks;
+void            trapinit(void);
+void            trapinithart(void);
+extern struct spinlock tickslock;
+void            usertrapret(void);
+#ifndef QEMU
+void            supervisor_external_handler(void);
+#endif
+void            device_init(unsigned long, uint64);
+
+// uart.c
+void            uartinit(void);
+void            uartintr(void);
+void            uartputc(int);
+void            uartputc_sync(int);
+int             uartgetc(void);
+
+// vm.c
+void            kvminit(void);
+void            kvminithart(void);
+uint64          kvmpa(uint64);
+void            kvmmap(uint64, uint64, uint64, int);
+int             mappages(pagetable_t, uint64, uint64, uint64, int);
+pagetable_t     uvmcreate(void);
+void            uvminit(pagetable_t, uchar *, uint);
+uint64          uvmalloc(pagetable_t, uint64, uint64);
+uint64          uvmdealloc(pagetable_t, uint64, uint64);
+int             uvmcopy(pagetable_t, pagetable_t, uint64);
+void            uvmfree(pagetable_t, uint64);
+void            uvmunmap(pagetable_t, uint64, uint64, int);
+void            uvmclear(pagetable_t, uint64);
+uint64          walkaddr(pagetable_t, uint64);
+int             copyout(pagetable_t, uint64, char *, uint64);
+int             copyin(pagetable_t, char *, uint64, uint64);
+int             copyinstr(pagetable_t, char *, uint64, uint64);
+
+// virtio_disk.c
+void            virtio_disk_init(void);
+void            virtio_disk_rw(struct buf *b, int write);
+void            virtio_disk_intr(void);
+
+// plic.c
+void            plicinit(void);
+void            plicinithart(void);
+int             plic_claim(void);
+void            plic_complete(int);
+
+// logo.c
+void            print_logo(void);
+
+// test.c
+void            test_kalloc(void);
+void            test_vm(unsigned long);
+void            test_sdcard(void);
+// spi.c
+// void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,
+//               uint64 data_bit_length, uint32 endian);
+
+
+// void            ptesprintf(pagetable_t, int);
+// int             vmprint(pagetable_t);
+
+// number of elements in fixed-size array
+#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
diff --git a/kernel/include/disk.h b/kernel/include/disk.h
new file mode 100644
index 0000000000000000000000000000000000000000..3186fce330ba3849550a303abe5e868309bd35ba
--- /dev/null
+++ b/kernel/include/disk.h
@@ -0,0 +1,11 @@
+#ifndef __DISK_H
+#define __DISK_H
+
+#include "buf.h"
+
+void disk_init(void);
+void disk_read(struct buf *b);
+void disk_write(struct buf *b);
+void disk_intr(void);
+
+#endif
diff --git a/kernel/include/dmac.h b/kernel/include/dmac.h
new file mode 100644
index 0000000000000000000000000000000000000000..bab55b7482dfee8bd9ec677590330fb3b476d4ce
--- /dev/null
+++ b/kernel/include/dmac.h
@@ -0,0 +1,1539 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _DRIVER_DMAC_H
+#define _DRIVER_DMAC_H
+
+// #include "platform.h"
+#include "plic.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* DMAC */
+#define DMAC_CHANNEL_COUNT (DMAC_CHANNEL_MAX)
+#define LAST_ROW (-1)
+
+typedef enum _dmac_channel_number
+{
+    DMAC_CHANNEL0 = 0,
+    DMAC_CHANNEL1 = 1,
+    DMAC_CHANNEL2 = 2,
+    DMAC_CHANNEL3 = 3,
+    DMAC_CHANNEL4 = 4,
+    DMAC_CHANNEL5 = 5,
+    DMAC_CHANNEL_MAX
+} dmac_channel_number_t;
+
+typedef enum _dmac_src_dst_select
+{
+    DMAC_SRC = 0x1,
+    DMAC_DST = 0x2,
+    DMAC_SRC_DST = 0x3
+} dmac_src_dst_select_t;
+
+typedef enum _state_value
+{
+    clear = 0,
+    set = 1
+} state_value_t;
+
+typedef enum _dmac_lock_bus_ch
+{
+    DMAC_LOCK_BUS = 0x1,
+    DMAC_LOCK_CHANNEL = 0x2,
+    DMAC_LOCK_BUS_CH = 0x3
+} dmac_lock_bus_ch_t;
+
+typedef enum _dmac_sw_hw_hs_select
+{
+    DMAC_HS_HARDWARE = 0x0,
+    DMAC_HS_SOFTWARE = 0x1
+} dmac_sw_hw_hs_select_t;
+
+typedef enum _dmac_scatter_gather_param
+{
+    DMAC_SG_COUNT = 0x0,
+    DMAC_SG_INTERVAL = 0x1
+} dmac_scatter_gather_param_t;
+
+typedef enum _dmac_irq
+{
+    /* no interrupts */
+    DMAC_IRQ_NONE = 0x00,
+    /* transfer complete */
+    DMAC_IRQ_TFR = 0x01,
+    /* block transfer complete */
+    DMAC_IRQ_BLOCK = 0x02,
+    /* source transaction complete */
+    DMAC_IRQ_SRCTRAN = 0x04,
+    /* destination transaction complete */
+    DMAC_IRQ_DSTTRAN = 0x08,
+    /* error */
+    DMAC_IRQ_ERR = 0x10,
+    /* all interrupts */
+    DMAC_IRQ_ALL = 0x1f
+} dmac_irq_t;
+
+typedef enum _dmac_software_req
+{
+    /* ReqSrcReq/ReqDstReq */
+    DMAC_REQUEST = 0x1,
+    /* SglReqSrcReq/SglReqDstReq */
+    DMAC_SINGLE_REQUEST = 0x2,
+    /* LstReqSrcReq/LstReqDstReq */
+    DMAC_LAST_REQUEST = 0x4
+} dmac_software_req_t;
+
+typedef enum _dmac_master_number
+{
+    DMAC_MASTER1 = 0x0,
+    DMAC_MASTER2 = 0x1
+} dmac_master_number_t;
+
+typedef enum _dmac_transfer_flow
+{
+    /* mem to mem - DMAC   flow ctlr */
+    DMAC_MEM2MEM_DMA = 0x0,
+    /* mem to prf - DMAC   flow ctlr */
+    DMAC_MEM2PRF_DMA = 0x1,
+    /* prf to mem - DMAC   flow ctlr */
+    DMAC_PRF2MEM_DMA = 0x2,
+    /* prf to prf - DMAC   flow ctlr */
+    DMAC_PRF2PRF_DMA = 0x3,
+    /* prf to mem - periph flow ctlr */
+    DMAC_PRF2MEM_PRF = 0x4,
+    /* prf to prf - source flow ctlr */
+    DMAC_PRF2PRF_SRCPRF = 0x5,
+    /* mem to prf - periph flow ctlr */
+    DMAC_MEM2PRF_PRF = 0x6,
+    /* prf to prf - dest   flow ctlr */
+    DMAC_PRF2PRF_DSTPRF = 0x7
+} dmac_transfer_flow_t;
+
+typedef enum _dmac_burst_trans_length
+{
+    DMAC_MSIZE_1 = 0x0,
+    DMAC_MSIZE_4 = 0x1,
+    DMAC_MSIZE_8 = 0x2,
+    DMAC_MSIZE_16 = 0x3,
+    DMAC_MSIZE_32 = 0x4,
+    DMAC_MSIZE_64 = 0x5,
+    DMAC_MSIZE_128 = 0x6,
+    DMAC_MSIZE_256 = 0x7
+} dmac_burst_trans_length_t;
+
+typedef enum _dmac_address_increment
+{
+    DMAC_ADDR_INCREMENT = 0x0,
+    DMAC_ADDR_NOCHANGE = 0x1
+} dmac_address_increment_t;
+
+typedef enum _dmac_transfer_width
+{
+    DMAC_TRANS_WIDTH_8 = 0x0,
+    DMAC_TRANS_WIDTH_16 = 0x1,
+    DMAC_TRANS_WIDTH_32 = 0x2,
+    DMAC_TRANS_WIDTH_64 = 0x3,
+    DMAC_TRANS_WIDTH_128 = 0x4,
+    DMAC_TRANS_WIDTH_256 = 0x5
+} dmac_transfer_width_t;
+
+typedef enum _dmac_hs_interface
+{
+    DMAC_HS_IF0 = 0x0,
+    DMAC_HS_IF1 = 0x1,
+    DMAC_HS_IF2 = 0x2,
+    DMAC_HS_IF3 = 0x3,
+    DMAC_HS_IF4 = 0x4,
+    DMAC_HS_IF5 = 0x5,
+    DMAC_HS_IF6 = 0x6,
+    DMAC_HS_IF7 = 0x7,
+    DMAC_HS_IF8 = 0x8,
+    DMAC_HS_IF9 = 0x9,
+    DMAC_HS_IF10 = 0xa,
+    DMAC_HS_IF11 = 0xb,
+    DMAC_HS_IF12 = 0xc,
+    DMAC_HS_IF13 = 0xd,
+    DMAC_HS_IF14 = 0xe,
+    DMAC_HS_IF15 = 0xf
+} dmac_hs_interface_t;
+
+typedef enum _dmac_multiblk_transfer_type
+{
+    CONTIGUOUS = 0,
+    RELOAD = 1,
+    SHADOWREGISTER = 2,
+    LINKEDLIST = 3
+} dmac_multiblk_transfer_type_t;
+
+typedef enum _dmac_multiblk_type
+{
+    DMAC_SRC_DST_CONTINUE = 0,
+    DMAC_SRC_CONTINUE_DST_RELAOD = 2,
+    DMAC_SRC_CONTINUE_DST_LINKEDLIST = 3,
+    DMAC_SRC_RELOAD_DST_CONTINUE = 4,
+    DMAC_SRC_RELOAD_DST_RELOAD = 5,
+    DMAC_SRC_RELOAD_DST_LINKEDLIST = 6,
+    DMAC_SRC_LINKEDLIST_DST_CONTINUE = 7,
+    DMAC_SRC_LINKEDLIST_DST_RELOAD = 8,
+    DMAC_SRC_LINKEDLIST_DST_LINKEDLIST = 9,
+    DMAC_SRC_SHADOWREG_DST_CONTINUE = 10
+} dmac_multiblk_type_t;
+
+typedef enum _dmac_transfer_type
+{
+    DMAC_TRANSFER_ROW1 = 0x1,
+    DMAC_TRANSFER_ROW2 = 0x2,
+    DMAC_TRANSFER_ROW3 = 0x3,
+    DMAC_TRANSFER_ROW4 = 0x4,
+    DMAC_TRANSFER_ROW5 = 0x5,
+    DMAC_TRANSFER_ROW6 = 0x6,
+    DMAC_TRANSFER_ROW7 = 0x7,
+    DMAC_TRANSFER_ROW8 = 0x8,
+    DMAC_TRANSFER_ROW9 = 0x9,
+    DMAC_TRANSFER_ROW10 = 0xa
+} dmac_transfer_type_t;
+
+typedef enum _dmac_prot_level
+{
+    /* default prot level */
+    DMAC_NONCACHE_NONBUFF_NONPRIV_OPCODE = 0x0,
+    DMAC_NONCACHE_NONBUFF_NONPRIV_DATA = 0x1,
+    DMAC_NONCACHE_NONBUFF_PRIV_OPCODE = 0x2,
+    DMAC_NONCACHE_NONBUFF_PRIV_DATA = 0x3,
+    DMAC_NONCACHE_BUFF_NONPRIV_OPCODE = 0x4,
+    DMAC_NONCACHE_BUFF_NONPRIV_DATA = 0x5,
+    DMAC_NONCACHE_BUFF_PRIV_OPCODE = 0x6,
+    DMAC_NONCACHE_BUFF_PRIV_DATA = 0x7,
+    DMAC_CACHE_NONBUFF_NONPRIV_OPCODE = 0x8,
+    DMAC_CACHE_NONBUFF_NONPRIV_DATA = 0x9,
+    DMAC_CACHE_NONBUFF_PRIV_OPCODE = 0xa,
+    DMAC_CACHE_NONBUFF_PRIV_DATA = 0xb,
+    DMAC_CACHE_BUFF_NONPRIV_OPCODE = 0xc,
+    DMAC_CACHE_BUFF_NONPRIV_DATA = 0xd,
+    DMAC_CACHE_BUFF_PRIV_OPCODE = 0xe,
+    DMAC_CACHE_BUFF_PRIV_DATA = 0xf
+} dmac_prot_level_t;
+
+typedef enum _dmac_fifo_mode
+{
+    DMAC_FIFO_MODE_SINGLE = 0x0,
+    DMAC_FIFO_MODE_HALF = 0x1
+} dmac_fifo_mode_t;
+
+typedef enum _dw_dmac_flow_ctl_mode
+{
+    DMAC_DATA_PREFETCH_ENABLED = 0x0,
+    DMAC_DATA_PREFETCH_DISABLED = 0x1
+} dw_dmac_flow_ctl_mode_t;
+
+typedef enum _dmac_polarity_level
+{
+    DMAC_ACTIVE_HIGH = 0x0,
+    DMAC_ACTIVE_LOW = 0x1
+} dmac_polarity_level_t;
+
+typedef enum _dmac_lock_level
+{
+    DMAC_LOCK_LEVEL_DMA_TRANSFER = 0x0,
+    DMAC_LOCK_LEVEL_BLOCK_TRANSFER = 0x1,
+    DMAC_LOCK_LEVEL_TRANSACTION = 0x2
+} dmac_lock_level_t;
+
+typedef enum _dmac_channel_priority
+{
+    DMAC_PRIORITY_0 = 0x0,
+    DMAC_PRIORITY_1 = 0x1,
+    DMAC_PRIORITY_2 = 0x2,
+    DMAC_PRIORITY_3 = 0x3,
+    DMAC_PRIORITY_4 = 0x4,
+    DMAC_PRIORITY_5 = 0x5,
+    DMAC_PRIORITY_6 = 0x6,
+    DMAC_PRIORITY_7 = 0x7
+} dmac_channel_priority_t;
+
+typedef enum _dmac_state
+{
+    ZERO,
+    ONE
+} dmac_state_t;
+
+typedef enum _dmac_common_int
+{
+    SLVIF_COMMON_DEC_ERR = 0,
+    SLVIF_COMMON_WR2RO_ERR = 1,
+    SLVIF_COMMON_RD2WO_ERR = 2,
+    SLVIF_COMMON__WRONHOLD_ERR = 3,
+    SLVIF_UNDEFINED_DEC_ERR = 4,
+    SLVIF_ALL_INT = 5
+} dmac_common_int_t;
+
+typedef struct _dmac_cfg
+{
+    /**
+     * Bit 0 is used to enable dmac
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 dmac_en : 1;
+    /**
+     * Bit 1 is used to glabally enable interrupt generation
+     * 0x1 for enable interrupt, 0x0 for disable interrupt
+     */
+    uint64 int_en : 1;
+    /* Bits [63:2] is reserved */
+    uint64 rsvd : 62;
+} __attribute__((packed, aligned(8))) dmac_cfg_t;
+
+typedef union _dmac_cfg_u
+{
+    dmac_cfg_t cfg;
+    uint64 data;
+} dmac_cfg_u_t;
+
+typedef struct _damc_chen
+{
+    /**
+     * Bit 0 is used to enable channel 1
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch1_en : 1;
+    /**
+     * Bit 1 is used to enable channel 2
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch2_en : 1;
+    /**
+     * Bit 2 is used to enable channel 3
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch3_en : 1;
+    /**
+     * Bit 3 is used to enable channel 4
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch4_en : 1;
+    /**
+     * Bit 4 is used to enable channel 5
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch5_en : 1;
+    /**
+     * Bit 5 is used to enable channel 6
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch6_en : 1;
+    /* Bits [7:6] is reserved */
+    uint64 rsvd1 : 2;
+    /**
+     * Bit 8 is write enable bit
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch1_en_we : 1;
+    /**
+     * Bit 9 is write enable bit
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch2_en_we : 1;
+    /**
+     * Bit 10 is write enable bit
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch3_en_we : 1;
+    /**
+     * Bit 11 is write enable bit
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch4_en_we : 1;
+    /**
+     * Bit 12 is write enable bit
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch5_en_we : 1;
+    /**
+     * Bit 13 is write enable bit
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 ch6_en_we : 1;
+    /* Bits [15:14] is reserved */
+    uint64 rsvd2 : 2;
+    /**
+     * Bit 16 is susped reuest
+     * 0x1 for request channel suspend
+     * 0x0 for no channel suspend request
+     */
+    uint64 ch1_susp : 1;
+    /**
+     * Bit 17 is susped reuest
+     * 0x1 for request channel suspend
+     * 0x0 for no channel suspend request
+     */
+    uint64 ch2_susp : 1;
+    /* Bit 18 is susped reuest
+     * 0x1 for request channel suspend
+     * 0x0 for no channel suspend request
+     */
+    uint64 ch3_susp : 1;
+    /**
+     * Bit 19 is susped reuest
+     * 0x1 for request channel suspend
+     * 0x0 for no channel suspend request
+     */
+    uint64 ch4_susp : 1;
+    /**
+     * Bit 20 is susped reuest
+     * 0x1 for request channel suspend
+     * 0x0 for no channel suspend request
+     */
+    uint64 ch5_susp : 1;
+    /**
+     * Bit 21 is susped reuest
+     * 0x1 for request channel suspend
+     * 0x0 for no channel suspend request
+     */
+    uint64 ch6_susp : 1;
+    /* Bits [23:22] is reserved */
+    uint64 rsvd3 : 2;
+    /**
+     * Bit  24 is write enable to the channel suspend bit
+     * 0x1 for enable write to CH1_SUSP bit
+     * 0x0 for disable write to CH1_SUSP bit
+     */
+    uint64 ch1_susp_we : 1;
+    /**
+     * Bit  25 is write enable to the channel suspend bit
+     * 0x1 for enable write to CH2_SUSP bit
+     * 0x0 for disable write to CH2_SUSP bit
+     */
+    uint64 ch2_susp_we : 1;
+    /**
+     * Bit  26 is write enable to the channel suspend bit
+     * 0x1 for enable write to CH3_SUSP bit
+     * 0x0 for disable write to CH3_SUSP bit
+     */
+    uint64 ch3_susp_we : 1;
+    /**
+     * Bit  27 is write enable to the channel suspend bit
+     * 0x1 for enable write to CH4_SUSP bit
+     * 0x0 for disable write to CH4_SUSP bit
+     */
+    uint64 ch4_susp_we : 1;
+    /**
+     * Bit  28 is write enable to the channel suspend bit
+     * 0x1 for enable write to CH5_SUSP bit
+     * 0x0 for disable write to CH5_SUSP bit
+     */
+    uint64 ch5_susp_we : 1;
+    /**
+     * Bit  29 is write enable to the channel suspend bit
+     * 0x1 for enable write to CH6_SUSP bit
+     * 0x0 for disable write to CH6_SUSP bit
+     */
+    uint64 ch6_susp_we : 1;
+    /* Bits [31:30] is reserved */
+    uint64 rsvd4 : 2;
+    /**
+     * Bit  32 is channel-1 abort requst bit
+     * 0x1 for request for channnel abort
+     * 0x0 for no channel abort request
+     */
+    uint64 ch1_abort : 1;
+    /**
+     * Bit  33 is channel-2 abort requst bit
+     * 0x1 for request for channnel abort
+     * 0x0 for no channel abort request
+     */
+    uint64 ch2_abort : 1;
+    /**
+     * Bit  34 is channel-3 abort requst bit
+     * 0x1 for request for channnel abort
+     * 0x0 for no channel abort request
+     */
+    uint64 ch3_abort : 1;
+    /**
+     * Bit  35 is channel-4 abort requst bit
+     * 0x1 for request for channnel abort
+     * 0x0 for no channel abort request
+     */
+    uint64 ch4_abort : 1;
+    /**
+     * Bit  36 is channel-5 abort requst bit
+     * 0x1 for request for channnel abort
+     * 0x0 for no channel abort request
+     */
+    uint64 ch5_abort : 1;
+    /**
+     * Bit  37 is channel-6 abort requst bit
+     * 0x1 for request for channnel abort
+     * 0x0 for no channel abort request
+     */
+    uint64 ch6_abort : 1;
+    /* Bits [39:38] is reserved */
+    uint64 rsvd5 : 2;
+    /**
+     * Bit 40 is ued to write enable  channel-1 abort bit
+     * 0x1 for enable write to CH1_ABORT bit
+     * 0x0 for disable write to CH1_ABORT bit
+     */
+    uint64 ch1_abort_we : 1;
+    /**
+     * Bit 41 is ued to write enable  channel-2 abort bit
+     * 0x1 for enable write to CH2_ABORT bit
+     * 0x0 for disable write to CH2_ABORT bit
+     */
+    uint64 ch2_abort_we : 1;
+    /**
+     * Bit 42 is ued to write enable  channel-3 abort bit
+     * 0x1 for enable write to CH3_ABORT bit
+     * 0x0 for disable write to CH3_ABORT bit
+     */
+    uint64 ch3_abort_we : 1;
+    /**
+     * Bit 43 is ued to write enable  channel-4 abort bit
+     * 0x1 for enable write to CH4_ABORT bit
+     * 0x0 for disable write to CH4_ABORT bit
+     */
+    uint64 ch4_abort_we : 1;
+    /**
+     * Bit 44 is ued to write enable  channel-5 abort bit
+     * 0x1 for enable write to CH5_ABORT bit
+     * 0x0 for disable write to CH5_ABORT bit
+     */
+    uint64 ch5_abort_we : 1;
+    /**
+     * Bit 45 is ued to write enable  channel-6 abort bit
+     * 0x1 for enable write to CH6_ABORT bit
+     * 0x0 for disable write to CH6_ABORT bit
+     */
+    uint64 ch6_abort_we : 1;
+    /* Bits [47:46] is reserved */
+    uint64 rsvd6 : 2;
+    /* Bits [63:48] is reserved */
+    uint64 rsvd7 : 16;
+} __attribute__((packed, aligned(8))) damc_chen_t;
+
+typedef union _dmac_chen_u
+{
+    damc_chen_t dmac_chen;
+    uint64 data;
+} dmac_chen_u_t;
+
+typedef struct _dmac_intstatus
+{
+    /**
+     * Bit 0 is channel 1 interrupt bit
+     * 0x1 for channel 1 interrupt  active
+     * 0x0 for channel 1 interrupt inactive
+     */
+    uint64 ch1_intstat : 1;
+    /**
+     * Bit 1 is channel 1 interrupt bit
+     * 0x1 for channel 2 interrupt  active
+     * 0x0 for channel 2 interrupt inactive
+     */
+    uint64 ch2_intstat : 1;
+    /**
+     * Bit 2 is channel 3 interrupt bit
+     * 0x1 for channel 3 interrupt  active
+     * 0x0 for channel 3 interrupt inactive
+     */
+    uint64 ch3_intstat : 1;
+    /**
+     * Bit 3 is channel 4 interrupt bit
+     * 0x1 for channel 4 interrupt  active
+     * 0x0 for channel 4 interrupt inactive
+     */
+    uint64 ch4_intstat : 1;
+    /**
+     * Bit 4 is channel 5 interrupt bit
+     * 0x1 for channel 5 interrupt  active
+     * 0x0 for channel 5 interrupt inactive
+     */
+    uint64 ch5_intstat : 1;
+    /**
+     * Bit 5 is channel 6 interrupt bit
+     * 0x1 for channel 6 interrupt  active
+     * 0x0 for channel 6 interrupt inactive
+     */
+    uint64 ch6_intstat : 1;
+    /* Bits [15:6] is reserved */
+    uint64 rsvd1 : 10;
+    /**
+     * Bit 16 is commom register status bit
+     * 0x1 for common register interrupt is active
+     * 0x0 for common register interrupt inactive
+     */
+    uint64 commonreg_intstat : 1;
+    /* Bits [63:17] is reserved */
+    uint64 rsvd2 : 47;
+} __attribute__((packed, aligned(8))) dmac_intstatus_t;
+
+typedef union _dmac_intstatus_u
+{
+    dmac_intstatus_t intstatus;
+    uint64 data;
+} dmac_intstatus_u_t;
+
+typedef struct _dmac_commonreg_intclear
+{
+    /**
+     * Bit 0 is slave nterface Common Register
+     * Decode Error Interrupt clear Bit
+     * x01 for clear SLVIF_CommonReg_DEC_ERR interrupt
+     * in DMAC_COMMONREG_INTSTATUSREG
+     * 0x0 for inactive signal
+     */
+    uint64 clear_slvif_dec_err_intstat : 1;
+    /**
+     * Bit 1 is Slave Interface Common Register Write
+     * to Read only Error Interrupt clear Bit
+     * x01 for clear SLVIF_CommonReg_WR2RO_ERR interrupt
+     * in DMAC_COMMONREG_INTSTATUSREG
+     * 0x0 for inactive signal
+     */
+    uint64 clear_slvif_wr2ro_err_intstat : 1;
+    /**
+     * Bit 2 is Slave Interface Common Register Read to
+     * Write only Error Interrupt clear Bit
+     * x01 for clear SLVIF_CommonReg_RD2WO_ERR  interrupt
+     * in DMAC_COMMONREG_INTSTATUSREG
+     * 0x0 for inactive signal
+     */
+    uint64 clear_slvif_rd2wo_err_intstat : 1;
+    /**
+     * Bit 3 is Slave Interface Common Register Write
+     * On Hold Error Interrupt clear Bit
+     * x01 for clear SSLVIF_CommonReg_WrOnHold_ERR interrupt
+     * in DMAC_COMMONREG_INTSTATUSREG
+     * 0x0 for inactive signal
+     */
+    uint64 clear_slvif_wronhold_err_intstat : 1;
+    /* Bits [7:4] is reserved */
+    uint64 rsvd1 : 4;
+    /**
+     * Bit 8 is Slave Interface Undefined register
+     * Decode Error Interrupt clear Bit
+     * x01 for clear SLVIF_UndefinedReg_DEC_ERRinterrupt
+     * in DMAC_COMMONREG_INTSTATUSREG
+     * 0x0 for inactive signal
+     */
+    uint64 clear_slvif_undefinedreg_dec_err_intstat : 1;
+    /* Bits [63:9] is reserved */
+    uint64 rsvd2 : 55;
+} __attribute__((packed, aligned(8))) dmac_commonreg_intclear_t;
+
+typedef union _dmac_commonreg_intclear_u
+{
+    dmac_commonreg_intclear_t com_intclear;
+    uint64 data;
+} dmac_commonreg_intclear_u_t;
+
+typedef struct _dmac_commonreg_intstatus_enable
+{
+    /**
+     * Bit 0 is Slave Interface Common Register Decode Error
+     * Interrupt Status Enable Bit
+     * 0x1 for SLVIF_CommonReg_DEC_ERR_IntStat bit enable
+     * 0x0 for SLVIF_CommonReg_DEC_ERR_IntStat bit disable
+     */
+    uint64 enable_slvif_dec_err_intstat : 1;
+    /**
+     * Bit 1 is Slave Interface Common Register Write to Read
+     * only Error Interrupt Status Enable Bit
+     * 0x1 for SLVIF_CommonReg_WR2RO_ERR_IntStat bit enable
+     * 0x0 for SLVIF_CommonReg_WR2RO_ERR_IntStat bit disable
+     */
+    uint64 enable_slvif_wr2ro_err_intstat : 1;
+    /*!<
+     * Bit 2 is Slave Interface Common Register Read to Write
+     * only Error Interrupt Status Enable Bit
+     * 0x1 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit enable
+     * 0x0 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit disable
+     */
+    uint64 enable_slvif_rd2wo_err_intstat : 1;
+    /**
+     * Bit 3 is Slave Interface Common Register Write On Hold
+     * Error Interrupt Status Enable Bit
+     * 0x1 for SLVIF_CommonReg_WrOnHold_ERR_IntStat bit enable
+     * 0x0 for SLVIF_CommonReg_WrOnHold_ERR_IntStat bit disable
+     */
+    uint64 enable_slvif_wronhold_err_intstat : 1;
+    /* Bits [7:4] is reserved */
+    uint64 rsvd1 : 4;
+    /**
+     * Bit 8 is Slave Interface Undefined register Decode
+     * Error Interrupt Status enable Bit
+     * 0x1 for SLVIF_UndefinedReg_DEC_ERR_IntStat bit enable
+     * 0x0 for SLVIF_UndefinedReg_DEC_ERR_IntStat disable
+     */
+    uint64 enable_slvif_undefinedreg_dec_err_intstat : 1;
+    /* Bits [63:9] is reserved */
+    uint64 rsvd2 : 55;
+} __attribute__((packed, aligned(8))) dmac_commonreg_intstatus_enable_t;
+
+typedef union _dmac_commonreg_intstatus_enable_u
+{
+    dmac_commonreg_intstatus_enable_t intstatus_enable;
+    uint64 data;
+} dmac_commonreg_intstatus_enable_u_t;
+
+typedef struct _dmac_commonreg_intsignal_enable
+{
+    /**
+     * Bit 0 is Slave Interface Common Register Decode Error
+     * Interrupt Signal Enable Bit
+     * 0x1 for SLVIF_CommonReg_DEC_ERR_IntStat signal enable
+     * 0x0 for SLVIF_CommonReg_DEC_ERR_IntStat signal disable
+     */
+    uint64 enable_slvif_dec_err_intsignal : 1;
+    /**
+     * Bit 1 is Slave Interface Common Register Write to Read only
+     *  Error Interrupt Signal Enable Bit
+     * 0x1 for SLVIF_CommonReg_WR2RO_ERR_IntStat signal enable
+     * 0x0 for SLVIF_CommonReg_WR2RO_ERR_IntStat signal disable
+     */
+    uint64 enable_slvif_wr2ro_err_intsignal : 1;
+    /**
+     * Bit 2 is Slave Interface Common Register Read to
+     *  Write only Error Interrupt Status Enable Bit
+     * 0x1 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit enable
+     * 0x0 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit disable
+     */
+    uint64 enable_slvif_rd2wo_err_intsignal : 1;
+    /**
+     * Bit 3 is Slave Interface Common Register Write On Hold Error
+     * Interrupt Signal Enable Bit
+     * 0x1 for SLVIF_CommonReg_WrOnHold_ERR_IntStat signal enable
+     * 0x0 for SLVIF_CommonReg_WrOnHold_ERR_IntStat signal disable
+     */
+    uint64 enable_slvif_wronhold_err_intsignal : 1;
+    /* Bits [7:4] is reserved */
+    uint64 rsvd1 : 4;
+    /**
+     * Bit 8 is Slave Interface Undefined register Decode Error
+     * Interrupt Signal Enable Bit
+     * 0x1 for SLVIF_UndefinedReg_DEC_ERR_IntStat signal enable
+     * 0x0 for SLVIF_UndefinedReg_DEC_ERR_IntStat signal disable
+     */
+    uint64 enable_slvif_undefinedreg_dec_err_intsignal : 1;
+    /* Bits [63:9] is reserved */
+    uint64 rsvd2 : 55;
+} __attribute__((packed, aligned(8))) dmac_commonreg_intsignal_enable_t;
+
+typedef union _dmac_commonreg_intsignal_enable_u
+{
+    dmac_commonreg_intsignal_enable_t intsignal_enable;
+    uint64 data;
+} dmac_commonreg_intsignal_enable_u_t;
+
+typedef struct _dmac_commonreg_intstatus
+{
+    /**
+     * Bit 0 is Slave Interface Common Register Decode
+     * Error Interrupt Status Bit
+     * 0x1 for Slave Interface Decode Error detected
+     * 0x0 for No Slave Interface Decode Errors
+     */
+    uint64 slvif_dec_err_intstat : 1;
+    /**
+     * Bit 1 is Slave Interface Common Register Write to Read Only
+     * Error Interrupt Status bit
+     * 0x1 for Slave Interface Write to Read Only Error detected
+     * 0x0 No Slave Interface Write to Read Only Errors
+     */
+    uint64 slvif_wr2ro_err_intstat : 1;
+    /**
+     * Bit 2 is Slave Interface Common Register Read to Write
+     * only Error Interrupt Status bit
+     * 0x1 for Slave Interface Read to Write Only Error detected
+     * 0x0 for No Slave Interface Read to Write Only Errors
+     */
+    uint64 slvif_rd2wo_err_intstat : 1;
+    /**
+     * Bit 3 is Slave Interface Common Register Write On
+     * Hold Error Interrupt Status Bit
+     * 0x1 for Slave Interface Common Register Write On Hold Error detected
+     * 0x0 for No Slave Interface Common Register Write On Hold Errors
+     */
+    uint64 slvif_wronhold_err_intstat : 1;
+    /*!< Bits [7:4] is reserved */
+    uint64 rsvd1 : 4;
+    /**
+     * Bit 8 is Slave Interface Undefined register Decode
+     * Error Interrupt Signal Enable Bit
+     * 0x1 for  Slave Interface Decode Error detected
+     * 0x0 for No Slave Interface Decode Errors
+     */
+    uint64 slvif_undefinedreg_dec_err_intstat : 1;
+    /* Bits [63:9] is reserved */
+    uint64 rsvd2 : 55;
+} __attribute__((packed, aligned(8))) dmac_commonreg_intstatus_t;
+
+typedef union _dmac_commonreg_intstatus_u
+{
+    dmac_commonreg_intstatus_t commonreg_intstatus;
+    uint64 data;
+} dmac_commonreg_intstatus_u_t;
+
+typedef struct _dmac_reset
+{
+    /* Bit 0 is DMAC reset request bit */
+    uint64 rst : 1;
+    /* Bits [63:1] is reserved */
+    uint64 rsvd : 63;
+} __attribute__((packed, aligned(8))) dmac_reset_t;
+
+typedef union _dmac_reset_u
+{
+    dmac_reset_t reset;
+    uint64 data;
+} dmac_reset_u_t;
+
+typedef struct _dmac_ch_block_ts
+{
+    uint64 block_ts : 22;
+    /*!< Bit [21:0] is block transfer size*/
+    uint64 rsvd : 42;
+    /*!< Bits [63:22] is reserved */
+} __attribute__((packed, aligned(8))) dmac_ch_block_ts_t;
+
+typedef union _dmac_ch_block_ts_u
+{
+    dmac_ch_block_ts_t block_ts;
+    uint64 data;
+} dmac_ch_block_ts_u_t;
+
+typedef struct _dmac_ch_ctl
+{
+    /**
+     * Bit 0 is source master select
+     * 1 for AXI master 2, 0 for AXI master 1
+     */
+    uint64 sms : 1;
+    /* Bit 1 is reserved */
+    uint64 rsvd1 : 1;
+    /**
+     * Bit 2 is destination master select
+     * 0x1 for AXI master 2,0x0 for AXI master 1
+     */
+    uint64 dms : 1;
+    /* Bit 3 is reserved */
+    uint64 rsvd2 : 1;
+    /**
+     * Bit 4 is source address increment
+     * 0x1 for no change, 0x0 for incremnet
+     */
+    uint64 sinc : 1;
+    /**
+     * Bit 5 is reserved
+     */
+    uint64 rsvd3 : 1;
+    /**
+     * Bit 6 is destination address incremnet
+     * 0x1 for no change, 0x0 for increment
+     */
+    uint64 dinc : 1;
+    /* Bit 7 is reserved*/
+    uint64 rsvd4 : 1;
+    /**
+     * Bits [10:8] is source transfer width
+     * 0x0 for source transfer width is 8 bits
+     * 0x1 for source transfer width is 16 bits
+     * 0x2 for source transfer width is 32 bits
+     * 0x3 for source transfer width is 64 bits
+     * 0x4 for source transfer width is 128 bits
+     * 0x5  for source transfer width is 256 bits
+     * 0x6 for source transfer width is 512 bits
+     */
+    uint64 src_tr_width : 3;
+    /**
+     * Bits [13:11] is detination transfer width
+     * 0x0 for detination transfer width is 8 bits
+     * 0x1 for detination transfer width is 16 bits
+     * 0x2 for detination transfer width is 32 bits
+     * 0x3 for detination transfer width is 64 bits
+     * 0x4 for detination transfer width is 128 bits
+     * 0x5  for detination transfer width is 256 bits
+     * 0x6 for detination transfer width is 512 bits
+     */
+    uint64 dst_tr_width : 3;
+    /**
+     * Bits [17:14] is source burst transaction length
+     * 0x0 for 1 data item read from rource in the burst transaction
+     * 0x1 for 4 data item read from rource in the burst transaction
+     * 0x2 for 8 data item read from rource in the burst transaction
+     * 0x3 for 16 data item read from rource in the burst transaction
+     * 0x4 for 32 data item read from rource in the burst transaction
+     * 0x5 for 64 data item read from rource in the burst transaction
+     * 0x6 for 128 data item read from rource in the burst transaction
+     * 0x7 for 256 data item read from rource in the burst transaction
+     * 0x8 for 512 data item read from rource in the burst transaction
+     * 0x9 for 1024 data item read from rource in the burst transaction
+     */
+    uint64 src_msize : 4;
+    /**
+     * Bits [17:14] is sdestination burst transaction length
+     * 0x0 for 1 data item read from rource in the burst transaction
+     * 0x1 for 4 data item read from rource in the burst transaction
+     * 0x2 for 8 data item read from rource in the burst transaction
+     * 0x3 for 16 data item read from rource in the burst transaction
+     * 0x4 for 32 data item read from rource in the burst transaction
+     * 0x5 for 64 data item read from rource in the burst transaction
+     * 0x6 for 128 data item read from rource in the burst transaction
+     * 0x7 for 256 data item read from rource in the burst transaction
+     * 0x8 for 512 data item read from rource in the burst transaction
+     * 0x9 for 1024 data item read from rource in the burst transaction
+     */
+    uint64 dst_msize : 4;
+    /**
+     * Bits [25:22] is reserved
+     */
+    uint64 rsvd5 : 4;
+    /*!< Bits [29:26] is reserved */
+    uint64 rsvd6 : 4;
+    /**
+     * Bit 30 is Non Posted Last Write Enable
+     * 0x1 for posted writes may be used till the end of the block
+     * 0x 0 for posted writes may be used throughout the block transfer
+     */
+    uint64 nonposted_lastwrite_en : 1;
+    /* Bit 31 is resrved */
+    uint64 rsvd7 : 1;
+    /* Bits [34:32] is reserved*/
+    uint64 rsvd8 : 3;
+    /* Bits [37:35] is reserved*/
+    uint64 rsvd9 : 3;
+    /**
+     * Bit 38 is source burst length enable
+     * 1 for enable, 0 for disable
+     */
+    uint64 arlen_en : 1;
+    /* Bits [46:39] is source burst length*/
+    uint64 arlen : 8;
+    /**
+     * Bit 47 is destination burst length enable
+     * 1 for enable, 0 for disable
+     */
+    uint64 awlen_en : 1;
+    /* Bits [55:48] is destination burst length */
+    uint64 awlen : 8;
+    /**
+     * Bit 56 is source status enable
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 src_stat_en : 1;
+    /**
+     * Bit 57 is destination status enable
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 dst_stat_en : 1;
+    /**
+     * Bit 58 is interrupt completion of block transfer
+     * 0x1 for enable CHx_IntStatusReg.BLOCK_TFR_DONE_IntStat field
+     * 0x0 for dsiable CHx_IntStatusReg.BLOCK_TFR_DONE_IntStat field
+     */
+    uint64 ioc_blktfr : 1;
+    /**
+     * Bits [61:59] is reserved
+     */
+    uint64 rsvd10 : 3;
+    /**
+     * Bit 62 is last shadow linked list item
+     * 0x1 for indicate shadowreg/LLI content is the last one
+     * 0x0 for indicate  shadowreg/LLI content not the last one
+     */
+    uint64 shadowreg_or_lli_last : 1;
+    /**
+     * Bit 63 is last shadow linked list item valid
+     * 0x1 for indicate shadowreg/LLI content is  valid
+     * 0x0 for indicate  shadowreg/LLI content is invalid
+     */
+    uint64 shadowreg_or_lli_valid : 1;
+} __attribute__((packed, aligned(8))) dmac_ch_ctl_t;
+
+typedef union _dmac_ch_ctl_u
+{
+    dmac_ch_ctl_t ch_ctl;
+    uint64 data;
+} dmac_ch_ctl_u_t;
+
+typedef struct _dmac_ch_cfg
+{
+    /**
+     * Bit[1:0] is source multi block transfer type
+     * 0x0 for continuous multiblock type
+     * 0x1 for reload multiblock type
+     * 0x2 for shadow register based multiblock type
+     * 0x3 for linked lisr bases multiblock type
+     */
+    uint64 src_multblk_type : 2;
+    /**
+     * Bit[3:2] is source multi block transfer type
+     * 0x0 for continuous multiblock type
+     * 0x1 for reload multiblock type
+     * 0x2 for shadow register based multiblock type
+     * 0x3 for linked lisr bases multiblock type
+     */
+    uint64 dst_multblk_type : 2;
+    /* Bits [31:4] is reserved*/
+    uint64 rsvd1 : 28;
+    /**
+     * Bits [34:32] is transfer type and flow control
+     * 0x0  transfer memory to memory and flow controler is dmac
+     * 0x1  transfer memory to peripheral and flow controler is dmac
+     * 0x2  transfer peripheral to memory and flow controler is dmac
+     * 0x3  transfer peripheral to peripheral and flow controler is dmac
+     * 0x4  transfer peripheral to memory and flow controler is
+     * source peripheral
+     * 0x5  transfer peripheral to peripheral and flow controler
+     * is source peripheral
+     * 0x6  transfer memory to peripheral and flow controler is
+     * destination peripheral
+     * 0x7  transfer peripheral to peripheral and flow controler
+     * is destination peripheral
+     */
+    uint64 tt_fc : 3;
+    /**
+     * Bit 35 is source software or hardware handshaking select
+     * 0x1 for software handshaking is used
+     * 0x0 for hardware handshaking is used
+     */
+    uint64 hs_sel_src : 1;
+    /**
+     * Bit 36 is destination software or hardware handshaking select
+     *0x1 for software handshaking is used
+     *0x0 for hardware handshaking is used
+     */
+    uint64 hs_sel_dst : 1;
+    /**
+     * Bit 37 is sorce hardware handshaking interface polarity
+     * 0x1 active low, 0x0 active high
+     */
+    uint64 src_hwhs_pol : 1;
+    /**
+     * Bit 38 is destination hardware handshaking interface polarity
+     * 0x1 active low, 0x0 active high
+     */
+    uint64 dst_hwhs_pol : 1;
+    /**
+     * Bits [41:39] is assign a hardware handshaking interface
+     * to source of channel x
+     */
+    uint64 src_per : 4;
+    /* Bit 43 is reserved*/
+    uint64 rsvd3 : 1;
+    /**
+     * Bits [46:44] is assign a hardware handshaking interface
+     * to destination of channel x
+     */
+    uint64 dst_per : 4;
+    /* Bit 48 is reserved*/
+    uint64 rsvd5 : 1;
+    /* Bits [51:49] is channel priority,7 is highest, 0 is lowest*/
+    uint64 ch_prior : 3;
+    /**
+     * Bit 52 is channel lock bit
+     * 0x0 for channel is not locked, 0x1 for channel is locked
+     */
+    uint64 lock_ch : 1;
+    /**
+     * Bits [54:53] is chnannel lock level
+     * 0x0 for  duration of channel is locked for entire DMA transfer
+     * 0x1 for duration of channel is locked for current block transfer
+     */
+    uint64 lock_ch_l : 2;
+    uint64 src_osr_lmt : 4;
+    /* Bits [58:55] is source outstanding request limit */
+    uint64 dst_osr_lmt : 4;
+    /* Bits [62:59] is destination outstanding request limit */
+} __attribute__((packed, aligned(8))) dmac_ch_cfg_t;
+
+typedef union _dmac_ch_cfg_u
+{
+    dmac_ch_cfg_t ch_cfg;
+    uint64 data;
+} dmac_ch_cfg_u_t;
+
+typedef struct _dmac_ch_llp
+{
+    /**
+     * Bit 0 is LLI master select
+     * 0x0 for next linked list item resides on AXI madster1 interface
+     * 0x1 for next linked list item resides on AXI madster2 interface
+     */
+    uint64 lms : 1;
+    /* Bits [5:1] is reserved */
+    uint64 rsvd1 : 5;
+    /* Bits [63:6] is starting address memeory of LLI block */
+    uint64 loc : 58;
+} __attribute__((packed, aligned(8))) dmac_ch_llp_t;
+
+typedef union _dmac_ch_llp_u
+{
+    dmac_ch_llp_t llp;
+    uint64 data;
+} dmac_ch_llp_u_t;
+
+typedef struct _dmac_ch_status
+{
+    /* Bits [21:0] is completed block transfer size */
+    uint64 cmpltd_blk_size : 22;
+    /* Bits [46:32] is reserved */
+    uint64 rsvd1 : 15;
+    /* Bits [63:47] is reserved */
+    uint64 rsvd2 : 17;
+} __attribute__((packed, aligned(8))) dmac_ch_status_t;
+
+typedef union _dmac_ch_status_u
+{
+    dmac_ch_status_t status;
+    uint64 data;
+} dmac_ch_status_u_t;
+
+typedef struct _dmac_ch_swhssrc
+{
+    /**
+     * Bit 0 is software handshake request for channel source
+     * 0x1 source periphraral request for a dma transfer
+     * 0x0 source peripheral is not request for a burst transfer
+     */
+    uint64 swhs_req_src : 1;
+    /**
+     * Bit 1 is write enable bit for software handshake request
+     *0x1 for enable, 0x0 for disable
+     */
+    uint64 swhs_req_src_we : 1;
+    /**
+     * Bit 2 is software handshake single request for channel source
+     * 0x1 for source peripheral requesr for a single dma transfer
+     *  0x0 for source peripheral is not requesting for a single transfer
+     */
+    uint64 swhs_sglreq_src : 1;
+    /**
+     * Bit 3 is write enable bit for software handshake
+     * single request for channle source
+     * 0x1 for enable write, 0x0 for disable write
+     */
+    uint64 swhs_sglreq_src_we : 1;
+    /**
+     * Bit 4 software handshake last request for channel source
+     * 0x1 for current transfer is last transfer
+     * 0x0 for current transfer is not the last transfer
+     */
+    uint64 swhs_lst_src : 1;
+    /**
+     * Bit 5 is write enable bit for software
+     * handshake last request
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 swhs_lst_src_we : 1;
+    /* Bits [63:6] is reserved */
+    uint64 rsvd : 58;
+} __attribute__((packed, aligned(8))) dmac_ch_swhssrc_t;
+
+typedef union _dmac_ch_swhssrc_u
+{
+    dmac_ch_swhssrc_t swhssrc;
+    uint64 data;
+} dmac_ch_swhssrc_u_t;
+
+typedef struct _dmac_ch_swhsdst
+{
+    /**
+     * Bit 0 is software handshake request for channel destination
+     * 0x1 destination periphraral request for a dma transfer
+     * 0x0 destination peripheral is not request for a burst transfer
+     */
+    uint64 swhs_req_dst : 1;
+    /**
+     * Bit 1 is write enable bit for software handshake request
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 swhs_req_dst_we : 1;
+    /**
+     * Bit 2 is software handshake single request for channel destination
+     * 0x1 for destination peripheral requesr for a single dma transfer
+     * 0x0 for destination peripheral is not requesting
+     * for a single transfer
+     */
+    uint64 swhs_sglreq_dst : 1;
+    /**
+     * Bit 3 is write enable bit for software handshake
+     * single request for channle destination
+     * 0x1 for enable write, 0x0 for disable write
+     */
+    uint64 swhs_sglreq_dst_we : 1;
+    /**
+     * Bit 4 software handshake last request for channel dstination
+     * 0x1 for current transfer is last transfer
+     * 0x0 for current transfer is not the last transfer
+     */
+    uint64 swhs_lst_dst : 1;
+    /**
+     * Bit 5 is write enable bit for software handshake last request
+     * 0x1 for enable, 0x0 for disable
+     */
+    uint64 swhs_lst_dst_we : 1;
+    /* Bits [63:6] is reserved */
+    uint64 rsvd : 58;
+} __attribute__((packed, aligned(8))) dmac_ch_swhsdst_t;
+
+typedef union _dmac_ch_swhsdst_u
+{
+    dmac_ch_swhsdst_t swhsdst;
+    uint64 data;
+} dmac_ch_swhsdst_u_t;
+
+typedef struct _dmac_ch_blk_tfr_resumereq
+{
+    /**
+     * Bit 0 is block transfer resume request bit
+     * 0x1 for request for resuming
+     * 0x0 for no request to resume
+     */
+    uint64 blk_tfr_resumereq : 1;
+    /* Bits [63:1] is reserved */
+    uint64 rsvd : 63;
+} __attribute__((packed, aligned(8))) dmac_ch_blk_tfr_resumereq_t;
+
+typedef union _dmac_ch_blk_tfr_resumereq_u
+{
+    dmac_ch_blk_tfr_resumereq_t blk_tfr_resumereq;
+    uint64 data;
+} dmac_ch_blk_tfr_resumereq_u_t;
+
+typedef struct _dmac_ch_intstatus_enable
+{
+    /* Bit 0 is block transfer done interrupt status enable */
+    uint64 enable_block_tfr_done_intstatus : 1;
+    /* DMA transfer done interrupt status enable */
+    uint64 enable_dma_tfr_done_intstat : 1;
+    /* Bit 2 reserved */
+    uint64 rsvd1 : 1;
+    /* Bit 3 source transaction complete status enable */
+    uint64 enable_src_transcomp_intstat : 1;
+    /* Bit 4 destination transaction complete */
+    uint64 enable_dst_transcomp_intstat : 1;
+    /* Bit 5 Source Decode Error Status Enable */
+    uint64 enable_src_dec_err_intstat : 1;
+    /* Bit 6 Destination Decode Error Status Enable */
+    uint64 enable_dst_dec_err_intstat : 1;
+    /* Bit 7 Source Slave Error Status Enable */
+    uint64 enable_src_slv_err_intstat : 1;
+    /* Bit 8 Destination Slave Error Status Enable */
+    uint64 enable_dst_slv_err_intstat : 1;
+    /* Bit 9 LLI Read Decode Error Status Enable */
+    uint64 enable_lli_rd_dec_err_intstat : 1;
+    /* Bit 10 LLI WRITE Decode Error Status Enable */
+    uint64 enable_lli_wr_dec_err_intstat : 1;
+    /* Bit 11 LLI Read Slave Error Status Enable */
+    uint64 enable_lli_rd_slv_err_intstat : 1;
+    /* Bit 12 LLI WRITE Slave Error Status Enable */
+    uint64 enable_lli_wr_slv_err_intstat : 1;
+    uint64 rsvd2 : 51;
+} dmac_ch_intstatus_enable_t;
+
+typedef union _dmac_ch_intstatus_enable_u
+{
+    dmac_ch_intstatus_enable_t ch_intstatus_enable;
+    uint64 data;
+} dmac_ch_intstatus_enable_u_t;
+
+typedef struct _dmac_ch_intclear
+{
+    /* Bit 0 block transfer done interrupt clear bit.*/
+    uint64 blk_tfr_done_intstat : 1;
+    /* Bit 1 DMA transfer done interrupt clear bit */
+    uint64 dma_tfr_done_intstat : 1;
+    /* Bit 2 is reserved */
+    uint64 resv1 : 1;
+    uint64 resv2 : 61;
+} __attribute__((packed, aligned(8))) dmac_ch_intclear_t;
+
+typedef union _dmac_ch_intclear_u
+{
+    uint64 data;
+    dmac_ch_intclear_t intclear;
+} dmac_ch_intclear_u_t;
+
+typedef struct _dmac_channel
+{
+    /* (0x100) SAR Address Register */
+    uint64 sar;
+    /* (0x108) DAR Address Register */
+    uint64 dar;
+    /* (0x110) Block Transfer Size Register */
+    uint64 block_ts;
+    /* (0x118) Control Register */
+    uint64 ctl;
+    /* (0x120) Configure Register */
+    uint64 cfg;
+    /* (0x128) Linked List Pointer register */
+    uint64 llp;
+    /* (0x130) Channelx Status Register */
+    uint64 status;
+    /* (0x138) Channelx Software handshake Source Register */
+    uint64 swhssrc;
+    /* (0x140) Channelx Software handshake Destination Register */
+    uint64 swhsdst;
+    /* (0x148) Channelx Block Transfer Resume Request Register */
+    uint64 blk_tfr;
+    /* (0x150) Channelx AXI ID Register */
+    uint64 axi_id;
+    /* (0x158) Channelx AXI QOS Register */
+    uint64 axi_qos;
+    /* Reserved address */
+    uint64 reserved1[4];
+    /* (0x180) Interrupt Status Enable Register */
+    uint64 intstatus_en;
+    /* (0x188) Channelx Interrupt Status Register */
+    uint64 intstatus;
+    /* (0x190) Interrupt  Siganl Enable Register */
+    uint64 intsignal_en;
+    /* (0x198) Interrupt Clear Register */
+    uint64 intclear;
+    uint64 reserved2[12];
+} __attribute__((packed, aligned(8))) dmac_channel_t;
+
+typedef struct _dmac
+{
+    /* (0x00) DMAC ID Rgister */
+    uint64 id;
+    /* (0x08) DMAC COMPVER Register */
+    uint64 compver;
+    /* (0x10) DMAC Configure Register */
+    uint64 cfg;
+    /* (0x18) Channel Enable Register */
+    uint64 chen;
+    uint64 reserved1[2];
+    /* (0x30) DMAC Interrupt Status Register */
+    uint64 intstatus;
+    /* (0x38) DMAC Common register Interrupt Status Register */
+    uint64 com_intclear;
+    /* (0x40) DMAC Common Interrupt Enable Register */
+    uint64 com_intstatus_en;
+    /* (0x48) DMAC Common Interrupt Signal Enable Register */
+    uint64 com_intsignal_en;
+    /* (0x50) DMAC Common Interrupt Status */
+    uint64 com_intstatus;
+    /* (0x58) DMAC Reset register */
+    uint64 reset;
+    uint64 reserved2[20];
+    dmac_channel_t channel[DMAC_CHANNEL_COUNT];
+} __attribute__((packed, aligned(8))) dmac_t;
+
+typedef struct _dmac_channel_config
+{
+    uint64 sar;
+    uint64 dar;
+    uint8 ctl_sms;
+    uint8 ctl_dms;
+    uint8 ctl_src_msize;
+    uint8 ctl_drc_msize;
+    uint8 ctl_sinc;
+    uint8 ctl_dinc;
+    uint8 ctl_src_tr_width;
+    uint8 ctl_dst_tr_width;
+    uint8 ctl_ioc_blktfr;
+    uint8 ctl_src_stat_en;
+    uint8 ctl_dst_stat_en;
+    uint8 cfg_dst_per;
+    uint8 cfg_src_per;
+    uint8 cfg_src_hs_pol;
+    uint8 cfg_dst_hs_pol;
+    uint8 cfg_hs_sel_src;
+    uint8 cfg_hs_sel_dst;
+    uint64 cfg_src_multblk_type;
+    uint64 cfg_dst_multblk_type;
+    uint64 llp_loc;
+    uint8 llp_lms;
+    uint64 ctl_block_ts;
+    uint8 ctl_tt_fc;
+    uint8 cfg_protctl;
+    uint8 cfg_fifo_mode;
+    uint8 cfg_fcmode;
+    uint8 cfg_lock_ch_l;
+    uint8 cfg_ch_prior;
+} dmac_channel_config_t;
+
+#define LIST_ENTRY(ptr, type, member) \
+    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
+
+struct list_head_t
+{
+    struct list_head_t *next, *prev;
+};
+
+/**
+ * @brief       Dmac.data/dw_dmac_lli_item
+ *
+ * @desc        This structure is used when creating Linked List Items.
+ *
+ * @see         dw_dmac_addLliItem()
+ */
+typedef struct _dmac_lli_item
+{
+    uint64 sar;
+    uint64 dar;
+    uint64 ch_block_ts;
+    uint64 llp;
+    uint64 ctl;
+    uint64 sstat;
+    uint64 dstat;
+    uint64 resv;
+} __attribute__((packed, aligned(64))) dmac_lli_item_t;
+
+extern volatile dmac_t *const dmac;
+
+/**
+ * @brief       Dmac initialize
+ */
+void dmac_init(void);
+
+/**
+ * @brief       Set dmac param
+ *
+ * @param[in]   channel_num             Dmac channel
+ * @param[in]   src                     Dmac source
+ * @param[in]   dest                    Dmac dest
+ * @param[in]   src_inc                 Source address increase or not
+ * @param[in]   dest_inc                Dest address increase or not
+ * @param[in]   dmac_burst_size         Dmac burst length
+ * @param[in]   dmac_trans_width        Dmac transfer data width
+ * @param[in]   block_size               Dmac transfer length
+ *
+ */
+void dmac_set_single_mode(dmac_channel_number_t channel_num,
+                          const void *src, void *dest, dmac_address_increment_t src_inc,
+                          dmac_address_increment_t dest_inc,
+                          dmac_burst_trans_length_t dmac_burst_size,
+                          dmac_transfer_width_t dmac_trans_width,
+                          uint64 block_size);
+
+/**
+ * @brief       Determine the transfer is complete or not
+ *
+ * @param[in]   channel_num             Dmac channel
+ *
+ * @return      result
+ *     - 0      uncompleted
+ *     - 1  completed
+*/
+int dmac_is_done(dmac_channel_number_t channel_num);
+
+/**
+ * @brief       Wait for dmac work done
+ *
+ * @param[in]   channel_num  Dmac channel
+ *
+ */
+void dmac_wait_done(dmac_channel_number_t channel_num);
+
+/**
+ * @brief       Determine the dma is idle or not
+ *
+ * @param[in]   channel_num             Dmac channel
+ *
+ * @return      result
+ *     - 0      busy
+ *     - 1      idel
+*/
+int dmac_is_idle(dmac_channel_number_t channel_num);
+
+/**
+ * @brief       Wait for dmac idle
+ *
+ * @param[in]   channel_num  Dmac channel
+ *
+ */
+void dmac_wait_idle(dmac_channel_number_t channel_num);
+
+/**
+ * @brief       Set interrupt param
+ *
+ * @param[in]   channel_num             Dmac channel
+ * @param[in]   dmac_callback           Dmac interrupt callback
+ * @param[in]   ctx                     The param of callback
+ * @param[in]   priority                Interrupt priority
+ */
+//void dmac_set_irq(dmac_channel_number_t channel_num, plic_irq_callback_t dmac_callback, void *ctx, uint32 priority);
+
+/**
+ * @brief       Set interrupt param
+ *
+ * @param[in]   channel_num             Dmac channel
+ * @param[in]   dmac_callback           Dmac interrupt callback
+ * @param[in]   ctx                     The param of callback
+ * @param[in]   priority                Interrupt priority
+ */
+//void dmac_irq_register(dmac_channel_number_t channel_num, plic_irq_callback_t dmac_callback, void *ctx, uint32 priority);
+
+/**
+ * @brief       Unregister dmac interrupt
+ *
+ * @param[in]   channel_num             Dmac channel
+ *
+ */
+void dmac_irq_unregister(dmac_channel_number_t channel_num);
+
+/**
+ * @brief       Disable dmac interrupt
+ *
+ * @param[in]   channel_num             Dmac channel
+ *
+ */
+void dmac_free_irq(dmac_channel_number_t channel_num);
+
+/**
+ * @brief       Set source dest and length
+ *
+ * @param[in]   channel_num             Dmac channel
+ * @param[in]   src                     Source
+ * @param[in]   dest                    Dest
+ * @param[in]   len                     The length of dmac transfer
+ */
+void dmac_set_src_dest_length(dmac_channel_number_t channel_num, const void *src, void *dest, uint64 len);
+
+/**
+ * @brief       Disable dmac channel interrupt
+ *
+ * @param[in]   channel_num             Dmac channel
+ *
+*/
+void dmac_disable_channel_interrupt(dmac_channel_number_t channel_num);
+
+/**
+ * @brief       Disable dmac channel
+ *
+ * @param[in]   channel_num             Dmac channel
+ *
+*/
+void dmac_channel_disable(dmac_channel_number_t channel_num);
+
+/**
+ * @brief       Enable dmac channel
+ *
+ * @param[in]   channel_num             Dmac channel
+ *
+*/
+void dmac_channel_enable(dmac_channel_number_t channel_num);
+
+void dmac_intr(dmac_channel_number_t channel_num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_DMAC_H */
diff --git a/kernel/include/elf.h b/kernel/include/elf.h
new file mode 100644
index 0000000000000000000000000000000000000000..81a1ae0de55c0572d72f0d8d384ad537d1f9406e
--- /dev/null
+++ b/kernel/include/elf.h
@@ -0,0 +1,85 @@
+#ifndef __ELF_H
+#define __ELF_H
+#include "param.h"
+
+// Format of an ELF executable file
+
+#define ELF_MAGIC 0x464C457FU  // "\x7FELF" in little endian
+
+// File header
+struct elfhdr {
+  uint magic;  // must equal ELF_MAGIC
+  uchar elf[12];
+  ushort type;
+  ushort machine;
+  uint version;
+  uint64 entry;
+  uint64 phoff;
+  uint64 shoff;
+  uint flags;
+  ushort ehsize;
+  ushort phentsize;
+  ushort phnum;
+  ushort shentsize;
+  ushort shnum;
+  ushort shstrndx;
+};
+
+// Program section header
+struct proghdr {
+  uint32 type;
+  uint32 flags;
+  uint64 off;
+  uint64 vaddr;
+  uint64 paddr;
+  uint64 filesz;
+  uint64 memsz;
+  uint64 align;
+};
+
+#define ET_NONE   0
+#define ET_REL    1
+#define ET_EXEC   2
+#define ET_DYN    3
+#define ET_CORE   4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+// Values for Proghdr type
+#define PT_NULL    0
+#define PT_LOAD    1
+#define PT_DYNAMIC 2
+#define PT_INTERP  3
+#define PT_NOTE    4
+#define PT_SHLIB   5
+#define PT_PHDR    6
+#define PT_TLS     7    
+
+#define PATH_MAX        4096
+
+// Flag bits for Proghdr flags
+#define ELF_PROG_FLAG_EXEC      1
+#define ELF_PROG_FLAG_WRITE     2
+#define ELF_PROG_FLAG_READ      4
+
+#endif
+
+#define PGDIR_SHIFT_L3  30
+#define __AC(X,Y)	(X##Y)
+#define _AC(X,Y)	__AC(X,Y)
+#define PTRS_PER_PGD		1024
+#define PGDIR_SHIFT     PGDIR_SHIFT_L3
+#define PGDIR_SIZE      (_AC(1, UL) << PGDIR_SHIFT)
+#define TASK_SIZE      MAXVA
+#define ELF_ET_DYN_BASE		((TASK_SIZE / 3) * 2)
+
+struct binprm{
+	char buf[BINPRM_BUF_SIZE];
+	char** argv,** argp;
+	unsigned long p;              /* current top of mem */
+	struct dirent * file;
+	int e_uid, e_gid;
+	int argvn, argpn;
+	char * filename;	            /* Name of binary */
+	unsigned long loader, exec;
+};
\ No newline at end of file
diff --git a/kernel/include/errno.h b/kernel/include/errno.h
new file mode 100644
index 0000000000000000000000000000000000000000..fdbf4e92fb0ad2a293a29a8c139a36077a45f8e6
--- /dev/null
+++ b/kernel/include/errno.h
@@ -0,0 +1,139 @@
+#ifndef __ERRNO_H
+#define __ERRNO_H
+
+#define EPERM            1
+#define ENOENT           2
+#define ESRCH            3
+#define EINTR            4
+#define EIO              5
+#define ENXIO            6
+#define E2BIG            7
+#define ENOEXEC          8
+#define EBADF            9
+#define ECHILD          10
+#define EAGAIN          11
+#define ENOMEM          12
+#define EACCES          13
+#define EFAULT          14
+#define ENOTBLK         15
+#define EBUSY           16
+#define EEXIST          17
+#define EXDEV           18
+#define ENODEV          19
+#define ENOTDIR         20
+#define EISDIR          21
+#define EINVAL          22
+#define ENFILE          23
+#define EMFILE          24
+#define ENOTTY          25
+#define ETXTBSY         26
+#define EFBIG           27
+#define ENOSPC          28
+#define ESPIPE          29
+#define EROFS           30
+#define EMLINK          31
+#define EPIPE           32
+#define EDOM            33
+#define ERANGE          34
+#define EDEADLK         35
+#define ENAMETOOLONG    36
+#define ENOLCK          37
+#define ENOSYS          38
+#define ENOTEMPTY       39
+#define ELOOP           40
+#define EWOULDBLOCK     EAGAIN
+#define ENOMSG          42
+#define EIDRM           43
+#define ECHRNG          44
+#define EL2NSYNC        45
+#define EL3HLT          46
+#define EL3RST          47
+#define ELNRNG          48
+#define EUNATCH         49
+#define ENOCSI          50
+#define EL2HLT          51
+#define EBADE           52
+#define EBADR           53
+#define EXFULL          54
+#define ENOANO          55
+#define EBADRQC         56
+#define EBADSLT         57
+#define EDEADLOCK       EDEADLK
+#define EBFONT          59
+#define ENOSTR          60
+#define ENODATA         61
+#define ETIME           62
+#define ENOSR           63
+#define ENONET          64
+#define ENOPKG          65
+#define EREMOTE         66
+#define ENOLINK         67
+#define EADV            68
+#define ESRMNT          69
+#define ECOMM           70
+#define EPROTO          71
+#define EMULTIHOP       72
+#define EDOTDOT         73
+#define EBADMSG         74
+#define EOVERFLOW       75
+#define ENOTUNIQ        76
+#define EBADFD          77
+#define EREMCHG         78
+#define ELIBACC         79
+#define ELIBBAD         80
+#define ELIBSCN         81
+#define ELIBMAX         82
+#define ELIBEXEC        83
+#define EILSEQ          84
+#define ERESTART        85
+#define ESTRPIPE        86
+#define EUSERS          87
+#define ENOTSOCK        88
+#define EDESTADDRREQ    89
+#define EMSGSIZE        90
+#define EPROTOTYPE      91
+#define ENOPROTOOPT     92
+#define EPROTONOSUPPORT 93
+#define ESOCKTNOSUPPORT 94
+#define EOPNOTSUPP      95
+#define ENOTSUP         EOPNOTSUPP
+#define EPFNOSUPPORT    96
+#define EAFNOSUPPORT    97
+#define EADDRINUSE      98
+#define EADDRNOTAVAIL   99
+#define ENETDOWN        100
+#define ENETUNREACH     101
+#define ENETRESET       102
+#define ECONNABORTED    103
+#define ECONNRESET      104
+#define ENOBUFS         105
+#define EISCONN         106
+#define ENOTCONN        107
+#define ESHUTDOWN       108
+#define ETOOMANYREFS    109
+#define ETIMEDOUT       110
+#define ECONNREFUSED    111
+#define EHOSTDOWN       112
+#define EHOSTUNREACH    113
+#define EALREADY        114
+#define EINPROGRESS     115
+#define ESTALE          116
+#define EUCLEAN         117
+#define ENOTNAM         118
+#define ENAVAIL         119
+#define EISNAM          120
+#define EREMOTEIO       121
+#define EDQUOT          122
+#define ENOMEDIUM       123
+#define EMEDIUMTYPE     124
+#define ECANCELED       125
+#define ENOKEY          126
+#define EKEYEXPIRED     127
+#define EKEYREVOKED     128
+#define EKEYREJECTED    129
+#define EOWNERDEAD      130
+#define ENOTRECOVERABLE 131
+#define ERFKILL         132
+#define EHWPOISON       133
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/fat32.h b/kernel/include/fat32.h
new file mode 100644
index 0000000000000000000000000000000000000000..524f52b7846df588510cb93d371bb7b4a22371e3
--- /dev/null
+++ b/kernel/include/fat32.h
@@ -0,0 +1,256 @@
+#ifndef __FAT32_H
+#define __FAT32_H
+
+#include "sleeplock.h"
+#include "stat.h"
+#include "file.h"
+
+#define ATTR_READ_ONLY      0x01  // 只读
+#define ATTR_HIDDEN         0x02  // 隐藏
+#define ATTR_SYSTEM         0x04  // 系统
+#define ATTR_VOLUME_ID      0x08  // 卷标
+#define ATTR_DIRECTORY      0x10  // 目录
+#define ATTR_ARCHIVE        0x20  // 文档
+#define ATTR_LONG_NAME      0x0F  // 长名
+#define ATTR_LINK           0x40  // link
+
+#define LAST_LONG_ENTRY     0x40  // 最后一个长文件名目录
+#define FAT32_EOC           0x0ffffff8  // 
+#define EMPTY_ENTRY         0xe5
+#define END_OF_ENTRY        0x00
+#define CHAR_LONG_NAME      13
+#define CHAR_SHORT_NAME     11
+
+#define FAT32_MAX_FILENAME  255
+#define FAT32_MAX_PATH      260
+#define ENTRY_CACHE_NUM     1024
+
+/* fields that start with "_" are something we don't use */
+
+// 短文件名(32字节)
+// 对于已经分配使用的目录项,
+// 它的第一个字节是文件名的第一个字符,
+// 而文件或目录被删除后,它所对应的目录项的第一个字节将被置为0xE5
+typedef struct short_name_entry {
+
+    // 文件名.扩展名(8+3)
+    // 如果文件名不足8个则用0x20进行填充
+    // 如果是子目录,则将扩展名部分用“0x20”进行填充
+    char        name[CHAR_SHORT_NAME]; 
+
+    // 属性 
+    // 0 读写 1 只读 2 隐藏 4 系统 8 卷标 16 子目录 32 归档 64 link
+    uint8       attr;
+
+    // 保留
+    // 0 默认 0x00 文件名全大写 0x08 文件名全小写 0x10 扩展名全大写
+    // 0x00 扩展名全小写 0x18 文件名全小写,扩展名全大写 
+    uint8       _nt_res;
+
+    // 创建时间的10ms位
+    // 精确到0.1秒
+    uint8       _crt_time_tenth; 
+
+    // 文件创建时间
+    // 0~4b为秒,以2秒为单位,有效值为0~29,可以表示的时刻为0~58
+    // 5~10b为分,有效值为0~59
+    // 11~15b为时,有效值为0~23
+    uint16      _crt_time;
+
+    // 文件创建日期
+    // 0~4bit 为日,有效值为1~31
+    // 5~8bit 为月,有效值为1~12
+    // 9~15bit 为年,有效值为0~127,这是一个相对于1980年的年数值
+    uint16      _crt_date;
+
+    uint16      _lst_acce_date; // 文件最后访问日期
+    uint16      fst_clus_hi;  // 文件起始簇号的高16位
+    uint16      _lst_wrt_time;  // 文件最近修改的时间
+    uint16      _lst_wrt_date; // 文件最近修改的日期
+    uint16      fst_clus_lo;  // 文件起始簇号的低16位
+    uint32      file_size;  // 文件的大小
+} __attribute__((packed, aligned(4))) short_name_entry_t;
+
+// 长文件名(32字节)
+typedef struct long_name_entry {
+
+    // 长文件名目录项的序列号,一个文件的第一个目录项序列号为 1,
+    // 然后依次递增。
+    // 如果是该文件的最后一个长文件名目录项,
+    // 则将该目录项的序号与0x40进行“或(OR)运算”的结果写入该位置。
+    // 如果该长文件名目录项对应的文件或子目录被删除,
+    // 则将该字节设置成删除标志0xE5。
+    uint8       order; 
+
+    // 长文件名unicode码1
+    // 长文件名的第 1~5 个字符。长文件名使用Unicode码,
+    // 每个字符需要两个字节的空间。
+    // 如果文件名结束但还有未使用的字节,
+    // 则会在文件名后先填充两个字节的“00”,然后开始使用0xFF填充。
+    wchar       name1[5]; 
+
+    // 长目录项的属性标志,一定是0x0F。
+    uint8       attr; 
+
+    // 系统保留
+    uint8       _type; 
+
+    // 校验和
+    // 如果一个文件的长文件名需要几个长文件名目录项进行存储,
+    // 则这些长文件名目录项具有相同的校验和。
+    uint8       checksum; 
+
+    // 长文件名unicode码2
+    // 文件名的第6~11个字符,未使用的字节用0xFF填充。
+    wchar       name2[6];
+
+    uint16      _fst_clus_lo; // 文件起始簇号 保留 目前常置0
+
+    // 长文件名unicode码3
+    // 文件名的第 12~13 个字符,未使用的字节用0xFF填充。
+    wchar       name3[2]; 
+} __attribute__((packed, aligned(4))) long_name_entry_t;
+
+// 目录项
+union dentry {
+    short_name_entry_t  sne;
+    long_name_entry_t   lne;
+};
+
+struct link{
+    union dentry de;
+    uint32 link_count;
+};
+#define  MAX_FILENAMX 16
+/*stsatfs*/
+struct statvfs
+  {
+    
+#ifndef __USE_FILE_OFFSET64
+    
+    unsigned long int f_frsize;
+    unsigned long int  f_bsize;
+    unsigned long f_blocks;
+    unsigned long f_bfree;
+    unsigned long  f_bavail;
+    unsigned long f_files;
+    unsigned long f_ffree;
+    unsigned long f_favail;   
+    unsigned long int f_namemax;
+#else
+    __fsblkcnt64_t f_blocks;
+    __fsblkcnt64_t f_bfree;
+    __fsblkcnt64_t f_bavail;
+    __fsfilcnt64_t f_files;
+    __fsfilcnt64_t f_ffree;
+    __fsfilcnt64_t f_favail;
+#endif
+    unsigned long int f_fsid;
+#ifdef _STATVFSBUF_F_UNUSED
+    int __f_unused;
+#endif
+    unsigned long int f_flag;
+    int __f_spare[6];
+  };
+// 文件/目录在内存中的简单投影
+struct dirent {
+    char  filename[FAT32_MAX_FILENAME + 1];  // 文件名
+    uint8   attribute;  // 属性
+
+    // uint8   create_time_tenth;
+    // uint16  create_time;
+    // uint16  create_date;
+    
+    uint32  first_clus;  // 起始簇号
+
+    // uint16  last_write_time;
+    
+    uint32  file_size;  // 文件大小
+
+    uint32  cur_clus;  // 当前簇号
+    uint    clus_cnt;  // 当前簇是该文件的第几个簇
+
+    /* for OS */
+    uint8   dev;   // 设备号
+    uint8   dirty;  // 浊/清
+    short   valid;  // 合法性
+    int     ref;  // 关联数
+    uint32  off;      // 父目录的entry的偏移      // offset in the parent dir entry, for writing convenience
+    struct dirent *parent;  // because FAT32 doesn't have such thing like inum, use this for cache trick
+    struct dirent *next;  // 
+    struct dirent *prev;  // 
+    struct sleeplock    lock;  
+    uint8  mount_flag; 
+    long long  last_access_date; 
+    long long  last_write_date;
+};
+
+//被挂载的文件系统的抽象结构体
+struct fstype
+{
+    
+    uint32  first_data_sec; // data所在的第一个扇区
+    uint32  data_sec_cnt; // 数据扇区数
+    uint32  data_clus_cnt; // 数据簇数
+    uint32  byts_per_clus; // 每簇字节数
+
+    struct { 
+        uint16  byts_per_sec;  // 扇区字节数
+        uint8   sec_per_clus;  // 每簇扇区数
+        uint16  rsvd_sec_cnt;  // 保留扇区数
+        uint8   fat_cnt;  // fatæ•°          
+        uint32  hidd_sec;  // 隐藏扇区数         
+        uint32  tot_sec;  // 总扇区数          
+        uint32  fat_sz;   // 一个fat所占扇区数           
+        uint32  root_clus; // 根目录簇号 
+    } bpb; 
+
+    int vaild;
+    struct dirent root; //这个文件系统的根目录文件
+    uint8   mount_mode;//是否被挂载的标志
+};
+#define BITSOFFDSET 1024
+#define NUMFDSET    (BITSOFFDSET/(sizeof(uint64)*8))
+struct fd_set
+{
+    uint64 fds_bits[NUMFDSET];
+};
+
+int             fat32_init(void);
+struct dirent*  dirlookup(struct dirent *entry, char *filename, uint *poff);
+char*           formatname(char *name);
+void            emake(struct dirent *dp, struct dirent *ep, uint off);
+struct dirent*  ealloc(struct dirent *dp, char *name, int attr);
+struct dirent*  edup(struct dirent *entry);
+void            eupdate(struct dirent *entry);
+void            etrunc(struct dirent *entry);
+void            eremove(struct dirent *entry);
+void            eput(struct dirent *entry);
+void            estat(struct dirent *ep, struct stat *st);
+void            elock(struct dirent *entry);
+void            eunlock(struct dirent *entry);
+int             enext(struct dirent *dp, struct dirent *ep, uint off, int *count);
+struct dirent*  ename(char *path);
+struct dirent*  enameparent(char *path, char *name);
+int             eread(struct dirent *entry, int user_dst, uint64 dst, uint off, uint n);
+int             ewrite(struct dirent *entry, int user_src, uint64 src, uint off, uint n);
+struct dirent*  enameparent2(char *path, char *name, struct file *f);
+struct dirent*  ename2(char *path, struct file *f);
+// int             filewrite2(struct file *f, uint64 addr, int n);
+uint32          get_byts_per_clus();
+int             link(char* oldpath, struct file *f1, char* newpath, struct file *f2);
+int             unlink(char *path, struct file *f);
+int             remove(char *path);
+int             isdirempty(struct dirent *dp);
+int             remove2(char *path, struct file *f);
+int             syn_disk(uint64 start,long len);
+int             do_mount(struct dirent*mountpoint,struct dirent*dev);
+int             do_umount(struct dirent*mountpoint);
+void            dirtreeinit();
+struct dirent*  create(char *path, short type, int mode);
+struct dirent*  create2(char *path, short type, int mode, struct file *f);
+int             get_major(char *path);
+int             do_statfs(struct statvfs* stat,struct dirent*dp);
+void            getdstat(struct dirent *de, struct dstat *st);
+int              namepath(struct dirent*dp,char*path,int len);
+#endif
diff --git a/kernel/include/fcntl.h b/kernel/include/fcntl.h
new file mode 100644
index 0000000000000000000000000000000000000000..0197681997fbed131df07d0957be44825f7321fc
--- /dev/null
+++ b/kernel/include/fcntl.h
@@ -0,0 +1,25 @@
+#ifndef __FCNTL_H
+#define __FCNTL_H
+
+
+#define O_RDONLY    0x000    // 只读
+#define O_WRONLY    0x001    // 只写
+#define O_RDWR      0x002    // 读写
+#define O_CREATE    0x040    // 文件若不存在则新建
+#define O_TRUNC     0x200    // 当以只读或读写方式打开时,则将文件长度截断为0
+#define O_APPEND    0x400    //追加
+#define O_DIRECTORY 0x010000 // 如果参数path所指的文件并非目录, 则打开文件失败
+#define O_CLOEXEC   0x80000  // 当调用exec()函数成功后,文件描述符会自动关闭。
+
+#define AT_FDCWD        -100
+#define AT_REMOVEDIR    0x200
+
+#define FD_CLOEXEC  1
+#define F_DUPFD  0
+#define F_GETFD  1
+#define F_SETFD  2
+#define F_GETFL  3
+#define F_SETFL  4
+#define F_DUPFD_CLOEXEC 1030
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/file.h b/kernel/include/file.h
new file mode 100644
index 0000000000000000000000000000000000000000..8ce968afddec238edbf8e84fbd5acb9b8ebca58c
--- /dev/null
+++ b/kernel/include/file.h
@@ -0,0 +1,78 @@
+#ifndef __FILE_H
+#define __FILE_H
+
+#define AT_SYMLINK_NOFOLLOW	0x100   /* Do not follow symbolic links.  */
+#define AT_EMPTY_PATH		0x1000	/* Allow empty relative pathname */
+#define LOOKUP_FOLLOW		0x0001	/* follow links at the end */
+#define LOOKUP_EMPTY		0x4000	/* accept empty path [user_... only] */
+#define UTIME_NOW	((1l << 30) - 1l)
+#define UTIME_OMIT	((1l << 30) - 2l)
+
+struct file {
+  enum { FD_NONE, FD_PIPE, FD_ENTRY, FD_DEVICE } type;
+  int ref; // reference count  // 引用数
+  char readable;  // 可读?
+  char writable;  // 可写?
+  struct pipe *pipe; // FD_PIPE // 管道
+  struct dirent *ep;  
+  uint64 off;          // FD_ENTRY // 目录项偏移
+  short major;       // FD_DEVICE // 设备
+  int map_pid;
+  struct spinlock	lock;
+};
+
+// #define major(dev)  ((dev) >> 16 & 0xFFFF)
+// #define minor(dev)  ((dev) & 0xFFFF)
+// #define	mkdev(m,n)  ((uint)((m)<<16| (n)))
+
+// map major device number to device functions.
+struct devsw {
+  int (*read)(int, uint64, int);  // 函数指针,指向一个读函数
+  int (*write)(int, uint64, int);  // 函数指针,指向一个写函数
+};
+
+
+struct mapped_file{
+  uint64 baseaddr;
+  unsigned long len;
+  struct file  *mfile;
+  int valid;
+  long off;
+};
+
+extern struct devsw devsw[];
+
+#define CONSOLE 1
+#define NULL_DEV 4
+#define ZERO_DEV 5
+#define RTC_DEV  6
+#define MAPPED_DEV_NUM 6
+
+
+#define MAP_FILE 0
+#define MAP_SHARED 0x01
+#define MAP_PRIVATE 0x02
+#define MAP_ANONYMOUS 0x20
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+struct file*    filealloc(void);
+void            fileclose(struct file*);
+
+struct file*    filedup(struct file*);
+
+void            fileinit(void);
+int             fileread(struct file*, uint64, int n);
+int             fileread2(struct file*, uint64, int n);
+int             filestat(struct file*, uint64 addr);
+int             filewrite(struct file*, uint64, int n);
+int             filewrite2(struct file*, uint64, int n);
+int             dirnext(struct file *f, uint64 addr);
+int             do_utimes_fd(int fd, struct timespec64 *times, int flags);
+int             do_utimes_path(int dfd,  char  *filename,	struct timespec64 *times, int flags);
+int             dirnext2(struct file *f, uint64 buf, uint64 len);
+int             filereadv(struct file *f, struct iovec* ioarr, int count);
+int             filewritev(struct file *f, struct iovec *ioarr, int count);
+#endif
\ No newline at end of file
diff --git a/kernel/include/fpioa.h b/kernel/include/fpioa.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c8fd5570ac0b5ebffee4654d824061da1477513
--- /dev/null
+++ b/kernel/include/fpioa.h
@@ -0,0 +1,1036 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file
+ * @brief      Field Programmable GPIO Array (FPIOA)
+ *
+ *             The FPIOA peripheral supports the following features:
+ *
+ *             - 48 IO with 256 functions
+ *
+ *             - Schmitt trigger
+ *
+ *             - Invert input and output
+ *
+ *             - Pull up and pull down
+ *
+ *             - Driving selector
+ *
+ *             - Static input and output
+ *
+ */
+
+#ifndef _DRIVER_FPIOA_H
+#define _DRIVER_FPIOA_H
+
+// #include <stdint.h>
+// #include "platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clang-format off */
+/* Pad number settings */
+#define FPIOA_NUM_IO    (48)
+/* clang-format on */
+
+/**
+ * @brief      FPIOA IO functions
+ *
+ * @note       FPIOA pin function table
+ *
+ * | Function  | Name             | Description                       |
+ * |-----------|------------------|-----------------------------------|
+ * | 0         | JTAG_TCLK        | JTAG Test Clock                   |
+ * | 1         | JTAG_TDI         | JTAG Test Data In                 |
+ * | 2         | JTAG_TMS         | JTAG Test Mode Select             |
+ * | 3         | JTAG_TDO         | JTAG Test Data Out                |
+ * | 4         | SPI0_D0          | SPI0 Data 0                       |
+ * | 5         | SPI0_D1          | SPI0 Data 1                       |
+ * | 6         | SPI0_D2          | SPI0 Data 2                       |
+ * | 7         | SPI0_D3          | SPI0 Data 3                       |
+ * | 8         | SPI0_D4          | SPI0 Data 4                       |
+ * | 9         | SPI0_D5          | SPI0 Data 5                       |
+ * | 10        | SPI0_D6          | SPI0 Data 6                       |
+ * | 11        | SPI0_D7          | SPI0 Data 7                       |
+ * | 12        | SPI0_SS0         | SPI0 Chip Select 0                |
+ * | 13        | SPI0_SS1         | SPI0 Chip Select 1                |
+ * | 14        | SPI0_SS2         | SPI0 Chip Select 2                |
+ * | 15        | SPI0_SS3         | SPI0 Chip Select 3                |
+ * | 16        | SPI0_ARB         | SPI0 Arbitration                  |
+ * | 17        | SPI0_SCLK        | SPI0 Serial Clock                 |
+ * | 18        | UARTHS_RX        | UART High speed Receiver          |
+ * | 19        | UARTHS_TX        | UART High speed Transmitter       |
+ * | 20        | RESV6            | Reserved function                 |
+ * | 21        | RESV7            | Reserved function                 |
+ * | 22        | CLK_SPI1         | Clock SPI1                        |
+ * | 23        | CLK_I2C1         | Clock I2C1                        |
+ * | 24        | GPIOHS0          | GPIO High speed 0                 |
+ * | 25        | GPIOHS1          | GPIO High speed 1                 |
+ * | 26        | GPIOHS2          | GPIO High speed 2                 |
+ * | 27        | GPIOHS3          | GPIO High speed 3                 |
+ * | 28        | GPIOHS4          | GPIO High speed 4                 |
+ * | 29        | GPIOHS5          | GPIO High speed 5                 |
+ * | 30        | GPIOHS6          | GPIO High speed 6                 |
+ * | 31        | GPIOHS7          | GPIO High speed 7                 |
+ * | 32        | GPIOHS8          | GPIO High speed 8                 |
+ * | 33        | GPIOHS9          | GPIO High speed 9                 |
+ * | 34        | GPIOHS10         | GPIO High speed 10                |
+ * | 35        | GPIOHS11         | GPIO High speed 11                |
+ * | 36        | GPIOHS12         | GPIO High speed 12                |
+ * | 37        | GPIOHS13         | GPIO High speed 13                |
+ * | 38        | GPIOHS14         | GPIO High speed 14                |
+ * | 39        | GPIOHS15         | GPIO High speed 15                |
+ * | 40        | GPIOHS16         | GPIO High speed 16                |
+ * | 41        | GPIOHS17         | GPIO High speed 17                |
+ * | 42        | GPIOHS18         | GPIO High speed 18                |
+ * | 43        | GPIOHS19         | GPIO High speed 19                |
+ * | 44        | GPIOHS20         | GPIO High speed 20                |
+ * | 45        | GPIOHS21         | GPIO High speed 21                |
+ * | 46        | GPIOHS22         | GPIO High speed 22                |
+ * | 47        | GPIOHS23         | GPIO High speed 23                |
+ * | 48        | GPIOHS24         | GPIO High speed 24                |
+ * | 49        | GPIOHS25         | GPIO High speed 25                |
+ * | 50        | GPIOHS26         | GPIO High speed 26                |
+ * | 51        | GPIOHS27         | GPIO High speed 27                |
+ * | 52        | GPIOHS28         | GPIO High speed 28                |
+ * | 53        | GPIOHS29         | GPIO High speed 29                |
+ * | 54        | GPIOHS30         | GPIO High speed 30                |
+ * | 55        | GPIOHS31         | GPIO High speed 31                |
+ * | 56        | GPIO0            | GPIO pin 0                        |
+ * | 57        | GPIO1            | GPIO pin 1                        |
+ * | 58        | GPIO2            | GPIO pin 2                        |
+ * | 59        | GPIO3            | GPIO pin 3                        |
+ * | 60        | GPIO4            | GPIO pin 4                        |
+ * | 61        | GPIO5            | GPIO pin 5                        |
+ * | 62        | GPIO6            | GPIO pin 6                        |
+ * | 63        | GPIO7            | GPIO pin 7                        |
+ * | 64        | UART1_RX         | UART1 Receiver                    |
+ * | 65        | UART1_TX         | UART1 Transmitter                 |
+ * | 66        | UART2_RX         | UART2 Receiver                    |
+ * | 67        | UART2_TX         | UART2 Transmitter                 |
+ * | 68        | UART3_RX         | UART3 Receiver                    |
+ * | 69        | UART3_TX         | UART3 Transmitter                 |
+ * | 70        | SPI1_D0          | SPI1 Data 0                       |
+ * | 71        | SPI1_D1          | SPI1 Data 1                       |
+ * | 72        | SPI1_D2          | SPI1 Data 2                       |
+ * | 73        | SPI1_D3          | SPI1 Data 3                       |
+ * | 74        | SPI1_D4          | SPI1 Data 4                       |
+ * | 75        | SPI1_D5          | SPI1 Data 5                       |
+ * | 76        | SPI1_D6          | SPI1 Data 6                       |
+ * | 77        | SPI1_D7          | SPI1 Data 7                       |
+ * | 78        | SPI1_SS0         | SPI1 Chip Select 0                |
+ * | 79        | SPI1_SS1         | SPI1 Chip Select 1                |
+ * | 80        | SPI1_SS2         | SPI1 Chip Select 2                |
+ * | 81        | SPI1_SS3         | SPI1 Chip Select 3                |
+ * | 82        | SPI1_ARB         | SPI1 Arbitration                  |
+ * | 83        | SPI1_SCLK        | SPI1 Serial Clock                 |
+ * | 84        | SPI_SLAVE_D0     | SPI Slave Data 0                  |
+ * | 85        | SPI_SLAVE_SS     | SPI Slave Select                  |
+ * | 86        | SPI_SLAVE_SCLK   | SPI Slave Serial Clock            |
+ * | 87        | I2S0_MCLK        | I2S0 Master Clock                 |
+ * | 88        | I2S0_SCLK        | I2S0 Serial Clock(BCLK)           |
+ * | 89        | I2S0_WS          | I2S0 Word Select(LRCLK)           |
+ * | 90        | I2S0_IN_D0       | I2S0 Serial Data Input 0          |
+ * | 91        | I2S0_IN_D1       | I2S0 Serial Data Input 1          |
+ * | 92        | I2S0_IN_D2       | I2S0 Serial Data Input 2          |
+ * | 93        | I2S0_IN_D3       | I2S0 Serial Data Input 3          |
+ * | 94        | I2S0_OUT_D0      | I2S0 Serial Data Output 0         |
+ * | 95        | I2S0_OUT_D1      | I2S0 Serial Data Output 1         |
+ * | 96        | I2S0_OUT_D2      | I2S0 Serial Data Output 2         |
+ * | 97        | I2S0_OUT_D3      | I2S0 Serial Data Output 3         |
+ * | 98        | I2S1_MCLK        | I2S1 Master Clock                 |
+ * | 99        | I2S1_SCLK        | I2S1 Serial Clock(BCLK)           |
+ * | 100       | I2S1_WS          | I2S1 Word Select(LRCLK)           |
+ * | 101       | I2S1_IN_D0       | I2S1 Serial Data Input 0          |
+ * | 102       | I2S1_IN_D1       | I2S1 Serial Data Input 1          |
+ * | 103       | I2S1_IN_D2       | I2S1 Serial Data Input 2          |
+ * | 104       | I2S1_IN_D3       | I2S1 Serial Data Input 3          |
+ * | 105       | I2S1_OUT_D0      | I2S1 Serial Data Output 0         |
+ * | 106       | I2S1_OUT_D1      | I2S1 Serial Data Output 1         |
+ * | 107       | I2S1_OUT_D2      | I2S1 Serial Data Output 2         |
+ * | 108       | I2S1_OUT_D3      | I2S1 Serial Data Output 3         |
+ * | 109       | I2S2_MCLK        | I2S2 Master Clock                 |
+ * | 110       | I2S2_SCLK        | I2S2 Serial Clock(BCLK)           |
+ * | 111       | I2S2_WS          | I2S2 Word Select(LRCLK)           |
+ * | 112       | I2S2_IN_D0       | I2S2 Serial Data Input 0          |
+ * | 113       | I2S2_IN_D1       | I2S2 Serial Data Input 1          |
+ * | 114       | I2S2_IN_D2       | I2S2 Serial Data Input 2          |
+ * | 115       | I2S2_IN_D3       | I2S2 Serial Data Input 3          |
+ * | 116       | I2S2_OUT_D0      | I2S2 Serial Data Output 0         |
+ * | 117       | I2S2_OUT_D1      | I2S2 Serial Data Output 1         |
+ * | 118       | I2S2_OUT_D2      | I2S2 Serial Data Output 2         |
+ * | 119       | I2S2_OUT_D3      | I2S2 Serial Data Output 3         |
+ * | 120       | RESV0            | Reserved function                 |
+ * | 121       | RESV1            | Reserved function                 |
+ * | 122       | RESV2            | Reserved function                 |
+ * | 123       | RESV3            | Reserved function                 |
+ * | 124       | RESV4            | Reserved function                 |
+ * | 125       | RESV5            | Reserved function                 |
+ * | 126       | I2C0_SCLK        | I2C0 Serial Clock                 |
+ * | 127       | I2C0_SDA         | I2C0 Serial Data                  |
+ * | 128       | I2C1_SCLK        | I2C1 Serial Clock                 |
+ * | 129       | I2C1_SDA         | I2C1 Serial Data                  |
+ * | 130       | I2C2_SCLK        | I2C2 Serial Clock                 |
+ * | 131       | I2C2_SDA         | I2C2 Serial Data                  |
+ * | 132       | CMOS_XCLK        | DVP System Clock                  |
+ * | 133       | CMOS_RST         | DVP System Reset                  |
+ * | 134       | CMOS_PWDN        | DVP Power Down Mode               |
+ * | 135       | CMOS_VSYNC       | DVP Vertical Sync                 |
+ * | 136       | CMOS_HREF        | DVP Horizontal Reference output   |
+ * | 137       | CMOS_PCLK        | Pixel Clock                       |
+ * | 138       | CMOS_D0          | Data Bit 0                        |
+ * | 139       | CMOS_D1          | Data Bit 1                        |
+ * | 140       | CMOS_D2          | Data Bit 2                        |
+ * | 141       | CMOS_D3          | Data Bit 3                        |
+ * | 142       | CMOS_D4          | Data Bit 4                        |
+ * | 143       | CMOS_D5          | Data Bit 5                        |
+ * | 144       | CMOS_D6          | Data Bit 6                        |
+ * | 145       | CMOS_D7          | Data Bit 7                        |
+ * | 146       | SCCB_SCLK        | SCCB Serial Clock                 |
+ * | 147       | SCCB_SDA         | SCCB Serial Data                  |
+ * | 148       | UART1_CTS        | UART1 Clear To Send               |
+ * | 149       | UART1_DSR        | UART1 Data Set Ready              |
+ * | 150       | UART1_DCD        | UART1 Data Carrier Detect         |
+ * | 151       | UART1_RI         | UART1 Ring Indicator              |
+ * | 152       | UART1_SIR_IN     | UART1 Serial Infrared Input       |
+ * | 153       | UART1_DTR        | UART1 Data Terminal Ready         |
+ * | 154       | UART1_RTS        | UART1 Request To Send             |
+ * | 155       | UART1_OUT2       | UART1 User-designated Output 2    |
+ * | 156       | UART1_OUT1       | UART1 User-designated Output 1    |
+ * | 157       | UART1_SIR_OUT    | UART1 Serial Infrared Output      |
+ * | 158       | UART1_BAUD       | UART1 Transmit Clock Output       |
+ * | 159       | UART1_RE         | UART1 Receiver Output Enable      |
+ * | 160       | UART1_DE         | UART1 Driver Output Enable        |
+ * | 161       | UART1_RS485_EN   | UART1 RS485 Enable                |
+ * | 162       | UART2_CTS        | UART2 Clear To Send               |
+ * | 163       | UART2_DSR        | UART2 Data Set Ready              |
+ * | 164       | UART2_DCD        | UART2 Data Carrier Detect         |
+ * | 165       | UART2_RI         | UART2 Ring Indicator              |
+ * | 166       | UART2_SIR_IN     | UART2 Serial Infrared Input       |
+ * | 167       | UART2_DTR        | UART2 Data Terminal Ready         |
+ * | 168       | UART2_RTS        | UART2 Request To Send             |
+ * | 169       | UART2_OUT2       | UART2 User-designated Output 2    |
+ * | 170       | UART2_OUT1       | UART2 User-designated Output 1    |
+ * | 171       | UART2_SIR_OUT    | UART2 Serial Infrared Output      |
+ * | 172       | UART2_BAUD       | UART2 Transmit Clock Output       |
+ * | 173       | UART2_RE         | UART2 Receiver Output Enable      |
+ * | 174       | UART2_DE         | UART2 Driver Output Enable        |
+ * | 175       | UART2_RS485_EN   | UART2 RS485 Enable                |
+ * | 176       | UART3_CTS        | UART3 Clear To Send               |
+ * | 177       | UART3_DSR        | UART3 Data Set Ready              |
+ * | 178       | UART3_DCD        | UART3 Data Carrier Detect         |
+ * | 179       | UART3_RI         | UART3 Ring Indicator              |
+ * | 180       | UART3_SIR_IN     | UART3 Serial Infrared Input       |
+ * | 181       | UART3_DTR        | UART3 Data Terminal Ready         |
+ * | 182       | UART3_RTS        | UART3 Request To Send             |
+ * | 183       | UART3_OUT2       | UART3 User-designated Output 2    |
+ * | 184       | UART3_OUT1       | UART3 User-designated Output 1    |
+ * | 185       | UART3_SIR_OUT    | UART3 Serial Infrared Output      |
+ * | 186       | UART3_BAUD       | UART3 Transmit Clock Output       |
+ * | 187       | UART3_RE         | UART3 Receiver Output Enable      |
+ * | 188       | UART3_DE         | UART3 Driver Output Enable        |
+ * | 189       | UART3_RS485_EN   | UART3 RS485 Enable                |
+ * | 190       | TIMER0_TOGGLE1   | TIMER0 Toggle Output 1            |
+ * | 191       | TIMER0_TOGGLE2   | TIMER0 Toggle Output 2            |
+ * | 192       | TIMER0_TOGGLE3   | TIMER0 Toggle Output 3            |
+ * | 193       | TIMER0_TOGGLE4   | TIMER0 Toggle Output 4            |
+ * | 194       | TIMER1_TOGGLE1   | TIMER1 Toggle Output 1            |
+ * | 195       | TIMER1_TOGGLE2   | TIMER1 Toggle Output 2            |
+ * | 196       | TIMER1_TOGGLE3   | TIMER1 Toggle Output 3            |
+ * | 197       | TIMER1_TOGGLE4   | TIMER1 Toggle Output 4            |
+ * | 198       | TIMER2_TOGGLE1   | TIMER2 Toggle Output 1            |
+ * | 199       | TIMER2_TOGGLE2   | TIMER2 Toggle Output 2            |
+ * | 200       | TIMER2_TOGGLE3   | TIMER2 Toggle Output 3            |
+ * | 201       | TIMER2_TOGGLE4   | TIMER2 Toggle Output 4            |
+ * | 202       | CLK_SPI2         | Clock SPI2                        |
+ * | 203       | CLK_I2C2         | Clock I2C2                        |
+ * | 204       | INTERNAL0        | Internal function signal 0        |
+ * | 205       | INTERNAL1        | Internal function signal 1        |
+ * | 206       | INTERNAL2        | Internal function signal 2        |
+ * | 207       | INTERNAL3        | Internal function signal 3        |
+ * | 208       | INTERNAL4        | Internal function signal 4        |
+ * | 209       | INTERNAL5        | Internal function signal 5        |
+ * | 210       | INTERNAL6        | Internal function signal 6        |
+ * | 211       | INTERNAL7        | Internal function signal 7        |
+ * | 212       | INTERNAL8        | Internal function signal 8        |
+ * | 213       | INTERNAL9        | Internal function signal 9        |
+ * | 214       | INTERNAL10       | Internal function signal 10       |
+ * | 215       | INTERNAL11       | Internal function signal 11       |
+ * | 216       | INTERNAL12       | Internal function signal 12       |
+ * | 217       | INTERNAL13       | Internal function signal 13       |
+ * | 218       | INTERNAL14       | Internal function signal 14       |
+ * | 219       | INTERNAL15       | Internal function signal 15       |
+ * | 220       | INTERNAL16       | Internal function signal 16       |
+ * | 221       | INTERNAL17       | Internal function signal 17       |
+ * | 222       | CONSTANT         | Constant function                 |
+ * | 223       | INTERNAL18       | Internal function signal 18       |
+ * | 224       | DEBUG0           | Debug function 0                  |
+ * | 225       | DEBUG1           | Debug function 1                  |
+ * | 226       | DEBUG2           | Debug function 2                  |
+ * | 227       | DEBUG3           | Debug function 3                  |
+ * | 228       | DEBUG4           | Debug function 4                  |
+ * | 229       | DEBUG5           | Debug function 5                  |
+ * | 230       | DEBUG6           | Debug function 6                  |
+ * | 231       | DEBUG7           | Debug function 7                  |
+ * | 232       | DEBUG8           | Debug function 8                  |
+ * | 233       | DEBUG9           | Debug function 9                  |
+ * | 234       | DEBUG10          | Debug function 10                 |
+ * | 235       | DEBUG11          | Debug function 11                 |
+ * | 236       | DEBUG12          | Debug function 12                 |
+ * | 237       | DEBUG13          | Debug function 13                 |
+ * | 238       | DEBUG14          | Debug function 14                 |
+ * | 239       | DEBUG15          | Debug function 15                 |
+ * | 240       | DEBUG16          | Debug function 16                 |
+ * | 241       | DEBUG17          | Debug function 17                 |
+ * | 242       | DEBUG18          | Debug function 18                 |
+ * | 243       | DEBUG19          | Debug function 19                 |
+ * | 244       | DEBUG20          | Debug function 20                 |
+ * | 245       | DEBUG21          | Debug function 21                 |
+ * | 246       | DEBUG22          | Debug function 22                 |
+ * | 247       | DEBUG23          | Debug function 23                 |
+ * | 248       | DEBUG24          | Debug function 24                 |
+ * | 249       | DEBUG25          | Debug function 25                 |
+ * | 250       | DEBUG26          | Debug function 26                 |
+ * | 251       | DEBUG27          | Debug function 27                 |
+ * | 252       | DEBUG28          | Debug function 28                 |
+ * | 253       | DEBUG29          | Debug function 29                 |
+ * | 254       | DEBUG30          | Debug function 30                 |
+ * | 255       | DEBUG31          | Debug function 31                 |
+ *
+ * Any IO of FPIOA have 256 functions, it is a IO-function matrix.
+ * All IO have default reset function, after reset, re-configure
+ * IO function is required.
+ */
+
+/* clang-format off */
+typedef enum _fpioa_function
+{
+    FUNC_JTAG_TCLK        = 0,  /*!< JTAG Test Clock */
+    FUNC_JTAG_TDI         = 1,  /*!< JTAG Test Data In */
+    FUNC_JTAG_TMS         = 2,  /*!< JTAG Test Mode Select */
+    FUNC_JTAG_TDO         = 3,  /*!< JTAG Test Data Out */
+    FUNC_SPI0_D0          = 4,  /*!< SPI0 Data 0 */
+    FUNC_SPI0_D1          = 5,  /*!< SPI0 Data 1 */
+    FUNC_SPI0_D2          = 6,  /*!< SPI0 Data 2 */
+    FUNC_SPI0_D3          = 7,  /*!< SPI0 Data 3 */
+    FUNC_SPI0_D4          = 8,  /*!< SPI0 Data 4 */
+    FUNC_SPI0_D5          = 9,  /*!< SPI0 Data 5 */
+    FUNC_SPI0_D6          = 10, /*!< SPI0 Data 6 */
+    FUNC_SPI0_D7          = 11, /*!< SPI0 Data 7 */
+    FUNC_SPI0_SS0         = 12, /*!< SPI0 Chip Select 0 */
+    FUNC_SPI0_SS1         = 13, /*!< SPI0 Chip Select 1 */
+    FUNC_SPI0_SS2         = 14, /*!< SPI0 Chip Select 2 */
+    FUNC_SPI0_SS3         = 15, /*!< SPI0 Chip Select 3 */
+    FUNC_SPI0_ARB         = 16, /*!< SPI0 Arbitration */
+    FUNC_SPI0_SCLK        = 17, /*!< SPI0 Serial Clock */
+    FUNC_UARTHS_RX        = 18, /*!< UART High speed Receiver */
+    FUNC_UARTHS_TX        = 19, /*!< UART High speed Transmitter */
+    FUNC_RESV6            = 20, /*!< Reserved function */
+    FUNC_RESV7            = 21, /*!< Reserved function */
+    FUNC_CLK_SPI1         = 22, /*!< Clock SPI1 */
+    FUNC_CLK_I2C1         = 23, /*!< Clock I2C1 */
+    FUNC_GPIOHS0          = 24, /*!< GPIO High speed 0 */
+    FUNC_GPIOHS1          = 25, /*!< GPIO High speed 1 */
+    FUNC_GPIOHS2          = 26, /*!< GPIO High speed 2 */
+    FUNC_GPIOHS3          = 27, /*!< GPIO High speed 3 */
+    FUNC_GPIOHS4          = 28, /*!< GPIO High speed 4 */
+    FUNC_GPIOHS5          = 29, /*!< GPIO High speed 5 */
+    FUNC_GPIOHS6          = 30, /*!< GPIO High speed 6 */
+    FUNC_GPIOHS7          = 31, /*!< GPIO High speed 7 */
+    FUNC_GPIOHS8          = 32, /*!< GPIO High speed 8 */
+    FUNC_GPIOHS9          = 33, /*!< GPIO High speed 9 */
+    FUNC_GPIOHS10         = 34, /*!< GPIO High speed 10 */
+    FUNC_GPIOHS11         = 35, /*!< GPIO High speed 11 */
+    FUNC_GPIOHS12         = 36, /*!< GPIO High speed 12 */
+    FUNC_GPIOHS13         = 37, /*!< GPIO High speed 13 */
+    FUNC_GPIOHS14         = 38, /*!< GPIO High speed 14 */
+    FUNC_GPIOHS15         = 39, /*!< GPIO High speed 15 */
+    FUNC_GPIOHS16         = 40, /*!< GPIO High speed 16 */
+    FUNC_GPIOHS17         = 41, /*!< GPIO High speed 17 */
+    FUNC_GPIOHS18         = 42, /*!< GPIO High speed 18 */
+    FUNC_GPIOHS19         = 43, /*!< GPIO High speed 19 */
+    FUNC_GPIOHS20         = 44, /*!< GPIO High speed 20 */
+    FUNC_GPIOHS21         = 45, /*!< GPIO High speed 21 */
+    FUNC_GPIOHS22         = 46, /*!< GPIO High speed 22 */
+    FUNC_GPIOHS23         = 47, /*!< GPIO High speed 23 */
+    FUNC_GPIOHS24         = 48, /*!< GPIO High speed 24 */
+    FUNC_GPIOHS25         = 49, /*!< GPIO High speed 25 */
+    FUNC_GPIOHS26         = 50, /*!< GPIO High speed 26 */
+    FUNC_GPIOHS27         = 51, /*!< GPIO High speed 27 */
+    FUNC_GPIOHS28         = 52, /*!< GPIO High speed 28 */
+    FUNC_GPIOHS29         = 53, /*!< GPIO High speed 29 */
+    FUNC_GPIOHS30         = 54, /*!< GPIO High speed 30 */
+    FUNC_GPIOHS31         = 55, /*!< GPIO High speed 31 */
+    FUNC_GPIO0            = 56, /*!< GPIO pin 0 */
+    FUNC_GPIO1            = 57, /*!< GPIO pin 1 */
+    FUNC_GPIO2            = 58, /*!< GPIO pin 2 */
+    FUNC_GPIO3            = 59, /*!< GPIO pin 3 */
+    FUNC_GPIO4            = 60, /*!< GPIO pin 4 */
+    FUNC_GPIO5            = 61, /*!< GPIO pin 5 */
+    FUNC_GPIO6            = 62, /*!< GPIO pin 6 */
+    FUNC_GPIO7            = 63, /*!< GPIO pin 7 */
+    FUNC_UART1_RX         = 64, /*!< UART1 Receiver */
+    FUNC_UART1_TX         = 65, /*!< UART1 Transmitter */
+    FUNC_UART2_RX         = 66, /*!< UART2 Receiver */
+    FUNC_UART2_TX         = 67, /*!< UART2 Transmitter */
+    FUNC_UART3_RX         = 68, /*!< UART3 Receiver */
+    FUNC_UART3_TX         = 69, /*!< UART3 Transmitter */
+    FUNC_SPI1_D0          = 70, /*!< SPI1 Data 0 */
+    FUNC_SPI1_D1          = 71, /*!< SPI1 Data 1 */
+    FUNC_SPI1_D2          = 72, /*!< SPI1 Data 2 */
+    FUNC_SPI1_D3          = 73, /*!< SPI1 Data 3 */
+    FUNC_SPI1_D4          = 74, /*!< SPI1 Data 4 */
+    FUNC_SPI1_D5          = 75, /*!< SPI1 Data 5 */
+    FUNC_SPI1_D6          = 76, /*!< SPI1 Data 6 */
+    FUNC_SPI1_D7          = 77, /*!< SPI1 Data 7 */
+    FUNC_SPI1_SS0         = 78, /*!< SPI1 Chip Select 0 */
+    FUNC_SPI1_SS1         = 79, /*!< SPI1 Chip Select 1 */
+    FUNC_SPI1_SS2         = 80, /*!< SPI1 Chip Select 2 */
+    FUNC_SPI1_SS3         = 81, /*!< SPI1 Chip Select 3 */
+    FUNC_SPI1_ARB         = 82, /*!< SPI1 Arbitration */
+    FUNC_SPI1_SCLK        = 83, /*!< SPI1 Serial Clock */
+    FUNC_SPI_SLAVE_D0     = 84, /*!< SPI Slave Data 0 */
+    FUNC_SPI_SLAVE_SS     = 85, /*!< SPI Slave Select */
+    FUNC_SPI_SLAVE_SCLK   = 86, /*!< SPI Slave Serial Clock */
+    FUNC_I2S0_MCLK        = 87, /*!< I2S0 Master Clock */
+    FUNC_I2S0_SCLK        = 88, /*!< I2S0 Serial Clock(BCLK) */
+    FUNC_I2S0_WS          = 89, /*!< I2S0 Word Select(LRCLK) */
+    FUNC_I2S0_IN_D0       = 90, /*!< I2S0 Serial Data Input 0 */
+    FUNC_I2S0_IN_D1       = 91, /*!< I2S0 Serial Data Input 1 */
+    FUNC_I2S0_IN_D2       = 92, /*!< I2S0 Serial Data Input 2 */
+    FUNC_I2S0_IN_D3       = 93, /*!< I2S0 Serial Data Input 3 */
+    FUNC_I2S0_OUT_D0      = 94, /*!< I2S0 Serial Data Output 0 */
+    FUNC_I2S0_OUT_D1      = 95, /*!< I2S0 Serial Data Output 1 */
+    FUNC_I2S0_OUT_D2      = 96, /*!< I2S0 Serial Data Output 2 */
+    FUNC_I2S0_OUT_D3      = 97, /*!< I2S0 Serial Data Output 3 */
+    FUNC_I2S1_MCLK        = 98, /*!< I2S1 Master Clock */
+    FUNC_I2S1_SCLK        = 99, /*!< I2S1 Serial Clock(BCLK) */
+    FUNC_I2S1_WS          = 100,    /*!< I2S1 Word Select(LRCLK) */
+    FUNC_I2S1_IN_D0       = 101,    /*!< I2S1 Serial Data Input 0 */
+    FUNC_I2S1_IN_D1       = 102,    /*!< I2S1 Serial Data Input 1 */
+    FUNC_I2S1_IN_D2       = 103,    /*!< I2S1 Serial Data Input 2 */
+    FUNC_I2S1_IN_D3       = 104,    /*!< I2S1 Serial Data Input 3 */
+    FUNC_I2S1_OUT_D0      = 105,    /*!< I2S1 Serial Data Output 0 */
+    FUNC_I2S1_OUT_D1      = 106,    /*!< I2S1 Serial Data Output 1 */
+    FUNC_I2S1_OUT_D2      = 107,    /*!< I2S1 Serial Data Output 2 */
+    FUNC_I2S1_OUT_D3      = 108,    /*!< I2S1 Serial Data Output 3 */
+    FUNC_I2S2_MCLK        = 109,    /*!< I2S2 Master Clock */
+    FUNC_I2S2_SCLK        = 110,    /*!< I2S2 Serial Clock(BCLK) */
+    FUNC_I2S2_WS          = 111,    /*!< I2S2 Word Select(LRCLK) */
+    FUNC_I2S2_IN_D0       = 112,    /*!< I2S2 Serial Data Input 0 */
+    FUNC_I2S2_IN_D1       = 113,    /*!< I2S2 Serial Data Input 1 */
+    FUNC_I2S2_IN_D2       = 114,    /*!< I2S2 Serial Data Input 2 */
+    FUNC_I2S2_IN_D3       = 115,    /*!< I2S2 Serial Data Input 3 */
+    FUNC_I2S2_OUT_D0      = 116,    /*!< I2S2 Serial Data Output 0 */
+    FUNC_I2S2_OUT_D1      = 117,    /*!< I2S2 Serial Data Output 1 */
+    FUNC_I2S2_OUT_D2      = 118,    /*!< I2S2 Serial Data Output 2 */
+    FUNC_I2S2_OUT_D3      = 119,    /*!< I2S2 Serial Data Output 3 */
+    FUNC_RESV0            = 120,    /*!< Reserved function */
+    FUNC_RESV1            = 121,    /*!< Reserved function */
+    FUNC_RESV2            = 122,    /*!< Reserved function */
+    FUNC_RESV3            = 123,    /*!< Reserved function */
+    FUNC_RESV4            = 124,    /*!< Reserved function */
+    FUNC_RESV5            = 125,    /*!< Reserved function */
+    FUNC_I2C0_SCLK        = 126,    /*!< I2C0 Serial Clock */
+    FUNC_I2C0_SDA         = 127,    /*!< I2C0 Serial Data */
+    FUNC_I2C1_SCLK        = 128,    /*!< I2C1 Serial Clock */
+    FUNC_I2C1_SDA         = 129,    /*!< I2C1 Serial Data */
+    FUNC_I2C2_SCLK        = 130,    /*!< I2C2 Serial Clock */
+    FUNC_I2C2_SDA         = 131,    /*!< I2C2 Serial Data */
+    FUNC_CMOS_XCLK        = 132,    /*!< DVP System Clock */
+    FUNC_CMOS_RST         = 133,    /*!< DVP System Reset */
+    FUNC_CMOS_PWDN        = 134,    /*!< DVP Power Down Mode */
+    FUNC_CMOS_VSYNC       = 135,    /*!< DVP Vertical Sync */
+    FUNC_CMOS_HREF        = 136,    /*!< DVP Horizontal Reference output */
+    FUNC_CMOS_PCLK        = 137,    /*!< Pixel Clock */
+    FUNC_CMOS_D0          = 138,    /*!< Data Bit 0 */
+    FUNC_CMOS_D1          = 139,    /*!< Data Bit 1 */
+    FUNC_CMOS_D2          = 140,    /*!< Data Bit 2 */
+    FUNC_CMOS_D3          = 141,    /*!< Data Bit 3 */
+    FUNC_CMOS_D4          = 142,    /*!< Data Bit 4 */
+    FUNC_CMOS_D5          = 143,    /*!< Data Bit 5 */
+    FUNC_CMOS_D6          = 144,    /*!< Data Bit 6 */
+    FUNC_CMOS_D7          = 145,    /*!< Data Bit 7 */
+    FUNC_SCCB_SCLK        = 146,    /*!< SCCB Serial Clock */
+    FUNC_SCCB_SDA         = 147,    /*!< SCCB Serial Data */
+    FUNC_UART1_CTS        = 148,    /*!< UART1 Clear To Send */
+    FUNC_UART1_DSR        = 149,    /*!< UART1 Data Set Ready */
+    FUNC_UART1_DCD        = 150,    /*!< UART1 Data Carrier Detect */
+    FUNC_UART1_RI         = 151,    /*!< UART1 Ring Indicator */
+    FUNC_UART1_SIR_IN     = 152,    /*!< UART1 Serial Infrared Input */
+    FUNC_UART1_DTR        = 153,    /*!< UART1 Data Terminal Ready */
+    FUNC_UART1_RTS        = 154,    /*!< UART1 Request To Send */
+    FUNC_UART1_OUT2       = 155,    /*!< UART1 User-designated Output 2 */
+    FUNC_UART1_OUT1       = 156,    /*!< UART1 User-designated Output 1 */
+    FUNC_UART1_SIR_OUT    = 157,    /*!< UART1 Serial Infrared Output */
+    FUNC_UART1_BAUD       = 158,    /*!< UART1 Transmit Clock Output */
+    FUNC_UART1_RE         = 159,    /*!< UART1 Receiver Output Enable */
+    FUNC_UART1_DE         = 160,    /*!< UART1 Driver Output Enable */
+    FUNC_UART1_RS485_EN   = 161,    /*!< UART1 RS485 Enable */
+    FUNC_UART2_CTS        = 162,    /*!< UART2 Clear To Send */
+    FUNC_UART2_DSR        = 163,    /*!< UART2 Data Set Ready */
+    FUNC_UART2_DCD        = 164,    /*!< UART2 Data Carrier Detect */
+    FUNC_UART2_RI         = 165,    /*!< UART2 Ring Indicator */
+    FUNC_UART2_SIR_IN     = 166,    /*!< UART2 Serial Infrared Input */
+    FUNC_UART2_DTR        = 167,    /*!< UART2 Data Terminal Ready */
+    FUNC_UART2_RTS        = 168,    /*!< UART2 Request To Send */
+    FUNC_UART2_OUT2       = 169,    /*!< UART2 User-designated Output 2 */
+    FUNC_UART2_OUT1       = 170,    /*!< UART2 User-designated Output 1 */
+    FUNC_UART2_SIR_OUT    = 171,    /*!< UART2 Serial Infrared Output */
+    FUNC_UART2_BAUD       = 172,    /*!< UART2 Transmit Clock Output */
+    FUNC_UART2_RE         = 173,    /*!< UART2 Receiver Output Enable */
+    FUNC_UART2_DE         = 174,    /*!< UART2 Driver Output Enable */
+    FUNC_UART2_RS485_EN   = 175,    /*!< UART2 RS485 Enable */
+    FUNC_UART3_CTS        = 176,    /*!< UART3 Clear To Send */
+    FUNC_UART3_DSR        = 177,    /*!< UART3 Data Set Ready */
+    FUNC_UART3_DCD        = 178,    /*!< UART3 Data Carrier Detect */
+    FUNC_UART3_RI         = 179,    /*!< UART3 Ring Indicator */
+    FUNC_UART3_SIR_IN     = 180,    /*!< UART3 Serial Infrared Input */
+    FUNC_UART3_DTR        = 181,    /*!< UART3 Data Terminal Ready */
+    FUNC_UART3_RTS        = 182,    /*!< UART3 Request To Send */
+    FUNC_UART3_OUT2       = 183,    /*!< UART3 User-designated Output 2 */
+    FUNC_UART3_OUT1       = 184,    /*!< UART3 User-designated Output 1 */
+    FUNC_UART3_SIR_OUT    = 185,    /*!< UART3 Serial Infrared Output */
+    FUNC_UART3_BAUD       = 186,    /*!< UART3 Transmit Clock Output */
+    FUNC_UART3_RE         = 187,    /*!< UART3 Receiver Output Enable */
+    FUNC_UART3_DE         = 188,    /*!< UART3 Driver Output Enable */
+    FUNC_UART3_RS485_EN   = 189,    /*!< UART3 RS485 Enable */
+    FUNC_TIMER0_TOGGLE1   = 190,    /*!< TIMER0 Toggle Output 1 */
+    FUNC_TIMER0_TOGGLE2   = 191,    /*!< TIMER0 Toggle Output 2 */
+    FUNC_TIMER0_TOGGLE3   = 192,    /*!< TIMER0 Toggle Output 3 */
+    FUNC_TIMER0_TOGGLE4   = 193,    /*!< TIMER0 Toggle Output 4 */
+    FUNC_TIMER1_TOGGLE1   = 194,    /*!< TIMER1 Toggle Output 1 */
+    FUNC_TIMER1_TOGGLE2   = 195,    /*!< TIMER1 Toggle Output 2 */
+    FUNC_TIMER1_TOGGLE3   = 196,    /*!< TIMER1 Toggle Output 3 */
+    FUNC_TIMER1_TOGGLE4   = 197,    /*!< TIMER1 Toggle Output 4 */
+    FUNC_TIMER2_TOGGLE1   = 198,    /*!< TIMER2 Toggle Output 1 */
+    FUNC_TIMER2_TOGGLE2   = 199,    /*!< TIMER2 Toggle Output 2 */
+    FUNC_TIMER2_TOGGLE3   = 200,    /*!< TIMER2 Toggle Output 3 */
+    FUNC_TIMER2_TOGGLE4   = 201,    /*!< TIMER2 Toggle Output 4 */
+    FUNC_CLK_SPI2         = 202,    /*!< Clock SPI2 */
+    FUNC_CLK_I2C2         = 203,    /*!< Clock I2C2 */
+    FUNC_INTERNAL0        = 204,    /*!< Internal function signal 0 */
+    FUNC_INTERNAL1        = 205,    /*!< Internal function signal 1 */
+    FUNC_INTERNAL2        = 206,    /*!< Internal function signal 2 */
+    FUNC_INTERNAL3        = 207,    /*!< Internal function signal 3 */
+    FUNC_INTERNAL4        = 208,    /*!< Internal function signal 4 */
+    FUNC_INTERNAL5        = 209,    /*!< Internal function signal 5 */
+    FUNC_INTERNAL6        = 210,    /*!< Internal function signal 6 */
+    FUNC_INTERNAL7        = 211,    /*!< Internal function signal 7 */
+    FUNC_INTERNAL8        = 212,    /*!< Internal function signal 8 */
+    FUNC_INTERNAL9        = 213,    /*!< Internal function signal 9 */
+    FUNC_INTERNAL10       = 214,    /*!< Internal function signal 10 */
+    FUNC_INTERNAL11       = 215,    /*!< Internal function signal 11 */
+    FUNC_INTERNAL12       = 216,    /*!< Internal function signal 12 */
+    FUNC_INTERNAL13       = 217,    /*!< Internal function signal 13 */
+    FUNC_INTERNAL14       = 218,    /*!< Internal function signal 14 */
+    FUNC_INTERNAL15       = 219,    /*!< Internal function signal 15 */
+    FUNC_INTERNAL16       = 220,    /*!< Internal function signal 16 */
+    FUNC_INTERNAL17       = 221,    /*!< Internal function signal 17 */
+    FUNC_CONSTANT         = 222,    /*!< Constant function */
+    FUNC_INTERNAL18       = 223,    /*!< Internal function signal 18 */
+    FUNC_DEBUG0           = 224,    /*!< Debug function 0 */
+    FUNC_DEBUG1           = 225,    /*!< Debug function 1 */
+    FUNC_DEBUG2           = 226,    /*!< Debug function 2 */
+    FUNC_DEBUG3           = 227,    /*!< Debug function 3 */
+    FUNC_DEBUG4           = 228,    /*!< Debug function 4 */
+    FUNC_DEBUG5           = 229,    /*!< Debug function 5 */
+    FUNC_DEBUG6           = 230,    /*!< Debug function 6 */
+    FUNC_DEBUG7           = 231,    /*!< Debug function 7 */
+    FUNC_DEBUG8           = 232,    /*!< Debug function 8 */
+    FUNC_DEBUG9           = 233,    /*!< Debug function 9 */
+    FUNC_DEBUG10          = 234,    /*!< Debug function 10 */
+    FUNC_DEBUG11          = 235,    /*!< Debug function 11 */
+    FUNC_DEBUG12          = 236,    /*!< Debug function 12 */
+    FUNC_DEBUG13          = 237,    /*!< Debug function 13 */
+    FUNC_DEBUG14          = 238,    /*!< Debug function 14 */
+    FUNC_DEBUG15          = 239,    /*!< Debug function 15 */
+    FUNC_DEBUG16          = 240,    /*!< Debug function 16 */
+    FUNC_DEBUG17          = 241,    /*!< Debug function 17 */
+    FUNC_DEBUG18          = 242,    /*!< Debug function 18 */
+    FUNC_DEBUG19          = 243,    /*!< Debug function 19 */
+    FUNC_DEBUG20          = 244,    /*!< Debug function 20 */
+    FUNC_DEBUG21          = 245,    /*!< Debug function 21 */
+    FUNC_DEBUG22          = 246,    /*!< Debug function 22 */
+    FUNC_DEBUG23          = 247,    /*!< Debug function 23 */
+    FUNC_DEBUG24          = 248,    /*!< Debug function 24 */
+    FUNC_DEBUG25          = 249,    /*!< Debug function 25 */
+    FUNC_DEBUG26          = 250,    /*!< Debug function 26 */
+    FUNC_DEBUG27          = 251,    /*!< Debug function 27 */
+    FUNC_DEBUG28          = 252,    /*!< Debug function 28 */
+    FUNC_DEBUG29          = 253,    /*!< Debug function 29 */
+    FUNC_DEBUG30          = 254,    /*!< Debug function 30 */
+    FUNC_DEBUG31          = 255,    /*!< Debug function 31 */
+    FUNC_MAX              = 256,    /*!< Function numbers */
+} fpioa_function_t;
+/* clang-format on */
+
+/**
+ * @brief      FPIOA pull settings
+ *
+ * @note       FPIOA pull settings description
+ *
+ * | PU  | PD  | Description                       |
+ * |-----|-----|-----------------------------------|
+ * | 0   | 0   | No Pull                           |
+ * | 0   | 1   | Pull Down                         |
+ * | 1   | 0   | Pull Up                           |
+ * | 1   | 1   | Undefined                         |
+ *
+ */
+
+/* clang-format off */
+typedef enum _fpioa_pull
+{
+    FPIOA_PULL_NONE,      /*!< No Pull */
+    FPIOA_PULL_DOWN,      /*!< Pull Down */
+    FPIOA_PULL_UP,        /*!< Pull Up */
+    FPIOA_PULL_MAX        /*!< Count of pull settings */
+} fpioa_pull_t;
+/* clang-format on */
+
+/**
+ * @brief      FPIOA driving settings
+ *
+ * @note       FPIOA driving settings description
+ *             There are 16 kinds of driving settings
+ *
+ * @note       Low Level Output Current
+ *
+ * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)|
+ * |--------|-------|-------|-------|
+ * |0000    |3.2    |5.4    |8.3    |
+ * |0001    |4.7    |8.0    |12.3   |
+ * |0010    |6.3    |10.7   |16.4   |
+ * |0011    |7.8    |13.2   |20.2   |
+ * |0100    |9.4    |15.9   |24.2   |
+ * |0101    |10.9   |18.4   |28.1   |
+ * |0110    |12.4   |20.9   |31.8   |
+ * |0111    |13.9   |23.4   |35.5   |
+ *
+ * @note       High Level Output Current
+ *
+ * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)|
+ * |--------|-------|-------|-------|
+ * |0000    |5.0    |7.6    |11.2   |
+ * |0001    |7.5    |11.4   |16.8   |
+ * |0010    |10.0   |15.2   |22.3   |
+ * |0011    |12.4   |18.9   |27.8   |
+ * |0100    |14.9   |22.6   |33.3   |
+ * |0101    |17.4   |26.3   |38.7   |
+ * |0110    |19.8   |30.0   |44.1   |
+ * |0111    |22.3   |33.7   |49.5   |
+ *
+ */
+
+/* clang-format off */
+typedef enum _fpioa_driving
+{
+    FPIOA_DRIVING_0,      /*!< 0000 */
+    FPIOA_DRIVING_1,      /*!< 0001 */
+    FPIOA_DRIVING_2,      /*!< 0010 */
+    FPIOA_DRIVING_3,      /*!< 0011 */
+    FPIOA_DRIVING_4,      /*!< 0100 */
+    FPIOA_DRIVING_5,      /*!< 0101 */
+    FPIOA_DRIVING_6,      /*!< 0110 */
+    FPIOA_DRIVING_7,      /*!< 0111 */
+    FPIOA_DRIVING_8,      /*!< 1000 */
+    FPIOA_DRIVING_9,      /*!< 1001 */
+    FPIOA_DRIVING_10,     /*!< 1010 */
+    FPIOA_DRIVING_11,     /*!< 1011 */
+    FPIOA_DRIVING_12,     /*!< 1100 */
+    FPIOA_DRIVING_13,     /*!< 1101 */
+    FPIOA_DRIVING_14,     /*!< 1110 */
+    FPIOA_DRIVING_15,     /*!< 1111 */
+    FPIOA_DRIVING_MAX     /*!< Count of driving settings */
+} fpioa_driving_t;
+/* clang-format on */
+
+/**
+ * @brief      FPIOA IO
+ *
+ *             FPIOA IO is the specific pin of the chip package. Every IO
+ *             has a 32bit width register that can independently implement
+ *             schmitt trigger, invert input, invert output, strong pull
+ *             up, driving selector, static input and static output. And more,
+ *             it can implement any pin of any peripheral devices.
+ *
+ * @note       FPIOA IO's register bits Layout
+ *
+ * | Bits      | Name     |Description                                        |
+ * |-----------|----------|---------------------------------------------------|
+ * | 31        | PAD_DI   | Read current IO's data input.                     |
+ * | 30:24     | NA       | Reserved bits.                                    |
+ * | 23        | ST       | Schmitt trigger.                                  |
+ * | 22        | DI_INV   | Invert Data input.                                |
+ * | 21        | IE_INV   | Invert the input enable signal.                   |
+ * | 20        | IE_EN    | Input enable. It can disable or enable IO input.  |
+ * | 19        | SL       | Slew rate control enable.                         |
+ * | 18        | SPU      | Strong pull up.                                   |
+ * | 17        | PD       | Pull select: 0 for pull down, 1 for pull up.      |
+ * | 16        | PU       | Pull enable.                                      |
+ * | 15        | DO_INV   | Invert the result of data output select (DO_SEL). |
+ * | 14        | DO_SEL   | Data output select: 0 for DO, 1 for OE.           |
+ * | 13        | OE_INV   | Invert the output enable signal.                  |
+ * | 12        | OE_EN    | Output enable.It can disable or enable IO output. |
+ * | 11:8      | DS       | Driving selector.                                 |
+ * | 7:0       | CH_SEL   | Channel select from 256 input.                    |
+ *
+ */
+typedef struct _fpioa_io_config
+{
+    uint32 ch_sel : 8;
+    /*!< Channel select from 256 input. */
+    uint32 ds : 4;
+    /*!< Driving selector. */
+    uint32 oe_en : 1;
+    /*!< Static output enable, will AND with OE_INV. */
+    uint32 oe_inv : 1;
+    /*!< Invert output enable. */
+    uint32 do_sel : 1;
+    /*!< Data output select: 0 for DO, 1 for OE. */
+    uint32 do_inv : 1;
+    /*!< Invert the result of data output select (DO_SEL). */
+    uint32 pu : 1;
+    /*!< Pull up enable. 0 for nothing, 1 for pull up. */
+    uint32 pd : 1;
+    /*!< Pull down enable. 0 for nothing, 1 for pull down. */
+    uint32 resv0 : 1;
+    /*!< Reserved bits. */
+    uint32 sl : 1;
+    /*!< Slew rate control enable. */
+    uint32 ie_en : 1;
+    /*!< Static input enable, will AND with IE_INV. */
+    uint32 ie_inv : 1;
+    /*!< Invert input enable. */
+    uint32 di_inv : 1;
+    /*!< Invert Data input. */
+    uint32 st : 1;
+    /*!< Schmitt trigger. */
+    uint32 resv1 : 7;
+    /*!< Reserved bits. */
+    uint32 pad_di : 1;
+    /*!< Read current IO's data input. */
+} __attribute__((packed, aligned(4))) fpioa_io_config_t;
+
+/**
+ * @brief      FPIOA tie setting
+ *
+ *             FPIOA Object have 48 IO pin object and 256 bit input tie bits.
+ *             All SPI arbitration signal will tie high by default.
+ *
+ * @note       FPIOA function tie bits RAM Layout
+ *
+ * | Address   | Name             |Description                       |
+ * |-----------|------------------|----------------------------------|
+ * | 0x000     | TIE_EN[31:0]     | Input tie enable bits [31:0]     |
+ * | 0x004     | TIE_EN[63:32]    | Input tie enable bits [63:32]    |
+ * | 0x008     | TIE_EN[95:64]    | Input tie enable bits [95:64]    |
+ * | 0x00C     | TIE_EN[127:96]   | Input tie enable bits [127:96]   |
+ * | 0x010     | TIE_EN[159:128]  | Input tie enable bits [159:128]  |
+ * | 0x014     | TIE_EN[191:160]  | Input tie enable bits [191:160]  |
+ * | 0x018     | TIE_EN[223:192]  | Input tie enable bits [223:192]  |
+ * | 0x01C     | TIE_EN[255:224]  | Input tie enable bits [255:224]  |
+ * | 0x020     | TIE_VAL[31:0]    | Input tie value bits [31:0]      |
+ * | 0x024     | TIE_VAL[63:32]   | Input tie value bits [63:32]     |
+ * | 0x028     | TIE_VAL[95:64]   | Input tie value bits [95:64]     |
+ * | 0x02C     | TIE_VAL[127:96]  | Input tie value bits [127:96]    |
+ * | 0x030     | TIE_VAL[159:128] | Input tie value bits [159:128]   |
+ * | 0x034     | TIE_VAL[191:160] | Input tie value bits [191:160]   |
+ * | 0x038     | TIE_VAL[223:192] | Input tie value bits [223:192]   |
+ * | 0x03C     | TIE_VAL[255:224] | Input tie value bits [255:224]   |
+ *
+ * @note       Function which input tie high by default
+ *
+ * | Name          |Description                            |
+ * |---------------|---------------------------------------|
+ * | SPI0_ARB      | Arbitration function of SPI master 0  |
+ * | SPI1_ARB      | Arbitration function of SPI master 1  |
+ *
+ *             Tie high means the SPI Arbitration input is 1
+ *
+ */
+typedef struct _fpioa_tie
+{
+    uint32 en[FUNC_MAX / 32];
+    /*!< FPIOA GPIO multiplexer tie enable array */
+    uint32 val[FUNC_MAX / 32];
+    /*!< FPIOA GPIO multiplexer tie value array */
+} __attribute__((packed, aligned(4))) fpioa_tie_t;
+
+/**
+ * @brief      FPIOA Object
+ *
+ *             FPIOA Object have 48 IO pin object and 256 bit input tie bits.
+ *             All SPI arbitration signal will tie high by default.
+ *
+ * @note       FPIOA IO Pin RAM Layout
+ *
+ * | Address   | Name     |Description                     |
+ * |-----------|----------|--------------------------------|
+ * | 0x000     | PAD0     | FPIOA GPIO multiplexer io 0    |
+ * | 0x004     | PAD1     | FPIOA GPIO multiplexer io 1    |
+ * | 0x008     | PAD2     | FPIOA GPIO multiplexer io 2    |
+ * | 0x00C     | PAD3     | FPIOA GPIO multiplexer io 3    |
+ * | 0x010     | PAD4     | FPIOA GPIO multiplexer io 4    |
+ * | 0x014     | PAD5     | FPIOA GPIO multiplexer io 5    |
+ * | 0x018     | PAD6     | FPIOA GPIO multiplexer io 6    |
+ * | 0x01C     | PAD7     | FPIOA GPIO multiplexer io 7    |
+ * | 0x020     | PAD8     | FPIOA GPIO multiplexer io 8    |
+ * | 0x024     | PAD9     | FPIOA GPIO multiplexer io 9    |
+ * | 0x028     | PAD10    | FPIOA GPIO multiplexer io 10   |
+ * | 0x02C     | PAD11    | FPIOA GPIO multiplexer io 11   |
+ * | 0x030     | PAD12    | FPIOA GPIO multiplexer io 12   |
+ * | 0x034     | PAD13    | FPIOA GPIO multiplexer io 13   |
+ * | 0x038     | PAD14    | FPIOA GPIO multiplexer io 14   |
+ * | 0x03C     | PAD15    | FPIOA GPIO multiplexer io 15   |
+ * | 0x040     | PAD16    | FPIOA GPIO multiplexer io 16   |
+ * | 0x044     | PAD17    | FPIOA GPIO multiplexer io 17   |
+ * | 0x048     | PAD18    | FPIOA GPIO multiplexer io 18   |
+ * | 0x04C     | PAD19    | FPIOA GPIO multiplexer io 19   |
+ * | 0x050     | PAD20    | FPIOA GPIO multiplexer io 20   |
+ * | 0x054     | PAD21    | FPIOA GPIO multiplexer io 21   |
+ * | 0x058     | PAD22    | FPIOA GPIO multiplexer io 22   |
+ * | 0x05C     | PAD23    | FPIOA GPIO multiplexer io 23   |
+ * | 0x060     | PAD24    | FPIOA GPIO multiplexer io 24   |
+ * | 0x064     | PAD25    | FPIOA GPIO multiplexer io 25   |
+ * | 0x068     | PAD26    | FPIOA GPIO multiplexer io 26   |
+ * | 0x06C     | PAD27    | FPIOA GPIO multiplexer io 27   |
+ * | 0x070     | PAD28    | FPIOA GPIO multiplexer io 28   |
+ * | 0x074     | PAD29    | FPIOA GPIO multiplexer io 29   |
+ * | 0x078     | PAD30    | FPIOA GPIO multiplexer io 30   |
+ * | 0x07C     | PAD31    | FPIOA GPIO multiplexer io 31   |
+ * | 0x080     | PAD32    | FPIOA GPIO multiplexer io 32   |
+ * | 0x084     | PAD33    | FPIOA GPIO multiplexer io 33   |
+ * | 0x088     | PAD34    | FPIOA GPIO multiplexer io 34   |
+ * | 0x08C     | PAD35    | FPIOA GPIO multiplexer io 35   |
+ * | 0x090     | PAD36    | FPIOA GPIO multiplexer io 36   |
+ * | 0x094     | PAD37    | FPIOA GPIO multiplexer io 37   |
+ * | 0x098     | PAD38    | FPIOA GPIO multiplexer io 38   |
+ * | 0x09C     | PAD39    | FPIOA GPIO multiplexer io 39   |
+ * | 0x0A0     | PAD40    | FPIOA GPIO multiplexer io 40   |
+ * | 0x0A4     | PAD41    | FPIOA GPIO multiplexer io 41   |
+ * | 0x0A8     | PAD42    | FPIOA GPIO multiplexer io 42   |
+ * | 0x0AC     | PAD43    | FPIOA GPIO multiplexer io 43   |
+ * | 0x0B0     | PAD44    | FPIOA GPIO multiplexer io 44   |
+ * | 0x0B4     | PAD45    | FPIOA GPIO multiplexer io 45   |
+ * | 0x0B8     | PAD46    | FPIOA GPIO multiplexer io 46   |
+ * | 0x0BC     | PAD47    | FPIOA GPIO multiplexer io 47   |
+ *
+ */
+typedef struct _fpioa
+{
+    fpioa_io_config_t io[FPIOA_NUM_IO];
+    /*!< FPIOA GPIO multiplexer io array */
+    fpioa_tie_t tie;
+    /*!< FPIOA GPIO multiplexer tie */
+} __attribute__((packed, aligned(4))) fpioa_t;
+
+/**
+ * @brief       FPIOA object instanse
+ */
+extern volatile fpioa_t *const fpioa;
+
+/**
+ * @brief       Initialize FPIOA user custom default settings
+ *
+ * @note        This function will set all FPIOA pad registers to user-defined
+ *              values from kconfig
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_init(void);
+
+/**
+ * @brief       Get IO configuration
+ *
+ * @param[in]   number      The IO number
+ * @param       cfg         Pointer to struct of IO configuration for specified IO
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_get_io(int number, fpioa_io_config_t *cfg);
+
+/**
+ * @brief       Set IO configuration
+ *
+ * @param[in]   number      The IO number
+ * @param[in]   cfg         Pointer to struct of IO configuration for specified IO
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_io(int number, fpioa_io_config_t *cfg);
+
+/**
+ * @brief       Set IO configuration with function number
+ *
+ * @note        The default IO configuration which bind to function number will
+ *              set automatically
+ *
+ * @param[in]   number      The IO number
+ * @param[in]   function    The function enum number
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_function_raw(int number, fpioa_function_t function);
+
+/**
+ * @brief       Set only IO configuration with function number
+ *
+ * @note        The default IO configuration which bind to function number will
+ *              set automatically
+ *
+ * @param[in]   number      The IO number
+ * @param[in]   function    The function enum number
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_function(int number, fpioa_function_t function);
+
+/**
+ * @brief       Set tie enable to function
+ *
+ * @param[in]   function    The function enum number
+ * @param[in]   enable      Tie enable to set, 1 is enable, 0 is disable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_tie_enable(fpioa_function_t function, int enable);
+
+/**
+ * @brief       Set tie value to function
+ *
+ * @param[in]   function    The function enum number
+ * @param[in]   value       Tie value to set, 1 is HIGH, 0 is LOW
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_tie_value(fpioa_function_t function, int value);
+
+/**
+ * @brief      Set IO pull function
+ *
+ * @param[in]   number  The IO number
+ * @param[in]   pull    The pull enum number
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_io_pull(int number, fpioa_pull_t pull);
+
+/**
+ * @brief       Get IO pull function
+ *
+ * @param[in]   number  The IO number
+ *
+ * @return      result
+ *     - -1     Fail
+ *     - Other  The pull enum number
+ */
+int fpioa_get_io_pull(int number);
+
+/**
+ * @brief       Set IO driving
+ *
+ * @param[in]   number   The IO number
+ * @param[in]   driving  The driving enum number
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_io_driving(int number, fpioa_driving_t driving);
+
+/**
+ * @brief       Get IO driving
+ *
+ * @param[in]   number  The IO number
+ *
+ * @return      result
+ *     - -1     Fail
+ *     - Other  The driving enum number
+ */
+int fpioa_get_io_driving(int number);
+
+/**
+ * @brief       Get IO by function
+ *
+ * @param[in]   function  The function enum number
+ *
+ * @return      result
+ *     - -1     Fail
+ *     - Other  The IO number
+ */
+int fpioa_get_io_by_function(fpioa_function_t function);
+
+/**
+ * @brief       Set IO slew rate control
+ *
+ * @param[in]   number      The IO number
+ * @param[in]   sl_value    Enable slew rate. 0: disable 1:enable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_sl(int number, uint8 sl_enable);
+
+/**
+ * @brief       Set IO schmitt trigger
+ *
+ * @param[in]   number       The IO number
+ * @param[in]   st_enable    Enable schmitt trigger. 0: disable 1:enable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_st(int number, uint8 st_enable);
+
+/**
+ * @brief       Set IO output invert enable
+ *
+ * @param[in]   number       The IO number
+ * @param[in]   inv_enable   Enable output invert. 0: disable 1:enable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int fpioa_set_oe_inv(int number, uint8 inv_enable);
+
+void fpioa_pin_init(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_FPIOA_H */
diff --git a/kernel/include/gpiohs.h b/kernel/include/gpiohs.h
new file mode 100644
index 0000000000000000000000000000000000000000..99abe6ccf455d8cca67ad34de2f0d355116cb54f
--- /dev/null
+++ b/kernel/include/gpiohs.h
@@ -0,0 +1,278 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _DRIVER_GPIOHS_H
+#define _DRIVER_GPIOHS_H
+
+typedef enum _gpio_drive_mode
+{
+    GPIO_DM_INPUT,
+    GPIO_DM_INPUT_PULL_DOWN,
+    GPIO_DM_INPUT_PULL_UP,
+    GPIO_DM_OUTPUT,
+} gpio_drive_mode_t;
+
+typedef enum _gpio_pin_edge
+{
+    GPIO_PE_NONE,
+    GPIO_PE_FALLING,
+    GPIO_PE_RISING,
+    GPIO_PE_BOTH,
+    GPIO_PE_LOW,
+    GPIO_PE_HIGH = 8,
+} gpio_pin_edge_t;
+
+typedef enum _gpio_pin_value
+{
+    GPIO_PV_LOW,
+    GPIO_PV_HIGH
+} gpio_pin_value_t;
+
+/* clang-format off */
+/* Register address offsets */
+#define GPIOHS_INPUT_VAL  (0x00)
+#define GPIOHS_INPUT_EN   (0x04)
+#define GPIOHS_OUTPUT_EN  (0x08)
+#define GPIOHS_OUTPUT_VAL (0x0C)
+#define GPIOHS_PULLUP_EN  (0x10)
+#define GPIOHS_DRIVE      (0x14)
+#define GPIOHS_RISE_IE    (0x18)
+#define GPIOHS_RISE_IP    (0x1C)
+#define GPIOHS_FALL_IE    (0x20)
+#define GPIOHS_FALL_IP    (0x24)
+#define GPIOHS_HIGH_IE    (0x28)
+#define GPIOHS_HIGH_IP    (0x2C)
+#define GPIOHS_LOW_IE     (0x30)
+#define GPIOHS_LOW_IP     (0x34)
+#define GPIOHS_IOF_EN     (0x38)
+#define GPIOHS_IOF_SEL    (0x3C)
+#define GPIOHS_OUTPUT_XOR (0x40)
+/* clang-format on */
+
+/**
+ * @brief      GPIO bits raw object
+ */
+typedef struct _gpiohs_raw
+{
+    /* Address offset 0x00 */
+    uint32 input_val;
+    /* Address offset 0x04 */
+    uint32 input_en;
+    /* Address offset 0x08 */
+    uint32 output_en;
+    /* Address offset 0x0c */
+    uint32 output_val;
+    /* Address offset 0x10 */
+    uint32 pullup_en;
+    /* Address offset 0x14 */
+    uint32 drive;
+    /* Address offset 0x18 */
+    uint32 rise_ie;
+    /* Address offset 0x1c */
+    uint32 rise_ip;
+    /* Address offset 0x20 */
+    uint32 fall_ie;
+    /* Address offset 0x24 */
+    uint32 fall_ip;
+    /* Address offset 0x28 */
+    uint32 high_ie;
+    /* Address offset 0x2c */
+    uint32 high_ip;
+    /* Address offset 0x30 */
+    uint32 low_ie;
+    /* Address offset 0x34 */
+    uint32 low_ip;
+    /* Address offset 0x38 */
+    uint32 iof_en;
+    /* Address offset 0x3c */
+    uint32 iof_sel;
+    /* Address offset 0x40 */
+    uint32 output_xor;
+} __attribute__((packed, aligned(4))) gpiohs_raw_t;
+
+/**
+ * @brief       GPIO bits object
+ */
+typedef struct _gpiohs_bits
+{
+    uint32 b0 : 1;
+    uint32 b1 : 1;
+    uint32 b2 : 1;
+    uint32 b3 : 1;
+    uint32 b4 : 1;
+    uint32 b5 : 1;
+    uint32 b6 : 1;
+    uint32 b7 : 1;
+    uint32 b8 : 1;
+    uint32 b9 : 1;
+    uint32 b10 : 1;
+    uint32 b11 : 1;
+    uint32 b12 : 1;
+    uint32 b13 : 1;
+    uint32 b14 : 1;
+    uint32 b15 : 1;
+    uint32 b16 : 1;
+    uint32 b17 : 1;
+    uint32 b18 : 1;
+    uint32 b19 : 1;
+    uint32 b20 : 1;
+    uint32 b21 : 1;
+    uint32 b22 : 1;
+    uint32 b23 : 1;
+    uint32 b24 : 1;
+    uint32 b25 : 1;
+    uint32 b26 : 1;
+    uint32 b27 : 1;
+    uint32 b28 : 1;
+    uint32 b29 : 1;
+    uint32 b30 : 1;
+    uint32 b31 : 1;
+} __attribute__((packed, aligned(4))) gpiohs_bits_t;
+
+/**
+ * @brief       GPIO bits multi access union
+ */
+typedef union _gpiohs_u32
+{
+    /* 32x1 bit mode */
+    uint32 u32[1];
+    /* 16x2 bit mode */
+    uint16 u16[2];
+    /* 8x4 bit mode */
+    uint8 u8[4];
+    /* 1 bit mode */
+    gpiohs_bits_t bits;
+} __attribute__((packed, aligned(4))) gpiohs_u32_t;
+
+/**
+ * @brief      GPIO object
+ *
+ *             The GPIO controller is a peripheral device mapped in the
+ *             internal memory map, discoverable in the Configuration String.
+ *             It is responsible for low-level configuration of the actual
+ *             GPIO pads on the device (direction, pull up-enable, and drive
+ *             value), as well as selecting between various sources of the
+ *             controls for these signals. The GPIO controller allows seperate
+ *             configuration of each of N GPIO bits.
+ *
+ *             Once the interrupt is pending, it will remain set until a 1 is
+ *             written to the *_ip register at that bit.
+ */
+
+typedef struct _gpiohs
+{
+    /* Address offset 0x00, Input Values */
+    gpiohs_u32_t input_val;
+    /* Address offset 0x04, Input enable */
+    gpiohs_u32_t input_en;
+    /* Address offset 0x08, Output enable */
+    gpiohs_u32_t output_en;
+    /* Address offset 0x0c, Onput Values */
+    gpiohs_u32_t output_val;
+    /* Address offset 0x10, Internal Pull-Ups enable */
+    gpiohs_u32_t pullup_en;
+    /* Address offset 0x14, Drive Strength */
+    gpiohs_u32_t drive;
+    /* Address offset 0x18, Rise interrupt enable */
+    gpiohs_u32_t rise_ie;
+    /* Address offset 0x1c, Rise interrupt pending */
+    gpiohs_u32_t rise_ip;
+    /* Address offset 0x20, Fall interrupt enable */
+    gpiohs_u32_t fall_ie;
+    /* Address offset 0x24, Fall interrupt pending */
+    gpiohs_u32_t fall_ip;
+    /* Address offset 0x28, High interrupt enable */
+    gpiohs_u32_t high_ie;
+    /* Address offset 0x2c, High interrupt pending */
+    gpiohs_u32_t high_ip;
+    /* Address offset 0x30, Low interrupt enable */
+    gpiohs_u32_t low_ie;
+    /* Address offset 0x34, Low interrupt pending */
+    gpiohs_u32_t low_ip;
+    /* Address offset 0x38, HW I/O Function enable */
+    gpiohs_u32_t iof_en;
+    /* Address offset 0x3c, HW I/O Function select */
+    gpiohs_u32_t iof_sel;
+    /* Address offset 0x40, Output XOR (invert) */
+    gpiohs_u32_t output_xor;
+} __attribute__((packed, aligned(4))) gpiohs_t;
+
+/**
+ * @brief       GPIO High-speed object instanse
+ */
+extern volatile gpiohs_t *const gpiohs;
+
+/**
+ * @brief       Set Gpiohs drive mode
+ *
+ * @param[in]   pin         Gpiohs pin
+ * @param[in]   mode        Gpiohs pin drive mode
+ */
+void gpiohs_set_drive_mode(uint8 pin, gpio_drive_mode_t mode);
+
+/**
+ * @brief       Get Gpiohs pin value
+ *
+ * @param[in]   pin     Gpiohs pin
+ * @return      Pin     value
+ *
+ *     - GPIO_PV_Low     Gpiohs pin low
+ *     - GPIO_PV_High    Gpiohs pin high
+ */
+gpio_pin_value_t gpiohs_get_pin(uint8 pin);
+
+/**
+ * @brief      Set Gpiohs pin value
+ *
+ * @param[in]   pin      Gpiohs pin
+ * @param[in]   value    Gpiohs pin value
+ */
+void gpiohs_set_pin(uint8 pin, gpio_pin_value_t value);
+
+/**
+ * @brief      Set Gpiohs pin edge for interrupt
+ *
+ * @param[in]   pin         Gpiohs pin
+ * @param[in]   edge        Gpiohs pin edge type
+ */
+void gpiohs_set_pin_edge(uint8 pin, gpio_pin_edge_t edge);
+
+/**
+ * @brief      Set Gpiohs pin interrupt
+ *
+ * @param[in]   pin             Gpiohs pin
+ * @param[in]   priority        Gpiohs pin interrupt priority
+ * @param[in]   func            Gpiohs pin interrupt service routine
+ */
+void gpiohs_set_irq(uint8 pin, uint32 priority, void (*func)());
+
+/**
+ * @brief      Set Gpiohs pin interrupt
+ *
+ * @param[in]   pin             Gpiohs pin
+ * @param[in]   priority        Gpiohs pin interrupt priority
+ * @param[in]   callback        Gpiohs pin interrupt service routine
+ * @param[in]   ctx             Gpiohs interrupt param
+ */
+//void gpiohs_irq_register(uint8 pin, uint32 priority, plic_irq_callback_t callback, void *ctx);
+
+/**
+ * @brief      Unregister Gpiohs pin interrupt
+ *
+ * @param[in]   pin             Gpiohs pin
+ */
+void gpiohs_irq_unregister(uint8 pin);
+
+
+#endif /* _DRIVER_GPIOHS_H */
diff --git a/kernel/include/intr.h b/kernel/include/intr.h
new file mode 100644
index 0000000000000000000000000000000000000000..f6fdcd5c4a5667a0de4b9e6cf202fd44d69b4e67
--- /dev/null
+++ b/kernel/include/intr.h
@@ -0,0 +1,10 @@
+// Intr on and off.
+
+
+#ifndef __INTR_H
+#define __INTR_H
+
+void push_off(void);
+void pop_off(void);
+
+#endif
diff --git a/kernel/include/kalloc.h b/kernel/include/kalloc.h
new file mode 100644
index 0000000000000000000000000000000000000000..c5cb01c7add81cc485620432605e2d16f0fa8794
--- /dev/null
+++ b/kernel/include/kalloc.h
@@ -0,0 +1,27 @@
+#ifndef __KALLOC_H
+#define __KALLOC_H
+
+#include "types.h"
+#include "spinlock.h"
+
+struct share_page{
+    uint64 addr;
+    int shared_pages;
+};
+struct kmem{
+  struct spinlock lock;
+  struct run *freelist;
+  uint64 npage;
+};
+
+extern char *mm_table;
+extern int mm_table_sz;
+extern uint64 pa_addr_start;
+extern struct kmem kmem;
+
+void*           kalloc(void);
+void            kfree(void *);
+void            kinit(void);
+uint64          freemem_amount(void);
+void            kernel_page_fault(void);
+#endif
\ No newline at end of file
diff --git a/kernel/include/memlayout.h b/kernel/include/memlayout.h
new file mode 100644
index 0000000000000000000000000000000000000000..1a776dddacccd26565b91dda086a0f59dade41a4
--- /dev/null
+++ b/kernel/include/memlayout.h
@@ -0,0 +1,132 @@
+#ifndef __MEMLAYOUT_H
+#define __MEMLAYOUT_H
+
+// Physical memory layout
+
+// k210 peripherals
+// (0x0200_0000, 0x1000),      /* CLINT     */
+// // we only need claim/complete for target0 after initializing
+// (0x0C20_0000, 0x1000),      /* PLIC      */
+// (0x3800_0000, 0x1000),      /* UARTHS    */
+// (0x3800_1000, 0x1000),      /* GPIOHS    */
+// (0x5020_0000, 0x1000),      /* GPIO      */
+// (0x5024_0000, 0x1000),      /* SPI_SLAVE */
+// (0x502B_0000, 0x1000),      /* FPIOA     */
+// (0x502D_0000, 0x1000),      /* TIMER0    */
+// (0x502E_0000, 0x1000),      /* TIMER1    */
+// (0x502F_0000, 0x1000),      /* TIMER2    */
+// (0x5044_0000, 0x1000),      /* SYSCTL    */
+// (0x5200_0000, 0x1000),      /* SPI0      */
+// (0x5300_0000, 0x1000),      /* SPI1      */
+// (0x5400_0000, 0x1000),      /* SPI2      */
+// (0x8000_0000, 0x600000),    /* Memory    */
+
+// qemu -machine virt is set up like this,
+// based on qemu's hw/riscv/virt.c:
+//
+// 00001000 -- boot ROM, provided by qemu
+// 02000000 -- CLINT
+// 0C000000 -- PLIC
+// 10000000 -- uart0 
+// 10001000 -- virtio disk 
+// 80000000 -- boot ROM jumps here in machine mode
+//             -kernel loads the kernel here
+// unused RAM after 80000000.
+
+#define VIRT_OFFSET             0x3F00000000L
+
+#ifdef QEMU
+// qemu puts UART registers here in physical memory.
+#define UART                    0x10000000L
+#else
+#define UART                    0x38000000L
+#endif
+
+#define UART_V                  (UART + VIRT_OFFSET)
+
+#ifdef QEMU
+// virtio mmio interface
+#define VIRTIO0                 0x10001000
+#define VIRTIO0_V               (VIRTIO0 + VIRT_OFFSET)
+#endif
+
+// local interrupt controller, which contains the timer.
+#define CLINT                   0x02000000L
+#define CLINT_V                 (CLINT + VIRT_OFFSET)
+
+#define PLIC                    0x0c000000L
+#define PLIC_V                  (PLIC + VIRT_OFFSET)
+
+#define PLIC_PRIORITY           (PLIC_V + 0x0)
+#define PLIC_PENDING            (PLIC_V + 0x1000)
+#define PLIC_MENABLE(hart)      (PLIC_V + 0x2000 + (hart) * 0x100)
+#define PLIC_SENABLE(hart)      (PLIC_V + 0x2080 + (hart) * 0x100)
+#define PLIC_MPRIORITY(hart)    (PLIC_V + 0x200000 + (hart) * 0x2000)
+#define PLIC_SPRIORITY(hart)    (PLIC_V + 0x201000 + (hart) * 0x2000)
+#define PLIC_MCLAIM(hart)       (PLIC_V + 0x200004 + (hart) * 0x2000)
+#define PLIC_SCLAIM(hart)       (PLIC_V + 0x201004 + (hart) * 0x2000)
+
+#ifndef QEMU
+#define GPIOHS                  0x38001000
+#define DMAC                    0x50000000
+#define GPIO                    0x50200000
+#define SPI_SLAVE               0x50240000
+#define FPIOA                   0x502B0000
+#define SPI0                    0x52000000
+#define SPI1                    0x53000000
+#define SPI2                    0x54000000
+#define SYSCTL                  0x50440000
+
+#define GPIOHS_V                (0x38001000 + VIRT_OFFSET)
+#define DMAC_V                  (0x50000000 + VIRT_OFFSET)
+#define GPIO_V                  (0x50200000 + VIRT_OFFSET)
+#define SPI_SLAVE_V             (0x50240000 + VIRT_OFFSET)
+#define FPIOA_V                 (0x502B0000 + VIRT_OFFSET)
+#define SPI0_V                  (0x52000000 + VIRT_OFFSET)
+#define SPI1_V                  (0x53000000 + VIRT_OFFSET)
+#define SPI2_V                  (0x54000000 + VIRT_OFFSET)
+#define SYSCTL_V                (0x50440000 + VIRT_OFFSET)
+
+
+#endif
+
+// the physical address of rustsbi
+#define RUSTSBI_BASE            0x80000000
+
+// the kernel expects there to be RAM
+// for use by the kernel and user pages
+// from physical address 0x80200000 to PHYSTOP.
+#ifndef QEMU
+#define KERNBASE                0x80020000
+#else
+#define KERNBASE                0x80200000
+#endif
+
+#define PHYSTOP                 0x80600000L
+
+// map the trampoline page to the highest address,
+// in both user and kernel space.
+#define TRAMPOLINE              (MAXVA - PGSIZE)
+
+// map kernel stacks beneath the trampoline,
+// each surrounded by invalid guard pages.
+// #define KSTACK(p)               (TRAMPOLINE - ((p) + 1) * 2 * PGSIZE)
+#define VKSTACK                 0x3EC0000000L
+#define VUSTACK                 0x7FFFF000
+#define VMMAP_BASE              0x40000000
+#define VMMAP_TOP               0x70000000
+// User memory layout.
+// Address zero first:
+//   text
+//   original data and bss
+//   fixed-size stack
+//   expandable heap
+//   ...
+//   TRAPFRAME (p->trapframe, used by the trampoline)
+//   TRAMPOLINE (the same page as in the kernel)
+#define TRAPFRAME               (TRAMPOLINE - PGSIZE)
+#define VUSTACK_BASE            (TRAPFRAME - PGSIZE)
+
+#define MAXUVA                  RUSTSBI_BASE
+
+#endif
diff --git a/kernel/include/null.h b/kernel/include/null.h
new file mode 100644
index 0000000000000000000000000000000000000000..48f2cfb8a757d16cf3d460029906a3ad9673910b
--- /dev/null
+++ b/kernel/include/null.h
@@ -0,0 +1,10 @@
+#ifndef __NULL_H
+#define __NULL_H
+
+#include "types.h"
+
+void nullinit(void);
+int nullread(int user_dst, uint64 dst, int n);
+int nullwrite(int user_src, uint64 src, int n);
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/param.h b/kernel/include/param.h
new file mode 100644
index 0000000000000000000000000000000000000000..e7332a8b79ffb1f201d64a551accc997c35cbf51
--- /dev/null
+++ b/kernel/include/param.h
@@ -0,0 +1,30 @@
+#ifndef __PARAM_H
+#define __PARAM_H
+
+#define NPROC        50  // maximum number of processes
+#define NCPU          2  // maximum number of CPUs
+#define NOFILE      101  // open files per process
+#define NFILE       200  // open files per system
+#define NINODE       50  // maximum number of active i-nodes
+#define NDEV         10  // maximum major device number
+#define ROOTDEV       1  // device number of file system root disk
+#define MAXARG       32  // max exec arguments
+#define MAXOPBLOCKS  1024  // max # of blocks any FS op writes
+#define LOGSIZE      (MAXOPBLOCKS*3)  // max data blocks in on-disk log
+#define NBUF         (MAXOPBLOCKS*3)  // size of disk block cache
+#define NBUFLIST     64
+#define FSSIZE       1000  // size of file system in blocks
+#define MAXPATH      260   // maximum file path name
+#define INTERVAL     (390000000 / 100) // timer interrupt interval
+#define BINPRM_BUF_SIZE  128  //可执行文件头大小
+#define AT_VECTOR_SIZE (2 * (2 + 20 + 1))
+
+
+
+
+
+#define WNOHANG       0x1
+#define WUNTRACED     0x2
+#define WCONTINUED    0x4
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/pipe.h b/kernel/include/pipe.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd503e7922e90a3748e4ce4f55a2dd6b2e097520
--- /dev/null
+++ b/kernel/include/pipe.h
@@ -0,0 +1,25 @@
+#ifndef __PIPE_H
+#define __PIPE_H
+
+#include "types.h"
+#include "spinlock.h"
+#include "file.h"
+
+#define PIPESIZE 512
+
+struct pipe {
+  struct spinlock lock;
+  char data[PIPESIZE];
+  uint nread;     // number of bytes read
+  uint nwrite;    // number of bytes written
+  int readopen;   // read fd is still open
+  int writeopen;  // write fd is still open
+};
+
+int pipealloc(struct file **f0, struct file **f1);
+void pipeclose(struct pipe *pi, int writable);
+int pipewrite(struct pipe *pi, uint64 addr, int n);
+int piperead(struct pipe *pi, uint64 addr, int n);
+int pipewrite2(struct pipe *pi, uint64 addr, int n);
+int piperead2(struct pipe *pi, uint64 addr, int n);
+#endif
\ No newline at end of file
diff --git a/kernel/include/plic.h b/kernel/include/plic.h
new file mode 100644
index 0000000000000000000000000000000000000000..8faa9d11a2c1fc8bf6eff7dd5acdf476f25682f6
--- /dev/null
+++ b/kernel/include/plic.h
@@ -0,0 +1,101 @@
+#ifndef __PLIC_H
+#define __PLIC_H 
+
+#include "memlayout.h"
+
+/**
+ * @brief       PLIC External Interrupt Numbers
+ *
+ * @note        PLIC interrupt sources
+ *
+ * | Source | Name                     | Description                        |
+ * |--------|--------------------------|------------------------------------|
+ * | 0      | IRQN_NO_INTERRUPT        | The non-existent interrupt         |
+ * | 1      | IRQN_SPI0_INTERRUPT      | SPI0 interrupt                     |
+ * | 2      | IRQN_SPI1_INTERRUPT      | SPI1 interrupt                     |
+ * | 3      | IRQN_SPI_SLAVE_INTERRUPT | SPI_SLAVE interrupt                |
+ * | 4      | IRQN_SPI3_INTERRUPT      | SPI3 interrupt                     |
+ * | 5      | IRQN_I2S0_INTERRUPT      | I2S0 interrupt                     |
+ * | 6      | IRQN_I2S1_INTERRUPT      | I2S1 interrupt                     |
+ * | 7      | IRQN_I2S2_INTERRUPT      | I2S2 interrupt                     |
+ * | 8      | IRQN_I2C0_INTERRUPT      | I2C0 interrupt                     |
+ * | 9      | IRQN_I2C1_INTERRUPT      | I2C1 interrupt                     |
+ * | 10     | IRQN_I2C2_INTERRUPT      | I2C2 interrupt                     |
+ * | 11     | IRQN_UART1_INTERRUPT     | UART1 interrupt                    |
+ * | 12     | IRQN_UART2_INTERRUPT     | UART2 interrupt                    |
+ * | 13     | IRQN_UART3_INTERRUPT     | UART3 interrupt                    |
+ * | 14     | IRQN_TIMER0A_INTERRUPT   | TIMER0 channel 0 or 1 interrupt    |
+ * | 15     | IRQN_TIMER0B_INTERRUPT   | TIMER0 channel 2 or 3 interrupt    |
+ * | 16     | IRQN_TIMER1A_INTERRUPT   | TIMER1 channel 0 or 1 interrupt    |
+ * | 17     | IRQN_TIMER1B_INTERRUPT   | TIMER1 channel 2 or 3 interrupt    |
+ * | 18     | IRQN_TIMER2A_INTERRUPT   | TIMER2 channel 0 or 1 interrupt    |
+ * | 19     | IRQN_TIMER2B_INTERRUPT   | TIMER2 channel 2 or 3 interrupt    |
+ * | 20     | IRQN_RTC_INTERRUPT       | RTC tick and alarm interrupt       |
+ * | 21     | IRQN_WDT0_INTERRUPT      | Watching dog timer0 interrupt      |
+ * | 22     | IRQN_WDT1_INTERRUPT      | Watching dog timer1 interrupt      |
+ * | 23     | IRQN_APB_GPIO_INTERRUPT  | APB GPIO interrupt                 |
+ * | 24     | IRQN_DVP_INTERRUPT       | Digital video port interrupt       |
+ * | 25     | IRQN_AI_INTERRUPT        | AI accelerator interrupt           |
+ * | 26     | IRQN_FFT_INTERRUPT       | FFT accelerator interrupt          |
+ * | 27     | IRQN_DMA0_INTERRUPT      | DMA channel0 interrupt             |
+ * | 28     | IRQN_DMA1_INTERRUPT      | DMA channel1 interrupt             |
+ * | 29     | IRQN_DMA2_INTERRUPT      | DMA channel2 interrupt             |
+ * | 30     | IRQN_DMA3_INTERRUPT      | DMA channel3 interrupt             |
+ * | 31     | IRQN_DMA4_INTERRUPT      | DMA channel4 interrupt             |
+ * | 32     | IRQN_DMA5_INTERRUPT      | DMA channel5 interrupt             |
+ * | 33     | IRQN_UARTHS_INTERRUPT    | Hi-speed UART0 interrupt           |
+ * | 34     | IRQN_GPIOHS0_INTERRUPT   | Hi-speed GPIO0 interrupt           |
+ * | 35     | IRQN_GPIOHS1_INTERRUPT   | Hi-speed GPIO1 interrupt           |
+ * | 36     | IRQN_GPIOHS2_INTERRUPT   | Hi-speed GPIO2 interrupt           |
+ * | 37     | IRQN_GPIOHS3_INTERRUPT   | Hi-speed GPIO3 interrupt           |
+ * | 38     | IRQN_GPIOHS4_INTERRUPT   | Hi-speed GPIO4 interrupt           |
+ * | 39     | IRQN_GPIOHS5_INTERRUPT   | Hi-speed GPIO5 interrupt           |
+ * | 40     | IRQN_GPIOHS6_INTERRUPT   | Hi-speed GPIO6 interrupt           |
+ * | 41     | IRQN_GPIOHS7_INTERRUPT   | Hi-speed GPIO7 interrupt           |
+ * | 42     | IRQN_GPIOHS8_INTERRUPT   | Hi-speed GPIO8 interrupt           |
+ * | 43     | IRQN_GPIOHS9_INTERRUPT   | Hi-speed GPIO9 interrupt           |
+ * | 44     | IRQN_GPIOHS10_INTERRUPT  | Hi-speed GPIO10 interrupt          |
+ * | 45     | IRQN_GPIOHS11_INTERRUPT  | Hi-speed GPIO11 interrupt          |
+ * | 46     | IRQN_GPIOHS12_INTERRUPT  | Hi-speed GPIO12 interrupt          |
+ * | 47     | IRQN_GPIOHS13_INTERRUPT  | Hi-speed GPIO13 interrupt          |
+ * | 48     | IRQN_GPIOHS14_INTERRUPT  | Hi-speed GPIO14 interrupt          |
+ * | 49     | IRQN_GPIOHS15_INTERRUPT  | Hi-speed GPIO15 interrupt          |
+ * | 50     | IRQN_GPIOHS16_INTERRUPT  | Hi-speed GPIO16 interrupt          |
+ * | 51     | IRQN_GPIOHS17_INTERRUPT  | Hi-speed GPIO17 interrupt          |
+ * | 52     | IRQN_GPIOHS18_INTERRUPT  | Hi-speed GPIO18 interrupt          |
+ * | 53     | IRQN_GPIOHS19_INTERRUPT  | Hi-speed GPIO19 interrupt          |
+ * | 54     | IRQN_GPIOHS20_INTERRUPT  | Hi-speed GPIO20 interrupt          |
+ * | 55     | IRQN_GPIOHS21_INTERRUPT  | Hi-speed GPIO21 interrupt          |
+ * | 56     | IRQN_GPIOHS22_INTERRUPT  | Hi-speed GPIO22 interrupt          |
+ * | 57     | IRQN_GPIOHS23_INTERRUPT  | Hi-speed GPIO23 interrupt          |
+ * | 58     | IRQN_GPIOHS24_INTERRUPT  | Hi-speed GPIO24 interrupt          |
+ * | 59     | IRQN_GPIOHS25_INTERRUPT  | Hi-speed GPIO25 interrupt          |
+ * | 60     | IRQN_GPIOHS26_INTERRUPT  | Hi-speed GPIO26 interrupt          |
+ * | 61     | IRQN_GPIOHS27_INTERRUPT  | Hi-speed GPIO27 interrupt          |
+ * | 62     | IRQN_GPIOHS28_INTERRUPT  | Hi-speed GPIO28 interrupt          |
+ * | 63     | IRQN_GPIOHS29_INTERRUPT  | Hi-speed GPIO29 interrupt          |
+ * | 64     | IRQN_GPIOHS30_INTERRUPT  | Hi-speed GPIO30 interrupt          |
+ * | 65     | IRQN_GPIOHS31_INTERRUPT  | Hi-speed GPIO31 interrupt          |
+ *
+ */
+
+#ifdef QEMU     // QEMU 
+#define UART_IRQ    10 
+#define DISK_IRQ    1
+#else           // k210 
+#define UART_IRQ    33
+#define DISK_IRQ    27
+#endif 
+
+void plicinit(void);
+
+// enable PLIC for each hart 
+void plicinithart(void);
+
+// ask PLIC what interrupt we should serve 
+int plic_claim(void);
+
+// tell PLIC that we've served this IRQ 
+void plic_complete(int irq);
+
+#endif 
diff --git a/kernel/include/printf.h b/kernel/include/printf.h
new file mode 100644
index 0000000000000000000000000000000000000000..304a7cd17dbf50946f27bcac5819242487cf9747
--- /dev/null
+++ b/kernel/include/printf.h
@@ -0,0 +1,39 @@
+#ifndef __PRINTF_H
+#define __PRINTF_H
+
+#define OPEN_LOG 1
+#define LOG_LEVEL 0
+
+typedef enum{
+    LOG_DEBUG = 0,
+    LOG_INF,
+    LOG_WARN,
+    LOG_ERROR
+} _LOG_LEVEL;
+
+extern const char* _FILE_;
+extern const char* _FUNCTION_;
+extern int _LINE_;
+extern int _LEVEL_;
+
+
+#define __LOG   _FILE_ = __FILE__; _LINE_ = __LINE__;
+
+#define __DEBUG {__LOG _LEVEL_ = LOG_DEBUG;}LOG_INPUT
+#define __INF   {__LOG _LEVEL_ = LOG_INF;}LOG_INPUT
+#define __WARN  {__LOG _LEVEL_ = LOG_WARN;}LOG_INPUT
+#define __ERROR {__LOG _LEVEL_ = LOG_ERROR;}LOG_INPUT
+
+void printfinit(void);
+
+void printf(char *fmt, ...);
+
+void panic(char *s) __attribute__((noreturn));
+
+void backtrace();
+
+void print_logo();
+
+void LOG_INPUT(const char *fmt, ...);
+
+#endif 
diff --git a/kernel/include/proc.h b/kernel/include/proc.h
new file mode 100644
index 0000000000000000000000000000000000000000..a0ca264ab886d984c75b39464dcbcd46377a63d7
--- /dev/null
+++ b/kernel/include/proc.h
@@ -0,0 +1,358 @@
+#ifndef __PROC_H
+#define __PROC_H
+
+#include "param.h"
+#include "riscv.h"
+#include "types.h"
+#include "spinlock.h"
+#include "file.h"
+#include "fat32.h"
+#include "trap.h"
+#include "timer.h"
+#include "signal.h"
+// Saved registers for kernel context switches.
+struct context {
+  uint64 ra;
+  uint64 sp;
+
+  // callee-saved
+  uint64 s0;
+  uint64 s1;
+  uint64 s2;
+  uint64 s3;
+  uint64 s4;
+  uint64 s5;
+  uint64 s6;
+  uint64 s7;
+  uint64 s8;
+  uint64 s9;
+  uint64 s10;
+  uint64 s11;
+};
+
+
+#define RLIMIT_CPU     0
+#define RLIMIT_FSIZE   1
+#define RLIMIT_DATA    2
+#define RLIMIT_STACK   3
+#define RLIMIT_CORE    4
+
+#ifndef RLIMIT_RSS
+#define RLIMIT_RSS     5
+#define RLIMIT_NPROC   6
+#define RLIMIT_NOFILE  7
+#define RLIMIT_MEMLOCK 8
+#define RLIMIT_AS      9
+#endif
+
+#define RLIMIT_LOCKS   10
+#define RLIMIT_SIGPENDING 11
+#define RLIMIT_MSGQUEUE 12
+#define RLIMIT_NICE    13
+#define RLIMIT_RTPRIO  14
+#define RLIMIT_RTTIME  15
+#define RLIMIT_NLIMITS 16
+
+/*
+ * SuS says limits have to be unsigned.
+ * Which makes a ton more sense anyway.
+ *
+ * Some architectures override this (for compatibility reasons):
+ */
+#ifndef RLIM_INFINITY
+# define RLIM_INFINITY		(~0UL)
+#endif
+#define RLIM64_INFINITY		(~0ULL)
+
+#define LONG_MAX __LONG_MAX__
+#undef ULONG_MAX
+#define ULONG_MAX (LONG_MAX * 2UL + 1UL)
+
+
+/* Flags for security_task_prlimit(). */
+#define LSM_PRLIMIT_READ  1
+#define LSM_PRLIMIT_WRITE 2
+
+#define RLIM_NLIMIT 16
+
+#define FUTEX_WAIT		0
+#define FUTEX_WAKE		1
+#define FUTEX_FD		2
+#define FUTEX_REQUEUE		3
+#define FUTEX_CMP_REQUEUE	4
+#define FUTEX_WAKE_OP		5
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
+#define FUTEX_WAIT_BITSET	9
+
+#define FUTEX_PRIVATE 128
+
+#define FUTEX_CLOCK_REALTIME 256
+
+
+#define FUTEX_WAIT		0
+#define FUTEX_WAKE		1
+#define FUTEX_FD		2
+#define FUTEX_REQUEUE		3
+#define FUTEX_CMP_REQUEUE	4
+#define FUTEX_WAKE_OP		5
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
+#define FUTEX_WAIT_BITSET	9
+#define FUTEX_WAKE_BITSET	10
+#define FUTEX_WAIT_REQUEUE_PI	11
+#define FUTEX_CMP_REQUEUE_PI	12
+#define FUTEX_LOCK_PI2		13
+
+#define FUTEX_PRIVATE_FLAG	128
+#define FUTEX_CLOCK_REALTIME	256
+#define FUTEX_CMD_MASK		~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
+
+#define AT_NULL   0	/* end of vector */
+#define AT_IGNORE 1	/* entry should be ignored */
+#define AT_EXECFD 2	/* file descriptor of program */
+#define AT_PHDR   3	/* program headers for program */
+#define AT_PHENT  4	/* size of program header entry */
+#define AT_PHNUM  5	/* number of program headers */
+#define AT_PAGESZ 6	/* system page size */
+#define AT_BASE   7	/* base address of interpreter */
+#define AT_FLAGS  8	/* flags */
+#define AT_ENTRY  9	/* entry point of program */
+#define AT_NOTELF 10	/* program is not ELF */
+#define AT_UID    11	/* real uid */
+#define AT_EUID   12	/* effective uid */
+#define AT_GID    13	/* real gid */
+#define AT_EGID   14	/* effective gid */
+#define AT_PLATFORM 15  /* string identifying CPU for optimizations */
+#define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
+#define AT_CLKTCK 17	/* frequency at which times() increments */
+/* AT_* values 18 through 22 are reserved */
+#define AT_SECURE 23   /* secure mode boolean */
+#define AT_BASE_PLATFORM 24	/* string identifying real platform, may
+				 * differ from AT_PLATFORM. */
+#define AT_RANDOM 25	/* address of 16 random bytes */
+#define AT_HWCAP2 26	/* extension of AT_HWCAP */
+
+#define AT_EXECFN  31	/* filename of program */
+
+#ifndef AT_MINSIGSTKSZ
+#define AT_MINSIGSTKSZ	51	/* minimal stack size for signal delivery */
+#endif
+#define PROT_NONE      0
+#define PROT_READ      1
+#define PROT_WRITE     2
+#define PROT_EXEC      4
+#define PROT_GROWSDOWN 0x01000000
+#define PROT_GROWSUP   0x02000000
+
+#define MAP_FILE		0
+#define MAP_SHARED		0x01
+#define MAP_PRIVATE		0x02
+#define MAP_FIXED		0x10
+#define MAP_ANONYMOUS	0x20
+
+typedef unsigned long long rlim_t;
+
+struct rlimit {
+	rlim_t rlim_cur;
+	rlim_t rlim_max;
+};
+
+struct rlimit64{
+unsigned long long  rlim_cur;
+unsigned long long  rlim_max;
+};
+
+
+
+
+struct tms{                     
+	long tms_utime;  
+	long tms_stime;  
+	long tms_cutime; 
+	long tms_cstime; 
+};
+
+// Per-CPU state.
+struct cpu {
+  struct proc *proc;          // The process running on this cpu, or null.
+  struct context context;     // swtch() here to enter scheduler().
+  int noff;                   // Depth of push_off() nesting.
+  int intena;                 // Were interrupts enabled before push_off()?
+};
+
+extern struct cpu cpus[NCPU];
+
+enum procstate { UNUSED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
+
+struct elf_seg{
+  uint64 off;
+  uint64 vaddr;
+  uint64 filesz;
+  uint64 memsz;
+};
+
+struct my_seg{
+  int num;
+  uint64 baseaddr;
+  uint64 prosize;
+};
+
+struct Iovec {
+    void* iovBase;	/* Pointer to data. */
+    uint64 iovLen;	/* Length of data. */
+};
+
+#define IOVMAX 64
+
+struct clone_args {
+  uint64 flags;        /* Flags bit mask */
+  uint64 pidfd;        /* Where to store PID file descriptor
+                         (pid_t *) */
+  uint64 child_tid;    /* Where to store child TID,
+                         in child's memory (pid_t *) */
+  uint64 parent_tid;   /* Where to store child TID,
+                         in parent's memory (int *) */
+  uint64 exit_signal;  /* Signal to deliver to parent on
+                         child termination */
+  uint64 stack;        /* Pointer to lowest byte of stack */
+  uint64 stack_size;   /* Size of stack */
+  uint64 tls;          /* Location of new TLS */
+  uint64 set_tid;      /* Pointer to a pid_t array
+                         (since Linux 5.5) */
+  uint64 set_tid_size; /* Number of elements in set_tid
+                         (since Linux 5.5) */
+  uint64 cgroup;       /* File descriptor for target cgroup
+                         of child (since Linux 5.7) */
+};
+
+
+// struct futex_val{
+//   int* uaddr;
+//   struct spinlock lock;
+// }
+// Per-process state
+
+struct mem_seg{
+  struct mem_seg *next;
+  struct mem_seg *prev;
+  int type;
+  uint64 start;
+  long len;
+  uint64 off;
+  uint real_len;
+  struct file *fd;
+  struct proc *parent;
+  int reserve;
+};
+
+struct free_mem_seg{
+  int type;
+  uint64 start;
+  long len;
+  struct free_mem_seg *next;
+  struct free_mem_seg *prev;
+};
+
+struct proc {
+  struct spinlock lock;
+
+  // p->lock must be held when using these:
+  enum procstate state;        // Process state
+  struct proc *parent;         // Parent process
+  void *chan;                  // If non-zero, sleeping on chan
+  int killed;                  // If non-zero, have been killed
+  int xstate;                  // Exit status to be returned to parent's wait
+  int pid;                     // Process ID
+
+  // these are private to the process, so p->lock need not be held.
+  uint64 kstack;               // Virtual address of kernel stack
+  uint64 sz;                   // Size of process memory (bytes)
+  uint64 static_sz;
+  uint64 stack_sz;             // 栈大小
+  uint64 ustack_base;
+  pagetable_t pagetable;       // User page table
+  pagetable_t kpagetable;      // Kernel page table
+  struct trapframe *trapframe; // data page for trampoline.S
+  struct context context;      // swtch() here to run process
+  struct file *ofile[NOFILE];  // Open files
+  struct dirent *cwd;          // Current directory
+  struct dirent *myep;
+  char name[16];               // Process name (debugging)
+  int tmask;                    // trace mask
+  uint64 mmap_size;
+  uint64 sbrk_size;
+  uint64 sbrk_base;
+  struct mapped_file mfile;    //映射的文件的范围
+  struct tms ti;
+  uint64 ikstmp;			        // the last moment when entering kernel
+	uint64 okstmp;			        // the last moment when leaving kernel
+	int64 vswtch;			          // voluntary context switches
+	int64 ivswtch;			        // involuntary context switches
+  struct my_seg my_seg;
+  sigset_t pending;           
+  sigset_t mask;
+  // sigset_t waiting;
+  uint64 act[N_SIG];
+  struct clone_args clone_arg;
+  struct rlimit rlim[RLIMIT_NLIMITS];
+  unsigned long load_bias;
+  struct mem_seg* seg;
+  struct free_mem_seg* free_seg;
+};
+
+
+struct dy_link_libraries{
+  char path[30];
+  pagetable_t pagetable;
+  int share_num;
+
+};
+
+void            reg_info(void);
+int             cpuid(void);
+void            exit(int);
+int             fork(void);
+int             growproc(int);
+pagetable_t     proc_pagetable(struct proc *);
+void            proc_freepagetable(pagetable_t, uint64, uint64,uint64);
+struct cpu*     mycpu(void);
+struct cpu*     getmycpu(void);
+struct proc*    myproc();
+void            procinit(void);
+void            scheduler(void) __attribute__((noreturn));
+void            sched(void);
+void            setproc(struct proc*);
+void            sleep(void*, struct spinlock*);
+void            userinit(void);
+int             wait(uint64);
+void            wakeup(void*);
+void            yield(void);
+int             either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
+int             either_copyin(void *dst, int user_src, uint64 src, uint64 len);
+void            procdump(void);
+uint64          procnum(void);
+void            test_proc_init(int);
+int             kill(int pid);
+
+int             do_clone(uint64 stack, uint64 flags,uint64 ptid,uint64 tls,uint64 ctid);
+int             do_waitpid(int pid, uint64 code, int options);
+uint64          do_mmap(uint64 start,long len, int prot, int flags, int fd, long off);
+uint64          do_munmap(uint64 start,  long len);
+uint64          do_msync(uint64 start,long len,int flags);
+int             apply_bvmem(uint64 start,int n, int flags);
+
+int             do_kill(int pid, int sig);
+int             do_set_tid_address(int *tidptr);
+void            do_exit_group(int status);
+int             do_gettid(void);
+
+struct proc*    findproc(int pid);
+int             do_futex(int *uaddr,int op,int val,struct timespec *timeout,int *uaddr2,int val3);
+void            initfreeseg( struct proc *p);
+void            initseg(struct proc *p);
+void            recycle_seg(struct proc *p);
+int             apply_bvmem2(pagetable_t pagetable,pagetable_t kpagetable, uint64 start,int n, int flags);
+#endif
\ No newline at end of file
diff --git a/kernel/include/rbtree.h b/kernel/include/rbtree.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e48816bd764134a7f9effd4c5b5cd1f0e55dfcf
--- /dev/null
+++ b/kernel/include/rbtree.h
@@ -0,0 +1,146 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea@suse.de>
+  
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  linux/include/linux/rbtree.h
+  To use rbtrees you'll have to implement your own insert and search cores.
+  This will avoid us to use callbacks and to drop drammatically performances.
+  I know it's not the cleaner way,  but in C (not in C++) to get
+  performances and genericity...
+  Some example of insert and search follows here. The search is a plain
+  normal search over an ordered tree. The insert instead must be implemented
+  int two steps: as first thing the code must insert the element in
+  order as a red leaf in the tree, then the support library function
+  rb_insert_color() must be called. Such function will do the
+  not trivial work to rebalance the rbtree if necessary.
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+						 unsigned long offset)
+{
+	struct rb_node * n = inode->i_rb_page_cache.rb_node;
+	struct page * page;
+	while (n)
+	{
+		page = rb_entry(n, struct page, rb_page_cache);
+		if (offset < page->offset)
+			n = n->rb_left;
+		else if (offset > page->offset)
+			n = n->rb_right;
+		else
+			return page;
+	}
+	return NULL;
+}
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+						   unsigned long offset,
+						   struct rb_node * node)
+{
+	struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+	struct rb_node * parent = NULL;
+	struct page * page;
+	while (*p)
+	{
+		parent = *p;
+		page = rb_entry(parent, struct page, rb_page_cache);
+		if (offset < page->offset)
+			p = &(*p)->rb_left;
+		else if (offset > page->offset)
+			p = &(*p)->rb_right;
+		else
+			return page;
+	}
+	rb_link_node(node, parent, p);
+	return NULL;
+}
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+						 unsigned long offset,
+						 struct rb_node * node)
+{
+	struct page * ret;
+	if ((ret = __rb_insert_page_cache(inode, offset, node)))
+		goto out;
+	rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+	return ret;
+}
+-----------------------------------------------------------------------
+*/
+ 
+#ifndef	_LINUX_RBTREE_H
+#define	_LINUX_RBTREE_H
+ 
+#include<include/types.h>
+ 
+struct rb_node
+{
+	unsigned long  rb_parent_color;
+#define	RB_RED		0
+#define	RB_BLACK	1
+	struct rb_node *rb_right;
+	struct rb_node *rb_left;
+} __attribute__((aligned(sizeof(long))));
+    /* The alignment might seem pointless, but allegedly CRIS needs it */
+ 
+struct rb_root
+{
+	struct rb_node *rb_node;
+};
+ 
+ 
+#define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))
+#define rb_color(r)   ((r)->rb_parent_color & 1)
+#define rb_is_red(r)   (!rb_color(r))
+#define rb_is_black(r) rb_color(r)
+#define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)
+#define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)
+ 
+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+	rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
+}
+static inline void rb_set_color(struct rb_node *rb, int color)
+{
+	rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
+}
+ 
+#define RB_ROOT	(struct rb_root) { NULL, }
+#define	rb_entry(ptr, type, member) container_of(ptr, type, member)
+ 
+#define RB_EMPTY_ROOT(root)	((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node)	(rb_parent(node) == node)
+#define RB_CLEAR_NODE(node)	(rb_set_parent(node, node))
+ 
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+ 
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(const struct rb_node *);
+extern struct rb_node *rb_prev(const struct rb_node *);
+extern struct rb_node *rb_first(const struct rb_root *);
+extern struct rb_node *rb_last(const struct rb_root *);
+ 
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 
+			    struct rb_root *root);
+ 
+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
+				struct rb_node ** rb_link)
+{
+	node->rb_parent_color = (unsigned long )parent;
+	node->rb_left = node->rb_right = NULL;
+ 
+	*rb_link = node;
+}
+ 
+#endif	/* _LINUX_RBTREE_H */
\ No newline at end of file
diff --git a/kernel/include/riscv.h b/kernel/include/riscv.h
new file mode 100644
index 0000000000000000000000000000000000000000..1196d9a991a7e3ce521c8e966e5953549b1b75d3
--- /dev/null
+++ b/kernel/include/riscv.h
@@ -0,0 +1,434 @@
+#ifndef __RISCV_H
+#define __RISCV_H
+#include "memlayout.h"
+// which hart (core) is this?
+static inline uint64
+r_mhartid()
+{
+  uint64 x;
+  asm volatile("csrr %0, mhartid" : "=r" (x) );
+  return x;
+}
+
+// Machine Status Register, mstatus
+
+#define MSTATUS_MPP_MASK (3L << 11) // previous mode.
+#define MSTATUS_MPP_M (3L << 11)
+#define MSTATUS_MPP_S (1L << 11)
+#define MSTATUS_MPP_U (0L << 11)
+#define MSTATUS_MIE (1L << 3)    // machine-mode interrupt enable.
+
+
+#define CLINT                   0x02000000L
+#define CLINT_V                 (CLINT + VIRT_OFFSET)
+#define CLINT_MTIME             (CLINT_V + 0xBFF8)
+
+static inline uint64 readtime()
+{
+	uint64 x;
+	x = *(uint64 *)CLINT_MTIME;
+	return x;
+}
+
+static inline uint64
+r_mstatus()
+{
+  uint64 x;
+  asm volatile("csrr %0, mstatus" : "=r" (x) );
+  return x;
+}
+
+static inline void 
+w_mstatus(uint64 x)
+{
+  asm volatile("csrw mstatus, %0" : : "r" (x));
+}
+
+// machine exception program counter, holds the
+// instruction address to which a return from
+// exception will go.
+static inline void 
+w_mepc(uint64 x)
+{
+  asm volatile("csrw mepc, %0" : : "r" (x));
+}
+
+// Supervisor Status Register, sstatus
+
+#define SSTATUS_SPP (1L << 8)  // Previous mode, 1=Supervisor, 0=User
+#define SSTATUS_SPIE (1L << 5) // Supervisor Previous Interrupt Enable
+#define SSTATUS_UPIE (1L << 4) // User Previous Interrupt Enable
+#define SSTATUS_SIE (1L << 1)  // Supervisor Interrupt Enable
+#define SSTATUS_UIE (1L << 0)  // User Interrupt Enable
+
+static inline uint64
+r_sstatus()
+{
+  uint64 x;
+  asm volatile("csrr %0, sstatus" : "=r" (x) );
+  return x;
+}
+
+static inline void 
+w_sstatus(uint64 x)
+{
+  asm volatile("csrw sstatus, %0" : : "r" (x));
+}
+
+// Supervisor Interrupt Pending
+static inline uint64
+r_sip()
+{
+  uint64 x;
+  asm volatile("csrr %0, sip" : "=r" (x) );
+  return x;
+}
+
+static inline void 
+w_sip(uint64 x)
+{
+  asm volatile("csrw sip, %0" : : "r" (x));
+}
+
+// Supervisor Interrupt Enable
+#define SIE_SEIE (1L << 9) // external
+#define SIE_STIE (1L << 5) // timer
+#define SIE_SSIE (1L << 1) // software
+static inline uint64
+r_sie()
+{
+  uint64 x;
+  asm volatile("csrr %0, sie" : "=r" (x) );
+  return x;
+}
+
+static inline void 
+w_sie(uint64 x)
+{
+  asm volatile("csrw sie, %0" : : "r" (x));
+}
+
+// Machine-mode Interrupt Enable
+#define MIE_MEIE (1L << 11) // external
+#define MIE_MTIE (1L << 7)  // timer
+#define MIE_MSIE (1L << 3)  // software
+static inline uint64
+r_mie()
+{
+  uint64 x;
+  asm volatile("csrr %0, mie" : "=r" (x) );
+  return x;
+}
+
+static inline void 
+w_mie(uint64 x)
+{
+  asm volatile("csrw mie, %0" : : "r" (x));
+}
+
+// machine exception program counter, holds the
+// instruction address to which a return from
+// exception will go.
+static inline void 
+w_sepc(uint64 x)
+{
+  asm volatile("csrw sepc, %0" : : "r" (x));
+}
+
+static inline uint64
+r_sepc()
+{
+  uint64 x;
+  asm volatile("csrr %0, sepc" : "=r" (x) );
+  return x;
+}
+
+// Machine Exception Delegation
+static inline uint64
+r_medeleg()
+{
+  uint64 x;
+  asm volatile("csrr %0, medeleg" : "=r" (x) );
+  return x;
+}
+
+static inline void 
+w_medeleg(uint64 x)
+{
+  asm volatile("csrw medeleg, %0" : : "r" (x));
+}
+
+// Machine Interrupt Delegation
+static inline uint64
+r_mideleg()
+{
+  uint64 x;
+  asm volatile("csrr %0, mideleg" : "=r" (x) );
+  return x;
+}
+
+static inline void 
+w_mideleg(uint64 x)
+{
+  asm volatile("csrw mideleg, %0" : : "r" (x));
+}
+
+// Supervisor Trap-Vector Base Address
+// low two bits are mode.
+static inline void 
+w_stvec(uint64 x)
+{
+  asm volatile("csrw stvec, %0" : : "r" (x));
+}
+
+static inline uint64
+r_stvec()
+{
+  uint64 x;
+  asm volatile("csrr %0, stvec" : "=r" (x) );
+  return x;
+}
+
+// Machine-mode interrupt vector
+static inline void 
+w_mtvec(uint64 x)
+{
+  asm volatile("csrw mtvec, %0" : : "r" (x));
+}
+
+// use riscv's sv39 page table scheme.
+#define SATP_SV39 (8L << 60)
+
+#define MAKE_SATP(pagetable) (SATP_SV39 | (((uint64)pagetable) >> 12))
+
+// supervisor address translation and protection;
+// holds the address of the page table.
+static inline void 
+w_satp(uint64 x)
+{
+  asm volatile("csrw satp, %0" : : "r" (x));
+}
+
+static inline uint64
+r_satp()
+{
+  uint64 x;
+  asm volatile("csrr %0, satp" : "=r" (x) );
+  return x;
+}
+
+// Supervisor Scratch register, for early trap handler in trampoline.S.
+static inline void 
+w_sscratch(uint64 x)
+{
+  asm volatile("csrw sscratch, %0" : : "r" (x));
+}
+
+static inline void 
+w_mscratch(uint64 x)
+{
+  asm volatile("csrw mscratch, %0" : : "r" (x));
+}
+
+// Supervisor Trap Cause
+static inline uint64
+r_scause()
+{
+  uint64 x;
+  asm volatile("csrr %0, scause" : "=r" (x) );
+  return x;
+}
+
+// Supervisor Trap Value
+static inline uint64
+r_stval()
+{
+  uint64 x;
+  asm volatile("csrr %0, stval" : "=r" (x) );
+  return x;
+}
+
+// Machine-mode Counter-Enable
+static inline void 
+w_mcounteren(uint64 x)
+{
+  asm volatile("csrw mcounteren, %0" : : "r" (x));
+}
+
+static inline uint64
+r_mcounteren()
+{
+  uint64 x;
+  asm volatile("csrr %0, mcounteren" : "=r" (x) );
+  return x;
+}
+
+// supervisor-mode cycle counter
+static inline uint64
+r_time()
+{
+  uint64 x;
+  // asm volatile("csrr %0, time" : "=r" (x) );
+  // this instruction will trap in SBI
+  asm volatile("rdtime %0" : "=r" (x) );
+  return x;
+}
+
+// enable device interrupts
+static inline void
+intr_on()
+{
+  w_sstatus(r_sstatus() | SSTATUS_SIE);
+}
+
+// disable device interrupts
+static inline void
+intr_off()
+{
+  w_sstatus(r_sstatus() & ~SSTATUS_SIE);
+}
+
+// are device interrupts enabled?
+static inline int
+intr_get()
+{
+  uint64 x = r_sstatus();
+  return (x & SSTATUS_SIE) != 0;
+}
+
+static inline uint64
+r_sp()
+{
+  uint64 x;
+  asm volatile("mv %0, sp" : "=r" (x) );
+  return x;
+}
+
+// read and write tp, the thread pointer, which holds
+// this core's hartid (core number), the index into cpus[].
+static inline uint64
+r_tp()
+{
+  uint64 x;
+  asm volatile("mv %0, tp" : "=r" (x) );
+  return x;
+}
+
+static inline void 
+w_tp(uint64 x)
+{
+  asm volatile("mv tp, %0" : : "r" (x));
+}
+
+static inline uint64
+r_ra()
+{
+  uint64 x;
+  asm volatile("mv %0, ra" : "=r" (x) );
+  return x;
+}
+
+static inline uint64
+r_fp()
+{
+  uint64 x;
+  asm volatile("mv %0, s0" : "=r" (x) );
+  return x;
+}
+
+// flush the TLB.
+static inline void
+sfence_vma()
+{
+  // the zero, zero means flush all TLB entries.
+  // asm volatile("sfence.vma zero, zero");
+  //asm volatile("sfence.vma");
+  asm volatile("fence");
+  asm volatile("fence.i");
+  asm volatile("sfence.vma");
+  asm volatile("fence");
+  asm volatile("fence.i");
+}
+
+
+#define PGSIZE 4096 // bytes per page
+#define PGSHIFT 12  // bits of offset within a page
+
+#define PGROUNDUP(sz)  (((sz)+PGSIZE-1) & ~(PGSIZE-1))
+#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1))
+#define PAGE_OFFSET(x, y) ((x) & ((y)-1))
+#define DOWN_ALIGN(x, y) (((uint64)(x)) & (~((uint64)((y)-1))))
+#define UP_ALIGN(x, y) (DOWN_ALIGN((x)-1, (y)) + (y))
+
+#define PTE_V (1L << 0) // valid
+#define PTE_R (1L << 1)
+#define PTE_W (1L << 2)
+#define PTE_X (1L << 3)
+#define PTE_U (1L << 4) // 1 -> user can access
+#define PTE_D (1L << 7)
+#define PTE_C (1L << 8) // copy when write
+
+// shift a physical address to the right place for a PTE.
+#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
+
+#define PTE2PA(pte) (((pte) >> 10) << 12)
+
+#define PTE_FLAGS(pte) ((pte) & 0x3FF)
+
+// extract the three 9-bit page table indices from a virtual address.
+#define PXMASK          0x1FF // 9 bits
+#define PXSHIFT(level)  (PGSHIFT+(9*(level)))
+#define PX(level, va) ((((uint64) (va)) >> PXSHIFT(level)) & PXMASK)
+
+// one beyond the highest possible virtual address.
+// MAXVA is actually one bit less than the max allowed by
+// Sv39, to avoid having to sign-extend virtual addresses
+// that have the high bit set.
+#define MAXVA (1L << (9 + 9 + 9 + 12 - 1))
+
+typedef uint64 pte_t;
+typedef uint64 *pagetable_t; // 512 PTEs
+
+/**
+ * RISC-V floating-point control and status register
+ */
+
+#define SSTATUS_FS_INIT		(1L << 13)
+#define SSTATUS_FS_CLEAN	(2L << 13)
+#define SSTATUS_FS_DIRTY	(3L << 13)
+#define SSTATUS_FS_BITS		(3L << 13)
+
+#define FRM_RNE		0
+#define FRM_RTZ		1
+#define FRM_RDN		2
+#define FRM_RUP		3
+#define FRM_RMM		4
+
+// set floating-point rounding mode
+static inline void w_frm(uint x)
+{
+	asm volatile("fsrm %0" : : "r" (x));
+}
+
+static inline uint64 r_sstatus_fs()
+{
+	return r_sstatus() & SSTATUS_FS_BITS;
+}
+
+static inline void w_sstatus_fs(uint64 bits)
+{
+	uint64 status = r_sstatus() & ~SSTATUS_FS_BITS;
+	w_sstatus(status | (bits & SSTATUS_FS_BITS));
+}
+
+// init floating-point unit
+static inline void floatinithart()
+{
+	// If sstatus.fs is off, floating-point instructions
+	// will be treated as illegal ones.
+	w_sstatus_fs(SSTATUS_FS_INIT);
+	w_frm(FRM_RNE);
+	w_sstatus_fs(SSTATUS_FS_CLEAN);
+}
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/sbi.h b/kernel/include/sbi.h
new file mode 100644
index 0000000000000000000000000000000000000000..3a0cc6ffb381c942cb16c6dfbd4beda4f2295581
--- /dev/null
+++ b/kernel/include/sbi.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2015 Regents of the University of California
+ */
+
+#ifndef _ASM_RISCV_SBI_H
+#define _ASM_RISCV_SBI_H
+
+
+
+#define SBI_SET_TIMER 0
+#define SBI_CONSOLE_PUTCHAR 1
+#define SBI_CONSOLE_GETCHAR 2
+#define SBI_CLEAR_IPI 3
+#define SBI_SEND_IPI 4
+#define SBI_REMOTE_FENCE_I 5
+#define SBI_REMOTE_SFENCE_VMA 6
+#define SBI_REMOTE_SFENCE_VMA_ASID 7
+#define SBI_SHUTDOWN 8
+
+#define SBI_CALL(which, arg0, arg1, arg2, arg3) ({		\
+	register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);	\
+	register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);	\
+	register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);	\
+	register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);	\
+	register uintptr_t a7 asm ("a7") = (uintptr_t)(which);	\
+	asm volatile ("ecall"					\
+		      : "+r" (a0)				\
+		      : "r" (a1), "r" (a2), "r" (a3), "r" (a7)	\
+		      : "memory");				\
+	a0;							\
+})
+
+/* Lazy implementations until SBI is finalized */
+#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0, 0)
+#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0, 0)
+#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0, 0)
+#define SBI_CALL_3(which, arg0, arg1, arg2) \
+		SBI_CALL(which, arg0, arg1, arg2, 0)
+#define SBI_CALL_4(which, arg0, arg1, arg2, arg3) \
+		SBI_CALL(which, arg0, arg1, arg2, arg3)
+
+static inline void sbi_console_putchar(int ch)
+{
+	SBI_CALL_1(SBI_CONSOLE_PUTCHAR, ch);
+}
+
+static inline int sbi_console_getchar(void)
+{
+	return SBI_CALL_0(SBI_CONSOLE_GETCHAR);
+}
+
+static inline void sbi_set_timer(uint64 stime_value)
+{
+	SBI_CALL_1(SBI_SET_TIMER, stime_value);
+}
+
+static inline void sbi_shutdown(void)
+{
+	SBI_CALL_0(SBI_SHUTDOWN);
+}
+
+static inline void sbi_clear_ipi(void)
+{
+	SBI_CALL_0(SBI_CLEAR_IPI);
+}
+
+static inline void sbi_send_ipi(const unsigned long *hart_mask)
+{
+	SBI_CALL_1(SBI_SEND_IPI, hart_mask);
+}
+
+static inline void sbi_remote_fence_i(const unsigned long *hart_mask)
+{
+	SBI_CALL_1(SBI_REMOTE_FENCE_I, hart_mask);
+}
+
+static inline void sbi_remote_sfence_vma(const unsigned long *hart_mask,
+					 unsigned long start,
+					 unsigned long size)
+{
+	SBI_CALL_3(SBI_REMOTE_SFENCE_VMA, hart_mask, start, size);
+}
+
+static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
+					      unsigned long start,
+					      unsigned long size,
+					      unsigned long asid)
+{
+	SBI_CALL_4(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask, start, size, asid);
+}
+
+static inline void sbi_set_extern_interrupt(unsigned long func_pointer) {
+	asm volatile("mv a6, %0" : : "r" (0x210));
+	SBI_CALL_1(0x0A000004, func_pointer);
+}
+
+static inline void sbi_set_mie(void) {
+	SBI_CALL_0(0x0A000005);
+}
+
+#endif
diff --git a/kernel/include/sdcard.h b/kernel/include/sdcard.h
new file mode 100644
index 0000000000000000000000000000000000000000..7fa417ef0f8fc04a9cb46f952270a64fdf3f5262
--- /dev/null
+++ b/kernel/include/sdcard.h
@@ -0,0 +1,12 @@
+#ifndef __SDCARD_H
+#define __SDCARD_H
+
+void sdcard_init(void);
+
+void sdcard_read_sector(uint8 *buf, int sectorno);
+
+void sdcard_write_sector(uint8 *buf, int sectorno);
+
+void test_sdcard(void);
+
+#endif 
diff --git a/kernel/include/signal.h b/kernel/include/signal.h
new file mode 100644
index 0000000000000000000000000000000000000000..825822e5368e7c26b546ed3255a0da1a5f98e7c0
--- /dev/null
+++ b/kernel/include/signal.h
@@ -0,0 +1,72 @@
+#ifndef __SIGNAL_H
+#define __SIGNAL_H
+
+#include "types.h"
+
+#define SIG_BLOCK     0
+#define SIG_UNBLOCK   1
+#define SIG_SETMASK   2
+
+#define N_SIG      65
+
+#define SIGHUP     1
+#define SIGINT     2
+#define SIGQUIT    3
+#define SIGILL     4
+#define SIGTRAP    5
+#define SIGABRT    6
+#define SIGIOT     SIGABRT
+#define SIGBUS     7
+#define SIGFPE     8
+#define SIGKILL    9
+#define SIGUSR1   10
+#define SIGSEGV   11
+#define SIGUSR2   12
+#define SIGPIPE   13
+#define SIGALRM   14
+#define SIGTERM   15
+#define SIGSTKFLT 16
+#define SIGCHLD   17
+#define SIGCONT   18
+#define SIGSTOP   19
+#define SIGTSTP   20
+#define SIGTTIN   21
+#define SIGTTOU   22
+#define SIGURG    23
+#define SIGXCPU   24
+#define SIGXFSZ   25
+#define SIGVTALRM 26
+#define SIGPROF   27
+#define SIGWINCH  28
+#define SIGIO     29
+#define SIGPOLL   SIGIO
+#define SIGPWR    30
+#define SIGSYS    31
+#define SIGUNUSED SIGSYS
+
+#define _NSIG     65
+
+#define SA_UNSUPPORTED 0x00000400
+#define SA_EXPOSE_TAGBITS 0x00000800
+
+#define SA_NOCLDSTOP 1
+#define SA_NOCLDWAIT 2
+#define SA_SIGINFO   4
+#define SA_ONSTACK   0x08000000
+#define SA_RESTART   0x10000000
+#define SA_NODEFER   0x40000000
+#define SA_RESETHAND 0x80000000
+#define SA_RESTORER  0x04000000
+
+int sigaction(int, struct sigaction *act);
+void sigadd(sigset_t *a, sigset_t *b);
+void sigsub(sigset_t *a, sigset_t *b);
+int sigprocmask(int how, sigset_t *set);
+int sigfind(sigset_t *a, sigset_t *b);
+void do_act();
+int sendsignal(int pid, int signum);
+int testsig(sigset_t *set, int signum);
+void sigreset(sigset_t *set, int signum);
+void sigset(sigset_t *set, int signum);
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/sleeplock.h b/kernel/include/sleeplock.h
new file mode 100644
index 0000000000000000000000000000000000000000..b622c4e74d33b72ecf65ce0553552b03e0ebc65f
--- /dev/null
+++ b/kernel/include/sleeplock.h
@@ -0,0 +1,24 @@
+#ifndef __SLEEPLOCK_H
+#define __SLEEPLOCK_H
+
+#include "types.h"
+#include "spinlock.h"
+
+struct spinlock;
+
+// Long-term locks for processes
+struct sleeplock {
+  uint locked;       // Is the lock held?
+  struct spinlock lk; // spinlock protecting this sleep lock
+  
+  // For debugging:
+  char *name;        // Name of lock.
+  int pid;           // Process holding lock
+};
+
+void            acquiresleep(struct sleeplock*);
+void            releasesleep(struct sleeplock*);
+int             holdingsleep(struct sleeplock*);
+void            initsleeplock(struct sleeplock*, char*);
+
+#endif
diff --git a/kernel/include/spi.h b/kernel/include/spi.h
new file mode 100644
index 0000000000000000000000000000000000000000..fdf62bd2af94ba5fe5910ab5cc7d1f415ce3d8d4
--- /dev/null
+++ b/kernel/include/spi.h
@@ -0,0 +1,492 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _DRIVER_SPI_H
+#define _DRIVER_SPI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clang-format off */
+typedef struct _spi
+{
+    /* SPI Control Register 0                                    (0x00)*/
+    volatile uint32 ctrlr0;
+    /* SPI Control Register 1                                    (0x04)*/
+    volatile uint32 ctrlr1;
+    /* SPI Enable Register                                       (0x08)*/
+    volatile uint32 ssienr;
+    /* SPI Microwire Control Register                            (0x0c)*/
+    volatile uint32 mwcr;
+    /* SPI Slave Enable Register                                 (0x10)*/
+    volatile uint32 ser;
+    /* SPI Baud Rate Select                                      (0x14)*/
+    volatile uint32 baudr;
+    /* SPI Transmit FIFO Threshold Level                         (0x18)*/
+    volatile uint32 txftlr;
+    /* SPI Receive FIFO Threshold Level                          (0x1c)*/
+    volatile uint32 rxftlr;
+    /* SPI Transmit FIFO Level Register                          (0x20)*/
+    volatile uint32 txflr;
+    /* SPI Receive FIFO Level Register                           (0x24)*/
+    volatile uint32 rxflr;
+    /* SPI Status Register                                       (0x28)*/
+    volatile uint32 sr;
+    /* SPI Interrupt Mask Register                               (0x2c)*/
+    volatile uint32 imr;
+    /* SPI Interrupt Status Register                             (0x30)*/
+    volatile uint32 isr;
+    /* SPI Raw Interrupt Status Register                         (0x34)*/
+    volatile uint32 risr;
+    /* SPI Transmit FIFO Overflow Interrupt Clear Register       (0x38)*/
+    volatile uint32 txoicr;
+    /* SPI Receive FIFO Overflow Interrupt Clear Register        (0x3c)*/
+    volatile uint32 rxoicr;
+    /* SPI Receive FIFO Underflow Interrupt Clear Register       (0x40)*/
+    volatile uint32 rxuicr;
+    /* SPI Multi-Master Interrupt Clear Register                 (0x44)*/
+    volatile uint32 msticr;
+    /* SPI Interrupt Clear Register                              (0x48)*/
+    volatile uint32 icr;
+    /* SPI DMA Control Register                                  (0x4c)*/
+    volatile uint32 dmacr;
+    /* SPI DMA Transmit Data Level                               (0x50)*/
+    volatile uint32 dmatdlr;
+    /* SPI DMA Receive Data Level                                (0x54)*/
+    volatile uint32 dmardlr;
+    /* SPI Identification Register                               (0x58)*/
+    volatile uint32 idr;
+    /* SPI DWC_ssi component version                             (0x5c)*/
+    volatile uint32 ssic_version_id;
+    /* SPI Data Register 0-36                                    (0x60 -- 0xec)*/
+    volatile uint32 dr[36];
+    /* SPI RX Sample Delay Register                              (0xf0)*/
+    volatile uint32 rx_sample_delay;
+    /* SPI SPI Control Register                                  (0xf4)*/
+    volatile uint32 spi_ctrlr0;
+    /* reserved                                                  (0xf8)*/
+    volatile uint32 resv;
+    /* SPI XIP Mode bits                                         (0xfc)*/
+    volatile uint32 xip_mode_bits;
+    /* SPI XIP INCR transfer opcode                              (0x100)*/
+    volatile uint32 xip_incr_inst;
+    /* SPI XIP WRAP transfer opcode                              (0x104)*/
+    volatile uint32 xip_wrap_inst;
+    /* SPI XIP Control Register                                  (0x108)*/
+    volatile uint32 xip_ctrl;
+    /* SPI XIP Slave Enable Register                             (0x10c)*/
+    volatile uint32 xip_ser;
+    /* SPI XIP Receive FIFO Overflow Interrupt Clear Register    (0x110)*/
+    volatile uint32 xrxoicr;
+    /* SPI XIP time out register for continuous transfers        (0x114)*/
+    volatile uint32 xip_cnt_time_out;
+    volatile uint32 endian;
+} __attribute__((packed, aligned(4))) spi_t;
+/* clang-format on */
+
+typedef enum _spi_device_num
+{
+    SPI_DEVICE_0,
+    SPI_DEVICE_1,
+    SPI_DEVICE_2,
+    SPI_DEVICE_3,
+    SPI_DEVICE_MAX,
+} spi_device_num_t;
+
+typedef enum _spi_work_mode
+{
+    SPI_WORK_MODE_0,
+    SPI_WORK_MODE_1,
+    SPI_WORK_MODE_2,
+    SPI_WORK_MODE_3,
+} spi_work_mode_t;
+
+typedef enum _spi_frame_format
+{
+    SPI_FF_STANDARD,
+    SPI_FF_DUAL,
+    SPI_FF_QUAD,
+    SPI_FF_OCTAL
+} spi_frame_format_t;
+
+typedef enum _spi_instruction_address_trans_mode
+{
+    SPI_AITM_STANDARD,
+    SPI_AITM_ADDR_STANDARD,
+    SPI_AITM_AS_FRAME_FORMAT
+} spi_instruction_address_trans_mode_t;
+
+typedef enum _spi_transfer_mode
+{
+    SPI_TMOD_TRANS_RECV,
+    SPI_TMOD_TRANS,
+    SPI_TMOD_RECV,
+    SPI_TMOD_EEROM
+} spi_transfer_mode_t;
+
+typedef enum _spi_transfer_width
+{
+    SPI_TRANS_CHAR = 0x1,
+    SPI_TRANS_SHORT = 0x2,
+    SPI_TRANS_INT = 0x4,
+} spi_transfer_width_t;
+
+typedef enum _spi_chip_select
+{
+    SPI_CHIP_SELECT_0,
+    SPI_CHIP_SELECT_1,
+    SPI_CHIP_SELECT_2,
+    SPI_CHIP_SELECT_3,
+    SPI_CHIP_SELECT_MAX,
+} spi_chip_select_t;
+
+typedef enum
+{
+    WRITE_CONFIG,
+    READ_CONFIG,
+    WRITE_DATA_BYTE,
+    READ_DATA_BYTE,
+    WRITE_DATA_BLOCK,
+    READ_DATA_BLOCK,
+} spi_slave_command_e;
+
+typedef struct
+{
+    uint8 cmd;
+    uint8 err;
+    uint32 addr;
+    uint32 len;
+} spi_slave_command_t;
+
+typedef enum
+{
+    IDLE,
+    COMMAND,
+    TRANSFER,
+} spi_slave_status_e;
+
+typedef int (*spi_slave_receive_callback_t)(void *ctx);
+
+// typedef struct _spi_slave_instance
+// {
+//     uint8 int_pin;
+//     uint8 ready_pin;
+//     dmac_channel_number_t dmac_channel;
+//     uint8 dfs;
+//     uint8 slv_oe;
+//     uint8 work_mode;
+//     uint64 data_bit_length;
+//     volatile spi_slave_status_e status;
+//     volatile spi_slave_command_t command;
+//     volatile uint8 *config_ptr;
+//     uint32 config_len;
+//     spi_slave_receive_callback_t callback;
+//     uint8 is_dual;
+//     uint8 mosi_pin;
+//     uint8 miso_pin;
+// } spi_slave_instance_t;
+
+// typedef struct _spi_data_t
+// {
+//     dmac_channel_number_t tx_channel;
+//     dmac_channel_number_t rx_channel;
+//     uint32 *tx_buf;
+//     uint64 tx_len;
+//     uint32 *rx_buf;
+//     uint64 rx_len;
+//     spi_transfer_mode_t transfer_mode;
+//     bool fill_mode;
+// } spi_data_t;
+
+extern volatile spi_t *const spi[4];
+
+/**
+ * @brief       Set spi configuration
+ *
+ * @param[in]   spi_num             Spi bus number
+ * @param[in]   mode                Spi mode
+ * @param[in]   frame_format        Spi frame format
+ * @param[in]   data_bit_length     Spi data bit length
+ * @param[in]   endian              0:little-endian 1:big-endian
+ *
+ * @return      Void
+ */
+void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,
+              uint64 data_bit_length, uint32 endian);
+
+/**
+ * @brief       Set multiline configuration
+ *
+ * @param[in]   spi_num                                 Spi bus number
+ * @param[in]   instruction_length                      Instruction length
+ * @param[in]   address_length                          Address length
+ * @param[in]   wait_cycles                             Wait cycles
+ * @param[in]   instruction_address_trans_mode          Spi transfer mode
+ *
+ */
+void spi_init_non_standard(spi_device_num_t spi_num, uint32 instruction_length, uint32 address_length,
+                           uint32 wait_cycles, spi_instruction_address_trans_mode_t instruction_address_trans_mode);
+
+/**
+ * @brief       Spi send data
+ *
+ * @param[in]   spi_num         Spi bus number
+ * @param[in]   chip_select     Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         Spi command length
+ * @param[in]   tx_buff         Spi transmit buffer point
+ * @param[in]   tx_len          Spi transmit buffer length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
+                            uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len);
+
+/**
+ * @brief       Spi receive data
+ *
+ * @param[in]   spi_num             Spi bus number
+ * @param[in]   chip_select         Spi chip select
+ * @param[in]   cmd_buff            Spi command buffer point
+ * @param[in]   cmd_len             Spi command length
+ * @param[in]   rx_buff             Spi receive buffer point
+ * @param[in]   rx_len              Spi receive buffer length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
+                               uint64 cmd_len, uint8 *rx_buff, uint64 rx_len);
+
+/**
+ * @brief       Spi special receive data
+ *
+ * @param[in]   spi_num         Spi bus number
+ * @param[in]   chip_select     Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         Spi command length
+ * @param[in]   rx_buff         Spi receive buffer point
+ * @param[in]   rx_len          Spi receive buffer length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+void spi_receive_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32 *cmd_buff,
+                               uint64 cmd_len, uint8 *rx_buff, uint64 rx_len);
+
+/**
+ * @brief       Spi special send data
+ *
+ * @param[in]   spi_num         Spi bus number
+ * @param[in]   chip_select     Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         Spi command length
+ * @param[in]   tx_buff         Spi transmit buffer point
+ * @param[in]   tx_len          Spi transmit buffer length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+void spi_send_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32 *cmd_buff,
+                            uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len);
+
+/**
+ * @brief       Spi send data by dma
+ *
+ * @param[in]   channel_num     Dmac channel number
+ * @param[in]   spi_num         Spi bus number
+ * @param[in]   chip_select     Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         Spi command length
+ * @param[in]   tx_buff         Spi transmit buffer point
+ * @param[in]   tx_len          Spi transmit buffer length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num,
+                                spi_chip_select_t chip_select,
+                                const uint8 *cmd_buff, uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len);
+
+/**
+ * @brief       Spi receive data by dma
+ *
+ * @param[in]   w_channel_num       Dmac write channel number
+ * @param[in]   r_channel_num       Dmac read channel number
+ * @param[in]   spi_num             Spi bus number
+ * @param[in]   chip_select         Spi chip select
+ * @param[in]   cmd_buff            Spi command buffer point
+ * @param[in]   cmd_len             Spi command length
+ * @param[in]   rx_buff             Spi receive buffer point
+ * @param[in]   rx_len              Spi receive buffer length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num,
+                                   dmac_channel_number_t dma_receive_channel_num,
+                                   spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
+                                   uint64 cmd_len, uint8 *rx_buff, uint64 rx_len);
+
+/**
+ * @brief       Spi special send data by dma
+ *
+ * @param[in]   channel_num     Dmac channel number
+ * @param[in]   spi_num         Spi bus number
+ * @param[in]   chip_select     Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         Spi command length
+ * @param[in]   tx_buff         Spi transmit buffer point
+ * @param[in]   tx_len          Spi transmit buffer length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+// void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num,
+//                                 spi_chip_select_t chip_select,
+//                                 const uint32 *cmd_buff, uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len);
+
+/**
+ * @brief       Spi special receive data by dma
+ *
+ * @param[in]   dma_send_channel_num        Dmac write channel number
+ * @param[in]   dma_receive_channel_num     Dmac read channel number
+ * @param[in]   spi_num                     Spi bus number
+ * @param[in]   chip_select                 Spi chip select
+ * @param[in]   cmd_buff                    Spi command buffer point
+ * @param[in]   cmd_len                     Spi command length
+ * @param[in]   rx_buff                     Spi receive buffer point
+ * @param[in]   rx_len                      Spi receive buffer length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+// void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num,
+//                                    dmac_channel_number_t dma_receive_channel_num,
+//                                    spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32 *cmd_buff,
+//                                    uint64 cmd_len, uint8 *rx_buff, uint64 rx_len);
+
+/**
+ * @brief       Spi fill dma
+ *
+ * @param[in]   channel_num     Dmac channel number
+ * @param[in]   spi_num         Spi bus number
+ * @param[in]   chip_select     Spi chip select
+ * @param[in]   tx_buff        Spi command buffer point
+ * @param[in]   tx_len         Spi command length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+// void spi_fill_data_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select,
+//                        const uint32 *tx_buff, uint64 tx_len);
+
+/**
+ * @brief       Spi normal send by dma
+ *
+ * @param[in]   channel_num     Dmac channel number
+ * @param[in]   spi_num         Spi bus number
+ * @param[in]   chip_select     Spi chip select
+ * @param[in]   tx_buff         Spi transmit buffer point
+ * @param[in]   tx_len          Spi transmit buffer length
+ * @param[in]   stw             Spi transfer width
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num,
+                              spi_chip_select_t chip_select,
+                              const void *tx_buff, uint64 tx_len, spi_transfer_width_t spi_transfer_width);
+
+/**
+ * @brief       Spi normal send by dma
+ *
+ * @param[in]   spi_num         Spi bus number
+ * @param[in]   spi_clk         Spi clock rate
+ *
+ * @return      The real spi clock rate
+ */
+uint32 spi_set_clk_rate(spi_device_num_t spi_num, uint32 spi_clk);
+
+/**
+ * @brief       Spi full duplex send receive data by dma
+ *
+ * @param[in]   dma_send_channel_num          Dmac write channel number
+ * @param[in]   dma_receive_channel_num       Dmac read channel number
+ * @param[in]   spi_num                       Spi bus number
+ * @param[in]   chip_select                   Spi chip select
+ * @param[in]   tx_buf                        Spi send buffer
+ * @param[in]   tx_len                        Spi send buffer length
+ * @param[in]   rx_buf                        Spi receive buffer
+ * @param[in]   rx_len                        Spi receive buffer length
+ *
+ */
+// void spi_dup_send_receive_data_dma(dmac_channel_number_t dma_send_channel_num,
+//                                    dmac_channel_number_t dma_receive_channel_num,
+//                                    spi_device_num_t spi_num, spi_chip_select_t chip_select,
+//                                    const uint8 *tx_buf, uint64 tx_len, uint8 *rx_buf, uint64 rx_len);
+
+/**
+ * @brief       Set spi slave configuration
+ *
+ * @param[in]   int_pin             SPI master starts sending data interrupt.
+ * @param[in]   ready_pin           SPI slave ready.
+ * @param[in]   dmac_channel        Dmac channel number for block.
+ * @param[in]   data_bit_length     Spi data bit length
+ * @param[in]   data                SPI slave device data buffer.
+ * @param[in]   len                 The length of SPI slave device data buffer.
+ * @param[in]   callback            Callback of spi slave.
+ *
+ * @return      Void
+ */
+// void spi_slave_config(uint8 int_pin, uint8 ready_pin, dmac_channel_number_t dmac_channel, uint64 data_bit_length, uint8 *data, uint32 len, spi_slave_receive_callback_t callback);
+
+// void spi_slave_dual_config(uint8 int_pin,
+//                            uint8 ready_pin,
+//                            uint8 mosi_pin,
+//                            uint8 miso_pin,
+//                            dmac_channel_number_t dmac_channel,
+//                            uint64 data_bit_length,
+//                            uint8 *data,
+//                            uint32 len,
+//                            spi_slave_receive_callback_t callback);
+
+/**
+ * @brief       Spi handle transfer data operations
+ *
+ * @param[in]   spi_num         Spi bus number
+ * @param[in]   chip_select     Spi chip select
+ * @param[in]   data            Spi transfer data information
+ * @param[in]   cb              Spi DMA callback
+ *
+ */
+// void spi_handle_data_dma(spi_device_num_t spi_num, spi_chip_select_t chip_select, spi_data_t data, plic_interrupt_t *cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_SPI_H */
diff --git a/kernel/include/spinlock.h b/kernel/include/spinlock.h
new file mode 100644
index 0000000000000000000000000000000000000000..4a0b7a1e6ff00b8398487bbe8251dcf8b0c7338a
--- /dev/null
+++ b/kernel/include/spinlock.h
@@ -0,0 +1,30 @@
+#ifndef __SPINLOCK_H
+#define __SPINLOCK_H
+
+struct cpu;
+
+// Mutual exclusion lock.
+struct spinlock {
+  uint locked;       // Is the lock held?
+
+  // For debugging:
+  char *name;        // Name of lock.
+  struct cpu *cpu;   // The cpu holding the lock.
+};
+
+// Initialize a spinlock 
+void initlock(struct spinlock*, char*);
+
+// Acquire the spinlock
+// Must be used with release()
+void acquire(struct spinlock*);
+
+// Release the spinlock 
+// Must be used with acquire()
+void release(struct spinlock*);
+
+// Check whether this cpu is holding the lock 
+// Interrupts must be off 
+int holding(struct spinlock*);
+
+#endif
diff --git a/kernel/include/stat.h b/kernel/include/stat.h
new file mode 100644
index 0000000000000000000000000000000000000000..fffe62f8eebd3e0560a20047927137c8bb518fe5
--- /dev/null
+++ b/kernel/include/stat.h
@@ -0,0 +1,96 @@
+#ifndef __STAT_H
+#define __STAT_H
+
+#define T_DIR     1   // Directory
+#define T_FILE    2   // File
+#define T_DEVICE  3   // Device
+
+#define STAT_MAX_NAME 32
+
+#define S_IFMT     0170000   // 文件类型bit字段的位掩码 
+#define S_IFSOCK   0140000   // socket
+#define S_IFLNK    0120000   // 符号链接
+#define S_IFREG    0100000   // 普通文件
+#define S_IFBLK    0060000   // 块设备
+#define S_IFDIR    0040000   // 目录
+#define S_IFCHR    0020000   // 字符设备
+#define S_IFIFO    0010000   // FIFO
+
+#define S_ISREG(m)    (((m) & S_IFMT) == S_IFREG) 
+#define S_ISDIR(m)    (((m) & S_IFMT) == S_IFDIR)
+#define S_ISBLK(m)    (((m) & S_IFMT) == S_IFBLK)
+#define S_ISLNK(m)    (((m) & S_IFMT) == S_IFLNK)
+#define S_ISCHR(m)    (((m) & S_IFMT) == S_IFCHR)
+#define S_ISIFO(m)    (((m) & S_IFMT) == S_IFIFO)
+#define S_ISSOCK(m)   (((m) & S_IFMT) == S_IFSOCK)
+
+// #define S_ISUID     04000   // set-user-ID bit (see execve(2))
+// #define S_ISGID     02000   // set-group-ID bit (see below)
+// #define S_ISVTX     01000   // sticky bit (see below)
+// #define S_IRWXU     00700   // owner has read, write, and execute permission
+// #define S_IRUSR     00400   // owner has read permission
+// #define S_IWUSR     00200   // owner has write permission
+// #define S_IXUSR     00100   // owner has execute permission
+// #define S_IRWXG     00070   // group has read, write, and execute permission
+// #define S_IRGRP     00040   // group has read permission
+// #define S_IWGRP     00020   // group has write permission
+// #define S_IXGRP     00010   // group has execute permission
+// #define S_IRWXO     00007   // others (not in group) have read, write, and execute permission
+// #define S_IROTH     00004   // others have read permission
+// #define S_IWOTH     00002   // others have write permission
+// #define S_IXOTH     00001   // others have execute permission
+
+
+// struct stat {
+//   char name[STAT_MAX_NAME + 1]; // 文件名
+//   int dev;         // 文件系统的磁盘设备
+//   short type;      // Type of file // 文件类型
+//   mode_t st_mode;  // 文件模式
+//   uint64 size;     // 文件大小(字节)
+//   uid_t  st_uid;   // 用户id
+//   gid_t  st_gid;   // 组id
+// };
+
+struct dstat {
+  uint64 d_ino;	// 索引结点号
+  int64 d_off;	// 到下一个dirent的偏移
+  uint16 d_reclen;	// 当前dirent的长度
+  uint8 d_type;	// 文件类型
+  char d_name[256];	//文件名
+};
+
+struct stat {
+  char name[STAT_MAX_NAME + 1]; // 文件名
+  int dev;     // File system's disk device // 文件系统的磁盘设备
+  short type;  // Type of file // 文件类型
+  uint64 size; // Size of file in bytes // 文件大小(字节)
+};
+
+struct kstat {
+	dev_t st_dev;
+	ino_t st_ino;
+	mode_t st_mode;
+	nlink_t st_nlink;
+	uid_t st_uid;
+	gid_t st_gid;
+	dev_t st_rdev;
+	unsigned long __pad;
+	off_t st_size;
+	blksize_t st_blksize;
+	int __pad2;
+	blkcnt_t st_blocks;
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+	unsigned __unused[2];
+};
+
+// struct stat {
+//   int dev;     // File system's disk device
+//   uint ino;    // Inode number
+//   short type;  // Type of file
+//   short nlink; // Number of links to file
+//   uint64 size; // Size of file in bytes
+// };
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/string.h b/kernel/include/string.h
new file mode 100644
index 0000000000000000000000000000000000000000..27bd9707542b3811108fea5e0aa1ffe6b00d2856
--- /dev/null
+++ b/kernel/include/string.h
@@ -0,0 +1,18 @@
+#ifndef __STRING_H
+#define __STRING_H
+
+#include "types.h"
+
+int             memcmp(const void*, const void*, uint);
+void*           memmove(void*, const void*, uint);
+void*           memset(void*, int, uint);
+char*           safestrcpy(char*, const char*, int);
+int             strlen(const char*);
+int             strncmp(const char*, const char*, uint);
+char*           strncpy(char*, const char*, int);
+void            wnstr(wchar *dst, char const *src, int len);
+void            snstr(char *dst, wchar const *src, int len);
+int             wcsncmp(wchar const *s1, wchar const *s2, int len);
+char*           strchr(const char *s, char c);
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e51e4790d78aecc887a4e34864da69f4bfe3128
--- /dev/null
+++ b/kernel/include/syscall.h
@@ -0,0 +1,14 @@
+#ifndef __SYSCALL_H
+#define __SYSCALL_H
+
+#include "types.h"
+#include "sysnum.h"
+
+int fetchaddr(uint64 addr, uint64 *ip);
+int fetchstr(uint64 addr, char *buf, int max);
+int argint(int n, int *ip);
+int argaddr(int n, uint64 *ip);
+int argstr(int n, char *buf, int max);
+void syscall(void);
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/sysctl.h b/kernel/include/sysctl.h
new file mode 100644
index 0000000000000000000000000000000000000000..08dc3e484f518167b369b17f86300f0d3d4472c0
--- /dev/null
+++ b/kernel/include/sysctl.h
@@ -0,0 +1,1078 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _DRIVER_SYSCTL_H
+#define _DRIVER_SYSCTL_H
+
+#include "types.h"
+// #include "platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief      System controller register
+ *
+ * @note       System controller register table
+ *
+ * | Offset    | Name           | Description                         |
+ * |-----------|----------------|-------------------------------------|
+ * | 0x00      | git_id         | Git short commit id                 |
+ * | 0x04      | clk_freq       | System clock base frequency         |
+ * | 0x08      | pll0           | PLL0 controller                     |
+ * | 0x0c      | pll1           | PLL1 controller                     |
+ * | 0x10      | pll2           | PLL2 controller                     |
+ * | 0x14      | resv5          | Reserved                            |
+ * | 0x18      | pll_lock       | PLL lock tester                     |
+ * | 0x1c      | rom_error      | AXI ROM detector                    |
+ * | 0x20      | clk_sel0       | Clock select controller0            |
+ * | 0x24      | clk_sel1       | Clock select controller1            |
+ * | 0x28      | clk_en_cent    | Central clock enable                |
+ * | 0x2c      | clk_en_peri    | Peripheral clock enable             |
+ * | 0x30      | soft_reset     | Soft reset ctrl                     |
+ * | 0x34      | peri_reset     | Peripheral reset controller         |
+ * | 0x38      | clk_th0        | Clock threshold controller 0        |
+ * | 0x3c      | clk_th1        | Clock threshold controller 1        |
+ * | 0x40      | clk_th2        | Clock threshold controller 2        |
+ * | 0x44      | clk_th3        | Clock threshold controller 3        |
+ * | 0x48      | clk_th4        | Clock threshold controller 4        |
+ * | 0x4c      | clk_th5        | Clock threshold controller 5        |
+ * | 0x50      | clk_th6        | Clock threshold controller 6        |
+ * | 0x54      | misc           | Miscellaneous controller            |
+ * | 0x58      | peri           | Peripheral controller               |
+ * | 0x5c      | spi_sleep      | SPI sleep controller                |
+ * | 0x60      | reset_status   | Reset source status                 |
+ * | 0x64      | dma_sel0       | DMA handshake selector              |
+ * | 0x68      | dma_sel1       | DMA handshake selector              |
+ * | 0x6c      | power_sel      | IO Power Mode Select controller     |
+ * | 0x70      | resv28         | Reserved                            |
+ * | 0x74      | resv29         | Reserved                            |
+ * | 0x78      | resv30         | Reserved                            |
+ * | 0x7c      | resv31         | Reserved                            |
+ *
+ */
+
+typedef enum _sysctl_pll_t
+{
+    SYSCTL_PLL0,
+    SYSCTL_PLL1,
+    SYSCTL_PLL2,
+    SYSCTL_PLL_MAX
+} sysctl_pll_t;
+
+typedef enum _sysctl_clock_source_t
+{
+    SYSCTL_SOURCE_IN0,
+    SYSCTL_SOURCE_PLL0,
+    SYSCTL_SOURCE_PLL1,
+    SYSCTL_SOURCE_PLL2,
+    SYSCTL_SOURCE_ACLK,
+    SYSCTL_SOURCE_MAX
+} sysctl_clock_source_t;
+
+typedef enum _sysctl_dma_channel_t
+{
+    SYSCTL_DMA_CHANNEL_0,
+    SYSCTL_DMA_CHANNEL_1,
+    SYSCTL_DMA_CHANNEL_2,
+    SYSCTL_DMA_CHANNEL_3,
+    SYSCTL_DMA_CHANNEL_4,
+    SYSCTL_DMA_CHANNEL_5,
+    SYSCTL_DMA_CHANNEL_MAX
+} sysctl_dma_channel_t;
+
+typedef enum _sysctl_dma_select_t
+{
+    SYSCTL_DMA_SELECT_SSI0_RX_REQ,
+    SYSCTL_DMA_SELECT_SSI0_TX_REQ,
+    SYSCTL_DMA_SELECT_SSI1_RX_REQ,
+    SYSCTL_DMA_SELECT_SSI1_TX_REQ,
+    SYSCTL_DMA_SELECT_SSI2_RX_REQ,
+    SYSCTL_DMA_SELECT_SSI2_TX_REQ,
+    SYSCTL_DMA_SELECT_SSI3_RX_REQ,
+    SYSCTL_DMA_SELECT_SSI3_TX_REQ,
+    SYSCTL_DMA_SELECT_I2C0_RX_REQ,
+    SYSCTL_DMA_SELECT_I2C0_TX_REQ,
+    SYSCTL_DMA_SELECT_I2C1_RX_REQ,
+    SYSCTL_DMA_SELECT_I2C1_TX_REQ,
+    SYSCTL_DMA_SELECT_I2C2_RX_REQ,
+    SYSCTL_DMA_SELECT_I2C2_TX_REQ,
+    SYSCTL_DMA_SELECT_UART1_RX_REQ,
+    SYSCTL_DMA_SELECT_UART1_TX_REQ,
+    SYSCTL_DMA_SELECT_UART2_RX_REQ,
+    SYSCTL_DMA_SELECT_UART2_TX_REQ,
+    SYSCTL_DMA_SELECT_UART3_RX_REQ,
+    SYSCTL_DMA_SELECT_UART3_TX_REQ,
+    SYSCTL_DMA_SELECT_AES_REQ,
+    SYSCTL_DMA_SELECT_SHA_RX_REQ,
+    SYSCTL_DMA_SELECT_AI_RX_REQ,
+    SYSCTL_DMA_SELECT_FFT_RX_REQ,
+    SYSCTL_DMA_SELECT_FFT_TX_REQ,
+    SYSCTL_DMA_SELECT_I2S0_TX_REQ,
+    SYSCTL_DMA_SELECT_I2S0_RX_REQ,
+    SYSCTL_DMA_SELECT_I2S1_TX_REQ,
+    SYSCTL_DMA_SELECT_I2S1_RX_REQ,
+    SYSCTL_DMA_SELECT_I2S2_TX_REQ,
+    SYSCTL_DMA_SELECT_I2S2_RX_REQ,
+    SYSCTL_DMA_SELECT_I2S0_BF_DIR_REQ,
+    SYSCTL_DMA_SELECT_I2S0_BF_VOICE_REQ,
+    SYSCTL_DMA_SELECT_MAX
+} sysctl_dma_select_t;
+
+/**
+ * @brief      System controller clock id
+ */
+typedef enum _sysctl_clock_t
+{
+    SYSCTL_CLOCK_PLL0,
+    SYSCTL_CLOCK_PLL1,
+    SYSCTL_CLOCK_PLL2,
+    SYSCTL_CLOCK_CPU,
+    SYSCTL_CLOCK_SRAM0,
+    SYSCTL_CLOCK_SRAM1,
+    SYSCTL_CLOCK_APB0,
+    SYSCTL_CLOCK_APB1,
+    SYSCTL_CLOCK_APB2,
+    SYSCTL_CLOCK_ROM,
+    SYSCTL_CLOCK_DMA,
+    SYSCTL_CLOCK_AI,
+    SYSCTL_CLOCK_DVP,
+    SYSCTL_CLOCK_FFT,
+    SYSCTL_CLOCK_GPIO,
+    SYSCTL_CLOCK_SPI0,
+    SYSCTL_CLOCK_SPI1,
+    SYSCTL_CLOCK_SPI2,
+    SYSCTL_CLOCK_SPI3,
+    SYSCTL_CLOCK_I2S0,
+    SYSCTL_CLOCK_I2S1,
+    SYSCTL_CLOCK_I2S2,
+    SYSCTL_CLOCK_I2C0,
+    SYSCTL_CLOCK_I2C1,
+    SYSCTL_CLOCK_I2C2,
+    SYSCTL_CLOCK_UART1,
+    SYSCTL_CLOCK_UART2,
+    SYSCTL_CLOCK_UART3,
+    SYSCTL_CLOCK_AES,
+    SYSCTL_CLOCK_FPIOA,
+    SYSCTL_CLOCK_TIMER0,
+    SYSCTL_CLOCK_TIMER1,
+    SYSCTL_CLOCK_TIMER2,
+    SYSCTL_CLOCK_WDT0,
+    SYSCTL_CLOCK_WDT1,
+    SYSCTL_CLOCK_SHA,
+    SYSCTL_CLOCK_OTP,
+    SYSCTL_CLOCK_RTC,
+    SYSCTL_CLOCK_ACLK = 40,
+    SYSCTL_CLOCK_HCLK,
+    SYSCTL_CLOCK_IN0,
+    SYSCTL_CLOCK_MAX
+} sysctl_clock_t;
+
+/**
+ * @brief      System controller clock select id
+ */
+typedef enum _sysctl_clock_select_t
+{
+    SYSCTL_CLOCK_SELECT_PLL0_BYPASS,
+    SYSCTL_CLOCK_SELECT_PLL1_BYPASS,
+    SYSCTL_CLOCK_SELECT_PLL2_BYPASS,
+    SYSCTL_CLOCK_SELECT_PLL2,
+    SYSCTL_CLOCK_SELECT_ACLK,
+    SYSCTL_CLOCK_SELECT_SPI3,
+    SYSCTL_CLOCK_SELECT_TIMER0,
+    SYSCTL_CLOCK_SELECT_TIMER1,
+    SYSCTL_CLOCK_SELECT_TIMER2,
+    SYSCTL_CLOCK_SELECT_SPI3_SAMPLE,
+    SYSCTL_CLOCK_SELECT_MAX = 11
+} sysctl_clock_select_t;
+
+/**
+ * @brief      System controller clock threshold id
+ */
+typedef enum _sysctl_threshold_t
+{
+    SYSCTL_THRESHOLD_ACLK,
+    SYSCTL_THRESHOLD_APB0,
+    SYSCTL_THRESHOLD_APB1,
+    SYSCTL_THRESHOLD_APB2,
+    SYSCTL_THRESHOLD_SRAM0,
+    SYSCTL_THRESHOLD_SRAM1,
+    SYSCTL_THRESHOLD_AI,
+    SYSCTL_THRESHOLD_DVP,
+    SYSCTL_THRESHOLD_ROM,
+    SYSCTL_THRESHOLD_SPI0,
+    SYSCTL_THRESHOLD_SPI1,
+    SYSCTL_THRESHOLD_SPI2,
+    SYSCTL_THRESHOLD_SPI3,
+    SYSCTL_THRESHOLD_TIMER0,
+    SYSCTL_THRESHOLD_TIMER1,
+    SYSCTL_THRESHOLD_TIMER2,
+    SYSCTL_THRESHOLD_I2S0,
+    SYSCTL_THRESHOLD_I2S1,
+    SYSCTL_THRESHOLD_I2S2,
+    SYSCTL_THRESHOLD_I2S0_M,
+    SYSCTL_THRESHOLD_I2S1_M,
+    SYSCTL_THRESHOLD_I2S2_M,
+    SYSCTL_THRESHOLD_I2C0,
+    SYSCTL_THRESHOLD_I2C1,
+    SYSCTL_THRESHOLD_I2C2,
+    SYSCTL_THRESHOLD_WDT0,
+    SYSCTL_THRESHOLD_WDT1,
+    SYSCTL_THRESHOLD_MAX = 28
+} sysctl_threshold_t;
+
+/**
+ * @brief      System controller reset control id
+ */
+typedef enum _sysctl_reset_t
+{
+    SYSCTL_RESET_SOC,
+    SYSCTL_RESET_ROM,
+    SYSCTL_RESET_DMA,
+    SYSCTL_RESET_AI,
+    SYSCTL_RESET_DVP,
+    SYSCTL_RESET_FFT,
+    SYSCTL_RESET_GPIO,
+    SYSCTL_RESET_SPI0,
+    SYSCTL_RESET_SPI1,
+    SYSCTL_RESET_SPI2,
+    SYSCTL_RESET_SPI3,
+    SYSCTL_RESET_I2S0,
+    SYSCTL_RESET_I2S1,
+    SYSCTL_RESET_I2S2,
+    SYSCTL_RESET_I2C0,
+    SYSCTL_RESET_I2C1,
+    SYSCTL_RESET_I2C2,
+    SYSCTL_RESET_UART1,
+    SYSCTL_RESET_UART2,
+    SYSCTL_RESET_UART3,
+    SYSCTL_RESET_AES,
+    SYSCTL_RESET_FPIOA,
+    SYSCTL_RESET_TIMER0,
+    SYSCTL_RESET_TIMER1,
+    SYSCTL_RESET_TIMER2,
+    SYSCTL_RESET_WDT0,
+    SYSCTL_RESET_WDT1,
+    SYSCTL_RESET_SHA,
+    SYSCTL_RESET_RTC,
+    SYSCTL_RESET_MAX = 31
+} sysctl_reset_t;
+
+/**
+ * @brief      System controller power bank id
+ */
+typedef enum _sysctl_power_bank
+{
+    SYSCTL_POWER_BANK0,
+    SYSCTL_POWER_BANK1,
+    SYSCTL_POWER_BANK2,
+    SYSCTL_POWER_BANK3,
+    SYSCTL_POWER_BANK4,
+    SYSCTL_POWER_BANK5,
+    SYSCTL_POWER_BANK6,
+    SYSCTL_POWER_BANK7,
+    SYSCTL_POWER_BANK_MAX,
+} sysctl_power_bank_t;
+
+/**
+ * @brief      System controller reset control id
+ */
+typedef enum _sysctl_io_power_mode
+{
+    SYSCTL_POWER_V33,
+    SYSCTL_POWER_V18
+} sysctl_io_power_mode_t;
+
+/**
+ * @brief      System reset status
+ */
+typedef enum _sysctl_reset_enum_status
+{
+    SYSCTL_RESET_STATUS_HARD,
+    SYSCTL_RESET_STATUS_SOFT,
+    SYSCTL_RESET_STATUS_WDT0,
+    SYSCTL_RESET_STATUS_WDT1,
+    SYSCTL_RESET_STATUS_MAX,
+} sysctl_reset_enum_status_t;
+
+/**
+ * @brief       Git short commit id
+ *
+ *              No. 0 Register (0x00)
+ */
+typedef struct _sysctl_git_id
+{
+    uint32 git_id : 32;
+} __attribute__((packed, aligned(4))) sysctl_git_id_t;
+
+/**
+ * @brief       System clock base frequency
+ *
+ *              No. 1 Register (0x04)
+ */
+typedef struct _sysctl_clk_freq
+{
+    uint32 clk_freq : 32;
+} __attribute__((packed, aligned(4))) sysctl_clk_freq_t;
+
+/**
+ * @brief       PLL0 controller
+ *
+ *              No. 2 Register (0x08)
+ */
+typedef struct _sysctl_pll0
+{
+    uint32 clkr0 : 4;
+    uint32 clkf0 : 6;
+    uint32 clkod0 : 4;
+    uint32 bwadj0 : 6;
+    uint32 pll_reset0 : 1;
+    uint32 pll_pwrd0 : 1;
+    uint32 pll_intfb0 : 1;
+    uint32 pll_bypass0 : 1;
+    uint32 pll_test0 : 1;
+    uint32 pll_out_en0 : 1;
+    uint32 pll_test_en : 1;
+    uint32 reserved : 5;
+} __attribute__((packed, aligned(4))) sysctl_pll0_t;
+
+/**
+ * @brief       PLL1 controller
+ *
+ *              No. 3 Register (0x0c)
+ */
+typedef struct _sysctl_pll1
+{
+    uint32 clkr1 : 4;
+    uint32 clkf1 : 6;
+    uint32 clkod1 : 4;
+    uint32 bwadj1 : 6;
+    uint32 pll_reset1 : 1;
+    uint32 pll_pwrd1 : 1;
+    uint32 pll_intfb1 : 1;
+    uint32 pll_bypass1 : 1;
+    uint32 pll_test1 : 1;
+    uint32 pll_out_en1 : 1;
+    uint32 reserved : 6;
+} __attribute__((packed, aligned(4))) sysctl_pll1_t;
+
+/**
+ * @brief       PLL2 controller
+ *
+ *              No. 4 Register (0x10)
+ */
+typedef struct _sysctl_pll2
+{
+    uint32 clkr2 : 4;
+    uint32 clkf2 : 6;
+    uint32 clkod2 : 4;
+    uint32 bwadj2 : 6;
+    uint32 pll_reset2 : 1;
+    uint32 pll_pwrd2 : 1;
+    uint32 pll_intfb2 : 1;
+    uint32 pll_bypass2 : 1;
+    uint32 pll_test2 : 1;
+    uint32 pll_out_en2 : 1;
+    uint32 pll_ckin_sel2 : 2;
+    uint32 reserved : 4;
+} __attribute__((packed, aligned(4))) sysctl_pll2_t;
+
+/**
+ * @brief       PLL lock tester
+ *
+ *              No. 6 Register (0x18)
+ */
+typedef struct _sysctl_pll_lock
+{
+    uint32 pll_lock0 : 2;
+    uint32 pll_slip_clear0 : 1;
+    uint32 test_clk_out0 : 1;
+    uint32 reserved0 : 4;
+    uint32 pll_lock1 : 2;
+    uint32 pll_slip_clear1 : 1;
+    uint32 test_clk_out1 : 1;
+    uint32 reserved1 : 4;
+    uint32 pll_lock2 : 2;
+    uint32 pll_slip_clear2 : 1;
+    uint32 test_clk_out2 : 1;
+    uint32 reserved2 : 12;
+} __attribute__((packed, aligned(4))) sysctl_pll_lock_t;
+
+/**
+ * @brief       AXI ROM detector
+ *
+ *              No. 7 Register (0x1c)
+ */
+typedef struct _sysctl_rom_error
+{
+    uint32 rom_mul_error : 1;
+    uint32 rom_one_error : 1;
+    uint32 reserved : 30;
+} __attribute__((packed, aligned(4))) sysctl_rom_error_t;
+
+/**
+ * @brief       Clock select controller0
+ *
+ *              No. 8 Register (0x20)
+ */
+typedef struct _sysctl_clk_sel0
+{
+    uint32 aclk_sel : 1;
+    uint32 aclk_divider_sel : 2;
+    uint32 apb0_clk_sel : 3;
+    uint32 apb1_clk_sel : 3;
+    uint32 apb2_clk_sel : 3;
+    uint32 spi3_clk_sel : 1;
+    uint32 timer0_clk_sel : 1;
+    uint32 timer1_clk_sel : 1;
+    uint32 timer2_clk_sel : 1;
+    uint32 reserved : 16;
+} __attribute__((packed, aligned(4))) sysctl_clk_sel0_t;
+
+/**
+ * @brief       Clock select controller1
+ *
+ *              No. 9 Register (0x24)
+ */
+typedef struct _sysctl_clk_sel1
+{
+    uint32 spi3_sample_clk_sel : 1;
+    uint32 reserved0 : 30;
+    uint32 reserved1 : 1;
+} __attribute__((packed, aligned(4))) sysctl_clk_sel1_t;
+
+/**
+ * @brief       Central clock enable
+ *
+ *              No. 10 Register (0x28)
+ */
+typedef struct _sysctl_clk_en_cent
+{
+    uint32 cpu_clk_en : 1;
+    uint32 sram0_clk_en : 1;
+    uint32 sram1_clk_en : 1;
+    uint32 apb0_clk_en : 1;
+    uint32 apb1_clk_en : 1;
+    uint32 apb2_clk_en : 1;
+    uint32 reserved : 26;
+} __attribute__((packed, aligned(4))) sysctl_clk_en_cent_t;
+
+/**
+ * @brief       Peripheral clock enable
+ *
+ *              No. 11 Register (0x2c)
+ */
+typedef struct _sysctl_clk_en_peri
+{
+    uint32 rom_clk_en : 1;
+    uint32 dma_clk_en : 1;
+    uint32 ai_clk_en : 1;
+    uint32 dvp_clk_en : 1;
+    uint32 fft_clk_en : 1;
+    uint32 gpio_clk_en : 1;
+    uint32 spi0_clk_en : 1;
+    uint32 spi1_clk_en : 1;
+    uint32 spi2_clk_en : 1;
+    uint32 spi3_clk_en : 1;
+    uint32 i2s0_clk_en : 1;
+    uint32 i2s1_clk_en : 1;
+    uint32 i2s2_clk_en : 1;
+    uint32 i2c0_clk_en : 1;
+    uint32 i2c1_clk_en : 1;
+    uint32 i2c2_clk_en : 1;
+    uint32 uart1_clk_en : 1;
+    uint32 uart2_clk_en : 1;
+    uint32 uart3_clk_en : 1;
+    uint32 aes_clk_en : 1;
+    uint32 fpioa_clk_en : 1;
+    uint32 timer0_clk_en : 1;
+    uint32 timer1_clk_en : 1;
+    uint32 timer2_clk_en : 1;
+    uint32 wdt0_clk_en : 1;
+    uint32 wdt1_clk_en : 1;
+    uint32 sha_clk_en : 1;
+    uint32 otp_clk_en : 1;
+    uint32 reserved : 1;
+    uint32 rtc_clk_en : 1;
+    uint32 reserved0 : 2;
+} __attribute__((packed, aligned(4))) sysctl_clk_en_peri_t;
+
+/**
+ * @brief       Soft reset ctrl
+ *
+ *              No. 12 Register (0x30)
+ */
+typedef struct _sysctl_soft_reset
+{
+    uint32 soft_reset : 1;
+    uint32 reserved : 31;
+} __attribute__((packed, aligned(4))) sysctl_soft_reset_t;
+
+/**
+ * @brief       Peripheral reset controller
+ *
+ *              No. 13 Register (0x34)
+ */
+typedef struct _sysctl_peri_reset
+{
+    uint32 rom_reset : 1;
+    uint32 dma_reset : 1;
+    uint32 ai_reset : 1;
+    uint32 dvp_reset : 1;
+    uint32 fft_reset : 1;
+    uint32 gpio_reset : 1;
+    uint32 spi0_reset : 1;
+    uint32 spi1_reset : 1;
+    uint32 spi2_reset : 1;
+    uint32 spi3_reset : 1;
+    uint32 i2s0_reset : 1;
+    uint32 i2s1_reset : 1;
+    uint32 i2s2_reset : 1;
+    uint32 i2c0_reset : 1;
+    uint32 i2c1_reset : 1;
+    uint32 i2c2_reset : 1;
+    uint32 uart1_reset : 1;
+    uint32 uart2_reset : 1;
+    uint32 uart3_reset : 1;
+    uint32 aes_reset : 1;
+    uint32 fpioa_reset : 1;
+    uint32 timer0_reset : 1;
+    uint32 timer1_reset : 1;
+    uint32 timer2_reset : 1;
+    uint32 wdt0_reset : 1;
+    uint32 wdt1_reset : 1;
+    uint32 sha_reset : 1;
+    uint32 reserved : 2;
+    uint32 rtc_reset : 1;
+    uint32 reserved0 : 2;
+} __attribute__((packed, aligned(4))) sysctl_peri_reset_t;
+
+/**
+ * @brief       Clock threshold controller 0
+ *
+ *              No. 14 Register (0x38)
+ */
+typedef struct _sysctl_clk_th0
+{
+    uint32 sram0_gclk_threshold : 4;
+    uint32 sram1_gclk_threshold : 4;
+    uint32 ai_gclk_threshold : 4;
+    uint32 dvp_gclk_threshold : 4;
+    uint32 rom_gclk_threshold : 4;
+    uint32 reserved : 12;
+} __attribute__((packed, aligned(4))) sysctl_clk_th0_t;
+
+/**
+ * @brief       Clock threshold controller 1
+ *
+ *              No. 15 Register (0x3c)
+ */
+typedef struct _sysctl_clk_th1
+{
+    uint32 spi0_clk_threshold : 8;
+    uint32 spi1_clk_threshold : 8;
+    uint32 spi2_clk_threshold : 8;
+    uint32 spi3_clk_threshold : 8;
+} __attribute__((packed, aligned(4))) sysctl_clk_th1_t;
+
+/**
+ * @brief       Clock threshold controller 2
+ *
+ *              No. 16 Register (0x40)
+ */
+typedef struct _sysctl_clk_th2
+{
+    uint32 timer0_clk_threshold : 8;
+    uint32 timer1_clk_threshold : 8;
+    uint32 timer2_clk_threshold : 8;
+    uint32 reserved : 8;
+} __attribute__((packed, aligned(4))) sysctl_clk_th2_t;
+
+/**
+ * @brief       Clock threshold controller 3
+ *
+ *              No. 17 Register (0x44)
+ */
+typedef struct _sysctl_clk_th3
+{
+    uint32 i2s0_clk_threshold : 16;
+    uint32 i2s1_clk_threshold : 16;
+} __attribute__((packed, aligned(4))) sysctl_clk_th3_t;
+
+/**
+ * @brief       Clock threshold controller 4
+ *
+ *              No. 18 Register (0x48)
+ */
+typedef struct _sysctl_clk_th4
+{
+    uint32 i2s2_clk_threshold : 16;
+    uint32 i2s0_mclk_threshold : 8;
+    uint32 i2s1_mclk_threshold : 8;
+} __attribute__((packed, aligned(4))) sysctl_clk_th4_t;
+
+/**
+ * @brief       Clock threshold controller 5
+ *
+ *              No. 19 Register (0x4c)
+ */
+typedef struct _sysctl_clk_th5
+{
+    uint32 i2s2_mclk_threshold : 8;
+    uint32 i2c0_clk_threshold : 8;
+    uint32 i2c1_clk_threshold : 8;
+    uint32 i2c2_clk_threshold : 8;
+} __attribute__((packed, aligned(4))) sysctl_clk_th5_t;
+
+/**
+ * @brief       Clock threshold controller 6
+ *
+ *              No. 20 Register (0x50)
+ */
+typedef struct _sysctl_clk_th6
+{
+    uint32 wdt0_clk_threshold : 8;
+    uint32 wdt1_clk_threshold : 8;
+    uint32 reserved0 : 8;
+    uint32 reserved1 : 8;
+} __attribute__((packed, aligned(4))) sysctl_clk_th6_t;
+
+/**
+ * @brief       Miscellaneous controller
+ *
+ *              No. 21 Register (0x54)
+ */
+typedef struct _sysctl_misc
+{
+    uint32 debug_sel : 6;
+    uint32 reserved0 : 4;
+    uint32 spi_dvp_data_enable : 1;
+    uint32 reserved1 : 21;
+} __attribute__((packed, aligned(4))) sysctl_misc_t;
+
+/**
+ * @brief       Peripheral controller
+ *
+ *              No. 22 Register (0x58)
+ */
+typedef struct _sysctl_peri
+{
+    uint32 timer0_pause : 1;
+    uint32 timer1_pause : 1;
+    uint32 timer2_pause : 1;
+    uint32 timer3_pause : 1;
+    uint32 timer4_pause : 1;
+    uint32 timer5_pause : 1;
+    uint32 timer6_pause : 1;
+    uint32 timer7_pause : 1;
+    uint32 timer8_pause : 1;
+    uint32 timer9_pause : 1;
+    uint32 timer10_pause : 1;
+    uint32 timer11_pause : 1;
+    uint32 spi0_xip_en : 1;
+    uint32 spi1_xip_en : 1;
+    uint32 spi2_xip_en : 1;
+    uint32 spi3_xip_en : 1;
+    uint32 spi0_clk_bypass : 1;
+    uint32 spi1_clk_bypass : 1;
+    uint32 spi2_clk_bypass : 1;
+    uint32 i2s0_clk_bypass : 1;
+    uint32 i2s1_clk_bypass : 1;
+    uint32 i2s2_clk_bypass : 1;
+    uint32 jtag_clk_bypass : 1;
+    uint32 dvp_clk_bypass : 1;
+    uint32 debug_clk_bypass : 1;
+    uint32 reserved0 : 1;
+    uint32 reserved1 : 6;
+} __attribute__((packed, aligned(4))) sysctl_peri_t;
+
+/**
+ * @brief       SPI sleep controller
+ *
+ *              No. 23 Register (0x5c)
+ */
+typedef struct _sysctl_spi_sleep
+{
+    uint32 ssi0_sleep : 1;
+    uint32 ssi1_sleep : 1;
+    uint32 ssi2_sleep : 1;
+    uint32 ssi3_sleep : 1;
+    uint32 reserved : 28;
+} __attribute__((packed, aligned(4))) sysctl_spi_sleep_t;
+
+/**
+ * @brief       Reset source status
+ *
+ *              No. 24 Register (0x60)
+ */
+typedef struct _sysctl_reset_status
+{
+    uint32 reset_sts_clr : 1;
+    uint32 pin_reset_sts : 1;
+    uint32 wdt0_reset_sts : 1;
+    uint32 wdt1_reset_sts : 1;
+    uint32 soft_reset_sts : 1;
+    uint32 reserved : 27;
+} __attribute__((packed, aligned(4))) sysctl_reset_status_t;
+
+/**
+ * @brief       DMA handshake selector
+ *
+ *              No. 25 Register (0x64)
+ */
+typedef struct _sysctl_dma_sel0
+{
+    uint32 dma_sel0 : 6;
+    uint32 dma_sel1 : 6;
+    uint32 dma_sel2 : 6;
+    uint32 dma_sel3 : 6;
+    uint32 dma_sel4 : 6;
+    uint32 reserved : 2;
+} __attribute__((packed, aligned(4))) sysctl_dma_sel0_t;
+
+/**
+ * @brief       DMA handshake selector
+ *
+ *              No. 26 Register (0x68)
+ */
+typedef struct _sysctl_dma_sel1
+{
+    uint32 dma_sel5 : 6;
+    uint32 reserved : 26;
+} __attribute__((packed, aligned(4))) sysctl_dma_sel1_t;
+
+/**
+ * @brief       IO Power Mode Select controller
+ *
+ *              No. 27 Register (0x6c)
+ */
+typedef struct _sysctl_power_sel
+{
+    uint32 power_mode_sel0 : 1;
+    uint32 power_mode_sel1 : 1;
+    uint32 power_mode_sel2 : 1;
+    uint32 power_mode_sel3 : 1;
+    uint32 power_mode_sel4 : 1;
+    uint32 power_mode_sel5 : 1;
+    uint32 power_mode_sel6 : 1;
+    uint32 power_mode_sel7 : 1;
+    uint32 reserved : 24;
+} __attribute__((packed, aligned(4))) sysctl_power_sel_t;
+
+/**
+ * @brief       System controller object
+ *
+ *              The System controller is a peripheral device mapped in the
+ *              internal memory map, discoverable in the Configuration String.
+ *              It is responsible for low-level configuration of all system
+ *              related peripheral device. It contain PLL controller, clock
+ *              controller, reset controller, DMA handshake controller, SPI
+ *              controller, timer controller, WDT controller and sleep
+ *              controller.
+ */
+typedef struct _sysctl
+{
+    /* No. 0 (0x00): Git short commit id */
+    sysctl_git_id_t git_id;
+    /* No. 1 (0x04): System clock base frequency */
+    sysctl_clk_freq_t clk_freq;
+    /* No. 2 (0x08): PLL0 controller */
+    sysctl_pll0_t pll0;
+    /* No. 3 (0x0c): PLL1 controller */
+    sysctl_pll1_t pll1;
+    /* No. 4 (0x10): PLL2 controller */
+    sysctl_pll2_t pll2;
+    /* No. 5 (0x14): Reserved */
+    uint32 resv5;
+    /* No. 6 (0x18): PLL lock tester */
+    sysctl_pll_lock_t pll_lock;
+    /* No. 7 (0x1c): AXI ROM detector */
+    sysctl_rom_error_t rom_error;
+    /* No. 8 (0x20): Clock select controller0 */
+    sysctl_clk_sel0_t clk_sel0;
+    /* No. 9 (0x24): Clock select controller1 */
+    sysctl_clk_sel1_t clk_sel1;
+    /* No. 10 (0x28): Central clock enable */
+    sysctl_clk_en_cent_t clk_en_cent;
+    /* No. 11 (0x2c): Peripheral clock enable */
+    sysctl_clk_en_peri_t clk_en_peri;
+    /* No. 12 (0x30): Soft reset ctrl */
+    sysctl_soft_reset_t soft_reset;
+    /* No. 13 (0x34): Peripheral reset controller */
+    sysctl_peri_reset_t peri_reset;
+    /* No. 14 (0x38): Clock threshold controller 0 */
+    sysctl_clk_th0_t clk_th0;
+    /* No. 15 (0x3c): Clock threshold controller 1 */
+    sysctl_clk_th1_t clk_th1;
+    /* No. 16 (0x40): Clock threshold controller 2 */
+    sysctl_clk_th2_t clk_th2;
+    /* No. 17 (0x44): Clock threshold controller 3 */
+    sysctl_clk_th3_t clk_th3;
+    /* No. 18 (0x48): Clock threshold controller 4 */
+    sysctl_clk_th4_t clk_th4;
+    /* No. 19 (0x4c): Clock threshold controller 5 */
+    sysctl_clk_th5_t clk_th5;
+    /* No. 20 (0x50): Clock threshold controller 6 */
+    sysctl_clk_th6_t clk_th6;
+    /* No. 21 (0x54): Miscellaneous controller */
+    sysctl_misc_t misc;
+    /* No. 22 (0x58): Peripheral controller */
+    sysctl_peri_t peri;
+    /* No. 23 (0x5c): SPI sleep controller */
+    sysctl_spi_sleep_t spi_sleep;
+    /* No. 24 (0x60): Reset source status */
+    sysctl_reset_status_t reset_status;
+    /* No. 25 (0x64): DMA handshake selector */
+    sysctl_dma_sel0_t dma_sel0;
+    /* No. 26 (0x68): DMA handshake selector */
+    sysctl_dma_sel1_t dma_sel1;
+    /* No. 27 (0x6c): IO Power Mode Select controller */
+    sysctl_power_sel_t power_sel;
+    /* No. 28 (0x70): Reserved */
+    uint32 resv28;
+    /* No. 29 (0x74): Reserved */
+    uint32 resv29;
+    /* No. 30 (0x78): Reserved */
+    uint32 resv30;
+    /* No. 31 (0x7c): Reserved */
+    uint32 resv31;
+} __attribute__((packed, aligned(4))) sysctl_t;
+
+/**
+ * @brief       Abstruct PLL struct
+ */
+typedef struct _sysctl_general_pll
+{
+    uint32 clkr : 4;
+    uint32 clkf : 6;
+    uint32 clkod : 4;
+    uint32 bwadj : 6;
+    uint32 pll_reset : 1;
+    uint32 pll_pwrd : 1;
+    uint32 pll_intfb : 1;
+    uint32 pll_bypass : 1;
+    uint32 pll_test : 1;
+    uint32 pll_out_en : 1;
+    uint32 pll_ckin_sel : 2;
+    uint32 reserved : 4;
+} __attribute__((packed, aligned(4))) sysctl_general_pll_t;
+
+/**
+ * @brief       System controller object instanse
+ */
+extern volatile sysctl_t *const sysctl;
+
+/**
+ * @brief       Enable clock for peripheral
+ *
+ * @param[in]   clock       The clock to be enable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_clock_enable(sysctl_clock_t clock);
+
+/**
+ * @brief       Enable clock for peripheral
+ *
+ * @param[in]   clock       The clock to be disable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_clock_disable(sysctl_clock_t clock);
+
+/**
+ * @brief       Sysctl clock set threshold
+ *
+ * @param[in]   which           Which threshold to set
+ * @param[in]   threshold       The threshold value
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_clock_set_threshold(sysctl_threshold_t which, int threshold);
+
+/**
+ * @brief       Sysctl clock get threshold
+ *
+ * @param[in]   which       Which threshold to get
+ *
+ * @return      The threshold value
+ *     - Other  Value of threshold
+ *     - -1     Fail
+ */
+int sysctl_clock_get_threshold(sysctl_threshold_t which);
+
+/**
+ * @brief       Sysctl clock set clock select
+ *
+ * @param[in]   which       Which clock select to set
+ * @param[in]   select      The clock select value
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_clock_set_clock_select(sysctl_clock_select_t which, int select);
+
+/**
+ * @brief       Sysctl clock get clock select
+ *
+ * @param[in]   which  Which clock select to get
+ *
+ * @return      The clock select value
+ *     - Other  Value of clock select
+ *     - -1     Fail
+ */
+int sysctl_clock_get_clock_select(sysctl_clock_select_t which);
+
+/**
+ * @brief       Get PLL frequency
+ *
+ * @param[in]   pll     The PLL id
+ *
+ * @return      The frequency of PLL
+ */
+uint32 sysctl_pll_get_freq(sysctl_pll_t pll);
+
+/**
+ * @brief       Get base clock frequency by clock id
+ *
+ * @param[in]   clock       The clock id
+ *
+ * @return      The clock frequency
+ */
+uint32 sysctl_clock_get_freq(sysctl_clock_t clock);
+
+/**
+ * @brief       Reset device by reset controller
+ *
+ * @param[in]   reset       The reset signal
+ */
+void sysctl_reset(sysctl_reset_t reset);
+
+/**
+ * @brief       Enable the PLL and power on with reset
+ *
+ * @param[in]   pll     The pll id
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_pll_enable(sysctl_pll_t pll);
+
+/**
+ * @brief       Disable the PLL and power off
+ *
+ * @param[in]   pll     The pll id
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_pll_disable(sysctl_pll_t pll);
+
+/**
+ * @brief       Select DMA channel handshake peripheral signal
+ *
+ * @param[in]   channel     The DMA channel
+ * @param[in]   select      The peripheral select
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_dma_select(sysctl_dma_channel_t channel, sysctl_dma_select_t select);
+
+/**
+ * @brief       Set SPI0_D0-D7 DVP_D0-D7 as spi and dvp data pin
+ *
+ * @param[in]   en     Enable or not
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+uint32 sysctl_set_spi0_dvp_data(uint8 en);
+
+/**
+ * @brief       Set io power mode
+ *
+ * @param[in]   power_bank          IO power bank
+ * @param[in]   io_power_mode       Set power mode 3.3v or 1.8
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+void sysctl_set_power_mode(sysctl_power_bank_t power_bank, sysctl_io_power_mode_t io_power_mode);
+
+/**
+ * @brief       get the frequency of CPU
+ * 
+ * @return      The frequency of CPU
+ */
+uint32 sysctl_cpu_get_freq(void);
+
+/**
+ * @brief       Set frequency of CPU
+ * @param[in]   freq       The desired frequency in Hz
+ *
+ * @return      The actual frequency of CPU after set
+ */
+uint32 sysctl_cpu_set_freq(uint32 freq);
+
+/**
+ * @brief       Init PLL freqency
+ * @param[in]   pll            The PLL id
+ * @param[in]   pll_freq       The desired frequency in Hz
+
+ */
+uint32 sysctl_pll_set_freq(sysctl_pll_t pll, uint32 pll_freq);
+
+/**
+ * @brief       Enable interrupt
+ */
+void sysctl_enable_irq(void);
+
+/**
+ * @brief       Disable interrupt
+ */
+void sysctl_disable_irq(void);
+
+/**
+ * @brief       Get the time start up to now
+ *
+ * @return      The time of microsecond
+ */
+uint64 sysctl_get_time_us(void);
+
+/**
+ * @brief       Get reset status
+ *
+ * @return      The status of reset
+ */
+sysctl_reset_enum_status_t sysctl_get_reset_status(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_SYSCTL_H */
diff --git a/kernel/include/sysinfo.h b/kernel/include/sysinfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..470f402056598341c7203b9710a43b96bc2ebdec
--- /dev/null
+++ b/kernel/include/sysinfo.h
@@ -0,0 +1,12 @@
+#ifndef __SYSINFO_H
+#define __SYSINFO_H
+
+#include "types.h"
+
+struct sysinfo {
+  uint64 freemem;   // amount of free memory (bytes)
+  uint64 nproc;     // number of process
+};
+
+
+#endif
diff --git a/kernel/include/sysnum.h b/kernel/include/sysnum.h
new file mode 100644
index 0000000000000000000000000000000000000000..0fcfc895a8450547eee55196db977324eefb835b
--- /dev/null
+++ b/kernel/include/sysnum.h
@@ -0,0 +1,88 @@
+#ifndef __SYSNUM_H
+#define __SYSNUM_H
+
+// System call numbers
+#define SYS_fork         500
+#define SYS_exit         93
+#define SYS_wait         501
+#define SYS_pipe         502
+#define SYS_read         63
+#define SYS_exec         503
+#define SYS_chdir        49
+#define SYS_dup         23
+#define SYS_getpid      172
+#define SYS_sbrk        514
+#define SYS_sleep       504
+#define SYS_uptime      505
+#define SYS_open        506
+#define SYS_openat      56
+#define SYS_write       64
+#define SYS_remove      507
+#define SYS_trace       508
+#define SYS_sysinfo     179
+#define SYS_mkdir       509
+#define SYS_close       57
+#define SYS_test_proc   510
+#define SYS_dev         511
+#define SYS_dup3        24
+#define SYS_readdir     512
+#define SYS_getcwd      17
+#define SYS_pipe2       59
+#define SYS_rename      513
+#define SYS_clone       220
+#define SYS_execve      221
+#define SYS_wait4       260
+#define SYS_getppid     173
+#define SYS_mkdirat     34
+#define SYS_mmap        222
+#define SYS_munmap      215
+#define SYS_times       153
+#define SYS_uname       160
+#define SYS_sched_yield 124
+#define SYS_gettimeofday 169
+#define SYS_nanosleep   101
+#define SYS_getdents64  61
+#define SYS_fstat     80
+#define SYS_fstatat     79
+#define SYS_mount       40
+#define SYS_umount2     39
+#define SYS_linkat      37
+#define SYS_unlinkat    35
+#define SYS_rt_sigprocmask 135
+#define SYS_rt_sigaction 134
+#define SYS_rt_sigtimedwait 137
+#define SYS_set_tid_address 96
+#define SYS_exit_group  94
+#define SYS_kill        129
+#define SYS_gettid      178
+#define SYS_prlimit64 261
+#define SYS_clock_gettime 113
+#define SYS_futex       98
+#define SYS_lseek       62
+#define SYS_ioctl       29
+#define SYS_statfs      43
+#define SYS_mprotect    226
+#define SYS_utimensat   88
+#define SYS_readv       65
+#define SYS_writev      66
+#define SYS_msync       227
+#define SYS_writev       66
+#define SYS_clock_settime 112
+#define SYS_setitimer    103
+#define SYS_getuid			174
+#define SYS_geteuid			175
+#define SYS_getgid			176
+#define SYS_getegid			177
+#define SYS_sendfile        71
+#define SYS_syslog 			116
+#define SYS_renameat2       276
+#define SYS_fcntl           25
+#define SYS_faccessat    48
+#define SYS_fchdir          50
+#define SYS_readlinkat    78
+#define SYS_tgkill          131
+#define SYS_umask           166
+#define SYS_brk             214
+#define SYS_getrusage       165
+#define SYS_pselect         72
+#endif
\ No newline at end of file
diff --git a/kernel/include/timer.h b/kernel/include/timer.h
new file mode 100644
index 0000000000000000000000000000000000000000..4252eb32f69275090892a0077b40710b37ca7542
--- /dev/null
+++ b/kernel/include/timer.h
@@ -0,0 +1,34 @@
+#ifndef __TIMER_H
+#define __TIMER_H
+
+#include "types.h"
+#include "spinlock.h"
+#include "proc.h"
+#define	ITIMER_REAL		0
+#define	ITIMER_VIRTUAL		1
+#define	ITIMER_PROF		2
+
+
+struct sleep_proc{
+	uint sleep_ticks;
+	struct proc* p;
+	struct spinlock lock;
+};
+
+extern struct spinlock tickslock;
+extern uint ticks;
+
+void timerinit();
+void set_next_timeout();
+void timer_tick(int cpl);
+int gain_sleep(TimeVal *tv);
+
+#define N_SLEEP_PRCO 5
+
+#ifndef QEMU 
+#define CLK_FREQ 		8900000
+#else 
+#define CLK_FREQ 		10000000
+#endif 
+
+#endif
diff --git a/kernel/include/trap.h b/kernel/include/trap.h
new file mode 100644
index 0000000000000000000000000000000000000000..e70b9aa95ee788fc82cdba5ba6094b4cb56d8e82
--- /dev/null
+++ b/kernel/include/trap.h
@@ -0,0 +1,104 @@
+#ifndef __TRAP_H
+#define __TRAP_H
+
+// per-process data for the trap handling code in trampoline.S.
+// sits in a page by itself just under the trampoline page in the
+// user page table. not specially mapped in the kernel page table.
+// the sscratch register points here.
+// uservec in trampoline.S saves user registers in the trapframe,
+// then initializes registers from the trapframe's
+// kernel_sp, kernel_hartid, kernel_satp, and jumps to kernel_trap.
+// usertrapret() and userret in trampoline.S set up
+// the trapframe's kernel_*, restore user registers from the
+// trapframe, switch to the user page table, and enter user space.
+// the trapframe includes callee-saved user registers like s0-s11 because the
+// return-to-user path via usertrapret() doesn't return through
+// the entire kernel call stack.
+struct trapframe {
+  /*   0 */ uint64 kernel_satp;   // kernel page table
+  /*   8 */ uint64 kernel_sp;     // top of process's kernel stack
+  /*  16 */ uint64 kernel_trap;   // usertrap()
+  /*  24 */ uint64 epc;           // saved user program counter
+  /*  32 */ uint64 kernel_hartid; // saved kernel tp
+  /*  40 */ uint64 ra;
+  /*  48 */ uint64 sp;
+  /*  56 */ uint64 gp;
+  /*  64 */ uint64 tp;
+  /*  72 */ uint64 t0;
+  /*  80 */ uint64 t1;
+  /*  88 */ uint64 t2;
+  /*  96 */ uint64 s0;
+  /* 104 */ uint64 s1;
+  /* 112 */ uint64 a0;
+  /* 120 */ uint64 a1;
+  /* 128 */ uint64 a2;
+  /* 136 */ uint64 a3;
+  /* 144 */ uint64 a4;
+  /* 152 */ uint64 a5;
+  /* 160 */ uint64 a6;
+  /* 168 */ uint64 a7;
+  /* 176 */ uint64 s2;
+  /* 184 */ uint64 s3;
+  /* 192 */ uint64 s4;
+  /* 200 */ uint64 s5;
+  /* 208 */ uint64 s6;
+  /* 216 */ uint64 s7;
+  /* 224 */ uint64 s8;
+  /* 232 */ uint64 s9;
+  /* 240 */ uint64 s10;
+  /* 248 */ uint64 s11;
+  /* 256 */ uint64 t3;
+  /* 264 */ uint64 t4;
+  /* 272 */ uint64 t5;
+  /* 280 */ uint64 t6;
+
+	/* 288 */ uint64 ft0;
+	/* 296 */ uint64 ft1;
+	/* 304 */ uint64 ft2;
+	/* 312 */ uint64 ft3;
+	/* 320 */ uint64 ft4;
+	/* 328 */ uint64 ft5;
+	/* 336 */ uint64 ft6;
+	/* 344 */ uint64 ft7;
+	/* 352 */ uint64 fs0;
+	/* 360 */ uint64 fs1;
+	/* 368 */ uint64 fa0;
+	/* 376 */ uint64 fa1;
+	/* 384 */ uint64 fa2;
+	/* 392 */ uint64 fa3;
+	/* 400 */ uint64 fa4;
+	/* 408 */ uint64 fa5;
+	/* 416 */ uint64 fa6;
+	/* 424 */ uint64 fa7;
+	/* 432 */ uint64 fs2;
+	/* 440 */ uint64 fs3;
+	/* 448 */ uint64 fs4;
+	/* 456 */ uint64 fs5;
+	/* 464 */ uint64 fs6;
+	/* 472 */ uint64 fs7;
+	/* 480 */ uint64 fs8;
+	/* 488 */ uint64 fs9;
+	/* 496 */ uint64 fs10;
+	/* 504 */ uint64 fs11;
+	/* 512 */ uint64 ft8;
+	/* 520 */ uint64 ft9;
+	/* 528 */ uint64 ft10;
+	/* 536 */ uint64 ft11;
+
+	/* 544 */ uint64 fcsr;
+};
+
+void            trapinithart(void);
+void            usertrapret(void);
+void            trapframedump(struct trapframe *tf);
+typedef void (*floattrap)(struct trapframe*);
+
+#define INSTRUCTION_ACCESS_FAULT    0x1
+#define LOAD_ACCESS_FAULT           0x5
+#define STORE_ACCESS_FAULT          0x7
+#define EXCP_ENV_CALL               0x8
+#define INSTRUCTION_PAGE_FAULT      0xc 
+#define LOAD_PAGE_FAULT             0xd
+#define STORE_PAGE_FAULT            0xf
+
+#endif
diff --git a/kernel/include/types.h b/kernel/include/types.h
new file mode 100644
index 0000000000000000000000000000000000000000..9dcbf65d36791d70a26ec36d2aa4d6cdfdf64add
--- /dev/null
+++ b/kernel/include/types.h
@@ -0,0 +1,148 @@
+#ifndef __TYPES_H
+#define __TYPES_H
+
+typedef unsigned int   uint;
+typedef unsigned short ushort;
+typedef unsigned char  uchar;
+typedef unsigned short wchar;
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int  uint32;
+typedef unsigned long uint64;
+typedef long int64;
+
+typedef unsigned long uintptr_t;
+typedef uint64 pde_t;
+
+typedef uint64 pid_t;
+typedef unsigned int mode_t;
+typedef uint32 uid_t;
+typedef uint32 gid_t;
+typedef unsigned int size_t;
+typedef unsigned long dev_t;
+typedef uint64 ino_t;
+typedef uint32 nlink_t;
+typedef long off_t;
+typedef long blkcnt_t;
+typedef uint blksize_t;
+typedef long clock_t;
+typedef long time_t;
+typedef int clockid_t;
+
+#define __BYTE_ORDER 1234
+
+struct timeval {
+	time_t		tv_sec;		/* seconds */
+	time_t	tv_usec;	/* microseconds */
+};
+
+struct itimerval {
+	struct timeval it_interval; //定时器设置的时间
+	struct timeval it_value; //å»¶æ—¶æ—¶é—´
+};
+
+
+struct timespec64 {
+	long long	tv_sec;			/* seconds */
+	long long   tv_nsec;		/* nanoseconds */
+};
+
+struct timespec { 
+    time_t tv_sec; 
+    int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321);
+    long tv_nsec; 
+    int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); 
+};
+
+#define SIGSETSIZE 1
+
+union sigval {
+	int sival_int;
+	void *sival_ptr;
+};
+
+#define	RUSAGE_SELF			0
+#define	RUSAGE_CHILDREN		(-1)
+#define	RUSAGE_THREAD		1
+
+struct rusage {
+	struct timeval	ru_utime;
+	struct timeval	ru_stime;
+	long			ru_maxrss;
+	long			ru_ixrss;
+	long			ru_idrss;
+	long			ru_isrss;
+	long			ru_minflt;
+	long			ru_majflt;
+	long			ru_nswap;
+	long			ru_inblock;
+	long			ru_oublock;
+	long			ru_msgsnd;
+	long			ru_msgrcv;
+	long			ru_nsignals;
+	long			ru_nvcsw;
+	long			ru_nivcsw;
+	// long			__reserved[16];
+};
+
+// typedef struct
+// { 
+//     unsigned long __bits[SIGSETSIZE];
+// } sigset_t;
+
+struct iovec { 
+	void *iov_base;
+	size_t iov_len;
+};
+
+typedef struct {
+	unsigned long __bits[SIGSETSIZE];
+} sigset_t;
+typedef void (*__sighandler_t)(int);
+struct sigaction {
+	__sighandler_t sa_handler;
+	sigset_t sa_mask;	// signals to be blocked during handling 
+	int sa_flags;
+	// void (*sa_restorer)(void);	// this field is not used on risc-v
+};
+
+
+typedef struct
+{
+    uint64 sec;  // 自 Unix 纪元起的秒数
+    uint64 usec; // 微秒数
+} TimeVal;
+
+// #define NULL ((void *)0)
+#define NULL 0
+
+#define readb(addr) (*(volatile uint8 *)(addr))     
+#define readw(addr) (*(volatile uint16 *)(addr))    
+#define readd(addr) (*(volatile uint32 *)(addr))    
+#define readq(addr) (*(volatile uint64 *)(addr))    
+
+#define writeb(v, addr)                      \
+    {                                        \
+        (*(volatile uint8 *)(addr)) = (v); \
+    }
+#define writew(v, addr)                       \
+    {                                         \
+        (*(volatile uint16 *)(addr)) = (v); \
+    }
+#define writed(v, addr)                       \
+    {                                         \
+        (*(volatile uint32 *)(addr)) = (v); \
+    }
+#define writeq(v, addr)                       \
+    {                                         \
+        (*(volatile uint64 *)(addr)) = (v); \
+    }
+
+#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
+
+#define CLOCK_REALTIME 0
+#define CLOCK_MONOTONIC 1
+#define CLOCK_PROCESS_CPUTIME_ID 2
+#define CLOCK_THREAD_CPUTIME_ID 3
+#endif
diff --git a/kernel/include/uname.h b/kernel/include/uname.h
new file mode 100644
index 0000000000000000000000000000000000000000..7889d2622e0a78bcfe5e756ad8c4eea8e1a797fd
--- /dev/null
+++ b/kernel/include/uname.h
@@ -0,0 +1,28 @@
+#ifndef __UNAME_H 
+#define __UNAME_H 
+
+#include "types.h"
+
+#define UTSNAME_STR_LEN 	65
+struct utsname {
+	char sysname[UTSNAME_STR_LEN];
+	char nodename[UTSNAME_STR_LEN];
+	char release[UTSNAME_STR_LEN];
+	char version[UTSNAME_STR_LEN];
+	char machine[UTSNAME_STR_LEN];
+	char domainname[UTSNAME_STR_LEN];
+};
+
+extern char const UNAME_SYSNAME[];
+extern char const UNAME_NODENAME[];
+extern char const UNAME_RELEASE[];
+extern char const UNAME_VERSION[];
+extern char const UNAME_MACHINE[];
+extern char const UNAME_DOMAINNAME[];
+
+
+
+int do_uname(uint64 addr);
+void sys_nameinit();
+
+#endif
\ No newline at end of file
diff --git a/kernel/include/utils.h b/kernel/include/utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..b61076cd636a7430eb0d4c6806b744c995cd566a
--- /dev/null
+++ b/kernel/include/utils.h
@@ -0,0 +1,339 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _DRIVER_UTILS_H
+#define _DRIVER_UTILS_H
+
+// #ifdef __cplusplus
+// #include <cstdbool>
+// #include <cstddef>
+// #include <cstdint>
+// #else /* __cplusplus */
+// #include <stdbool.h>
+// #include <stddef.h>
+// #include <stdint.h>
+// #include <stdio.h>
+// #endif /* __cplusplus */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define KENDRYTE_MIN(a, b) ((a) > (b) ? (b) : (a))
+#define KENDRYTE_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#ifdef __ASSEMBLY__
+#define KENDRYTE_CAST(type, ptr) ptr
+#else /* __ASSEMBLY__ */
+/**
+ * @brief       Cast the pointer to specified pointer type.
+ *
+ * @param[in]   type        The pointer type to cast to
+ * @param[in]   ptr         The pointer to apply the type cast to
+ */
+#define KENDRYTE_CAST(type, ptr) ((type)(ptr))
+#endif /* __ASSEMBLY__ */
+
+/**
+ * @addtogroup      UTIL_RW_FUNC Memory Read/Write Utilities
+ *
+ * This section implements read and write functionality for various
+ * memory untis. The memory unit terms used for these functions are
+ * consistent with those used in the ARM Architecture Reference Manual
+ * ARMv7-A and ARMv7-R edition manual. The terms used for units of memory are:
+ *
+ *  Unit of Memory | Abbreviation | Size in Bits
+ * :---------------|:-------------|:------------:
+ *  Byte           | byte         |       8
+ *  Half Word      | hword        |      16
+ *  Word           | word         |      32
+ *  Double Word    | dword        |      64
+ *
+ */
+
+/**
+ * @brief       Write the 8 bit byte to the destination address in device memory.
+ *
+ * @param[in]   dest        Write destination pointer address
+ * @param[in]   src         8 bit data byte to write to memory
+ */
+#define kendryte_write_byte(dest, src) \
+    (*KENDRYTE_CAST(volatile uint8_t *, (dest)) = (src))
+
+/**
+ * @brief       Read and return the 8 bit byte from the source address in device memory.
+ *
+ * @param[in]   src     Read source pointer address
+ *
+ * @return      8 bit data byte value
+ */
+#define kendryte_read_byte(src) (*KENDRYTE_CAST(volatile uint8_t *, (src)))
+
+/**
+ * @brief       Write the 16 bit half word to the destination address in device memory.
+ *
+ * @param[in]   dest        Write destination pointer address
+ * @param[in]   src         16 bit data half word to write to memory
+ */
+#define kendryte_write_hword(dest, src) \
+    (*KENDRYTE_CAST(volatile uint16_t *, (dest)) = (src))
+
+/**
+ * @brief       Read and return the 16 bit half word from the source address in device
+ *
+ * @param[in]   src     Read source pointer address
+ *
+ * @return      16 bit data half word value
+ */
+#define kendryte_read_hword(src) (*KENDRYTE_CAST(volatile uint16_t *, (src)))
+
+/**
+ * @brief       Write the 32 bit word to the destination address in device memory.
+ *
+ * @param[in]   dest        Write destination pointer address
+ * @param[in]   src         32 bit data word to write to memory
+ */
+#define kendryte_write_word(dest, src) \
+    (*KENDRYTE_CAST(volatile uint32 *, (dest)) = (src))
+
+/**
+ * @brief       Read and return the 32 bit word from the source address in device memory.
+ *
+ * @param[in]   src     Read source pointer address
+ *
+ * @return      32 bit data half word value
+ */
+#define kendryte_read_word(src) (*KENDRYTE_CAST(volatile uint32 *, (src)))
+
+/**
+ * @brief       Write the 64 bit double word to the destination address in device memory.
+ *
+ * @param[in]   dest        Write destination pointer address
+ * @param[in]   src         64 bit data word to write to memory
+ */
+#define kendryte_write_dword(dest, src) \
+    (*KENDRYTE_CAST(volatile uint64_t *, (dest)) = (src))
+
+/**
+ * @brief       Read and return the 64 bit double word from the source address in device
+ *
+ * @param[in]   src     Read source pointer address
+ *
+ * @return      64 bit data half word value
+ */
+#define kendryte_read_dword(src) (*KENDRYTE_CAST(volatile uint64_t *, (src)))
+
+/**
+ * @brief       Set selected bits in the 8 bit byte at the destination address in device
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to set in destination byte
+ */
+#define kendryte_setbits_byte(dest, bits) \
+    (kendryte_write_byte(dest, kendryte_read_byte(dest) | (bits)))
+
+/**
+ * @brief       Clear selected bits in the 8 bit byte at the destination address in device
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to clear in destination byte
+ */
+#define kendryte_clrbits_byte(dest, bits) \
+    (kendryte_write_byte(dest, kendryte_read_byte(dest) & ~(bits)))
+
+/**
+ * @brief       Change or toggle selected bits in the 8 bit byte at the destination address
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to change in destination byte
+ */
+#define kendryte_xorbits_byte(dest, bits) \
+    (kendryte_write_byte(dest, kendryte_read_byte(dest) ^ (bits)))
+
+/**
+ * @brief       Replace selected bits in the 8 bit byte at the destination address in device
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   msk         Bits to replace in destination byte
+ * @param[in]   src         Source bits to write to cleared bits in destination byte
+ */
+#define kendryte_replbits_byte(dest, msk, src) \
+    (kendryte_write_byte(dest, (kendryte_read_byte(dest) & ~(msk)) | ((src) & (msk))))
+
+/**
+ * @brief       Set selected bits in the 16 bit halfword at the destination address in
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to set in destination halfword
+ */
+#define kendryte_setbits_hword(dest, bits) \
+    (kendryte_write_hword(dest, kendryte_read_hword(dest) | (bits)))
+
+/**
+ * @brief       Clear selected bits in the 16 bit halfword at the destination address in
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to clear in destination halfword
+ */
+#define kendryte_clrbits_hword(dest, bits) \
+    (kendryte_write_hword(dest, kendryte_read_hword(dest) & ~(bits)))
+
+/**
+ * @brief       Change or toggle selected bits in the 16 bit halfword at the destination
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to change in destination halfword
+ */
+#define kendryte_xorbits_hword(dest, bits) \
+    (kendryte_write_hword(dest, kendryte_read_hword(dest) ^ (bits)))
+
+/**
+ * @brief       Replace selected bits in the 16 bit halfword at the destination address in
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   msk         Bits to replace in destination byte
+ * @param[in]   src         Source bits to write to cleared bits in destination halfword
+ */
+#define kendryte_replbits_hword(dest, msk, src) \
+    (kendryte_write_hword(dest, (kendryte_read_hword(dest) & ~(msk)) | ((src) & (msk))))
+
+/**
+ * @brief       Set selected bits in the 32 bit word at the destination address in device
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to set in destination word
+ */
+#define kendryte_setbits_word(dest, bits) \
+    (kendryte_write_word(dest, kendryte_read_word(dest) | (bits)))
+
+/**
+ * @brief       Clear selected bits in the 32 bit word at the destination address in device
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to clear in destination word
+ */
+#define kendryte_clrbits_word(dest, bits) \
+    (kendryte_write_word(dest, kendryte_read_word(dest) & ~(bits)))
+
+/**
+ * @brief       Change or toggle selected bits in the 32 bit word at the destination address
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to change in destination word
+ */
+#define kendryte_xorbits_word(dest, bits) \
+    (kendryte_write_word(dest, kendryte_read_word(dest) ^ (bits)))
+
+/**
+ * @brief       Replace selected bits in the 32 bit word at the destination address in
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   msk         Bits to replace in destination word
+ * @param[in]   src         Source bits to write to cleared bits in destination word
+ */
+#define kendryte_replbits_word(dest, msk, src) \
+    (kendryte_write_word(dest, (kendryte_read_word(dest) & ~(msk)) | ((src) & (msk))))
+
+/**
+ * @brief      Set selected bits in the 64 bit doubleword at the destination address in
+ *
+ * @param[in]   dest     Destination pointer address
+ * @param[in]   bits     Bits to set in destination doubleword
+ */
+#define kendryte_setbits_dword(dest, bits) \
+    (kendryte_write_dword(dest, kendryte_read_dword(dest) | (bits)))
+
+/**
+ * @brief       Clear selected bits in the 64 bit doubleword at the destination address in
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to clear in destination doubleword
+ */
+#define kendryte_clrbits_dword(dest, bits) \
+    (kendryte_write_dword(dest, kendryte_read_dword(dest) & ~(bits)))
+
+/**
+ * @brief       Change or toggle selected bits in the 64 bit doubleword at the destination
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   bits        Bits to change in destination doubleword
+ */
+#define kendryte_xorbits_dword(dest, bits) \
+    (kendryte_write_dword(dest, kendryte_read_dword(dest) ^ (bits)))
+
+/**
+ * @brief       Replace selected bits in the 64 bit doubleword at the destination address in
+ *
+ * @param[in]   dest        Destination pointer address
+ * @param[in]   msk         its to replace in destination doubleword
+ * @param[in]   src         Source bits to write to cleared bits in destination word
+ */
+#define kendryte_replbits_dword(dest, msk, src) \
+    (kendryte_write_dword(dest, (kendryte_read_dword(dest) & ~(msk)) | ((src) & (msk))))
+
+
+/**
+ * @brief       Set value by mask
+ *
+ * @param[in]   bits        The one be set
+ * @param[in]   mask        mask value
+ * @param[in]   value       The value to set
+ */
+void set_bit(volatile uint32 *bits, uint32 mask, uint32 value);
+
+/**
+ * @brief       Set value by mask
+ *
+ * @param[in]   bits        The one be set
+ * @param[in]   mask        Mask value
+ * @param[in]   offset      Mask's offset
+ * @param[in]   value       The value to set
+ */
+void set_bit_offset(volatile uint32 *bits, uint32 mask, uint64 offset, uint32 value);
+
+/**
+ * @brief       Set bit for gpio, only set one bit
+ *
+ * @param[in]   bits        The one be set
+ * @param[in]   idx         Offset value
+ * @param[in]   value       The value to set
+ */
+void set_gpio_bit(volatile uint32 *bits, uint64 idx, uint32 value);
+
+/**
+ * @brief      Get bits value of mask
+ *
+ * @param[in]   bits        The source data
+ * @param[in]   mask        Mask value
+ * @param[in]   offset      Mask's offset
+ *
+ * @return      The bits value of mask
+ */
+uint32 get_bit(volatile uint32 *bits, uint32 mask, uint64 offset);
+
+/**
+ * @brief       Get a bit value by offset
+ *
+ * @param[in]   bits        The source data
+ * @param[in]   offset      Bit's offset
+ *
+ *
+ * @return      The bit value
+ */
+uint32 get_gpio_bit(volatile uint32 *bits, uint64 offset);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _DRIVER_COMMON_H */
diff --git a/kernel/include/virtio.h b/kernel/include/virtio.h
new file mode 100644
index 0000000000000000000000000000000000000000..caf6d47878202cf1deabd90fb3a51d3e47d42c1a
--- /dev/null
+++ b/kernel/include/virtio.h
@@ -0,0 +1,84 @@
+#ifndef __VIRTIO_H
+#define __VIRTIO_H
+
+#include "types.h"
+#include "buf.h"
+
+//
+// virtio device definitions.
+// for both the mmio interface, and virtio descriptors.
+// only tested with qemu.
+// this is the "legacy" virtio interface.
+//
+// the virtio spec:
+// https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.pdf
+//
+
+// virtio mmio control registers, mapped starting at 0x10001000.
+// from qemu virtio_mmio.h
+#define VIRTIO_MMIO_MAGIC_VALUE		0x000 // 0x74726976
+#define VIRTIO_MMIO_VERSION		0x004 // version; 1 is legacy
+#define VIRTIO_MMIO_DEVICE_ID		0x008 // device type; 1 is net, 2 is disk
+#define VIRTIO_MMIO_VENDOR_ID		0x00c // 0x554d4551
+#define VIRTIO_MMIO_DEVICE_FEATURES	0x010
+#define VIRTIO_MMIO_DRIVER_FEATURES	0x020
+#define VIRTIO_MMIO_GUEST_PAGE_SIZE	0x028 // page size for PFN, write-only
+#define VIRTIO_MMIO_QUEUE_SEL		0x030 // select queue, write-only
+#define VIRTIO_MMIO_QUEUE_NUM_MAX	0x034 // max size of current queue, read-only
+#define VIRTIO_MMIO_QUEUE_NUM		0x038 // size of current queue, write-only
+#define VIRTIO_MMIO_QUEUE_ALIGN		0x03c // used ring alignment, write-only
+#define VIRTIO_MMIO_QUEUE_PFN		0x040 // physical page number for queue, read/write
+#define VIRTIO_MMIO_QUEUE_READY		0x044 // ready bit
+#define VIRTIO_MMIO_QUEUE_NOTIFY	0x050 // write-only
+#define VIRTIO_MMIO_INTERRUPT_STATUS	0x060 // read-only
+#define VIRTIO_MMIO_INTERRUPT_ACK	0x064 // write-only
+#define VIRTIO_MMIO_STATUS		0x070 // read/write
+
+// status register bits, from qemu virtio_config.h
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE	1
+#define VIRTIO_CONFIG_S_DRIVER		2
+#define VIRTIO_CONFIG_S_DRIVER_OK	4
+#define VIRTIO_CONFIG_S_FEATURES_OK	8
+
+// device feature bits
+#define VIRTIO_BLK_F_RO              5	/* Disk is read-only */
+#define VIRTIO_BLK_F_SCSI            7	/* Supports scsi command passthru */
+#define VIRTIO_BLK_F_CONFIG_WCE     11	/* Writeback mode available in config */
+#define VIRTIO_BLK_F_MQ             12	/* support more than one vq */
+#define VIRTIO_F_ANY_LAYOUT         27
+#define VIRTIO_RING_F_INDIRECT_DESC 28
+#define VIRTIO_RING_F_EVENT_IDX     29
+
+// this many virtio descriptors.
+// must be a power of two.
+#define NUM 8
+
+struct VRingDesc {
+  uint64 addr;
+  uint32 len;
+  uint16 flags;
+  uint16 next;
+};
+#define VRING_DESC_F_NEXT  1 // chained with another descriptor
+#define VRING_DESC_F_WRITE 2 // device writes (vs read)
+
+struct VRingUsedElem {
+  uint32 id;   // index of start of completed descriptor chain
+  uint32 len;
+};
+
+// for disk ops
+#define VIRTIO_BLK_T_IN  0 // read the disk
+#define VIRTIO_BLK_T_OUT 1 // write the disk
+
+struct UsedArea {
+  uint16 flags;
+  uint16 id;
+  struct VRingUsedElem elems[NUM];
+};
+
+void            virtio_disk_init(void);
+void            virtio_disk_rw(struct buf *b, int write);
+void            virtio_disk_intr(void);
+
+#endif
diff --git a/kernel/include/vm.h b/kernel/include/vm.h
new file mode 100644
index 0000000000000000000000000000000000000000..c324230f708ffdbcb99020747732dd06affe7b43
--- /dev/null
+++ b/kernel/include/vm.h
@@ -0,0 +1,55 @@
+#ifndef __VM_H 
+#define __VM_H 
+
+#include "types.h"
+#include "riscv.h"
+#include "fat32.h"
+#include "proc.h"
+
+void            kvminit(void);
+void            kvminithart(void);
+uint64          kvmpa(uint64);
+void            kvmmap(uint64, uint64, uint64, int);
+int             mappages(pagetable_t, uint64, uint64, uint64, int);
+pagetable_t     uvmcreate(void);
+// void            uvminit(pagetable_t, uchar *, uint);
+int             uvminit(pagetable_t, pagetable_t, uchar *, uint);
+uint64          uvmalloc(pagetable_t, pagetable_t, uint64, uint64);
+uint64          uvmdealloc(pagetable_t, pagetable_t, uint64, uint64);
+// int             uvmcopy(pagetable_t, pagetable_t, uint64);
+int             uvmcopy(pagetable_t, pagetable_t, pagetable_t, uint64);
+void            uvmfree(pagetable_t, uint64);
+// void            uvmunmap(pagetable_t, uint64, uint64, int);
+void            vmunmap(pagetable_t, uint64, uint64, int);
+void            uvmclear(pagetable_t, uint64);
+uint64          walkaddr(pagetable_t, uint64);
+uint64          walkaddr2(pagetable_t, uint64);
+int             copyout(pagetable_t, uint64, char *, uint64);
+int             copyin(pagetable_t, char *, uint64, uint64);
+int             copyinstr(pagetable_t, char *, uint64, uint64);
+pagetable_t     proc_kpagetable(void);
+void            kvmfreeusr(pagetable_t kpt);
+void            kvmfree(pagetable_t kpagetable, int stack_free);
+uint64          kwalkaddr(pagetable_t pagetable, uint64 va);
+// int             copyout2(uint64 dstva,const char *src, uint64 len);
+// int             copyin2(char *dst, uint64 srcva, uint64 len);
+int             copyinstr2(char *dst, uint64 srcva, uint64 max);
+pte_t *         walk(pagetable_t pagetable, uint64 va, int alloc);
+void            vmprint(pagetable_t pagetable);
+int             loadseg(pagetable_t pagetable, uint64 va, struct dirent *ep, uint offset, uint sz);
+int             copy_elfseg(pagetable_t pagetable, uint64 src, char *dstva, uint64 len);
+
+int             proc_share(pagetable_t old, pagetable_t new, pagetable_t knew, uint64 start, uint64 end);
+
+int             start_map(uint64 start_address,unsigned long len,int prot, struct dirent *ep,long off);
+int             end_map(uint64 start_address,long len);
+uint64          uvmallocpage(pagetable_t pagetable, pagetable_t kpagetable, uint64 a);
+void            uvmdeallocpage(pagetable_t pagetable, pagetable_t kpagetable, uint64 a);
+int            memoryload(uint64 addr);
+int             check_map_link(uint64 addr,struct proc* p);
+int             rangeinseg(uint64 start, uint64 end);
+int             do_load_fault(uint64 addr);
+int             do_store_fault(uint64 addr);
+uint64          uvmallocpage2(pagetable_t pagetable, pagetable_t kpagetable, uint64 a, int flags);
+int             do_ins_fault(uint64 addr);
+#endif 
diff --git a/kernel/include/zero.h b/kernel/include/zero.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c8a5d533e51f567b267ca327936d8fc65f5637c
--- /dev/null
+++ b/kernel/include/zero.h
@@ -0,0 +1,10 @@
+#ifndef __ZERO_H
+#define __ZERO_H
+
+#include "types.h"
+
+void zeroinit(void);
+int zeroread(int user_dst, uint64 dst, int n);
+int zerowrite(int user_src, uint64 src, int n);
+
+#endif
\ No newline at end of file
diff --git a/kernel/intr.c b/kernel/intr.c
new file mode 100644
index 0000000000000000000000000000000000000000..27b7ec3beaf62a8b64bb8d43447ebdcb3fcdf390
--- /dev/null
+++ b/kernel/intr.c
@@ -0,0 +1,40 @@
+#include "include/types.h"
+#include "include/param.h"
+#include "include/proc.h"
+#include "include/intr.h"
+#include "include/printf.h"
+
+// push_off/pop_off are like intr_off()/intr_on() except that they are matched:
+// it takes two pop_off()s to undo two push_off()s.  Also, if interrupts
+// are initially off, then push_off, pop_off leaves them off.
+
+void
+push_off(void)
+{
+  int old = intr_get();
+
+  intr_off();
+  //printf("\e[32mpush_off()\e[0m: cpuid(): %d\n", cpuid());
+  if(mycpu()->noff == 0)
+    mycpu()->intena = old;
+  mycpu()->noff += 1;
+}
+
+void
+pop_off(void)
+{
+  struct cpu *c = mycpu();
+
+  //printf("\e[31mpop_off()\e[0m: cpuid(): %d\n", cpuid());
+  if(intr_get())
+    panic("pop_off - interruptible");
+  if(c->noff < 1) {
+    //printf("c->noff = %d\n", c->noff);
+    panic("pop_off");
+  }
+  //printf("c->noff: %d\n", c->noff);
+  //printf("c: %x\n", c);
+  c->noff -= 1;
+  if(c->noff == 0 && c->intena)
+    intr_on();
+}
diff --git a/kernel/kalloc.c b/kernel/kalloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..60c0adacd0c14780a1b42e72bd2d7b503a162e20
--- /dev/null
+++ b/kernel/kalloc.c
@@ -0,0 +1,193 @@
+// Physical memory allocator, for user processes,
+// kernel stacks, page-table pages,
+// and pipe buffers. Allocates whole 4096-byte pages.
+
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+#include "include/spinlock.h"
+#include "include/kalloc.h"
+#include "include/string.h"
+#include "include/printf.h"
+#include "include/vm.h"
+#include "include/proc.h"
+
+void freerange(void *pa_start, void *pa_end);
+char *mm_table;
+int mm_table_sz=0;
+uint64 pa_addr_start=0;
+
+extern char kernel_end[]; // first address after kernel.
+
+struct run {
+  struct run *next;
+};
+
+struct kmem kmem;
+extern char etext[];
+void
+kinit()
+{
+  initlock(&kmem.lock, "kmem");
+  kmem.freelist = 0;
+  kmem.npage = 0;
+  freerange(kernel_end, (void*)PHYSTOP);
+  #ifdef DEBUG
+  printf("kernel_end: %p, phystop: %p\n", kernel_end, (void*)PHYSTOP);
+  printf("kinit\n");
+  #endif
+}
+
+void
+freerange(void *pa_start, void *pa_end)
+{
+  char *p;
+  p = (char*)PGROUNDUP((uint64)pa_start);
+  mm_table_sz=((uint64)pa_end-(uint64)p)/PGSIZE;
+  int mm_table_page_sz=(mm_table_sz+PGSIZE-1)/PGSIZE;
+  mm_table_sz-=mm_table_page_sz;
+  mm_table=p;
+  p+=mm_table_page_sz*PGSIZE;
+  pa_addr_start=(uint64)p;
+  memset(mm_table, 1, mm_table_sz);
+  for(; p + PGSIZE < (char*)pa_end; p += PGSIZE)
+    kfree(p);
+  // memset(mm_table, 0, mm_table_sz);
+}
+
+// Free the page of physical memory pointed at by v,
+// which normally should have been returned by a
+// call to kalloc().  (The exception is when
+// initializing the allocator; see kinit above.)
+void
+kfree(void *pa)
+{
+  struct run *r;
+  
+  if(((uint64)pa % PGSIZE) != 0 || (char*)pa < kernel_end || (uint64)pa >= PHYSTOP)
+    panic("panic in kfree");
+  
+  int index=((uint64)pa-pa_addr_start)/PGSIZE;
+  acquire(&kmem.lock);
+  if(mm_table[index]>1){
+    --mm_table[index];
+    release(&kmem.lock);
+    return;
+  }
+  if(mm_table[index] == 0){
+    release(&kmem.lock);
+    __ERROR("%p can't free",pa);
+    panic("");
+  }
+  // Fill with junk to catch dangling refs.
+  memset(pa, 0, PGSIZE);
+
+  r = (struct run*)pa;
+
+  r->next = kmem.freelist;
+  kmem.freelist = r;
+  kmem.npage++;
+  //printf("----freepage---------------%d\n",index);
+  //printf("%d\n",kmem.npage);
+  --mm_table[index];
+  release(&kmem.lock);
+  
+}
+
+// Allocate one 4096-byte page of physical memory.
+// Returns a pointer that the kernel can use.
+// Returns 0 if the memory cannot be allocated.
+void *
+kalloc(void)
+{
+  struct run *r;
+
+  acquire(&kmem.lock);
+  r = kmem.freelist;
+  // __DEBUG("%d",kmem.npage);
+  if(r) {
+    kmem.freelist = r->next;
+    kmem.npage--;
+  }else{
+    __ERROR("don't have free page");
+    return (void*)r;
+  }
+
+  int index=((uint64)r-pa_addr_start)/PGSIZE;
+  // if(index >= mm_table_sz){
+  //   __ERROR("index = %d, mm_table_sz = %d",index,mm_table_sz);
+  // }
+  //printf("----page---------------%d\n",index);
+  if(mm_table[index] > 0){
+    release(&kmem.lock);
+    __ERROR("%p can't alloc",(uint64)r);
+    panic("");
+  }
+  ++mm_table[index];
+  release(&kmem.lock);
+  
+  
+
+  if(r)
+    memset((char*)r, 0, PGSIZE); // fill with junk
+  return (void*)r;
+}
+
+uint64
+freemem_amount(void)
+{
+  return kmem.npage << PGSHIFT;
+}
+void kernel_page_fault(void){
+  uint64 a =  PGROUNDDOWN(r_stval());
+  struct proc *p = myproc();
+  char *mem;
+  acquire(&kmem.lock);
+  struct run *r;
+  r = kmem.freelist;
+  if(r) {
+    kmem.freelist = r->next;
+    kmem.npage--;
+  }
+
+  if(r)
+    memset((char*)r, 5, PGSIZE);
+  else {
+    __ERROR("");
+    panic("");
+  }
+  mem = (char *)r;
+  memset(mem, 0, PGSIZE);
+
+  if (mappages(p->kpagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R) != 0){
+    __ERROR("error");
+    panic("");
+  }
+  int index=((uint64)r-pa_addr_start)/PGSIZE;
+  
+  mm_table[index]++;
+  release(&kmem.lock);
+}
+
+
+// uint64 kmalloc(int sz){    //内核的动态分配内存
+//   static uint64 mem=0;
+//   static int remaining_sz=0;
+//   uint64 ret=0;
+//   if(remaining_sz==0){
+//     mem=kalloc();
+//     remaining_sz=PGSIZE;
+//   }
+//   else{
+//     ret=mem;
+//     while(remaining_sz<sz){
+      
+//       sz-=remaining_sz;
+//     }
+//   }
+//   if(ret)
+//     memset((char*)mem, 5, sz);
+//   return 0;
+// }
diff --git a/kernel/kernelvec.S b/kernel/kernelvec.S
new file mode 100644
index 0000000000000000000000000000000000000000..cfd88f5e681ddc440024107eb8f308e0022cfe01
--- /dev/null
+++ b/kernel/kernelvec.S
@@ -0,0 +1,86 @@
+	#
+        # interrupts and exceptions while in supervisor
+        # mode come here.
+        #
+        # push all registers, call kerneltrap(), restore, return.
+        #
+.globl kerneltrap
+.globl kernelvec
+.align 4
+kernelvec:
+        // make room to save registers.
+        addi sp, sp, -256
+
+        // save the registers.
+        sd ra, 0(sp)
+        sd sp, 8(sp)
+        sd gp, 16(sp)
+        sd tp, 24(sp)
+        sd t0, 32(sp)
+        sd t1, 40(sp)
+        sd t2, 48(sp)
+        sd s0, 56(sp)
+        sd s1, 64(sp)
+        sd a0, 72(sp)
+        sd a1, 80(sp)
+        sd a2, 88(sp)
+        sd a3, 96(sp)
+        sd a4, 104(sp)
+        sd a5, 112(sp)
+        sd a6, 120(sp)
+        sd a7, 128(sp)
+        sd s2, 136(sp)
+        sd s3, 144(sp)
+        sd s4, 152(sp)
+        sd s5, 160(sp)
+        sd s6, 168(sp)
+        sd s7, 176(sp)
+        sd s8, 184(sp)
+        sd s9, 192(sp)
+        sd s10, 200(sp)
+        sd s11, 208(sp)
+        sd t3, 216(sp)
+        sd t4, 224(sp)
+        sd t5, 232(sp)
+        sd t6, 240(sp)
+
+	// call the C trap handler in trap.c
+        call kerneltrap
+
+        // restore registers.
+        ld ra, 0(sp)
+        ld sp, 8(sp)
+        ld gp, 16(sp)
+        // not this, in case we moved CPUs: ld tp, 24(sp)
+        ld t0, 32(sp)
+        ld t1, 40(sp)
+        ld t2, 48(sp)
+        ld s0, 56(sp)
+        ld s1, 64(sp)
+        ld a0, 72(sp)
+        ld a1, 80(sp)
+        ld a2, 88(sp)
+        ld a3, 96(sp)
+        ld a4, 104(sp)
+        ld a5, 112(sp)
+        ld a6, 120(sp)
+        ld a7, 128(sp)
+        ld s2, 136(sp)
+        ld s3, 144(sp)
+        ld s4, 152(sp)
+        ld s5, 160(sp)
+        ld s6, 168(sp)
+        ld s7, 176(sp)
+        ld s8, 184(sp)
+        ld s9, 192(sp)
+        ld s10, 200(sp)
+        ld s11, 208(sp)
+        ld t3, 216(sp)
+        ld t4, 224(sp)
+        ld t5, 232(sp)
+        ld t6, 240(sp)
+
+        addi sp, sp, 256
+
+        // return to whatever we were doing in the kernel.
+        sret
diff --git a/kernel/logo.c b/kernel/logo.c
new file mode 100644
index 0000000000000000000000000000000000000000..2a888c859943d16da17aa05891a0a4bbca72bbe5
--- /dev/null
+++ b/kernel/logo.c
@@ -0,0 +1,30 @@
+// Print Logo
+#include "include/types.h"
+#include "include/riscv.h"
+
+#ifdef QEMU
+void print_logo() {
+    printf("  (`-.            (`-.                            .-')       ('-.    _   .-')\n");
+    printf(" ( OO ).        _(OO  )_                        .(  OO)    _(  OO)  ( '.( OO )_ \n");
+    printf("(_/.  \\_)-. ,--(_/   ,. \\  ,--.                (_)---\\_)  (,------.  ,--.   ,--.) ,--. ,--.  \n");
+    printf(" \\  `.'  /  \\   \\   /(__/ /  .'       .-')     '  .-.  '   |  .---'  |   `.'   |  |  | |  |   \n");
+    printf("  \\     /\\   \\   \\ /   / .  / -.    _(  OO)   ,|  | |  |   |  |      |         |  |  | | .-')\n");
+    printf("   \\   \\ |    \\   '   /, | .-.  '  (,------. (_|  | |  |  (|  '--.   |  |'.'|  |  |  |_|( OO )\n");
+    printf("  .'    \\_)    \\     /__)' \\  |  |  '------'   |  | |  |   |  .--'   |  |   |  |  |  | | `-' /\n");
+    printf(" /  .'.  \\      \\   /    \\  `'  /              '  '-'  '-. |  `---.  |  |   |  | ('  '-'(_.-'\n");
+    printf("'--'   '--'      `-'      `----'                `-----'--' `------'  `--'   `--'   `-----'\n");
+}
+#else
+void print_logo() {
+    printf(" (`-')           (`-')                   <-.(`-')\n");
+    printf(" (OO )_.->      _(OO )                    __( OO)\n");
+    printf(" (_| \\_)--.,--.(_/,-.\\  ,--.    (`-')    '-'. ,--.  .----.   .--.   .----.\n");
+    printf(" \\  `.'  / \\   \\ / (_/ /  .'    ( OO).-> |  .'   / \\_,-.  | /_  |  /  ..  \\\n");
+    printf("  \\    .')  \\   /   / .  / -.  (,------. |      /)    .' .'  |  | |  /  \\  .\n");
+    printf("  .'    \\  _ \\     /_)'  .-. \\  `------' |  .   '   .'  /_   |  | '  \\  /  '\n");
+    printf(" /  .'.  \\ \\-'\\   /   \\  `-' /           |  |\\   \\ |      |  |  |  \\  `'  /\n");
+    printf("`--'   '--'    `-'     `----'            `--' '--' `------'  `--'   `---''\n");
+}
+#endif
+  
+
diff --git a/kernel/main.c b/kernel/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..64431e772af47c753bcb4143e1ff93222c87497c
--- /dev/null
+++ b/kernel/main.c
@@ -0,0 +1,93 @@
+// Copyright (c) 2006-2019 Frans Kaashoek, Robert Morris, Russ Cox,
+//                         Massachusetts Institute of Technology
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+#include "include/sbi.h"
+#include "include/console.h"
+#include "include/printf.h"
+#include "include/kalloc.h"
+#include "include/timer.h"
+#include "include/trap.h"
+#include "include/proc.h"
+#include "include/plic.h"
+#include "include/vm.h"
+#include "include/disk.h"
+#include "include/buf.h"
+#include "include/uname.h"
+#include "include/zero.h"
+#include "include/null.h"
+
+#ifndef QEMU
+#include "include/sdcard.h"
+#include "include/fpioa.h"
+#include "include/dmac.h"
+#endif
+
+static inline void inithartid(unsigned long hartid) {
+  asm volatile("mv tp, %0" : : "r" (hartid & 0x1));
+}
+
+volatile static int started = 0;
+
+void
+main(unsigned long hartid, unsigned long dtb_pa)
+{
+  inithartid(hartid);
+  
+  if (hartid == 0) {
+    zeroinit();
+    nullinit();
+    consoleinit();
+    floatinithart();
+    printfinit();   // init a lock for printf 
+    print_logo();
+    #ifdef DEBUG
+    printf("hart %d enter main()...\n", hartid);
+    #endif
+    kinit();         // physical page allocator
+    kvminit();       // create kernel page table
+    kvminithart();   // turn on paging
+    timerinit();     // init a lock for timer
+    trapinithart();  // install kernel trap vector, including interrupt handler
+    procinit();
+    plicinit();
+    plicinithart();
+    #ifndef QEMU
+    fpioa_pin_init();
+    dmac_init();
+    #endif 
+    disk_init();
+    binit();         // buffer cache
+    fileinit();      // file table
+    userinit();      // first user process
+    // printf("hart 0 init done\n");
+    __INF("hart 0 init done");
+
+    for(int i = 1; i < NCPU; i++) {
+      unsigned long mask = 1 << i;
+      sbi_send_ipi(&mask);
+    }
+    __sync_synchronize();
+    started = 1;
+  }
+  else
+  {
+    // hart 1
+    while (started == 0)
+      ;
+    __sync_synchronize();
+    #ifdef DEBUG
+    printf("hart %d enter main()...\n", hartid);
+    #endif
+    floatinithart();
+    kvminithart();
+    trapinithart();
+    plicinithart();  // ask PLIC for device interrupts
+    // printf("hart 1 init done\n");
+    __INF("hart 1 init done");
+  }
+  scheduler();
+}
diff --git a/kernel/null.c b/kernel/null.c
new file mode 100644
index 0000000000000000000000000000000000000000..fecd28761c80bb59bbd4016e80f3b805fa7587de
--- /dev/null
+++ b/kernel/null.c
@@ -0,0 +1,19 @@
+#include "include/null.h"
+#include "include/proc.h"
+#include "include/string.h"
+
+#define NULL_DEV 4
+
+int nullread(int user_dst, uint64 dst, int n){
+    return 0;
+}
+
+int nullwrite(int user_src, uint64 src, int n){
+    memset((void *)src, 0, n);
+    return n;
+}
+
+void nullinit(void){
+    devsw[NULL_DEV].read = nullread;
+    devsw[NULL_DEV].write = nullwrite;
+}
\ No newline at end of file
diff --git a/kernel/pipe.c b/kernel/pipe.c
new file mode 100644
index 0000000000000000000000000000000000000000..ab1bcceb1e1e4213cf60bb879b586480ef4e4d08
--- /dev/null
+++ b/kernel/pipe.c
@@ -0,0 +1,245 @@
+
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/param.h"
+#include "include/spinlock.h"
+#include "include/proc.h"
+#include "include/sleeplock.h"
+#include "include/file.h"
+#include "include/pipe.h"
+#include "include/kalloc.h"
+#include "include/vm.h"
+#include "include/printf.h"
+
+int
+pipealloc(struct file **f0, struct file **f1)
+{
+  struct pipe *pi;
+
+  pi = 0;
+  *f0 = *f1 = 0;
+  if((*f0 = filealloc()) == NULL || (*f1 = filealloc()) == NULL)
+    goto bad;
+  if((pi = (struct pipe*)kalloc()) == NULL)
+    goto bad;
+  pi->readopen = 1;
+  pi->writeopen = 1;
+  pi->nwrite = 0;
+  pi->nread = 0;
+  initlock(&pi->lock, "pipe");
+  (*f0)->type = FD_PIPE;
+  (*f0)->readable = 1;
+  (*f0)->writable = 0;
+  (*f0)->pipe = pi;
+  (*f1)->type = FD_PIPE;
+  (*f1)->readable = 0;
+  (*f1)->writable = 1;
+  (*f1)->pipe = pi;
+  return 0;
+
+ bad:
+  if(pi)
+    kfree((char*)pi);
+  if(*f0)
+    fileclose(*f0);
+  if(*f1)
+    fileclose(*f1);
+  return -1;
+}
+
+void
+pipeclose(struct pipe *pi, int writable)
+{
+  acquire(&pi->lock);
+  if(writable){
+    pi->writeopen = 0;
+    wakeup(&pi->nread);
+  } else {
+    pi->readopen = 0;
+    wakeup(&pi->nwrite);
+  }
+  if(pi->readopen == 0 && pi->writeopen == 0){
+    release(&pi->lock);
+    kfree((char*)pi);
+  } else
+    release(&pi->lock);
+}
+
+int
+pipewrite(struct pipe *pi, uint64 addr, int n)
+{
+  int i;
+  char ch;
+  struct proc *pr = myproc();
+  // __DEBUG("%d",n);
+  acquire(&pi->lock);
+  for(int i = 0;i<NOFILE;i++){
+    if(pr->ofile[i] && pr->ofile[i]->type == FD_PIPE && pr->ofile[i]->pipe != pi){
+      pr->ofile[i]->pipe->writeopen = 0;
+      // __DEBUG("lock %d",i);
+    }
+  }
+  for(i = 0; i < n; i++){
+    while(pi->nwrite == pi->nread + PIPESIZE){  //DOC: pipewrite-full
+      if(pi->readopen == 0 || pr->killed){
+        release(&pi->lock);
+        __ERROR("error");
+        return -1;
+      }
+      wakeup(&pi->nread);
+      sleep(&pi->nwrite, &pi->lock);
+    }
+    // if(copyin(pr->pagetable, &ch, addr + i, 1) == -1)
+    release(&pi->lock);
+    if(copyin(pr->pagetable ,&ch, addr + i, 1) < 0){
+      acquire(&pi->lock);
+      __ERROR("copy failed");
+      break;
+    }
+    acquire(&pi->lock);
+    pi->data[pi->nwrite++ % PIPESIZE] = ch;
+    // __DEBUG("pid %d frome %p write %p to pipe",pr->pid,addr+i,ch);
+  }
+  wakeup(&pi->nread);
+  while(pi->nread != pi->nwrite){
+    release(&pi->lock);
+    yield();
+    myproc()->ivswtch += 1;
+    acquire(&pi->lock);
+  }
+  for(int i = 0;i<NOFILE;i++){
+    if(pr->ofile[i] && pr->ofile[i]->type == FD_PIPE && pr->ofile[i]->pipe != pi){
+      pr->ofile[i]->pipe->writeopen = 1;
+      // __DEBUG("free %d",i);
+    }
+  }
+  release(&pi->lock);
+  return i;
+}
+
+int
+pipewrite2(struct pipe *pi, uint64 addr, int n)
+{
+  int i;
+  char* buf = (char*)addr;
+  struct proc *pr = myproc();
+
+  acquire(&pi->lock);
+  for(int i = 0;i<NOFILE;i++){
+    if(pr->ofile[i] && pr->ofile[i]->type == FD_PIPE && pr->ofile[i]->pipe != pi){
+      pr->ofile[i]->pipe->writeopen = 0;
+    }
+  }
+  for(i = 0; i < n; i++){
+    while(pi->nwrite == pi->nread + PIPESIZE){  //DOC: pipewrite-full
+      if(pi->readopen == 0 || pr->killed){
+        release(&pi->lock);
+        __ERROR("error");
+        return -1;
+      }
+      wakeup(&pi->nread);
+      sleep(&pi->nwrite, &pi->lock);
+    }
+    pi->data[pi->nwrite++ % PIPESIZE] = buf[i];
+  }
+  wakeup(&pi->nread);
+  while(pi->nread != pi->nwrite){
+    release(&pi->lock);
+    yield();
+    myproc()->ivswtch += 1;
+    acquire(&pi->lock);
+  }
+  for(int i = 0;i<NOFILE;i++){
+    if(pr->ofile[i] && pr->ofile[i]->type == FD_PIPE && pr->ofile[i]->pipe != pi){
+      pr->ofile[i]->pipe->writeopen = 1;
+    }
+  }
+  release(&pi->lock);
+  return i;
+}
+
+int
+piperead(struct pipe *pi, uint64 addr, int n)
+{
+  int i;
+  struct proc *pr = myproc();
+  char ch;
+  // __DEBUG("%d",n);
+  acquire(&pi->lock);
+  for(int i = 0;i<NOFILE;i++){
+    if(pr->ofile[i] && pr->ofile[i]->type == FD_PIPE && pr->ofile[i]->pipe != pi){
+      pr->ofile[i]->pipe->readopen = 0;
+      // __DEBUG("lock %d",i);
+    }
+  }
+  while(pi->nread == pi->nwrite && pi->writeopen){  //DOC: pipe-empty
+    if(pr->killed){
+      release(&pi->lock);
+      return -1;
+    }
+    sleep(&pi->nread, &pi->lock); //DOC: piperead-sleep
+  }
+  for(i = 0; i < n; i++){  //DOC: piperead-copy
+    if(pi->nread == pi->nwrite)
+      break;
+    ch = pi->data[pi->nread++ % PIPESIZE];
+    // __DEBUG("pid %d from pipe read %p to %p",pr->pid,ch,addr+i);
+    if(copyout(pr->pagetable,addr + i, &ch, 1) == -1)
+      break;
+  }
+  wakeup(&pi->nwrite);  //DOC: piperead-wakeup
+  // while(pi->nread != pi->nwrite){
+  //   release(&pi->lock);
+  //   yield();
+  //   myproc()->ivswtch += 1;
+  //   acquire(&pi->lock);
+  // }
+  for(int i = 0;i<NOFILE;i++){
+    if(pr->ofile[i] && pr->ofile[i]->type == FD_PIPE && pr->ofile[i]->pipe != pi){
+      pr->ofile[i]->pipe->readopen = 1;
+      // __DEBUG("free %d",i);
+    }
+  }
+  release(&pi->lock);
+  return i;
+}
+
+int
+piperead2(struct pipe *pi, uint64 addr, int n)
+{
+  int i;
+  struct proc *pr = myproc();
+  char *buf = (char *)addr;
+  acquire(&pi->lock);
+  for(int i = 0;i<NOFILE;i++){
+    if(pr->ofile[i] && pr->ofile[i]->type == FD_PIPE && pr->ofile[i]->pipe != pi){
+      pr->ofile[i]->pipe->readopen = 0;
+    }
+  }
+  while(pi->nread == pi->nwrite && pi->writeopen){  //DOC: pipe-empty
+    if(pr->killed){
+      release(&pi->lock);
+      return -1;
+    }
+    sleep(&pi->nread, &pi->lock); //DOC: piperead-sleep
+  }
+  for(i = 0; i < n; i++){  //DOC: piperead-copy
+    if(pi->nread == pi->nwrite)
+      break;
+    buf[i] = pi->data[pi->nread++ % PIPESIZE];
+  }
+  wakeup(&pi->nwrite);  //DOC: piperead-wakeup
+  // while(pi->nread != pi->nwrite){
+  //   release(&pi->lock);
+  //   yield();
+  //   myproc()->ivswtch += 1;
+  //   acquire(&pi->lock);
+  // }
+  for(int i = 0;i<NOFILE;i++){
+    if(pr->ofile[i] && pr->ofile[i]->type == FD_PIPE && pr->ofile[i]->pipe != pi){
+      pr->ofile[i]->pipe->readopen = 1;
+    }
+  }
+  release(&pi->lock);
+  return i;
+}
\ No newline at end of file
diff --git a/kernel/plic.c b/kernel/plic.c
new file mode 100644
index 0000000000000000000000000000000000000000..0965fc247f099cb302eeb8dba3d0c14181e8f0e1
--- /dev/null
+++ b/kernel/plic.c
@@ -0,0 +1,69 @@
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+#include "include/sbi.h"
+#include "include/plic.h"
+#include "include/proc.h"
+#include "include/printf.h"
+
+//
+// the riscv Platform Level Interrupt Controller (PLIC).
+//
+
+void plicinit(void) {
+	writed(1, PLIC_V + DISK_IRQ * sizeof(uint32));  // enable disk irq
+	writed(1, PLIC_V + UART_IRQ * sizeof(uint32));  // enable uart irq
+
+	#ifdef DEBUG 
+	printf("plicinit\n");
+	#endif 
+}
+
+void
+plicinithart(void)
+{
+  int hart = cpuid();
+  #ifdef QEMU
+  // set uart's enable bit for this hart's S-mode. 
+  *(uint32*)PLIC_SENABLE(hart)= (1 << UART_IRQ) | (1 << DISK_IRQ);
+  // set this hart's S-mode priority threshold to 0.
+  *(uint32*)PLIC_SPRIORITY(hart) = 0;
+  #else
+  uint32 *hart_m_enable = (uint32*)PLIC_MENABLE(hart);
+  *(hart_m_enable) = readd(hart_m_enable) | (1 << DISK_IRQ);
+  uint32 *hart0_m_int_enable_hi = hart_m_enable + 1;
+  *(hart0_m_int_enable_hi) = readd(hart0_m_int_enable_hi) | (1 << (UART_IRQ % 32));
+  #endif
+  #ifdef DEBUG
+  printf("plicinithart\n");
+  #endif
+}
+
+// ask the PLIC what interrupt we should serve.
+int
+plic_claim(void)
+{
+  int hart = cpuid();
+  int irq;
+  #ifndef QEMU
+  irq = *(uint32*)PLIC_MCLAIM(hart);
+  #else
+  irq = *(uint32*)PLIC_SCLAIM(hart);
+  #endif
+  return irq;
+}
+
+// tell the PLIC we've served this IRQ.
+void
+plic_complete(int irq)
+{
+  int hart = cpuid();
+  #ifndef QEMU
+  *(uint32*)PLIC_MCLAIM(hart) = irq;
+  #else
+  *(uint32*)PLIC_SCLAIM(hart) = irq;
+  #endif
+}
+
diff --git a/kernel/printf.c b/kernel/printf.c
new file mode 100644
index 0000000000000000000000000000000000000000..7b0eaeeecd5dada0aabc80b8024fc1bf2a380385
--- /dev/null
+++ b/kernel/printf.c
@@ -0,0 +1,259 @@
+//
+// formatted console output -- printf, panic.
+//
+
+#include <stdarg.h>
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/riscv.h"
+#include "include/spinlock.h"
+#include "include/console.h"
+#include "include/printf.h"
+
+volatile int panicked = 0;
+
+static char digits[] = "0123456789abcdef";
+
+// lock to avoid interleaving concurrent printf's.
+static struct {
+  struct spinlock lock;
+  int locking;
+} pr;
+
+void printstring(const char* s) {
+    while (*s)
+    {
+        consputc(*s++);
+    }
+}
+
+static void
+printint(int xx, int base, int sign)
+{
+  char buf[16];
+  int i;
+  uint x;
+
+  if(sign && (sign = xx < 0))
+    x = -xx;
+  else
+    x = xx;
+
+  i = 0;
+  do {
+    buf[i++] = digits[x % base];
+  } while((x /= base) != 0);
+
+  if(sign)
+    buf[i++] = '-';
+
+  while(--i >= 0)
+    consputc(buf[i]);
+}
+
+
+static void
+printptr(uint64 x)
+{
+  int i;
+  consputc('0');
+  consputc('x');
+  for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
+    consputc(digits[x >> (sizeof(uint64) * 8 - 4)]);
+}
+
+// Print to the console. only understands %d, %x, %p, %s.
+void
+printf(char *fmt, ...)
+{
+  va_list ap;
+  int i, c;
+  int locking;
+  char *s;
+
+  locking = pr.locking;
+  if(locking)
+    acquire(&pr.lock);
+  
+  if (fmt == 0)
+    panic("null fmt");
+
+  va_start(ap, fmt);
+  for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
+    if(c != '%'){
+      consputc(c);
+      continue;
+    }
+    c = fmt[++i] & 0xff;
+    if(c == 0)
+      break;
+    switch(c){
+    case 'd':
+      printint(va_arg(ap, int), 10, 1);
+      break;
+    case 'x':
+      printint(va_arg(ap, int), 16, 1);
+      break;
+    case 'p':
+      printptr(va_arg(ap, uint64));
+      break;
+    case 's':
+      if((s = va_arg(ap, char*)) == 0)
+        s = "(null)";
+      for(; *s; s++)
+        consputc(*s);
+      break;
+    case '%':
+      consputc('%');
+      break;
+    default:
+      // Print unknown % sequence to draw attention.
+      consputc('%');
+      consputc(c);
+      break;
+    }
+  }
+  if(locking)
+    release(&pr.lock);
+}
+
+void
+panic(char *s)
+{
+  printf("panic: ");
+  printf(s);
+  printf("\n");
+  backtrace();
+  panicked = 1; // freeze uart output from other CPUs
+  for(;;)
+    ;
+}
+
+void backtrace()
+{
+  uint64 *fp = (uint64 *)r_fp();
+  uint64 *bottom = (uint64 *)PGROUNDUP((uint64)fp);
+  printf("backtrace:\n");
+  while (fp < bottom) {
+    uint64 ra = *(fp - 1);
+    printf("%p\n", ra - 4);
+    fp = (uint64 *)*(fp - 2);
+  }
+}
+
+void
+printfinit(void)
+{
+  initlock(&pr.lock, "pr");
+  pr.locking = 1;   // changed, used to be 1
+}
+
+const char* _FILE_;
+const char* _FUNCTION_;
+int _LINE_;
+int _LEVEL_;
+
+const char* LOG_LEVEL_INPUT(const int level){
+    switch (level)
+    {
+    case LOG_DEBUG:
+        return "DEBUG";
+    case LOG_INF:
+        return "INF";
+    case LOG_WARN:
+        return "WARN";
+    case LOG_ERROR:
+        return "ERROR";
+    default:
+        return "NUKNOW";
+        break;
+    }
+}
+
+
+void LOG_INPUT(const char *fmt, ...){
+  #ifdef OPEN_LOG
+  if(_LEVEL_ >= LOG_LEVEL){
+    printf("[%s] [%s:%d] ",LOG_LEVEL_INPUT(_LEVEL_), _FILE_, _LINE_);
+    va_list ap;
+    int i, c;
+    int locking;
+    char *s;
+
+    locking = pr.locking;
+
+    if(locking)
+      acquire(&pr.lock);
+  
+    if (fmt == 0)
+      panic("null fmt");
+
+    va_start(ap, fmt);
+    for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
+      if(c != '%'){
+        consputc(c);
+        continue;
+      }
+      c = fmt[++i] & 0xff;
+      if(c == 0)
+        break;
+      switch(c){
+      case 'd':
+        printint(va_arg(ap, int), 10, 1);
+        break;
+      case 'x':
+        printint(va_arg(ap, int), 16, 1);
+        break;
+      case 'p':
+        printptr(va_arg(ap, uint64));
+        break;
+      case 's':
+        if((s = va_arg(ap, char*)) == 0)
+          s = "(null)";
+        for(; *s; s++)
+          consputc(*s);
+        break;
+      case '%':
+        consputc('%');
+        break;
+      default:
+        consputc('%');
+        consputc(c);
+        break;
+      }
+    }
+    consputc('\n');
+
+    if(locking)
+      release(&pr.lock);
+  }
+  #endif
+}
+
+
+#ifdef QEMU
+void print_logo() {
+    printf("  (`-.            (`-.                            .-')       ('-.    _   .-')\n");
+    printf(" ( OO ).        _(OO  )_                        .(  OO)    _(  OO)  ( '.( OO )_ \n");
+    printf("(_/.  \\_)-. ,--(_/   ,. \\  ,--.                (_)---\\_)  (,------.  ,--.   ,--.) ,--. ,--.  \n");
+    printf(" \\  `.'  /  \\   \\   /(__/ /  .'       .-')     '  .-.  '   |  .---'  |   `.'   |  |  | |  |   \n");
+    printf("  \\     /\\   \\   \\ /   / .  / -.    _(  OO)   ,|  | |  |   |  |      |         |  |  | | .-')\n");
+    printf("   \\   \\ |    \\   '   /, | .-.  '  (,------. (_|  | |  |  (|  '--.   |  |'.'|  |  |  |_|( OO )\n");
+    printf("  .'    \\_)    \\     /__)' \\  |  |  '------'   |  | |  |   |  .--'   |  |   |  |  |  | | `-' /\n");
+    printf(" /  .'.  \\      \\   /    \\  `'  /              '  '-'  '-. |  `---.  |  |   |  | ('  '-'(_.-'\n");
+    printf("'--'   '--'      `-'      `----'                `-----'--' `------'  `--'   `--'   `-----'\n");
+}
+#else
+void print_logo() {
+    printf(" (`-')           (`-')                   <-.(`-')\n");
+    printf(" (OO )_.->      _(OO )                    __( OO)\n");
+    printf(" (_| \\_)--.,--.(_/,-.\\  ,--.    (`-')    '-'. ,--.  .----.   .--.   .----.\n");
+    printf(" \\  `.'  / \\   \\ / (_/ /  .'    ( OO).-> |  .'   / \\_,-.  | /_  |  /  ..  \\\n");
+    printf("  \\    .')  \\   /   / .  / -.  (,------. |      /)    .' .'  |  | |  /  \\  .\n");
+    printf("  .'    \\  _ \\     /_)'  .-. \\  `------' |  .   '   .'  /_   |  | '  \\  /  '\n");
+    printf(" /  .'.  \\ \\-'\\   /   \\  `-' /           |  |\\   \\ |      |  |  |  \\  `'  /\n");
+    printf("`--'   '--'    `-'     `----'            `--' '--' `------'  `--'   `---''\n");
+}
+#endif
+  
\ No newline at end of file
diff --git a/kernel/proc.c b/kernel/proc.c
new file mode 100644
index 0000000000000000000000000000000000000000..cc3384935ae349934f332520cf7f6d30a68eb564
--- /dev/null
+++ b/kernel/proc.c
@@ -0,0 +1,2096 @@
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+#include "include/spinlock.h"
+#include "include/proc.h"
+#include "include/intr.h"
+#include "include/kalloc.h"
+#include "include/printf.h"
+#include "include/string.h"
+#include "include/fat32.h"
+#include "include/file.h"
+#include "include/trap.h"
+#include "include/vm.h"
+#include "include/signal.h"
+
+struct cpu cpus[NCPU];
+
+struct proc proc[NPROC];
+
+struct proc *initproc;
+
+int nextpid = 1;
+struct spinlock pid_lock;
+
+extern void forkret(void);
+extern void swtch(struct context*, struct context*);
+static void wakeup1(struct proc *chan);
+static void freeproc(struct proc *p);
+
+extern char trampoline[]; // trampoline.S
+
+void reg_info(void) {
+  printf("register info: {\n");
+  printf("sstatus: %p\n", r_sstatus());
+  printf("sip: %p\n", r_sip());
+  printf("sie: %p\n", r_sie());
+  printf("sepc: %p\n", r_sepc());
+  printf("stvec: %p\n", r_stvec());
+  printf("satp: %p\n", r_satp());
+  printf("scause: %p\n", r_scause());
+  printf("stval: %p\n", r_stval());
+  printf("sp: %p\n", r_sp());
+  printf("tp: %p\n", r_tp());
+  printf("ra: %p\n", r_ra());
+  printf("}\n");
+}
+
+// initialize the proc table at boot time.
+void
+procinit(void)
+{
+  struct proc *p;
+  
+  initlock(&pid_lock, "nextpid");
+  for(p = proc; p < &proc[NPROC]; p++) {
+      initlock(&p->lock, "proc");
+
+      // Allocate a page for the process's kernel stack.
+      // Map it high in memory, followed by an invalid
+      // guard page.
+      // char *pa = kalloc();
+      // // printf("[procinit]kernel stack: %p\n", (uint64)pa);
+      // if(pa == 0)
+      //   panic("kalloc");
+      // uint64 va = KSTACK((int) (p - proc));
+      // // printf("[procinit]kvmmap va %p to pa %p\n", va, (uint64)pa);
+      // kvmmap(va, (uint64)pa, PGSIZE, PTE_R | PTE_W);
+      // p->kstack = va;
+  }
+  //kvminithart();
+
+  memset(cpus, 0, sizeof(cpus));
+  #ifdef DEBUG
+  printf("procinit\n");
+  #endif
+}
+
+// Must be called with interrupts disabled,
+// to prevent race with process being moved
+// to a different CPU.
+int
+cpuid()
+{
+  int id = r_tp();
+  return id;
+}
+
+// Return this CPU's cpu struct.
+// Interrupts must be disabled.
+struct cpu*
+mycpu(void) {
+  int id = cpuid();
+  struct cpu *c = &cpus[id];
+  
+  return c;
+}
+
+// Return the current struct proc *, or zero if none.
+struct proc*
+myproc(void) {
+  push_off();
+  struct cpu *c = mycpu();
+  struct proc *p = c->proc;
+  pop_off();
+  return p;
+}
+
+int
+allocpid() {
+  int pid;
+  
+  acquire(&pid_lock);
+  pid = nextpid;
+  nextpid = nextpid + 1;
+  release(&pid_lock);
+
+  return pid;
+}
+
+// Look in the process table for an UNUSED proc.
+// If found, initialize state required to run in the kernel,
+// and return with p->lock held.
+// If there are no free procs, or a memory allocation fails, return 0.
+
+void initfreeseg( struct proc *p){
+  struct free_mem_seg *head = kalloc();
+  struct free_mem_seg *temp=head;
+  for(int i=1;i<20;++i){
+    struct free_mem_seg *next=temp+1;
+    temp->next=next;
+    next->prev=temp;
+    temp=next;
+  }
+  head->prev=temp;
+  temp->next=head;
+  p->free_seg=head;
+}
+
+void initseg(struct proc *p){
+  struct mem_seg *head = kalloc();
+  struct mem_seg *temp=head;
+  for(int i=0;i<20;++i){
+    struct mem_seg *next=temp+1;
+    temp->next=next;
+    next->prev=temp;
+    temp=next;
+  }
+  head->prev=temp;
+  temp->next=head;
+  p->seg=head;
+  
+}
+
+static struct proc*
+allocproc(void)
+{
+  struct proc *p;
+
+  for(p = proc; p < &proc[NPROC]; p++) {
+    acquire(&p->lock);
+    if(p->state == UNUSED) {
+      goto found;
+    } else {
+      release(&p->lock);
+    }
+  }
+  return NULL;
+
+found:
+  p->pid = allocpid();
+
+  // Allocate a trapframe page.
+  if((p->trapframe = (struct trapframe *)kalloc()) == NULL){
+    release(&p->lock);
+    return NULL;
+  }
+
+  // An empty user page table.
+  // And an identical kernel page table for this proc.
+  if ((p->pagetable = proc_pagetable(p)) == NULL ||
+      (p->kpagetable = proc_kpagetable()) == NULL) {
+    freeproc(p);
+    release(&p->lock);
+    return NULL;
+  }
+  p->kstack = VKSTACK;
+  // Set up new context to start executing at forkret,
+  // which returns to user space.
+  memset(&p->context, 0, sizeof(p->context));
+  p->context.ra = (uint64)forkret;
+  p->context.sp = p->kstack + PGSIZE;
+  p->load_bias=0;
+  p->ustack_base = VUSTACK;
+  p->mmap_size = 0;
+  p->sz = 0;
+  p->parent = 0;
+  p->name[0] = 0;
+  p->chan = 0;
+  p->killed = 0;
+  p->xstate = 0;
+  memset(&p->ti,0,sizeof(p->ti));
+  memset(&p->mfile, 0, sizeof(p->mfile));
+  memset(&p->my_seg,0, sizeof(p->my_seg));
+  memset(&p->ofile[0], 0, sizeof(p->ofile));
+  memset(&p->mask, 0, sizeof(p->mask));
+  memset(&p->pending, 0, sizeof(p->pending));
+  memset(&p->act[0],0,sizeof(p->act));
+  p->myep = 0;
+  memset(&p->rlim,0,sizeof(p->rlim));
+  p->stack_sz = 0;
+  p->static_sz = 0;
+  p->vswtch = p->ivswtch = 0;
+  return p;
+}
+
+// free a proc structure and the data hanging from it,
+// including user pages.
+// p->lock must be held.
+
+void recycle_seg(struct proc *p){
+  for(struct mem_seg* temp=p->seg;temp!=p->seg->prev;temp=temp->next){
+    if(temp->type!=0){
+      //printf("PGROUNDDOWN(temp->start):-------->%d      len:%d\n",PGROUNDDOWN(temp->start),PGROUNDUP(temp->len));
+      vmunmap(p->pagetable, PGROUNDDOWN(temp->start), PGROUNDUP(temp->len)/PGSIZE, 1);
+    }
+    if(temp==0){
+      panic("recycle_seg error!");
+    }
+  }
+  uint64 pa=(uint64)p->free_seg;
+  kfree((void*)PGROUNDDOWN(pa));
+  pa=(uint64)p->seg;
+  kfree((void*)PGROUNDDOWN(pa));
+}
+
+static void
+freeproc(struct proc *p)
+{
+  if(p->trapframe)
+    kfree((void*)p->trapframe);
+  p->trapframe = 0;
+  if (p->kpagetable) {
+    kvmfree(p->kpagetable, 1);
+  }
+  p->kpagetable = 0;
+  // recycle_seg(p);
+  if(p->pagetable)
+    proc_freepagetable(p->pagetable, p->sz, p->ustack_base, p->mmap_size);
+  p->pagetable = 0;
+  p->sz = 0;
+  p->pid = 0;
+  p->parent = 0;
+  p->name[0] = 0;
+  p->chan = 0;
+  p->killed = 0;
+  p->xstate = 0;
+  p->state = UNUSED;
+  // p->ustack_base = VUSTACK;
+  // p->mmap_size = 0;
+  // memset(&p->ti,0,sizeof(p->ti));
+  // memset(&p->mfile, 0, sizeof(p->mfile));
+  // memset(&p->my_seg,0, sizeof(p->my_seg));
+  // memset(&p->ofile[0], 0, sizeof(p->ofile));
+  // memset(&p->mask, 0, sizeof(p->mask));
+  // memset(&p->pending, 0, sizeof(p->pending));
+  // memset(&p->act[0],0,sizeof(p->act));
+  // p->myep = 0;
+  // memset(&p->rlim,0,sizeof(p->rlim));
+  // p->stack_sz = 0;
+  // p->static_sz = 0;
+  // p->vswtch = p->ivswtch = 0;
+}
+
+// Create a user page table for a given process,
+// with no user memory, but with trampoline pages.
+pagetable_t
+proc_pagetable(struct proc *p)
+{
+  pagetable_t pagetable;
+
+  // An empty page table.
+  pagetable = uvmcreate();
+  if(pagetable == 0)
+    return NULL;
+
+  // map the trampoline code (for system call return)
+  // at the highest user virtual address.
+  // only the supervisor uses it, on the way
+  // to/from user space, so not PTE_U.
+  if(mappages(pagetable, TRAMPOLINE, PGSIZE,
+              (uint64)trampoline, PTE_R | PTE_X) < 0){
+    uvmfree(pagetable, 0);
+    return NULL;
+  }
+
+  // map the trapframe just below TRAMPOLINE, for trampoline.S.
+  if(mappages(pagetable, TRAPFRAME, PGSIZE,
+              (uint64)(p->trapframe), PTE_R | PTE_W) < 0){
+    vmunmap(pagetable, TRAMPOLINE, 1, 0);
+    uvmfree(pagetable, 0);
+    return NULL;
+  }
+
+  return pagetable;
+}
+
+// Free a process's page table, and free the
+// physical memory it refers to.
+void
+proc_freepagetable(pagetable_t pagetable, uint64 sz,uint64 ustack_base, uint64 mmap_size)
+{
+  vmunmap(pagetable, TRAMPOLINE, 1, 0);
+  vmunmap(pagetable, TRAPFRAME, 1, 0);
+  vmunmap(pagetable, ustack_base, (VUSTACK - ustack_base)/PGSIZE, 1);
+  vmunmap(pagetable, VMMAP_BASE, mmap_size / PGSIZE, 1);
+  uvmfree(pagetable, sz);
+}
+
+// a user program that calls exec("/init")
+// od -t xC initcode
+// uchar initcode[] = {
+//   0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x02,
+//   0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x35, 0x02,
+//   0x93, 0x08, 0x70, 0x1f, 0x73, 0x00, 0x00, 0x00,
+//   0x93, 0x08, 0xd0, 0x05, 0x73, 0x00, 0x00, 0x00,
+//   0xef, 0xf0, 0x9f, 0xff, 0x2f, 0x69, 0x6e, 0x69,
+//   0x74, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
+//   0x00, 0x00, 0x00, 0x00
+// };
+
+uchar initcode[] = {
+
+0x19,0x71,0x86,0xfc, 0xa2,0xf8,0xa6,0xf4, 0xca,0xf0,0xce,0xec, 0xd2,0xe8,0xd6,0xe4,
+0xda,0xe0,0x5e,0xfc, 0x62,0xf8,0x66,0xf4, 0x6a,0xf0,0x6e,0xec, 0x00,0x01,0x13,0x01,
+0x01,0x83,0x01,0x46, 0x85,0x45,0x09,0x45, 0x97,0x10,0x00,0x00, 0xe7,0x80,0x80,0xb3,
+0x63,0x49,0x05,0x00, 0x89,0x47,0xe3,0xd6, 0xa7,0xfe,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0x60,0xaa,0x17,0x15, 0x00,0x00,0x13,0x05, 0x65,0x0b,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0x80,0xac,0x17,0x15, 0x00,0x00,0x13,0x05, 0xe5,0x0a,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0x80,0xab,0x17,0x15, 0x00,0x00,0x13,0x05, 0x65,0x0a,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0x80,0xaa,0x17,0x15, 0x00,0x00,0x13,0x05, 0xe5,0x09,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0x80,0xa9,0x17,0x15, 0x00,0x00,0x13,0x05, 0xe5,0x09,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0x80,0xa8,0x93,0x05, 0x00,0x04,0x17,0x15, 0x00,0x00,0x13,0x05, 0xa5,0x09,0x97,0x10,
+0x00,0x00,0xe7,0x80, 0x00,0xa6,0x97,0x10, 0x00,0x00,0xe7,0x80, 0xa0,0xa3,0x93,0x05,
+0x00,0x04,0x17,0x15, 0x00,0x00,0x13,0x05, 0xe5,0x08,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0x40,0xa4,0x97,0x10, 0x00,0x00,0xe7,0x80, 0xe0,0xa1,0x93,0x05, 0x00,0x04,0x17,0x15,
+0x00,0x00,0x13,0x05, 0x25,0x08,0x97,0x10, 0x00,0x00,0xe7,0x80, 0x80,0xa2,0x97,0x10,
+0x00,0x00,0xe7,0x80, 0x20,0xa0,0x17,0x15, 0x00,0x00,0x13,0x05, 0xa5,0x07,0x97,0x10,
+0x00,0x00,0xe7,0x80, 0x40,0xa2,0x93,0x05, 0x00,0x04,0x17,0x15, 0x00,0x00,0x13,0x05,
+0xe5,0x06,0x97,0x10, 0x00,0x00,0xe7,0x80, 0xc0,0x9f,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0x60,0x9d,0x93,0x05, 0x00,0x04,0x17,0x15, 0x00,0x00,0x13,0x05, 0xa5,0x05,0x97,0x10,
+0x00,0x00,0xe7,0x80, 0x00,0x9e,0x97,0x10, 0x00,0x00,0xe7,0x80, 0xa0,0x9b,0x93,0x05,
+0x00,0x04,0x17,0x15, 0x00,0x00,0x13,0x05, 0xe5,0x04,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0x40,0x9c,0x97,0x10, 0x00,0x00,0xe7,0x80, 0xe0,0x99,0x93,0x07, 0x90,0x02,0x23,0x24,
+0xf4,0xf8,0x97,0x17, 0x00,0x00,0x93,0x87, 0x67,0x17,0x8c,0x63, 0x90,0x67,0x94,0x6b,
+0x98,0x6f,0x9c,0x73, 0x23,0x30,0xb4,0xf6, 0x23,0x34,0xc4,0xf6, 0x23,0x38,0xd4,0xf6,
+0x23,0x3c,0xe4,0xf6, 0x23,0x30,0xf4,0xf8, 0x81,0x45,0x17,0x15, 0x00,0x00,0x13,0x05,
+0x65,0x01,0x97,0x10, 0x00,0x00,0xe7,0x80, 0xc0,0x97,0x7d,0x77, 0x93,0x07,0x87,0x7f,
+0xa2,0x97,0x88,0xe3, 0x97,0x17,0x00,0x00, 0x83,0xb7,0xc7,0x00, 0x23,0x3c,0xf4,0xf4,
+0x93,0x07,0x84,0xf5, 0x23,0x3c,0xf4,0xea, 0x01,0x49,0x93,0x07, 0x87,0x7c,0xa2,0x97,
+0x23,0xb0,0x07,0x00, 0x23,0x30,0x04,0x80, 0x93,0x07,0x07,0x7d, 0xa2,0x97,0x23,0xb0,
+0x07,0x00,0x01,0x4a, 0x81,0x4a,0x93,0x07, 0x07,0x7f,0xa2,0x97, 0x23,0xb0,0x07,0x00,
+0x05,0x4d,0x85,0x4d, 0x85,0x47,0x93,0x06, 0x87,0x7e,0xa2,0x96, 0x9c,0xe2,0x93,0x07,
+0x84,0xf8,0x93,0x06, 0x07,0x7e,0xa2,0x96, 0x9c,0xe2,0x93,0x09, 0x04,0x86,0x13,0x0b,
+0xc4,0xf8,0x93,0x0b, 0x84,0xeb,0x93,0x07, 0x84,0x8c,0x13,0x07, 0x87,0x7b,0x22,0x97,
+0x1c,0xe3,0x99,0xa3, 0x63,0x52,0xa0,0x54, 0x93,0x04,0x14,0x8d, 0x1b,0x0c,0xf5,0xff,
+0x02,0x1c,0x13,0x5c, 0x0c,0x02,0x93,0x0c, 0x24,0x8d,0xe2,0x9c, 0x13,0x0c,0x00,0x02,
+0x93,0x07,0x04,0xad, 0xfd,0x76,0x13,0x87, 0x86,0x7d,0x22,0x97, 0x1c,0xe3,0x93,0x07,
+0x04,0xec,0x13,0x87, 0x06,0x7c,0x22,0x97, 0x1c,0xe3,0xc5,0xa6, 0x63,0x8c,0x0a,0x3c,
+0x93,0x07,0x20,0x03, 0xb3,0x07,0xfa,0x02, 0x13,0x87,0x07,0xf9, 0x22,0x97,0x56,0x97,
+0x23,0x00,0x07,0xb4, 0x05,0x2a,0x13,0x17, 0x3a,0x00,0x13,0x07, 0x07,0xf9,0x22,0x97,
+0xfd,0x76,0x93,0x86, 0x86,0x7d,0xa2,0x96, 0x94,0x62,0xb6,0x97, 0x23,0x34,0xf7,0xf2,
+0x93,0x07,0x09,0xf9, 0xa2,0x97,0x23,0x88, 0x87,0x8d,0x05,0x29, 0x81,0x4a,0x59,0xae,
+0x63,0x85,0x0a,0x0a, 0x93,0x07,0x20,0x03, 0xb3,0x07,0xfa,0x02, 0x13,0x87,0x07,0xf9,
+0x22,0x97,0x56,0x97, 0x23,0x00,0x07,0xb4, 0x1b,0x07,0x1a,0x00, 0x0e,0x07,0x13,0x07,
+0x07,0xf9,0x22,0x97, 0xfd,0x76,0x93,0x86, 0x86,0x7d,0xa2,0x96, 0x94,0x62,0xb6,0x97,
+0x23,0x34,0xf7,0xf2, 0x9b,0x07,0x2a,0x00, 0x8e,0x07,0x93,0x87, 0x07,0xf9,0xa2,0x97,
+0x23,0xb4,0x07,0xf2, 0xfd,0x76,0x93,0x87, 0x86,0x7e,0xa2,0x97, 0x98,0x63,0x93,0x87,
+0x06,0x7f,0xa2,0x97, 0x9c,0x63,0x63,0xdb, 0xe7,0x00,0x8a,0x07, 0x13,0x87,0x06,0x7e,
+0x22,0x97,0x18,0x63, 0xba,0x97,0x9c,0x43, 0x63,0x8b,0xa7,0x05, 0x97,0x00,0x00,0x00,
+0xe7,0x80,0x80,0x7b, 0x63,0x1a,0x05,0x16, 0x83,0x37,0x04,0x80, 0xc5,0xe3,0xfd,0x77,
+0x93,0x87,0x07,0x7d, 0xa2,0x97,0x9c,0x63, 0x63,0x92,0x07,0x10, 0x85,0x47,0x63,0x83,
+0xfd,0x14,0xfd,0x77, 0x93,0x87,0x07,0x7c, 0xa2,0x97,0x8c,0x63, 0x03,0x35,0x04,0xec,
+0x97,0x00,0x00,0x00, 0xe7,0x80,0x40,0x7d, 0x69,0xa2,0x9b,0x07, 0x1a,0x00,0x8e,0x07,
+0x93,0x87,0x07,0xf9, 0xa2,0x97,0x23,0xb4, 0x07,0xf2,0x7d,0x3a, 0x61,0xb7,0x7d,0x77,
+0x93,0x07,0x07,0x7f, 0xa2,0x97,0x9c,0x63, 0x85,0x27,0x93,0x06, 0x07,0x7f,0xa2,0x96,
+0x9c,0xe2,0x93,0x07, 0x07,0x7d,0xa2,0x97, 0x9c,0x63,0x85,0xe7, 0x83,0x37,0x04,0x80,
+0xfd,0x76,0x13,0x87, 0x06,0x7d,0x22,0x97, 0x1c,0xe3,0x63,0x84, 0x07,0x14,0x93,0x87,
+0x86,0x7c,0xa2,0x97, 0x23,0xb0,0x07,0x00, 0x23,0x30,0x04,0x80, 0x23,0x30,0x07,0x00,
+0x0d,0xaa,0x03,0x25, 0x84,0x8c,0x97,0x00, 0x00,0x00,0xe7,0x80, 0xa0,0x75,0x03,0x25,
+0xc4,0x8c,0x97,0x00, 0x00,0x00,0xe7,0x80, 0xe0,0x74,0xc9,0xb7, 0x1b,0x89,0x17,0x00,
+0x93,0x17,0x39,0x00, 0x93,0x87,0x07,0xf9, 0xa2,0x97,0x23,0xb4, 0x07,0xf2,0x05,0x45,
+0x97,0x00,0x00,0x00, 0xe7,0x80,0x00,0x73, 0x85,0x47,0x7d,0x77, 0x13,0x07,0x87,0x7c,
+0x22,0x97,0x18,0x63, 0x63,0x03,0xf7,0x02, 0x93,0x07,0x20,0x03, 0x33,0x05,0xf9,0x02,
+0x93,0x05,0x20,0x44, 0xfd,0x77,0x93,0x87, 0x87,0x7d,0xa2,0x97, 0x9c,0x63,0x3e,0x95,
+0x97,0x00,0x00,0x00, 0xe7,0x80,0xe0,0x71, 0x15,0xb7,0x13,0x05, 0x20,0x03,0x33,0x05,
+0xa9,0x02,0x93,0x05, 0x20,0x24,0xfd,0x77, 0x93,0x87,0x87,0x7d, 0xa2,0x97,0x9c,0x63,
+0x3e,0x95,0x97,0x00, 0x00,0x00,0xe7,0x80, 0xc0,0x6f,0x09,0xb7, 0x05,0x45,0x97,0x00,
+0x00,0x00,0xe7,0x80, 0x20,0x6d,0x03,0x25, 0xc4,0x8c,0x97,0x00, 0x00,0x00,0xe7,0x80,
+0xc0,0x70,0x03,0x25, 0x84,0x8c,0x97,0x00, 0x00,0x00,0xe7,0x80, 0xa0,0x6b,0x03,0x25,
+0xc4,0x8c,0x97,0x00, 0x00,0x00,0xe7,0x80, 0xe0,0x6a,0xfd,0x77, 0x93,0x87,0x07,0x7d,
+0xa2,0x97,0x9c,0x63, 0x85,0x27,0x8e,0x07, 0x93,0x87,0x07,0xf9, 0xa2,0x97,0x23,0xb4,
+0x07,0xf2,0x6d,0xbd, 0xde,0x85,0x17,0x15, 0x00,0x00,0x13,0x05, 0xa5,0xd4,0x97,0x00,
+0x00,0x00,0xe7,0x80, 0x60,0x69,0xb1,0xa0, 0xfd,0x77,0x93,0x87, 0x07,0x7d,0xa2,0x97,
+0x9c,0x63,0xa9,0xe7, 0x5a,0x85,0x97,0x00, 0x00,0x00,0xe7,0x80, 0x20,0x64,0x83,0x37,
+0x04,0x80,0x89,0xcf, 0x7d,0x77,0x93,0x07, 0x87,0x7d,0xa2,0x97, 0x9c,0x63,0x23,0x30,
+0xf4,0xec,0x93,0x07, 0x87,0x7c,0xa2,0x97, 0x23,0xb0,0x07,0x00, 0x93,0x07,0x09,0xf9,
+0x33,0x89,0x87,0x00, 0x23,0x08,0x09,0x8c, 0x85,0x47,0x23,0x30, 0x04,0x80,0x63,0x87,
+0xfd,0x0e,0x05,0x2d, 0x01,0x49,0x01,0x4a, 0x81,0x4a,0xa9,0xaa, 0x97,0x00,0x00,0x00,
+0xe7,0x80,0x80,0x5e, 0xaa,0x8a,0x0d,0xc9, 0x03,0x25,0x84,0x8c, 0x97,0x00,0x00,0x00,
+0xe7,0x80,0x40,0x61, 0x03,0x25,0xc4,0x8c, 0x97,0x00,0x00,0x00, 0xe7,0x80,0x80,0x60,
+0x01,0x45,0x97,0x00, 0x00,0x00,0xe7,0x80, 0x60,0x5d,0xfd,0x77, 0x93,0x87,0x07,0x7d,
+0xa2,0x97,0x23,0xb0, 0x07,0x00,0xbd,0xbf, 0x01,0x45,0x97,0x00, 0x00,0x00,0xe7,0x80,
+0x60,0x5e,0x03,0x25, 0x84,0x8c,0x97,0x00, 0x00,0x00,0xe7,0x80, 0x00,0x62,0x03,0x25,
+0x84,0x8c,0x97,0x00, 0x00,0x00,0xe7,0x80, 0xe0,0x5c,0x03,0x25, 0xc4,0x8c,0x97,0x00,
+0x00,0x00,0xe7,0x80, 0x20,0x5c,0x7d,0x75, 0x93,0x07,0x05,0x7d, 0xa2,0x97,0x94,0x63,
+0x9b,0x87,0x16,0x00, 0x63,0x45,0xfa,0x04, 0x13,0x07,0x20,0x03, 0xb3,0x87,0xe7,0x02,
+0x13,0x07,0x85,0x7d, 0x22,0x97,0x18,0x63, 0x3e,0x97,0x93,0x07, 0x84,0xeb,0x9b,0x0a,
+0x0a,0x00,0x1b,0x86, 0x06,0x00,0xbb,0x06, 0xda,0x40,0xfd,0x36, 0x93,0x95,0x06,0x02,
+0x93,0xd6,0xd5,0x01, 0x93,0x05,0x05,0x7c, 0xa2,0x95,0x8c,0x61, 0xae,0x96,0x98,0xe3,
+0x13,0x07,0x27,0x03, 0xa1,0x07,0xe3,0x9c, 0xd7,0xfe,0xbb,0x8a, 0xca,0x40,0x93,0x97,
+0x3a,0x00,0x93,0x87, 0x07,0xf9,0xa2,0x97, 0x23,0xb4,0x07,0xf2, 0xde,0x85,0x03,0x35,
+0x84,0xeb,0x97,0x00, 0x00,0x00,0xe7,0x80, 0x20,0x56,0xe9,0xbd, 0x17,0x15,0x00,0x00,
+0x13,0x05,0xc5,0xc0, 0x97,0x10,0x00,0x00, 0xe7,0x80,0x00,0x9b, 0xce,0x85,0x17,0x15,
+0x00,0x00,0x13,0x05, 0x25,0xc1,0x97,0x10, 0x00,0x00,0xe7,0x80, 0xe0,0x99,0x83,0x27,
+0xc4,0xf8,0x85,0xcb, 0x03,0x47,0x04,0xad, 0x93,0x07,0x60,0x06, 0x63,0x18,0xf7,0x00,
+0x03,0x47,0x14,0xad, 0x93,0x07,0x10,0x06, 0x63,0x0d,0xf7,0x00, 0x17,0x15,0x00,0x00,
+0x13,0x05,0xc5,0xbf, 0x97,0x10,0x00,0x00, 0xe7,0x80,0x00,0x97, 0x23,0x30,0x04,0x80,
+0xc9,0xb5,0x17,0x15, 0x00,0x00,0x13,0x05, 0x65,0xbd,0x97,0x10, 0x00,0x00,0xe7,0x80,
+0xa0,0x95,0x23,0x30, 0x04,0x80,0x75,0xb5, 0x13,0x07,0xc0,0x07, 0x03,0x39,0x84,0x80,
+0x63,0x8e,0xe7,0x06, 0x85,0x04,0x63,0x89, 0x94,0x13,0xa6,0x86, 0x83,0xc7,0xf4,0xff,
+0xe3,0x8e,0x87,0xc1, 0x29,0x47,0xe3,0x8d, 0xe7,0xc4,0x1b,0x07, 0x19,0x00,0x23,0x34,
+0xe4,0x80,0x13,0x07, 0x09,0xf9,0x33,0x09, 0x87,0x00,0x23,0x08, 0xf9,0x8c,0x13,0x07,
+0x20,0x02,0x63,0x8d, 0xe7,0x00,0x13,0x07, 0x20,0x03,0x33,0x07, 0xea,0x02,0x13,0x07,
+0x07,0xf9,0x22,0x97, 0x56,0x97,0x23,0x00, 0xf7,0xb4,0x85,0x2a, 0x03,0x37,0x04,0x80,
+0x45,0xf7,0x13,0x07, 0xe0,0x03,0xe3,0x91, 0xe7,0xfa,0x83,0xc7, 0x06,0x00,0x63,0x86,
+0x87,0x17,0x63,0x9a, 0xe7,0x00,0x23,0x30, 0x44,0x81,0x89,0x47, 0x7d,0x77,0x13,0x07,
+0x87,0x7c,0x22,0x97, 0x1c,0xe3,0x03,0x39, 0x84,0x80,0x69,0xb7, 0xfd,0x77,0x93,0x87,
+0x87,0x7b,0xa2,0x97, 0x88,0x63,0x97,0x00, 0x00,0x00,0xe7,0x80, 0xc0,0x42,0x03,0x39,
+0x84,0x80,0xfd,0x77, 0x93,0x87,0x07,0x7d, 0xa2,0x97,0x23,0xb0, 0x47,0x01,0x9d,0xb7,
+0x01,0x45,0x97,0x00, 0x00,0x00,0xe7,0x80, 0xc0,0x3f,0x5a,0x85, 0x97,0x00,0x00,0x00,
+0xe7,0x80,0xc0,0x3f, 0x83,0x27,0xc4,0xf8, 0x8d,0xeb,0x8c,0x60, 0x6e,0x85,0x97,0x10,
+0x00,0x00,0xe7,0x80, 0x60,0x88,0xa1,0x04, 0x63,0x88,0x34,0x03, 0x97,0x00,0x00,0x00,
+0xe7,0x80,0x80,0x3c, 0x79,0xf9,0x9c,0x60, 0x23,0x30,0xf4,0xec, 0xde,0x85,0x66,0x85,
+0x97,0x00,0x00,0x00, 0xe7,0x80,0x40,0x40, 0xf9,0xbf,0x8c,0x60, 0x6a,0x85,0x97,0x10,
+0x00,0x00,0xe7,0x80, 0x60,0x85,0xc1,0xbf, 0x81,0x45,0x17,0x15, 0x00,0x00,0x13,0x05,
+0x65,0xb1,0x97,0x00, 0x00,0x00,0xe7,0x80, 0xc0,0x3e,0x7d,0x77, 0x93,0x07,0x87,0x7f,
+0xa2,0x97,0x88,0xe3, 0x93,0x07,0x07,0x7f, 0xa2,0x97,0x23,0xb0, 0x87,0x01,0x05,0x4d,
+0x89,0x4d,0xa9,0x47, 0x93,0x06,0x87,0x7e, 0xa2,0x96,0x9c,0xe2, 0x93,0x07,0x04,0xf6,
+0x13,0x07,0x07,0x7e, 0x22,0x97,0x1c,0xe3, 0x13,0x06,0x00,0x20, 0x93,0x05,0x04,0x8d,
+0xfd,0x77,0x93,0x87, 0x87,0x7f,0xa2,0x97, 0x88,0x63,0x97,0x00, 0x00,0x00,0xe7,0x80,
+0x20,0x37,0x2a,0x8c, 0xe3,0x10,0x05,0xaa, 0x89,0x47,0xe3,0x83, 0xfd,0xf4,0x97,0x17,
+0x00,0x00,0x93,0x87, 0xa7,0xbf,0x03,0xb3, 0x07,0x00,0x83,0xb8, 0x87,0x00,0x03,0xb8,
+0x07,0x01,0x88,0x6f, 0x8c,0x73,0x90,0x77, 0x94,0x7b,0x98,0x7f, 0xbc,0x63,0x23,0x3c,
+0x64,0x80,0x23,0x30, 0x14,0x83,0x23,0x34, 0x04,0x83,0x23,0x38, 0xa4,0x82,0x23,0x3c,
+0xb4,0x82,0x23,0x30, 0xc4,0x84,0x23,0x34, 0xd4,0x84,0x23,0x38, 0xe4,0x84,0x23,0x3c,
+0xf4,0x84,0x97,0x17, 0x00,0x00,0x93,0x87, 0xe7,0xa2,0x23,0x3c, 0xf4,0xea,0x23,0x34,
+0x04,0xec,0x93,0x04, 0x84,0x81,0x17,0x1d, 0x00,0x00,0x13,0x0d, 0x2d,0xa4,0x97,0x1d,
+0x00,0x00,0x93,0x8d, 0xad,0xa1,0xbe,0x8c, 0x11,0xb7,0x23,0x30, 0x44,0x81,0x85,0x47,
+0x7d,0x77,0x13,0x07, 0x87,0x7c,0x22,0x97, 0x1c,0xe3,0xe3,0x0e, 0x0a,0xe8,0x03,0x39,
+0x84,0x80,0x0d,0xb5, 0x41,0x11,0x22,0xe4, 0x00,0x08,0xaa,0x87, 0x85,0x05,0x85,0x07,
+0x03,0xc7,0xf5,0xff, 0xa3,0x8f,0xe7,0xfe, 0x75,0xfb,0x22,0x64, 0x41,0x01,0x82,0x80,
+0x41,0x11,0x22,0xe4, 0x00,0x08,0x83,0x47, 0x05,0x00,0x85,0xc3, 0xaa,0x87,0x85,0x07,
+0x03,0xc7,0x07,0x00, 0x6d,0xff,0x85,0x05, 0x85,0x07,0x03,0xc7, 0xf5,0xff,0xa3,0x8f,
+0xe7,0xfe,0x75,0xfb, 0x22,0x64,0x41,0x01, 0x82,0x80,0xaa,0x87, 0xed,0xb7,0x41,0x11,
+0x22,0xe4,0x00,0x08, 0x83,0x47,0x05,0x00, 0x91,0xcb,0x03,0xc7, 0x05,0x00,0x63,0x17,
+0xf7,0x00,0x05,0x05, 0x85,0x05,0x83,0x47, 0x05,0x00,0xe5,0xfb, 0x03,0xc5,0x05,0x00,
+0x3b,0x85,0xa7,0x40, 0x22,0x64,0x41,0x01, 0x82,0x80,0x41,0x11, 0x22,0xe4,0x00,0x08,
+0x83,0x47,0x05,0x00, 0x91,0xcf,0x05,0x05, 0xaa,0x87,0x85,0x46, 0x89,0x9e,0x3b,0x85,
+0xf6,0x00,0x85,0x07, 0x03,0xc7,0xf7,0xff, 0x7d,0xfb,0x22,0x64, 0x41,0x01,0x82,0x80,
+0x01,0x45,0xe5,0xbf, 0x41,0x11,0x22,0xe4, 0x00,0x08,0x19,0xca, 0xaa,0x87,0x02,0x16,
+0x01,0x92,0x33,0x07, 0xa6,0x00,0x23,0x80, 0xb7,0x00,0x85,0x07, 0xe3,0x9d,0xe7,0xfe,
+0x22,0x64,0x41,0x01, 0x82,0x80,0x41,0x11, 0x22,0xe4,0x00,0x08, 0x83,0x47,0x05,0x00,
+0x99,0xcb,0x63,0x87, 0xf5,0x00,0x05,0x05, 0x83,0x47,0x05,0x00, 0xfd,0xfb,0x01,0x45,
+0x22,0x64,0x41,0x01, 0x82,0x80,0x01,0x45, 0xe5,0xbf,0x1d,0x71, 0x86,0xec,0xa2,0xe8,
+0xa6,0xe4,0xca,0xe0, 0x4e,0xfc,0x52,0xf8, 0x56,0xf4,0x5a,0xf0, 0x5e,0xec,0x62,0xe8,
+0x80,0x10,0xaa,0x8b, 0x2e,0x8a,0x2a,0x89, 0x81,0x44,0x93,0x0a, 0xf4,0xfa,0x29,0x4b,
+0x35,0x4c,0xa6,0x89, 0x85,0x24,0x63,0xd7, 0x44,0x03,0x05,0x46, 0xd6,0x85,0x01,0x45,
+0x97,0x00,0x00,0x00, 0xe7,0x80,0xc0,0x1b, 0x63,0x5e,0xa0,0x00, 0x83,0x47,0xf4,0xfa,
+0x23,0x00,0xf9,0x00, 0x63,0x87,0x67,0x01, 0x05,0x09,0xe3,0x9c, 0x87,0xfd,0xa6,0x89,
+0x11,0xa0,0xa6,0x89, 0xde,0x99,0x23,0x80, 0x09,0x00,0x5e,0x85, 0xe6,0x60,0x46,0x64,
+0xa6,0x64,0x06,0x69, 0xe2,0x79,0x42,0x7a, 0xa2,0x7a,0x02,0x7b, 0xe2,0x6b,0x42,0x6c,
+0x25,0x61,0x82,0x80, 0x01,0x11,0x06,0xec, 0x22,0xe8,0x26,0xe4, 0x4a,0xe0,0x00,0x10,
+0x2e,0x89,0x81,0x45, 0x97,0x00,0x00,0x00, 0xe7,0x80,0xa0,0x19, 0x63,0x45,0x05,0x02,
+0xaa,0x84,0xca,0x85, 0x97,0x00,0x00,0x00, 0xe7,0x80,0x40,0x19, 0x2a,0x89,0x26,0x85,
+0x97,0x00,0x00,0x00, 0xe7,0x80,0x00,0x16, 0x4a,0x85,0xe2,0x60, 0x42,0x64,0xa2,0x64,
+0x02,0x69,0x05,0x61, 0x82,0x80,0x7d,0x59, 0xc5,0xbf,0x41,0x11, 0x22,0xe4,0x00,0x08,
+0x03,0x47,0x05,0x00, 0x93,0x07,0xd0,0x02, 0x85,0x45,0x63,0x03, 0xf7,0x04,0x03,0x47,
+0x05,0x00,0x9b,0x07, 0x07,0xfd,0x93,0xf7, 0xf7,0x0f,0xa5,0x46, 0x63,0xed,0xf6,0x02,
+0x81,0x46,0x25,0x46, 0x05,0x05,0x9b,0x97, 0x26,0x00,0xb5,0x9f, 0x9b,0x97,0x17,0x00,
+0xb9,0x9f,0x9b,0x86, 0x07,0xfd,0x03,0x47, 0x05,0x00,0x9b,0x07, 0x07,0xfd,0x93,0xf7,
+0xf7,0x0f,0xe3,0x71, 0xf6,0xfe,0x3b,0x85, 0xd5,0x02,0x22,0x64, 0x41,0x01,0x82,0x80,
+0x05,0x05,0xfd,0x55, 0x6d,0xbf,0x81,0x46, 0xfd,0xb7,0x41,0x11, 0x22,0xe4,0x00,0x08,
+0x63,0x74,0xb5,0x02, 0x63,0x5f,0xc0,0x00, 0x02,0x16,0x01,0x92, 0xb3,0x07,0xc5,0x00,
+0x2a,0x87,0x85,0x05, 0x05,0x07,0x83,0xc6, 0xf5,0xff,0xa3,0x0f, 0xd7,0xfe,0xe3,0x9a,
+0xe7,0xfe,0x22,0x64, 0x41,0x01,0x82,0x80, 0x33,0x07,0xc5,0x00, 0xb2,0x95,0xe3,0x5a,
+0xc0,0xfe,0x9b,0x07, 0xf6,0xff,0x82,0x17, 0x81,0x93,0x93,0xc7, 0xf7,0xff,0xba,0x97,
+0xfd,0x15,0x7d,0x17, 0x83,0xc6,0x05,0x00, 0x23,0x00,0xd7,0x00, 0xe3,0x9a,0xe7,0xfe,
+0xc9,0xbf,0x41,0x11, 0x22,0xe4,0x00,0x08, 0x05,0xca,0x9b,0x06, 0xf6,0xff,0x82,0x16,
+0x81,0x92,0x85,0x06, 0xaa,0x96,0x83,0x47, 0x05,0x00,0x03,0xc7, 0x05,0x00,0x63,0x98,
+0xe7,0x00,0x05,0x05, 0x85,0x05,0xe3,0x18, 0xd5,0xfe,0x01,0x45, 0x19,0xa0,0x3b,0x85,
+0xe7,0x40,0x22,0x64, 0x41,0x01,0x82,0x80, 0x01,0x45,0xe5,0xbf, 0x41,0x11,0x06,0xe4,
+0x22,0xe0,0x00,0x08, 0x97,0x00,0x00,0x00, 0xe7,0x80,0x60,0xf6, 0xa2,0x60,0x02,0x64,
+0x41,0x01,0x82,0x80, 0x93,0x08,0x40,0x1f, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08,
+0xd0,0x05,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0x50,0x1f, 0x73,0x00,0x00,0x00,
+0x82,0x80,0x93,0x08, 0x60,0x1f,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0xf0,0x03,
+0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08, 0x00,0x04,0x73,0x00, 0x00,0x00,0x82,0x80,
+0x93,0x08,0x90,0x03, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08, 0x10,0x08,0x73,0x00,
+0x00,0x00,0x82,0x80, 0x93,0x08,0x70,0x1f, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08,
+0xa0,0x1f,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0x00,0x05, 0x73,0x00,0x00,0x00,
+0x82,0x80,0x93,0x08, 0xd0,0x1f,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0x10,0x03,
+0x73,0x00,0x00,0x00, 0x82,0x80,0xdd,0x48, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08,
+0xc0,0x0a,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0x20,0x20, 0x73,0x00,0x00,0x00,
+0x82,0x80,0x93,0x08, 0x80,0x1f,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0x90,0x1f,
+0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08, 0xe0,0x1f,0x73,0x00, 0x00,0x00,0x82,0x80,
+0x93,0x08,0xf0,0x1f, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08, 0x00,0x20,0x73,0x00,
+0x00,0x00,0x82,0x80, 0xc5,0x48,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0xb0,0x1f,
+0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08, 0xc0,0x1f,0x73,0x00, 0x00,0x00,0x82,0x80,
+0x93,0x08,0x30,0x0b, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08, 0x10,0x20,0x73,0x00,
+0x00,0x00,0x82,0x80, 0x93,0x08,0x80,0x03, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08,
+0xb0,0x03,0x73,0x00, 0x00,0x00,0x82,0x80, 0xe1,0x48,0x73,0x00, 0x00,0x00,0x82,0x80,
+0x93,0x08,0xc0,0x0d, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08, 0xd0,0x03,0x73,0x00,
+0x00,0x00,0x82,0x80, 0x93,0x08,0x20,0x02, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08,
+0x40,0x10,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0xf0,0x04, 0x73,0x00,0x00,0x00,
+0x82,0x80,0x93,0x08, 0x80,0x02,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0x70,0x02,
+0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08, 0x50,0x02,0x73,0x00, 0x00,0x00,0x82,0x80,
+0x93,0x08,0x30,0x02, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08, 0x50,0x06,0x73,0x00,
+0x00,0x00,0x82,0x80, 0x93,0x08,0x70,0x08, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08,
+0x60,0x08,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0x90,0x08, 0x73,0x00,0x00,0x00,
+0x82,0x80,0x93,0x08, 0x50,0x10,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0xe0,0x03,
+0x73,0x00,0x00,0x00, 0x82,0x80,0xf5,0x48, 0x73,0x00,0x00,0x00, 0x82,0x80,0x93,0x08,
+0xb0,0x02,0x73,0x00, 0x00,0x00,0x82,0x80, 0x93,0x08,0x20,0x0e, 0x73,0x00,0x00,0x00,
+0x82,0x80,0x93,0x08, 0x80,0x05,0x73,0x00, 0x00,0x00,0x82,0x80, 0x01,0x11,0x06,0xec,
+0x22,0xe8,0x00,0x10, 0xa3,0x07,0xb4,0xfe, 0x05,0x46,0x93,0x05, 0xf4,0xfe,0x97,0x00,
+0x00,0x00,0xe7,0x80, 0x80,0xe4,0xe2,0x60, 0x42,0x64,0x05,0x61, 0x82,0x80,0x39,0x71,
+0x06,0xfc,0x22,0xf8, 0x26,0xf4,0x4a,0xf0, 0x4e,0xec,0x80,0x00, 0xaa,0x84,0x99,0xc2,
+0x63,0xc8,0x05,0x08, 0x81,0x25,0x81,0x48, 0x93,0x09,0x04,0xfc, 0xce,0x86,0x01,0x47,
+0x01,0x26,0x17,0x05, 0x00,0x00,0x13,0x05, 0xe5,0x68,0x3a,0x88, 0x05,0x27,0xbb,0xf7,
+0xc5,0x02,0x82,0x17, 0x81,0x93,0xaa,0x97, 0x83,0xc7,0x07,0x00, 0x23,0x80,0xf6,0x00,
+0x9b,0x87,0x05,0x00, 0xbb,0xd5,0xc5,0x02, 0x85,0x06,0xe3,0xf0, 0xc7,0xfe,0x63,0x8c,
+0x08,0x00,0x93,0x07, 0x07,0xfd,0x33,0x87, 0x87,0x00,0x93,0x07, 0xd0,0x02,0x23,0x08,
+0xf7,0xfe,0x1b,0x07, 0x28,0x00,0x63,0x56, 0xe0,0x02,0x13,0x09, 0x04,0xfc,0x3a,0x99,
+0xfd,0x19,0xba,0x99, 0x7d,0x37,0x02,0x17, 0x01,0x93,0xb3,0x89, 0xe9,0x40,0x83,0x45,
+0xf9,0xff,0x26,0x85, 0x97,0x00,0x00,0x00, 0xe7,0x80,0x80,0xf5, 0x7d,0x19,0xe3,0x18,
+0x39,0xff,0xe2,0x70, 0x42,0x74,0xa2,0x74, 0x02,0x79,0xe2,0x69, 0x21,0x61,0x82,0x80,
+0xbb,0x05,0xb0,0x40, 0x85,0x48,0x8d,0xbf, 0x19,0x71,0x86,0xfc, 0xa2,0xf8,0xa6,0xf4,
+0xca,0xf0,0xce,0xec, 0xd2,0xe8,0xd6,0xe4, 0xda,0xe0,0x5e,0xfc, 0x62,0xf8,0x66,0xf4,
+0x6a,0xf0,0x6e,0xec, 0x00,0x01,0x03,0xc9, 0x05,0x00,0x63,0x0f, 0x09,0x18,0xaa,0x8a,
+0x32,0x8b,0x93,0x84, 0x15,0x00,0x81,0x49, 0x13,0x0a,0x50,0x02, 0x55,0x4c,0x97,0x0c,
+0x00,0x00,0x93,0x8c, 0xac,0x57,0x93,0x0d, 0x80,0x02,0x41,0x4d, 0x97,0x0b,0x00,0x00,
+0x93,0x8b,0x4b,0x5c, 0x39,0xa8,0xca,0x85, 0x56,0x85,0x97,0x00, 0x00,0x00,0xe7,0x80,
+0x20,0xee,0x19,0xa0, 0x63,0x8d,0x49,0x01, 0x85,0x04,0x03,0xc9, 0xf4,0xff,0x63,0x0d,
+0x09,0x14,0xe3,0x99, 0x09,0xfe,0xe3,0x10, 0x49,0xff,0xd2,0x89, 0xf5,0xb7,0x63,0x0c,
+0x49,0x11,0x9b,0x07, 0xd9,0xf9,0x93,0xf7, 0xf7,0x0f,0x63,0x6e, 0xfc,0x10,0x9b,0x07,
+0xd9,0xf9,0x13,0xf7, 0xf7,0x0f,0x63,0x68, 0xec,0x10,0x93,0x17, 0x27,0x00,0xe6,0x97,
+0x9c,0x43,0xe6,0x97, 0x82,0x87,0x13,0x09, 0x8b,0x00,0x85,0x46, 0x29,0x46,0x83,0x25,
+0x0b,0x00,0x56,0x85, 0x97,0x00,0x00,0x00, 0xe7,0x80,0xa0,0xea, 0x4a,0x8b,0x81,0x49,
+0x65,0xb7,0x13,0x09, 0x8b,0x00,0x81,0x46, 0x29,0x46,0x83,0x25, 0x0b,0x00,0x56,0x85,
+0x97,0x00,0x00,0x00, 0xe7,0x80,0xe0,0xe8, 0x4a,0x8b,0x81,0x49, 0x71,0xb7,0x13,0x09,
+0x8b,0x00,0x81,0x46, 0x6a,0x86,0x83,0x25, 0x0b,0x00,0x56,0x85, 0x97,0x00,0x00,0x00,
+0xe7,0x80,0x20,0xe7, 0x4a,0x8b,0x81,0x49, 0x85,0xbf,0x93,0x07, 0x8b,0x00,0x23,0x34,
+0xf4,0xf8,0x83,0x39, 0x0b,0x00,0x93,0x05, 0x00,0x03,0x56,0x85, 0x97,0x00,0x00,0x00,
+0xe7,0x80,0x00,0xe3, 0x93,0x05,0x80,0x07, 0x56,0x85,0x97,0x00, 0x00,0x00,0xe7,0x80,
+0x20,0xe2,0x6a,0x89, 0x93,0xd7,0xc9,0x03, 0xde,0x97,0x83,0xc5, 0x07,0x00,0x56,0x85,
+0x97,0x00,0x00,0x00, 0xe7,0x80,0xc0,0xe0, 0x92,0x09,0x7d,0x39, 0xe3,0x14,0x09,0xfe,
+0x03,0x3b,0x84,0xf8, 0x81,0x49,0x0d,0xb7, 0x13,0x09,0x8b,0x00, 0x83,0x39,0x0b,0x00,
+0x63,0x81,0x09,0x02, 0x83,0xc5,0x09,0x00, 0xad,0xc5,0x56,0x85, 0x97,0x00,0x00,0x00,
+0xe7,0x80,0x00,0xde, 0x85,0x09,0x83,0xc5, 0x09,0x00,0xe5,0xf9, 0x4a,0x8b,0x81,0x49,
+0xe5,0xbd,0x97,0x09, 0x00,0x00,0x93,0x89, 0xe9,0x43,0xee,0x85, 0xf9,0xbf,0x13,0x09,
+0x8b,0x00,0x83,0x45, 0x0b,0x00,0x56,0x85, 0x97,0x00,0x00,0x00, 0xe7,0x80,0x40,0xdb,
+0x4a,0x8b,0x81,0x49, 0xd1,0xbd,0xd2,0x85, 0x56,0x85,0x97,0x00, 0x00,0x00,0xe7,0x80,
+0x20,0xda,0x81,0x49, 0xd1,0xb5,0xd2,0x85, 0x56,0x85,0x97,0x00, 0x00,0x00,0xe7,0x80,
+0x20,0xd9,0xca,0x85, 0x56,0x85,0x97,0x00, 0x00,0x00,0xe7,0x80, 0x60,0xd8,0x81,0x49,
+0x65,0xb5,0x4a,0x8b, 0x81,0x49,0x4d,0xb5, 0xe6,0x70,0x46,0x74, 0xa6,0x74,0x06,0x79,
+0xe6,0x69,0x46,0x6a, 0xa6,0x6a,0x06,0x6b, 0xe2,0x7b,0x42,0x7c, 0xa2,0x7c,0x02,0x7d,
+0xe2,0x6d,0x09,0x61, 0x82,0x80,0x5d,0x71, 0x06,0xec,0x22,0xe8, 0x00,0x10,0x10,0xe0,
+0x14,0xe4,0x18,0xe8, 0x1c,0xec,0x23,0x30, 0x04,0x03,0x23,0x34, 0x14,0x03,0x22,0x86,
+0x23,0x34,0x84,0xfe, 0x97,0x00,0x00,0x00, 0xe7,0x80,0x40,0xe0, 0xe2,0x60,0x42,0x64,
+0x61,0x61,0x82,0x80, 0x1d,0x71,0x06,0xec, 0x22,0xe8,0x00,0x10, 0x0c,0xe4,0x10,0xe8,
+0x14,0xec,0x18,0xf0, 0x1c,0xf4,0x23,0x38, 0x04,0x03,0x23,0x3c, 0x14,0x03,0x13,0x06,
+0x84,0x00,0x23,0x34, 0xc4,0xfe,0xaa,0x85, 0x05,0x45,0x97,0x00, 0x00,0x00,0xe7,0x80,
+0xe0,0xdc,0xe2,0x60, 0x42,0x64,0x25,0x61, 0x82,0x80,0x41,0x11, 0x22,0xe4,0x00,0x08,
+0x93,0x06,0x05,0xff, 0x97,0x07,0x00,0x00, 0x83,0xb7,0xc7,0x41, 0x2d,0xa0,0x18,0x46,
+0x2d,0x9f,0x23,0x2c, 0xe5,0xfe,0x98,0x63, 0x10,0x63,0x3d,0xa8, 0x03,0x27,0x85,0xff,
+0x31,0x9f,0x98,0xc7, 0x83,0x36,0x05,0xff, 0x91,0xa0,0x98,0x63, 0x63,0xe4,0xe7,0x00,
+0x63,0xea,0xe6,0x00, 0xba,0x87,0xe3,0xfa, 0xd7,0xfe,0x98,0x63, 0x63,0xe4,0xe6,0x00,
+0xe3,0xea,0xe7,0xfe, 0x83,0x25,0x85,0xff, 0x90,0x63,0x13,0x98, 0x05,0x02,0x13,0x57,
+0xc8,0x01,0x36,0x97, 0xe3,0x0d,0xe6,0xfa, 0x23,0x38,0xc5,0xfe, 0x90,0x47,0x93,0x15,
+0x06,0x02,0x13,0xd7, 0xc5,0x01,0x3e,0x97, 0xe3,0x8a,0xe6,0xfa, 0x94,0xe3,0x17,0x07,
+0x00,0x00,0x23,0x39, 0xf7,0x3a,0x22,0x64, 0x41,0x01,0x82,0x80, 0x39,0x71,0x06,0xfc,
+0x22,0xf8,0x26,0xf4, 0x4a,0xf0,0x4e,0xec, 0x52,0xe8,0x56,0xe4, 0x5a,0xe0,0x80,0x00,
+0x93,0x14,0x05,0x02, 0x81,0x90,0xbd,0x04, 0x91,0x80,0x1b,0x8a, 0x14,0x00,0x85,0x04,
+0x17,0x05,0x00,0x00, 0x03,0x35,0x05,0x38, 0x15,0xc5,0x1c,0x61, 0x98,0x47,0x63,0x71,
+0x97,0x04,0xd2,0x89, 0x1b,0x07,0x0a,0x00, 0x85,0x66,0x63,0x73, 0xd7,0x00,0x85,0x69,
+0x1b,0x8b,0x09,0x00, 0x9b,0x99,0x49,0x00, 0x17,0x09,0x00,0x00, 0x13,0x09,0x89,0x35,
+0xfd,0x5a,0xa5,0xa8, 0x97,0x07,0x00,0x00, 0x93,0x87,0xc7,0x34, 0x17,0x07,0x00,0x00,
+0x13,0x07,0xc7,0x34, 0x98,0xe3,0x98,0xe7, 0x23,0xa8,0x07,0x00, 0xba,0x87,0xd1,0xb7,
+0x63,0x8c,0xe4,0x02, 0x3b,0x07,0x47,0x41, 0x98,0xc7,0x93,0x16, 0x07,0x02,0x13,0xd7,
+0xc6,0x01,0xba,0x97, 0x23,0xa4,0x47,0x01, 0x17,0x07,0x00,0x00, 0x23,0x3c,0xa7,0x30,
+0x13,0x85,0x07,0x01, 0xe2,0x70,0x42,0x74, 0xa2,0x74,0x02,0x79, 0xe2,0x69,0x42,0x6a,
+0xa2,0x6a,0x02,0x6b, 0x21,0x61,0x82,0x80, 0x98,0x63,0x18,0xe1, 0xf1,0xbf,0x23,0x24,
+0x65,0x01,0x41,0x05, 0x97,0x00,0x00,0x00, 0xe7,0x80,0x60,0xec, 0x03,0x35,0x09,0x00,
+0x71,0xd9,0x1c,0x61, 0x98,0x47,0xe3,0x75, 0x97,0xfa,0x03,0x37, 0x09,0x00,0x3e,0x85,
+0xe3,0x19,0xf7,0xfe, 0x4e,0x85,0x97,0x00, 0x00,0x00,0xe7,0x80, 0x20,0xa5,0xe3,0x18,
+0x55,0xfd,0x01,0x45, 0x45,0xbf,0x00,0x00,
+0x2f,0x64,0x65,0x76, 0x00,0x00,0x00,0x00, 0x2f,0x70,0x72,0x6f, 0x63,0x00,0x00,0x00,
+0x2f,0x76,0x61,0x72, 0x00,0x00,0x00,0x00, 0x2f,0x76,0x61,0x72, 0x2f,0x74,0x6d,0x70,
+0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x76,0x61,0x72,0x2f, 0x74,0x6d,0x70,0x2f,
+0x58,0x58,0x58,0x00, 0x00,0x00,0x00,0x00, 0x2f,0x64,0x65,0x76, 0x2f,0x72,0x74,0x63,
+0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x2f,0x70,0x72,0x6f, 0x63,0x2f,0x6d,0x6f,
+0x75,0x6e,0x74,0x73, 0x00,0x00,0x00,0x00, 0x2f,0x70,0x72,0x6f, 0x63,0x2f,0x6d,0x65,
+0x6d,0x69,0x6e,0x66, 0x6f,0x00,0x00,0x00, 0x2f,0x62,0x69,0x6e, 0x00,0x00,0x00,0x00,
+0x2f,0x62,0x69,0x6e, 0x2f,0x6c,0x73,0x00, 0x2f,0x64,0x65,0x76, 0x2f,0x6e,0x75,0x6c,
+0x6c,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x2f,0x64,0x65,0x76, 0x2f,0x7a,0x65,0x72,
+0x6f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x62,0x75,0x73,0x79, 0x62,0x6f,0x78,0x5f,
+0x63,0x6d,0x64,0x2e, 0x74,0x78,0x74,0x00, 0x62,0x75,0x73,0x79, 0x62,0x6f,0x78,0x00,
+0x74,0x65,0x73,0x74, 0x63,0x61,0x73,0x65, 0x20,0x62,0x75,0x73, 0x79,0x62,0x6f,0x78,
+0x20,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x25,0x73,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x20,0x73,0x75,0x63, 0x63,0x65,0x73,0x73, 0x0a,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x20,0x66,0x61,0x69, 0x6c,0x0a,0x00,0x00, 0x2e,0x2f,0x6c,0x75, 0x61,0x00,0x00,0x00,
+0x74,0x65,0x73,0x74, 0x63,0x61,0x73,0x65, 0x20,0x6c,0x75,0x61, 0x20,0x25,0x73,0x20,
+0x73,0x75,0x63,0x63, 0x65,0x73,0x73,0x0a, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x74,0x65,0x73,0x74, 0x63,0x61,0x73,0x65, 0x20,0x6c,0x75,0x61, 0x20,0x25,0x73,0x20,
+0x66,0x61,0x69,0x6c, 0x0a,0x00,0x00,0x00, 0x2f,0x6c,0x6d,0x62, 0x65,0x6e,0x63,0x68,
+0x5f,0x74,0x65,0x73, 0x74,0x63,0x6f,0x64, 0x65,0x2e,0x73,0x68, 0x00,0x00,0x00,0x00,
+0x64,0x61,0x74,0x65, 0x2e,0x6c,0x75,0x61, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x66,0x69,0x6c,0x65, 0x5f,0x69,0x6f,0x2e, 0x6c,0x75,0x61,0x00, 0x00,0x00,0x00,0x00,
+0x6d,0x61,0x78,0x5f, 0x6d,0x69,0x6e,0x2e, 0x6c,0x75,0x61,0x00, 0x00,0x00,0x00,0x00,
+0x72,0x61,0x6e,0x64, 0x6f,0x6d,0x2e,0x6c, 0x75,0x61,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x72,0x65,0x6d,0x6f, 0x76,0x65,0x2e,0x6c, 0x75,0x61,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x72,0x6f,0x75,0x6e, 0x64,0x5f,0x6e,0x75, 0x6d,0x2e,0x6c,0x75, 0x61,0x00,0x00,0x00,
+0x73,0x69,0x6e,0x33, 0x30,0x2e,0x6c,0x75, 0x61,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x73,0x6f,0x72,0x74, 0x2e,0x6c,0x75,0x61, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x73,0x74,0x72,0x69, 0x6e,0x67,0x73,0x2e, 0x6c,0x75,0x61,0x00, 0x00,0x00,0x00,0x00,
+0x01,0x00,0x00,0x00, 0x02,0x00,0x00,0x00, 0x0b,0x00,0x00,0x00, 0x0e,0x00,0x00,0x00,
+0x0f,0x00,0x00,0x00, 0x14,0x00,0x00,0x00, 0x15,0x00,0x00,0x00, 0x16,0x00,0x00,0x00,
+0x1a,0x00,0x00,0x00, 0x20,0x00,0x00,0x00, 0x28,0x6e,0x75,0x6c, 0x6c,0x29,0x00,0x00,
+0xc6,0xfb,0xff,0xff, 0xee,0xfa,0xff,0xff, 0xee,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff,
+0xee,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff,
+0xee,0xfb,0xff,0xff, 0x0a,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff,
+0xee,0xfb,0xff,0xff, 0x42,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff,
+0x90,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff, 0xee,0xfb,0xff,0xff,
+0xee,0xfb,0xff,0xff, 0x26,0xfb,0xff,0xff, 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
+0x38,0x39,0x41,0x42, 0x43,0x44,0x45,0x46, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x38,0x12,0x00,0x00, 0x00,0x00,0x00,0x00, 0x48,0x12,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x58,0x12,0x00,0x00, 0x00,0x00,0x00,0x00, 0x68,0x12,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x78,0x12,0x00,0x00, 0x00,0x00,0x00,0x00, 0x88,0x12,0x00,0x00, 0x00,0x00,0x00,0x00,
+0x98,0x12,0x00,0x00, 0x00,0x00,0x00,0x00, 0xa8,0x12,0x00,0x00, 0x00,0x00,0x00,0x00,
+0xb8,0x12,0x00,0x00, 0x00,0x00,0x00,0x00
+};
+
+// uchar printhello[] = {
+//     0x13, 0x00, 0x00, 0x00,     // nop
+//     0x13, 0x00, 0x00, 0x00,     // nop 
+//     0x13, 0x00, 0x00, 0x00,     // nop 
+//     // <start>
+//     0x17, 0x05, 0x00, 0x00,     // auipc a0, 0x0 
+//     0x13, 0x05, 0x05, 0x00,     // mv a0, a0 
+//     0x93, 0x08, 0x60, 0x01,     // li a7, 22 
+//     0x73, 0x00, 0x00, 0x00,     // ecall 
+//     0xef, 0xf0, 0x1f, 0xff,     // jal ra, <start>
+//     // <loop>
+//     0xef, 0x00, 0x00, 0x00,     // jal ra, <loop>
+// };
+
+
+// void test_proc_init(int proc_num) {
+//   if(proc_num > NPROC) panic("test_proc_init\n");
+//   struct proc *p;
+//   for(int i = 0; i < proc_num; i++) {
+//     p = allocproc();
+//     uvminit(p->pagetable, (uchar*)printhello, sizeof(printhello));
+//     p->sz = PGSIZE;
+//     p->trapframe->epc = 0x0;
+//     p->trapframe->sp = PGSIZE;
+//     safestrcpy(p->name, "test_code", sizeof(p->name));
+//     p->state = RUNNABLE;
+//     release(&p->lock);
+//   }
+//   initproc = proc;
+//   printf("[test_proc]test_proc init done\n");
+// }
+
+// Set up first user process.
+void
+userinit(void)
+{
+  struct proc *p;
+
+  p = allocproc();
+  initproc = p;
+  // allocate one user page and copy init's instructions
+  // and data into it.
+  int i = uvminit(p->pagetable , p->kpagetable, initcode, sizeof(initcode));
+  p->sz = i;
+  p->static_sz =  sizeof(initcode);
+  p->my_seg.prosize=sizeof(initcode);
+  p->ustack_base = VUSTACK - PGSIZE;
+  char *mem;
+  mem = kalloc();
+  // printf("[uvminit]kalloc: %p\n", mem);
+  memset(mem, 0, PGSIZE);
+  mappages(p->pagetable, p->ustack_base, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U);
+  mappages(p->kpagetable, p->ustack_base, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X);
+  // prepare for the very first "return" from kernel to user.
+  p->trapframe->epc = 0x0;      // user program counter
+  p->trapframe->sp = VUSTACK;  // user stack pointer
+
+  safestrcpy(p->name, "initcode", sizeof(p->name));
+
+  p->state = RUNNABLE;
+
+  p->tmask = 0;
+
+  release(&p->lock);
+  #ifdef DEBUG
+  printf("userinit\n");
+  #endif
+}
+
+// Grow or shrink user memory by n bytes.
+// Return 0 on success, -1 on failure.
+int
+growproc(int n)
+{
+  uint sz;
+  struct proc *p = myproc();
+
+  sz = p->sz;
+  n = PGROUNDUP(n);
+  if(n > 0){
+    if((sz = apply_bvmem(sz,n,PTE_W|PTE_R)) == 0) {
+      __ERROR("");
+      return -1;
+    }
+  } else if(n < 0){
+    if(n + p->sbrk_size < 0){
+      __ERROR("");
+      return -1;
+    }
+    sz = uvmdealloc(p->pagetable, p->kpagetable, sz, sz + n);
+  }
+  p->sz += n;
+  p->sbrk_size += n;
+  if(p->sz != p->sbrk_base + p->sbrk_size){
+    __ERROR("error");
+    panic("");
+  }
+  return 0;
+}
+
+
+
+int apply_bvmem(uint64 start,int n, int flags){  //申请一块虚拟内存,但不分配内存页
+  struct proc *p = myproc();
+  uint64 a, last;
+  pte_t *pte,*kpte;
+
+  a = PGROUNDDOWN(start);
+  last = PGROUNDUP(start + n);
+  
+  for(;a != last;a += PGSIZE){
+    if((pte = walk(p->pagetable, a, 1)) == NULL){
+      __ERROR("");
+      return -1;
+    }
+    // __DEBUG("%p",a);
+    if(*pte & PTE_V || PTE_FLAGS(*pte))
+      continue;
+
+    if((kpte = walk(p->kpagetable, a, 1)) == NULL){
+      __ERROR("");
+      return -1;
+    }
+    if(*kpte & PTE_V)
+      continue;
+    *pte = (*pte | flags | PTE_U) & (~PTE_V);
+    *kpte = (*pte | flags) & (~PTE_U);
+  }
+  return last+PGSIZE;
+}
+
+int apply_bvmem2(pagetable_t pagetable,pagetable_t kpagetable, uint64 start,int n, int flags){  //申请一块虚拟内存,但不分配内存页
+  uint64 a, last;
+  pte_t *pte,*kpte;
+
+  a = PGROUNDDOWN(start);
+  last = PGROUNDUP(start + n);
+  
+  for(;a != last;a += PGSIZE){
+    if((pte = walk(pagetable, a, 1)) == NULL){
+      __ERROR("");
+      return -1;
+    }
+    // __DEBUG("%p",a);
+    if(*pte & PTE_V)
+      continue;
+
+    if((kpte = walk(kpagetable, a, 1)) == NULL){
+      __ERROR("");
+      return -1;
+    }
+    if(*kpte & PTE_V)
+      continue;
+    *pte = (*pte | flags | PTE_U) & (~PTE_V);
+    *kpte = (*pte | flags) & (~PTE_U);
+  }
+  return last+PGSIZE;
+}
+
+// Create a new process, copying the parent.
+// Sets up child kernel stack to return as if from fork() system call.
+int
+fork(void)
+{
+  // __DEBUG("-----------flags:%d--ptid:%d--tls:%d--ctid%d",flags,ptid,tls,ctid);
+  //printf("start \n");
+  int i, pid;
+  struct proc *np;
+  struct proc *p = myproc();
+  // Allocate process.
+  if((np = allocproc()) == NULL){
+    return -1;
+  }
+
+  // Copy user memory from parent to child.
+  if(proc_share(p->pagetable, np->pagetable, np->kpagetable, 0, p->sz) < 0){
+    freeproc(np);
+    release(&np->lock);
+    return -1;
+  }
+  if(proc_share(p->pagetable, np->pagetable, np->kpagetable, p->ustack_base, VUSTACK) < 0){
+    freeproc(np);
+    release(&np->lock);
+    return -1;
+  }
+  if(proc_share(p->pagetable, np->pagetable, np->kpagetable, VMMAP_BASE, VMMAP_BASE + p->mmap_size) < 0){
+    freeproc(np);
+    release(&np->lock);
+    return -1;
+  }
+  np->sz = p->sz;
+
+  np->static_sz=p->static_sz;
+  np->my_seg.prosize=p->my_seg.prosize;
+  // if(memmove((char*)np->seg,(char*)p->seg,PGSIZE)==0){
+  //   panic("in do_clone strncmp error!");
+  // }
+  // if(memmove((char*)np->free_seg,(char*)p->free_seg,PGSIZE)==0){
+  //   panic("in do_clone strncmp error!");
+  // }
+  np->parent = p;
+  
+  // copy tracing mask from parent.
+  np->tmask = p->tmask;
+
+  // copy saved user registers.
+  *(np->trapframe) = *(p->trapframe);
+
+  // Cause fork to return 0 in the child.
+  np->trapframe->a0 = 0;
+  np->sbrk_base = p->sbrk_base;
+  np->sbrk_size = p->sbrk_size;
+  np->mmap_size = p->mmap_size;
+  np->ustack_base = p->ustack_base;
+  // increment reference counts on open file descriptors.
+  for(i = 0; i < NOFILE; i++)
+    if(p->ofile[i])
+      np->ofile[i] = filedup(p->ofile[i]);
+  
+  np->cwd = edup(p->cwd);
+  np->my_seg.baseaddr =p->my_seg.baseaddr;
+  np->my_seg.num = p->my_seg.num;
+  np->my_seg.prosize = p->my_seg.prosize;
+  np->myep=p->myep;
+  np->load_bias=p->load_bias;
+
+  for(int i = 0;i<SIGSETSIZE;i++){
+    np->pending.__bits[i] = p->pending.__bits[i];
+    np->mask.__bits[i] = p->mask.__bits[i];
+  }
+
+  for(int i = 0;i < N_SIG;i++){
+    np->act[i] = p->act[i];
+  }
+
+  for(int i = 0;i<RLIMIT_NLIMITS;i++){
+    np->rlim[i].rlim_cur = p->rlim[i].rlim_cur;
+    np->rlim[i].rlim_max = p->rlim[i].rlim_max;
+  }
+  
+  safestrcpy(np->name, p->name, sizeof(p->name));
+
+  pid = np->pid;
+
+  np->state = RUNNABLE;
+  //printf("end \n");
+  release(&np->lock);
+  return pid;
+  //printf("start \n");
+  // int i, pid;
+  // struct proc *np;
+  // struct proc *p = myproc();
+
+  // // Allocate process.
+  // if((np = allocproc()) == NULL){
+  //   return -1;
+  // }
+  // // Copy user memory from parent to child.
+  // if(proc_share(p->pagetable, np->pagetable, np->kpagetable, 0, p->sz) < 0){
+  //   freeproc(np);
+  //   release(&np->lock);
+  //   return -1;
+  // }
+  // if(proc_share(p->pagetable, np->pagetable, np->kpagetable, p->ustack_base, VUSTACK) < 0){
+  //   freeproc(np);
+  //   release(&np->lock);
+  //   return -1;
+  // }
+  // if(proc_share(p->pagetable, np->pagetable, np->kpagetable, VMMAP_BASE, VMMAP_BASE + p->mmap_size) < 0){
+  //   freeproc(np);
+  //   release(&np->lock);
+  //   return -1;
+  // }
+
+  // np->sz = p->sz;
+  // np->ustack_base = p->ustack_base;
+  // np->static_sz=p->static_sz;
+
+  // np->parent = p;
+  // np->sbrk_base = p->sbrk_base;
+  // np->sbrk_size = p->sbrk_size;
+  // np->mmap_size = p->mmap_size;
+  // // copy tracing mask from parent.
+  // np->tmask = p->tmask;
+
+  // // copy saved user registers.
+  // *(np->trapframe) = *(p->trapframe);
+
+  // // Cause fork to return 0 in the child.
+  // np->trapframe->a0 = 0;
+
+  // // increment reference counts on open file descriptors.
+  // for(i = 0; i < NOFILE; i++)
+  //   if(p->ofile[i])
+  //     np->ofile[i] = filedup(p->ofile[i]);
+  
+  // np->cwd = edup(p->cwd);
+  // np->my_seg.baseaddr =p->my_seg.baseaddr;
+  // np->my_seg.num = p->my_seg.num;
+  // np->my_seg.prosize = p->my_seg.prosize;
+  // np->myep=p->myep;
+
+  // for(int i = 0;i<SIGSETSIZE;i++){
+  //   np->pending.__bits[i] = p->pending.__bits[i];
+  //   np->mask.__bits[i] = p->mask.__bits[i];
+  // }
+
+  // for(int i = 0;i < N_SIG;i++){
+  //   np->act[i] = p->act[i];
+  // }
+
+
+  // for(int i = 0;i<RLIMIT_NLIMITS;i++){
+  //   np->rlim[i].rlim_cur = p->rlim[i].rlim_cur;
+  //   np->rlim[i].rlim_max = p->rlim[i].rlim_max;
+  // }
+  
+  // safestrcpy(np->name, p->name, sizeof(p->name));
+
+  // pid = np->pid;
+
+  // np->state = RUNNABLE;
+  // //printf("end \n");
+  // release(&np->lock);
+  
+  // return pid;
+}
+
+int do_clone(uint64 stack, uint64 flags,uint64 ptid,uint64 tls,uint64 ctid){
+  // __DEBUG("-----------flags:%d--ptid:%d--tls:%d--ctid%d",flags,ptid,tls,ctid);
+  //printf("start \n");
+  int i, pid;
+  struct proc *np;
+  struct proc *p = myproc();
+  // Allocate process.
+  if((np = allocproc()) == NULL){
+    return -1;
+  }
+
+  // Copy user memory from parent to child.
+  if(proc_share(p->pagetable, np->pagetable, np->kpagetable, 0, p->sz) < 0){
+    freeproc(np);
+    release(&np->lock);
+    return -1;
+  }
+  if(proc_share(p->pagetable, np->pagetable, np->kpagetable, p->ustack_base, VUSTACK) < 0){
+    freeproc(np);
+    release(&np->lock);
+    return -1;
+  }
+  if(proc_share(p->pagetable, np->pagetable, np->kpagetable, VMMAP_BASE, VMMAP_BASE + p->mmap_size) < 0){
+    freeproc(np);
+    release(&np->lock);
+    return -1;
+  }
+  np->sz = p->sz;
+
+  np->static_sz=p->static_sz;
+  np->my_seg.prosize=p->my_seg.prosize;
+  // if(memmove((char*)np->seg,(char*)p->seg,PGSIZE)==0){
+  //   panic("in do_clone strncmp error!");
+  // }
+  // if(memmove((char*)np->free_seg,(char*)p->free_seg,PGSIZE)==0){
+  //   panic("in do_clone strncmp error!");
+  // }
+  np->parent = p;
+  
+  // copy tracing mask from parent.
+  np->tmask = p->tmask;
+
+  // copy saved user registers.
+  *(np->trapframe) = *(p->trapframe);
+
+  if(stack!=0){
+    np->trapframe->sp = stack;
+  }
+
+  // Cause fork to return 0 in the child.
+  np->trapframe->a0 = 0;
+  np->sbrk_base = p->sbrk_base;
+  np->sbrk_size = p->sbrk_size;
+  np->mmap_size = p->mmap_size;
+  np->ustack_base = p->ustack_base;
+  // increment reference counts on open file descriptors.
+  for(i = 0; i < NOFILE; i++)
+    if(p->ofile[i])
+      np->ofile[i] = filedup(p->ofile[i]);
+  
+  np->cwd = edup(p->cwd);
+  np->my_seg.baseaddr =p->my_seg.baseaddr;
+  np->my_seg.num = p->my_seg.num;
+  np->my_seg.prosize = p->my_seg.prosize;
+  np->myep=p->myep;
+  np->load_bias=p->load_bias;
+
+  for(int i = 0;i<SIGSETSIZE;i++){
+    np->pending.__bits[i] = p->pending.__bits[i];
+    np->mask.__bits[i] = p->mask.__bits[i];
+  }
+
+  for(int i = 0;i < N_SIG;i++){
+    np->act[i] = p->act[i];
+  }
+
+  for(int i = 0;i<RLIMIT_NLIMITS;i++){
+    np->rlim[i].rlim_cur = p->rlim[i].rlim_cur;
+    np->rlim[i].rlim_max = p->rlim[i].rlim_max;
+  }
+  
+  safestrcpy(np->name, p->name, sizeof(p->name));
+
+  pid = np->pid;
+
+  np->state = RUNNABLE;
+  //printf("end \n");
+  release(&np->lock);
+  return pid;
+}
+// Pass p's abandoned children to init.
+// Caller must hold p->lock.
+void
+reparent(struct proc *p)
+{
+  struct proc *pp;
+
+  for(pp = proc; pp < &proc[NPROC]; pp++){
+    // this code uses pp->parent without holding pp->lock.
+    // acquiring the lock first could cause a deadlock
+    // if pp or a child of pp were also in exit()
+    // and about to try to lock p.
+    if(pp->parent == p){
+      // pp->parent can't change between the check and the acquire()
+      // because only the parent changes it, and we're the parent.
+      acquire(&pp->lock);
+      pp->parent = initproc;
+      // we should wake up init here, but that would require
+      // initproc->lock, which would be a deadlock, since we hold
+      // the lock on one of init's children (pp). this is why
+      // exit() always wakes init (before acquiring any locks).
+      release(&pp->lock);
+    }
+  }
+}
+
+// Exit the current process.  Does not return.
+// An exited process remains in the zombie state
+// until its parent calls wait().
+void
+exit(int status)
+{
+  struct proc *p = myproc();
+  // int pid = myproc()->pid;
+  if(p == initproc)
+    panic("init exiting");
+  
+  p = myproc();
+  // Close all open files.
+  for(int fd = 0; fd < NOFILE; fd++){
+    if(p->ofile[fd]){
+      struct file *f = p->ofile[fd];
+      fileclose(f);
+      p->ofile[fd] = 0;
+    }
+  }
+
+  eput(p->cwd);
+  p->cwd = 0;
+
+  // we might re-parent a child to init. we can't be precise about
+  // waking up init, since we can't acquire its lock once we've
+  // acquired any other proc lock. so wake up init whether that's
+  // necessary or not. init may miss this wakeup, but that seems
+  // harmless.
+  acquire(&initproc->lock);
+  wakeup1(initproc);
+  release(&initproc->lock);
+
+  // grab a copy of p->parent, to ensure that we unlock the same
+  // parent we locked. in case our parent gives us away to init while
+  // we're waiting for the parent lock. we may then race with an
+  // exiting parent, but the result will be a harmless spurious wakeup
+  // to a dead or wrong process; proc structs are never re-allocated
+  // as anything else.
+  acquire(&p->lock);
+  struct proc *original_parent = p->parent;
+  release(&p->lock);
+
+  if(original_parent){
+    sendsignal(original_parent->pid, SIGCHLD);
+  }
+  // we need the parent's lock in order to wake it up from wait().
+  // the parent-then-child rule says we have to lock it first.
+  acquire(&original_parent->lock);
+
+  acquire(&p->lock);
+
+  // Give any children to init.
+  reparent(p);
+  
+  // Parent might be sleeping in wait().
+  wakeup1(original_parent);
+
+  p->xstate = status;
+  p->state = ZOMBIE;
+
+  release(&original_parent->lock);
+
+  // Jump into the scheduler, never to return.
+  sched();
+  panic("zombie exit");
+}
+
+// Wait for a child process to exit and return its pid.
+// Return -1 if this process has no children.
+int
+wait(uint64 addr)
+{
+  struct proc *np;
+  int havekids, pid;
+  struct proc *p = myproc();
+
+  // hold p->lock for the whole time to avoid lost
+  // wakeups from a child's exit().
+  acquire(&p->lock);
+
+  for(;;){
+    // Scan through table looking for exited children.
+    havekids = 0;
+    for(np = proc; np < &proc[NPROC]; np++){
+      // this code uses np->parent without holding np->lock.
+      // acquiring the lock first would cause a deadlock,
+      // since np might be an ancestor, and we already hold p->lock.
+      if(np->parent == p){
+        // np->parent can't change between the check and the acquire()
+        // because only the parent changes it, and we're the parent.
+        acquire(&np->lock);
+        havekids = 1;
+        if(np->state == ZOMBIE){
+          // Found one.
+          pid = np->pid;
+
+          if(addr != 0 && copyout(p->pagetable, addr, (char *)&np->xstate, sizeof(np->xstate)) < 0) {
+            release(&np->lock);
+            release(&p->lock);
+            return -1;
+          }
+          // p->ti.tms_cstime+=np->ti.tms_stime;
+          // p->ti.tms_cutime+=np->ti.tms_utime;
+          freeproc(np);
+          release(&np->lock);
+          release(&p->lock);
+          return pid;
+        }
+        release(&np->lock);
+      }
+    }
+
+    // No point waiting if we don't have any children.
+    if(!havekids || p->killed){
+      release(&p->lock);
+      return -1;
+    }
+    
+    // Wait for a child to exit.
+    sleep(p, &p->lock);  //DOC: wait-sleep
+  }
+}
+
+
+int do_waitpid(int pid_t, uint64 wstatus, int options){
+  struct proc *p = myproc();
+  struct proc *np;
+  int havekids, pid = pid_t;
+  // hold p->lock for the whole time to avoid lost
+  // wakeups from a child's exit().
+  acquire(&p->lock);
+  for(;;){
+    // Scan through table looking for exited children.
+    havekids = 0;
+    for(np = proc; np < &proc[NPROC]; np++){
+      if(np->parent == p){
+        if(pid>0){
+          if(np->pid!=pid){
+            continue;
+          }
+        }
+        else if(pid ==-1){}
+        else{
+          return -1;
+        }
+        acquire(&np->lock);
+          havekids = 1;
+          if(np->state == ZOMBIE){
+          // Found one.
+            pid = np->pid;
+            if(wstatus != 0) {
+              int status = (np->xstate<<8)& 0xff00;
+              copyout(p->pagetable, wstatus, (char *)&status, sizeof(status));
+            }
+            p->ti.tms_cstime += np->ti.tms_stime + np->ti.tms_cstime;
+				    p->ti.tms_cutime += np->ti.tms_utime + np->ti.tms_cutime;
+            freeproc(np);
+            release(&np->lock);
+            release(&p->lock);
+            return pid;
+          }
+          release(&np->lock);
+      }
+    }
+    if(!havekids || p->killed){
+      release(&p->lock);
+      return -1;
+    }
+    if(options==WNOHANG) {
+      return 0;
+    }
+    else{
+      sleep(p, &p->lock);
+    }
+  }
+}
+
+
+// Per-CPU process scheduler.
+// Each CPU calls scheduler() after setting itself up.
+// Scheduler never returns.  It loops, doing:
+//  - choose a process to run.
+//  - swtch to start running that process.
+//  - eventually that process transfers control
+//    via swtch back to the scheduler.
+void
+scheduler(void)
+{
+  struct proc *p;
+  struct cpu *c = mycpu();
+  extern pagetable_t kernel_pagetable;
+
+  c->proc = 0;
+  for(;;){
+    // Avoid deadlock by ensuring that devices can interrupt.
+    intr_on();
+    
+    int found = 0;
+    for(p = proc; p < &proc[NPROC]; p++) {
+      acquire(&p->lock);
+      // if(p->state == SLEEPING){
+        // __DEBUG("pid %d is sleeping",p->pid);
+      // }
+      if(p->state == RUNNABLE) {
+        // Switch to chosen process.  It is the process's job
+        // to release its lock and then reacquire it
+        // before jumping back to us.
+        // printf("[scheduler]found runnable proc with pid: %d\n", p->pid);
+        p->state = RUNNING;
+        c->proc = p;
+        w_satp(MAKE_SATP(p->kpagetable));
+        sfence_vma();
+        swtch(&c->context, &p->context);
+        w_satp(MAKE_SATP(kernel_pagetable));
+        sfence_vma();
+        // Process is done running for now.
+        // It should have changed its p->state before coming back.
+        c->proc = 0;
+
+        found = 1;
+      }
+      release(&p->lock);
+    }
+    if(found == 0) {
+      intr_on();
+      asm volatile("wfi");
+    }
+  }
+}
+
+// Switch to scheduler.  Must hold only p->lock
+// and have changed proc->state. Saves and restores
+// intena because intena is a property of this
+// kernel thread, not this CPU. It should
+// be proc->intena and proc->noff, but that would
+// break in the few places where a lock is held but
+// there's no process.
+void
+sched(void)
+{
+  int intena;
+  struct proc *p = myproc();
+
+  if(!holding(&p->lock)){
+    int a = p->lock.locked;
+    uint64 b = (uint64)p->lock.cpu;
+    uint64 c = (uint64)mycpu();
+    __ERROR("locked = %d, cpu = %p, lock.cpu = %p",a,c,b);
+    panic("sched p->lock");
+  }
+  if(mycpu()->noff != 1){
+    int noff = mycpu()->noff;
+    __ERROR("noff = %d",noff);
+    panic("sched locks");
+  }
+  if(p->state == RUNNING)
+    panic("sched running");
+  if(intr_get())
+    panic("sched interruptible");
+
+  p->ti.tms_stime += readtime() - p->ikstmp;
+
+  intena = mycpu()->intena;
+  swtch(&p->context, &mycpu()->context);
+  mycpu()->intena = intena;
+
+  p->ikstmp = readtime();
+}
+
+// struct proc* find_runnable_proc(){
+//   struct proc* p;
+//   for(p = proc; p < &proc[NPROC]; p++) {
+//     acquire(&p->lock);
+//     if(p->state == RUNNABLE) {
+//       release(&p->lock);
+//       return p;
+//     } else {
+//       release(&p->lock);
+//     }
+//   }
+  
+//   return NULL;
+// }
+
+// Give up the CPU for one scheduling round.
+void
+yield(void)
+{
+  struct proc *p = myproc();
+  acquire(&p->lock);
+  p->state = RUNNABLE;
+  sched();
+  release(&p->lock);
+}
+
+// A fork child's very first scheduling by scheduler()
+// will swtch to forkret.
+void
+forkret(void)
+{
+  // printf("run in forkret\n");
+  static int first = 1;
+
+  // Still holding p->lock from scheduler.
+  release(&myproc()->lock);
+
+  if (first) {
+    // File system initialization must be run in the context of a
+    // regular process (e.g., because it calls sleep), and thus cannot
+    // be run from main().
+    // printf("[forkret]first scheduling\n");
+    first = 0;
+    fat32_init();
+    myproc()->cwd = ename("/");
+  }
+  myproc()->ikstmp = readtime();
+  usertrapret();
+}
+
+// Atomically release lock and sleep on chan.
+// Reacquires lock when awakened.
+void
+sleep(void *chan, struct spinlock *lk)
+{
+  struct proc *p = myproc();
+  // __DEBUG("pid %d sleep",p->pid);
+
+  // Must acquire p->lock in order to
+  // change p->state and then call sched.
+  // Once we hold p->lock, we can be
+  // guaranteed that we won't miss any wakeup
+  // (wakeup locks p->lock),
+  // so it's okay to release lk.
+  if(lk != &p->lock){  //DOC: sleeplock0
+    acquire(&p->lock);  //DOC: sleeplock1
+    release(lk);
+  }
+
+  p->vswtch += 1;
+  // Go to sleep.
+  p->chan = chan;
+  // printf("%s sleep\n",p->name);
+  p->state = SLEEPING;
+  
+  sched();
+
+  // Tidy up.
+  p->chan = 0;
+
+  // Reacquire original lock.
+  if(lk != &p->lock){
+    release(&p->lock);
+    acquire(lk);
+  }
+}
+
+// Wake up all processes sleeping on chan.
+// Must be called without any p->lock.
+void
+wakeup(void *chan)
+{
+  struct proc *p;
+
+  for(p = proc; p < &proc[NPROC]; p++) {
+    acquire(&p->lock);
+    if(p->state == SLEEPING && p->chan == chan) {
+      p->state = RUNNABLE;
+      // __DEBUG("wakeup pid %d",p->pid);
+    }
+    release(&p->lock);
+  }
+}
+
+// Wake up p if it is sleeping in wait(); used by exit().
+// Caller must hold p->lock.
+static void
+wakeup1(struct proc *p)
+{
+  if(!holding(&p->lock))
+    panic("wakeup1");
+  if(p->chan == p && p->state == SLEEPING) {
+    p->state = RUNNABLE;
+  }
+}
+
+// Kill the process with the given pid.
+// The victim won't exit until it tries to return
+// to user space (see usertrap() in trap.c).
+int
+kill(int pid)
+{
+  struct proc *p;
+
+  for(p = proc; p < &proc[NPROC]; p++){
+    acquire(&p->lock);
+    if(p->pid == pid){
+      p->killed = 1;
+      if(p->state == SLEEPING){
+        // Wake process from sleep().
+        p->state = RUNNABLE;
+      }
+      release(&p->lock);
+      return 0;
+    }
+    release(&p->lock);
+  }
+  return -1;
+}
+
+// Copy to either a user address, or kernel address,
+// depending on usr_dst.
+// Returns 0 on success, -1 on error.
+int
+either_copyout(int user_dst, uint64 dst, void *src, uint64 len)
+{
+  // struct proc *p = myproc();
+  if(user_dst){
+
+    return copyout(myproc()->pagetable, dst, src, len);
+  } else {
+    memmove((char *)dst, src, len);
+    return 0;
+  }
+}
+
+// Copy from either a user address, or kernel address,
+// depending on usr_src.
+// Returns 0 on success, -1 on error.
+int
+either_copyin(void *dst, int user_src, uint64 src, uint64 len)
+{
+  struct proc *p = myproc();
+  if(user_src){
+    return copyin(p->pagetable, dst, src, len);
+  } else {
+    memmove(dst, (char*)src, len);
+    return 0;
+  }
+}
+
+// Print a process listing to console.  For debugging.
+// Runs when user types ^P on console.
+// No lock to avoid wedging a stuck machine further.
+void
+procdump(void)
+{
+  static char *states[] = {
+  [UNUSED]    "unused",
+  [SLEEPING]  "sleep ",
+  [RUNNABLE]  "runble",
+  [RUNNING]   "run   ",
+  [ZOMBIE]    "zombie"
+  };
+  struct proc *p;
+  char *state;
+
+  printf("\nPID\tSTATE\tNAME\tMEM\n");
+  for(p = proc; p < &proc[NPROC]; p++){
+    if(p->state == UNUSED)
+      continue;
+    if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
+      state = states[p->state];
+    else
+      state = "???";
+    printf("%d\t%s\t%s\t%d", p->pid, state, p->name, p->sz);
+    printf("\n");
+  }
+}
+
+uint64
+procnum(void)
+{
+  int num = 0;
+  struct proc *p;
+
+  for (p = proc; p < &proc[NPROC]; p++) {
+    if (p->state != UNUSED) {
+      num++;
+    }
+  }
+
+  return num;
+}
+struct mem_seg* intert_mem_seg(uint64 start,long len){
+  struct proc *p=myproc();
+  start-=len;
+  struct mem_seg* new=0;
+  for(struct mem_seg* temp=p->seg;temp!=p->seg->prev;temp=temp->next){
+    if(temp->type==0){
+      temp->type=1;
+      temp->start=start;
+      temp->len=len;
+      return temp;
+    }else if(temp->start>start){
+      new=p->seg->prev;
+      new->prev->next=new->next;
+      new->next->prev=new->prev;
+      new->prev=temp->prev;
+      new->next=temp;
+      temp->prev->next=new;
+      temp->prev=new;
+
+      new->type=1;
+      new->start=start;
+      new->len=len;
+      return new;
+    }
+  }
+  return 0;
+}
+struct mem_seg* alloc_v_space(long len){
+  len = PGROUNDUP(len);
+  struct proc *p=myproc();
+  for(struct free_mem_seg* temp=p->free_seg;temp!=p->free_seg->prev;temp=temp->next){
+    if(temp==0){
+      printf("map link broken");
+    }
+    if(temp->type!=0){
+      if(len<=temp->len){
+        // struct free_mem_seg* new=p->free_seg->prev;
+        // new->prev->next=new->next;
+        // new->next->prev=new->prev;
+        temp->len-=len;
+        temp->start+=len;
+        if(!temp->len){
+          temp->type=0;
+          if(temp==p->free_seg){
+            p->free_seg=temp->next;
+          }
+          else{
+            temp->prev->next=temp->next;
+            temp->next->prev=temp->prev;
+
+            p->free_seg->prev->next=temp;
+            temp->prev=p->free_seg->prev;
+
+            p->free_seg->prev=temp;
+            temp->next=p->free_seg;
+          }
+        }
+        //printf("temp->start:%p         len:%p\n",temp->start,len);
+        return intert_mem_seg(temp->start,len);
+      }
+    }
+  }
+  return 0;
+}
+
+uint64 do_mmap(uint64 start, long len, int prot, int flags, int fd, long off){
+  if(len <= 0) return -1;
+  struct proc *p = myproc();
+  if(start == 0){
+    start = p->mmap_size + VMMAP_BASE;
+  }else{
+    return -1;
+  }
+  len = PGROUNDUP(len);
+  if(start + len >= VMMAP_TOP){
+    return -1;
+  }
+  if(apply_bvmem(start, len, PTE_W|PTE_R)<0){
+    return -1;
+  }
+  p->mmap_size += len;
+  return start;
+  // if(len <= 0) return start;
+  // struct mem_seg* new=0;
+  // struct proc *p = myproc();
+  // if(start == 0){
+  //   new = alloc_v_space(len);
+  //   if(!new){
+  //     return -1;
+  //   }
+  //   else{
+  //     start=new->start;
+  //   }
+  // }
+  // if(fd>=0&&fd<NOFILE){
+  //   if(p->ofile[fd]!=0){
+  //     new->fd=p->ofile[fd];
+  //     new->off=off;
+  //   }
+  // }
+  // new->real_len=len;
+  // new->type=flags;
+  // apply_bvmem(start, len, PTE_R|PTE_W);
+  // return start;
+  
+//   __DEBUG("%p",myproc()->rlim[RLIMIT_AS].rlim_max);
+//   __DEBUG("%p",myproc()->rlim[RLIMIT_STACK].rlim_max);
+//   __DEBUG("%p",myproc()->rlim[RLIMIT_FSIZE].rlim_max);
+//   __DEBUG("%p",myproc()->rlim[RLIMIT_DATA].rlim_max);
+//   __DEBUG("len = %p",len);
+//   // if(len > myproc()->rlim[RLIMIT_FSIZE].rlim_max - myproc()->rlim[RLIMIT_FSIZE].rlim_cur){
+//   //   len = myproc()->rlim[RLIMIT_FSIZE].rlim_max - myproc()->rlim[RLIMIT_FSIZE].rlim_cur;
+//   // }
+//   if(len == 0){
+//     myproc()->mfile.baseaddr = start;
+//     myproc()->mfile.len += 0;
+//     __DEBUG("strat = %p",start);
+//     return start;
+//   }
+
+//   if(len==0){
+//     len=PGSIZE;
+//   }
+//   else{
+//     len=PGROUNDUP(len);
+//   }
+//   if(len > PGSIZE) len = PGSIZE;
+//   struct dirent *mep;
+//   struct file *file=0;
+//   uint64 start_address=start;
+//   struct proc *p=myproc();
+//   __DEBUG("p->sz = %p, len = %p",p->sz,len);
+//   // uint64 old=p->sz;
+//   __DEBUG("pid = %d",p->pid);
+//   if(p->mfile.valid==0){
+//     start_address=alloc_v_space(len+p->mfile.len); //如果start为0系统分配一个合适大小的虚拟地址
+//     __DEBUG("start_address = %p",start_address);
+//   }else{
+//     start_address = p->mfile.baseaddr;
+//     p->sz += PGSIZE;
+//   }
+//   // if(p->mfile.valid==1){  //每个进程只能映射一个文件,当请求第二个时返回错误
+//   //   __ERROR("");
+//   //   return -1;
+//   // }
+//   // else{
+//   //   p->mfile.valid=1;
+//   // }
+//   // if(start_address<old){   //判断是否越界
+//   //   __ERROR("2\n");
+//   //   return -1;
+//   // }
+//   if(fd==-1&&(flags&MAP_ANONYMOUS)){   //匿名映射
+//     if(flags & MAP_SHARED){      //对flag的判断
+//       __DEBUG("MAP_ANONYMOUS----------mmap------------SHARED");
+      
+//     }
+//     else if(flags & MAP_PRIVATE){
+//       __DEBUG("MAP_ANONYMOUS-----------mmap------------PRIVATE");
+//     }
+//     else{
+//       __ERROR("");
+//       return -1;
+//     }
+//     goto start_map;
+//   }
+//   //printf("%d\n",fd);
+//   file = p->ofile[fd];
+//   if(file==0||file->ep==0){
+//     __ERROR("3\n");
+//     return -1;
+//   }
+//   if(off>file->ep->file_size){//判断是否越界
+//     __ERROR("4\n");
+//     return -1;
+//   }
+//   acquire(&file->lock);        //对file结构体的操作需要锁(原来并没有锁,为了满足原子操作新加的)
+//   if(flags & MAP_SHARED){      //对flag的判断
+//     // __DEBUG("mmap------------SHARED");
+//     if(file->map_pid<=0){
+//       file->map_pid=0;
+//     }
+//     else if(file->map_pid>0){
+//       release(&file->lock);
+//       // __DEBUG("it has been privately shared!");
+//       __ERROR("");
+//       return -1;
+//     }
+//   }
+//   else if(flags & MAP_PRIVATE){
+//     // __DEBUG("mmap------------PRIVATE");
+//     if(file->map_pid<=0){
+//       file->map_pid=p->pid;
+//     }
+//     else if(file->map_pid>0){
+//       release(&file->lock);
+//       // __DEBUG("it has been privately shared!");
+//       __ERROR("");
+//       return -1;
+//     }
+//   }
+//   else{
+//     release(&file->lock);
+//     __ERROR("");
+//     return -1;
+//   }
+//   release(&file->lock);
+// start_map:
+//   mep=file!=0?file->ep:0;
+//   if(start_map(start_address,len,prot, mep,off)==-1){ //开始映射
+//     panic("map error\n");
+//     return -1;
+//   }
+
+//  // printf("%s\n",(char*)start_address);
+//   if(p->mfile.valid == 0)
+//     p->mfile.baseaddr=start_address;
+//   if(len > PGSIZE) len = PGSIZE;
+//   p->mfile.len+=PGROUNDUP(len);
+//   p->mfile.valid = 1;
+//   p->mfile.mfile=file;
+//   p->mfile.off=off;
+//   __DEBUG("start_address = %p",start_address);
+//   return start_address;
+}
+int sort_free_link(uint64 start,long len,struct proc *p){
+  for(struct free_mem_seg* temp=p->free_seg;temp!=p->free_seg->prev;temp=temp->next){
+    if(temp->type!=0){
+      if(start<temp->start){
+        if(start+len==temp->start){
+          temp->start=start;
+          temp->len+=len;
+          if(temp->prev->type!=0){
+            if(temp->prev->start+temp->prev->len==start){
+              struct free_mem_seg*temp2=temp->prev;
+              if(temp2==p->free_seg){
+                p->free_seg=temp2->next;
+              }
+              else{
+                temp2->prev->next=temp2->next;
+                temp2->next->prev=temp2->prev;
+
+                p->free_seg->prev->next=temp2;
+                temp2->prev=p->free_seg->prev;
+
+                p->free_seg->prev=temp2;
+                temp2->next=p->free_seg;
+              }
+            }
+          }
+          return 1;
+        }
+
+        if(temp->prev->type!=0){
+          if(temp->prev->start+temp->prev->len==start){
+            temp->prev->start=start;
+            temp->len+=len;
+            return 1;
+          }
+          else{
+            struct free_mem_seg* temp2=p->free_seg->prev;
+            p->free_seg->prev=temp2->prev;
+            temp2->prev->next=p->free_seg;
+            
+            temp->next->prev=temp2;
+            temp2->next=temp->next;
+            temp->next=temp2;
+            temp2->prev=temp;
+
+            temp2->len=len;
+            temp2->type=1;
+            temp2->start=start;
+            return 1;
+          }
+        }
+        else{
+          temp->prev->type=1;
+          temp->prev->start=start;
+          temp->prev->len=len;
+          p->free_seg=temp->prev;
+          return 1;
+        }
+      }
+    }
+  }
+  return 0;
+}
+int munmap_link(uint64 start,long len,struct proc *p){
+  for(struct mem_seg* temp=p->seg;temp!=p->seg->prev;temp=temp->next){
+    if(temp->type!=0){
+      if(start>=temp->start&&start<temp->start+temp->len){
+        uint64 mmap_edge=temp->start+start+temp->len;
+        len=PGROUNDUP(len);
+        if(start+len>mmap_edge){
+          len=mmap_edge-start;
+        }
+        if(start-temp->start){
+         // __DEBUG("lrregular munmap!");
+          if(mmap_edge-(start+len)){
+            temp->len=start-temp->start;
+            struct mem_seg* temp2=p->seg->prev;
+            p->seg->prev=temp2->prev;
+            temp2->prev->next=p->seg;
+
+            temp->next->prev=temp2;
+            temp2->next=temp->next;
+            temp->next=temp2;
+            temp2->prev=temp;
+
+            temp2->fd=temp->fd;
+            temp2->len=mmap_edge-(start+len);
+            temp2->type=1;
+            temp2->parent=temp->parent;
+            temp2->start=start+len;
+          }else{
+            temp->len=mmap_edge-start;
+          }
+        }else{
+          if(mmap_edge-(start+len)){
+            //__DEBUG("lrregular munmap!");
+            temp->start=start+len;
+
+          }else{
+           // __DEBUG("munmap of rules!");
+            temp->type=0;
+            if(p->seg!=temp){
+              temp->prev->next=temp->next;
+              temp->next->prev=temp->prev;
+              p->seg->prev->next=temp;
+              temp->prev=p->seg->prev;
+              p->seg->prev=temp;
+              temp->next=p->seg;
+            }
+          }
+        }
+        return sort_free_link(start,len,p);
+      }
+    }
+  }
+  return 0;
+}
+uint64 do_munmap(uint64 start,long len){
+  struct proc *p = myproc();
+  if(len == 0) return 0;
+  if(len < 0) return -1;
+  if(start >= p->mmap_size + VMMAP_BASE){
+    return -1;
+  }
+  if(start < VMMAP_BASE){
+    return -1;
+  }
+  len = PGROUNDUP(len);
+  vmunmap(myproc()->pagetable, start, len / PGSIZE, 1);
+  return 0;
+  // if(start%PGSIZE){
+  //   return -1;
+  // }
+  // if(len==0){
+  //   return 0;
+  // }
+  // struct proc *p=myproc();
+  // if(!munmap_link(start,len,p)){
+  //   return -1;
+  // }
+  // end_map(start,len);
+  // if((start % PGSIZE) != 0){
+  //   panic("in do_munmap :start must be page aligned");
+  // }
+  // if(len == 0) return 0;
+  // struct proc* p=myproc();
+  // if(p->mfile.valid!=1){
+  //   __ERROR("-3\n");
+  //   return -1;
+  // }
+  // if((start<p->mfile.baseaddr||start>p->mfile.baseaddr+p->mfile.len)){
+  //   __ERROR("-1\n");
+  //   return -1;
+  // } 
+  // if(start+(int)len>p->mfile.baseaddr+p->mfile.len){
+  //   len=p->mfile.len;
+  // }
+  // if(p->mfile.mfile && !syn_disk(start,len)){
+  //   __ERROR("-2\n");
+  //   end_map(start,len);
+  //   return -1;
+  // }
+  // end_map(start,len);  //取消映射
+  // p->mfile.len -= PGROUNDUP(len);
+  // acquire(&p->lock);
+  // p->sz=PGROUNDUP(p->sz)-PGROUNDUP(len);
+  // release(&p->lock);
+  // p->mfile.valid=0;
+  // return 0;
+}
+
+uint64 do_msync(uint64 start,long len,int flags){
+  struct proc *p=myproc();
+  if(start+len>p->sz){
+    return -1;
+  }
+
+  return 0;
+}
+
+int do_kill(int pid, int sig){
+  sendsignal(pid, sig);
+  return 0;
+}
+
+int do_set_tid_address(int *tidptr){
+  struct proc *p=myproc();
+  if(tidptr!=0){
+    p->clone_arg.child_tid=*tidptr;
+  }
+  return p->pid;
+}
+
+void do_exit_group(int status){
+  exit(status);
+}
+
+int do_gettid(void){
+  struct proc *tid;
+  struct proc *p=myproc();
+  for(tid = proc; tid < &proc[NPROC]; tid++){
+    acquire(&tid->lock);
+    if(tid->parent== p){
+      return tid->pid;
+    }
+    release(&tid->lock);
+  }
+  return -1;
+}
+
+struct proc* findproc(int pid){
+  struct proc* p;
+  for(p = proc; p < &proc[NPROC]; p++) {
+    acquire(&p->lock);
+    if(p->pid == pid) {
+      release(&p->lock);
+      return p;
+    } else {
+      release(&p->lock);
+    }
+  }
+  
+  return NULL;
+}
+
+int futex_wait(int *uaddr,int val,struct timespec *timeout,int val3){
+  struct proc *p=myproc();
+  if(timeout!=0){
+
+  }
+  else{
+    
+    if(*uaddr==val){
+      TimeVal tv;
+      tv.sec = 1;
+      tv.usec = 0;
+      if(p->killed||gain_sleep(&tv)==0){
+        return -1;
+      }
+      acquire(&p->lock);  
+      p->state = SLEEPING;
+      __DEBUG("pid %d sleep",p->pid);
+      sched();
+      release(&p->lock);
+      return 0;
+      // acquire(&p->lock);
+      // sleep(uaddr,&p->lock);
+      // release(&p->lock);
+    }
+  }
+  return 0;
+}
+
+
+int do_futex(int *uaddr,int op,int val,struct timespec *timeout,int *uaddr2,int val3){
+  // __DEBUG("---uaddr:%d----op:%d----val:%d-----val3:%d\n",*uaddr,op,val,val3);
+  int cmd = op & FUTEX_CMD_MASK;
+	switch (cmd) {
+	case FUTEX_WAIT:
+    // __DEBUG("-------wait");
+		return futex_wait(uaddr, val, timeout, val3);
+  case FUTEX_WAKE:		
+    break;
+  case FUTEX_FD:		
+    break;
+  case FUTEX_REQUEUE:
+    break;
+  case FUTEX_CMP_REQUEUE:
+    break;	
+  case FUTEX_WAKE_OP:
+    // __DEBUG("wake");
+    wakeup(uaddr);
+    return 0;		
+  case FUTEX_LOCK_PI:
+    // __DEBUG("wait");
+    break;		
+  case FUTEX_UNLOCK_PI:
+    __DEBUG("wake");
+    break;		
+  case FUTEX_TRYLOCK_PI:
+    break;	
+  case FUTEX_WAIT_BITSET:
+    break;
+    // __DEBUG("wake");
+    // wakeup(uaddr);
+    return 0;
+  default:
+    break;
+  
+  }
+  return 0;
+}
\ No newline at end of file
diff --git a/kernel/rbtree.c b/kernel/rbtree.c
new file mode 100644
index 0000000000000000000000000000000000000000..ac91d994036254069e89a1def3b798bd4d794f00
--- /dev/null
+++ b/kernel/rbtree.c
@@ -0,0 +1,380 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea@suse.de>
+  (C) 2002  David Woodhouse <dwmw2@infradead.org>
+  
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  linux/lib/rbtree.c
+*/
+ 
+#include <include/rbtree.h>
+ 
+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *right = node->rb_right;
+	struct rb_node *parent = rb_parent(node);
+ 
+	if ((node->rb_right = right->rb_left))
+		rb_set_parent(right->rb_left, node);
+	right->rb_left = node;
+ 
+	rb_set_parent(right, parent);
+ 
+	if (parent)
+	{
+		if (node == parent->rb_left)
+			parent->rb_left = right;
+		else
+			parent->rb_right = right;
+	}
+	else
+		root->rb_node = right;
+	rb_set_parent(node, right);
+}
+ 
+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *left = node->rb_left;
+	struct rb_node *parent = rb_parent(node);
+ 
+	if ((node->rb_left = left->rb_right))
+		rb_set_parent(left->rb_right, node);
+	left->rb_right = node;
+ 
+	rb_set_parent(left, parent);
+ 
+	if (parent)
+	{
+		if (node == parent->rb_right)
+			parent->rb_right = left;
+		else
+			parent->rb_left = left;
+	}
+	else
+		root->rb_node = left;
+	rb_set_parent(node, left);
+}
+ 
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *parent, *gparent;
+ 
+	while ((parent = rb_parent(node)) && rb_is_red(parent))
+	{
+		gparent = rb_parent(parent);
+ 
+		if (parent == gparent->rb_left)
+		{
+			{
+				register struct rb_node *uncle = gparent->rb_right;
+				if (uncle && rb_is_red(uncle))
+				{
+					rb_set_black(uncle);
+					rb_set_black(parent);
+					rb_set_red(gparent);
+					node = gparent;
+					continue;
+				}
+			}
+ 
+			if (parent->rb_right == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_left(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+ 
+			rb_set_black(parent);
+			rb_set_red(gparent);
+			__rb_rotate_right(gparent, root);
+		} else {
+			{
+				register struct rb_node *uncle = gparent->rb_left;
+				if (uncle && rb_is_red(uncle))
+				{
+					rb_set_black(uncle);
+					rb_set_black(parent);
+					rb_set_red(gparent);
+					node = gparent;
+					continue;
+				}
+			}
+ 
+			if (parent->rb_left == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_right(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+ 
+			rb_set_black(parent);
+			rb_set_red(gparent);
+			__rb_rotate_left(gparent, root);
+		}
+	}
+ 
+	rb_set_black(root->rb_node);
+}
+ 
+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
+			     struct rb_root *root)
+{
+	struct rb_node *other;
+ 
+	while ((!node || rb_is_black(node)) && node != root->rb_node)
+	{
+		if (parent->rb_left == node)
+		{
+			other = parent->rb_right;
+			if (rb_is_red(other))
+			{
+				rb_set_black(other);
+				rb_set_red(parent);
+				__rb_rotate_left(parent, root);
+				other = parent->rb_right;
+			}
+			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+			    (!other->rb_right || rb_is_black(other->rb_right)))
+			{
+				rb_set_red(other);
+				node = parent;
+				parent = rb_parent(node);
+			}
+			else
+			{
+				if (!other->rb_right || rb_is_black(other->rb_right))
+				{
+					rb_set_black(other->rb_left);
+					rb_set_red(other);
+					__rb_rotate_right(other, root);
+					other = parent->rb_right;
+				}
+				rb_set_color(other, rb_color(parent));
+				rb_set_black(parent);
+				rb_set_black(other->rb_right);
+				__rb_rotate_left(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+		else
+		{
+			other = parent->rb_left;
+			if (rb_is_red(other))
+			{
+				rb_set_black(other);
+				rb_set_red(parent);
+				__rb_rotate_right(parent, root);
+				other = parent->rb_left;
+			}
+			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+			    (!other->rb_right || rb_is_black(other->rb_right)))
+			{
+				rb_set_red(other);
+				node = parent;
+				parent = rb_parent(node);
+			}
+			else
+			{
+				if (!other->rb_left || rb_is_black(other->rb_left))
+				{
+					rb_set_black(other->rb_right);
+					rb_set_red(other);
+					__rb_rotate_left(other, root);
+					other = parent->rb_left;
+				}
+				rb_set_color(other, rb_color(parent));
+				rb_set_black(parent);
+				rb_set_black(other->rb_left);
+				__rb_rotate_right(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+	}
+	if (node)
+		rb_set_black(node);
+}
+ 
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *child, *parent;
+	int color;
+ 
+	if (!node->rb_left)
+		child = node->rb_right;
+	else if (!node->rb_right)
+		child = node->rb_left;
+	else
+	{
+		struct rb_node *old = node, *left;
+ 
+		node = node->rb_right;
+		while ((left = node->rb_left) != NULL)
+			node = left;
+ 
+		if (rb_parent(old)) {
+			if (rb_parent(old)->rb_left == old)
+				rb_parent(old)->rb_left = node;
+			else
+				rb_parent(old)->rb_right = node;
+		} else
+			root->rb_node = node;
+ 
+		child = node->rb_right;
+		parent = rb_parent(node);
+		color = rb_color(node);
+ 
+		if (parent == old) {
+			parent = node;
+		} else {
+			if (child)
+				rb_set_parent(child, parent);
+			parent->rb_left = child;
+ 
+			node->rb_right = old->rb_right;
+			rb_set_parent(old->rb_right, node);
+		}
+ 
+		node->rb_parent_color = old->rb_parent_color;
+		node->rb_left = old->rb_left;
+		rb_set_parent(old->rb_left, node);
+ 
+		goto color;
+	}
+ 
+	parent = rb_parent(node);
+	color = rb_color(node);
+ 
+	if (child)
+		rb_set_parent(child, parent);
+	if (parent)
+	{
+		if (parent->rb_left == node)
+			parent->rb_left = child;
+		else
+			parent->rb_right = child;
+	}
+	else
+		root->rb_node = child;
+ 
+ color:
+	if (color == RB_BLACK)
+		__rb_erase_color(child, parent, root);
+}
+ 
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(const struct rb_root *root)
+{
+	struct rb_node	*n;
+ 
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_left)
+		n = n->rb_left;
+	return n;
+}
+ 
+struct rb_node *rb_last(const struct rb_root *root)
+{
+	struct rb_node	*n;
+ 
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_right)
+		n = n->rb_right;
+	return n;
+}
+ 
+struct rb_node *rb_next(const struct rb_node *node)
+{
+	struct rb_node *parent;
+ 
+	if (rb_parent(node) == node)
+		return NULL;
+ 
+	/* If we have a right-hand child, go down and then left as far
+	   as we can. */
+	if (node->rb_right) {
+		node = node->rb_right; 
+		while (node->rb_left)
+			node=node->rb_left;
+		return (struct rb_node *)node;
+	}
+ 
+	/* No right-hand children.  Everything down and left is
+	   smaller than us, so any 'next' node must be in the general
+	   direction of our parent. Go up the tree; any time the
+	   ancestor is a right-hand child of its parent, keep going
+	   up. First time it's a left-hand child of its parent, said
+	   parent is our 'next' node. */
+	while ((parent = rb_parent(node)) && node == parent->rb_right)
+		node = parent;
+ 
+	return parent;
+}
+ 
+struct rb_node *rb_prev(const struct rb_node *node)
+{
+	struct rb_node *parent;
+ 
+	if (rb_parent(node) == node)
+		return NULL;
+ 
+	/* If we have a left-hand child, go down and then right as far
+	   as we can. */
+	if (node->rb_left) {
+		node = node->rb_left; 
+		while (node->rb_right)
+			node=node->rb_right;
+		return (struct rb_node *)node;
+	}
+ 
+	/* No left-hand children. Go up till we find an ancestor which
+	   is a right-hand child of its parent */
+	while ((parent = rb_parent(node)) && node == parent->rb_left)
+		node = parent;
+ 
+	return parent;
+}
+ 
+void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+		     struct rb_root *root)
+{
+	struct rb_node *parent = rb_parent(victim);
+ 
+	/* Set the surrounding nodes to point to the replacement */
+	if (parent) {
+		if (victim == parent->rb_left)
+			parent->rb_left = new;
+		else
+			parent->rb_right = new;
+	} else {
+		root->rb_node = new;
+	}
+	if (victim->rb_left)
+		rb_set_parent(victim->rb_left, new);
+	if (victim->rb_right)
+		rb_set_parent(victim->rb_right, new);
+ 
+	/* Copy the pointers/colour from the victim to the replacement */
+	*new = *victim;
+}
\ No newline at end of file
diff --git a/kernel/sdcard.c b/kernel/sdcard.c
new file mode 100644
index 0000000000000000000000000000000000000000..e1beb38ec95c55628076957780d147d2c466d689
--- /dev/null
+++ b/kernel/sdcard.c
@@ -0,0 +1,475 @@
+#include "include/printf.h"
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/gpiohs.h"
+#include "include/buf.h"
+#include "include/spinlock.h"
+
+#include "include/dmac.h"
+#include "include/spi.h"
+#include "include/sdcard.h"
+
+void SD_CS_HIGH(void) {
+    gpiohs_set_pin(7, GPIO_PV_HIGH);
+}
+
+void SD_CS_LOW(void) {
+    gpiohs_set_pin(7, GPIO_PV_LOW);
+}
+
+void SD_HIGH_SPEED_ENABLE(void) {
+    // spi_set_clk_rate(SPI_DEVICE_0, 10000000);
+}
+
+static void sd_lowlevel_init(uint8 spi_index) {
+    gpiohs_set_drive_mode(7, GPIO_DM_OUTPUT);
+    // spi_set_clk_rate(SPI_DEVICE_0, 200000);     /*set clk rate*/
+}
+
+static void sd_write_data(uint8 const *data_buff, uint32 length) {
+    spi_init(SPI_DEVICE_0, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);
+    spi_send_data_standard(SPI_DEVICE_0, SPI_CHIP_SELECT_3, NULL, 0, data_buff, length);
+}
+
+static void sd_read_data(uint8 *data_buff, uint32 length) {
+    spi_init(SPI_DEVICE_0, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);
+    spi_receive_data_standard(SPI_DEVICE_0, SPI_CHIP_SELECT_3, NULL, 0, data_buff, length);
+}
+
+static void sd_write_data_dma(uint8 const *data_buff, uint32 length) {
+    spi_init(SPI_DEVICE_0, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);
+	spi_send_data_standard_dma(DMAC_CHANNEL0, SPI_DEVICE_0, SPI_CHIP_SELECT_3, NULL, 0, data_buff, length);
+}
+
+static void sd_read_data_dma(uint8 *data_buff, uint32 length) {
+    spi_init(SPI_DEVICE_0, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);
+	spi_receive_data_standard_dma(-1, DMAC_CHANNEL0, SPI_DEVICE_0, SPI_CHIP_SELECT_3, NULL, 0, data_buff, length);
+}
+
+/*
+ * @brief  Send 5 bytes command to the SD card.
+ * @param  Cmd: The user expected command to send to SD card.
+ * @param  Arg: The command argument.
+ * @param  Crc: The CRC.
+ * @retval None
+ */
+static void sd_send_cmd(uint8 cmd, uint32 arg, uint8 crc) {
+	uint8 frame[6];
+	frame[0] = (cmd | 0x40);
+	frame[1] = (uint8)(arg >> 24);
+	frame[2] = (uint8)(arg >> 16);
+	frame[3] = (uint8)(arg >> 8);
+	frame[4] = (uint8)(arg);
+	frame[5] = (crc);
+	SD_CS_LOW();
+	sd_write_data(frame, 6);
+}
+
+static void sd_end_cmd(void) {
+	uint8 frame[1] = {0xFF};
+	/*!< SD chip select high */
+	SD_CS_HIGH();
+	/*!< Send the Cmd bytes */
+	sd_write_data(frame, 1);
+}
+
+/*
+ * Be noticed: all commands & responses below 
+ * 		are in SPI mode format. May differ from 
+ * 		what they are in SD mode. 
+ */
+
+#define SD_CMD0 	0 
+#define SD_CMD8 	8
+#define SD_CMD58 	58 		// READ_OCR
+#define SD_CMD55 	55 		// APP_CMD
+#define SD_ACMD41 	41 		// SD_SEND_OP_COND
+#define SD_CMD16 	16 		// SET_BLOCK_SIZE 
+#define SD_CMD17 	17 		// READ_SINGLE_BLOCK
+#define SD_CMD24 	24 		// WRITE_SINGLE_BLOCK 
+#define SD_CMD13 	13 		// SEND_STATUS
+
+/*
+ * Read sdcard response in R1 type. 
+ */
+static uint8 sd_get_response_R1(void) {
+	uint8 result;
+	uint16 timeout = 0xff;
+
+	while (timeout--) {
+		sd_read_data(&result, 1);
+		if (result != 0xff)
+			return result;
+	}
+
+	// timeout!
+	return 0xff;
+}
+
+/* 
+ * Read the rest of R3 response 
+ * Be noticed: frame should be at least 4-byte long 
+ */
+static void sd_get_response_R3_rest(uint8 *frame) {
+	sd_read_data(frame, 4);
+}
+
+/* 
+ * Read the rest of R7 response 
+ * Be noticed: frame should be at least 4-byte long 
+ */
+static void sd_get_response_R7_rest(uint8 *frame) {
+	sd_read_data(frame, 4);
+}
+
+static int switch_to_SPI_mode(void) {
+	int timeout = 0xff;
+
+	while (--timeout) {
+		sd_send_cmd(SD_CMD0, 0, 0x95);
+		uint64 result = sd_get_response_R1();
+		sd_end_cmd();
+
+		if (0x01 == result) break;
+	}
+	if (0 == timeout) {
+		printf("SD_CMD0 failed\n");
+		return 0xff;
+	}
+
+	return 0;
+}
+
+// verify supply voltage range 
+static int verify_operation_condition(void) {
+	uint64 result;
+
+	// Stores the response reversely. 
+	// That means 
+	// frame[2] - VCA 
+	// frame[3] - Check Pattern 
+	uint8 frame[4];
+
+	sd_send_cmd(SD_CMD8, 0x01aa, 0x87);
+	result = sd_get_response_R1();
+	sd_get_response_R7_rest(frame);
+	sd_end_cmd();
+
+	if (0x09 == result) {
+		printf("invalid CRC for CMD8\n");
+		return 0xff;
+	}
+	else if (0x01 == result && 0x01 == (frame[2] & 0x0f) && 0xaa == frame[3]) {
+		return 0x00;
+	}
+
+	printf("verify_operation_condition() fail!\n");
+	return 0xff;
+}
+
+// read OCR register to check if the voltage range is valid 
+// this step is not mandotary, but I advise to use it 
+static int read_OCR(void) {
+	uint64 result;
+	result = 0;
+	uint8 ocr[4];
+
+	int timeout;
+
+	timeout = 0xff;
+	while (--timeout) {
+		sd_send_cmd(SD_CMD58, 0, 0);
+		result = sd_get_response_R1();
+		sd_get_response_R3_rest(ocr);
+		sd_end_cmd();
+
+		if (
+			0x01 == result && // R1 response in idle status 
+			(ocr[1] & 0x1f) && (ocr[2] & 0x80) 	// voltage range valid 
+		) {
+			return 0;
+		}
+	}
+
+	// timeout!
+	printf("read_OCR() timeout!\n");
+	printf("result = %d\n", result);
+	return 0xff;
+}
+
+// send ACMD41 to tell sdcard to finish initializing 
+static int set_SDXC_capacity(void) {
+	uint8 result = 0xff;
+
+	int timeout = 0xfff;
+	while (--timeout) {
+		sd_send_cmd(SD_CMD55, 0, 0);
+		result = sd_get_response_R1();
+		sd_end_cmd();
+		if (0x01 != result) {
+			printf("SD_CMD55 fail! result = %d\n", result);
+			return 0xff;
+		}
+
+		sd_send_cmd(SD_ACMD41, 0x40000000, 0);
+		result = sd_get_response_R1();
+		sd_end_cmd();
+		if (0 == result) {
+			return 0;
+		}
+	}
+
+	// timeout! 
+	printf("set_SDXC_capacity() timeout!\n");
+	printf("result = %d\n", result);
+	return 0xff;
+}
+
+// Used to differ whether sdcard is SDSC type. 
+static int is_standard_sd = 0;
+
+// check OCR register to see the type of sdcard, 
+// thus determine whether block size is suitable to buffer size
+static int check_block_size(void) {
+	uint8 result = 0xff;
+	uint8 ocr[4];
+
+	int timeout = 0xff;
+	while (timeout --) {
+		sd_send_cmd(SD_CMD58, 0, 0);
+		result = sd_get_response_R1();
+		sd_get_response_R3_rest(ocr);
+		sd_end_cmd();
+
+		if (0 == result) {
+			if (ocr[0] & 0x40) {
+				printf("SDHC/SDXC detected\n");
+				if (512 != BSIZE) {
+					printf("BSIZE != 512\n");
+					return 0xff;
+				}
+
+				is_standard_sd = 0;
+			}
+			else {
+				printf("SDSC detected, setting block size\n");
+
+				// setting SD card block size to BSIZE 
+				int timeout = 0xff;
+				int result = 0xff;
+				while (--timeout) {
+					sd_send_cmd(SD_CMD16, BSIZE, 0);
+					result = sd_get_response_R1();
+					sd_end_cmd();
+
+					if (0 == result) break;
+				}
+				if (0 == timeout) {
+					printf("check_OCR(): fail to set block size");
+					return 0xff;
+				}
+
+				is_standard_sd = 1;
+			}
+
+			return 0;
+		}
+	}
+
+	// timeout! 
+	printf("check_OCR() timeout!\n");
+	printf("result = %d\n", result);
+	return 0xff;
+}
+
+/*
+ * @brief  Initializes the SD/SD communication.
+ * @param  None
+ * @retval The SD Response:
+ *         - 0xFF: Sequence failed
+ *         - 0: Sequence succeed
+ */
+static int sd_init(void) {
+	uint8 frame[10];
+
+	sd_lowlevel_init(0);
+	//SD_CS_HIGH();
+	SD_CS_LOW();
+
+	// send dummy bytes for 80 clock cycles 
+	for (int i = 0; i < 10; i ++) 
+		frame[i] = 0xff;
+	sd_write_data(frame, 10);
+
+	if (0 != switch_to_SPI_mode()) 
+		return 0xff;
+	if (0 != verify_operation_condition()) 
+		return 0xff;
+	if (0 != read_OCR()) 
+		return 0xff;
+	if (0 != set_SDXC_capacity()) 
+		return 0xff;
+	if (0 != check_block_size()) 
+		return 0xff;
+
+	return 0;
+}
+
+static struct sleeplock sdcard_lock;
+
+void sdcard_init(void) {
+	int result = sd_init();
+	initsleeplock(&sdcard_lock, "sdcard");
+
+	if (0 != result) {
+		panic("sdcard_init failed");
+	}
+	#ifdef DEBUG
+	printf("sdcard_init\n");
+	#endif
+}
+
+void sdcard_read_sector(uint8 *buf, int sectorno) {
+	uint8 result;
+	uint32 address;
+	uint8 dummy_crc[2];
+
+	#ifdef DEBUG
+	printf("sdcard_read_sector()\n");
+	#endif
+
+	if (is_standard_sd) {
+		address = sectorno << 9;
+	}
+	else {
+		address = sectorno;
+	}
+
+	// enter critical section!
+	acquiresleep(&sdcard_lock);
+
+	sd_send_cmd(SD_CMD17, address, 0);
+	result = sd_get_response_R1();
+
+	if (0 != result) {
+		releasesleep(&sdcard_lock);
+		panic("sdcard: fail to read");
+	}
+
+	int timeout = 0xffffff;
+	while (--timeout) {
+		sd_read_data(&result, 1);
+		if (0xfe == result) break;
+	}
+	if (0 == timeout) {
+		panic("sdcard: timeout waiting for reading");
+	}
+	sd_read_data_dma(buf, BSIZE);
+	sd_read_data(dummy_crc, 2);
+
+	sd_end_cmd();
+
+	releasesleep(&sdcard_lock);
+	// leave critical section!
+}
+
+void sdcard_write_sector(uint8 *buf, int sectorno) {
+	uint32 address;
+	static uint8 const START_BLOCK_TOKEN = 0xfe;
+	uint8 dummy_crc[2] = {0xff, 0xff};
+
+	#ifdef DEBUG
+	printf("sdcard_write_sector()\n");
+	#endif
+
+	if (is_standard_sd) {
+		address = sectorno << 9;
+	}
+	else {
+		address = sectorno;
+	}
+
+	// enter critical section!
+	acquiresleep(&sdcard_lock);
+
+	sd_send_cmd(SD_CMD24, address, 0);
+	if (0 != sd_get_response_R1()) {
+		releasesleep(&sdcard_lock);
+		panic("sdcard: fail to write");
+	}
+
+	// sending data to be written 
+	sd_write_data(&START_BLOCK_TOKEN, 1);
+	sd_write_data_dma(buf, BSIZE);
+	sd_write_data(dummy_crc, 2);
+
+	// waiting for sdcard to finish programming 
+	uint8 result;
+	int timeout = 0xfff;
+	while (--timeout) {
+		sd_read_data(&result, 1);
+		if (0x05 == (result & 0x1f)) {
+			break;
+		}
+	}
+	if (0 == timeout) {
+		releasesleep(&sdcard_lock);
+		panic("sdcard: invalid response token");
+	}
+	
+	timeout = 0xffffff;
+	while (--timeout) {
+		sd_read_data(&result, 1);
+		if (0 != result) break;
+	}
+	if (0 == timeout) {
+		releasesleep(&sdcard_lock);
+		panic("sdcard: timeout waiting for response");
+	}
+	sd_end_cmd();
+
+	// send SD_CMD13 to check if writing is correctly done 
+	uint8 error_code = 0xff;
+	sd_send_cmd(SD_CMD13, 0, 0);
+	result = sd_get_response_R1();
+	sd_read_data(&error_code, 1);
+	sd_end_cmd();
+	if (0 != result || 0 != error_code) {
+		releasesleep(&sdcard_lock);
+		printf("result: %x\n", result);
+		printf("error_code: %x\n", error_code);
+		panic("sdcard: an error occurs when writing");
+	}
+
+	releasesleep(&sdcard_lock);
+	// leave critical section!
+}
+
+// A simple test for sdcard read/write test 
+void test_sdcard(void) {
+	uint8 buf[BSIZE];
+
+	for (int sec = 0; sec < 5; sec ++) {
+		for (int i = 0; i < BSIZE; i ++) {
+			buf[i] = 0xaa;		// data to be written 
+		}
+
+		sdcard_write_sector(buf, sec);
+
+		for (int i = 0; i < BSIZE; i ++) {
+			buf[i] = 0xff;		// fill in junk
+		}
+
+		sdcard_read_sector(buf, sec);
+		for (int i = 0; i < BSIZE; i ++) {
+			if (0 == i % 16) {
+				printf("\n");
+			}
+
+			printf("%x ", buf[i]);
+		}
+		printf("\n");
+	}
+
+	while (1) ;
+}
diff --git a/kernel/signal.c b/kernel/signal.c
new file mode 100644
index 0000000000000000000000000000000000000000..5c0f77ae1f8ace99f697fd9288d022cacf43cc9a
--- /dev/null
+++ b/kernel/signal.c
@@ -0,0 +1,146 @@
+#include "include/signal.h"
+#include "include/proc.h"
+#include "include/string.h"
+#include "include/riscv.h"
+#include "include/printf.h"
+
+void sigadd(sigset_t *a, sigset_t *b)
+{
+    if(!b || !a) return;
+
+    for(int i = 0;i<SIGSETSIZE;i++){
+        a->__bits[i] = a->__bits[i] | b->__bits[i];
+    }
+}
+
+void sigsub(sigset_t *a, sigset_t *b)
+{
+    if(!a || !b) return;
+    
+    for(int i = 0;i<SIGSETSIZE;i++){
+        a->__bits[i] = a->__bits[i] & (~(b->__bits[i]));
+    }
+}
+
+int sigprocmask(int how, sigset_t *set)
+{
+    struct proc *p = myproc();
+    // __DEBUG("");
+	switch (how) {
+        case SIG_BLOCK:
+            sigadd(&p->mask, set);
+            break;
+        case SIG_UNBLOCK:
+            sigsub(&p->mask, set);
+            break;
+        case SIG_SETMASK:
+            for(int i = 0; i<SIGSETSIZE;i++){
+                p->mask.__bits[i] = set->__bits[i];
+            }
+            break;
+        default:
+            return -1;
+	}
+  
+	return 0;
+}
+
+int sigaction(int sig, struct sigaction *act){
+    struct proc *p = myproc();
+    if(sig < N_SIG && sig > 0){
+        p->act[sig] = (uint64)(act->sa_handler);
+        // __DEBUG("pid %d %d %p",p->pid,sig,p->act[sig]);
+        return 0;
+    }
+    else{
+        __ERROR("error,sig = %d",sig);
+        return -1;        
+    }
+}
+
+int sigfind(sigset_t *a, sigset_t *b){
+    if(!a || !b) {
+        return -1;
+    }
+    unsigned long mid = 0;
+    for(int i = 0;i < SIGSETSIZE;i++){
+        if((mid = a->__bits[i] & b->__bits[i])){
+            for(int j = 0;j < 8*sizeof(long);j++){
+                if(mid & (1 << j)){
+                    return i*64 + j + 1;
+                }
+            }
+        }
+    }
+    return -1;
+}
+
+
+void do_act(){
+    
+    struct proc *p = myproc();
+    sigset_t mid;
+    for(int i = 0;i < SIGSETSIZE;i++){
+        mid.__bits[i] = p->pending.__bits[i];
+    }
+    int signum = 0;
+    sigsub(&mid, &p->mask);
+    for(int i = 0;i < SIGSETSIZE;i++){
+        if(mid.__bits[i]){
+            for(int j = 0;j < 8*sizeof(long);j++){
+                if(mid.__bits[i] & (1 << j)){
+                    signum = i*64 + j + 1;
+                    sigreset(&p->pending, signum);
+                    goto foundsig;
+                }
+            }
+        }
+    }
+    return;
+    
+foundsig:
+    if(p->act[signum]){
+        __DEBUG("find signum %d handler %p",signum,p->act[signum]);
+        p->trapframe->ra = p->trapframe->epc;
+        p->trapframe->epc = p->act[signum];
+        return;
+    }else{
+        switch (signum)
+        {
+        case SIGKILL:
+            kill(p->pid);
+            break;
+        case SIGABRT:
+            printf("Aborted! (core dumped)\n");
+            kill(p->pid);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+int sendsignal(int pid, int signum){
+    struct proc* p = findproc(pid);
+    if(!p) return -1;
+    sigset(&p->pending, signum);
+    return 0;
+}
+
+int testsig(sigset_t *set, int signum){
+    int num = (signum - 1) / (sizeof(long) * 8);
+    int off = (signum - 1) % (sizeof(long) * 8);
+    return (set->__bits[num]) & (1 << off);
+}
+
+void sigreset(sigset_t *set, int signum){
+    int num = (signum - 1) / (sizeof(long) * 8);
+    int off = (signum - 1) % (sizeof(long) * 8);
+    set->__bits[num] = set->__bits[num] & (~(1<<off));
+}
+
+void sigset(sigset_t *set, int signum){
+    int num = (signum - 1) / (sizeof(long) * 8);
+    int off = (signum - 1) % (sizeof(long) * 8);
+    set->__bits[num] = set->__bits[num] | (1<<off);
+}
\ No newline at end of file
diff --git a/kernel/sleeplock.c b/kernel/sleeplock.c
new file mode 100644
index 0000000000000000000000000000000000000000..c68e0bb951dbafeeec0db85f6abac6bcb1fd39f9
--- /dev/null
+++ b/kernel/sleeplock.c
@@ -0,0 +1,52 @@
+// Sleeping locks
+
+
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/spinlock.h"
+#include "include/proc.h"
+#include "include/sleeplock.h"
+
+void
+initsleeplock(struct sleeplock *lk, char *name)
+{
+  initlock(&lk->lk, "sleep lock");
+  lk->name = name;
+  lk->locked = 0;
+  lk->pid = 0;
+}
+
+void
+acquiresleep(struct sleeplock *lk)
+{
+  acquire(&lk->lk);
+  while (lk->locked) {
+    sleep(lk, &lk->lk);
+  }
+  lk->locked = 1;
+  lk->pid = myproc()->pid;
+  release(&lk->lk);
+}
+
+void
+releasesleep(struct sleeplock *lk)
+{
+  acquire(&lk->lk);
+  lk->locked = 0;
+  lk->pid = 0;
+  wakeup(lk);
+  release(&lk->lk);
+}
+
+int
+holdingsleep(struct sleeplock *lk)
+{
+  int r;
+  
+  acquire(&lk->lk);
+  r = lk->locked && (lk->pid == myproc()->pid);
+  release(&lk->lk);
+  return r;
+}
diff --git a/kernel/spi.c b/kernel/spi.c
new file mode 100644
index 0000000000000000000000000000000000000000..3e52a4d3a3b57d3630c48eb0e6e471a7cd8f08b9
--- /dev/null
+++ b/kernel/spi.c
@@ -0,0 +1,550 @@
+// SPI Protocol Implementation
+
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/utils.h"
+#include "include/dmac.h"
+#include "include/spi.h"
+#include "include/sysctl.h"
+#include "include/kalloc.h"
+#include "include/string.h"
+
+volatile spi_t *const spi[4] =
+    {
+        (volatile spi_t *)SPI0_V,
+        (volatile spi_t *)SPI1_V,
+        (volatile spi_t *)SPI_SLAVE_V,
+        (volatile spi_t *)SPI2_V};
+
+void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,
+              uint64 data_bit_length, uint32 endian)
+{
+    // configASSERT(data_bit_length >= 4 && data_bit_length <= 32);
+    // configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
+    // spi_clk_init(spi_num);
+
+    // uint8 dfs_offset, frf_offset, work_mode_offset;
+    uint8 dfs_offset = 0;
+    uint8 frf_offset = 0;
+    uint8 work_mode_offset = 0;
+    switch(spi_num)
+    {
+        case 0:
+        case 1:
+            dfs_offset = 16;
+            frf_offset = 21;
+            work_mode_offset = 6;
+            break;
+        case 2:
+            // configASSERT(!"Spi Bus 2 Not Support!");
+            break;
+        case 3:
+        default:
+            dfs_offset = 0;
+            frf_offset = 22;
+            work_mode_offset = 8;
+            break;
+    }
+
+    switch(frame_format)
+    {
+        case SPI_FF_DUAL:
+            // configASSERT(data_bit_length % 2 == 0);
+            break;
+        case SPI_FF_QUAD:
+            // configASSERT(data_bit_length % 4 == 0);
+            break;
+        case SPI_FF_OCTAL:
+            // configASSERT(data_bit_length % 8 == 0);
+            break;
+        default:
+            break;
+    }
+    volatile spi_t *spi_adapter = spi[spi_num];
+    if(spi_adapter->baudr == 0)
+        spi_adapter->baudr = 0x14;
+    spi_adapter->imr = 0x00;
+    spi_adapter->dmacr = 0x00;
+    spi_adapter->dmatdlr = 0x10;
+    spi_adapter->dmardlr = 0x00;
+    spi_adapter->ser = 0x00;
+    spi_adapter->ssienr = 0x00;
+    spi_adapter->ctrlr0 = (work_mode << work_mode_offset) | (frame_format << frf_offset) | ((data_bit_length - 1) << dfs_offset);
+    spi_adapter->spi_ctrlr0 = 0;
+    spi_adapter->endian = endian;
+}
+
+
+static void spi_set_tmod(uint8 spi_num, uint32 tmod)
+{
+    // configASSERT(spi_num < SPI_DEVICE_MAX);
+    volatile spi_t *spi_handle = spi[spi_num];
+    uint8 tmod_offset = 0;
+    switch(spi_num)
+    {
+        case 0:
+        case 1:
+        case 2:
+            tmod_offset = 8;
+            break;
+        case 3:
+        default:
+            tmod_offset = 10;
+            break;
+    }
+    set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset);
+}
+
+static spi_transfer_width_t spi_get_frame_size(uint64 data_bit_length)
+{
+    if(data_bit_length < 8)
+        return SPI_TRANS_CHAR;
+    else if(data_bit_length < 16)
+        return SPI_TRANS_SHORT;
+    return SPI_TRANS_INT;
+}
+
+void spi_send_data_normal(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *tx_buff, uint64 tx_len)
+{
+    // configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
+
+    uint64 index, fifo_len;
+    spi_set_tmod(spi_num, SPI_TMOD_TRANS);
+
+    volatile spi_t *spi_handle = spi[spi_num];
+
+    // uint8 dfs_offset;
+    uint8 dfs_offset = 0;
+    switch(spi_num)
+    {
+        case 0:
+        case 1:
+            dfs_offset = 16;
+            break;
+        case 2:
+            // configASSERT(!"Spi Bus 2 Not Support!");
+            break;
+        case 3:
+        default:
+            dfs_offset = 0;
+            break;
+    }
+    uint32 data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F;
+    spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length);
+
+    uint8 v_misalign_flag = 0;
+    uint32 v_send_data;
+    if((uintptr_t)tx_buff % frame_width)
+        v_misalign_flag = 1;
+
+    spi_handle->ssienr = 0x01;
+    spi_handle->ser = 1U << chip_select;
+    uint32 i = 0;
+    while(tx_len)
+    {
+        fifo_len = 32 - spi_handle->txflr;
+        fifo_len = fifo_len < tx_len ? fifo_len : tx_len;
+        switch(frame_width)
+        {
+            case SPI_TRANS_INT:
+                fifo_len = fifo_len / 4 * 4;
+                if(v_misalign_flag)
+                {
+                    for(index = 0; index < fifo_len; index += 4)
+                    {
+                        // memcpy(&v_send_data, tx_buff + i, 4);
+                        memmove(&v_send_data, tx_buff + i, 4);
+                        spi_handle->dr[0] = v_send_data;
+                        i += 4;
+                    }
+                } else
+                {
+                    for(index = 0; index < fifo_len / 4; index++)
+                        spi_handle->dr[0] = ((uint32 *)tx_buff)[i++];
+                }
+                break;
+            case SPI_TRANS_SHORT:
+                fifo_len = fifo_len / 2 * 2;
+                if(v_misalign_flag)
+                {
+                    for(index = 0; index < fifo_len; index += 2)
+                    {
+                        // memcpy(&v_send_data, tx_buff + i, 2);
+                        memmove(&v_send_data, tx_buff + i, 2);
+                        spi_handle->dr[0] = v_send_data;
+                        i += 2;
+                    }
+                } else
+                {
+                    for(index = 0; index < fifo_len / 2; index++)
+                        spi_handle->dr[0] = ((uint16 *)tx_buff)[i++];
+                }
+                break;
+            default:
+                for(index = 0; index < fifo_len; index++)
+                    spi_handle->dr[0] = tx_buff[i++];
+                break;
+        }
+        tx_len -= fifo_len;
+    }
+    while((spi_handle->sr & 0x05) != 0x04)
+        ;
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+}
+
+void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
+                            uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len)
+{
+    // configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
+    // uint8 *v_buf = malloc(cmd_len + tx_len);
+    uint8 *v_buf = kalloc();
+    uint64 i;
+    for(i = 0; i < cmd_len; i++)
+        v_buf[i] = cmd_buff[i];
+    for(i = 0; i < tx_len; i++)
+        v_buf[cmd_len + i] = tx_buff[i];
+
+    spi_send_data_normal(spi_num, chip_select, v_buf, cmd_len + tx_len);
+    // free((void *)v_buf);
+    kfree((void *)v_buf);
+}
+
+void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
+                               uint64 cmd_len, uint8 *rx_buff, uint64 rx_len)
+{
+    // configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
+    uint64 index, fifo_len;
+    if(cmd_len == 0)
+        spi_set_tmod(spi_num, SPI_TMOD_RECV);
+    else
+        spi_set_tmod(spi_num, SPI_TMOD_EEROM);
+    volatile spi_t *spi_handle = spi[spi_num];
+
+    // uint8 dfs_offset;
+    uint8 dfs_offset = 0;
+    switch(spi_num)
+    {
+        case 0:
+        case 1:
+            dfs_offset = 16;
+            break;
+        case 2:
+            // configASSERT(!"Spi Bus 2 Not Support!");
+            break;
+        case 3:
+        default:
+            dfs_offset = 0;
+            break;
+    }
+    uint32 data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F;
+    spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length);
+
+    uint32 i = 0;
+    uint64 v_cmd_len = cmd_len / frame_width;
+    uint32 v_rx_len = rx_len / frame_width;
+
+    spi_handle->ctrlr1 = (uint32)(v_rx_len - 1);
+    spi_handle->ssienr = 0x01;
+
+    while(v_cmd_len)
+    {
+        fifo_len = 32 - spi_handle->txflr;
+        fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len;
+        switch(frame_width)
+        {
+            case SPI_TRANS_INT:
+                for(index = 0; index < fifo_len; index++)
+                    spi_handle->dr[0] = ((uint32 *)cmd_buff)[i++];
+                break;
+            case SPI_TRANS_SHORT:
+                for(index = 0; index < fifo_len; index++)
+                    spi_handle->dr[0] = ((uint16 *)cmd_buff)[i++];
+                break;
+            default:
+                for(index = 0; index < fifo_len; index++)
+                    spi_handle->dr[0] = cmd_buff[i++];
+                break;
+        }
+        spi_handle->ser = 1U << chip_select;
+        v_cmd_len -= fifo_len;
+    }
+
+    if(cmd_len == 0)
+    {
+        spi_handle->dr[0] = 0xffffffff;
+        spi_handle->ser = 1U << chip_select;
+    }
+
+    i = 0;
+    while(v_rx_len)
+    {
+        fifo_len = spi_handle->rxflr;
+        fifo_len = fifo_len < v_rx_len ? fifo_len : v_rx_len;
+        switch(frame_width)
+        {
+            case SPI_TRANS_INT:
+                for(index = 0; index < fifo_len; index++)
+                    ((uint32 *)rx_buff)[i++] = spi_handle->dr[0];
+                break;
+            case SPI_TRANS_SHORT:
+                for(index = 0; index < fifo_len; index++)
+                    ((uint16 *)rx_buff)[i++] = (uint16)spi_handle->dr[0];
+                break;
+            default:
+                for(index = 0; index < fifo_len; index++)
+                    rx_buff[i++] = (uint8)spi_handle->dr[0];
+                break;
+        }
+
+        v_rx_len -= fifo_len;
+    }
+
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+}
+
+static spi_frame_format_t spi_get_frame_format(spi_device_num_t spi_num)
+{
+    uint8 frf_offset = 0;
+    switch(spi_num)
+    {
+        case 0:
+        case 1:
+            frf_offset = 21;
+            break;
+        case 2:
+            // configASSERT(!"Spi Bus 2 Not Support!");
+            break;
+        case 3:
+        default:
+            frf_offset = 22;
+            break;
+    }
+    volatile spi_t *spi_adapter = spi[spi_num];
+    return ((spi_adapter->ctrlr0 >> frf_offset) & 0x3);
+}
+
+void spi_receive_data_normal_dma(dmac_channel_number_t dma_send_channel_num,
+                                 dmac_channel_number_t dma_receive_channel_num,
+                                 spi_device_num_t spi_num, spi_chip_select_t chip_select, const void *cmd_buff,
+                                 uint64 cmd_len, void *rx_buff, uint64 rx_len)
+{
+    // configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
+
+    if(cmd_len == 0)
+        spi_set_tmod(spi_num, SPI_TMOD_RECV);
+    else
+        spi_set_tmod(spi_num, SPI_TMOD_EEROM);
+
+    volatile spi_t *spi_handle = spi[spi_num];
+
+    spi_handle->ctrlr1 = (uint32)(rx_len - 1);
+    spi_handle->dmacr = 0x3;
+    spi_handle->ssienr = 0x01;
+    if(cmd_len)
+        sysctl_dma_select((sysctl_dma_channel_t)dma_send_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2);
+    sysctl_dma_select((sysctl_dma_channel_t)dma_receive_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2);
+
+    dmac_set_single_mode(dma_receive_channel_num, (void *)(&spi_handle->dr[0]), rx_buff, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
+                         DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, rx_len);
+    if(cmd_len)
+        dmac_set_single_mode(dma_send_channel_num, cmd_buff, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
+                             DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, cmd_len);
+    if(cmd_len == 0 && spi_get_frame_format(spi_num) == SPI_FF_STANDARD)
+        spi[spi_num]->dr[0] = 0xffffffff;
+    spi_handle->ser = 1U << chip_select;
+    if(cmd_len)
+        dmac_wait_done(dma_send_channel_num);
+    dmac_wait_done(dma_receive_channel_num);
+
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+}
+
+void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num,
+                              spi_chip_select_t chip_select,
+                              const void *tx_buff, uint64 tx_len, spi_transfer_width_t spi_transfer_width)
+{
+    // configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
+    spi_set_tmod(spi_num, SPI_TMOD_TRANS);
+    volatile spi_t *spi_handle = spi[spi_num];
+    uint32 *buf;
+    int i;
+    switch(spi_transfer_width)
+    {
+        case SPI_TRANS_SHORT:
+            // buf = malloc((tx_len) * sizeof(uint32));
+            buf = kalloc();
+            for(i = 0; i < tx_len; i++)
+                buf[i] = ((uint16 *)tx_buff)[i];
+            break;
+        case SPI_TRANS_INT:
+            buf = (uint32 *)tx_buff;
+            break;
+        case SPI_TRANS_CHAR:
+        default:
+            buf = kalloc();
+            for(i = 0; i < tx_len; i++)
+                buf[i] = ((uint8 *)tx_buff)[i];
+            break;
+    }
+    spi_handle->dmacr = 0x2; /*enable dma transmit*/
+    spi_handle->ssienr = 0x01;
+
+    sysctl_dma_select((sysctl_dma_channel_t)channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2);
+    dmac_set_single_mode(channel_num, buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
+                         DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, tx_len);
+    spi_handle->ser = 1U << chip_select;
+    dmac_wait_done(channel_num);
+    if(spi_transfer_width != SPI_TRANS_INT)
+        kfree((void *)buf);
+
+    while((spi_handle->sr & 0x05) != 0x04)
+        ;
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+}
+
+void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num,
+                                   dmac_channel_number_t dma_receive_channel_num,
+                                   spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
+                                   uint64 cmd_len, uint8 *rx_buff, uint64 rx_len)
+{
+    // configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
+    volatile spi_t *spi_handle = spi[spi_num];
+
+    uint8 dfs_offset = 0;
+    switch(spi_num)
+    {
+        case 0:
+        case 1:
+            dfs_offset = 16;
+            break;
+        case 2:
+            // configASSERT(!"Spi Bus 2 Not Support!");
+            break;
+        case 3:
+        default:
+            dfs_offset = 0;
+            break;
+    }
+    uint32 data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F;
+    spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length);
+
+    uint64 i;
+
+    uint32 *write_cmd;
+    uint32 *read_buf;
+    uint64 v_recv_len;
+    uint64 v_cmd_len;
+    switch(frame_width)
+    {
+        case SPI_TRANS_INT:
+            write_cmd = kalloc();
+            for(i = 0; i < cmd_len / 4; i++)
+                write_cmd[i] = ((uint32 *)cmd_buff)[i];
+            read_buf = &write_cmd[i];
+            v_recv_len = rx_len / 4;
+            v_cmd_len = cmd_len / 4;
+            break;
+        case SPI_TRANS_SHORT:
+            write_cmd = kalloc();
+            for(i = 0; i < cmd_len / 2; i++)
+                write_cmd[i] = ((uint16 *)cmd_buff)[i];
+            read_buf = &write_cmd[i];
+            v_recv_len = rx_len / 2;
+            v_cmd_len = cmd_len / 2;
+            break;
+        default:
+            write_cmd = kalloc();
+            for(i = 0; i < cmd_len; i++)
+                write_cmd[i] = cmd_buff[i];
+            read_buf = &write_cmd[i];
+            v_recv_len = rx_len;
+            v_cmd_len = cmd_len;
+            break;
+    }
+
+    spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, write_cmd, v_cmd_len, read_buf, v_recv_len);
+
+    switch(frame_width)
+    {
+        case SPI_TRANS_INT:
+            for(i = 0; i < v_recv_len; i++)
+                ((uint32 *)rx_buff)[i] = read_buf[i];
+            break;
+        case SPI_TRANS_SHORT:
+            for(i = 0; i < v_recv_len; i++)
+                ((uint16 *)rx_buff)[i] = read_buf[i];
+            break;
+        default:
+            for(i = 0; i < v_recv_len; i++)
+                rx_buff[i] = read_buf[i];
+            break;
+    }
+
+    kfree(write_cmd);
+}
+
+void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num,
+                                spi_chip_select_t chip_select,
+                                const uint8 *cmd_buff, uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len)
+{
+    // configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
+
+    volatile spi_t *spi_handle = spi[spi_num];
+
+    uint8 dfs_offset = 0;
+    switch(spi_num)
+    {
+        case 0:
+        case 1:
+            dfs_offset = 16;
+            break;
+        case 2:
+            // configASSERT(!"Spi Bus 2 Not Support!");
+            break;
+        case 3:
+        default:
+            dfs_offset = 0;
+            break;
+    }
+    uint32 data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F;
+    spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length);
+
+    uint32 *buf;
+    uint64 v_send_len;
+    int i;
+    switch(frame_width)
+    {
+        case SPI_TRANS_INT:
+            buf = kalloc();
+            for(i = 0; i < cmd_len / 4; i++)
+                buf[i] = ((uint32 *)cmd_buff)[i];
+            for(i = 0; i < tx_len / 4; i++)
+                buf[cmd_len / 4 + i] = ((uint32 *)tx_buff)[i];
+            v_send_len = (cmd_len + tx_len) / 4;
+            break;
+        case SPI_TRANS_SHORT:
+            buf = kalloc();
+            for(i = 0; i < cmd_len / 2; i++)
+                buf[i] = ((uint16 *)cmd_buff)[i];
+            for(i = 0; i < tx_len / 2; i++)
+                buf[cmd_len / 2 + i] = ((uint16 *)tx_buff)[i];
+            v_send_len = (cmd_len + tx_len) / 2;
+            break;
+        default:
+            buf = kalloc();
+            for(i = 0; i < cmd_len; i++)
+                buf[i] = cmd_buff[i];
+            for(i = 0; i < tx_len; i++)
+                buf[cmd_len + i] = tx_buff[i];
+            v_send_len = cmd_len + tx_len;
+            break;
+    }
+
+    spi_send_data_normal_dma(channel_num, spi_num, chip_select, buf, v_send_len, SPI_TRANS_INT);
+
+    kfree((void *)buf);
+}
\ No newline at end of file
diff --git a/kernel/spinlock.c b/kernel/spinlock.c
new file mode 100644
index 0000000000000000000000000000000000000000..029d0df2e917a2c4fa7c7e39bba3c405ac140411
--- /dev/null
+++ b/kernel/spinlock.c
@@ -0,0 +1,88 @@
+// Mutual exclusion spin locks.
+
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/spinlock.h"
+#include "include/riscv.h"
+#include "include/proc.h"
+#include "include/intr.h"
+#include "include/printf.h"
+
+void
+initlock(struct spinlock *lk, char *name)
+{
+  lk->name = name;
+  lk->locked = 0;
+  lk->cpu = 0;
+}
+
+// Acquire the lock.
+// Loops (spins) until the lock is acquired.
+void
+acquire(struct spinlock *lk)
+{
+  push_off(); // disable interrupts to avoid deadlock.
+  if(holding(lk)){
+    // int a = lk->locked;
+    // __ERROR("lk->name = %s, lk->locked = %d, lk->cpu = %p, mycpu() = %p",lk->name,a,lk->cpu,mycpu());
+    panic("acquire");
+  }
+  // On RISC-V, sync_lock_test_and_set turns into an atomic swap:
+  //   a5 = 1
+  //   s1 = &lk->locked
+  //   amoswap.w.aq a5, a5, (s1)
+  while(__sync_lock_test_and_set(&lk->locked, 1) != 0)
+    ;
+
+  // Tell the C compiler and the processor to not move loads or stores
+  // past this point, to ensure that the critical section's memory
+  // references happen strictly after the lock is acquired.
+  // On RISC-V, this emits a fence instruction.
+  __sync_synchronize();
+
+  // Record info about lock acquisition for holding() and debugging.
+  lk->cpu = mycpu();
+}
+
+// Release the lock.
+void
+release(struct spinlock *lk)
+{
+  if(!holding(lk)){
+    // __ERROR("lk->name = %s, lk->locked = %d, lk->cpu = %p, mycpu() = %p",lk->name,lk->locked,lk->cpu,mycpu());
+    panic("release");
+  }
+
+  lk->cpu = 0;
+
+  // Tell the C compiler and the CPU to not move loads or stores
+  // past this point, to ensure that all the stores in the critical
+  // section are visible to other CPUs before the lock is released,
+  // and that loads in the critical section occur strictly before
+  // the lock is released.
+  // On RISC-V, this emits a fence instruction.
+  __sync_synchronize();
+
+  // Release the lock, equivalent to lk->locked = 0.
+  // This code doesn't use a C assignment, since the C standard
+  // implies that an assignment might be implemented with
+  // multiple store instructions.
+  // On RISC-V, sync_lock_release turns into an atomic swap:
+  //   s1 = &lk->locked
+  //   amoswap.w zero, zero, (s1)
+  __sync_lock_release(&lk->locked);
+
+  pop_off();
+}
+
+// Check whether this cpu is holding the lock.
+// Interrupts must be off.
+int
+holding(struct spinlock *lk)
+{
+  int r;
+  r = (lk->locked && lk->cpu == mycpu());
+  return r;
+}
diff --git a/kernel/string.c b/kernel/string.c
new file mode 100644
index 0000000000000000000000000000000000000000..84224577d17a0d363342cb92b349019672b2c3ac
--- /dev/null
+++ b/kernel/string.c
@@ -0,0 +1,150 @@
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/printf.h"
+
+void*
+memset(void *dst, int c, uint n)
+{
+  char *cdst = (char *) dst;
+  int i;
+  for(i = 0; i < n; i++){
+    cdst[i] = c;
+  }
+  return dst;
+}
+
+int
+memcmp(const void *v1, const void *v2, uint n)
+{
+  const uchar *s1, *s2;
+
+  s1 = v1;
+  s2 = v2;
+  while(n-- > 0){
+    if(*s1 != *s2)
+      return *s1 - *s2;
+    s1++, s2++;
+  }
+
+  return 0;
+}
+
+void*
+memmove(void *dst, const void *src, uint n)
+{
+  const char *s;
+  char *d;
+
+  // if((uint64)dst <= 0x12ad8 && (uint64)dst+n > 0x12ad8){
+  //    __DEBUG("dst = %p",dst);
+  // }
+
+  s = src;
+  d = dst;
+  if(s < d && s + n > d){
+    s += n;
+    d += n;
+    __DEBUG("");
+    while(n-- > 0)
+      *--d = *--s;
+  } else
+    while(n-- > 0)
+      *d++ = *s++;
+
+  return dst;
+}
+
+// memcpy exists to placate GCC.  Use memmove.
+void*
+memcpy(void *dst, const void *src, uint n)
+{
+  return memmove(dst, src, n);
+}
+
+int
+strncmp(const char *p, const char *q, uint n)
+{
+  while(n > 0 && *p && *p == *q)
+    n--, p++, q++;
+  if(n == 0)
+    return 0;
+  return (uchar)*p - (uchar)*q;
+}
+
+char*
+strncpy(char *s, const char *t, int n)
+{
+  char *os;
+
+  os = s;
+  while(n-- > 0 && (*s++ = *t++) != 0)
+    ;
+  while(n-- > 0)
+    *s++ = 0;
+  return os;
+}
+
+// Like strncpy but guaranteed to NUL-terminate.
+char*
+safestrcpy(char *s, const char *t, int n)
+{
+  char *os;
+
+  os = s;
+  if(n <= 0)
+    return os;
+  while(--n > 0 && (*s++ = *t++) != 0)
+    ;
+  *s = 0;
+  return os;
+}
+
+int
+strlen(const char *s)
+{
+  int n;
+
+  for(n = 0; s[n]; n++)
+    ;
+  return n;
+}
+
+// convert uchar string into wide char string 
+void wnstr(wchar *dst, char const *src, int len) {
+  while (len -- && *src) {
+    *(uchar*)dst = *src++;
+    dst ++;
+  }
+
+  *dst = 0;
+}
+
+// convert wide char string into uchar string 
+void snstr(char *dst, wchar const *src, int len) {
+  while (len -- && *src) {
+    *dst++ = (uchar)(*src & 0xff);
+    src ++;
+  }
+  while(len-- > 0)
+    *dst++ = 0;
+}
+
+int wcsncmp(wchar const *s1, wchar const *s2, int len) {
+  int ret = 0;
+
+  while (len-- && *s1) {
+    ret = (int)(*s1++ - *s2++);
+    if (ret) break;
+  }
+
+  return ret;
+}
+
+char*
+strchr(const char *s, char c)
+{
+  for(; *s; s++)
+    if(*s == c)
+      return (char*)s;
+  return 0;
+}
\ No newline at end of file
diff --git a/kernel/swtch.S b/kernel/swtch.S
new file mode 100644
index 0000000000000000000000000000000000000000..8c947130a2f1cceeeab39079e52917fce494ec0b
--- /dev/null
+++ b/kernel/swtch.S
@@ -0,0 +1,41 @@
+# Context switch
+#
+#   void swtch(struct context *old, struct context *new);
+# 
+# Save current registers in old. Load from new.	
+
+
+.globl swtch
+swtch:
+        sd ra, 0(a0)
+        sd sp, 8(a0)
+        sd s0, 16(a0)
+        sd s1, 24(a0)
+        sd s2, 32(a0)
+        sd s3, 40(a0)
+        sd s4, 48(a0)
+        sd s5, 56(a0)
+        sd s6, 64(a0)
+        sd s7, 72(a0)
+        sd s8, 80(a0)
+        sd s9, 88(a0)
+        sd s10, 96(a0)
+        sd s11, 104(a0)
+
+        ld ra, 0(a1)
+        ld sp, 8(a1)
+        ld s0, 16(a1)
+        ld s1, 24(a1)
+        ld s2, 32(a1)
+        ld s3, 40(a1)
+        ld s4, 48(a1)
+        ld s5, 56(a1)
+        ld s6, 64(a1)
+        ld s7, 72(a1)
+        ld s8, 80(a1)
+        ld s9, 88(a1)
+        ld s10, 96(a1)
+        ld s11, 104(a1)
+        
+        ret
+
diff --git a/kernel/syscall.c b/kernel/syscall.c
new file mode 100644
index 0000000000000000000000000000000000000000..0183959c91cb2c9e460f994ae93b56d719b6f7e0
--- /dev/null
+++ b/kernel/syscall.c
@@ -0,0 +1,406 @@
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+#include "include/spinlock.h"
+#include "include/proc.h"
+#include "include/syscall.h"
+#include "include/sysinfo.h"
+#include "include/kalloc.h"
+#include "include/vm.h"
+#include "include/string.h"
+#include "include/printf.h"
+
+// Fetch the uint64 at addr from the current process.
+int
+fetchaddr(uint64 addr, uint64 *ip)
+{
+  struct proc *p = myproc();
+  // if(addr >= p->sz || addr+sizeof(uint64) > p->sz)
+  //   return -1;
+  if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
+    return -1;
+  return 0;
+}
+
+// Fetch the nul-terminated string at addr from the current process.
+// Returns length of string, not including nul, or -1 for error.
+int
+fetchstr(uint64 addr, char *buf, int max)
+{
+  // struct proc *p = myproc();
+  // int err = copyinstr(p->pagetable, buf, addr, max);
+  int err = copyinstr(myproc()->pagetable, buf, addr, max);
+  if(err < 0)
+    return err;
+  return strlen(buf);
+}
+
+static uint64
+argraw(int n)
+{
+  struct proc *p = myproc();
+  switch (n) {
+  case 0:
+    return p->trapframe->a0;
+  case 1:
+    return p->trapframe->a1;
+  case 2:
+    return p->trapframe->a2;
+  case 3:
+    return p->trapframe->a3;
+  case 4:
+    return p->trapframe->a4;
+  case 5:
+    return p->trapframe->a5;
+  }
+  panic("argraw");
+  return -1;
+}
+
+// Fetch the nth 32-bit system call argument.
+int
+argint(int n, int *ip)
+{
+  *ip = argraw(n);
+  return 0;
+}
+
+// Retrieve an argument as a pointer.
+// Doesn't check for legality, since
+// copyin/copyout will do that.
+int
+argaddr(int n, uint64 *ip)
+{
+  *ip = argraw(n);
+  return 0;
+}
+
+// Fetch the nth word-sized system call argument as a null-terminated string.
+// Copies into buf, at most max.
+// Returns string length if OK (including nul), -1 if error.
+int
+argstr(int n, char *buf, int max)
+{
+  uint64 addr;
+  if(argaddr(n, &addr) < 0){
+    return -1;
+  }
+  return fetchstr(addr, buf, max);
+}
+
+extern uint64 sys_chdir(void);
+extern uint64 sys_close(void);
+extern uint64 sys_dup(void);
+extern uint64 sys_exec(void);
+extern uint64 sys_exit(void);
+extern uint64 sys_fork(void);
+extern uint64 sys_fstat(void);
+extern uint64 sys_getpid(void);
+extern uint64 sys_kill(void);
+extern uint64 sys_mkdir(void);
+extern uint64 sys_open(void);
+extern uint64 sys_pipe(void);
+extern uint64 sys_read(void);
+extern uint64 sys_sbrk(void);
+extern uint64 sys_sleep(void);
+extern uint64 sys_wait(void);
+extern uint64 sys_write(void);
+extern uint64 sys_uptime(void);
+extern uint64 sys_test_proc(void);
+extern uint64 sys_dev(void);
+extern uint64 sys_readdir(void);
+extern uint64 sys_getcwd(void);
+extern uint64 sys_remove(void);
+extern uint64 sys_trace(void);
+extern uint64 sys_sysinfo(void);
+extern uint64 sys_rename(void);
+extern uint64 sys_clone(void);
+extern uint64 sys_execve(void);
+extern uint64 sys_waitpid(void);
+extern uint64 sys_getppid(void);
+extern uint64 sys_mmap(void);
+extern uint64 sys_munmap(void);
+extern uint64 sys_times(void);
+extern uint64 sys_uname(void);
+extern uint64 sys_sched_yield(void);
+extern uint64 sys_gettimeofday(void);
+extern uint64 sys_nanosleep(void);
+extern uint64 sys_openat(void);
+extern uint64 sys_pipe2(void);
+extern uint64 sys_dup3(void);
+extern uint64 sys_getdents64(void);
+extern uint64 sys_mkdirat(void);
+extern uint64 sys_wait4(void);
+extern uint64 sys_fstatat(void);
+extern uint64 sys_mount(void);
+extern uint64 sys_umount2(void);
+extern uint64 sys_linkat(void);
+extern uint64 sys_unlinkat(void);
+extern uint64 sys_rt_sigprocmask(void);
+extern uint64 sys_rt_sigaction(void);
+extern uint64 sys_rt_sigtimedwait(void);
+extern uint64 sys_set_tid_address(void);
+extern uint64 sys_exit_group(void);
+extern uint64 sys_gettid(void);
+extern uint64 sys_prlimit64(void);
+extern uint64 sys_clock_gettime(void);
+extern uint64 sys_futex(void);
+extern uint64 sys_lseek(void);
+extern uint64 sys_ioctl(void);
+extern uint64 sys_statfs(void);
+extern uint64 sys_mprotect(void);
+extern uint64 sys_utimensat(void);
+extern uint64 sys_readv(void);
+extern uint64 sys_writev(void);
+extern uint64 sys_msync(void);
+extern uint64 sys_clock_settime(void);
+extern uint64 sys_clock_gettime(void);
+extern uint64 sys_setitimer(void);
+extern uint64 sys_getuid(void);
+extern uint64 sys_geteuid(void);
+extern uint64 sys_getgid(void);
+extern uint64 sys_getegid(void);
+extern uint64 sys_sendfile(void);
+extern uint64 sys_syslog(void);
+extern uint64 sys_renameat2(void);
+extern uint64 sys_fcntl(void);
+extern uint64 sys_faccessat(void);
+extern uint64 sys_fchdir(void);
+extern uint64 sys_readlinkat(void);
+extern uint64 sys_tgkill(void);
+extern uint64 sys_umask(void);
+extern uint64 sys_brk(void);
+extern uint64 sys_getrusage(void);
+extern uint64 sys_pselect(void);
+
+static uint64 (*syscalls[])(void) = {
+  [SYS_fork]        sys_fork,
+  [SYS_exit]        sys_exit,
+  [SYS_wait]        sys_wait,
+  [SYS_pipe]        sys_pipe,
+  [SYS_read]        sys_read,
+  [SYS_kill]        sys_kill,
+  [SYS_exec]        sys_exec,
+  [SYS_fstat]       sys_fstat,
+  [SYS_chdir]       sys_chdir,
+  [SYS_dup]         sys_dup,
+  [SYS_getpid]      sys_getpid,
+  [SYS_sbrk]        sys_sbrk,
+  [SYS_sleep]       sys_sleep,
+  [SYS_uptime]      sys_uptime,
+  [SYS_open]        sys_open,
+  [SYS_write]       sys_write,
+  [SYS_mkdir]       sys_mkdir,
+  [SYS_close]       sys_close,
+  [SYS_test_proc]   sys_test_proc,
+  [SYS_dev]         sys_dev,
+  [SYS_readdir]     sys_readdir,
+  [SYS_getcwd]      sys_getcwd,
+  [SYS_remove]      sys_remove,
+  [SYS_trace]       sys_trace,
+  [SYS_sysinfo]     sys_sysinfo,
+  [SYS_rename]      sys_rename,
+  [SYS_clone]       sys_clone,
+  [SYS_execve]      sys_execve,
+  [SYS_wait4]       sys_waitpid,
+  [SYS_getppid]     sys_getppid,
+  [SYS_mmap]        sys_mmap,
+  [SYS_munmap]      sys_munmap,
+  [SYS_times]       sys_times,
+  [SYS_uname]       sys_uname,
+  [SYS_sched_yield] sys_sched_yield,
+  [SYS_gettimeofday] sys_gettimeofday,
+  [SYS_nanosleep]   sys_nanosleep,
+  [SYS_getdents64]  sys_getdents64,
+  [SYS_mkdirat]     sys_mkdirat,
+  [SYS_fstatat]     sys_fstatat,
+  [SYS_mount]       sys_mount,
+  [SYS_umount2]     sys_umount2,
+  [SYS_linkat]      sys_linkat,
+  [SYS_unlinkat]    sys_unlinkat,
+  [SYS_openat]      sys_openat,
+  [SYS_pipe2]       sys_pipe2,
+  [SYS_dup3]        sys_dup3,
+  [SYS_rt_sigprocmask]  sys_rt_sigprocmask,
+  [SYS_rt_sigaction]  sys_rt_sigaction,
+  [SYS_rt_sigtimedwait] sys_rt_sigtimedwait,
+  [SYS_set_tid_address] sys_set_tid_address,
+  [SYS_exit_group] sys_exit_group,
+  [SYS_gettid]     sys_gettid,
+  [SYS_prlimit64]  sys_prlimit64,
+  [SYS_clock_gettime] sys_clock_gettime,
+  [SYS_futex]      sys_futex,
+  [SYS_lseek]       sys_lseek,
+  [SYS_ioctl]       sys_ioctl,
+  [SYS_statfs]   sys_statfs,
+  [SYS_mprotect]  sys_mprotect,
+  [SYS_utimensat] sys_utimensat,
+  [SYS_readv]      sys_readv,
+  [SYS_writev]     sys_writev,
+  [SYS_msync]      sys_msync,
+  [SYS_clock_settime] sys_clock_settime,
+  [SYS_clock_gettime] sys_clock_gettime,
+  [SYS_setitimer]  sys_setitimer,
+  [SYS_getuid]		sys_getuid,
+	[SYS_geteuid]		sys_getuid,
+	[SYS_getgid]		sys_getuid,
+  [SYS_getegid]		sys_getuid,
+  [SYS_sendfile]  sys_sendfile,
+  [SYS_syslog]  sys_syslog,
+  [SYS_renameat2] sys_renameat2,
+  [SYS_fcntl]     sys_fcntl,
+  [SYS_faccessat]		sys_faccessat,
+  [SYS_fchdir]    sys_fchdir,
+  [SYS_readlinkat]  sys_readlinkat,
+  [SYS_tgkill]      sys_tgkill,
+  [SYS_umask]       sys_umask,
+  [SYS_brk]         sys_brk,
+  [SYS_getrusage]   sys_getrusage,
+  [SYS_pselect]     sys_pselect,
+
+};
+
+static char *sysnames[] = {
+  [SYS_fork]        "fork",
+  [SYS_exit]        "exit",
+  [SYS_wait]        "wait",
+  [SYS_pipe]        "pipe",
+  [SYS_read]        "read",
+  [SYS_kill]        "kill",
+  [SYS_exec]        "exec",
+  [SYS_fstat]       "fstat",
+  [SYS_chdir]       "chdir",
+  [SYS_dup]         "dup",
+  [SYS_getpid]      "getpid",
+  [SYS_sbrk]        "sbrk",
+  [SYS_sleep]       "sleep",
+  [SYS_uptime]      "uptime",
+  [SYS_open]        "open",
+  [SYS_write]       "write",
+  [SYS_mkdir]       "mkdir",
+  [SYS_close]       "close",
+  [SYS_test_proc]   "test_proc",
+  [SYS_dev]         "dev",
+  [SYS_readdir]     "readdir",
+  [SYS_getcwd]      "getcwd",
+  [SYS_remove]      "remove",
+  [SYS_trace]       "trace",
+  [SYS_sysinfo]     "sysinfo",
+  [SYS_rename]      "rename",
+  [SYS_clone]       "clone",
+  [SYS_execve]      "sys_execve",
+  [SYS_wait4]       "sys_waitpid",
+  [SYS_getppid]     "sys_getppid",
+  [SYS_mmap]        "sys_mmap",
+  [SYS_munmap]      "sys_munmap",
+  [SYS_times]       "sys_times",
+  [SYS_uname]       "sys_uname",
+  [SYS_sched_yield] "sys_sched_yield",
+  [SYS_gettimeofday] "sys_gettimeofday",
+  [SYS_nanosleep]   "sys_nanosleep",
+  [SYS_fstatat]     "fstatat",
+  [SYS_mount]       "mount",
+  [SYS_umount2]     "umount2",
+  [SYS_linkat]      "linkat",
+  [SYS_unlinkat]    "unlinkat",
+  [SYS_getdents64]  "getdents64",
+  [SYS_mkdirat]     "mkdirat",
+  [SYS_openat]      "openat",
+  [SYS_pipe2]       "pipe2",
+  [SYS_dup3]        "dup3",
+  [SYS_rt_sigprocmask]  "rt_sigprocmask",
+  [SYS_rt_sigaction] "rt_sigaction",
+  [SYS_rt_sigtimedwait] "rt_sigtimedwait",
+  [SYS_prlimit64]  "prlimit64",
+  [SYS_futex]      "futex",
+  [SYS_set_tid_address] "set_tid_address",
+  [SYS_exit_group] "exit_group",
+  [SYS_gettid]     "gettid",
+  [SYS_clock_gettime] "clock_gettime",
+  [SYS_lseek]       "lseek",
+  [SYS_ioctl]       "ioctl",
+  [SYS_statfs]    "statfs",
+  [SYS_mprotect]  "mprotect",
+  [SYS_utimensat] "utimensat",
+  [SYS_readv]      "readv",
+  [SYS_writev]     "writev",
+  [SYS_msync]      "sys_msync",
+  [SYS_clock_settime] "clock_settime",
+  [SYS_clock_gettime] "clock_gettime",
+  [SYS_setitimer] "setitimer",
+  [SYS_getuid]		"getuid",
+	[SYS_geteuid]		"geteuid",
+	[SYS_getgid]		"getgid",
+	[SYS_getegid]		"getegid",
+  [SYS_sendfile]  "sendfile",
+  [SYS_syslog]  "syslog",
+  [SYS_renameat2] "renameat2",
+  [SYS_fcntl]   "fcntl",
+	[SYS_faccessat]		"faccessat",
+  [SYS_fchdir]    "fchdir",
+  [SYS_readlinkat]  "readlinkat",
+  [SYS_tgkill]      "tgkill",
+  [SYS_umask]       "umask",
+  [SYS_brk]         "brk",
+  [SYS_getrusage]   "getrusage",
+  [SYS_pselect]     "sys_pselect",
+};
+
+void
+syscall(void)
+{
+  int num;
+  struct proc *p = myproc();
+
+  num = p->trapframe->a7;
+  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
+    // if(num!=63&&num!=64&&num!=65&&num!=66&&num!=113&&num!=165&&num!=173){
+    //   __DEBUG("pid %d %s call %d %s",p->pid,p->name,num,sysnames[num]);
+    // }
+    p->trapframe->a0 = syscalls[num]();
+        
+    // if(num!=65&&num!=66&&num!=113&&num!=165&&num!=173){
+    //   __DEBUG("pid %d %s call %d %s return %p",p->pid,p->name,num,sysnames[num],p->trapframe->a0);
+    // }
+
+    // trace
+    if ((p->tmask & (1 << num)) != 0) {
+      __DEBUG("pid %d: %s -> %d", p->pid, sysnames[num], p->trapframe->a0);
+    }
+  } else {
+    __ERROR("pid %d %s: unknown sys call %d",
+            p->pid, p->name, num);
+    p->trapframe->a0 = -1;
+  }
+}
+
+uint64 
+sys_test_proc(void) {
+    int n;
+    argint(0, &n);
+    printf("hello world from proc %d, hart %d, arg %d\n", myproc()->pid, r_tp(), n);
+    return 0;
+}
+
+uint64
+sys_sysinfo(void)
+{
+  uint64 addr;
+  struct proc *p = myproc();
+
+  if (argaddr(0, &addr) < 0) {
+    return -1;
+  }
+
+  struct sysinfo info;
+  info.freemem = freemem_amount();
+  info.nproc = procnum();
+  // __DEBUG("%p",addr);
+  if (copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0) {
+    return -1;
+  }
+
+  return 0;
+}
\ No newline at end of file
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
new file mode 100644
index 0000000000000000000000000000000000000000..55bddab5ff1fae36cfad3dee8aa9a68bae60e240
--- /dev/null
+++ b/kernel/sysctl.c
@@ -0,0 +1,332 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/types.h"
+#include "include/sysctl.h"
+#include "include/memlayout.h"
+
+#define SYSCTRL_CLOCK_FREQ_IN0 (26000000UL)
+
+const uint8 get_select_pll2[] =
+    {
+        [SYSCTL_SOURCE_IN0] = 0,
+        [SYSCTL_SOURCE_PLL0] = 1,
+        [SYSCTL_SOURCE_PLL1] = 2,
+};
+
+const uint8 get_source_pll2[] =
+    {
+        [0] = SYSCTL_SOURCE_IN0,
+        [1] = SYSCTL_SOURCE_PLL0,
+        [2] = SYSCTL_SOURCE_PLL1,
+};
+
+const uint8 get_select_aclk[] =
+    {
+        [SYSCTL_SOURCE_IN0] = 0,
+        [SYSCTL_SOURCE_PLL0] = 1,
+};
+
+const uint8 get_source_aclk[] =
+    {
+        [0] = SYSCTL_SOURCE_IN0,
+        [1] = SYSCTL_SOURCE_PLL0,
+};
+
+volatile sysctl_t *const sysctl = (volatile sysctl_t *)SYSCTL_V;
+
+uint32 sysctl_get_git_id(void)
+{
+    return sysctl->git_id.git_id;
+}
+
+uint32 sysctl_get_freq(void)
+{
+    return sysctl->clk_freq.clk_freq;
+}
+
+static int sysctl_clock_bus_en(sysctl_clock_t clock, uint8 en)
+{
+    /*
+     * The timer is under APB0, to prevent apb0_clk_en1 and apb0_clk_en0
+     * on same register, we split it to peripheral and central two
+     * registers, to protect CPU close apb0 clock accidentally.
+     *
+     * The apb0_clk_en0 and apb0_clk_en1 have same function,
+     * one of them set, the APB0 clock enable.
+     */
+
+    /* The APB clock should carefully disable */
+    if(en)
+    {
+        switch(clock)
+        {
+            /*
+             * These peripheral devices are under APB0
+             * GPIO, UART1, UART2, UART3, SPI_SLAVE, I2S0, I2S1,
+             * I2S2, I2C0, I2C1, I2C2, FPIOA, SHA256, TIMER0,
+             * TIMER1, TIMER2
+             */
+            case SYSCTL_CLOCK_GPIO:
+            case SYSCTL_CLOCK_SPI2:
+            case SYSCTL_CLOCK_I2S0:
+            case SYSCTL_CLOCK_I2S1:
+            case SYSCTL_CLOCK_I2S2:
+            case SYSCTL_CLOCK_I2C0:
+            case SYSCTL_CLOCK_I2C1:
+            case SYSCTL_CLOCK_I2C2:
+            case SYSCTL_CLOCK_UART1:
+            case SYSCTL_CLOCK_UART2:
+            case SYSCTL_CLOCK_UART3:
+            case SYSCTL_CLOCK_FPIOA:
+            case SYSCTL_CLOCK_TIMER0:
+            case SYSCTL_CLOCK_TIMER1:
+            case SYSCTL_CLOCK_TIMER2:
+            case SYSCTL_CLOCK_SHA:
+                sysctl->clk_en_cent.apb0_clk_en = en;
+                break;
+
+            /*
+             * These peripheral devices are under APB1
+             * WDT, AES, OTP, DVP, SYSCTL
+             */
+            case SYSCTL_CLOCK_AES:
+            case SYSCTL_CLOCK_WDT0:
+            case SYSCTL_CLOCK_WDT1:
+            case SYSCTL_CLOCK_OTP:
+            case SYSCTL_CLOCK_RTC:
+                sysctl->clk_en_cent.apb1_clk_en = en;
+                break;
+
+            /*
+             * These peripheral devices are under APB2
+             * SPI0, SPI1
+             */
+            case SYSCTL_CLOCK_SPI0:
+            case SYSCTL_CLOCK_SPI1:
+                sysctl->clk_en_cent.apb2_clk_en = en;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    return 0;
+}
+
+static int sysctl_clock_device_en(sysctl_clock_t clock, uint8 en)
+{
+    switch(clock)
+    {
+        /*
+         * These devices are PLL
+         */
+        case SYSCTL_CLOCK_PLL0:
+            sysctl->pll0.pll_out_en0 = en;
+            break;
+        case SYSCTL_CLOCK_PLL1:
+            sysctl->pll1.pll_out_en1 = en;
+            break;
+        case SYSCTL_CLOCK_PLL2:
+            sysctl->pll2.pll_out_en2 = en;
+            break;
+
+        /*
+         * These devices are CPU, SRAM, APB bus, ROM, DMA, AI
+         */
+        case SYSCTL_CLOCK_CPU:
+            sysctl->clk_en_cent.cpu_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_SRAM0:
+            sysctl->clk_en_cent.sram0_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_SRAM1:
+            sysctl->clk_en_cent.sram1_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_APB0:
+            sysctl->clk_en_cent.apb0_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_APB1:
+            sysctl->clk_en_cent.apb1_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_APB2:
+            sysctl->clk_en_cent.apb2_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_ROM:
+            sysctl->clk_en_peri.rom_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_DMA:
+            sysctl->clk_en_peri.dma_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_AI:
+            sysctl->clk_en_peri.ai_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_DVP:
+            sysctl->clk_en_peri.dvp_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_FFT:
+            sysctl->clk_en_peri.fft_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_SPI3:
+            sysctl->clk_en_peri.spi3_clk_en = en;
+            break;
+
+        /*
+         * These peripheral devices are under APB0
+         * GPIO, UART1, UART2, UART3, SPI_SLAVE, I2S0, I2S1,
+         * I2S2, I2C0, I2C1, I2C2, FPIOA, SHA256, TIMER0,
+         * TIMER1, TIMER2
+         */
+        case SYSCTL_CLOCK_GPIO:
+            sysctl->clk_en_peri.gpio_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_SPI2:
+            sysctl->clk_en_peri.spi2_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_I2S0:
+            sysctl->clk_en_peri.i2s0_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_I2S1:
+            sysctl->clk_en_peri.i2s1_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_I2S2:
+            sysctl->clk_en_peri.i2s2_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_I2C0:
+            sysctl->clk_en_peri.i2c0_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_I2C1:
+            sysctl->clk_en_peri.i2c1_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_I2C2:
+            sysctl->clk_en_peri.i2c2_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_UART1:
+            sysctl->clk_en_peri.uart1_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_UART2:
+            sysctl->clk_en_peri.uart2_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_UART3:
+            sysctl->clk_en_peri.uart3_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_FPIOA:
+            sysctl->clk_en_peri.fpioa_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_TIMER0:
+            sysctl->clk_en_peri.timer0_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_TIMER1:
+            sysctl->clk_en_peri.timer1_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_TIMER2:
+            sysctl->clk_en_peri.timer2_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_SHA:
+            sysctl->clk_en_peri.sha_clk_en = en;
+            break;
+
+        /*
+         * These peripheral devices are under APB1
+         * WDT, AES, OTP, DVP, SYSCTL
+         */
+        case SYSCTL_CLOCK_AES:
+            sysctl->clk_en_peri.aes_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_WDT0:
+            sysctl->clk_en_peri.wdt0_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_WDT1:
+            sysctl->clk_en_peri.wdt1_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_OTP:
+            sysctl->clk_en_peri.otp_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_RTC:
+            sysctl->clk_en_peri.rtc_clk_en = en;
+            break;
+
+        /*
+         * These peripheral devices are under APB2
+         * SPI0, SPI1
+         */
+        case SYSCTL_CLOCK_SPI0:
+            sysctl->clk_en_peri.spi0_clk_en = en;
+            break;
+        case SYSCTL_CLOCK_SPI1:
+            sysctl->clk_en_peri.spi1_clk_en = en;
+            break;
+
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+int sysctl_clock_enable(sysctl_clock_t clock)
+{
+    if(clock >= SYSCTL_CLOCK_MAX)
+        return -1;
+    sysctl_clock_bus_en(clock, 1);
+    sysctl_clock_device_en(clock, 1);
+    return 0;
+}
+
+int sysctl_dma_select(sysctl_dma_channel_t channel, sysctl_dma_select_t select)
+{
+    sysctl_dma_sel0_t dma_sel0;
+    sysctl_dma_sel1_t dma_sel1;
+
+    /* Read register from bus */
+    dma_sel0 = sysctl->dma_sel0;
+    dma_sel1 = sysctl->dma_sel1;
+    switch(channel)
+    {
+        case SYSCTL_DMA_CHANNEL_0:
+            dma_sel0.dma_sel0 = select;
+            break;
+
+        case SYSCTL_DMA_CHANNEL_1:
+            dma_sel0.dma_sel1 = select;
+            break;
+
+        case SYSCTL_DMA_CHANNEL_2:
+            dma_sel0.dma_sel2 = select;
+            break;
+
+        case SYSCTL_DMA_CHANNEL_3:
+            dma_sel0.dma_sel3 = select;
+            break;
+
+        case SYSCTL_DMA_CHANNEL_4:
+            dma_sel0.dma_sel4 = select;
+            break;
+
+        case SYSCTL_DMA_CHANNEL_5:
+            dma_sel1.dma_sel5 = select;
+            break;
+
+        default:
+            return -1;
+    }
+
+    /* Write register back to bus */
+    sysctl->dma_sel0 = dma_sel0;
+    sysctl->dma_sel1 = dma_sel1;
+
+    return 0;
+}
diff --git a/kernel/sysfile.c b/kernel/sysfile.c
new file mode 100644
index 0000000000000000000000000000000000000000..eb13f9a009f6c7ffa8f3a4a7f03fa2a7accc95c1
--- /dev/null
+++ b/kernel/sysfile.c
@@ -0,0 +1,1721 @@
+//
+// File-system system calls.
+// Mostly argument checking, since we don't trust
+// user code, and calls into file.c and fs.c.
+//
+
+
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/param.h"
+#include "include/stat.h"
+#include "include/spinlock.h"
+#include "include/proc.h"
+#include "include/sleeplock.h"
+#include "include/file.h"
+#include "include/pipe.h"
+#include "include/fcntl.h"
+#include "include/fat32.h"
+#include "include/syscall.h"
+#include "include/string.h"
+#include "include/printf.h"
+#include "include/vm.h"
+#include "include/uname.h"
+#include "include/timer.h"
+#include "include/errno.h"
+#include "include/kalloc.h"
+
+// Fetch the nth word-sized system call argument as a file descriptor
+// and return both the descriptor and the corresponding struct file.
+// 读取文件描述符和对应文件
+static int
+argfd(int n, int *pfd, struct file **pf)
+{
+  int fd;
+  struct file *f;
+
+  if(argint(n, &fd) < 0){
+    __ERROR("read register failed");
+    return -1;
+  }
+  // __DEBUG("pid %d %d",myproc()->pid,fd);
+  if(fd!=AT_FDCWD)
+  {
+    if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == NULL){
+      // __ERROR("fd = %d, NOFILE = %d, f = %p",fd,NOFILE,(uint64)f);
+      return -1;
+    }
+  
+    if(pfd)
+      *pfd = fd;
+    if(pf)
+      *pf = f;
+  }
+  else
+  {
+    if(pfd)
+    *pfd = fd;
+    return -1;
+  }
+  
+  return 0;
+}
+
+// Allocate a file descriptor for the given file.
+// Takes over file reference from caller on success.
+// 分配文件描述符
+static int
+fdalloc(struct file *f)
+{
+  int fd;
+  struct proc *p = myproc();
+  // __DEBUG("%d",p->rlim[RLIMIT_NOFILE].rlim_max);
+  for(fd = 0; fd < NOFILE; fd++){
+    if(p->rlim[RLIMIT_NOFILE].rlim_cur && fd >= p->rlim[RLIMIT_NOFILE].rlim_cur){
+      __DEBUG("%d",p->rlim[RLIMIT_NOFILE].rlim_cur);
+      return -EMFILE;
+    }
+    if(p->ofile[fd] == 0){
+      p->ofile[fd] = f;
+      return fd;
+    }
+  }
+  return -1;
+}
+
+// 复制文件描述符
+uint64
+sys_dup(void)
+{
+  struct file *f;
+  int fd;
+
+  if(argfd(0, 0, &f) < 0){
+    __ERROR("read fd failed");
+    return -1;
+  }
+  if((fd=fdalloc(f)) < 0){
+    return -EMFILE;
+  }
+  filedup(f);
+  return fd;
+}
+
+
+uint64
+sys_dup3(void)
+{
+  struct file *f1;
+  struct file *f2;
+  int oldfd;
+  int newfd;
+
+  if(argfd(0, &oldfd, &f1) < 0){
+    __ERROR("read fd failed");
+    return -1;
+  }
+
+  if(argint(1, &newfd) < 0){
+    __ERROR("read register failed");
+    return -1;
+  }
+  
+  if(newfd == oldfd)
+    return newfd;
+
+  if(newfd < 0 || newfd >= NOFILE){
+    return -EMFILE;
+  }
+  if(myproc()->rlim[RLIMIT_NOFILE].rlim_cur && newfd >= myproc()->rlim[RLIMIT_NOFILE].rlim_cur)
+    return -EMFILE;
+
+  if(myproc()->ofile[newfd]){
+    f2 = myproc()->ofile[newfd];
+    myproc()->ofile[newfd] = 0;
+    fileclose(f2);
+  }
+
+  myproc()->ofile[newfd] = f1;
+  filedup(f1);
+  return newfd;
+}
+
+// 读文件
+uint64
+sys_read(void)
+{
+  struct file *f;
+  int count;
+  uint64 buf;
+
+  if(argfd(0, 0, &f) < 0){
+    __ERROR("read fd failed");
+    return -1;
+  }
+
+  if(argint(2, &count) < 0 || argaddr(1, &buf) < 0){
+    __ERROR("read register failed!");
+    return -1; 
+  }
+  // __DEBUG("pid %d read from %p",myproc()->pid,buf);
+  return fileread(f, buf, count);
+ 
+}
+
+uint64
+sys_readv(void){
+  int fd, count;
+	uint64 iovp;
+	struct file *f = NULL;
+	if (argfd(0, &fd, &f) < 0 || argaddr(1, &iovp) < 0 || argint(2, &count) < 0)
+		return -EBADF;
+
+	struct iovec *ioarr = (struct iovec *)kalloc();
+	if (ioarr == NULL)
+		return -ENOMEM;
+
+	if (copyin(myproc()->pagetable,(char *)ioarr, iovp, count * sizeof(struct iovec)) < 0) {
+		kfree((void *)ioarr);
+		return -EFAULT;
+	}
+
+	int ret = filereadv(f, ioarr, count);
+	
+	kfree((void *)ioarr);
+	return ret;
+}
+
+uint64
+sys_writev(void){
+  int fd, count;
+	uint64 iovp;
+	struct file *f = NULL;
+	if (argfd(0, &fd, &f) < 0 || argaddr(1, &iovp) < 0 || argint(2, &count) < 0)
+		return -EBADF;
+
+	struct iovec *ioarr = (struct iovec *)kalloc();
+	if (ioarr == NULL)
+		return -ENOMEM;
+
+	if (copyin(myproc()->pagetable,(char *)ioarr, iovp, count * sizeof(struct iovec)) < 0) {
+		kfree(ioarr);
+		return -EFAULT;
+	}
+
+	int ret = filewritev(f, ioarr, count);
+	
+	kfree(ioarr);
+	return ret;
+}
+
+// 写文件
+uint64
+sys_write(void)
+{
+  // __DEBUG("writing\n");
+  struct file *f;
+  int count;
+  uint64 buf;
+  
+  if(argfd(0, 0, &f) < 0){
+    // __ERROR("read fd failed");
+    return -1;
+  }
+
+  if(argint(2, &count) < 0 || argaddr(1, &buf) < 0){
+    __ERROR("read register failed!");
+    return -1;
+  }
+  // __DEBUG("pid %d write to %p",myproc()->pid,buf);
+  return filewrite(f, buf, count);
+
+}
+
+// 关闭文件
+uint64
+sys_close(void)
+{
+  int fd;
+  struct file *f;
+
+  if(argfd(0, &fd, &f) < 0){
+    __ERROR("read fd failed");
+    return -1;
+  }
+  myproc()->ofile[fd] = 0;
+  fileclose(f);
+  return 0;
+}
+
+
+// 打开文件
+uint64
+sys_open(void)
+{
+  char path[FAT32_MAX_PATH];
+  int fd, omode;
+  struct file *f;
+  struct dirent *ep;
+
+  if(argstr(0, path, FAT32_MAX_PATH) < 0 || argint(1, &omode) < 0)
+    return -1;
+
+  if(omode & O_CREATE){
+    ep = create(path, T_FILE, omode);
+    if(ep == NULL){
+      return -1;
+    }
+  } else {
+    if((ep = ename(path)) == NULL){
+      return -1;
+    }
+    elock(ep);
+    if((ep->attribute & ATTR_DIRECTORY) && omode != O_RDONLY){
+      eunlock(ep);
+      eput(ep);
+      return -1;
+    }
+  }
+
+  if((f = filealloc()) == NULL || (fd = fdalloc(f)) < 0){
+    __ERROR("filealloc failed or fdalloc failed");
+    if (f) {
+      fileclose(f);
+    }
+    eunlock(ep);
+    eput(ep);
+    return -1;
+  }
+
+  if(!(ep->attribute & ATTR_DIRECTORY) && (omode & O_TRUNC)){
+    etrunc(ep);
+  }
+
+  if((f->major = get_major(path)) > 0){
+    // __DEBUG("open a device");
+    f->type = FD_DEVICE;
+  }else{
+    f->type = FD_ENTRY;
+  }
+
+
+  f->type = FD_ENTRY;
+  f->off = (omode & O_APPEND) ? ep->file_size : 0;
+  f->ep = ep;
+  f->readable = !(omode & O_WRONLY);
+  f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
+
+  eunlock(ep);
+  return fd;
+}
+
+uint64
+sys_openat(void)
+{
+  char path[FAT32_MAX_PATH];
+  int fd, flags, mode;
+  struct file *f;
+  struct file *f2;
+  struct dirent *ep;
+  f2 = NULL;
+
+  if(argint(0, &fd) < 0 || argstr(1, path, FAT32_MAX_PATH) < 0 || argint(2, &flags) < 0 || argint(3, &mode) < 0){
+    __ERROR("can't read registers");
+    return -1;
+  }
+  if(*path != '/' && fd >= 0 && fd < NOFILE){
+    f2 = myproc()->ofile[fd];
+  }
+
+  // printf("%d\n", flags);
+  if(flags & O_CREATE){
+    
+    if(S_ISDIR(mode)){
+      ep = create2(path, T_DIR, flags, f2);
+      if(ep == NULL){
+        __ERROR("create a dir failed");
+        return -1;
+      }
+    }else{
+      ep = create2(path, T_FILE, flags, f2);
+      if(ep == NULL){
+        __ERROR("create a file failed");
+        return -1;
+      }
+    }
+    // printf("created!\n");
+  }
+  else{
+    if((ep = ename2(path, f2)) == NULL){
+      return -ENOENT;
+    }
+    elock(ep);
+    if((ep->attribute & ATTR_DIRECTORY) && ((flags & O_RDWR) || (flags & O_WRONLY))){
+      __ERROR("dir can't write");
+      eunlock(ep);
+      eput(ep);
+      return -1;
+    }
+    if((flags & O_DIRECTORY) && !(ep->attribute & ATTR_DIRECTORY)){
+      __ERROR("it is not dir");
+      eunlock(ep);
+      eput(ep);
+      return -ENOTDIR;
+    }
+  }
+  if((f = filealloc()) == NULL || (fd = fdalloc(f)) < 0){
+    // __ERROR("no free filetable or fd");
+    if (f) {
+      fileclose(f);
+    }
+    eunlock(ep);
+    eput(ep);
+    return -EMFILE;
+  }
+
+  if(!(ep->attribute & ATTR_DIRECTORY) && (flags & O_TRUNC)){
+    etrunc(ep);
+  }
+
+  if((f->major = get_major(path)) > 0){
+    // __DEBUG("open a device");
+    f->type = FD_DEVICE;
+  }else{
+    f->type = FD_ENTRY;
+  }
+
+  f->off = (flags & O_APPEND) ? ep->file_size : 0;
+  f->ep = ep;
+  f->readable = !(flags & O_WRONLY);
+  f->writable = (flags & O_WRONLY) || (flags & O_RDWR);
+
+  eunlock(ep);
+  return fd;
+}
+
+// 创建目录
+uint64
+sys_mkdir(void)
+{
+  char path[FAT32_MAX_PATH];
+  struct dirent *ep;
+
+  if(argstr(0, path, FAT32_MAX_PATH) < 0 || (ep = create(path, T_DIR, 0)) == 0){
+    __ERROR("read register failed");
+    return -1;
+  }
+  eunlock(ep);
+  eput(ep);
+  return 0;
+}
+
+uint64
+sys_mkdirat(void){
+  char path[FAT32_MAX_PATH];
+  struct file *f;
+  int dirfd, mode;
+  f = NULL;
+  if(argint(0, &dirfd) < 0 || argstr(1, path, FAT32_MAX_PATH) < 0 || argint(2, &mode)){
+    __ERROR("can't read registers");
+    return -1;
+  }
+  if(*path != '/' && dirfd >= 0 && dirfd < NOFILE){
+    f = myproc()->ofile[dirfd];
+  }
+  struct dirent *ep;
+  if((ep = create2(path, T_DIR, 0, f)) == 0){
+    __ERROR("can't create %s", path);
+    return -1;
+  }
+  eunlock(ep);
+  eput(ep);
+  return 0;
+}
+
+// 切换当前目录
+uint64
+sys_chdir(void)
+{
+  char path[FAT32_MAX_PATH];
+  struct dirent *ep;
+  struct proc *p = myproc();
+ 
+  if(argstr(0, path, FAT32_MAX_PATH) < 0){
+    __ERROR("%s",path);
+    return -1;
+  }
+
+  if((ep = ename(path)) == NULL)
+    return -ENOENT;
+
+  elock(ep);
+  if(!(ep->attribute & ATTR_DIRECTORY)){
+    __ERROR("%s is not a dir",ep->filename);
+    eunlock(ep);
+    eput(ep);
+    return -ENOTDIR;
+  }
+  eunlock(ep);
+  eput(p->cwd);
+  p->cwd = ep;
+  return 0;
+}
+
+uint64 sys_fchdir(void){
+  int fd;
+  struct file *f;
+  struct proc* p = myproc();
+  if(argint(0,&fd) < 0){
+    return -1;
+  }
+  if(fd > 0 && fd < NOFILE){
+    f = p->ofile[fd];
+    if(f == NULL){
+      return -ENOENT;
+    }
+  }else return -EBADF;
+  struct dirent *ep = f->ep;
+  elock(ep);
+  if(!(ep->attribute & ATTR_DIRECTORY)){
+    eunlock(ep);
+    eput(ep);
+    return -ENOTDIR;
+  }
+  eunlock(ep);
+  eput(p->cwd);
+  p->cwd = ep;
+  return 0;
+}
+
+// 创建管道
+uint64
+sys_pipe(void)
+{
+  uint64 fdarray; // user pointer to array of two integers
+  struct file *rf, *wf;
+  int fd0, fd1;
+  struct proc *p = myproc();
+
+  if(argaddr(0, &fdarray) < 0)
+    return -1;
+  if(pipealloc(&rf, &wf) < 0)
+    return -1;
+  fd0 = -1;
+  if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
+    if(fd0 >= 0)
+      p->ofile[fd0] = 0;
+    fileclose(rf);
+    fileclose(wf);
+    __ERROR("fdalloc failed");
+    return -1;
+  }
+  if(copyout(p->pagetable,fdarray, (char*)&fd0, sizeof(fd0)) < 0 ||
+     copyout(p->pagetable,fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){
+    p->ofile[fd0] = 0;
+    p->ofile[fd1] = 0;
+    fileclose(rf);
+    fileclose(wf);
+    return -1;
+  }
+  return 0;
+}
+
+uint64
+sys_pipe2(void)
+{
+  uint64 fdarray; // user pointer to array of two integers
+  struct file *rf, *wf;
+  int fd0, fd1;
+  struct proc *p = myproc();
+  if(argaddr(0, &fdarray) < 0){
+    __ERROR("can't read registers");
+    return -1;
+  }
+  if(pipealloc(&rf, &wf) < 0){
+    __ERROR("create pipe failed");
+    return -1;
+  }
+  fd0 = -1;
+  if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
+    __ERROR("no free fd");
+    if(fd0 >= 0)
+      p->ofile[fd0] = 0;
+    fileclose(rf);
+    fileclose(wf);
+    return -1;
+  }
+  
+  if(copyout(p->pagetable,fdarray, (char*)&fd0, sizeof(fd0)) < 0 ||
+     copyout(p->pagetable,fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){
+    __ERROR("copy failed");
+    p->ofile[fd0] = 0;
+    p->ofile[fd1] = 0;
+    fileclose(rf);
+    fileclose(wf);
+    return -1;
+  }
+  // __DEBUG("fd[0] = %d, fd[1] = %d", (*((int*)fdarray)), (*((int*)(fdarray + sizeof(fd0)))));
+  return 0;
+}
+
+// To open console device.
+uint64
+sys_dev(void)
+{
+  int fd, omode;
+  int major, minor;
+  struct file *f;
+
+  if(argint(0, &omode) < 0 || argint(1, &major) < 0 || argint(2, &minor) < 0){
+    return -1;
+  }
+
+  if(omode & O_CREATE){
+    panic("dev file on FAT");
+  }
+
+  if(major < 0 || major >= NDEV)
+    return -1;
+
+  if((f = filealloc()) == NULL || (fd = fdalloc(f)) < 0){
+    if(f)
+      fileclose(f);
+    return -1;
+  }
+
+  f->type = FD_DEVICE;
+  f->off = 0;
+  f->ep = 0;
+  f->major = major;
+  f->readable = !(omode & O_WRONLY);
+  f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
+
+  return fd;
+}
+
+// 读目录
+// To support ls command
+uint64
+sys_readdir(void)
+{
+  struct file *f;
+  uint64 p;
+
+  if(argfd(0, 0, &f) < 0){
+    __ERROR("read fd failed");
+    return -1;
+  }
+
+  if(argaddr(1, &p) < 0){
+    __ERROR("read register failed");
+    return -1;
+  }
+  return dirnext(f, p);
+}
+
+// get absolute cwd string
+// 获取当前目录
+uint64
+sys_getcwd(void)
+{
+  uint64 addr;
+  int size;
+  if (argaddr(0, &addr) < 0 || argint(1, &size) < 0)
+    return NULL;
+
+  struct dirent *de = myproc()->cwd;
+  char path[FAT32_MAX_PATH];
+  char *s;
+  int len;
+
+  if (de->parent == NULL) {
+    s = "/";
+  } else {
+    s = path + FAT32_MAX_PATH - 1;
+    *s = '\0';
+    while (de->parent) {
+      len = strlen(de->filename);
+      s -= len;
+      if (s <= path)          // can't reach root "/"
+        return -1;
+      strncpy(s, de->filename, len);
+      *--s = '/';
+      de = de->parent;
+    }
+  }
+  if (size < strlen(s) + 1){
+    if (copyout(myproc()->pagetable, addr, s, strlen(s) + 1) < 0)
+      return NULL;
+  }
+  else{ 
+    if (copyout(myproc()->pagetable, addr, s, strlen(s) + 1) < 0)
+      return NULL;
+  }
+  return addr;
+
+}
+
+
+uint64
+sys_remove(void)
+{
+  char path[FAT32_MAX_PATH];
+  int len;
+  if((len = argstr(0, path, FAT32_MAX_PATH)) <= 0)
+    return -1;
+  return remove(path);
+}
+
+int rename(char *old, char *new, struct file *f1, struct file *f2){
+  struct dirent *src = NULL, *dst = NULL, *pdst = NULL;
+  int srclock = 0;
+  char *name;
+  if ((src = ename2(old, f1)) == NULL || (pdst = enameparent2(new, old, f2)) == NULL
+      || (name = formatname(old)) == NULL) {
+    goto fail;          // src doesn't exist || dst parent doesn't exist || illegal new name
+  }
+  for (struct dirent *ep = pdst; ep != NULL; ep = ep->parent) {
+    if (ep == src) {    // In what universe can we move a directory into its child?
+      goto fail;
+    }
+  }
+
+  uint off;
+  elock(src);     // must hold child's lock before acquiring parent's, because we do so in other similar cases
+  srclock = 1;
+  elock(pdst);
+  dst = dirlookup(pdst, name, &off);
+  if (dst != NULL) {
+    eunlock(pdst);
+    if (src == dst) {
+      goto fail;
+    } else if (src->attribute & dst->attribute & ATTR_DIRECTORY) {
+      elock(dst);
+      if (!isdirempty(dst)) {    // it's ok to overwrite an empty dir
+        eunlock(dst);
+        goto fail;
+      }
+      elock(pdst);
+    } else {                    // src is not a dir || dst exists and is not an dir
+      goto fail;
+    }
+  }
+
+  if (dst) {
+    eremove(dst);
+    eunlock(dst);
+  }
+  memmove(src->filename, name, FAT32_MAX_FILENAME);
+  emake(pdst, src, off);
+  if (src->parent != pdst) {
+    eunlock(pdst);
+    elock(src->parent);
+  }
+  eremove(src);
+  eunlock(src->parent);
+  struct dirent *psrc = src->parent;  // src must not be root, or it won't pass the for-loop test
+  src->parent = edup(pdst);
+  src->off = off;
+  src->valid = 1;
+  eunlock(src);
+
+  eput(psrc);
+  if (dst) {
+    eput(dst);
+  }
+  eput(pdst);
+  eput(src);
+
+  return 0;
+
+fail:
+  if (srclock)
+    eunlock(src);
+  if (dst)
+    eput(dst);
+  if (pdst)
+    eput(pdst);
+  if (src)
+    eput(src);
+  return -1;
+}
+
+// Must hold too many locks at a time! It's possible to raise a deadlock.
+// Because this op takes some steps, we can't promise
+uint64
+sys_rename(void)
+{
+  char old[FAT32_MAX_PATH], new[FAT32_MAX_PATH];
+  if (argstr(0, old, FAT32_MAX_PATH) < 0 || argstr(1, new, FAT32_MAX_PATH) < 0) {
+      return -1;
+  }
+  return rename(old,new,NULL,NULL);
+}
+
+void getkstat(struct dirent *de, struct kstat *kst){
+  kst->st_dev = de->dev;
+  kst->st_ino = de->first_clus;
+  kst->st_mode = (de->attribute & ATTR_DIRECTORY) ? S_IFDIR : S_IFREG;
+  kst->st_mode |= (de->attribute & ATTR_READ_ONLY) ? 0444 : 0777;
+  kst->st_nlink = 1;
+  kst->st_uid = 0;
+  kst->st_gid = 0;
+  kst->st_rdev = 0;
+  kst->__pad = 0;
+  kst->__pad2 = 0;
+  kst->st_size = de->file_size;
+  kst->st_blksize = get_byts_per_clus();
+  kst->st_blocks = (kst->st_size / kst->st_blksize);
+  if (kst->st_blocks * kst->st_blksize < kst->st_size)
+    kst->st_blocks++;
+  kst->st_atim.tv_nsec = 0;
+  kst->st_atim.tv_sec = de->last_access_date;
+  kst->st_ctim.tv_nsec = 0;
+  kst->st_ctim.tv_sec = 0;
+  kst->st_mtim.tv_nsec = 0;
+  kst->st_mtim.tv_sec = de->last_write_date;
+  kst->__unused[0] = 0;
+  kst->__unused[1] = 0;
+}
+
+uint64
+sys_getdents64(void){
+  int len;
+  struct file *f; 
+  uint64 buf;
+  if(argfd(0, 0, &f) < 0){
+    __ERROR("read fd failed");
+    return -EBADF;
+  }
+  if(argaddr(1, &buf) < 0 || argint(2, &len) < 0){
+    __ERROR("can't read registers\n");
+    return -1;
+  }
+  if(!(f->ep->attribute & ATTR_DIRECTORY)) return -ENOTDIR;
+  if(!rangeinseg(buf, buf + len)) return -EFAULT;
+  return dirnext2(f, buf, len);
+  // getdstat(f->ep, &ds);
+  // if(copyout(myproc()->pagetable, buf, (char*)&ds, sizeof(ds)) < 0){
+  //   __ERROR("copy wrong\n");
+  //   return -1;
+  // }
+  // return sizeof(len);
+}
+
+uint64
+sys_fstatat(void){
+  struct file *f2 = NULL;
+  int fd; 
+  char path[FAT32_MAX_PATH];
+  uint64 buf; 
+  struct kstat ks;
+  int flags;
+  if(argint(0, &fd) < 0 || argstr(1, path, FAT32_MAX_PATH) < 0 || argaddr(2, &buf) < 0 || argint(3, &flags) < 0){
+    __ERROR("can't read registers");
+    return -1;
+  }
+  // __DEBUG("%d",flags);
+  if(*path != '/' && fd >= 0 && fd < NOFILE){
+    f2 = myproc()->ofile[fd];
+  }
+  struct dirent *ep = ename2(path, f2);
+  if(ep == NULL){
+    return -ENOENT;
+  }
+  getkstat(ep, &ks);
+  if(copyout(myproc()->pagetable, buf, (char*)&ks, sizeof(ks)) < 0){
+    __ERROR("copy wrong\n");
+    return -1;
+  }
+  return 0;
+}
+
+uint64
+sys_fstat(void)
+{
+  struct file *f;
+	uint64 st; // user pointer to struct stat
+// __DEBUG("entry fstat\n");
+	if (argfd(0, 0, &f) < 0)
+		return -EBADF;
+	argaddr(1, &st);
+	return filestat(f, st);
+}
+
+uint64 sys_mount()
+{
+    char mount_path[FAT32_MAX_PATH];
+    char dev_path[FAT32_MAX_PATH];
+    char  fstype[10];
+     int  flags;
+  struct dirent *ep,*dev_ep;
+
+    if(argstr(0,dev_path,FAT32_MAX_PATH)<0||argstr(1,mount_path,FAT32_MAX_PATH)<0)
+    {
+      __ERROR("argument not allowed\n");
+      return -1;
+    }
+
+    if(argstr(2,fstype,10)<0|| argint(3, (int*)&flags) <0)
+    {
+       __ERROR("argument not allowed\n");
+        return -1;
+    }
+    //mountpoint  not allowed the root
+    if(strncmp("/",mount_path,2)==0)
+    {
+      __ERROR("not allowed\n");
+      return -1;
+    }
+    if((dev_ep=ename(dev_path))==NULL)
+    {
+      __ERROR("dev not found file");
+      return -1;
+    }
+
+   if((ep=ename(mount_path))==NULL)
+   {
+      __ERROR("mount not found file");
+     return -1;
+   }
+   
+   if(!(ep->attribute & ATTR_DIRECTORY))
+   {
+     __ERROR("mountpoint is not a dir");
+     return -1;
+   }
+   if (strncmp("vfat", fstype, 5) != 0 &&
+		strncmp("fat32", fstype, 6) != 0)
+  {
+    __ERROR("the fstype is not fat32");
+		return -1;
+	}
+    int ret= do_mount(ep,dev_ep);
+    
+    return ret;
+}
+
+
+uint64
+sys_umount2(void)
+{
+	char dev_path[FAT32_MAX_PATH];
+  argstr(0,dev_path,FAT32_MAX_PATH);
+  struct dirent*ep;
+  if(strncmp("/",dev_path,2)==0)
+  {
+    __ERROR("path error");
+    return -1;
+  }
+
+  if((ep=ename(dev_path))==NULL)
+  {
+    __ERROR("not found file\n");
+    return -1;
+  }
+   int ret=do_umount(ep);
+	return ret;
+
+}
+
+
+uint64
+sys_linkat(void){
+  int olddirfd, newdirfd;
+  char oldpath[FAT32_MAX_PATH], newpath[FAT32_MAX_PATH];
+  int flags;
+  struct file *f1, *f2;
+  f1 = NULL;f2 = NULL;
+  if(argint(0, &olddirfd) < 0 || argstr(1, oldpath, FAT32_MAX_PATH) < 0){
+    __ERROR("can't read register\n");
+    return -1;
+  }
+  if(argint(2, &newdirfd) < 0 || argstr(3, newpath, FAT32_MAX_PATH) < 0 || argint(4, &flags) < 0){
+    __ERROR("can't read register\n");
+    return -1;
+  }
+  if(*oldpath != '/' && olddirfd >= 0 && olddirfd < NOFILE){
+    f1 = myproc()->ofile[olddirfd];
+  }
+  if(*newpath != '/' && newdirfd >= 0 && newdirfd < NOFILE){
+    f2 = myproc()->ofile[newdirfd];
+  }
+  return link(oldpath, f1, newpath, f2);  
+}
+
+
+uint64
+sys_unlinkat(void){
+  int dirfd;
+  char path[FAT32_MAX_PATH];
+  int flags;
+  struct file *f;
+  f = NULL;
+  if(argint(0, &dirfd) < 0 || argstr(1, path, FAT32_MAX_PATH) < 0 || argint(2, &flags) < 0){
+    __ERROR("can't read register\n");
+    return -1;
+  }
+  if(*path != '/' && dirfd >= 0 && dirfd < NOFILE){
+    f = myproc()->ofile[dirfd];
+  }
+  return unlink(path, f);
+}
+
+uint64
+sys_uname(void){
+  uint64 sys_name;
+  if(argaddr(0, &sys_name) < 0)
+    return -1;
+  return do_uname(sys_name);
+}
+
+uint64
+sys_sched_yield(void){
+  yield();
+	return 0;
+}
+
+uint64
+sys_gettimeofday(void){
+
+	uint64 ptval;
+	if (argaddr(0, &ptval) < 0) {
+		return -1;
+	}
+  
+  TimeVal *tval =( TimeVal *)ptval;
+	uint64 tmp_ticks = r_time();
+	tval->sec = tmp_ticks / CLK_FREQ;
+	tval->usec = tmp_ticks / (CLK_FREQ / 100000);
+	tval->usec = (tval->usec % 100000) * 10;
+
+	return 0;
+}
+
+
+
+uint64
+sys_nanosleep(void){
+  uint64 addr;
+  TimeVal *tv;
+  struct proc *p = myproc();
+  if(argaddr(0, &addr) < 0)
+    return -1;
+  tv=(TimeVal *)addr;
+
+  if(myproc()->killed||gain_sleep(tv)==0){
+    return -1;
+  }
+  
+  acquire(&p->lock);  
+  p->state = SLEEPING;
+  // __DEBUG("pid %d sleep",p->pid);
+  sched();
+  release(&p->lock);
+
+  return 0;
+}
+
+int rlim64_is_infinity(unsigned long long rlim64)
+{
+#if BITS_PER_LONG < 64
+	return rlim64 >= ULONG_MAX;
+#else
+	return rlim64 == RLIM64_INFINITY;
+#endif
+}
+
+
+void rlim64_to_rlim(const struct rlimit *rlim64, struct rlimit *rlim)
+{
+if (rlim64_is_infinity(rlim64->rlim_cur))
+		rlim->rlim_cur = RLIM_INFINITY;
+	else
+		rlim->rlim_cur = (unsigned long)rlim64->rlim_cur;
+	if (rlim64_is_infinity(rlim64->rlim_max))
+		rlim->rlim_max = RLIM_INFINITY;
+	else
+		rlim->rlim_max = (unsigned long)rlim64->rlim_max;
+}
+
+int do_prlimit(struct proc*tsk, unsigned int resource,
+		struct rlimit *new_rlim, struct rlimit *old_rlim)
+{
+      struct rlimit *rlim;
+      int ret=0;
+	if (resource >= RLIM_NLIMIT){
+    return -1;
+       }
+       if(new_rlim)
+       {
+         if(new_rlim->rlim_cur>new_rlim->rlim_max)
+         {
+           return -1;
+         }
+       }
+       rlim=tsk->rlim+resource;
+       if(new_rlim)
+       {
+          if(new_rlim->rlim_max>rlim->rlim_max)
+          {
+            return -1;
+          }
+       }
+       if(!ret)
+        {
+          if(old_rlim)
+          *old_rlim=*rlim;
+          
+         if(new_rlim)
+           *rlim=*new_rlim;  
+       }
+    return ret;
+}
+
+uint64 
+sys_prlimit64(void)
+{
+  uint64 addr1;
+  uint64 addr2;
+  pid_t pid;
+  uint64  resource;
+  struct rlimit new_rlim;
+  struct rlimit old_rlim;
+  // int ret=0;
+  // unsigned int checkflags=0;
+	// struct rlimit old, new;
+  struct proc*np;
+  
+  
+  if(argaddr(0,&pid)<0||argaddr(1,&resource)<0||argaddr(2,&addr1)<0||argaddr(3,&addr2)<0)
+  {
+    return  -1;
+  }
+  if(pid == 0) np = myproc();
+  else if((np = findproc(pid)) == NULL){
+    __ERROR("");
+    return -1;
+  }
+  if(copyin(myproc()->pagetable,(char*)&new_rlim,addr1,sizeof(struct rlimit)) < 0){
+    __ERROR("");
+    return -1;
+  }
+  if(addr2){
+    // __DEBUG("");
+    if(copyin(myproc()->pagetable,(char*)&old_rlim,addr2,sizeof(struct rlimit))<0){
+      __ERROR("");
+      return -1;
+    }
+    old_rlim.rlim_cur = np->rlim[resource].rlim_cur;
+    old_rlim.rlim_max = np->rlim[resource].rlim_max;
+    if(copyout(myproc()->pagetable,addr2, (char*)&old_rlim,sizeof(struct rlimit))<0){
+      __ERROR("");
+      return -1;
+    }
+  }
+  // __DEBUG("resource = %d",resource);
+  if(np->rlim[resource].rlim_cur) return 0;
+  // __DEBUG("rlim_cur = %p",new_rlim.rlim_cur);
+  // __DEBUG("rlim_max = %p",new_rlim.rlim_max);
+  np->rlim[resource].rlim_cur = new_rlim.rlim_cur;
+  np->rlim[resource].rlim_max = new_rlim.rlim_max;
+  // __DEBUG("%p",resource);
+  return 0;
+
+  // if(addr2)
+  // {
+  //   rlim64_to_rlim(&old_rlim, &old);
+  //   checkflags|= LSM_PRLIMIT_READ;
+   
+  // }
+  // if(new_rlim)
+  // {
+  //   rlim64_to_rlim(&new_rlim, &new);
+  //   checkflags |= LSM_PRLIMIT_WRITE;
+  // }
+  // np= findproc((int)pid);
+  // if(np!=NULL)
+  // {
+  //   ret=do_prlimit(np,resource,&new,&old);
+  // }
+  // return ret;
+}
+
+uint64 
+sys_lseek(void)
+{
+  int whence;
+  uint64 off;
+  struct file* f;
+
+  if(argfd(0, 0, &f) < 0){
+    __ERROR("read fd failed");
+    return -1;
+  }
+  if(argaddr(1,&off) < 0 || argint(2,&whence) < 0){
+    __ERROR("read register failed");
+    return -1;
+  }
+  off_t offset = (off_t)off;
+  switch (whence)
+  {
+  case SEEK_SET:
+    f->off = offset;
+    return offset;
+  case SEEK_CUR:
+    f->off = offset + f->off;
+    return f->off;
+  case SEEK_END:
+    f->off = f->ep->file_size + offset;
+    return f->off;
+  default:
+    return -1;
+  }
+}
+
+uint64
+sys_ioctl(void)
+{
+  #define TIOCGWINSZ	0x5413
+	#define TCGETS		0x5401
+  #define TIOCGPGRP	0x540F
+  #define RTC_RD_TIME 0xffffffff80247009
+
+	struct winsize {
+		uint16 ws_row;		/* rows, in character */
+		uint16 ws_col; 		/* columns, in characters */
+		uint16 ws_xpixel;	/* horizontal size, pixels (unused) */
+		uint16 ws_ypixel;	/* vertical size, pixels (unused) */
+	};
+
+	#define ICRNL		0000400
+	#define OPOST		0000001
+	#define ONLCR		0000004
+	#define ICANON	0000002
+	#define ECHO		0000010
+
+
+	struct termios {
+		uint16 c_iflag; /* 输入模式标志*/
+		uint16 c_oflag; /* 输出模式标志*/
+		uint16 c_cflag; /* 控制模式标志*/
+		uint16 c_lflag; /*区域模式标志或本地模式标志或局部模式*/
+		uint8 c_line; /*行控制line discipline */
+		uint8 c_cc[8]; /* 控制字符特性*/
+	};
+
+	int fd;
+	struct file *f;
+	uint64 request;
+	uint64 argp;
+
+	if (argfd(0, &fd, &f) < 0 || argaddr(1, &request) < 0 || argaddr(2, &argp) < 0)
+		return -EBADF;
+	//  __DEBUG("fd = %d, name = %s, type = %d, request = %p",fd,f->ep->filename,f->type,request);
+	if (f->type != FD_DEVICE)
+		return -EPERM;
+	switch (request) {
+  case RTC_RD_TIME: {
+		break;
+	}
+	case TIOCGWINSZ: {
+		struct winsize win = {
+			.ws_row = 24,
+			.ws_col = 80,
+		};
+		if (copyout(myproc()->pagetable, argp, (char*)&win, sizeof(win)) < 0)
+			return -EFAULT;
+		break;
+	}
+	case TCGETS: {
+		struct termios terminfo = {
+			.c_iflag = ICRNL,
+			.c_oflag = OPOST|ONLCR,
+			.c_cflag = 0,
+			.c_lflag = ICANON|ECHO,
+			.c_line = 0,
+			.c_cc = {0},
+		};
+		if (copyout(myproc()->pagetable, argp, (char*)&terminfo, sizeof(terminfo)) < 0)
+			return -EFAULT;
+		break;
+	}
+  // case TIOCGPGRP: {
+	// 	pid_t *pid = (pid_t *)argp;
+  //   *pid = 0;
+	// 	break;
+	// }
+	default:
+		return -EPERM;
+	}
+	return 0;
+
+  // return -1;
+}
+
+
+uint64
+sys_statfs(void)
+{
+  char  path[MAXPATH];
+  uint64 addr1;
+  struct  statvfs* stat;
+  struct dirent *dp;
+  int ret;
+  if(argstr(0,path,MAXPATH)<0||argaddr(1,&addr1)<0)
+  {
+    return -1;
+  }
+   if((dp=ename(path))==NULL)
+  {
+    printf("not found file\n");
+    return -1;
+  }
+  stat=(struct statvfs*)addr1;
+  
+  ret=do_statfs(stat,dp);
+return ret;
+}
+
+
+long do_utimes(int dfd,  char  *filename, struct timespec64 *times,
+	       int flags)
+{
+	if (*filename == NULL && dfd != AT_FDCWD)
+		return do_utimes_fd(dfd, times, flags);
+	return do_utimes_path(dfd, filename, times, flags);
+}
+
+
+uint64 
+sys_utimensat(void)
+{
+  int dfd;
+  char filename[MAXPATH];
+  struct timespec64 times[2];
+  uint64 addrs1;
+  int flags;
+  if(argint(0,&dfd)<0||argstr(1,filename,MAXPATH)<0||argaddr(2,&addrs1)<0||argint(3,&flags)<0)
+  {
+    return -1;
+  }
+  if(addrs1 == NULL){
+    uint64 tmp_ticks = r_time();
+    times[0].tv_nsec=(long)tmp_ticks / (CLK_FREQ / 100000);
+    times[0].tv_nsec=(times[0].tv_nsec % 100000) * 10000;
+    times[0].tv_sec=(long)tmp_ticks / CLK_FREQ;
+    times[1].tv_nsec=times[0].tv_nsec;
+    times[1].tv_sec=times[0].tv_sec;
+  }else{
+    times[0].tv_nsec=((struct timespec64*)addrs1)[0].tv_nsec;
+    times[0].tv_sec=((struct timespec64*)addrs1)[0].tv_sec;
+    times[1].tv_nsec=((struct timespec64*)addrs1)[1].tv_nsec;
+    times[1].tv_sec=((struct timespec64*)addrs1)[1].tv_sec;
+  }
+  if(times[0].tv_nsec==UTIME_OMIT&&
+  times[1].tv_nsec==UTIME_OMIT)
+  {
+   
+    return 0;
+  }
+  
+  return do_utimes(dfd,filename,times,flags);
+
+}
+
+uint64 sys_sendfile(void){
+  int out_fd, in_fd;
+  uint64 addr;
+  int count;
+  char buf[512];
+  memset(buf,0,512);
+  if(argint(0,&out_fd) < 0 || argint(1,&in_fd) < 0 || argaddr(2,&addr) < 0 || argint(3, &count) < 0){
+    __ERROR("read register failed");
+    return -1;
+  }
+  off_t off = 0;
+  off_t *offset = (off_t *)addr;
+  struct file *in_file = myproc()->ofile[in_fd];
+  struct file *out_file = myproc()->ofile[out_fd];
+  if(in_file->readable == 0 || out_file->writable == 0){
+    __ERROR("error");
+    return -EINVAL;
+  }
+  if(offset){
+    off = in_file->off;
+    in_file->off = *offset;
+  }
+  if(count > in_file->ep->file_size - in_file->off){
+    count = in_file->ep->file_size - in_file->off;
+  }
+  int n = 0;
+  while(n < count){
+    int i = count - n > 512 ? 512 : count - n;
+    fileread2(in_file, (uint64)buf, i);
+    filewrite2(out_file, (uint64)buf, i);
+    n += i;
+  }
+  if(offset){
+    *offset = in_file->off;
+    in_file->off = off;
+  }
+  return 0;
+}
+
+uint64 sys_renameat2(void){
+  int olddirfd; 
+  char oldpath[FAT32_MAX_PATH];
+  int newdirfd;
+  char newpath[FAT32_MAX_PATH];
+  int flags;
+  struct file *f1 = NULL;
+  struct file *f2 = NULL;
+  if(argint(0,&olddirfd) < 0 || argstr(1,oldpath,FAT32_MAX_PATH) < 0 || argint(2,&newdirfd) < 0
+    || argstr(3,newpath,FAT32_MAX_PATH) < 0 || argint(4,&flags) < 0){
+    __ERROR("error");
+    return -1;
+  }
+  if(*oldpath != '/' && olddirfd >= 0 && olddirfd < NOFILE){
+    f1 = myproc()->ofile[olddirfd];
+  }
+  if(*newpath != '/' && newdirfd >= 0 && newdirfd < NOFILE){
+    f2 = myproc()->ofile[newdirfd];
+  }
+  struct dirent *ep1 = ename2(oldpath, f1);
+  if(ep1 == NULL) return -ENOENT;
+  struct dirent *ep2 = ename2(newpath, f2);
+  if(ep2 != NULL){
+    unlink(newpath, f2);
+  }
+  return rename(oldpath,newpath,f1,f2);
+}
+
+uint64 sys_fcntl(void){
+  int fd, cmd;
+	struct file *f;
+	uint64 arg;
+	if (argfd(0, &fd, &f) < 0 || argint(1, &cmd) < 0)
+		return -1;
+  // __DEBUG("fd = %d, cmd = %d",fd,cmd);
+  struct proc *p = myproc();
+  if(cmd == F_GETFL){
+    int mode = 0;
+    if(f->readable && f->writable){
+      mode |= O_RDWR;
+    }
+    else if(f->readable){
+      mode |= O_RDONLY;
+    }
+    else if(f->writable){
+      mode |= O_WRONLY;
+    }
+    return mode;
+  }
+  // if(cmd == F_GETFD){
+  //   __DEBUG("GETFD");
+  //   return fd;
+  // }
+  // if(cmd == F_SETFD){
+  //   if(argaddr(2, &arg) < 0){
+  //     __ERROR("read register failed");
+  //     return -1;
+  //   }
+  //   int newfd = (int)newfd;
+  //   if(fd == newfd) return 0;
+  //   if(myproc()->ofile[newfd] != NULL){
+  //     fileclose(myproc()->ofile[newfd]);
+  //   }
+  //   // __DEBUG("%s %d to %d",f->ep->filename,fd,newfd);
+  //   myproc()->ofile[newfd] = f;
+  //   filedup(f);
+  //   return 0;
+  // }
+	if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
+    if(argaddr(2, &arg) < 0){
+      return -1;
+    }
+		int minfd = (int)arg;
+		if (minfd < 0)
+			return -1;
+    for(fd = minfd; fd < NOFILE; fd++){
+      if(p->rlim[RLIMIT_NOFILE].rlim_cur && fd >= p->rlim[RLIMIT_NOFILE].rlim_cur){
+        __DEBUG("%d",p->rlim[RLIMIT_NOFILE].rlim_cur);
+        return -EMFILE;
+      }
+      if(p->ofile[fd] == 0){
+        p->ofile[fd] = f;
+        filedup(f);
+        return fd;
+      }
+    }
+	}
+	return -1;
+}
+#define R_OK	4		/* Test for read permission.  */
+#define W_OK	2		/* Test for write permission.  */
+#define X_OK	1		/* Test for execute permission.  */
+#define F_OK	0		/* Test for existence.  */              
+
+uint64
+sys_faccessat(void)
+{
+  char path[MAXPATH];
+	int fd, mode, flags;
+	struct file *f = NULL;
+  struct dirent* ip;
+	if (argint(0, &fd) < 0) {
+		return -1;
+  }
+  
+	if (argstr(1, path, MAXPATH) < 0 || argint(2, &mode) < 0 || argint(3, &flags) < 0)
+		return -1;
+
+  if(*path != '/' && fd >= 0 && fd < NOFILE){
+    f = myproc()->ofile[fd];
+  }
+  ip = ename2(path, f);
+	if (ip != NULL) {
+		if (mode == F_OK) {
+			eput(ip);
+			return 0;
+		}
+	} else return -ENOENT;
+
+
+	return 0;
+}
+
+
+uint64  sys_readlinkat(void)
+{
+  int fd;
+  char path[MAXPATH];
+  uint64 buffer,size;
+  struct dirent*dp;
+  struct file*f=NULL;
+  int len;
+  if(argint(0,&fd)<0)
+  {
+    return -1;
+  }
+  if(argstr(1,path,MAXPATH)<0||argaddr(2,&buffer)<0||argaddr(3,&size)<0)
+  {
+    return -1;
+  }
+  if(strncmp(path,"/proc/self/exe",13)!=0)
+  {
+if(*path != '/' && fd >= 0 && fd < NOFILE){
+    f = myproc()->ofile[fd];
+  }
+  
+  dp = ename2(path, f);
+}
+else{
+  dp=myproc()->cwd;
+}
+  //__DEBUG("dp=%d       name=  %s",dp,path);
+  if(dp==NULL)
+  {
+    return -1;
+  }
+  len=namepath(dp,path,MAXPATH);
+  if(len>size)
+  {
+    len=size;
+  }
+  copyout(myproc()->pagetable,buffer,path,len);
+  //__DEBUG("buf=%s        path=%s",buffer,path);
+  return len;
+
+}
+
+
+uint64 sys_umask(void)
+{
+  int mode;
+  if(argint(0,&mode)<0){
+    return -1;
+  }
+  return -1;
+}
+
+void fdzero(struct fd_set *set){
+  for(int i = 0;i<NUMFDSET;i++)
+    set->fds_bits[i] = 0;
+}
+
+void fdset(struct fd_set *set ,int fd){
+  int n = fd/(sizeof(uint64) * 8);
+  int off = fd%(sizeof(uint64) * 8);
+  set->fds_bits[n] |= (1L<<off);
+}
+
+void fdclr(struct fd_set *set ,int fd){
+  int n = fd/(sizeof(uint64) * 8);
+  int off = fd%(sizeof(uint64) * 8);
+  set->fds_bits[n] &= ~(1L<<off);
+}
+
+int fdisset(const struct fd_set *set ,int fd){
+  int n = fd/(sizeof(uint64) * 8);
+  int off = fd%(sizeof(uint64) * 8);
+  return (set->fds_bits[n] & (1L<<off));
+}
+
+int testfdset(int nfds,const struct fd_set *read, const struct fd_set *write,const struct fd_set *except,
+struct fd_set *newread,struct fd_set *newwrite,struct fd_set *newexcept)
+{
+  struct proc *p = myproc();
+  int ret = 0;
+  for(int i = 0;i<nfds;i++){
+    if(fdisset(read,i)){
+      if(p->ofile[i] && p->ofile[i]->readable){
+        if(p->ofile[i]->type == FD_PIPE){
+          // __DEBUG("%d %d", p->ofile[i]->pipe->readopen,p->ofile[i]->pipe->writeopen);
+          if(p->ofile[i]->pipe->readopen){
+            fdset(newread,i);
+            ret++;
+          }
+        }else if(p->ofile[i]->type == FD_ENTRY){
+          if(!(p->ofile[i]->ep->lock.locked)){
+            fdset(newread,i);
+            ret++;
+          }
+        }else if(p->ofile[i]->type == FD_DEVICE){
+          if(!(p->ofile[i]->lock.locked)){
+            fdset(newread,i);
+            ret++;
+          }
+        }
+      }
+    }
+    if(fdisset(write,i)){
+      if(p->ofile[i] && p->ofile[i]->writable){
+        if(p->ofile[i]->type == FD_PIPE){
+          // __DEBUG("%d %d", p->ofile[i]->pipe->readopen,p->ofile[i]->pipe->writeopen);
+          if(p->ofile[i]->pipe->writeopen){
+            fdset(newread,i);
+            ret++;
+          }
+        }else if(p->ofile[i]->type == FD_ENTRY){
+          if(!(p->ofile[i]->ep->lock.locked)){
+            fdset(newread,i);
+            ret++;
+          }
+        }else if(p->ofile[i]->type == FD_DEVICE){
+          if(!(p->ofile[i]->lock.locked)){
+            fdset(newread,i);
+            ret++;
+          }
+        }
+      }
+    }
+  }
+  return ret;
+}
+
+uint64 sys_pselect(void){
+  int nfds;
+  uint64 readfds=0,writefds=0,errorfds=0,timeout=0,sigmask;
+  if (argint(0, &nfds) < 0 || argaddr(1, &readfds) < 0|| argaddr(2, &writefds) < 0|| argaddr(3, &errorfds) < 0||
+  argaddr(4, &timeout) < 0 || argaddr(5, &sigmask) < 0)
+	 	return -1;
+  if(nfds > BITSOFFDSET || nfds < 0) return -EINVAL;
+  struct proc *p = myproc();
+  sigset_t mid;
+  for(int i = 0; i<SIGSETSIZE;i++){
+    mid.__bits[i] = p->mask.__bits[i];
+  }
+  if(sigmask){
+    sigset_t *mask = (sigset_t *)sigmask;
+    for(int i = 0; i<SIGSETSIZE;i++){
+      p->mask.__bits[i] = mask->__bits[i];
+    }
+  }
+  struct fd_set readset,writeset,exceptset;
+  fdzero(&readset);
+  fdzero(&writeset);
+  fdzero(&exceptset);
+  if(readfds) copyin(p->pagetable, (char *)&readset, (uint64)readfds, sizeof(readset));
+  if(writefds) copyin(p->pagetable, (char *)&writeset, (uint64)writefds, sizeof(writeset));
+  if(errorfds) copyin(p->pagetable, (char *)&exceptset, (uint64)errorfds, sizeof(exceptset));
+  // __DEBUG("%p",readset.fds_bits[0]);
+  // __DEBUG("%p",writeset.fds_bits[0]);
+  // __DEBUG("%p",exceptset.fds_bits[0]);
+  struct fd_set newreadset,newwriteset,newexceptset;
+  fdzero(&newreadset);
+  fdzero(&newwriteset);
+  fdzero(&newexceptset);
+  int ret = 0;
+  if((ret = testfdset(nfds,&readset,&writeset,&exceptset,&newreadset,&newwriteset,&newexceptset)) > 0){
+    if(readfds) copyout(p->pagetable, (uint64)readfds, (char *)&newreadset, sizeof(newreadset));
+    if(writefds) copyout(p->pagetable, (uint64)writefds, (char *)&newwriteset, sizeof(newwriteset));
+    if(errorfds) copyout(p->pagetable, (uint64)errorfds, (char *)&newexceptset, sizeof(newexceptset));
+    for(int i = 0; i<SIGSETSIZE;i++){
+      p->mask.__bits[i] = mid.__bits[i];
+    }
+    // __DEBUG("%p",newreadset.fds_bits[0]);
+    // __DEBUG("%p",newwriteset.fds_bits[0]);
+    // __DEBUG("%p",newexceptset.fds_bits[0]);
+    return ret;
+  }
+  struct timespec *time = (struct timespec *)timeout;
+  TimeVal tv;
+  tv.sec = 0, tv.usec = 100000;
+  if(time){
+    int n = (time->tv_sec) * 10 + (time->tv_nsec/100000000);
+    while(n){
+      if(myproc()->killed||gain_sleep(&tv)==0){
+        return -EINTR;
+      }
+      acquire(&p->lock);  
+      p->state = SLEEPING;
+      // __DEBUG("pid %d sleep",p->pid);
+      sched();
+      release(&p->lock);
+      if((ret = testfdset(nfds,&readset,&writeset,&exceptset,&newreadset,&newwriteset,&newexceptset)) > 0){
+        if(readfds) copyout(p->pagetable, (uint64)readfds, (char *)&newreadset, sizeof(newreadset));
+        if(writefds) copyout(p->pagetable, (uint64)writefds, (char *)&newwriteset, sizeof(newwriteset));
+        if(errorfds) copyout(p->pagetable, (uint64)errorfds, (char *)&newexceptset, sizeof(newexceptset));
+        for(int i = 0; i<SIGSETSIZE;i++){
+          p->mask.__bits[i] = mid.__bits[i];
+        }
+        // __DEBUG("%p",newreadset.fds_bits[0]);
+        // __DEBUG("%p",newwriteset.fds_bits[0]);
+        // __DEBUG("%p",newexceptset.fds_bits[0]);
+        return ret;
+      }
+      n--;
+    }
+    if(readfds) copyout(p->pagetable, (uint64)readfds, (char *)&newreadset, sizeof(newreadset));
+    if(writefds) copyout(p->pagetable, (uint64)writefds, (char *)&newwriteset, sizeof(newwriteset));
+    if(errorfds) copyout(p->pagetable, (uint64)errorfds, (char *)&newexceptset, sizeof(newexceptset));
+    for(int i = 0; i<SIGSETSIZE;i++){
+      p->mask.__bits[i] = mid.__bits[i];
+    }
+    // __DEBUG("%p",newreadset.fds_bits[0]);
+    // __DEBUG("%p",newwriteset.fds_bits[0]);
+    // __DEBUG("%p",newexceptset.fds_bits[0]);
+    return 0;
+  }else{
+    while(1){
+      if(myproc()->killed||gain_sleep(&tv)==0){
+        return -EINTR;
+      }
+      acquire(&p->lock);  
+      p->state = SLEEPING;
+      // __DEBUG("pid %d sleep",p->pid);
+      sched();
+      release(&p->lock);
+      if((ret = testfdset(nfds,&readset,&writeset,&exceptset,&newreadset,&newwriteset,&newexceptset)) > 0){
+        if(readfds) copyout(p->pagetable, (uint64)readfds, (char *)&newreadset, sizeof(newreadset));
+        if(writefds) copyout(p->pagetable, (uint64)writefds, (char *)&newwriteset, sizeof(newwriteset));
+        if(errorfds) copyout(p->pagetable, (uint64)errorfds, (char *)&newexceptset, sizeof(newexceptset));
+        for(int i = 0; i<SIGSETSIZE;i++){
+          p->mask.__bits[i] = mid.__bits[i];
+        }
+        return ret;
+      }
+    }
+  }
+}
diff --git a/kernel/sysproc.c b/kernel/sysproc.c
new file mode 100644
index 0000000000000000000000000000000000000000..be2aaf9fb21e7c66ab9b6ec8e8544924ff6daf09
--- /dev/null
+++ b/kernel/sysproc.c
@@ -0,0 +1,621 @@
+
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/spinlock.h"
+#include "include/proc.h"
+#include "include/syscall.h"
+#include "include/timer.h"
+#include "include/kalloc.h"
+#include "include/string.h"
+#include "include/printf.h"
+#include "include/vm.h"
+#include "include/errno.h"
+
+extern int exec(char *path, char **argv,char **argp);
+extern int do_execve(char *path, char **argv,char **envp);
+
+uint64
+sys_exec(void)
+{
+ char path[FAT32_MAX_PATH], *argv[MAXARG];
+  int i;
+  uint64 uargv, uarg;
+
+  if(argstr(0, path, FAT32_MAX_PATH) < 0 || argaddr(1, &uargv) < 0){
+    return -1;
+  }
+  memset(argv, 0, sizeof(argv));
+  for(i=0;uargv!=0; i++){
+    if(i >= NELEM(argv)){
+      __ERROR("1");
+      goto bad;
+    }
+    if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){
+      __ERROR("2");
+      goto bad;
+    }
+    if(uarg == 0){
+      argv[i] = 0;
+      break;
+    }
+    argv[i] = kalloc();
+    if(argv[i] == 0){
+      __ERROR("3");
+      goto bad;
+    }
+    if(fetchstr(uarg, argv[i], PGSIZE) < 0){
+      __ERROR("4");
+      goto bad;
+    }
+  }
+  int ret = exec(path, argv,0);
+  
+  for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
+    kfree(argv[i]);
+  return ret;
+  
+  bad:
+  for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
+    kfree(argv[i]);
+  return -1;
+}
+
+uint64 sys_execve(void){
+  char filename[FAT32_MAX_PATH];
+  uint64 argv;
+  uint64 argp;
+  if(argstr(0, filename, FAT32_MAX_PATH) < 0 || argaddr(1, &argv) || argaddr(2, &argp)){
+    return -1;
+  }
+  return exec(filename,(char **)argv,(char **)argp);
+}
+
+uint64
+sys_exit(void)
+{
+  int n;
+  if(argint(0, &n) < 0)
+    return -1;
+  exit(n);
+  return 0;  // not reached
+}
+
+uint64
+sys_getpid(void)
+{
+  return myproc()->pid;
+}
+
+uint64 
+sys_getppid(void) {
+	struct proc *p = myproc();
+	int pid;
+
+	pid = p->parent->pid;
+
+	return pid;
+}
+
+uint64
+sys_fork(void)
+{
+  return do_clone(0,0,0,0,0);
+}
+
+uint64 
+sys_syslog(void)
+{
+  return 0;
+}
+
+
+uint64
+sys_wait(void)
+{
+  uint64 p;
+  if(argaddr(0, &p) < 0)
+    return -1;
+  return wait(p);
+}
+
+uint64
+sys_waitpid(void){
+  uint64 pid,wstatus,options;
+  if(argaddr(0, &pid) < 0||argaddr(1, &wstatus) < 0||argaddr(0, &options) < 0){
+    __ERROR("read register failed");
+    return -1;
+  }
+  return do_waitpid((int)pid,wstatus,(int)options);
+}
+
+uint64
+sys_sbrk(void)
+{
+  struct proc *p = myproc();
+  int addr;
+  int n;
+  if(argint(0, &n) < 0)
+    return -1;
+  n = PGROUNDUP(n);
+  if(p->sz + n >= VMMAP_BASE){
+    return -1;
+  }
+  addr = p->sbrk_base + p->sbrk_size;
+  if(growproc(n) < 0)
+    return -1;
+  return addr;
+}
+
+uint64 sys_brk(void)
+{
+  struct proc *p = myproc();
+  uint64 addr;
+  if(argaddr(0, &addr) < 0)
+    return -1;
+  uint64 start = p->sbrk_base + p->sbrk_size;
+  if(addr == 0) return start;
+  addr = PGROUNDUP(addr);
+  int n = addr - start;
+  if(p->sz + n >= VMMAP_BASE){
+    return -1;
+  }
+  if(growproc(n) < 0)
+    return -1;
+  return start;
+}
+
+uint64
+sys_sleep(void)
+{
+  int n;
+  uint ticks0;
+
+  if(argint(0, &n) < 0)
+    return -1;
+  acquire(&tickslock);
+  ticks0 = ticks;
+  while(ticks - ticks0 < n){
+    // printf("sleeping %d\n",ticks - ticks0);
+    if(myproc()->killed){
+      release(&tickslock);
+      return -1;
+    }
+    sleep(&ticks, &tickslock);
+  }
+  release(&tickslock);
+  return 0;
+}
+
+
+// return how many clock tick interrupts have occurred
+// since start.
+uint64
+sys_uptime(void)
+{
+  uint xticks;
+
+  acquire(&tickslock);
+  xticks = ticks;
+  release(&tickslock);
+  return xticks;
+}
+
+uint64
+sys_times(void)
+{
+  struct proc *p=myproc();
+  uint64 addr_tms;
+  uint xticks;
+  if(argaddr(0, &addr_tms) < 0) {
+    return -1;
+  }
+  struct tms *t=(struct tms*)addr_tms;
+
+  if(t!=0){
+    t->tms_cstime=p->ti.tms_cstime;
+    t->tms_cutime=p->ti.tms_cutime;
+    t->tms_stime=p->ti.tms_stime;
+    t->tms_utime=p->ti.tms_utime;
+  }
+  //printf("ddd");
+  acquire(&tickslock);
+  xticks = ticks;
+  release(&tickslock);
+  return xticks;
+}
+
+uint64
+sys_trace(void)
+{
+  int mask;
+  if(argint(0, &mask) < 0) {
+    return -1;
+  }
+  myproc()->tmask = mask;
+  return 0;
+}
+
+uint64 sys_clone(void){
+  uint64 flags, stack,ptid,tls,ctid;
+	if (argaddr(0, &flags) < 0||argaddr(1, &stack) < 0||argaddr(1, &ptid) < 0||argaddr(1, &tls) < 0||argaddr(1, &ctid) < 0) 
+		return -1;
+  return do_clone(stack,flags,ptid,tls,ctid);
+}
+
+uint64 sys_mmap(void){
+  uint64 start, len, prot, flags, fd, off;
+  if (argaddr(0, &start) < 0||argaddr(1, &len) < 0||argaddr(2, &prot)||argaddr(3, &flags)||argaddr(4, &fd)||argaddr(5, &off)){
+    __ERROR("");
+		return -1;
+  }
+  // printf("mmap---------------->start:%d (long)len:%d ,prot:%d flags:%d fd:%d off:%d\n",start, len, prot, flags, fd, off);
+  return do_mmap(start, (long)len, prot, flags, fd, off);
+}
+
+uint64 sys_munmap(void){
+  uint64 start, len;
+  if (argaddr(0, &start) < 0||argaddr(1, &len) < 0){
+    return -1;
+  }
+  // __DEBUG("start:%d   len:%d   ",start,len);
+  return do_munmap(start,(long)len);
+}
+
+uint64 sys_msync(void){
+  uint64 start, len; 
+  int flags;
+  if (argaddr(0, &start) < 0||argaddr(1, &len) < 0||argint(2,&flags)){
+    return -1;
+  }
+  if(start%PGSIZE){
+    return -1;
+  }
+  return do_msync(start,len,flags);
+}
+uint64 sys_rt_sigprocmask(void){
+  int how;
+  uint64 set,oldset;
+  if(argint(0,&how) < 0 || argaddr(1,&set) < 0 || argaddr(2, &oldset) < 0){
+    __ERROR("read registers failed");
+    return -1;
+  }
+ 
+  // __DEBUG("%p",((sigset_t *)set)->__bits[0]);
+  sigset_t a;
+  if(set){
+    // __DEBUG("%p",set);
+    if(copyin(myproc()->pagetable, (char *)&a, set, sizeof(sigset_t)) < 0)
+      return -1;
+  }
+  if(oldset){
+    struct proc *p = myproc();
+    // __DEBUG("oldset = %p",oldset);
+    if(copyout(myproc()->pagetable, oldset, (char *)&p->mask, sizeof(sigset_t)) < 0)
+      return -1;
+  }
+  return sigprocmask(how, &a);
+
+}
+
+uint64 sys_rt_sigaction(void){
+  int sig;
+  uint64 act;
+  uint64 oldact;
+  if(argint(0,&sig) < 0 || argaddr(1,&act) < 0 || argaddr(2,&oldact) < 0){
+    __ERROR("read registers failed");
+    return -1;
+  }
+  // __DEBUG("%d",sig);
+  struct sigaction new;
+
+  // __DEBUG("%p",a);
+  if(act && copyin(myproc()->pagetable ,(char *)&(new.sa_handler), act, sizeof(__sighandler_t)) < 0){
+    __ERROR("copy failed");
+    return -1;
+  }
+
+  
+  return sigaction(sig, &new);
+}
+
+uint64 sys_rt_sigtimedwait(void){
+  uint64 a,b,c;
+  sigset_t set;
+  struct timespec timeout;
+
+  if(argaddr(0,&a) < 0 || argaddr(1,&b) < 0 || argaddr(2, &c) < 0){
+    __ERROR("read registers failed");
+    return -1;
+  }
+
+  if(a && copyin(myproc()->pagetable, (char *)&set, a, sizeof(sigset_t)) < 0)
+    return -1;
+
+  if(c){
+    if(copyin(myproc()->pagetable, (char *)&timeout, c, sizeof(struct timespec)) < 0)
+      return -1;
+  }
+
+  struct proc *p = myproc();
+
+  int ret;
+  if((ret = sigfind(&p->pending, &set)) > 0)
+    return ret;
+  
+  TimeVal tv;
+  tv.sec = 0;
+  tv.usec = 100000;
+
+  if(c){
+    int n = (timeout.tv_sec) * 10 + (timeout.tv_nsec/100000000);
+    while(n){
+      if(myproc()->killed||gain_sleep(&tv)==0){
+        return -EINTR;
+      }
+      acquire(&p->lock);  
+      p->state = SLEEPING;
+      __DEBUG("pid %d sleep",p->pid);
+      sched();
+      release(&p->lock);
+      
+      if((ret = sigfind(&p->pending, &set)) > 0){
+        return ret;
+      }
+      n--;
+    }
+    return -EAGAIN;
+  }else{
+    while(1){
+      
+      if(myproc()->killed||gain_sleep(&tv)==0){
+        return -EINTR;
+      }
+      acquire(&p->lock);  
+      p->state = SLEEPING;
+      __DEBUG("pid %d sleep",p->pid);
+      sched();
+      release(&p->lock);
+      if((ret = sigfind(&p->pending, &set)) > 0)
+        return ret;
+    }
+  }
+}
+
+uint64 sys_set_tid_address(void){
+  uint64 tidptr;
+  if (argaddr(0, &tidptr) < 0){
+    return -1;
+  }
+  return do_set_tid_address((int*)tidptr);
+}
+
+
+uint64 sys_exit_group(void){
+  int status;
+  if (argint(0, &status) < 0){
+    return -1;
+  }
+  do_exit_group(status);
+  return 0;
+}
+
+uint64 sys_gettid(void){
+  return do_gettid();
+}
+
+uint64 sys_kill(void){
+  int pid,sig;
+  if(argint(0, &pid) < 0||argint(1, &sig) < 0)
+    return -1;
+  
+  return do_kill(pid,sig);
+}
+
+uint64 sys_futex(void){
+  uint64 uaddr,timeout,uaddr2;
+  int op,val,val3;
+  if(argaddr(0, &uaddr) < 0||argint(1, &op) < 0||argint(2, &val) < 0||argaddr(3, &timeout) < 0||argaddr(4, &uaddr2) < 0||argint(5, &val3) < 0)
+    return -1;
+  return do_futex((int*)uaddr,op,val,(struct timespec*)timeout,(int*)uaddr2,val3);
+}
+
+uint64 sys_mprotect(void){
+  struct proc *p = myproc();
+  uint64 addr, len;
+  int prot;
+  if(argaddr(0,&addr) < 0 || argaddr(1,&len)<0||argint(2,&prot) < 0){
+    __ERROR("read register failed");
+    return -EPERM;
+  }
+  // __DEBUG("mprotect---------->addr:%p  len:%p",addr,len);
+  addr = PGROUNDDOWN(addr);
+  len = PGROUNDUP(len);
+  // __DEBUG("addr = %p , len = %p",addr,len);
+  if(addr + len > p->sz && addr - VMMAP_BASE > p->mmap_size && addr < p->ustack_base) {
+    // __ERROR("over size");
+    return -EINVAL;
+  }
+  if((prot & PROT_GROWSDOWN) && (prot & PROT_GROWSUP)){
+    __ERROR("");
+    return -EINVAL;
+  }
+  prot = (prot << 1) & (PTE_X|PTE_W|PTE_R);
+  // __DEBUG("prot = %p",prot);
+  for(int i = addr;i < addr + len;i+=PGSIZE){
+    pte_t *pte = walk(p->pagetable,i,0);
+    pte_t *kpte = walk(p->kpagetable,i,0);
+    int copy_when_write = 0;
+    if(pte == NULL) return -EACCES;
+    else {
+      if((*pte & PTE_C) && (prot & PTE_W)){
+        copy_when_write = 1;
+      }
+      if(*pte & PTE_V){
+        *pte = PA2PTE(PTE2PA(*pte)) | prot | PTE_V | PTE_U;
+        *kpte = *pte & (~PTE_U);
+      }else{
+        *pte = PA2PTE(PTE2PA(*pte)) | prot | PTE_U;
+        *kpte = *pte & (~PTE_U);
+      }
+      if(copy_when_write){
+        *pte |= PTE_C;
+        *kpte |= PTE_C;
+      }
+      // __DEBUG("pa = %p, flags = %p",PTE2PA(*pte), PTE_FLAGS(*pte));
+    }
+  }
+  return 0;
+}
+
+uint64 sys_clock_gettime(void){
+  int which_clock;
+  uint64 tp;
+  if (argint(0, &which_clock) < 0 ||argaddr(1, &tp) < 0) {
+		return -EINVAL;
+	}
+  struct timespec *ptp=(struct timespec*)tp;
+  uint64 tmp_ticks = r_time();
+  switch(which_clock){
+    case CLOCK_REALTIME:
+	    if(ptp!=0){
+        ptp->tv_sec = (long)tmp_ticks / CLK_FREQ;
+	      ptp->tv_nsec = (long)tmp_ticks / (CLK_FREQ / 100000);
+	      ptp->tv_nsec = (ptp->tv_nsec % 100000) * 10000;
+
+
+        // __DEBUG("ptp->tv_sec:%d",ptp->tv_sec);
+        // __DEBUG("ptp->tv_nsec:%d",ptp->tv_nsec);
+      }
+      return 0;
+    case CLOCK_MONOTONIC:
+    case CLOCK_PROCESS_CPUTIME_ID:
+    case CLOCK_THREAD_CPUTIME_ID:
+    default:
+      break;
+  }
+  return -1;
+}
+
+uint64 sys_clock_settime(void){
+  int which_clock;
+  uint64 tp;
+  if (argint(0, &which_clock) < 0 ||argaddr(1, &tp) < 0) {
+		return -EINVAL;
+	}
+  if (CLOCK_REALTIME != which_clock) {
+		return -EINVAL;
+	}
+  return 0;
+}
+
+uint64
+sys_getuid(void)
+{
+	return 0;
+}
+
+static int do_setitimer(int which, struct itimerval *value,
+			struct itimerval *ovalue)
+{
+
+  TimeVal tv;
+  
+    switch(which)
+    {
+      case ITIMER_REAL:
+        tv.sec=value-> it_value.tv_sec;
+        tv.usec=value->it_value.tv_usec;
+         gain_sleep(&tv);
+          break;
+         case  ITIMER_VIRTUAL:
+         break;
+         case ITIMER_PROF:
+         break;
+         default:
+              return -ENAVAIL;
+    }
+	return 0;
+}
+
+
+
+uint64 sys_setitimer(void)
+{
+   int which; 
+    uint64 address1,address2;
+  struct itimerval * new_timer1,*old_timer2;
+  int ret;
+    if(argint(0,&which)<0||argaddr(1,&address1)<0||argaddr(2,&address2)<0)
+    {
+      return -1;
+    }
+  new_timer1=(struct itimerval*)address1;
+  old_timer2=(struct itimerval*)address2;
+  if(new_timer1==NULL)
+  {
+    __ERROR("new-value==NULL");
+    return -1;
+  }
+ret=do_setitimer(which,new_timer1,old_timer2);
+  return ret;
+
+}
+
+uint64 sys_tgkill(void)
+{
+  int tgid,tid,sig;
+  if(argint(0,&tgid) < 0 || argint(1,&tid) < 0 || argint(2,&sig) < 0){
+    return -1;
+  }
+  if(sendsignal(tgid,sig) < 0)
+    return -ESRCH;
+  return 0;
+}
+
+static inline void convert_to_timeval(uint64 time, struct timeval *tv)
+{
+	tv->tv_sec = time / CLK_FREQ;
+	tv->tv_usec = (time % CLK_FREQ) * 1000 / (CLK_FREQ / 1000);
+}
+
+static inline uint64 convert_from_timespec(const struct timespec *ts)
+{
+	uint64 time = ts->tv_sec * CLK_FREQ
+					+ ts->tv_nsec * (CLK_FREQ / 1000 / 100) / 10 / 1000;
+	return time;
+}
+
+uint64 sys_getrusage(void){
+  int who;
+	uint64 addr;
+	struct rusage r;
+	struct proc *p = myproc();
+
+	argint(0, &who);
+	argaddr(1, &addr);
+
+	memset(&r, 0, sizeof(r));
+	switch (who)
+	{
+		case RUSAGE_SELF:
+		case RUSAGE_THREAD:
+			convert_to_timeval(p->ti.tms_utime, &r.ru_utime);
+			convert_to_timeval(p->ti.tms_stime, &r.ru_stime);
+			r.ru_nvcsw = p->vswtch;
+			r.ru_nivcsw = p->ivswtch;
+			break;
+		case RUSAGE_CHILDREN:
+			convert_to_timeval(p->ti.tms_cutime, &r.ru_utime);
+			convert_to_timeval(p->ti.tms_cstime, &r.ru_stime);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	if (copyout(p->pagetable ,addr, (char *)&r, sizeof(r)) < 0)
+		return -EFAULT;
+
+	return 0;
+}
\ No newline at end of file
diff --git a/kernel/timer.c b/kernel/timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..e5957a9ecf5ad26f959f3a47514ae3ae8d7cd82c
--- /dev/null
+++ b/kernel/timer.c
@@ -0,0 +1,99 @@
+// Timer Interrupt handler
+
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/riscv.h"
+#include "include/sbi.h"
+#include "include/spinlock.h"
+#include "include/timer.h"
+#include "include/printf.h"
+#include "include/proc.h"
+
+struct spinlock tickslock;
+uint ticks;
+
+struct sleep_proc sleep_procs[N_SLEEP_PRCO];
+
+
+int gain_sleep(TimeVal *tv){
+    struct sleep_proc* sp;
+    for(sp=sleep_procs;sp<&sleep_procs[N_SLEEP_PRCO];++sp){
+        acquire(&sp->lock);
+        if(sp->p==0){
+            sp->p=myproc();
+            sp->sleep_ticks=ticks + tv->sec*CLK_FREQ/INTERVAL + tv->usec*(CLK_FREQ/100000)/10/INTERVAL;
+            release(&sp->lock);
+            return 1;
+        }
+        release(&sp->lock);
+    }
+    return 0;
+}
+
+void timerinit() {
+    initlock(&tickslock, "time");
+    #ifdef DEBUG
+    printf("timerinit\n");
+    #endif
+
+    struct sleep_proc* sp;
+
+    for(sp=sleep_procs;sp<&sleep_procs[N_SLEEP_PRCO];++sp){
+        initlock(&sp->lock,"sleep");
+        sp->p=0;
+    }
+}
+
+void
+set_next_timeout() {
+    // There is a very strange bug,
+    // if comment the `printf` line below
+    // the timer will not work.
+
+    // this bug seems to disappear automatically
+    // printf("");
+    sbi_set_timer(r_time() + INTERVAL);
+}
+
+
+void wakeup_sleep(){
+    struct sleep_proc* sp;
+    for(sp=sleep_procs;sp<&sleep_procs[N_SLEEP_PRCO];++sp){
+        acquire(&sp->lock);
+        if(sp->p!=0){
+            if(sp->p->killed){
+                sp->p=0;
+            }
+            else{
+                if(ticks>sp->sleep_ticks){
+                    struct proc* p=sp->p;
+                    acquire(&p->lock);
+                    if(sp->p->state==SLEEPING){
+                        sp->p->state=RUNNABLE;
+                        sp->p=0;
+                    }
+                    release(&p->lock);
+                }
+            }
+        }
+        release(&sp->lock);
+    }
+}
+
+void timer_tick(int cpl) {
+    struct proc* p=myproc();
+    if(p!=0){
+        if(cpl==1){
+            ++p->ti.tms_stime;
+        }
+        else{
+            ++p->ti.tms_utime;
+        }
+    }
+    acquire(&tickslock);
+    ticks++;
+    wakeup_sleep();
+    release(&tickslock);
+    set_next_timeout();
+}
diff --git a/kernel/trampoline.S b/kernel/trampoline.S
new file mode 100644
index 0000000000000000000000000000000000000000..a3e1b8731cfd966832dbbe93127562de37768e91
--- /dev/null
+++ b/kernel/trampoline.S
@@ -0,0 +1,225 @@
+	#
+        # code to switch between user and kernel space.
+        #
+        # this code is mapped at the same virtual address
+        # (TRAMPOLINE) in user and kernel space so that
+        # it continues to work when it switches page tables.
+	#
+	# kernel.ld causes this to be aligned
+        # to a page boundary.
+        #
+	.section trampsec
+.globl trampoline
+trampoline:
+.align 4
+.globl uservec
+uservec:    
+	#
+        # trap.c sets stvec to point here, so
+        # traps from user space start here,
+        # in supervisor mode, but with a
+        # user page table.
+        #
+        # sscratch points to where the process's p->trapframe is
+        # mapped into user space, at TRAPFRAME.
+        #
+        
+	# swap a0 and sscratch
+        # so that a0 is TRAPFRAME
+        csrrw a0, sscratch, a0
+
+        # save the user registers in TRAPFRAME
+        sd ra, 40(a0)
+        sd sp, 48(a0)
+        sd gp, 56(a0)
+        sd tp, 64(a0)
+        sd t0, 72(a0)
+        sd t1, 80(a0)
+        sd t2, 88(a0)
+        sd s0, 96(a0)
+        sd s1, 104(a0)
+        sd a1, 120(a0)
+        sd a2, 128(a0)
+        sd a3, 136(a0)
+        sd a4, 144(a0)
+        sd a5, 152(a0)
+        sd a6, 160(a0)
+        sd a7, 168(a0)
+        sd s2, 176(a0)
+        sd s3, 184(a0)
+        sd s4, 192(a0)
+        sd s5, 200(a0)
+        sd s6, 208(a0)
+        sd s7, 216(a0)
+        sd s8, 224(a0)
+        sd s9, 232(a0)
+        sd s10, 240(a0)
+        sd s11, 248(a0)
+        sd t3, 256(a0)
+        sd t4, 264(a0)
+        sd t5, 272(a0)
+        sd t6, 280(a0)
+
+        # fsd ft0, 288(a0)
+	# fsd ft1, 296(a0)
+	# fsd ft2, 304(a0)
+	# fsd ft3, 312(a0)
+	# fsd ft4, 320(a0)
+	# fsd ft5, 328(a0)
+	# fsd ft6, 336(a0)
+	# fsd ft7, 344(a0)
+	# fsd fs0, 352(a0)
+	# fsd fs1, 360(a0)
+	# fsd fa0, 368(a0)
+	# fsd fa1, 376(a0)
+	# fsd fa2, 384(a0)
+	# fsd fa3, 392(a0)
+	# fsd fa4, 400(a0)
+	# fsd fa5, 408(a0)
+	# fsd fa6, 416(a0)
+	# fsd fa7, 424(a0)
+	# fsd fs2, 432(a0)
+	# fsd fs3, 440(a0)
+	# fsd fs4, 448(a0)
+	# fsd fs5, 456(a0)
+	# fsd fs6, 464(a0)
+	# fsd fs7, 472(a0)
+	# fsd fs8, 480(a0)
+	# fsd fs9, 488(a0)
+	# fsd fs10, 496(a0)
+	# fsd fs11, 504(a0)
+	# fsd ft8, 512(a0)
+	# fsd ft9, 520(a0)
+	# fsd ft10, 528(a0)
+	# fsd ft11, 536(a0)
+        # fcsr;
+
+	# save the user a0 in p->trapframe->a0
+        csrr t0, sscratch
+        sd t0, 112(a0)
+
+        # restore kernel stack pointer from p->trapframe->kernel_sp
+        ld sp, 8(a0)
+
+        # make tp hold the current hartid, from p->trapframe->kernel_hartid
+        ld tp, 32(a0)
+
+        # load the address of usertrap(), p->trapframe->kernel_trap
+        ld t0, 16(a0)
+
+        # restore kernel page table from p->trapframe->kernel_satp
+        ld t1, 0(a0)
+        csrw satp, t1
+
+        # sfence.vma zero, zero
+        #sfence.vma
+        fence
+        fence.i
+        sfence.vma
+        fence
+        fence.i
+
+        # a0 is no longer valid, since the kernel page
+        # table does not specially map p->tf.
+
+        # jump to usertrap(), which does not return
+        jr t0
+
+.globl userret
+userret:
+        # userret(TRAPFRAME, pagetable)
+        # switch from kernel to user.
+        # usertrapret() calls here.
+        # a0: TRAPFRAME, in user page table.
+        # a1: user page table, for satp.
+
+        # switch to the user page table.
+
+
+        csrw satp, a1
+
+        # sfence.vma zero, zero
+        #sfence.vma
+        fence
+        fence.i
+        sfence.vma
+        fence
+        fence.i
+        
+        # put the saved user a0 in sscratch, so we
+        # can swap it with our a0 (TRAPFRAME) in the last step.
+        ld t0, 112(a0)
+        csrw sscratch, t0
+
+        # restore all but a0 from TRAPFRAME
+        ld ra, 40(a0)
+        ld sp, 48(a0)
+        ld gp, 56(a0)
+        ld tp, 64(a0)
+        ld t0, 72(a0)
+        ld t1, 80(a0)
+        ld t2, 88(a0)
+        ld s0, 96(a0)
+        ld s1, 104(a0)
+        ld a1, 120(a0)
+        ld a2, 128(a0)
+        ld a3, 136(a0)
+        ld a4, 144(a0)
+        ld a5, 152(a0)
+        ld a6, 160(a0)
+        ld a7, 168(a0)
+        ld s2, 176(a0)
+        ld s3, 184(a0)
+        ld s4, 192(a0)
+        ld s5, 200(a0)
+        ld s6, 208(a0)
+        ld s7, 216(a0)
+        ld s8, 224(a0)
+        ld s9, 232(a0)
+        ld s10, 240(a0)
+        ld s11, 248(a0)
+        ld t3, 256(a0)
+        ld t4, 264(a0)
+        ld t5, 272(a0)
+        ld t6, 280(a0)
+
+        # fld ft0, 288(a0)
+	# fld ft1, 296(a0)
+	# fld ft2, 304(a0)
+	# fld ft3, 312(a0)
+	# fld ft4, 320(a0)
+	# fld ft5, 328(a0)
+	# fld ft6, 336(a0)
+	# fld ft7, 344(a0)
+	# fld fs0, 352(a0)
+	# fld fs1, 360(a0)
+	# fld fa0, 368(a0)
+	# fld fa1, 376(a0)
+	# fld fa2, 384(a0)
+	# fld fa3, 392(a0)
+	# fld fa4, 400(a0)
+	# fld fa5, 408(a0)
+	# fld fa6, 416(a0)
+	# fld fa7, 424(a0)
+	# fld fs2, 432(a0)
+	# fld fs3, 440(a0)
+	# fld fs4, 448(a0)
+	# fld fs5, 456(a0)
+	# fld fs6, 464(a0)
+	# fld fs7, 472(a0)
+	# fld fs8, 480(a0)
+	# fld fs9, 488(a0)
+	# fld fs10, 496(a0)
+	# fld fs11, 504(a0)
+	# fld ft8, 512(a0)
+	# fld ft9, 520(a0)
+	# fld ft10, 528(a0)
+	# fld ft11, 536(a0)
+        
+	# restore user a0, and save TRAPFRAME in sscratch
+        csrrw a0, sscratch, a0
+
+        # return to user mode and user pc.
+        # usertrapret() set up sstatus and sepc.
+        sret
+
diff --git a/kernel/trap.c b/kernel/trap.c
new file mode 100644
index 0000000000000000000000000000000000000000..dd6bc60915d01dde2d89106b96a1c62315fc1d1e
--- /dev/null
+++ b/kernel/trap.c
@@ -0,0 +1,440 @@
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+#include "include/spinlock.h"
+#include "include/proc.h"
+#include "include/sbi.h"
+#include "include/plic.h"
+#include "include/trap.h"
+#include "include/syscall.h"
+#include "include/printf.h"
+#include "include/console.h"
+#include "include/timer.h"
+#include "include/disk.h"
+#include "include/vm.h"
+#include "include/kalloc.h"
+#include "include/string.h"
+
+extern char trampoline[], uservec[], userret[];
+
+uchar const storefloat[] __attribute__((section("_storefloat"))) = {
+  0x41, 0x11, 0x22, 0xE4, 0x26, 0xE0, 0x00, 0x08, 0x27, 0x30, 0x05, 0x12, 0x27, 0x34, 0x15, 0x12,
+	0x27, 0x38, 0x25, 0x12, 0x27, 0x3C, 0x35, 0x12, 0x27, 0x30, 0x45, 0x14, 0x27, 0x34, 0x55, 0x14,
+	0x27, 0x38, 0x65, 0x14, 0x27, 0x3C, 0x75, 0x14, 0x27, 0x30, 0x85, 0x16, 0x27, 0x34, 0x95, 0x16,
+	0x27, 0x38, 0xA5, 0x16, 0x27, 0x3C, 0xB5, 0x16, 0x27, 0x30, 0xC5, 0x18, 0x27, 0x34, 0xD5, 0x18,
+	0x27, 0x38, 0xE5, 0x18, 0x27, 0x3C, 0xF5, 0x18, 0x27, 0x30, 0x05, 0x1B, 0x27, 0x34, 0x15, 0x1B,
+	0x27, 0x38, 0x25, 0x1B, 0x27, 0x3C, 0x35, 0x1B, 0x27, 0x30, 0x45, 0x1D, 0x27, 0x34, 0x55, 0x1D,
+	0x27, 0x38, 0x65, 0x1D, 0x27, 0x3C, 0x75, 0x1D, 0x27, 0x30, 0x85, 0x1F, 0x27, 0x34, 0x95, 0x1F,
+	0x27, 0x38, 0xA5, 0x1F, 0x27, 0x3C, 0xB5, 0x1F, 0x27, 0x30, 0xC5, 0x21, 0x27, 0x34, 0xD5, 0x21,
+	0x27, 0x38, 0xE5, 0x21, 0x27, 0x3C, 0xF5, 0x21, 0xF3, 0x24, 0x30, 0x00, 0x23, 0x30, 0x95, 0x22,
+	0x22, 0x64, 0x82, 0x64, 0x41, 0x01, 0x82, 0x80
+};
+
+uchar const loadfloat[] __attribute__((section("_loadfloat"))) = {
+  0x41, 0x11, 0x22, 0xE4, 0x00, 0x08, 0x07, 0x30,
+	0x05, 0x12, 0x87, 0x30, 0x85, 0x12, 0x07, 0x31, 0x05, 0x13, 0x87, 0x31, 0x85, 0x13, 0x07, 0x32, 
+	0x05, 0x14, 0x87, 0x32, 0x85, 0x14, 0x07, 0x33, 0x05, 0x15, 0x87, 0x33, 0x85, 0x15, 0x07, 0x34, 
+	0x05, 0x16, 0x87, 0x34, 0x85, 0x16, 0x07, 0x35, 0x05, 0x17, 0x87, 0x35, 0x85, 0x17, 0x07, 0x36, 
+	0x05, 0x18, 0x87, 0x36, 0x85, 0x18, 0x07, 0x37, 0x05, 0x19, 0x87, 0x37, 0x85, 0x19, 0x07, 0x38, 
+	0x05, 0x1A, 0x87, 0x38, 0x85, 0x1A, 0x07, 0x39, 0x05, 0x1B, 0x87, 0x39, 0x85, 0x1B, 0x07, 0x3A, 
+	0x05, 0x1C, 0x87, 0x3A, 0x85, 0x1C, 0x07, 0x3B, 0x05, 0x1D, 0x87, 0x3B, 0x85, 0x1D, 0x07, 0x3C, 
+	0x05, 0x1E, 0x87, 0x3C, 0x85, 0x1E, 0x07, 0x3D, 0x05, 0x1F, 0x87, 0x3D, 0x85, 0x1F, 0x07, 0x3E, 
+	0x05, 0x20, 0x87, 0x3E, 0x85, 0x20, 0x07, 0x3F, 0x05, 0x21, 0x87, 0x3F, 0x85, 0x21, 0x03, 0x35, 
+	0x05, 0x22, 0x73, 0x10, 0x35, 0x00, 0x22, 0x64, 0x41, 0x01, 0x82, 0x80
+};
+
+// in kernelvec.S, calls kerneltrap().
+extern void kernelvec();
+
+int devintr(int cpl);
+int page_fault();
+
+// void
+// trapinit(void)
+// {
+//   initlock(&tickslock, "time");
+//   #ifdef DEBUG
+//   printf("trapinit\n");
+//   #endif
+// }
+
+// set up to take exceptions and traps while in the kernel.
+void
+trapinithart(void)
+{
+  w_stvec((uint64)kernelvec);
+  w_sstatus(r_sstatus() | SSTATUS_SIE);
+  // enable supervisor-mode timer interrupts.
+  w_sie(r_sie() | SIE_SEIE | SIE_SSIE | SIE_STIE);
+  set_next_timeout();
+  #ifdef DEBUG
+  printf("trapinithart\n");
+  #endif
+}
+
+//
+// handle an interrupt, exception, or system call from user space.
+// called from trampoline.S
+//
+void
+usertrap(void)
+{
+  // __DEBUG("");
+  ((floattrap)storefloat)(myproc()->trapframe);
+  int which_dev = 0;
+
+  if((r_sstatus() & SSTATUS_SPP) != 0)
+    panic("usertrap: not from user mode");
+
+  // send interrupts and exceptions to kerneltrap(),
+  // since we're now in the kernel.
+  w_stvec((uint64)kernelvec);
+
+  struct proc *p = myproc();
+  // __DEBUG("%p",p->trapframe->epc);
+  uint64 timestamp = readtime();
+	p->ikstmp = timestamp;
+	p->ti.tms_utime += timestamp - p->okstmp;
+
+  // __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+  // __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+  // __DEBUG("a7 = %p", p->trapframe->a7);
+  
+  // save user program counter.
+  p->trapframe->epc = r_sepc();
+  // __DEBUG("sepc = %p",p->trapframe->epc);
+  if(r_scause() == 8){
+    // system call
+    if(p->killed)
+      exit(-1);
+    // sepc points to the ecall instruction,
+    // but we want to return to the next instruction.
+    p->trapframe->epc += 4;
+    // an interrupt will change sstatus &c registers,
+    // so don't enable until done with those registers.
+    intr_on();
+    syscall();
+  } 
+  else if((which_dev = devintr(0)) != 0 && which_dev != 2){
+    // __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+    // __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+  } 
+  else if(page_fault()!=0){
+    // __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+    // __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+    // __DEBUG("p->sbrk_base = %p  p->sz = %p p->mmap_size = %p p->ustack_base = %p",p->sbrk_base,p->sz,p->mmap_size,p->ustack_base);
+  }
+  else {
+    __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+    __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+    // trapframedump(p->trapframe);
+    p->killed = 1;
+  }
+
+  if(p->killed)
+    exit(-1);
+
+  // give up the CPU if this is a timer interrupt.
+  if(which_dev == 2){
+    yield();
+    myproc()->ivswtch += 1;
+  }
+
+  usertrapret();
+}
+
+//
+// return to user space
+//
+void
+usertrapret(void)
+{
+  struct proc *p = myproc();
+
+  // we're about to switch the destination of traps from
+  // kerneltrap() to usertrap(), so turn off interrupts until
+  // we're back in user space, where usertrap() is correct.
+  intr_off();
+
+  uint64 timestamp = readtime();
+	p->okstmp = timestamp;
+	p->ti.tms_stime += timestamp - p->ikstmp;
+
+  // send syscalls, interrupts, and exceptions to trampoline.S
+  w_stvec(TRAMPOLINE + (uservec - trampoline));
+
+  // set up trapframe values that uservec will need when
+  // the process next re-enters the kernel.
+  p->trapframe->kernel_satp = r_satp();         // kernel page table
+  p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack
+  p->trapframe->kernel_trap = (uint64)usertrap;
+  p->trapframe->kernel_hartid = r_tp();         // hartid for cpuid()
+
+  // set up the registers that trampoline.S's sret will use
+  // to get to user space.
+  
+  // set S Previous Privilege mode to User.
+  unsigned long x = r_sstatus();
+  x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
+  x |= SSTATUS_SPIE; // enable interrupts in user mode
+  w_sstatus(x);
+
+  // set S Exception Program Counter to the saved user pc.
+  w_sepc(p->trapframe->epc);
+  
+  // set signal handler
+  if(r_scause() != 8){
+    do_act();
+  }
+  // else{
+  //   __DEBUG("return = %p",p->trapframe->a0);
+  // }
+
+  // tell trampoline.S the user page table to switch to.
+  // printf("[usertrapret]p->pagetable: %p\n", p->pagetable);
+  uint64 satp = MAKE_SATP(p->pagetable);
+
+  // jump to trampoline.S at the top of memory, which 
+  // switches to the user page table, restores user registers,
+  // and switches to user mode with sret.
+  ((floattrap)loadfloat)(p->trapframe);
+  uint64 fn = TRAMPOLINE + (userret - trampoline);
+  // __DEBUG("%p",p->trapframe->epc);
+  ((void (*)(uint64,uint64))fn)(TRAPFRAME, satp);
+}
+
+// interrupts and exceptions from kernel code go here via kernelvec,
+// on whatever the current kernel stack is.
+void 
+kerneltrap() {
+  // __DEBUG("");
+  int which_dev = 0;
+  uint64 sepc = r_sepc();
+  uint64 sstatus = r_sstatus();
+  uint64 scause = r_scause();
+  
+  if((sstatus & SSTATUS_SPP) == 0)
+    panic("kerneltrap: not from supervisor mode");
+  if(intr_get() != 0)
+    panic("kerneltrap: interrupts enabled");
+  // if(r_scause() == 13 || r_scause() == 15){
+  //   if(r_stval() > 0x80000000){
+  //     printf("r_stval:------------------------------->%p\n",r_stval());
+  //     kernel_page_fault();
+  //   }
+  // }
+  if((which_dev = devintr(1)) == 0){
+    __ERROR("scause %p", scause);
+    __ERROR("sepc=%p stval=%p hart=%d", r_sepc(), r_stval(), r_tp());
+    struct proc *p = myproc();
+    if (p != 0) {
+      __ERROR("pid: %d, name: %s", p->pid, p->name);
+    }
+    panic("kerneltrap");
+  }
+  // printf("which_dev: %d\n", which_dev);
+  
+  // give up the CPU if this is a timer interrupt.
+  if(which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING) {
+    yield();
+  }
+  // the yield() may have caused some traps to occur,
+  // so restore trap registers for use by kernelvec.S's sepc instruction.
+  w_sepc(sepc);
+  w_sstatus(sstatus);
+}
+
+// Check if it's an external/software interrupt, 
+// and handle it. 
+// returns  2 if timer interrupt, 
+//          1 if other device, 
+//          0 if not recognized. 
+int devintr(int cpl) {
+	uint64 scause = r_scause();
+
+	#ifdef QEMU 
+	// handle external interrupt 
+	if ((0x8000000000000000L & scause) && 9 == (scause & 0xff)) 
+	#else 
+	// on k210, supervisor software interrupt is used 
+	// in alternative to supervisor external interrupt, 
+	// which is not available on k210. 
+	if (0x8000000000000001L == scause && 9 == r_stval()) 
+	#endif 
+	{
+		int irq = plic_claim();
+		if (UART_IRQ == irq) {
+			// keyboard input 
+			int c = sbi_console_getchar();
+			if (-1 != c) {
+				consoleintr(c);
+			}
+		}
+		else if (DISK_IRQ == irq) {
+			disk_intr();
+		}
+		else if (irq) {
+			printf("unexpected interrupt irq = %d\n", irq);
+		}
+
+		if (irq) { plic_complete(irq);}
+
+		#ifndef QEMU 
+		w_sip(r_sip() & ~2);    // clear pending bit
+		sbi_set_mie();
+		#endif 
+
+		return 1;
+	}
+	else if (0x8000000000000005L == scause) {
+		timer_tick(cpl);
+		return 2;
+	}
+	else { return 0;}
+}
+
+
+void *mmap_kalloc(struct mem_seg* seg,struct proc* p,uint64 base_addr){
+  pte_t *pte;
+  if(seg->type&MAP_ANONYMOUS){
+    if(p->parent){
+      if((pte = walk(p->parent->pagetable, base_addr, 0))==NULL){
+        return kalloc();
+      }else{
+        if((*pte & PTE_V)!=0){
+          uint64 pa=PTE2PA(*pte);
+          int index=((uint64)pa-pa_addr_start)/PGSIZE;
+          ++mm_table[index];
+          return (void*)pa;
+        }
+        else{
+          return kalloc();
+        }
+      }
+    }
+  }
+  else{
+    return kalloc();
+  }
+  return NULL;
+}
+int check_map_link(uint64 addr,struct proc* p){
+  //printf("addr------!!!------------->%d\n",addr);
+  char* mem=0;
+  pte_t *pte,*kpte;
+  for(struct mem_seg* temp=p->seg;temp!=p->seg->prev->prev;temp=temp->next){
+    //printf("temp->type--------------------------:%d\n",temp->type);
+    if(temp->type!=0){
+      //printf("temp->start:----->%d      temp->len:------->%d  temp->start+temp->len:------>%d\n",temp->start,temp->len,temp->start+temp->len);
+      if(addr>=temp->start&&addr<temp->start+temp->len){
+        uint64 base_addr=PGROUNDDOWN(addr);
+        if((*(pte = walk(p->pagetable, base_addr, 1)) & PTE_V)==0){
+          if((mem = mmap_kalloc(temp,p,base_addr)) == NULL)
+            panic("no page");
+          //printf("real addr:------------->%p\n",(uint64)mem);
+          *pte = PA2PTE((uint64)mem)|PTE_R|PTE_W|PTE_X|PTE_U|PTE_V;
+        }
+        if((*(kpte = walk(p->kpagetable, base_addr, 1)) & PTE_V)==0){
+          *kpte = PA2PTE((uint64)mem)|PTE_R|PTE_W|PTE_X|PTE_V;
+        }
+        if(temp->fd){ 
+          uint size =temp->start+temp->len-base_addr;
+          size=size>PGSIZE?PGSIZE:size;
+          if(eread(temp->fd->ep, 0, (uint64)mem, temp->off+(base_addr-temp->start), size) != size)
+            panic("do_store_fault : error file map");
+        }
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+int page_fault(){
+  // __DEBUG("pid %d %p",myproc()->pid,r_stval());
+  memoryload(r_stval());
+
+  switch (r_scause()) {
+	case STORE_PAGE_FAULT: 
+	case STORE_ACCESS_FAULT: 
+		return do_store_fault(r_stval());
+	case LOAD_PAGE_FAULT: 
+	case LOAD_ACCESS_FAULT: 
+		return do_load_fault(r_stval());
+	case INSTRUCTION_PAGE_FAULT:
+	case INSTRUCTION_ACCESS_FAULT:
+    return do_ins_fault(r_stval());
+	default: 
+    return -1;
+	}
+  return 0;
+}
+
+void trapframedump(struct trapframe *tf)
+{
+  printf("a0: %p\t", tf->a0);
+  printf("a1: %p\t", tf->a1);
+  printf("a2: %p\t", tf->a2);
+  printf("a3: %p\n", tf->a3);
+  printf("a4: %p\t", tf->a4);
+  printf("a5: %p\t", tf->a5);
+  printf("a6: %p\t", tf->a6);
+  printf("a7: %p\n", tf->a7);
+  printf("t0: %p\t", tf->t0);
+  printf("t1: %p\t", tf->t1);
+  printf("t2: %p\t", tf->t2);
+  printf("t3: %p\n", tf->t3);
+  printf("t4: %p\t", tf->t4);
+  printf("t5: %p\t", tf->t5);
+  printf("t6: %p\t", tf->t6);
+  printf("s0: %p\n", tf->s0);
+  printf("s1: %p\t", tf->s1);
+  printf("s2: %p\t", tf->s2);
+  printf("s3: %p\t", tf->s3);
+  printf("s4: %p\n", tf->s4);
+  printf("s5: %p\t", tf->s5);
+  printf("s6: %p\t", tf->s6);
+  printf("s7: %p\t", tf->s7);
+  printf("s8: %p\n", tf->s8);
+  printf("s9: %p\t", tf->s9);
+  printf("s10: %p\t", tf->s10);
+  printf("s11: %p\t", tf->s11);
+  printf("ra: %p\n", tf->ra);
+  printf("sp: %p\t", tf->sp);
+  printf("gp: %p\t", tf->gp);
+  printf("tp: %p\t", tf->tp);
+  printf("epc: %p\n", tf->epc);
+  printf("ft0: %p\t", tf->ft0);
+  printf("ft1: %p\t", tf->ft1);
+  printf("ft2: %p\t", tf->ft2);
+  printf("ft3: %p\n", tf->ft3);
+  printf("ft4: %p\t", tf->ft4);
+  printf("ft5: %p\t", tf->ft5);
+  printf("ft6: %p\t", tf->ft6);
+  printf("ft7: %p\n", tf->ft7);
+  printf("fs0: %p\t", tf->fs0);
+  printf("fs1: %p\t", tf->fs1);
+  printf("fa0: %p\t", tf->fa0);
+  printf("fa1: %p\n", tf->fa1);
+  printf("fa2: %p\t", tf->fa2);
+  printf("fa3: %p\t", tf->fa3);
+  printf("fa4: %p\t", tf->fa4);
+  printf("fa5: %p\n", tf->fa5);
+  printf("fa6: %p\t", tf->fa6);
+  printf("fa7: %p\t", tf->fa7);
+  printf("fs2: %p\t", tf->fs2);
+  printf("fs3: %p\n", tf->fs3);
+  printf("fs4: %p\t", tf->fs4);
+  printf("fs5: %p\t", tf->fs5);
+  printf("fs6: %p\t", tf->fs6);
+  printf("fs7: %p\n", tf->fs7);
+  printf("fs8: %p\t", tf->fs8);
+  printf("fs9: %p\t", tf->fs9);
+  printf("fs10: %p\t", tf->fs10);
+  printf("fs11: %p\n", tf->fs11);
+  printf("ft8: %p\t", tf->ft8);
+  printf("ft9: %p\t", tf->ft9);
+  printf("ft10: %p\t", tf->ft10);
+  printf("ft11: %p\n", tf->ft11);
+}
diff --git a/kernel/uart.c b/kernel/uart.c
new file mode 100644
index 0000000000000000000000000000000000000000..eaa7739e13bd2a9844a39e37ce1d9f8235dde292
--- /dev/null
+++ b/kernel/uart.c
@@ -0,0 +1,197 @@
+//
+// low-level driver routines for 16550a UART.
+//
+
+
+#include "include/types.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/riscv.h"
+#include "include/spinlock.h"
+#include "include/proc.h"
+#include "include/intr.h"
+
+// the UART control registers are memory-mapped
+// at address UART0. this macro returns the
+// address of one of the registers.
+#define Reg(reg) ((volatile unsigned char *)(UART + reg))
+
+// the UART control registers.
+// some have different meanings for
+// read vs write.
+// see http://byterunner.com/16550.html
+#define RHR 0                 // receive holding register (for input bytes)
+#define THR 0                 // transmit holding register (for output bytes)
+#define IER 1                 // interrupt enable register
+#define IER_TX_ENABLE (1<<0)
+#define IER_RX_ENABLE (1<<1)
+#define FCR 2                 // FIFO control register
+#define FCR_FIFO_ENABLE (1<<0)
+#define FCR_FIFO_CLEAR (3<<1) // clear the content of the two FIFOs
+#define ISR 2                 // interrupt status register
+#define LCR 3                 // line control register
+#define LCR_EIGHT_BITS (3<<0)
+#define LCR_BAUD_LATCH (1<<7) // special mode to set baud rate
+#define LSR 5                 // line status register
+#define LSR_RX_READY (1<<0)   // input is waiting to be read from RHR
+#define LSR_TX_IDLE (1<<5)    // THR can accept another character to send
+
+#define ReadReg(reg) (*(Reg(reg)))
+#define WriteReg(reg, v) (*(Reg(reg)) = (v))
+
+// the transmit output buffer.
+struct spinlock uart_tx_lock;
+#define UART_TX_BUF_SIZE 32
+char uart_tx_buf[UART_TX_BUF_SIZE];
+int uart_tx_w; // write next to uart_tx_buf[uart_tx_w++]
+int uart_tx_r; // read next from uart_tx_buf[uar_tx_r++]
+
+extern volatile int panicked; // from printf.c
+
+void uartstart();
+
+void
+uartinit(void)
+{
+  // disable interrupts.
+  WriteReg(IER, 0x00);
+
+  // special mode to set baud rate.
+  WriteReg(LCR, LCR_BAUD_LATCH);
+
+  // LSB for baud rate of 38.4K.
+  WriteReg(0, 0x03);
+
+  // MSB for baud rate of 38.4K.
+  WriteReg(1, 0x00);
+
+  // leave set-baud mode,
+  // and set word length to 8 bits, no parity.
+  WriteReg(LCR, LCR_EIGHT_BITS);
+
+  // reset and enable FIFOs.
+  WriteReg(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
+
+  // enable transmit and receive interrupts.
+  WriteReg(IER, IER_TX_ENABLE | IER_RX_ENABLE);
+
+    uart_tx_w = uart_tx_r = 0;
+
+  initlock(&uart_tx_lock, "uart");
+}
+
+// add a character to the output buffer and tell the
+// UART to start sending if it isn't already.
+// blocks if the output buffer is full.
+// because it may block, it can't be called
+// from interrupts; it's only suitable for use
+// by write().
+void
+uartputc(int c)
+{
+  acquire(&uart_tx_lock);
+
+  if(panicked){
+    for(;;)
+      ;
+  }
+
+  while(1){
+    if(((uart_tx_w + 1) % UART_TX_BUF_SIZE) == uart_tx_r){
+      // buffer is full.
+      // wait for uartstart() to open up space in the buffer.
+      sleep(&uart_tx_r, &uart_tx_lock);
+    } else {
+      uart_tx_buf[uart_tx_w] = c;
+      uart_tx_w = (uart_tx_w + 1) % UART_TX_BUF_SIZE;
+      uartstart();
+      release(&uart_tx_lock);
+      return;
+    }
+  }
+}
+
+// alternate version of uartputc() that doesn't 
+// use interrupts, for use by kernel printf() and
+// to echo characters. it spins waiting for the uart's
+// output register to be empty.
+void
+uartputc_sync(int c)
+{
+  push_off();
+
+  if(panicked){
+    for(;;)
+      ;
+  }
+
+  // wait for Transmit Holding Empty to be set in LSR.
+  while((ReadReg(LSR) & LSR_TX_IDLE) == 0)
+    ;
+  WriteReg(THR, c);
+
+  pop_off();
+}
+
+// if the UART is idle, and a character is waiting
+// in the transmit buffer, send it.
+// caller must hold uart_tx_lock.
+// called from both the top- and bottom-half.
+void
+uartstart()
+{
+  while(1){
+    if(uart_tx_w == uart_tx_r){
+      // transmit buffer is empty.
+      return;
+    }
+    
+    if((ReadReg(LSR) & LSR_TX_IDLE) == 0){
+      // the UART transmit holding register is full,
+      // so we cannot give it another byte.
+      // it will interrupt when it's ready for a new byte.
+      return;
+    }
+    
+    int c = uart_tx_buf[uart_tx_r];
+    uart_tx_r = (uart_tx_r + 1) % UART_TX_BUF_SIZE;
+    
+    // maybe uartputc() is waiting for space in the buffer.
+    wakeup(&uart_tx_r);
+    
+    WriteReg(THR, c);
+  }
+}
+
+// read one input character from the UART.
+// return -1 if none is waiting.
+int
+uartgetc(void)
+{
+  if(ReadReg(LSR) & 0x01){
+    // input data is ready.
+    return ReadReg(RHR);
+  } else {
+    return -1;
+  }
+}
+
+// handle a uart interrupt, raised because input has
+// arrived, or the uart is ready for more output, or
+// both. called from trap.c.
+void
+uartintr(void)
+{
+  // read and process incoming characters.
+  while(1){
+    int c = uartgetc();
+    if(c == -1)
+      break;
+    consoleintr(c);
+  }
+
+  // send buffered characters.
+  acquire(&uart_tx_lock);
+  uartstart();
+  release(&uart_tx_lock);
+}
diff --git a/kernel/uname.c b/kernel/uname.c
new file mode 100644
index 0000000000000000000000000000000000000000..1ee3e121f848a2a6e3604555f7e1277f41830710
--- /dev/null
+++ b/kernel/uname.c
@@ -0,0 +1,62 @@
+#include "include/uname.h"
+#include "include/types.h"
+#include "include/printf.h"
+#include "include/fat32.h"
+#include "include/vm.h"
+
+
+char const UNAME_SYSNAME[] = "xv6-k210";
+char const UNAME_NODENAME[] = "none";
+char const UNAME_RELEASE[] = "5.0";
+char const UNAME_VERSION[] = __DATE__" "__TIME__;
+#ifndef QEMU 
+char const UNAME_MACHINE[] = "Kendryte K210";
+#else 
+char const UNAME_MACHINE[] = "QEMU";
+#endif 
+char const UNAME_DOMAINNAME[] = "none";
+
+
+int do_uname(uint64 addr){
+ struct utsname *user_uts = (struct utsname*)addr;
+
+	if (copyout(myproc()->pagetable,(uint64)user_uts->sysname, 
+			(void*)UNAME_SYSNAME, sizeof(UNAME_SYSNAME)) < 0) 
+	{
+		return -1;
+	}
+	if (copyout(myproc()->pagetable,(uint64)user_uts->nodename, 
+			(void*)UNAME_NODENAME, sizeof(UNAME_NODENAME)) < 0) 
+	{
+	
+		return -1;
+	}
+	if (copyout(myproc()->pagetable,(uint64)user_uts->release, 
+			(void*)UNAME_RELEASE, sizeof(UNAME_RELEASE)) < 0) 
+	{
+		
+		return -1;
+	}
+	if (copyout(myproc()->pagetable,(uint64)user_uts->version, 
+			(void*)UNAME_VERSION, sizeof(UNAME_VERSION)) < 0) 
+	{
+	
+		return -1;
+	}
+	if (copyout(myproc()->pagetable,(uint64)user_uts->machine, 
+			(void*)UNAME_MACHINE, sizeof(UNAME_MACHINE)) < 0) 
+	{
+	
+		return -1;
+	}
+	if (copyout(myproc()->pagetable,(uint64)user_uts->domainname, 
+			(void*)UNAME_DOMAINNAME, sizeof(UNAME_DOMAINNAME)) < 0) 
+	{
+		return -1;
+	}
+   sfence_vma();
+   return 0;
+}
+
+
+
diff --git a/kernel/utils.c b/kernel/utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..20e6c8d4e1018e7398d85e5d6cfffc6da33d4934
--- /dev/null
+++ b/kernel/utils.c
@@ -0,0 +1,28 @@
+#include "include/types.h"
+#include "include/utils.h"
+
+void set_bit(volatile uint32 *bits, uint32 mask, uint32 value)
+{
+    uint32 org = (*bits) & ~mask;
+    *bits = org | (value & mask);
+}
+
+void set_bit_offset(volatile uint32 *bits, uint32 mask, uint64 offset, uint32 value)
+{
+    set_bit(bits, mask << offset, value << offset);
+}
+
+void set_gpio_bit(volatile uint32 *bits, uint64 offset, uint32 value)
+{
+    set_bit_offset(bits, 1, offset, value);
+}
+
+uint32 get_bit(volatile uint32 *bits, uint32 mask, uint64 offset)
+{
+    return ((*bits) & (mask << offset)) >> offset;
+}
+
+uint32 get_gpio_bit(volatile uint32 *bits, uint64 offset)
+{
+    return get_bit(bits, 1, offset);
+}
diff --git a/kernel/virtio_disk.c b/kernel/virtio_disk.c
new file mode 100644
index 0000000000000000000000000000000000000000..2772c8d35c5f0cadc8560a6c950d5fa34fabac40
--- /dev/null
+++ b/kernel/virtio_disk.c
@@ -0,0 +1,277 @@
+//
+// driver for qemu's virtio disk device.
+// uses qemu's mmio interface to virtio.
+// qemu presents a "legacy" virtio interface.
+//
+// qemu ... -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
+//
+
+
+#include "include/types.h"
+#include "include/riscv.h"
+#include "include/param.h"
+#include "include/memlayout.h"
+#include "include/spinlock.h"
+#include "include/sleeplock.h"
+#include "include/buf.h"
+#include "include/virtio.h"
+#include "include/proc.h"
+#include "include/vm.h"
+#include "include/string.h"
+#include "include/printf.h"
+
+
+// the address of virtio mmio register r.
+#define R(r) ((volatile uint32 *)(VIRTIO0_V + (r)))
+
+static struct disk {
+ // memory for virtio descriptors &c for queue 0.
+ // this is a global instead of allocated because it must
+ // be multiple contiguous pages, which kalloc()
+ // doesn't support, and page aligned.
+  char pages[2*PGSIZE];
+  struct VRingDesc *desc;
+  uint16 *avail;
+  struct UsedArea *used;
+
+  // our own book-keeping.
+  char free[NUM];  // is a descriptor free?
+  uint16 used_idx; // we've looked this far in used[2..NUM].
+
+  // track info about in-flight operations,
+  // for use when completion interrupt arrives.
+  // indexed by first descriptor index of chain.
+  struct {
+    struct buf *b;
+    char status;
+  } info[NUM];
+  
+  struct spinlock vdisk_lock;
+  
+} __attribute__ ((aligned (PGSIZE))) disk;
+
+void
+virtio_disk_init(void)
+{
+  uint32 status = 0;
+
+  initlock(&disk.vdisk_lock, "virtio_disk");
+
+  if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
+     *R(VIRTIO_MMIO_VERSION) != 1 ||
+     *R(VIRTIO_MMIO_DEVICE_ID) != 2 ||
+     *R(VIRTIO_MMIO_VENDOR_ID) != 0x554d4551){
+    panic("could not find virtio disk");
+  }
+  
+  status |= VIRTIO_CONFIG_S_ACKNOWLEDGE;
+  *R(VIRTIO_MMIO_STATUS) = status;
+
+  status |= VIRTIO_CONFIG_S_DRIVER;
+  *R(VIRTIO_MMIO_STATUS) = status;
+
+  // negotiate features
+  uint64 features = *R(VIRTIO_MMIO_DEVICE_FEATURES);
+  features &= ~(1 << VIRTIO_BLK_F_RO);
+  features &= ~(1 << VIRTIO_BLK_F_SCSI);
+  features &= ~(1 << VIRTIO_BLK_F_CONFIG_WCE);
+  features &= ~(1 << VIRTIO_BLK_F_MQ);
+  features &= ~(1 << VIRTIO_F_ANY_LAYOUT);
+  features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
+  features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
+  *R(VIRTIO_MMIO_DRIVER_FEATURES) = features;
+
+  // tell device that feature negotiation is complete.
+  status |= VIRTIO_CONFIG_S_FEATURES_OK;
+  *R(VIRTIO_MMIO_STATUS) = status;
+
+  // tell device we're completely ready.
+  status |= VIRTIO_CONFIG_S_DRIVER_OK;
+  *R(VIRTIO_MMIO_STATUS) = status;
+
+  *R(VIRTIO_MMIO_GUEST_PAGE_SIZE) = PGSIZE;
+
+  // initialize queue 0.
+  *R(VIRTIO_MMIO_QUEUE_SEL) = 0;
+  uint32 max = *R(VIRTIO_MMIO_QUEUE_NUM_MAX);
+  if(max == 0)
+    panic("virtio disk has no queue 0");
+  if(max < NUM)
+    panic("virtio disk max queue too short");
+  *R(VIRTIO_MMIO_QUEUE_NUM) = NUM;
+  memset(disk.pages, 0, sizeof(disk.pages));
+  *R(VIRTIO_MMIO_QUEUE_PFN) = ((uint64)disk.pages) >> PGSHIFT;
+
+  // desc = pages -- num * VRingDesc
+  // avail = pages + 0x40 -- 2 * uint16, then num * uint16
+  // used = pages + 4096 -- 2 * uint16, then num * vRingUsedElem
+
+  disk.desc = (struct VRingDesc *) disk.pages;
+  disk.avail = (uint16*)(((char*)disk.desc) + NUM*sizeof(struct VRingDesc));
+  disk.used = (struct UsedArea *) (disk.pages + PGSIZE);
+
+  for(int i = 0; i < NUM; i++)
+    disk.free[i] = 1;
+
+  // plic.c and trap.c arrange for interrupts from VIRTIO0_IRQ.
+  #ifdef DEBUG
+  printf("virtio_disk_init\n");
+  #endif
+}
+
+// find a free descriptor, mark it non-free, return its index.
+static int
+alloc_desc()
+{
+  for(int i = 0; i < NUM; i++){
+    if(disk.free[i]){
+      disk.free[i] = 0;
+      return i;
+    }
+  }
+  return -1;
+}
+
+// mark a descriptor as free.
+static void
+free_desc(int i)
+{
+  if(i >= NUM)
+    panic("virtio_disk_intr 1");
+  if(disk.free[i])
+    panic("virtio_disk_intr 2");
+  disk.desc[i].addr = 0;
+  disk.free[i] = 1;
+  wakeup(&disk.free[0]);
+}
+
+// free a chain of descriptors.
+static void
+free_chain(int i)
+{
+  while(1){
+    free_desc(i);
+    if(disk.desc[i].flags & VRING_DESC_F_NEXT)
+      i = disk.desc[i].next;
+    else
+      break;
+  }
+}
+
+static int
+alloc3_desc(int *idx)
+{
+  for(int i = 0; i < 3; i++){
+    idx[i] = alloc_desc();
+    if(idx[i] < 0){
+      for(int j = 0; j < i; j++)
+        free_desc(idx[j]);
+      return -1;
+    }
+  }
+  return 0;
+}
+
+void
+virtio_disk_rw(struct buf *b, int write)
+{
+  uint64 sector = b->sectorno;
+
+  acquire(&disk.vdisk_lock);
+
+  // the spec says that legacy block operations use three
+  // descriptors: one for type/reserved/sector, one for
+  // the data, one for a 1-byte status result.
+
+  // allocate the three descriptors.
+  int idx[3];
+  while(1){
+    if(alloc3_desc(idx) == 0) {
+      break;
+    }
+    sleep(&disk.free[0], &disk.vdisk_lock);
+  }
+  
+  // format the three descriptors.
+  // qemu's virtio-blk.c reads them.
+
+  struct virtio_blk_outhdr {
+    uint32 type;
+    uint32 reserved;
+    uint64 sector;
+  } buf0;
+
+  if(write)
+    buf0.type = VIRTIO_BLK_T_OUT; // write the disk
+  else
+    buf0.type = VIRTIO_BLK_T_IN; // read the disk
+  buf0.reserved = 0;
+  buf0.sector = sector;
+
+  // buf0 is on a kernel stack, which is not direct mapped,
+  // thus the call to kvmpa().
+  disk.desc[idx[0]].addr = (uint64) kwalkaddr(myproc()->kpagetable, (uint64) &buf0);
+  disk.desc[idx[0]].len = sizeof(buf0);
+  disk.desc[idx[0]].flags = VRING_DESC_F_NEXT;
+  disk.desc[idx[0]].next = idx[1];
+
+  disk.desc[idx[1]].addr = (uint64) b->data;
+  disk.desc[idx[1]].len = BSIZE;
+  if(write)
+    disk.desc[idx[1]].flags = 0; // device reads b->data
+  else
+    disk.desc[idx[1]].flags = VRING_DESC_F_WRITE; // device writes b->data
+  disk.desc[idx[1]].flags |= VRING_DESC_F_NEXT;
+  disk.desc[idx[1]].next = idx[2];
+
+  disk.info[idx[0]].status = 0;
+  disk.desc[idx[2]].addr = (uint64) &disk.info[idx[0]].status;
+  disk.desc[idx[2]].len = 1;
+  disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status
+  disk.desc[idx[2]].next = 0;
+
+  // record struct buf for virtio_disk_intr().
+  b->disk = 1;
+  disk.info[idx[0]].b = b;
+
+  // avail[0] is flags
+  // avail[1] tells the device how far to look in avail[2...].
+  // avail[2...] are desc[] indices the device should process.
+  // we only tell device the first index in our chain of descriptors.
+  disk.avail[2 + (disk.avail[1] % NUM)] = idx[0];
+  __sync_synchronize();
+  disk.avail[1] = disk.avail[1] + 1;
+
+  *R(VIRTIO_MMIO_QUEUE_NOTIFY) = 0; // value is queue number
+
+  // Wait for virtio_disk_intr() to say request has finished.
+  while(b->disk == 1) {
+    sleep(b, &disk.vdisk_lock);
+  }
+
+  disk.info[idx[0]].b = 0;
+  free_chain(idx[0]);
+
+  release(&disk.vdisk_lock);
+}
+
+void
+virtio_disk_intr()
+{
+  acquire(&disk.vdisk_lock);
+
+  while((disk.used_idx % NUM) != (disk.used->id % NUM)){
+    int id = disk.used->elems[disk.used_idx].id;
+
+    if(disk.info[id].status != 0)
+      panic("virtio_disk_intr status");
+    
+    disk.info[id].b->disk = 0;   // disk is done with buf
+    wakeup(disk.info[id].b);
+
+    disk.used_idx = (disk.used_idx + 1) % NUM;
+  }
+  *R(VIRTIO_MMIO_INTERRUPT_ACK) = *R(VIRTIO_MMIO_INTERRUPT_STATUS) & 0x3;
+
+  release(&disk.vdisk_lock);
+}
diff --git a/kernel/vm.c b/kernel/vm.c
new file mode 100644
index 0000000000000000000000000000000000000000..881f9d73595e171ada7ddc5dbf38a38e0fdbd2f6
--- /dev/null
+++ b/kernel/vm.c
@@ -0,0 +1,1257 @@
+#include "include/param.h"
+#include "include/types.h"
+#include "include/memlayout.h"
+#include "include/elf.h"
+#include "include/riscv.h"
+#include "include/vm.h"
+#include "include/kalloc.h"
+#include "include/proc.h"
+#include "include/printf.h"
+#include "include/string.h"
+
+/*
+ * the kernel's page table.
+ */
+pagetable_t kernel_pagetable;
+
+extern char etext[];  // kernel.ld sets this to end of kernel code.
+extern char trampoline[]; // trampoline.S
+/*
+ * create a direct-map page table for the kernel.
+ */
+void
+kvminit()
+{
+  kernel_pagetable = (pagetable_t) kalloc();
+  // printf("kernel_pagetable: %p\n", kernel_pagetable);
+
+  memset(kernel_pagetable, 0, PGSIZE);
+
+  // uart registers
+  kvmmap(UART_V, UART, PGSIZE, PTE_R | PTE_W);
+  
+  #ifdef QEMU
+  // virtio mmio disk interface
+  kvmmap(VIRTIO0_V, VIRTIO0, PGSIZE, PTE_R | PTE_W);
+  #endif
+  // CLINT
+  kvmmap(CLINT_V, CLINT, 0x10000, PTE_R | PTE_W);
+
+  // PLIC
+  kvmmap(PLIC_V, PLIC, 0x4000, PTE_R | PTE_W);
+  kvmmap(PLIC_V + 0x200000, PLIC + 0x200000, 0x4000, PTE_R | PTE_W);
+
+  #ifndef QEMU
+  // GPIOHS
+  kvmmap(GPIOHS_V, GPIOHS, 0x1000, PTE_R | PTE_W);
+
+  // DMAC
+  kvmmap(DMAC_V, DMAC, 0x1000, PTE_R | PTE_W);
+
+  // GPIO
+  // kvmmap(GPIO_V, GPIO, 0x1000, PTE_R | PTE_W);
+
+  // SPI_SLAVE
+  kvmmap(SPI_SLAVE_V, SPI_SLAVE, 0x1000, PTE_R | PTE_W);
+
+  // FPIOA
+  kvmmap(FPIOA_V, FPIOA, 0x1000, PTE_R | PTE_W);
+
+  // SPI0
+  kvmmap(SPI0_V, SPI0, 0x1000, PTE_R | PTE_W);
+
+  // SPI1
+  kvmmap(SPI1_V, SPI1, 0x1000, PTE_R | PTE_W);
+
+  // SPI2
+  kvmmap(SPI2_V, SPI2, 0x1000, PTE_R | PTE_W);
+
+  // SYSCTL
+  kvmmap(SYSCTL_V, SYSCTL, 0x1000, PTE_R | PTE_W);
+  
+  #endif
+  
+  // map rustsbi
+  // kvmmap(RUSTSBI_BASE, RUSTSBI_BASE, KERNBASE - RUSTSBI_BASE, PTE_R | PTE_X);
+  // map kernel text executable and read-only.
+  kvmmap(KERNBASE, KERNBASE, (uint64)etext - KERNBASE, PTE_R | PTE_X);
+  // map kernel data and the physical RAM we'll make use of.
+  // __DEBUG("-----------etext-------%p",(uint64)etext);
+
+  kvmmap((uint64)etext, (uint64)etext, PHYSTOP - (uint64)etext, PTE_R | PTE_W);
+  // map the trampoline for trap entry/exit to
+  // the highest virtual address in the kernel.
+  kvmmap(TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X);
+
+  #ifdef DEBUG
+  printf("kvminit\n");
+  #endif
+}
+
+// Switch h/w page table register to the kernel's page table,
+// and enable paging.
+void
+kvminithart()
+{
+  w_satp(MAKE_SATP(kernel_pagetable));
+  // reg_info();
+  sfence_vma();
+  #ifdef DEBUG
+  printf("kvminithart\n");
+  #endif
+}
+
+// Return the address of the PTE in page table pagetable
+// that corresponds to virtual address va.  If alloc!=0,
+// create any required page-table pages.
+//
+// The risc-v Sv39 scheme has three levels of page-table
+// pages. A page-table page contains 512 64-bit PTEs.
+// A 64-bit virtual address is split into five fields:
+//   39..63 -- must be zero.
+//   30..38 -- 9 bits of level-2 index.
+//   21..29 -- 9 bits of level-1 index.
+//   12..20 -- 9 bits of level-0 index.
+//    0..11 -- 12 bits of byte offset within the page.
+pte_t *
+walk(pagetable_t pagetable, uint64 va, int alloc)
+{
+  
+  if(va >= MAXVA){
+    int c = 1;
+    __ERROR("%p,%d",va,c);
+    kill(myproc()->pid);
+    // panic("walk");
+  }
+
+  for(int level = 2; level > 0; level--) {
+    pte_t *pte = &pagetable[PX(level, va)];
+    if(*pte & PTE_V) {
+      pagetable = (pagetable_t)PTE2PA(*pte);
+    } else {
+      if(!alloc || (pagetable = (pde_t*)kalloc()) == NULL){
+        __ERROR("error");
+        return NULL;
+      }
+      memset(pagetable, 0, PGSIZE);
+      *pte = PA2PTE(pagetable) | PTE_V;
+    }
+  }
+  return &pagetable[PX(0, va)];
+}
+
+// Look up a virtual address, return the physical address,
+// or 0 if not mapped.
+// Can only be used to look up user pages.
+uint64
+walkaddr(pagetable_t pagetable, uint64 va)
+{
+  pte_t *pte;
+  uint64 pa;
+  if(va >= MAXVA)
+    return NULL;
+  //printf("va---------------------------------------->%p\n",va);
+  pte = walk(pagetable, va, 0);
+  if(pte == 0){
+    __ERROR("pte == 0");
+    return NULL;
+  }
+  if((*pte & PTE_V) == 0){
+    // __DEBUG("va = %p, p->sz = %p, ra = %p",va,myproc()->sz,r_ra());
+    if(memoryload(va) == 0){
+      do_store_fault(va);
+    }
+    
+    pte = walk(pagetable, va, 0);
+    
+    // __ERROR("isn't vaild pages");
+    // return NULL;
+    // __ERROR("");
+    // return NULL;
+  }
+  if((*pte & PTE_U) == 0){
+    __ERROR("isn't user pages");
+    return NULL;
+  }
+  pa = PTE2PA(*pte);
+  return pa;
+}
+
+
+uint64
+walkaddr2(pagetable_t pagetable, uint64 va)
+{
+  pte_t *pte;
+  uint64 pa;
+
+  if(va >= MAXVA)
+    return NULL;
+
+  pte = walk(pagetable, va, 0);
+  if(pte == 0)
+    return NULL;
+  if((*pte & PTE_V) == 0)
+    return NULL;
+  if((*pte & PTE_U) == 0)
+    return NULL;
+  pa = PTE2PA(*pte);
+  return pa;
+}
+// add a mapping to the kernel page table.
+// only used when booting.
+// does not flush TLB or enable paging.
+void
+kvmmap(uint64 va, uint64 pa, uint64 sz, int perm)
+{
+  if(mappages(kernel_pagetable, va, sz, pa, perm) != 0)
+    panic("kvmmap");
+}
+
+// translate a kernel virtual address to
+// a physical address. only needed for
+// addresses on the stack.
+// assumes va is page aligned.
+uint64
+kvmpa(uint64 va)
+{
+  return kwalkaddr(kernel_pagetable, va);
+}
+
+uint64
+kwalkaddr(pagetable_t kpt, uint64 va)
+{
+  uint64 off = va % PGSIZE;
+  pte_t *pte;
+  uint64 pa;
+  
+  pte = walk(kpt, va, 0);
+  if(pte == 0)
+    panic("kvmpa");
+  if((*pte & PTE_V) == 0)
+    panic("kvmpa");
+  pa = PTE2PA(*pte);
+  return pa+off;
+}
+
+// Create PTEs for virtual addresses starting at va that refer to
+// physical addresses starting at pa. va and size might not
+// be page-aligned. Returns 0 on success, -1 if walk() couldn't
+// allocate a needed page-table page.
+int
+mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
+{
+  uint64 a, last;
+  pte_t *pte;
+
+  a = PGROUNDDOWN(va);
+  last = PGROUNDDOWN(va + size - 1);
+  for(;;){
+    if((pte = walk(pagetable, a, 1)) == NULL)
+      return -1;
+    if(*pte & PTE_V){
+      __ERROR("va = %p, pa = %p",a,(PTE2PA(*pte)));
+      panic("remap");
+    }
+    *pte = PA2PTE(pa) | perm | PTE_V;
+    if(a == last)
+      break;
+    a += PGSIZE;
+    pa += PGSIZE;
+  }
+  return 0;
+}
+
+// Remove npages of mappings starting from va. va must be
+// page-aligned. The mappings must exist.
+// Optionally free the physical memory.
+void
+vmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
+{
+  uint64 a;
+  pte_t *pte;
+
+  if((va % PGSIZE) != 0)
+    panic("vmunmap: not aligned");
+
+  for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
+    //printf("----------%d\n",a);
+    if((pte = walk(pagetable, a, 0)) == 0)
+      continue;
+    if((*pte & PTE_V) == 0){
+      *pte = 0;
+      continue;
+    }
+    if(PTE_FLAGS(*pte) == PTE_V)
+      panic("vmunmap: not a leaf");
+    if(do_free){
+      if((*pte&PTE_V)!=0){
+        uint64 pa = PTE2PA(*pte);
+        // __DEBUG("pa = %p",pa);
+        kfree((void*)pa);
+      }
+      //printf("free page\n");
+    }
+    *pte = 0;
+  }
+}
+
+// create an empty user page table.
+// returns 0 if out of memory.
+pagetable_t
+uvmcreate()
+{
+  pagetable_t pagetable;
+  pagetable = (pagetable_t) kalloc();
+  if(pagetable == NULL)
+    return NULL;
+  memset(pagetable, 0, PGSIZE);
+  return pagetable;
+}
+
+// Load the user initcode into address 0 of pagetable,
+// for the very first process.
+// sz must be less than a page.
+int
+uvminit(pagetable_t pagetable, pagetable_t kpagetable, uchar *src, uint sz)
+{
+  char *mem;
+  int i = 0;
+  for(;i < sz;i+=PGSIZE){
+    mem = kalloc();
+    memset(mem, 0, PGSIZE);
+    mappages(pagetable, i, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U);
+    mappages(kpagetable, i, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X);
+    uint k = sz - i*PGSIZE > PGSIZE ? PGSIZE : sz - i*PGSIZE;
+    memmove(mem, src + i, k);
+  }
+  return i;
+}
+
+// Allocate PTEs and physical memory to grow process from oldsz to
+// newsz, which need not be page aligned.  Returns new size or 0 on error.
+uint64
+uvmalloc(pagetable_t pagetable, pagetable_t kpagetable, uint64 oldsz, uint64 newsz)
+{
+  char *mem;
+  uint64 a;
+
+  if(newsz < oldsz)
+    return oldsz;
+
+  oldsz = PGROUNDUP(oldsz);
+  for(a = oldsz; a < newsz; a += PGSIZE){
+    mem = kalloc();
+    if(mem == NULL){
+      uvmdealloc(pagetable, kpagetable, a, oldsz);
+      return 0;
+    }
+    memset(mem, 0, PGSIZE);
+    if (mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0) {
+      kfree(mem);
+      uvmdealloc(pagetable, kpagetable, a, oldsz);
+      return 0;
+    }
+    if (mappages(kpagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R) != 0){
+      int npages = (a - oldsz) / PGSIZE;
+      vmunmap(pagetable, oldsz, npages + 1, 1);   // plus the page allocated above.
+      vmunmap(kpagetable, oldsz, npages, 0);
+      return 0;
+    }
+  }
+  return newsz;
+}
+uint64
+uvmallocpage(pagetable_t pagetable, pagetable_t kpagetable, uint64 a)
+{
+  char *mem;
+  a = PGROUNDDOWN(a);
+  mem = kalloc();
+  if(mem == NULL){
+    return -1;
+  }
+  memset(mem, 0, PGSIZE);
+  if (mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0) {
+    __ERROR("error");
+    kfree(mem);
+    uvmdeallocpage(pagetable, kpagetable, a);
+    return -1;
+  }
+  if (mappages(kpagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R) != 0){
+    __ERROR("error");
+    vmunmap(pagetable, a, 1, 1);   // plus the page allocated above.
+    vmunmap(kpagetable, a, 1, 0);
+    return -1;
+  }
+  return 0;
+}
+
+uint64
+uvmallocpage2(pagetable_t pagetable, pagetable_t kpagetable, uint64 a, int flags)
+{
+  char *mem;
+  a = PGROUNDDOWN(a);
+  mem = kalloc();
+  if(mem == NULL){
+    return -1;
+  }
+  memset(mem, 0, PGSIZE);
+  if (mappages(pagetable, a, PGSIZE, (uint64)mem, flags|PTE_U) != 0) {
+    __ERROR("error");
+    kfree(mem);
+    uvmdeallocpage(pagetable, kpagetable, a);
+    return -1;
+  }
+  if (mappages(kpagetable, a, PGSIZE, (uint64)mem, flags & (~PTE_U)) != 0){
+    __ERROR("error");
+    vmunmap(pagetable, a, 1, 1);   // plus the page allocated above.
+    vmunmap(kpagetable, a, 1, 0);
+    return -1;
+  }
+  return 0;
+}
+
+// Deallocate user pages to bring the process size from oldsz to
+// newsz.  oldsz and newsz need not be page-aligned, nor does newsz
+// need to be less than oldsz.  oldsz can be larger than the actual
+// process size.  Returns the new process size.
+uint64
+uvmdealloc(pagetable_t pagetable, pagetable_t kpagetable, uint64 oldsz, uint64 newsz)
+{
+  if(newsz >= oldsz)
+    return oldsz;
+
+  if(PGROUNDDOWN(newsz) < PGROUNDUP(oldsz)){
+    int npages = (PGROUNDUP(oldsz) - PGROUNDDOWN(newsz)) / PGSIZE;
+    vmunmap(kpagetable, PGROUNDDOWN(newsz), npages, 0);
+    vmunmap(pagetable, PGROUNDDOWN(newsz), npages, 1);
+  }
+
+  return newsz;
+}
+
+void
+uvmdeallocpage(pagetable_t pagetable, pagetable_t kpagetable, uint64 a)
+{
+  vmunmap(kpagetable, PGROUNDUP(a), 1, 0);
+  vmunmap(pagetable, PGROUNDUP(a), 1, 1);
+}
+
+// Recursively free page-table pages.
+// All leaf mappings must already have been removed.
+void
+freewalk(pagetable_t pagetable)
+{
+  // // there are 2^9 = 512 PTEs in a page table.
+  // for(int i = 0; i < 512; i++){
+  //   pte_t pte = pagetable[i];
+  //   if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){
+  //     // this PTE points to a lower-level page table.
+  //     uint64 child = PTE2PA(pte);
+  //     if(child != 0)
+  //       freewalk((pagetable_t)child);
+  //     pagetable[i] = 0;
+  //   } else if(pte & PTE_V){
+  //     __ERROR("%p",PTE2PA(pte));
+  //     panic("freewalk: leaf");
+  //   }
+  // }
+  // kfree((void*)pagetable);
+
+  for(int i = 0;i<512;i++){
+    pte_t pte = pagetable[i];
+    if(pte & PTE_V){
+      uint64 child = PTE2PA(pte);
+      pagetable_t pagetable2 = (pagetable_t)child;
+      for(int j = 0;j<512;j++){
+        pte_t pte2 = pagetable2[j];
+        if(pte2 & PTE_V){
+          uint64 child2 = PTE2PA(pte2);
+          pagetable_t pagetable3 = (pagetable_t)child2;
+          kfree((void*)pagetable3);
+        }else{
+          continue;
+        }
+      }
+      kfree((void*)pagetable2);
+    }else{
+      continue;
+    }
+  }
+  kfree((void*)pagetable);
+}
+
+// Free user memory pages,
+// then free page-table pages.
+void
+uvmfree(pagetable_t pagetable, uint64 sz)
+{
+  if(sz > 0)
+    vmunmap(pagetable, 0, PGROUNDUP(sz)/PGSIZE, 1);
+  freewalk(pagetable);
+}
+
+// Given a parent process's page table, copy
+// its memory into a child's page table.
+// Copies both the page table and the
+// physical memory.
+// returns 0 on success, -1 on failure.
+// frees any allocated pages on failure.
+int
+uvmcopy(pagetable_t old, pagetable_t new, pagetable_t knew, uint64 sz)
+{
+  pte_t *pte;
+  uint64 pa, i = 0, ki = 0;
+  uint flags;
+  char *mem;
+
+  while (i < sz){
+    if((pte = walk(old, i, 0)) == NULL)
+      panic("uvmcopy: pte should exist");
+    if((*pte & PTE_V) == 0)
+      panic("uvmcopy: page not present");
+    pa = PTE2PA(*pte);
+    flags = PTE_FLAGS(*pte);
+    if((mem = kalloc()) == NULL)
+      goto err;
+    memmove(mem, (char*)pa, PGSIZE);
+    if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0) {
+      kfree(mem);
+      goto err;
+    }
+    i += PGSIZE;
+    if(mappages(knew, ki, PGSIZE, (uint64)mem, flags & ~PTE_U) != 0){
+      goto err;
+    }
+    ki += PGSIZE;
+  }
+  return 0;
+
+ err:
+  vmunmap(knew, 0, ki / PGSIZE, 0);
+  vmunmap(new, 0, i / PGSIZE, 1);
+  return -1;
+}
+
+
+int
+proc_share(pagetable_t old, pagetable_t new, pagetable_t knew, uint64 start, uint64 end)
+{
+  pte_t *pte;
+  uint64 pa, i = start, ki = start;
+  uint flags;
+  //char *mem;
+  while (i < end){
+    if((pte = walk(old, i, 0)) == NULL)
+      panic("uvmcopy: pte should exist");
+    if((*pte & PTE_V)==0){
+      pte_t *newpte;
+      if((newpte=walk(new,i,1)) == NULL){
+        __ERROR("i == %p",i);
+        panic("");
+      }
+      *newpte = *newpte | PTE_FLAGS(*pte);
+      i+=PGSIZE;
+      ki+=PGSIZE;
+      continue;
+    }
+    if(*pte & PTE_W){
+      *pte |= PTE_C;
+      // __DEBUG("pid %d %s share vaddr %p",myproc()->pid,myproc()->name,i);
+    }
+    *pte=*pte & ~PTE_W;
+    flags = PTE_FLAGS(*pte);
+    pa = PTE2PA(*pte);
+    int index=((uint64)pa-pa_addr_start)/PGSIZE;
+    acquire(&kmem.lock);
+    ++mm_table[index];
+    release(&kmem.lock);
+    // __DEBUG("pa = %p, %p",pa, mm_table[index]);
+    if(mappages(new, i, PGSIZE, pa, flags) != 0) {
+      panic("share fail");
+      goto err;
+    }
+    i += PGSIZE;
+    if(mappages(knew, ki, PGSIZE, pa, flags & ~PTE_U) != 0){
+      goto err;
+    }
+    ki += PGSIZE;
+  }
+  return 0;
+
+ err:
+  vmunmap(knew, 0, ki / PGSIZE, 0);
+  vmunmap(new, 0, i / PGSIZE, 1);
+  return -1;
+}
+
+
+// mark a PTE invalid for user access.
+// used by exec for the user stack guard page.
+void
+uvmclear(pagetable_t pagetable, uint64 va)
+{
+  pte_t *pte;
+  
+  pte = walk(pagetable, va, 0);
+  if(pte == NULL)
+    panic("uvmclear");
+  *pte &= ~PTE_U;
+}
+
+// Copy from kernel to user.
+// Copy len bytes from src to virtual address dstva in a given page table.
+// Return 0 on success, -1 on error.
+int
+copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
+{
+  uint64 n, va0, pa0;
+  while(len > 0){
+    va0 = PGROUNDDOWN(dstva);
+     //__DEBUG("dstva = %p, ra = %p",dstva,r_ra());
+    pa0 = walkaddr(pagetable, va0);
+    if(pa0 == NULL){
+      __ERROR("error");
+      return -1;
+    }
+    n = PGSIZE - (dstva - va0);
+    if(n > len)
+      n = len;
+    memmove((void *)(pa0 + (dstva - va0)), src, n);
+    len -= n;
+    src += n;
+    dstva = va0 + PGSIZE;
+  }
+  return 0;
+}
+
+// int
+// copyout2(uint64 dstva, const char *src, uint64 len)
+// {
+//   uint64 sz = myproc()->sz;
+//   if (dstva + len > sz || dstva >= sz) {
+//     return -1;
+//   }
+//   memmove((void *)dstva, src, len);
+//   return 0;
+// }
+
+// Copy from user to kernel.
+// Copy len bytes to dst from virtual address srcva in a given page table.
+// Return 0 on success, -1 on error.
+int
+copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
+{
+
+  uint64 n, va0, pa0;
+  // __DEBUG("srcva = %p",srcva);
+  while(len > 0){
+    // __DEBUG("srcva = %p",srcva);
+    va0 = PGROUNDDOWN(srcva);
+    // __DEBUG("va0 = %p",va0);
+    pa0 = walkaddr(pagetable, va0);
+    if(pa0 == NULL){
+      __ERROR("error");
+      return -1;
+    }
+    n = PGSIZE - (srcva - va0);
+    if(n > len)
+      n = len;
+    memmove(dst, (void *)(pa0 + (srcva - va0)), n);
+
+    len -= n;
+    dst += n;
+    srcva = va0 + PGSIZE;
+  }
+  return 0;
+}
+
+// int
+// copyin2(char *dst, uint64 srcva, uint64 len)
+// {
+//   uint64 sz = myproc()->sz;
+//   if (srcva + len > sz || srcva >= sz) {
+//     return -1;
+//   }
+//   memmove(dst, (void *)srcva, len);
+//   return 0;
+// }
+
+// Copy a null-terminated string from user to kernel.
+// Copy bytes to dst from virtual address srcva in a given page table,
+// until a '\0', or max.
+// Return 0 on success, -1 on error.
+int
+copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
+{
+  uint64 n, va0, pa0;
+  int got_null = 0;
+
+  while(got_null == 0 && max > 0){
+    va0 = PGROUNDDOWN(srcva);
+    // __DEBUG("va0 = %p");
+    pa0 = walkaddr(pagetable, va0);
+    if(pa0 == NULL)
+      return -1;
+    n = PGSIZE - (srcva - va0);
+    if(n > max)
+      n = max;
+
+    char *p = (char *) (pa0 + (srcva - va0));
+    while(n > 0){
+      if(*p == '\0'){
+        *dst = '\0';
+        got_null = 1;
+        break;
+      } else {
+        *dst = *p;
+      }
+      --n;
+      --max;
+      p++;
+      dst++;
+    }
+
+    srcva = va0 + PGSIZE;
+  }
+  if(got_null){
+    return 0;
+  } else {
+    return -1;
+  }
+}
+
+int
+copyinstr2(char *dst, uint64 srcva, uint64 max)
+{
+  int got_null = 0;
+  uint64 sz = myproc()->sz;
+  while(srcva < sz && max > 0){
+    char *p = (char *)srcva;
+    if(*p == '\0'){
+      *dst = '\0';
+      got_null = 1;
+      break;
+    } else {
+      *dst = *p;
+    }
+    --max;
+    srcva++;
+    dst++;
+  }
+  if(got_null){
+    return 0;
+  } else {
+    return -1;
+  }
+}
+
+// initialize kernel pagetable for each process.
+pagetable_t
+proc_kpagetable()
+{
+  pagetable_t kpt = (pagetable_t) kalloc();
+  if (kpt == NULL)
+    return NULL;
+  memmove(kpt, kernel_pagetable, PGSIZE);
+
+  // remap stack and trampoline, because they share the same page table of level 1 and 0
+  char *pstack = kalloc();
+  if(pstack == NULL)
+    goto fail;
+  if (mappages(kpt, VKSTACK, PGSIZE, (uint64)pstack, PTE_R | PTE_W) != 0)
+    goto fail;
+  
+  return kpt;
+
+fail:
+  kvmfree(kpt, 1);
+  return NULL;
+}
+
+// only free page table, not physical pages
+void
+kfreewalk(pagetable_t kpt)
+{
+  for (int i = 0; i < 512; i++) {
+    pte_t pte = kpt[i];
+    if ((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0) {
+      if(PTE2PA(pte)!= 0){
+        kfreewalk((pagetable_t) PTE2PA(pte));
+      }
+      kpt[i] = 0;
+    } else if (pte & PTE_V) {
+      break;
+    }
+  }
+  kfree((void *) kpt);
+  // pagetable_t pagetable = kpt;
+  // for(int i = 0;i<512;i++){
+  //   pte_t pte = pagetable[i];
+  //   if(pte & PTE_V){
+  //     uint64 child = PTE2PA(pte);
+  //     pagetable_t pagetable2 = (pagetable_t)child;
+  //     kfree((void*)pagetable2);
+  //   }else{
+  //     continue;
+  //   }
+  // }
+  // kfree((void*)pagetable);
+}
+
+void
+kvmfreeusr(pagetable_t kpt)
+{
+  pte_t pte;
+  for (int i = 0; i < PX(2, MAXUVA); i++) {
+    pte = kpt[i];
+    if ((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0) {
+      kfreewalk((pagetable_t) PTE2PA(pte));
+      kpt[i] = 0;
+    }
+  }
+}
+
+void
+kvmfree(pagetable_t kpt, int stack_free)
+{
+  if (stack_free) {
+    vmunmap(kpt, VKSTACK, 1, 1);
+    pte_t pte = kpt[PX(2, VKSTACK)];
+    if ((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0) {
+      kfreewalk((pagetable_t) PTE2PA(pte));
+    }
+  }
+  kvmfreeusr(kpt);
+  kfree(kpt);
+}
+
+void vmprint(pagetable_t pagetable)
+{
+  const int capacity = 512;
+  printf("page table %p\n", pagetable);
+  for (pte_t *pte = (pte_t *) pagetable; pte < pagetable + capacity; pte++) {
+    if (*pte & PTE_V)
+    {
+      pagetable_t pt2 = (pagetable_t) PTE2PA(*pte); 
+      printf("..%d: pte %p pa %p\n", pte - pagetable, *pte, pt2);
+
+      for (pte_t *pte2 = (pte_t *) pt2; pte2 < pt2 + capacity; pte2++) {
+        if (*pte2 & PTE_V)
+        {
+          pagetable_t pt3 = (pagetable_t) PTE2PA(*pte2);
+          printf(".. ..%d: pte %p pa %p\n", pte2 - pt2, *pte2, pt3);
+
+          for (pte_t *pte3 = (pte_t *) pt3; pte3 < pt3 + capacity; pte3++)
+            if (*pte3 & PTE_V)
+              printf(".. .. ..%d: pte %p pa %p\n", pte3 - pt3, *pte3, PTE2PA(*pte3));
+        }
+      }
+    }
+  }
+  return;
+}
+
+int start_map(uint64 start_address,unsigned long len,int prot, struct dirent *ep,long off){
+  if((start_address % PGSIZE) != 0){
+    panic("start_address must be page aligned");
+  }
+  // char *mem;
+  uint64 a = start_address;
+  struct proc*p=myproc();
+  // pagetable_t pagetable = p->pagetable;
+  // pagetable_t kpagetable = p->kpagetable;
+  // uint i, n;
+  // uint64 pa;
+  // for(; a < start_address+(int)len; a += PGSIZE){
+    // mem = kalloc();
+    //printf("%d\n",mem);
+    //printf("alloc a page\n");
+    walkaddr(p->pagetable,a);
+    // if(uvmallocpage(p->pagetable, p->kpagetable, a) < 0){
+    //   __ERROR("error");
+    //   panic("ins fault\n");
+    // }
+    // if(mem == NULL){
+    //   __ERROR("");
+    //   uvmdealloc(pagetable, kpagetable, a, start_address);
+    //   return -1;
+    // }
+    // memset(mem, 0, PGSIZE);
+    // if (mappages(pagetable, a, PGSIZE, (uint64)mem, prot|PTE_U) != 0) {
+    //   __ERROR("");
+    //   kfree(mem);
+    //   uvmdealloc(pagetable, kpagetable, a, start_address);
+    //   return -1;
+    // }
+    // if (mappages(kpagetable, a, PGSIZE, (uint64)mem, prot) != 0){
+    //   __ERROR("");
+    //   int npages = (a - start_address) / PGSIZE;
+    //   vmunmap(pagetable, start_address, npages + 1, 1);
+    //   vmunmap(kpagetable, start_address, npages, 0);
+    //   return -1;
+    // }
+  // }
+  if(ep!=0){
+    if(len > PGSIZE) len = PGSIZE;
+    if(loadseg(p->pagetable,start_address,ep,off,len) < 0){
+      __ERROR("");
+      return -1;
+    }
+    // elock(ep);
+    // if(off+len>ep->file_size){
+    //   len = ep->file_size-off;
+    // }
+    // for(i = 0; i < (int)len; i += PGSIZE){
+    //   // __DEBUG("%p",start_address + i);
+    //   pa = walkaddr(pagetable, start_address + i);
+    //   //printf("%d\n",pa);
+    //   if(pa == NULL)
+    //     panic("start_map: address should exist");
+    //   if(len - i < PGSIZE)
+    //     n = len - i;
+    //   else
+    //     n = PGSIZE;
+    //   if(eread(ep, 0, (uint64)pa, off+i, n) != n){
+    //     __ERROR("");
+    //     return -1;
+    //   }
+    // }
+    // eunlock(ep);
+  }
+  return 1;
+}
+int end_map(uint64 start_address,long len){
+  start_address=PGROUNDDOWN(start_address);
+  len=PGROUNDUP(len);
+  struct proc*p=myproc();
+  pagetable_t pagetable = p->pagetable;
+  pagetable_t kpagetable = p->kpagetable;
+  uvmdealloc(pagetable, kpagetable,start_address+(int)len, start_address);
+  return 1;
+}
+
+int copy_elfseg(pagetable_t pagetable, uint64 src, char *dstva, uint64 len){
+  uint64 n, va0, pa0;
+
+  while(len > 0){
+    va0 = PGROUNDDOWN(src);
+    //printf("------%p\n",va0);
+    // __DEBUG("%p",va0);
+    pa0 = walkaddr(pagetable, va0);
+    if(pa0 == NULL){
+      return -1;
+    }
+    n = PGSIZE - (src - va0);
+    if(n > len)
+      n = len;
+    memmove(dstva, (void *)(pa0 + (src - va0)), n);
+
+    len -= n;
+    dstva += n;
+    src = va0 + PGSIZE;
+  }
+  return 0;
+}
+
+void printfpage(uint64 vaddr){
+  intr_off();
+  vaddr = PGROUNDDOWN(vaddr);
+  struct proc *p = myproc();
+  pte_t *pte = walk(p->pagetable, vaddr, 0);
+  if(*pte == NULL){
+    __ERROR("vaddr %p",vaddr);
+    panic("");
+  }
+  uint64 paddr = PTE2PA(*pte);
+  uint64 *i = (uint64 *)vaddr;
+  __DEBUG("show a page             pid %d %s   vaddr %p   paddr %p",p->pid,p->name,vaddr,paddr);
+  uint64 *start = (uint64 *)paddr;
+  while((uint64)start < paddr + PGSIZE){
+    printf("%p           ", (uint64)i);
+    for(int i=0;i<8;i++){
+      printf("%p  ",(*start));
+      start++;
+      i++;
+    }
+    printf("\n");
+  }
+  intr_on();
+}
+
+int memoryload(uint64 addr){
+  pte_t *pte;
+  struct proc* p=myproc();
+  // __DEBUG("%s",p->name);
+  if(addr >= p->sbrk_base){
+    return 0;
+  }
+  struct elf_seg my;
+  uint64 start = PGROUNDDOWN(addr);
+  uint64 end = start + PGSIZE;
+  // __DEBUG("start = %p",start);
+  // __DEBUG("end = %p",end);
+  if((pte = walk(p->pagetable, addr, 0)) == NULL){
+    __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+    __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+    __DEBUG("p->sbrk_base = %p  p->sz = %p p->mmap_size = %p p->ustack_base = %p",p->sbrk_base,p->sz,p->mmap_size,p->ustack_base);
+    panic("");
+  }
+  if((PTE_V & *pte) == 0){
+    int flags = PTE_FLAGS(*pte);
+    if(uvmallocpage2(p->pagetable, p->kpagetable, start, flags) < 0){
+      __ERROR("error");
+      panic("ins fault\n");
+    }
+    // __DEBUG("map address from %p to %p",start,end - 1);
+    uint64 phaddr = p->my_seg.baseaddr;
+    // __DEBUG("baseaddr = %p",p->my_seg.baseaddr);
+    for(int j=0;j<p->my_seg.num;++j){
+      int flag = 0;
+      uint64 left, right;
+      // __DEBUG("phaddr%d = %p",j,phaddr);
+      if(copy_elfseg(p->pagetable, phaddr,(char *)&my, sizeof(struct elf_seg)) < 0){
+        __ERROR("error");
+        panic("ins fault");
+      }
+      if(my.filesz == 0) continue;
+      // __DEBUG("my%d.filesz = %p",j,my.filesz);
+      // __DEBUG("my%d.memsz = %p",j,my.memsz);
+      // __DEBUG("my%d.vaddr = %p",j,my.vaddr);
+      // __DEBUG("my%d.off = %p",j,my.off);
+      if(start >= my.vaddr && end < my.vaddr + my.filesz - 1){
+        left = start; right = end - 1;
+        flag = 1;
+      }
+      else if((start < my.vaddr && end >= my.vaddr && end < my.vaddr + my.filesz - 1) || 
+      (start >= my.vaddr && end >= my.vaddr + my.filesz - 1 && start < my.vaddr + my.filesz - 1)){
+        left = start > my.vaddr ? start : my.vaddr;
+        right = end - 1 < my.vaddr + my.filesz - 1 ? end - 1 : my.vaddr + my.filesz - 1;
+        flag = 1;
+      }
+      else if(start < my.vaddr && end >= my.vaddr + my.filesz - 1){
+        left = my.vaddr; right = my.vaddr + my.filesz - 1;
+        flag = 1;
+      }
+      if(flag){
+        // __DEBUG("seg%d load address from %p to %p",j ,left, right);
+        if(loadseg(p->pagetable, left, p->myep, my.off + (left - my.vaddr), right - left + 1) < 0){
+          __ERROR("error");
+          panic("ins fault\n");
+        }
+      }
+      phaddr += sizeof(struct elf_seg);
+    }
+    // __DEBUG("");
+    // printfpage(start);
+  }
+  return 1;
+}
+
+int rangeinseg(uint64 start, uint64 end){
+  pte_t *pt = walk(myproc()->pagetable, start, 0);
+  if((*pt & PTE_V) == 0) return 0;
+  pt = walk(myproc()->pagetable, end - 1, 0);
+  if((*pt & PTE_V) == 0) return 0;
+  return 1;
+}
+
+int do_store_fault(uint64 addr){
+  pte_t *pte,*kpte;
+  uint64 pa;
+  char *mem;
+  uint flags;
+  struct proc* p=myproc();
+  if(addr >= p->sz && addr - VMMAP_BASE > p->mmap_size && addr < VMMAP_TOP){
+    pte = walk(p->pagetable, addr, 0);
+    __ERROR("addr = %p p->sz = %p",addr,p->sz);
+    panic("do_store_fault error");
+  }
+  addr=PGROUNDDOWN(addr);
+  // if(addr == 0){
+  //   __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+  //   __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+  //   __DEBUG("p->sbrk_base = %p  p->sz = %p p->mmap_size = %p p->ustack_base = %p",p->sbrk_base,p->sz,p->mmap_size,p->ustack_base);
+  // }
+  uint64 oldustack_base=p->ustack_base;
+  uint64 faultaddr=addr;
+  if(addr > VMMAP_TOP && addr < p->ustack_base){
+    // __DEBUG("try to grow stack");
+    while(faultaddr<oldustack_base){
+      if((pte = walk(p->pagetable, faultaddr, 1)) == NULL){
+        __ERROR("grow stack failed");
+        panic("");
+      }
+      *pte = PTE_W | PTE_R | PTE_U;
+      if((kpte = walk(p->kpagetable, faultaddr, 1)) == NULL){
+        __ERROR("grow stack failed");
+        panic("");
+      }
+      *kpte=*pte& ~PTE_U;
+      p->ustack_base -= PGSIZE;
+      faultaddr+=PGSIZE;
+    }
+    // __DEBUG("grow stack success, new ustackbase = %p",p->ustack_base);
+  }
+  if((pte = walk(p->pagetable, addr, 0)) == NULL){
+    kill(p->pid);
+    //panic("do_store_fault: pte should exist");
+  }
+  if((*pte & PTE_U) == 0){
+    __ERROR("addr %p not PTE_U",addr);
+    kill(p->pid);
+    // panic("");
+  }
+  else if((*pte&PTE_C)){
+    if((mem = kalloc()) == NULL)
+      panic("no free page");
+    memset(mem, 0, PGSIZE);
+    pa = PTE2PA(*pte);
+    memmove((void *)mem,(const void *)pa,PGSIZE);
+    kfree((void *)pa);
+    // int index=((uint64)pa-pa_addr_start)/PGSIZE;
+    // __DEBUG("pid %d addr %p %p",p->pid,addr,mm_table[index]);
+    flags = PTE_FLAGS(*pte);
+    *pte=(PA2PTE((uint64)mem)|flags|PTE_W) & (~PTE_C);
+    if((kpte = walk(p->kpagetable, addr, 0)) == NULL){
+      kill(p->pid);
+      // panic("do_store_fault: kpte should exist");
+    }
+    *kpte=*pte& ~PTE_U;
+    sfence_vma();
+    // __DEBUG("");
+    // printfpage(addr);
+    // __DEBUG("pid %d enble %p write",p->pid,addr);
+  }
+  else if((*pte & PTE_W) && (*pte & PTE_V) == 0){
+    if((mem = kalloc()) == NULL)
+      panic("no page");
+    memset(mem, 0, PGSIZE);
+    pa = PTE2PA(*pte);
+    flags = PTE_FLAGS(*pte);
+    *pte=PA2PTE((uint64)mem)|flags|PTE_V;
+    if((kpte = walk(p->kpagetable, addr, 0)) == NULL)
+      panic("do_store_fault: kpte should exist");
+    *kpte=*pte& ~PTE_U;
+  }
+  else if((*pte & PTE_W) == 0 && (*pte & PTE_V)){
+    // __ERROR("vaddr %p can't write",addr);
+    // __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+    // __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+    // __DEBUG("p->sbrk_base = %p  p->sz = %p p->mmap_size = %p p->ustack_base = %p",p->sbrk_base,p->sz,p->mmap_size,p->ustack_base);
+    // trapframedump(p->trapframe);
+    // panic("");
+    kill(p->pid);
+  }else{
+
+  }
+  return 1;
+}
+
+int do_load_fault(uint64 addr){
+  pte_t *pte,*kpte;
+  char *mem;
+  struct proc* p=myproc();
+  if(addr >= p->sz && addr - VMMAP_BASE > p->mmap_size && addr < VMMAP_TOP){
+    pte = walk(p->pagetable, addr, 0);
+    __ERROR("addr = %p",addr);
+    panic("do_store_fault error");
+  }
+  addr=PGROUNDDOWN(addr);
+  // if(addr == 0){
+  //   __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+  //   __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+  //   __DEBUG("p->sbrk_base = %p  p->sz = %p p->mmap_size = %p p->ustack_base = %p",p->sbrk_base,p->sz,p->mmap_size,p->ustack_base);
+  // }
+  if(addr > VMMAP_TOP && addr < p->ustack_base){
+    // __DEBUG("try to grow stack");
+    if((pte = walk(p->pagetable, addr, 1)) == NULL){
+      __ERROR("grow stack failed");
+      panic("");
+    }
+    *pte = PTE_W | PTE_R | PTE_U;
+    if((kpte = walk(p->kpagetable, addr, 1)) == NULL){
+      __ERROR("grow stack failed");
+      panic("");
+    }
+    *kpte=*pte& ~PTE_U;
+    p->ustack_base -= PGSIZE;
+    // __DEBUG("grow stack success, new ustackbase = %p",p->ustack_base);
+  }
+  if((pte = walk(p->pagetable, addr, 0)) == NULL){
+    kill(p->pid);
+    //panic("do_load_fault: pte should exist");
+  }
+  if((*pte & PTE_U) == 0){
+    __ERROR("addr %p not PTE_U",addr);
+    kill(p->pid);
+    // panic("");
+  }
+  else if((*pte&PTE_V) == 0 && (*pte & PTE_R)){
+    if((mem = kalloc()) == NULL)
+      panic("no page");
+    memset(mem, 0, PGSIZE);
+    uint64 flags = PTE_FLAGS(*pte);
+    *pte=PA2PTE((uint64)mem)|flags|PTE_V;
+    if((kpte = walk(p->kpagetable, addr, 0)) == NULL){
+      kill(p->pid);
+      // panic("do_store_fault: kpte should exist");
+    }
+    *kpte=*pte& ~PTE_U;
+  }
+  else if((*pte&PTE_V) && (*pte&PTE_R)){
+    // __DEBUG("pa = %p, va = %p",*pte,PTE2PA(*pte),addr);
+  }
+  else{
+    // __ERROR("vaddr %p can't read",addr);
+    // __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+    // __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+    // __DEBUG("p->sbrk_base = %p  p->sz = %p p->mmap_size = %p p->ustack_base = %p",p->sbrk_base,p->sz,p->mmap_size,p->ustack_base);
+    // trapframedump(p->trapframe);
+    // panic("");
+    kill(p->pid);
+  }
+  return 1;
+}
+
+int do_ins_fault(uint64 addr){
+  
+  pte_t *pte,*kpte;
+  char *mem;
+  struct proc* p=myproc();
+  if(addr >= p->sz && addr - VMMAP_BASE > p->mmap_size && addr < VMMAP_TOP){
+    pte = walk(p->pagetable, addr, 0);
+    __ERROR("addr = %p",addr);
+    panic("do_store_fault error");
+  }
+  addr=PGROUNDDOWN(addr);
+  if((pte = walk(p->pagetable, addr, 0)) == NULL)
+    panic("do_load_fault: pte should exist");
+  if((*pte & PTE_U) == 0){
+    __ERROR("addr %p not PTE_U",addr);
+    panic("");
+  }
+  if((*pte&PTE_V) == 0 && (*pte & PTE_X)){
+    if((mem = kalloc()) == NULL)
+      panic("no page");
+    memset(mem, 0, PGSIZE);
+    uint64 flags = PTE_FLAGS(*pte);
+    *pte=PA2PTE((uint64)mem)|flags|PTE_V;
+    if((kpte = walk(p->kpagetable, addr, 0)) == NULL)
+      panic("do_store_fault: kpte should exist");
+    *kpte=*pte& ~PTE_U;
+  }
+  else if((*pte&PTE_V) && (*pte&PTE_X)){
+    // __DEBUG("pa = %p, va = %p",*pte,PTE2PA(*pte),addr);
+  }
+  else{
+    // __ERROR("vaddr %p can't execute",addr);
+    // __DEBUG("usertrap(): unexpected scause %p pid=%d %s", r_scause(), p->pid, p->name);
+    // __DEBUG("            sepc=%p stval=%p", r_sepc(), r_stval());
+    // __DEBUG("p->sbrk_base = %p  p->sz = %p p->mmap_size = %p p->ustack_base = %p",p->sbrk_base,p->sz,p->mmap_size,p->ustack_base);
+    // trapframedump(p->trapframe);
+    // panic("");
+    kill(p->pid);
+    
+  }
+  return 1;
+}
\ No newline at end of file
diff --git a/kernel/xv6-riscv-license b/kernel/xv6-riscv-license
new file mode 100644
index 0000000000000000000000000000000000000000..bd4fb5bfcb80957d5c88e2b14a3df63d3510598c
--- /dev/null
+++ b/kernel/xv6-riscv-license
@@ -0,0 +1,23 @@
+The xv6 software is:
+
+Copyright (c) 2006-2019 Frans Kaashoek, Robert Morris, Russ Cox,
+                        Massachusetts Institute of Technology
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/kernel/zero.c b/kernel/zero.c
new file mode 100644
index 0000000000000000000000000000000000000000..5dd1ec4b241fc9508dbda03f958b179b0717c73c
--- /dev/null
+++ b/kernel/zero.c
@@ -0,0 +1,35 @@
+#include "include/types.h"
+#include "include/proc.h"
+#include "include/string.h"
+#include "include/zero.h"
+
+#define ZERO_DEV 5
+#define ZEROBUGSIZE 128
+
+char zerobuf[ZEROBUGSIZE];
+
+int zeroread(int user_dst, uint64 dst, int n)
+{
+    int count = 0;
+    int c = n;
+    while(c > 0){
+        if(c > ZEROBUGSIZE) count  = ZEROBUGSIZE;
+        else count = c;
+        if(either_copyout(user_dst, dst, (void *)zerobuf, count) < 0){
+            return n - c;
+        }
+        c -= count;
+    }
+    return n;
+}
+
+int zerowrite(int user_src, uint64 src, int n)
+{
+    return 0;
+}
+
+void zeroinit(){
+    memset((void *)zerobuf, 0, sizeof(zerobuf));
+    devsw[ZERO_DEV].read = zeroread;
+    devsw[ZERO_DEV].write = zerowrite;
+}