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; +}