From d6ce30924713db3a1355e0c644adb9e845f1df4e Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Wed, 10 Apr 2019 00:38:31 +0800 Subject: [PATCH 01/61] Fix some review issues. --- kernel/src/arch/mipsel/compiler_rt.rs | 8 -------- kernel/src/arch/mipsel/context.rs | 4 ++-- kernel/src/arch/mipsel/cpu.rs | 3 ++- 3 files changed, 4 insertions(+), 11 deletions(-) delete mode 100644 kernel/src/arch/mipsel/compiler_rt.rs diff --git a/kernel/src/arch/mipsel/compiler_rt.rs b/kernel/src/arch/mipsel/compiler_rt.rs deleted file mode 100644 index b49a3ce..0000000 --- a/kernel/src/arch/mipsel/compiler_rt.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Workaround for missing compiler-builtin symbols -//! -//! [atomic](http://llvm.org/docs/Atomics.html#libcalls-atomic) - -#[no_mangle] -pub extern fn abort() { - panic!("abort"); -} diff --git a/kernel/src/arch/mipsel/context.rs b/kernel/src/arch/mipsel/context.rs index 7e473ad..e0502ee 100644 --- a/kernel/src/arch/mipsel/context.rs +++ b/kernel/src/arch/mipsel/context.rs @@ -50,8 +50,8 @@ pub struct TrapFrame { pub sp: usize, pub fp: usize, pub ra: usize, - /// Reserve space for hartid - pub _hartid: usize, + /// Reserved + pub reserved: usize, } impl TrapFrame { diff --git a/kernel/src/arch/mipsel/cpu.rs b/kernel/src/arch/mipsel/cpu.rs index ea27d1f..764d472 100644 --- a/kernel/src/arch/mipsel/cpu.rs +++ b/kernel/src/arch/mipsel/cpu.rs @@ -1,4 +1,5 @@ use mips::registers::cp0; +use mips::instructions; use crate::consts::MAX_CPU_NUM; use core::ptr::{read_volatile, write_volatile}; @@ -21,7 +22,7 @@ pub unsafe fn start_others(hart_mask: usize) { } pub fn halt() { - /* nothing to do */ + unsafe { instructions::wait(); } } pub unsafe fn exit_in_qemu(error_code: u8) -> ! { From 657395784df6a3fc2a05ae246a9097c2445cd2ff Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Mon, 15 Apr 2019 13:02:06 +0800 Subject: [PATCH 02/61] Fix compile errors. --- kernel/src/arch/mipsel/cpu.rs | 1 - kernel/src/arch/mipsel/mod.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/kernel/src/arch/mipsel/cpu.rs b/kernel/src/arch/mipsel/cpu.rs index 0d21616..764d472 100644 --- a/kernel/src/arch/mipsel/cpu.rs +++ b/kernel/src/arch/mipsel/cpu.rs @@ -2,7 +2,6 @@ use mips::registers::cp0; use mips::instructions; use crate::consts::MAX_CPU_NUM; use core::ptr::{read_volatile, write_volatile}; -use mips::registers::cp0; static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM]; diff --git a/kernel/src/arch/mipsel/mod.rs b/kernel/src/arch/mipsel/mod.rs index 74103db..cf13942 100644 --- a/kernel/src/arch/mipsel/mod.rs +++ b/kernel/src/arch/mipsel/mod.rs @@ -1,4 +1,3 @@ -pub mod compiler_rt; pub mod consts; pub mod cpu; pub mod driver; From bfa4c9d47eb78cf0563eff3bfd20bcc0bf971b96 Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Mon, 15 Apr 2019 14:14:07 +0800 Subject: [PATCH 03/61] Support TLS for MIPS. --- kernel/src/arch/mipsel/boot/context.S | 56 +++++++++++-------- kernel/src/arch/mipsel/boot/trap.S | 3 + kernel/src/arch/mipsel/context.rs | 23 ++++---- kernel/src/arch/mipsel/interrupt.rs | 80 +++++++++++++++++++++++++++ kernel/src/syscall/mod.rs | 28 ++++++++++ 5 files changed, 156 insertions(+), 34 deletions(-) diff --git a/kernel/src/arch/mipsel/boot/context.S b/kernel/src/arch/mipsel/boot/context.S index 534ede5..d81e961 100644 --- a/kernel/src/arch/mipsel/boot/context.S +++ b/kernel/src/arch/mipsel/boot/context.S @@ -7,22 +7,23 @@ .globl switch_context .extern _root_page_table_ptr .extern _cur_kstack_ptr +.extern _cur_tls switch_context: // save from's registers addi sp, sp, (-4*14) sw sp, 0(a0) sw ra, 0(sp) - sw s0, 2*4(sp) - sw s1, 3*4(sp) - sw s2, 4*4(sp) - sw s3, 5*4(sp) - sw s4, 6*4(sp) - sw s5, 7*4(sp) - sw s6, 8*4(sp) - sw s7, 9*4(sp) - sw s8, 10*4(sp) - sw gp, 11*4(sp) + sw s0, 4*4(sp) + sw s1, 5*4(sp) + sw s2, 6*4(sp) + sw s3, 7*4(sp) + sw s4, 8*4(sp) + sw s5, 9*4(sp) + sw s6, 10*4(sp) + sw s7, 11*4(sp) + sw s8, 12*4(sp) + sw gp, 13*4(sp) // sw ra, 12*4(sp) // sw sp, 13*4(sp) @@ -31,27 +32,34 @@ switch_context: lw s1, 0(s0) sw s1, 4(sp) + // save TLS + la s2, _cur_tls + lw s1, 0(s2) + sw s1, 2*4(sp) + // restore to's registers lw sp, 0(a1) + + // restore page table address lw s1, 4(sp) sw s1, 0(s0) - // restore kstack ptr - // la s0, _cur_kstack_ptr - // addi s1, sp, 4 * 14 - // sw s1, 0(s0) + // restore TLS + lw s1, 2*4(sp) + sw s1, 0(s2) + mtc0 s1, $4, 2 // cp0.user_local lw ra, 0(sp) - lw s0, 2*4(sp) - lw s1, 3*4(sp) - lw s2, 4*4(sp) - lw s3, 5*4(sp) - lw s4, 6*4(sp) - lw s5, 7*4(sp) - lw s6, 8*4(sp) - lw s7, 9*4(sp) - lw s8, 10*4(sp) - lw gp, 11*4(sp) + lw s0, 4*4(sp) + lw s1, 5*4(sp) + lw s2, 6*4(sp) + lw s3, 7*4(sp) + lw s4, 8*4(sp) + lw s5, 9*4(sp) + lw s6, 10*4(sp) + lw s7, 11*4(sp) + lw s8, 12*4(sp) + lw gp, 13*4(sp) addi sp, sp, (4*14) sw zero, 0(a1) diff --git a/kernel/src/arch/mipsel/boot/trap.S b/kernel/src/arch/mipsel/boot/trap.S index 2d40343..44d48d2 100644 --- a/kernel/src/arch/mipsel/boot/trap.S +++ b/kernel/src/arch/mipsel/boot/trap.S @@ -177,3 +177,6 @@ _root_page_table_ptr: .global _cur_kstack_ptr _cur_kstack_ptr: .space 4 # 4bytes + .global _cur_tls +_cur_tls: + .space 4 # 4bytes diff --git a/kernel/src/arch/mipsel/context.rs b/kernel/src/arch/mipsel/context.rs index e5e2053..eec9bde 100644 --- a/kernel/src/arch/mipsel/context.rs +++ b/kernel/src/arch/mipsel/context.rs @@ -130,17 +130,21 @@ struct ContextData { ra: usize, /// Page table token satp: usize, - /// Callee-saved registers + /// s[0] = TLS + /// s[1] = reserved + /// s[2..11] = Callee-saved registers s: [usize; 12], } impl ContextData { - fn new(satp: usize) -> Self { - ContextData { + fn new(satp: usize, tls: usize) -> Self { + let mut context = ContextData { ra: trap_return as usize, - satp, + satp: satp, ..ContextData::default() - } + }; + context.s[0] = tls; + context } } @@ -191,7 +195,7 @@ impl Context { ); InitStack { - context: ContextData::new(satp), + context: ContextData::new(satp, 0), tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top), } .push_at(kstack_top) @@ -215,7 +219,7 @@ impl Context { ); InitStack { - context: ContextData::new(satp), + context: ContextData::new(satp, 0), tf: TrapFrame::new_user_thread(entry_addr, ustack_top), } .push_at(kstack_top) @@ -228,7 +232,7 @@ impl Context { /// All the other registers are same as the original. pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Self { InitStack { - context: ContextData::new(satp), + context: ContextData::new(satp, 0), tf: { let mut tf = tf.clone(); // fork function's ret value, the new process is 0 @@ -254,11 +258,10 @@ impl Context { tls: usize, ) -> Self { InitStack { - context: ContextData::new(satp), + context: ContextData::new(satp, tls), tf: { let mut tf = tf.clone(); tf.sp = ustack_top; // sp - tf.v1 = tls; tf.v0 = 0; // return value tf }, diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index bc60547..5ae84dd 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -70,6 +70,14 @@ pub extern "C" fn rust_trap(tf: &mut TrapFrame) { E::TLBModification => page_fault(tf), E::TLBLoadMiss => page_fault(tf), E::TLBStoreMiss => page_fault(tf), + E::ReservedInstruction => { + if !reserved_inst(tf) { + error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); + crate::trap::error(tf) + } else { + tf.epc = tf.epc + 4; + } + } _ => { error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); crate::trap::error(tf) @@ -149,6 +157,78 @@ fn syscall(tf: &mut TrapFrame) { } } +fn set_trapframe_register(rt: usize, val: usize, tf: &mut TrapFrame) { + match rt { + 1 => tf.at = val, + 2 => tf.v0 = val, + 3 => tf.v1 = val, + 4 => tf.a0 = val, + 5 => tf.a1 = val, + 6 => tf.a2 = val, + 7 => tf.a3 = val, + 8 => tf.t0 = val, + 9 => tf.t1 = val, + 10 => tf.t2 = val, + 11 => tf.t3 = val, + 12 => tf.t4 = val, + 13 => tf.t5 = val, + 14 => tf.t6 = val, + 15 => tf.t7 = val, + 16 => tf.s0 = val, + 17 => tf.s1 = val, + 18 => tf.s2 = val, + 19 => tf.s3 = val, + 20 => tf.s4 = val, + 21 => tf.s5 = val, + 22 => tf.s6 = val, + 23 => tf.s7 = val, + 24 => tf.t8 = val, + 25 => tf.t9 = val, + 26 => tf.k0 = val, + 27 => tf.k1 = val, + 28 => tf.gp = val, + 29 => tf.sp = val, + 30 => tf.fp = val, + 31 => tf.ra = val, + _ => { + error!("Unknown register {:?} ", rt); + crate::trap::error(tf) + } + } +} + +fn reserved_inst(tf: &mut TrapFrame) -> bool { + let inst = unsafe { + *(tf.epc as *const usize) + }; + + let opcode = inst >> 26; + let rt = (inst >> 16) & 0b11111; + let rd = (inst >> 11) & 0b11111; + let sel = (inst >> 6) & 0b111; + let format = inst & 0b111111; + + if opcode == 0b011111 && format == 0b111011 { + // RDHWR + if rd == 29 && sel == 0 { + info!("Read TLS by rdhdr"); + extern "C" { + fn _cur_tls(); + } + + let tls = unsafe { + *(_cur_tls as *const usize) + }; + set_trapframe_register(rt, tls, tf); + return true; + } else { + return false; + } + } + + false +} + fn page_fault(tf: &mut TrapFrame) { // TODO: set access/dirty bit let addr = tf.vaddr; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 0787d83..11558d3 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -288,8 +288,15 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { let x86_64_ret = x86_64_syscall(id, args, tf); #[cfg(not(target_arch = "x86_64"))] let x86_64_ret = None; + + #[cfg(target_arch = "mips")] + let mips_ret = mips_syscall(id, args, tf); + #[cfg(not(target_arch = "mips"))] + let mips_ret = None; if let Some(ret) = x86_64_ret { ret + } else if let Some(ret) = mips_ret { + ret } else { error!("unknown syscall id: {}, args: {:x?}", id, args); crate::trap::error(tf); @@ -309,6 +316,27 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { } } +#[cfg(target_arch = "mips")] +fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { + let ret = match id { + SYS_SET_THREAD_AREA => { + extern "C" { + fn _cur_tls(); + } + + unsafe { + asm!("mtc0 $0, $$4, 2": :"r"(args[0])); + *(_cur_tls as *mut usize) = args[0]; + } + Ok(0) + } + _ => { + return None; + } + }; + Some(ret) +} + #[cfg(target_arch = "x86_64")] fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { let ret = match id { From 9075a172ad726672eb7e1d6e43e4c9a435368f7a Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Mon, 15 Apr 2019 15:45:09 +0800 Subject: [PATCH 04/61] Fix iovec size for MIPSn32. --- kernel/src/syscall/fs.rs | 3 +++ kernel/src/syscall/mod.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index b16fe73..d94e8b5 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -1074,6 +1074,9 @@ pub struct IoVec { /// Starting address base: *mut u8, /// Number of bytes to transfer + #[cfg(target_arch = "mips")] + len: u32, + #[cfg(not(target_arch = "mips"))] len: u64, } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 11558d3..961f794 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -319,6 +319,9 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { #[cfg(target_arch = "mips")] fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { let ret = match id { + SYS_OPEN => sys_open(args[0] as *const u8, args[1], args[2]), + SYS_DUP2 => sys_dup2(args[0], args[1]), + SYS_MMAP2 => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), SYS_SET_THREAD_AREA => { extern "C" { fn _cur_tls(); From dc90cb5a8d97c537ffd0df97a0845fc8bb57f354 Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Mon, 15 Apr 2019 18:09:48 +0800 Subject: [PATCH 05/61] Fix pgfault, fstat syscall convention. biscuit/ls works! --- kernel/src/arch/mipsel/interrupt.rs | 16 +++++++ kernel/src/syscall/fs.rs | 67 ++++++++++++++++++++++++++++- kernel/src/syscall/mem.rs | 15 +++++++ kernel/src/syscall/mod.rs | 6 +++ 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index 5ae84dd..1c45132 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -78,6 +78,9 @@ pub extern "C" fn rust_trap(tf: &mut TrapFrame) { tf.epc = tf.epc + 4; } } + E::CoprocessorUnusable => { + tf.epc = tf.epc + 4; + } _ => { error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); crate::trap::error(tf) @@ -244,6 +247,19 @@ fn page_fault(tf: &mut TrapFrame) { tlb_entry.entry_lo0.get_pfn() << 12, tlb_entry.entry_lo1.get_pfn() << 12 ); + + let tlb_valid = if virt_addr.page_number() & 1 == 0 { + tlb_entry.entry_lo0.valid() + } else { + tlb_entry.entry_lo1.valid() + }; + + if !tlb_valid { + if !crate::memory::handle_page_fault(addr) { + crate::trap::error(tf); + } + } + tlb::write_tlb_random(tlb_entry) } Err(()) => { diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index d94e8b5..7035b31 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -913,7 +913,48 @@ pub struct Stat { ctime: Timespec, } -#[cfg(not(target_arch = "x86_64"))] +#[cfg(target_arch = "mips")] +#[repr(C)] +#[derive(Debug)] +pub struct Stat { + /// ID of device containing file + dev: u64, + /// padding + __pad1: u64, + /// inode number + ino: u64, + /// file type and mode + mode: StatMode, + /// number of hard links + nlink: u32, + + /// user ID of owner + uid: u32, + /// group ID of owner + gid: u32, + /// device ID (if special file) + rdev: u64, + /// padding + __pad2: u64, + /// total size, in bytes + size: u64, + + /// last access time + atime: Timespec, + /// last modification time + mtime: Timespec, + /// last status change time + ctime: Timespec, + + /// blocksize for filesystem I/O + blksize: u32, + /// padding + __pad3: u32, + /// number of 512B blocks allocated + blocks: u64, +} + +#[cfg(not(any(target_arch = "x86_64", target_arch = "mips"))] #[repr(C)] #[derive(Debug)] pub struct Stat { @@ -1042,7 +1083,29 @@ impl From for Stat { } } - #[cfg(not(target_arch = "x86_64"))] + #[cfg(target_arch = "mips")] + fn from(info: Metadata) -> Self { + Stat { + dev: info.dev as u64, + ino: info.inode as u64, + mode: StatMode::from_type_mode(info.type_, info.mode as u16), + nlink: info.nlinks as u32, + uid: info.uid as u32, + gid: info.gid as u32, + rdev: 0, + size: info.size as u64, + blksize: info.blk_size as u32, + blocks: info.blocks as u64, + atime: info.atime, + mtime: info.mtime, + ctime: info.ctime, + __pad1: 0, + __pad2: 0, + __pad3: 0, + } + } + + #[cfg(not(any(target_arch = "x86_64", target_arch="mips")))] fn from(info: Metadata) -> Self { Stat { dev: info.dev as u64, diff --git a/kernel/src/syscall/mem.rs b/kernel/src/syscall/mem.rs index 1c5bee9..0b471c2 100644 --- a/kernel/src/syscall/mem.rs +++ b/kernel/src/syscall/mem.rs @@ -123,6 +123,21 @@ bitflags! { } } +#[cfg(target_arch = "mips")] +bitflags! { + pub struct MmapFlags: usize { + /// Changes are shared. + const SHARED = 1 << 0; + /// Changes are private. + const PRIVATE = 1 << 1; + /// Place the mapping at the exact address + const FIXED = 1 << 4; + /// The mapping is not backed by any file. (non-POSIX) + const ANONYMOUS = 0x800; + } +} + +#[cfg(not(target_arch = "mips"))] bitflags! { pub struct MmapFlags: usize { /// Changes are shared. diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 961f794..efc5c0f 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -322,6 +322,12 @@ fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option sys_open(args[0] as *const u8, args[1], args[2]), SYS_DUP2 => sys_dup2(args[0], args[1]), SYS_MMAP2 => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), + SYS_FSTAT64 => sys_fstat(args[0], args[1] as *mut Stat), + SYS_STAT64 => sys_stat(args[0] as *const u8, args[1] as *mut Stat), + SYS_FCNTL64 => { + warn!("sys_fcntl64 is unimplemented"); + Ok(0) + } SYS_SET_THREAD_AREA => { extern "C" { fn _cur_tls(); From 9532311c1e4915341ad655f5a556e89daae22ba7 Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Tue, 16 Apr 2019 01:31:00 +0800 Subject: [PATCH 06/61] Copy TLS data in sys_fork. --- kernel/src/arch/mipsel/context.rs | 4 +++- kernel/src/arch/mipsel/interrupt.rs | 3 ++- kernel/src/syscall/mod.rs | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/src/arch/mipsel/context.rs b/kernel/src/arch/mipsel/context.rs index eec9bde..f84ae70 100644 --- a/kernel/src/arch/mipsel/context.rs +++ b/kernel/src/arch/mipsel/context.rs @@ -120,6 +120,7 @@ impl InitStack { extern "C" { fn trap_return(); + fn _cur_tls(); } /// Saved registers for kernel context switches. @@ -231,8 +232,9 @@ impl Context { /// The SATP register will be set to `satp`. /// All the other registers are same as the original. pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Self { + let tls = unsafe { *(_cur_tls as *const usize) }; InitStack { - context: ContextData::new(satp, 0), + context: ContextData::new(satp, tls), tf: { let mut tf = tf.clone(); // fork function's ret value, the new process is 0 diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index 1c45132..1036ffb 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -214,7 +214,6 @@ fn reserved_inst(tf: &mut TrapFrame) -> bool { if opcode == 0b011111 && format == 0b111011 { // RDHWR if rd == 29 && sel == 0 { - info!("Read TLS by rdhdr"); extern "C" { fn _cur_tls(); } @@ -222,7 +221,9 @@ fn reserved_inst(tf: &mut TrapFrame) -> bool { let tls = unsafe { *(_cur_tls as *const usize) }; + set_trapframe_register(rt, tls, tf); + info!("Read TLS by rdhdr {:x} to register {:?}", tls, rt); return true; } else { return false; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index efc5c0f..6082afc 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -319,6 +319,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { #[cfg(target_arch = "mips")] fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { let ret = match id { + SYS_FORK => sys_fork(tf), SYS_OPEN => sys_open(args[0] as *const u8, args[1], args[2]), SYS_DUP2 => sys_dup2(args[0], args[1]), SYS_MMAP2 => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), @@ -329,6 +330,7 @@ fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { + info!("set_thread_area: tls: 0x{:x}", args[0]); extern "C" { fn _cur_tls(); } From f5fe3ce4f3f34f8c7a3f29674d27fce879de4013 Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Tue, 16 Apr 2019 02:10:36 +0800 Subject: [PATCH 07/61] Move userstack to 0x60000000. --- kernel/src/arch/mipsel/consts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/src/arch/mipsel/consts.rs b/kernel/src/arch/mipsel/consts.rs index ff2ef0c..84ae103 100644 --- a/kernel/src/arch/mipsel/consts.rs +++ b/kernel/src/arch/mipsel/consts.rs @@ -6,8 +6,8 @@ pub const KERNEL_OFFSET: usize = 0x80100000; pub const MEMORY_OFFSET: usize = 0x8000_0000; -pub const USER_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE; +pub const USER_STACK_OFFSET: usize = 0x70000000 - USER_STACK_SIZE; pub const USER_STACK_SIZE: usize = 0x10000; -pub const USER32_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE; +pub const USER32_STACK_OFFSET: usize = 0x70000000 - USER_STACK_SIZE; pub const MAX_DTB_SIZE: usize = 0x2000; From 189c4aa5c6ba13380b49a8aa1a7b527dcc3a85fb Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Tue, 16 Apr 2019 02:42:44 +0800 Subject: [PATCH 08/61] Support sys_pipe for MIPS. --- kernel/src/syscall/mod.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 6082afc..86666ba 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -325,10 +325,23 @@ fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), SYS_FSTAT64 => sys_fstat(args[0], args[1] as *mut Stat), SYS_STAT64 => sys_stat(args[0] as *const u8, args[1] as *mut Stat), + SYS_PIPE => { + let fd_ptr = args[0] as *mut u32; + match sys_pipe(fd_ptr) { + Ok(code) => { + unsafe { + tf.v0 = *fd_ptr as usize; + tf.v1 = *(fd_ptr.add(1)) as usize; + } + Ok(tf.v0) + }, + Err(err) => Err(err) + } + }, SYS_FCNTL64 => { warn!("sys_fcntl64 is unimplemented"); Ok(0) - } + }, SYS_SET_THREAD_AREA => { info!("set_thread_area: tls: 0x{:x}", args[0]); extern "C" { From 3e7dd81dec5121fda7f606d0912ad489b82cfae7 Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Wed, 17 Apr 2019 17:37:28 +0800 Subject: [PATCH 09/61] Add lstat, fix timespec for musln32. --- kernel/src/syscall/fs.rs | 14 +++++++++++--- kernel/src/syscall/mod.rs | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 7035b31..1017332 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -3,6 +3,7 @@ use core::cell::UnsafeCell; use core::cmp::min; use core::mem::size_of; +#[cfg(not(target_arch = "mips"))] use rcore_fs::vfs::Timespec; use crate::drivers::SOCKET_ACTIVITY; @@ -913,6 +914,13 @@ pub struct Stat { ctime: Timespec, } +#[cfg(target_arch = "mips")] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Timespec { + pub sec: i32, + pub nsec: i32, +} + #[cfg(target_arch = "mips")] #[repr(C)] #[derive(Debug)] @@ -1096,9 +1104,9 @@ impl From for Stat { size: info.size as u64, blksize: info.blk_size as u32, blocks: info.blocks as u64, - atime: info.atime, - mtime: info.mtime, - ctime: info.ctime, + atime: Timespec { sec: info.atime.sec as i32, nsec: info.atime.nsec }, + mtime: Timespec { sec: info.mtime.sec as i32, nsec: info.mtime.nsec }, + ctime: Timespec { sec: info.ctime.sec as i32, nsec: info.ctime.nsec }, __pad1: 0, __pad2: 0, __pad3: 0, diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 86666ba..49051ec 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -324,6 +324,7 @@ fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option sys_dup2(args[0], args[1]), SYS_MMAP2 => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), SYS_FSTAT64 => sys_fstat(args[0], args[1] as *mut Stat), + SYS_LSTAT64 => sys_lstat(args[0] as *const u8, args[1] as *mut Stat), SYS_STAT64 => sys_stat(args[0] as *const u8, args[1] as *mut Stat), SYS_PIPE => { let fd_ptr = args[0] as *mut u32; From d2f2fa3d9744f25418438f195513be94dedd1f17 Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Wed, 17 Apr 2019 17:42:05 +0800 Subject: [PATCH 10/61] Two syscall for mips. --- kernel/src/syscall/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 49051ec..4f81361 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -339,6 +339,14 @@ fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option Err(err) } }, + SYS_GETPGID => { + warn!("sys_getpgid is unimplemented"); + Ok(0) + } + SYS_SETPGID => { + warn!("sys_setpgid is unimplemented"); + Ok(0) + } SYS_FCNTL64 => { warn!("sys_fcntl64 is unimplemented"); Ok(0) From 0ff24fe5898f11ea1452ac6edc500d53c133bee4 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 18 Apr 2019 17:43:35 +0800 Subject: [PATCH 11/61] Implement env support in sys_exec --- kernel/src/process/abi.rs | 8 +++----- kernel/src/process/structs.rs | 13 +++++++++---- kernel/src/shell.rs | 26 +++++++++++++++++--------- kernel/src/syscall/mod.rs | 4 ++-- kernel/src/syscall/proc.rs | 35 ++++++++++++++++++++--------------- 5 files changed, 51 insertions(+), 35 deletions(-) diff --git a/kernel/src/process/abi.rs b/kernel/src/process/abi.rs index 913fb1a..dcaa428 100644 --- a/kernel/src/process/abi.rs +++ b/kernel/src/process/abi.rs @@ -5,7 +5,7 @@ use core::ptr::null; pub struct ProcInitInfo { pub args: Vec, - pub envs: BTreeMap, + pub envs: Vec, pub auxv: BTreeMap, } @@ -19,10 +19,8 @@ impl ProcInitInfo { let envs: Vec<_> = self .envs .iter() - .map(|(key, value)| { - writer.push_str(value.as_str()); - writer.push_slice(&[b"="]); - writer.push_slice(key.as_bytes()); + .map(|arg| { + writer.push_str(arg.as_str()); writer.sp }) .collect(); diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 0bf6781..a8b0b63 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -158,7 +158,12 @@ impl Thread { } /// Make a new user process from ELF `data` - pub fn new_user<'a, Iter>(data: &[u8], exec_path: &str, args: Iter) -> Box + pub fn new_user<'a, Iter>( + data: &[u8], + exec_path: &str, + args: Iter, + envs: Vec, + ) -> Box where Iter: Iterator, { @@ -185,7 +190,7 @@ impl Thread { new_args.insert(1, exec_path); new_args.remove(2); warn!("loader args: {:?}", new_args); - return Thread::new_user(buf.as_slice(), exec_path,new_args.into_iter()); + return Thread::new_user(buf.as_slice(), exec_path, new_args.into_iter(), envs); } else { warn!("loader specified as {} but failed to read", &loader_path); } @@ -215,7 +220,7 @@ impl Thread { // Make init info let init_info = ProcInitInfo { args: args.map(|s| String::from(s)).collect(), - envs: BTreeMap::new(), + envs, auxv: { let mut map = BTreeMap::new(); if let Some(phdr_vaddr) = elf.get_phdr_vaddr() { @@ -421,7 +426,7 @@ impl ElfExt for ElfFile<'_> { virt_addr + mem_size, ph.flags().to_attr(), ByFrame::new(GlobalFrameAlloc), - "", + "elf", ); unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) } }; diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index 9b2690e..4c88786 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -10,9 +10,12 @@ use alloc::vec::Vec; pub fn run_user_shell() { if let Ok(inode) = ROOT_INODE.lookup("rust/sh") { let data = inode.read_as_vec().unwrap(); - processor() - .manager() - .add(Thread::new_user(data.as_slice(), "rust/sh", "sh".split(' '))); + processor().manager().add(Thread::new_user( + data.as_slice(), + "rust/sh", + "sh".split(' '), + Vec::new(), + )); } else { processor().manager().add(Thread::new_kernel(shell, 0)); } @@ -23,9 +26,11 @@ pub fn run_user_shell() { let cmdline = CMDLINE.read(); let inode = ROOT_INODE.lookup(&cmdline).unwrap(); let data = inode.read_as_vec().unwrap(); - processor() - .manager() - .add(Thread::new_user(data.as_slice(), cmdline.split(' '))); + processor().manager().add(Thread::new_user( + data.as_slice(), + cmdline.split(' '), + Vec::new(), + )); } pub extern "C" fn shell(_arg: usize) -> ! { @@ -42,9 +47,12 @@ pub extern "C" fn shell(_arg: usize) -> ! { let name = cmd.trim().split(' ').next().unwrap(); if let Ok(file) = ROOT_INODE.lookup(name) { let data = file.read_as_vec().unwrap(); - let _pid = processor() - .manager() - .add(Thread::new_user(data.as_slice(), &cmd, cmd.split(' '))); + let _pid = processor().manager().add(Thread::new_user( + data.as_slice(), + &cmd, + cmd.split(' '), + Vec::new(), + )); // TODO: wait until process exits, or use user land shell completely //unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap(); } else { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 1545af6..aaf9b9f 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -208,11 +208,11 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { warn!("sys_getpgid is unimplemented"); Ok(0) } - SYS_GETGROUPS=> { + SYS_GETGROUPS => { warn!("sys_getgroups is unimplemented"); Ok(0) } - SYS_SETGROUPS=> { + SYS_SETGROUPS => { warn!("sys_setgroups is unimplemented"); Ok(0) } diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 1159ff3..7e68948 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -146,23 +146,28 @@ pub fn sys_exec( current_argv = current_argv.add(1); } } -// // Check and copy envs to kernel -// let mut envs = Vec::new(); -// unsafe { -// let mut current_env = envp as *const *const u8; -// proc.vm.check_read_ptr(current_env)?; -// while !(*current_env).is_null() { -// let env = proc.vm.check_and_clone_cstr(*current_env)?; -// envs.push(env); -// current_env = current_env.add(1); -// } -// } -// + // Check and copy envs to kernel + let mut envs = Vec::new(); + unsafe { + let mut current_env = envp as *const *const u8; + if !current_env.is_null() { + proc.vm.check_read_ptr(current_env)?; + while !(*current_env).is_null() { + let env = proc.vm.check_and_clone_cstr(*current_env)?; + envs.push(env); + current_env = current_env.add(1); + } + } + } + if args.is_empty() { return Err(SysError::EINVAL); } - info!("EXEC: name:{:?} , args {:?}", exec_name, args); + info!( + "EXEC: name:{:?} , args {:?}, envp {:?}", + exec_name, args, envs + ); // Read program file //let path = args[0].as_str(); @@ -171,8 +176,8 @@ pub fn sys_exec( let buf = inode.read_as_vec()?; // Make new Thread - let iter = args.iter().map(|s| s.as_str()); - let mut thread = Thread::new_user(buf.as_slice(), exec_path, iter); + let args_iter = args.iter().map(|s| s.as_str()); + let mut thread = Thread::new_user(buf.as_slice(), exec_path, args_iter, envs); thread.proc.lock().clone_for_exec(&proc); // Activate new page table From 520bb2d9579e970bd0b417d8a76063175288d0b5 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 18 Apr 2019 20:24:36 +0800 Subject: [PATCH 12/61] change args from Iter to Vec --- kernel/src/process/structs.rs | 22 +++++++++------------- kernel/src/shell.rs | 6 +++--- kernel/src/syscall/proc.rs | 3 +-- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index a8b0b63..06cb0b7 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -158,15 +158,12 @@ impl Thread { } /// Make a new user process from ELF `data` - pub fn new_user<'a, Iter>( + pub fn new_user( data: &[u8], exec_path: &str, - args: Iter, + mut args: Vec, envs: Vec, - ) -> Box - where - Iter: Iterator, - { + ) -> Box { // Parse ELF let elf = ElfFile::new(data).expect("failed to read elf"); @@ -185,12 +182,11 @@ impl Thread { debug!("using loader {}", &loader_path); // Elf loader should not have INTERP // No infinite loop - let mut new_args: Vec<&str> = args.collect(); - new_args.insert(0, loader_path); - new_args.insert(1, exec_path); - new_args.remove(2); - warn!("loader args: {:?}", new_args); - return Thread::new_user(buf.as_slice(), exec_path, new_args.into_iter(), envs); + args.insert(0, loader_path.into()); + args.insert(1, exec_path.into()); + args.remove(2); + warn!("loader args: {:?}", args); + return Thread::new_user(buf.as_slice(), exec_path, args, envs); } else { warn!("loader specified as {} but failed to read", &loader_path); } @@ -219,7 +215,7 @@ impl Thread { // Make init info let init_info = ProcInitInfo { - args: args.map(|s| String::from(s)).collect(), + args, envs, auxv: { let mut map = BTreeMap::new(); diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index 4c88786..fe8dc61 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -13,7 +13,7 @@ pub fn run_user_shell() { processor().manager().add(Thread::new_user( data.as_slice(), "rust/sh", - "sh".split(' '), + vec!["sh".into()], Vec::new(), )); } else { @@ -28,7 +28,7 @@ pub fn run_user_shell() { let data = inode.read_as_vec().unwrap(); processor().manager().add(Thread::new_user( data.as_slice(), - cmdline.split(' '), + cmdline.split(' ').map(|s| s.into()).collect(), Vec::new(), )); } @@ -50,7 +50,7 @@ pub extern "C" fn shell(_arg: usize) -> ! { let _pid = processor().manager().add(Thread::new_user( data.as_slice(), &cmd, - cmd.split(' '), + cmd.split(' ').map(|s| s.into()).collect(), Vec::new(), )); // TODO: wait until process exits, or use user land shell completely diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 7e68948..9f3c97c 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -176,8 +176,7 @@ pub fn sys_exec( let buf = inode.read_as_vec()?; // Make new Thread - let args_iter = args.iter().map(|s| s.as_str()); - let mut thread = Thread::new_user(buf.as_slice(), exec_path, args_iter, envs); + let mut thread = Thread::new_user(buf.as_slice(), exec_path, args, envs); thread.proc.lock().clone_for_exec(&proc); // Activate new page table From f29f5e4d35a97d99e5a2feaf13bed6e974fd500f Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 18 Apr 2019 21:29:45 +0800 Subject: [PATCH 13/61] fix memory area alignment #41 --- crate/memory/src/memory_set/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index 77eddc1..94d8765 100644 --- a/crate/memory/src/memory_set/mod.rs +++ b/crate/memory/src/memory_set/mod.rs @@ -56,7 +56,9 @@ impl MemoryArea { } /// Check the array is within the readable memory fn check_read_array(&self, ptr: *const S, count: usize) -> bool { - ptr as usize >= self.start_addr && unsafe { ptr.add(count) as usize } <= self.end_addr + // page align + ptr as usize >= Page::of_addr(self.start_addr).start_address() + && unsafe { ptr.add(count) as usize } < Page::of_addr(self.end_addr + PAGE_SIZE - 1).start_address() } /// Check the array is within the writable memory fn check_write_array(&self, ptr: *mut S, count: usize) -> bool { From f74a3b8e8b894e4edd0ebc4a0b5b8bb5261e0e2e Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 19 Apr 2019 00:37:30 +0800 Subject: [PATCH 14/61] by default: use busybox sh, disable log, build in release mode --- kernel/Makefile | 4 +-- kernel/events | 62 -------------------------------------- kernel/src/logging.rs | 3 +- kernel/src/shell.rs | 6 ++-- kernel/src/syscall/fs.rs | 38 +++++++++++++---------- kernel/src/syscall/proc.rs | 4 +-- 6 files changed, 30 insertions(+), 87 deletions(-) delete mode 100644 kernel/events diff --git a/kernel/Makefile b/kernel/Makefile index d21f3f5..cdd9e0d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -33,8 +33,8 @@ arch ?= riscv64 board ?= none -mode ?= debug -LOG ?= debug +mode ?= release +LOG ?= graphic ?= off smp ?= 4 pci_passthru ?= diff --git a/kernel/events b/kernel/events deleted file mode 100644 index d99bc24..0000000 --- a/kernel/events +++ /dev/null @@ -1,62 +0,0 @@ -virtqueue_pop -virtio_blk_req_complete -virtio_blk_rw_complete -virtio_blk_submit_multireq -virtio_blk_handle_write -virtio_blk_handle_read -e1000e_link_status -e1000e_mac_set_sw -e1000e_irq_itr_set -e1000e_irq_eitr_set -e1000e_tx_disabled -e1000e_tx_descr -e1000e_rx_descr -#e1000e_rx_has_buffers -e1000e_rx_start_recv -#e1000e_rx_can_recv -e1000e_rx_can_recv_rings_full -e1000_receiver_overrun -#e1000e_rx_receive_iov -e1000e_core_ctrl_sw_reset -e1000e_core_ctrl_phy_reset -e1000e_rx_desc_buff_sizes -e1000e_rx_set_rctl -e1000e_rx_desc_len -e1000e_core_ctrl_write -e1000e_link_status_changed -e1000e_rx_rss_dispatched_to_queue -e1000e_rx_desc_buff_write -e1000e_rx_null_descriptor -e1000e_rx_set_rdt -e1000e_msix_use_vector_fail -e1000e_msix_init_fail -e1000e_msi_init_fail -e1000e_cb_pci_uninit -e1000e_cfg_support_virtio -e1000e_irq_msi_notify_postponed -e1000e_irq_msix_notify_postponed_vec -e1000e_irq_throttling_no_pending_vec -e1000e_irq_msix_notify_vec -e1000e_wrn_msix_vec_wrong -e1000e_wrn_msix_invalid -e1000e_irq_iam_clear_eiame -e1000e_irq_icr_clear_eiac -e1000e_irq_msi_notify -pci_update_mappings_del -pci_update_mappings_add -e1000e_irq_icr_write -e1000e_irq_icr_read_entry -e1000e_irq_legacy_notify -e1000e_irq_add_msi_other -e1000e_irq_pending_interrupts -e1000e_irq_icr_write -e1000e_irq_msix_notify_vec -e1000e_wrn_msix_vec_wrong -e1000e_wrn_msix_invalid -e1000e_irq_iam_clear_eiame -e1000e_irq_icr_clear_eiac -e1000e_irq_postponed_by_xitr -e1000e_intrmgr_rearm_timer -msix_* -#ahci_* -ide_* \ No newline at end of file diff --git a/kernel/src/logging.rs b/kernel/src/logging.rs index b832d50..838abe5 100644 --- a/kernel/src/logging.rs +++ b/kernel/src/logging.rs @@ -14,13 +14,12 @@ pub fn init() { static LOGGER: SimpleLogger = SimpleLogger; log::set_logger(&LOGGER).unwrap(); log::set_max_level(match option_env!("LOG") { - Some("off") => LevelFilter::Off, Some("error") => LevelFilter::Error, Some("warn") => LevelFilter::Warn, Some("info") => LevelFilter::Info, Some("debug") => LevelFilter::Debug, Some("trace") => LevelFilter::Trace, - _ => LevelFilter::Warn, + _ => LevelFilter::Off, }); } diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index fe8dc61..000ad63 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -8,12 +8,12 @@ use alloc::vec::Vec; #[cfg(not(feature = "run_cmdline"))] pub fn run_user_shell() { - if let Ok(inode) = ROOT_INODE.lookup("rust/sh") { + if let Ok(inode) = ROOT_INODE.lookup("busybox") { let data = inode.read_as_vec().unwrap(); processor().manager().add(Thread::new_user( data.as_slice(), - "rust/sh", - vec!["sh".into()], + "busybox", + vec!["busybox".into(), "sh".into()], Vec::new(), )); } else { diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 4ad87e7..d9f843a 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -80,11 +80,14 @@ pub fn sys_ppoll(ufds: *mut PollFd, nfds: usize, timeout: *const TimeSpec) -> Sy } pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResult { - info!( - "poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}", - ufds, nfds, timeout_msecs - ); let proc = process(); + if !proc.pid.is_init() { + // we trust pid 0 process + info!( + "poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}", + ufds, nfds, timeout_msecs + ); + } proc.vm.check_write_array(ufds, nfds)?; let polls = unsafe { slice::from_raw_parts_mut(ufds, nfds) }; @@ -222,11 +225,14 @@ pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResul } pub fn sys_writev(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult { - info!( - "writev: fd: {}, iov: {:?}, count: {}", - fd, iov_ptr, iov_count - ); let mut proc = process(); + if !proc.pid.is_init() { + // we trust pid 0 process + info!( + "writev: fd: {}, iov: {:?}, count: {}", + fd, iov_ptr, iov_count + ); + } let iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, false)?; let buf = iovs.read_all_to_vec(); @@ -297,7 +303,7 @@ pub fn sys_faccessat(dirfd: usize, path: *const u8, mode: usize, flags: usize) - // we trust pid 0 process info!( "faccessat: dirfd: {}, path: {:?}, mode: {:#o}, flags: {:?}", - dirfd, path, mode, flags + dirfd as isize, path, mode, flags ); } let inode = proc.lookup_inode_at(dirfd, &path)?; @@ -342,7 +348,7 @@ pub fn sys_fstatat(dirfd: usize, path: *const u8, stat_ptr: *mut Stat, flags: us let flags = AtFlags::from_bits_truncate(flags); info!( "fstatat: dirfd: {}, path: {:?}, stat_ptr: {:?}, flags: {:?}", - dirfd, path, stat_ptr, flags + dirfd as isize, path, stat_ptr, flags ); let inode = proc.lookup_inode_at(dirfd, &path)?; @@ -525,7 +531,7 @@ pub fn sys_renameat( let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? }; info!( "renameat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}", - olddirfd, oldpath, newdirfd, newpath + olddirfd as isize, oldpath, newdirfd as isize, newpath ); let (old_dir_path, old_file_name) = split_path(&oldpath); @@ -546,7 +552,7 @@ pub fn sys_mkdirat(dirfd: usize, path: *const u8, mode: usize) -> SysResult { // TODO: check pathname info!( "mkdirat: dirfd: {}, path: {:?}, mode: {:#o}", - dirfd, path, mode + dirfd as isize, path, mode ); let (dir_path, file_name) = split_path(&path); @@ -590,7 +596,7 @@ pub fn sys_linkat( let flags = AtFlags::from_bits_truncate(flags); info!( "linkat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}, flags: {:?}", - olddirfd, oldpath, newdirfd, newpath, flags + olddirfd as isize, oldpath, newdirfd as isize, newpath, flags ); let (new_dir_path, new_file_name) = split_path(&newpath); @@ -610,7 +616,7 @@ pub fn sys_unlinkat(dirfd: usize, path: *const u8, flags: usize) -> SysResult { let flags = AtFlags::from_bits_truncate(flags); info!( "unlinkat: dirfd: {}, path: {:?}, flags: {:?}", - dirfd, path, flags + dirfd as isize, path, flags ); let (dir_path, file_name) = split_path(&path); @@ -765,8 +771,8 @@ impl Process { ) -> Result, SysError> { let follow = true; debug!( - "lookup_inode_at: fd: {:?}, cwd: {:?}, path: {:?}, follow: {:?}", - dirfd, self.cwd, path, follow + "lookup_inode_at: dirfd: {:?}, cwd: {:?}, path: {:?}, follow: {:?}", + dirfd as isize, self.cwd, path, follow ); let follow_max_depth = if follow { FOLLOW_MAX_DEPTH } else { 0 }; if dirfd == AT_FDCWD { diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 9f3c97c..362aef0 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -124,7 +124,7 @@ pub fn sys_exec( envp: *const *const u8, tf: &mut TrapFrame, ) -> SysResult { - info!("exec: name: {:?}, argv: {:?} envp: {:?}", name, argv, envp); + info!("exec: name: {:?}, argv: {:?}, envp: {:?}", name, argv, envp); let proc = process(); let exec_name = if name.is_null() { String::from("") @@ -165,7 +165,7 @@ pub fn sys_exec( } info!( - "EXEC: name:{:?} , args {:?}, envp {:?}", + "exec: name: {:?}, args: {:?}, envp: {:?}", exec_name, args, envs ); From 229c64cc7d761a530fb537b44027ab5f467a99f5 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 19 Apr 2019 08:42:44 +0800 Subject: [PATCH 15/61] Fix IoVec length type --- kernel/src/syscall/fs.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index d9f843a..88c99ee 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -1155,7 +1155,7 @@ pub struct IoVec { /// Starting address base: *mut u8, /// Number of bytes to transfer - len: u64, + len: usize, } /// A valid IoVecs request from user @@ -1176,15 +1176,15 @@ impl IoVecs { if iov.len > 0 { // skip empty iov if readv { - vm.check_write_array(iov.base, iov.len as usize)?; + vm.check_write_array(iov.base, iov.len)?; } else { - vm.check_read_array(iov.base, iov.len as usize)?; + vm.check_read_array(iov.base, iov.len)?; } } } let slices = iovs .iter() - .map(|iov| unsafe { slice::from_raw_parts_mut(iov.base, iov.len as usize) }) + .map(|iov| unsafe { slice::from_raw_parts_mut(iov.base, iov.len) }) .collect(); Ok(IoVecs(slices)) } @@ -1215,6 +1215,7 @@ impl IoVecs { /// For writev: `set_len` is false, Vec.cap = total_len. pub fn new_buf(&self, set_len: bool) -> Vec { let total_len = self.0.iter().map(|slice| slice.len()).sum::(); + info!("{}", total_len); let mut buf = Vec::with_capacity(total_len); if set_len { unsafe { From 7ce2fca20957578314e47ceddd7fb9ebcc4434a8 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 19 Apr 2019 09:17:27 +0800 Subject: [PATCH 16/61] Fix ls -al for symlinks --- kernel/src/syscall/fs.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 88c99ee..0025034 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -259,7 +259,7 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) -> let inode = if flags.contains(OpenFlags::CREATE) { let (dir_path, file_name) = split_path(&path); // relative to cwd - let dir_inode = proc.lookup_inode_at(dir_fd, dir_path)?; + let dir_inode = proc.lookup_inode_at(dir_fd, dir_path, true)?; match dir_inode.find(file_name) { Ok(file_inode) => { if flags.contains(OpenFlags::EXCLUSIVE) { @@ -273,7 +273,7 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) -> Err(e) => return Err(SysError::from(e)), } } else { - proc.lookup_inode_at(dir_fd, &path)? + proc.lookup_inode_at(dir_fd, &path, true)? }; let fd = proc.get_free_fd(); @@ -306,7 +306,7 @@ pub fn sys_faccessat(dirfd: usize, path: *const u8, mode: usize, flags: usize) - dirfd as isize, path, mode, flags ); } - let inode = proc.lookup_inode_at(dirfd, &path)?; + let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?; Ok(0) } @@ -325,8 +325,7 @@ pub fn sys_getcwd(buf: *mut u8, len: usize) -> SysResult { } pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { - warn!("lstat is partial implemented as stat"); - sys_stat(path, stat_ptr) + sys_fstatat(AT_FDCWD, path, stat_ptr, AtFlags::SYMLINK_NOFOLLOW.bits()) } pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { @@ -351,7 +350,7 @@ pub fn sys_fstatat(dirfd: usize, path: *const u8, stat_ptr: *mut Stat, flags: us dirfd as isize, path, stat_ptr, flags ); - let inode = proc.lookup_inode_at(dirfd, &path)?; + let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?; let stat = Stat::from(inode.metadata()?); unsafe { stat_ptr.write(stat); @@ -373,7 +372,7 @@ pub fn sys_readlinkat(dirfd: usize, path: *const u8, base: *mut u8, len: usize) proc.vm.check_write_array(base, len)?; info!("readlink: path: {:?}, base: {:?}, len: {}", path, base, len); - let inode = proc.lookup_inode_at(dirfd, &path)?; + let inode = proc.lookup_inode_at(dirfd, &path, false)?; if inode.metadata()?.type_ == FileType::SymLink { // TODO: recursive link resolution and loop detection let mut slice = unsafe { slice::from_raw_parts_mut(base, len) }; @@ -536,8 +535,8 @@ pub fn sys_renameat( let (old_dir_path, old_file_name) = split_path(&oldpath); let (new_dir_path, new_file_name) = split_path(&newpath); - let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path)?; - let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path)?; + let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path, false)?; + let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, false)?; old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?; Ok(0) } @@ -556,7 +555,7 @@ pub fn sys_mkdirat(dirfd: usize, path: *const u8, mode: usize) -> SysResult { ); let (dir_path, file_name) = split_path(&path); - let inode = proc.lookup_inode_at(dirfd, dir_path)?; + let inode = proc.lookup_inode_at(dirfd, dir_path, true)?; if inode.find(file_name).is_ok() { return Err(SysError::EEXIST); } @@ -600,8 +599,8 @@ pub fn sys_linkat( ); let (new_dir_path, new_file_name) = split_path(&newpath); - let inode = proc.lookup_inode_at(olddirfd, &oldpath)?; - let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path)?; + let inode = proc.lookup_inode_at(olddirfd, &oldpath, true)?; + let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, true)?; new_dir_inode.link(new_file_name, &inode)?; Ok(0) } @@ -620,7 +619,7 @@ pub fn sys_unlinkat(dirfd: usize, path: *const u8, flags: usize) -> SysResult { ); let (dir_path, file_name) = split_path(&path); - let dir_inode = proc.lookup_inode_at(dirfd, dir_path)?; + let dir_inode = proc.lookup_inode_at(dirfd, dir_path, true)?; let file_inode = dir_inode.find(file_name)?; if file_inode.metadata()?.type_ == FileType::Dir { return Err(SysError::EISDIR); @@ -767,9 +766,8 @@ impl Process { &self, dirfd: usize, path: &str, - // follow: bool, + follow: bool, ) -> Result, SysError> { - let follow = true; debug!( "lookup_inode_at: dirfd: {:?}, cwd: {:?}, path: {:?}, follow: {:?}", dirfd as isize, self.cwd, path, follow @@ -789,7 +787,7 @@ impl Process { } pub fn lookup_inode(&self, path: &str) -> Result, SysError> { - self.lookup_inode_at(AT_FDCWD, path) + self.lookup_inode_at(AT_FDCWD, path, true) } } @@ -1215,7 +1213,6 @@ impl IoVecs { /// For writev: `set_len` is false, Vec.cap = total_len. pub fn new_buf(&self, set_len: bool) -> Vec { let total_len = self.0.iter().map(|slice| slice.len()).sum::(); - info!("{}", total_len); let mut buf = Vec::with_capacity(total_len); if set_len { unsafe { From 8494bf9b0c146200f17652e68a0ef7e4752870b3 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 19 Apr 2019 12:34:27 +0800 Subject: [PATCH 17/61] Fix sys_sendfile args --- kernel/src/arch/x86_64/gdt.rs | 29 ++++----- kernel/src/process/mod.rs | 112 ++++++++++++++++++++++++---------- kernel/src/syscall/mod.rs | 2 +- 3 files changed, 94 insertions(+), 49 deletions(-) diff --git a/kernel/src/arch/x86_64/gdt.rs b/kernel/src/arch/x86_64/gdt.rs index 90e5037..ed648e3 100644 --- a/kernel/src/arch/x86_64/gdt.rs +++ b/kernel/src/arch/x86_64/gdt.rs @@ -17,22 +17,19 @@ pub fn init() { static mut CPUS: [Option; MAX_CPU_NUM] = [ // TODO: More elegant ? - None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, -// None, None, None, None, None, None, None, None, -// None, None, None, None, None, None, None, None, -// None, None, None, None, None, None, None, None, -// None, None, None, None, None, None, None, None, -// None, None, None, None, None, None, None, None, -// None, None, None, None, None, None, None, None, -// None, None, None, None, None, None, None, None, -// None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, + // None, None, None, None, None, None, None, None, + // None, None, None, None, None, None, None, None, + // None, None, None, None, None, None, None, None, + // None, None, None, None, None, None, None, None, + // None, None, None, None, None, None, None, None, + // None, None, None, None, None, None, None, None, + // None, None, None, None, None, None, None, None, + // None, None, None, None, None, None, None, None, ]; pub struct Cpu { diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index fca611d..516d29e 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -27,38 +27,86 @@ pub fn init() { static PROCESSORS: [Processor; MAX_CPU_NUM] = [ // TODO: More elegant ? - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), - Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), -// Processor::new(), Processor::new(), Processor::new(), Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), + // Processor::new(), Processor::new(), Processor::new(), Processor::new(), ]; /// Get current process diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index aaf9b9f..046bd71 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -88,7 +88,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { } SYS_GETPID => sys_getpid(), // 40 - SYS_SENDFILE => sys_sendfile(args[0], args[1], args[3] as *mut usize, args[4]), + SYS_SENDFILE => sys_sendfile(args[0], args[1], args[2] as *mut usize, args[3]), SYS_SOCKET => sys_socket(args[0], args[1], args[2]), SYS_CONNECT => sys_connect(args[0], args[1] as *const SockAddr, args[2]), SYS_ACCEPT => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), From 8090e154c171d4cfabc9b585f1f950d309a6bcd9 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 19 Apr 2019 12:43:05 +0800 Subject: [PATCH 18/61] simplify sys_sendfile. check elf arch --- kernel/src/process/structs.rs | 18 +++++-- kernel/src/syscall/fs.rs | 95 ++++++++++++++++------------------- kernel/src/syscall/mod.rs | 8 +++ 3 files changed, 66 insertions(+), 55 deletions(-) diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 06cb0b7..a9982ee 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -174,18 +174,30 @@ impl Thread { _ => panic!("ELF is not executable or shared object"), } - // Check interpreter + // Check ELF arch + match elf.header.pt2.machine().as_machine() { + #[cfg(target_arch = "x86_64")] + header::Machine::X86_64 => {} + #[cfg(target_arch = "aarch64")] + header::Machine::AArch64 => {} + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + header::Machine::Other(243) => {} + #[cfg(target_arch = "mips")] + header::Machine::Mips => {} + machine @ _ => panic!("invalid elf arch: {:?}", machine), + } + + // Check interpreter (for dynamic link) if let Ok(loader_path) = elf.get_interpreter() { // assuming absolute path if let Ok(inode) = crate::fs::ROOT_INODE.lookup_follow(loader_path, FOLLOW_MAX_DEPTH) { if let Ok(buf) = inode.read_as_vec() { - debug!("using loader {}", &loader_path); // Elf loader should not have INTERP // No infinite loop args.insert(0, loader_path.into()); args.insert(1, exec_path.into()); args.remove(2); - warn!("loader args: {:?}", args); + info!("loader args: {:?}", args); return Thread::new_user(buf.as_slice(), exec_path, args, envs); } else { warn!("loader specified as {} but failed to read", &loader_path); diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 0025034..43d0bca 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -662,8 +662,8 @@ pub fn sys_pipe(fds: *mut u32) -> SysResult { ); unsafe { - *fds = read_fd as u32; - *(fds.add(1)) = write_fd as u32; + fds.write(read_fd as u32); + fds.add(1).write(write_fd as u32); } info!("pipe: created rfd: {} wfd: {}", read_fd, write_fd); @@ -676,69 +676,60 @@ pub fn sys_sync() -> SysResult { Ok(0) } -pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usize) -> SysResult { +pub fn sys_sendfile( + out_fd: usize, + in_fd: usize, + offset_ptr: *mut usize, + count: usize, +) -> SysResult { info!( - "sendfile: out: {}, in: {}, offset: {:?}, count: {}", - out_fd, in_fd, offset, count + "sendfile: out: {}, in: {}, offset_ptr: {:?}, count: {}", + out_fd, in_fd, offset_ptr, count ); let proc = process(); // We know it's save, pacify the borrow checker let proc_cell = UnsafeCell::new(proc); - let proc_in = unsafe { &mut *proc_cell.get() }; - let proc_out = unsafe { &mut *proc_cell.get() }; - //let in_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(in_fd)?).get() }; - //let out_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(out_fd)?).get() }; - let in_file = proc_in.get_file(in_fd)?; - let out_file = proc_out.get_file(out_fd)?; + let in_file = unsafe { (*proc_cell.get()).get_file(in_fd)? }; + let out_file = unsafe { (*proc_cell.get()).get_file(out_fd)? }; let mut buffer = [0u8; 1024]; - if offset.is_null() { - // read from current file offset - let mut bytes_read = 0; - while bytes_read < count { - let len = min(buffer.len(), count - bytes_read); - let read_len = in_file.read(&mut buffer[..len])?; - if read_len == 0 { - break; - } - bytes_read += read_len; - let mut bytes_written = 0; - while bytes_written < read_len { - let write_len = out_file.write(&buffer[bytes_written..])?; - if write_len == 0 { - return Err(SysError::EBADF); - } - bytes_written += write_len; - } + + let mut read_offset = if !offset_ptr.is_null() { + unsafe { + (*proc_cell.get()).vm.check_read_ptr(offset_ptr)?; + offset_ptr.read() } - return Ok(bytes_read); } else { - let proc_mem = unsafe { &mut *proc_cell.get() }; - proc_mem.vm.check_read_ptr(offset)?; - let mut read_offset = unsafe { *offset }; - // read from specified offset and write new offset back - let mut bytes_read = 0; - while bytes_read < count { - let len = min(buffer.len(), count - bytes_read); - let read_len = in_file.read_at(read_offset, &mut buffer[..len])?; - if read_len == 0 { - break; - } - bytes_read += read_len; - read_offset += read_len; - let mut bytes_written = 0; - while bytes_written < read_len { - let write_len = out_file.write(&buffer[bytes_written..])?; - if write_len == 0 { - return Err(SysError::EBADF); - } - bytes_written += write_len; + in_file.seek(SeekFrom::Current(0))? as usize + }; + + // read from specified offset and write new offset back + let mut bytes_read = 0; + while bytes_read < count { + let len = min(buffer.len(), count - bytes_read); + let read_len = in_file.read_at(read_offset, &mut buffer[..len])?; + if read_len == 0 { + break; + } + bytes_read += read_len; + read_offset += read_len; + let mut bytes_written = 0; + while bytes_written < read_len { + let write_len = out_file.write(&buffer[bytes_written..])?; + if write_len == 0 { + return Err(SysError::EBADF); } + bytes_written += write_len; } + } + + if !offset_ptr.is_null() { unsafe { - *offset = read_offset; + offset_ptr.write(read_offset); } - return Ok(bytes_read); + } else { + in_file.seek(SeekFrom::Current(bytes_read as i64))?; } + return Ok(bytes_read); } impl Process { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 046bd71..23487d7 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -229,6 +229,10 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { Err(SysError::EACCES) } SYS_SETPRIORITY => sys_set_priority(args[0]), + SYS_PRCTL => { + warn!("ptctl is unimplemented"); + Ok(0) + } // SYS_SETRLIMIT => sys_setrlimit(), SYS_SYNC => sys_sync(), SYS_MOUNT => { @@ -264,6 +268,10 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { SYS_MKDIRAT => sys_mkdirat(args[0], args[1] as *const u8, args[2]), // SYS_MKNODAT => sys_mknod(), // 260 + SYS_FCHMODAT => { + warn!("sys_fchmodat is unimplemented"); + Ok(0) + } SYS_FCHOWNAT => { warn!("sys_fchownat is unimplemented"); Ok(0) From 1fd0060a1acefa2295b9e19347ff9d5d4ffab2fb Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 19 Apr 2019 13:43:31 +0800 Subject: [PATCH 19/61] Fix typo --- kernel/src/syscall/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 23487d7..7bd1a77 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -230,7 +230,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { } SYS_SETPRIORITY => sys_set_priority(args[0]), SYS_PRCTL => { - warn!("ptctl is unimplemented"); + warn!("prctl is unimplemented"); Ok(0) } // SYS_SETRLIMIT => sys_setrlimit(), @@ -268,19 +268,12 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { SYS_MKDIRAT => sys_mkdirat(args[0], args[1] as *const u8, args[2]), // SYS_MKNODAT => sys_mknod(), // 260 - SYS_FCHMODAT => { - warn!("sys_fchmodat is unimplemented"); - Ok(0) - } SYS_FCHOWNAT => { warn!("sys_fchownat is unimplemented"); Ok(0) } SYS_NEWFSTATAT => sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]), SYS_UNLINKAT => sys_unlinkat(args[0], args[1] as *const u8, args[2]), - SYS_READLINKAT => { - sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3]) - } SYS_RENAMEAT => sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8), SYS_LINKAT => sys_linkat( args[0], @@ -290,6 +283,13 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { args[4], ), SYS_SYMLINKAT => Err(SysError::EACCES), + SYS_READLINKAT => { + sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3]) + } + SYS_FCHMODAT => { + warn!("sys_fchmodat is unimplemented"); + Ok(0) + } SYS_FACCESSAT => sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]), SYS_PPOLL => sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec), // ignore sigmask // 280 From 4a1c7976d3d7814671a5e1c92c439d20acc18bcb Mon Sep 17 00:00:00 2001 From: chyyuu Date: Fri, 19 Apr 2019 14:24:25 +0800 Subject: [PATCH 20/61] fix bug: correct sys_sendfile args[3..4]-->[2..3] --- kernel/src/syscall/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index aaf9b9f..046bd71 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -88,7 +88,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { } SYS_GETPID => sys_getpid(), // 40 - SYS_SENDFILE => sys_sendfile(args[0], args[1], args[3] as *mut usize, args[4]), + SYS_SENDFILE => sys_sendfile(args[0], args[1], args[2] as *mut usize, args[3]), SYS_SOCKET => sys_socket(args[0], args[1], args[2]), SYS_CONNECT => sys_connect(args[0], args[1] as *const SockAddr, args[2]), SYS_ACCEPT => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), From e01d23e526446b288225b940425954bb5d4568d7 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 20 Apr 2019 00:15:22 +0800 Subject: [PATCH 21/61] replace riscv-pk by OpenSBI ! --- .gitmodules | 3 - kernel/Cargo.toml | 1 + kernel/Makefile | 45 +++++---------- kernel/src/arch/riscv32/board/u540/linker.ld | 49 ----------------- kernel/src/arch/riscv32/board/u540/mod.rs | 13 ++++- kernel/src/arch/riscv32/board/virt/mod.rs | 18 ++++++ kernel/src/arch/riscv32/boot/entry.asm | 19 ------- kernel/src/arch/riscv32/boot/entry32.asm | 55 +++++++++++++++++++ kernel/src/arch/riscv32/boot/entry64.asm | 48 ++++++++++++++++ kernel/src/arch/riscv32/boot/linker.ld | 2 +- kernel/src/arch/riscv32/boot/linker64.ld | 2 +- kernel/src/arch/riscv32/consts.rs | 12 +--- kernel/src/arch/riscv32/cpu.rs | 17 ------ kernel/src/arch/riscv32/io.rs | 3 - kernel/src/arch/riscv32/memory.rs | 26 ++++++++- kernel/src/arch/riscv32/mod.rs | 40 +++++++++----- kernel/src/arch/riscv32/paging.rs | 12 +++- kernel/src/arch/riscv32/sbi.rs | 1 + kernel/src/fs/stdio.rs | 2 - kernel/src/memory.rs | 4 +- riscv-pk | 1 - tools/opensbi/README.md | 9 +++ tools/opensbi/fu540.elf | Bin 0 -> 359536 bytes tools/opensbi/virt_rv32.elf | Bin 0 -> 214736 bytes tools/opensbi/virt_rv64.elf | Bin 0 -> 220944 bytes 25 files changed, 224 insertions(+), 158 deletions(-) delete mode 100644 kernel/src/arch/riscv32/board/u540/linker.ld create mode 100644 kernel/src/arch/riscv32/board/virt/mod.rs delete mode 100644 kernel/src/arch/riscv32/boot/entry.asm create mode 100644 kernel/src/arch/riscv32/boot/entry32.asm create mode 100644 kernel/src/arch/riscv32/boot/entry64.asm delete mode 160000 riscv-pk create mode 100644 tools/opensbi/README.md create mode 100755 tools/opensbi/fu540.elf create mode 100755 tools/opensbi/virt_rv32.elf create mode 100755 tools/opensbi/virt_rv64.elf diff --git a/.gitmodules b/.gitmodules index 1f53219..2c5ce1f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "riscv-pk"] - path = riscv-pk - url = https://github.com/rcore-os/riscv-pk.git [submodule "user"] path = user url = https://github.com/rcore-os/rcore-user.git diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index a226293..c4ce68c 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -19,6 +19,7 @@ authors = [ ] [features] +default = ["sv39"] # Page table sv39 or sv48 (for riscv64) sv39 = [] board_u540 = ["sv39", "link_user"] diff --git a/kernel/Makefile b/kernel/Makefile index cdd9e0d..63f52ff 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -124,7 +124,8 @@ endif else ifeq ($(arch), riscv32) qemu_opts += \ -machine virt \ - -kernel $(kernel_img) \ + -kernel ../tools/opensbi/virt_rv32.elf \ + -device loader,addr=0x80400000,file=$(kernel_img) \ -drive file=$(SFSIMG),format=qcow2,id=sfs \ -device virtio-blk-device,drive=sfs qemu_net_opts += \ @@ -132,11 +133,19 @@ qemu_net_opts += \ -device virtio-net-device,netdev=net0 else ifeq ($(arch), riscv64) +ifeq ($(board), u540) +qemu_opts += \ + -machine virt \ + -kernel ../tools/opensbi/fu540.elf \ + -device loader,addr=0x80200000,file=$(kernel_img) +else qemu_opts += \ -machine virt \ - -kernel $(kernel_img) \ + -kernel ../tools/opensbi/virt_rv64.elf \ + -device loader,addr=0x80200000,file=$(kernel_img) \ -drive file=$(SFSIMG),format=qcow2,id=sfs \ -device virtio-blk-device,drive=sfs +endif qemu_net_opts += \ -netdev type=tap,id=net0,script=no,downscript=no \ -device virtio-net-device,netdev=net0 @@ -297,28 +306,8 @@ ifeq ($(need_bootloader), true) endif $(kernel_img): kernel $(bootloader) -ifeq ($(arch), riscv32) - @mkdir -p target/$(target)/bbl && \ - cd target/$(target)/bbl && \ - $(bbl_path)/configure \ - $(riscv_pk_args) \ - --with-arch=rv32imac \ - --disable-fp-emulation \ - --host=riscv64-unknown-elf \ - --with-payload=$(abspath $(kernel)) && \ - make -j && \ - cp bbl $(abspath $@) -else ifeq ($(arch), riscv64) - @mkdir -p target/$(target)/bbl && \ - cd target/$(target)/bbl && \ - $(bbl_path)/configure \ - $(riscv_pk_args) \ - --with-arch=rv64imac \ - --disable-fp-emulation \ - --host=riscv64-unknown-elf \ - --with-payload=$(abspath $(kernel)) && \ - make -j && \ - cp bbl $(abspath $@) +ifeq ($(arch), $(filter $(arch), riscv32 riscv64)) + @$(objcopy) $(kernel) --strip-all -O binary $@ else ifeq ($(arch), aarch64) ifneq ($(u_boot), ) @cp $(u_boot) $@ @@ -335,13 +324,7 @@ kernel: $(dtb) ifeq ($(arch), x86_64) @bootimage build $(build_args) @mv target/x86_64/bootimage.bin $(bootimage) -else ifeq ($(arch), riscv32) - @-patch -p0 -N -b \ - $(shell rustc --print sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \ - src/arch/riscv32/atomic.patch - @cargo xbuild $(build_args) -else ifeq ($(arch), riscv64) - @cp src/arch/riscv32/board/u540/linker.ld src/arch/riscv32/boot/linker64.ld +else ifeq ($(arch), $(filter $(arch), riscv32 riscv64)) @-patch -p0 -N -b \ $(shell rustc --print sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \ src/arch/riscv32/atomic.patch diff --git a/kernel/src/arch/riscv32/board/u540/linker.ld b/kernel/src/arch/riscv32/board/u540/linker.ld deleted file mode 100644 index 6bbe85b..0000000 --- a/kernel/src/arch/riscv32/board/u540/linker.ld +++ /dev/null @@ -1,49 +0,0 @@ -/* Copy from bbl-ucore : https://ring00.github.io/bbl-ucore */ - -/* Simple linker script for the ucore kernel. - See the GNU ld 'info' manual ("info ld") to learn the syntax. */ - -OUTPUT_ARCH(riscv) -ENTRY(_start) - -BASE_ADDRESS = 0xffffffffc0020000; - -SECTIONS -{ - /* Load the kernel at this address: "." means the current address */ - . = BASE_ADDRESS; - start = .; - - .text : { - stext = .; - *(.text.entry) - *(.text .text.*) - . = ALIGN(4K); - etext = .; - } - - .rodata : { - srodata = .; - *(.rodata .rodata.*) - . = ALIGN(4K); - erodata = .; - } - - .data : { - sdata = .; - *(.data .data.*) - edata = .; - } - - .stack : { - *(.bss.stack) - } - - .bss : { - sbss = .; - *(.bss .bss.*) - ebss = .; - } - - PROVIDE(end = .); -} diff --git a/kernel/src/arch/riscv32/board/u540/mod.rs b/kernel/src/arch/riscv32/board/u540/mod.rs index 2e9f7a6..816632d 100644 --- a/kernel/src/arch/riscv32/board/u540/mod.rs +++ b/kernel/src/arch/riscv32/board/u540/mod.rs @@ -4,7 +4,7 @@ use super::consts::KERNEL_OFFSET; pub unsafe fn init_external_interrupt() { const HART1_S_MODE_INTERRUPT_ENABLES: *mut u64 = (KERNEL_OFFSET + 0x0C00_2100) as *mut u64; const SERIAL: u64 = 4; - HART1_S_MODE_INTERRUPT_ENABLES.write(1 << SERIAL); + HART1_S_MODE_INTERRUPT_ENABLES.write_volatile(1 << SERIAL); } /// Claim and complete external interrupt by reading and writing to @@ -13,7 +13,14 @@ pub unsafe fn handle_external_interrupt() { const HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE: *mut u32 = (KERNEL_OFFSET + 0x0C20_2004) as *mut u32; // claim - let source = HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.read(); + let source = HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.read_volatile(); // complete - HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.write(source); + HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.write_volatile(source); +} + +pub unsafe fn enable_serial_interrupt() { + const SERIAL_BASE: *mut u8 = (KERNEL_OFFSET + 0x10010000) as *mut u8; + const UART_REG_IE: usize = 4; + const UART_RXWM: u8 = 0x2; + SERIAL_BASE.add(UART_REG_IE).write_volatile(UART_RXWM); } diff --git a/kernel/src/arch/riscv32/board/virt/mod.rs b/kernel/src/arch/riscv32/board/virt/mod.rs new file mode 100644 index 0000000..52df872 --- /dev/null +++ b/kernel/src/arch/riscv32/board/virt/mod.rs @@ -0,0 +1,18 @@ +use super::consts::KERNEL_OFFSET; + +/// Mask all external interrupt except serial. +pub unsafe fn init_external_interrupt() { + // By default: + // riscv-pk (bbl) enables all S-Mode IRQs (ref: machine/minit.c) + // OpenSBI v0.3 disables all IRQs (ref: platform/common/irqchip/plic.c) + + const HART0_S_MODE_INTERRUPT_ENABLES: *mut u32 = (KERNEL_OFFSET + 0x0C00_2080) as *mut u32; + const SERIAL: u32 = 0xa; + HART0_S_MODE_INTERRUPT_ENABLES.write_volatile(1 << SERIAL); +} + +pub unsafe fn enable_serial_interrupt() { + const UART16550: *mut u8 = (KERNEL_OFFSET + 0x10000000) as *mut u8; + UART16550.add(4).write_volatile(0x0B); + UART16550.add(1).write_volatile(0x01); +} diff --git a/kernel/src/arch/riscv32/boot/entry.asm b/kernel/src/arch/riscv32/boot/entry.asm deleted file mode 100644 index 3cee2fd..0000000 --- a/kernel/src/arch/riscv32/boot/entry.asm +++ /dev/null @@ -1,19 +0,0 @@ - .section .text.entry - .globl _start -_start: - add t0, a0, 1 - slli t0, t0, 16 - - lui sp, %hi(bootstack) - addi sp, sp, %lo(bootstack) - add sp, sp, t0 - - call rust_main - - .section .bss.stack - .align 12 #PGSHIFT - .global bootstack -bootstack: - .space 4096 * 16 * 8 - .global bootstacktop -bootstacktop: diff --git a/kernel/src/arch/riscv32/boot/entry32.asm b/kernel/src/arch/riscv32/boot/entry32.asm new file mode 100644 index 0000000..22cc0ee --- /dev/null +++ b/kernel/src/arch/riscv32/boot/entry32.asm @@ -0,0 +1,55 @@ + .section .text.entry + .globl _start +_start: + # a0 == hartid + # pc == 0x80200000 + # sp == 0x800xxxxx + + # 1. set sp + # sp = bootstack + (hartid + 1) * 0x10000 + add t0, a0, 1 + slli t0, t0, 16 + lui sp, %hi(bootstack) + add sp, sp, t0 + + # 2. enable paging + # satp = (1 << 31) | PPN(boot_page_table_sv32) + lui t0, %hi(boot_page_table_sv32) + li t1, 0xc0000000 - 0x80000000 + sub t0, t0, t1 + srli t0, t0, 12 + li t1, 1 << 31 + or t0, t0, t1 + csrw satp, t0 + sfence.vma + + # 3. jump to rust_main (absolute address) + lui t0, %hi(rust_main) + addi t0, t0, %lo(rust_main) + jr t0 + + .section .bss.stack + .align 12 # page align + .global bootstack +bootstack: + .space 4096 * 16 * 8 + .global bootstacktop +bootstacktop: + + .section .data + .align 12 # page align +boot_page_table_sv32: + # NOTE: assume kernel image < 16M + # 0x80000000 -> 0x80000000 (4M * 4) + # 0xc0000000 -> 0x80000000 (4M * 4) + .zero 4 * 512 + .word (0x80000 << 10) | 0xcf # VRWXAD + .word (0x80400 << 10) | 0xcf # VRWXAD + .word (0x80800 << 10) | 0xcf # VRWXAD + .word (0x80c00 << 10) | 0xcf # VRWXAD + .zero 4 * 252 + .word (0x80000 << 10) | 0xcf # VRWXAD + .word (0x80400 << 10) | 0xcf # VRWXAD + .word (0x80800 << 10) | 0xcf # VRWXAD + .word (0x80c00 << 10) | 0xcf # VRWXAD + .zero 4 * 252 diff --git a/kernel/src/arch/riscv32/boot/entry64.asm b/kernel/src/arch/riscv32/boot/entry64.asm new file mode 100644 index 0000000..69727d5 --- /dev/null +++ b/kernel/src/arch/riscv32/boot/entry64.asm @@ -0,0 +1,48 @@ + .section .text.entry + .globl _start +_start: + # a0 == hartid + # pc == 0x80200000 + # sp == 0x800xxxxx + + # 1. set sp + # sp = bootstack + (hartid + 1) * 0x10000 + add t0, a0, 1 + slli t0, t0, 16 + lui sp, %hi(bootstack) + add sp, sp, t0 + + # 2. enable paging + # satp = (8 << 60) | PPN(boot_page_table_sv39) + lui t0, %hi(boot_page_table_sv39) + li t1, 0xffffffffc0000000 - 0x80000000 + sub t0, t0, t1 + srli t0, t0, 12 + li t1, 8 << 60 + or t0, t0, t1 + csrw satp, t0 + sfence.vma + + # 3. jump to rust_main (absolute address) + lui t0, %hi(rust_main) + addi t0, t0, %lo(rust_main) + jr t0 + + .section .bss.stack + .align 12 # page align + .global bootstack +bootstack: + .space 4096 * 16 * 8 + .global bootstacktop +bootstacktop: + + .section .data + .align 12 # page align +boot_page_table_sv39: + # 0x00000000_80000000 -> 0x80000000 (1G) + # 0xffffffff_c0000000 -> 0x80000000 (1G) + .quad 0 + .quad 0 + .quad (0x80000 << 10) | 0xcf # VRWXAD + .zero 8 * 508 + .quad (0x80000 << 10) | 0xcf # VRWXAD diff --git a/kernel/src/arch/riscv32/boot/linker.ld b/kernel/src/arch/riscv32/boot/linker.ld index bc3ba7f..b9efafa 100644 --- a/kernel/src/arch/riscv32/boot/linker.ld +++ b/kernel/src/arch/riscv32/boot/linker.ld @@ -6,7 +6,7 @@ OUTPUT_ARCH(riscv) ENTRY(_start) -BASE_ADDRESS = 0xC0020000; +BASE_ADDRESS = 0xC0400000; SECTIONS { diff --git a/kernel/src/arch/riscv32/boot/linker64.ld b/kernel/src/arch/riscv32/boot/linker64.ld index 6bbe85b..87ca826 100644 --- a/kernel/src/arch/riscv32/boot/linker64.ld +++ b/kernel/src/arch/riscv32/boot/linker64.ld @@ -6,7 +6,7 @@ OUTPUT_ARCH(riscv) ENTRY(_start) -BASE_ADDRESS = 0xffffffffc0020000; +BASE_ADDRESS = 0xffffffffc0200000; SECTIONS { diff --git a/kernel/src/arch/riscv32/consts.rs b/kernel/src/arch/riscv32/consts.rs index 45fa998..3042054 100644 --- a/kernel/src/arch/riscv32/consts.rs +++ b/kernel/src/arch/riscv32/consts.rs @@ -22,17 +22,11 @@ pub const KERNEL_P2_INDEX: usize = (KERNEL_OFFSET >> 12 >> 10) & 0x3ff; #[cfg(target_arch = "riscv64")] pub const KERNEL_P4_INDEX: usize = (KERNEL_OFFSET >> 12 >> 9 >> 9 >> 9) & 0o777; -pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000; +pub const KERNEL_HEAP_SIZE: usize = 0x0080_0000; -#[cfg(target_arch = "riscv32")] -pub const MEMORY_OFFSET: usize = 0x8000_0000; -#[cfg(target_arch = "riscv64")] pub const MEMORY_OFFSET: usize = 0x8000_0000; - -#[cfg(target_arch = "riscv32")] -pub const MEMORY_END: usize = 0x8100_0000; -#[cfg(target_arch = "riscv64")] -pub const MEMORY_END: usize = 0x8100_0000; +// TODO: get memory end from device tree +pub const MEMORY_END: usize = 0x8800_0000; // FIXME: rv64 `sh` and `ls` will crash if stack top > 0x80000000 ??? pub const USER_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE; diff --git a/kernel/src/arch/riscv32/cpu.rs b/kernel/src/arch/riscv32/cpu.rs index f519e6f..7e146da 100644 --- a/kernel/src/arch/riscv32/cpu.rs +++ b/kernel/src/arch/riscv32/cpu.rs @@ -1,8 +1,3 @@ -use crate::consts::MAX_CPU_NUM; -use core::ptr::{read_volatile, write_volatile}; - -static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM]; - pub unsafe fn set_cpu_id(cpu_id: usize) { asm!("mv gp, $0" : : "r"(cpu_id)); } @@ -19,18 +14,6 @@ pub fn send_ipi(cpu_id: usize) { super::sbi::send_ipi(1 << cpu_id); } -pub unsafe fn has_started(cpu_id: usize) -> bool { - read_volatile(&STARTED[cpu_id]) -} - -pub unsafe fn start_others(hart_mask: usize) { - for cpu_id in 0..32 { - if (hart_mask >> cpu_id) & 1 != 0 { - write_volatile(&mut STARTED[cpu_id], true); - } - } -} - pub fn halt() { unsafe { riscv::asm::wfi() } } diff --git a/kernel/src/arch/riscv32/io.rs b/kernel/src/arch/riscv32/io.rs index 161dfd1..ea1e74a 100644 --- a/kernel/src/arch/riscv32/io.rs +++ b/kernel/src/arch/riscv32/io.rs @@ -47,6 +47,3 @@ pub fn getchar_option() -> Option { pub fn putfmt(fmt: Arguments) { SerialPort.write_fmt(fmt).unwrap(); } - -const TXDATA: *mut u32 = 0x38000000 as *mut u32; -const RXDATA: *mut u32 = 0x38000004 as *mut u32; diff --git a/kernel/src/arch/riscv32/memory.rs b/kernel/src/arch/riscv32/memory.rs index a846c11..af7333b 100644 --- a/kernel/src/arch/riscv32/memory.rs +++ b/kernel/src/arch/riscv32/memory.rs @@ -8,13 +8,17 @@ use riscv::{addr::*, register::sstatus}; /// Initialize the memory management module pub fn init(dtb: usize) { + // allow user memory access unsafe { sstatus::set_sum(); - } // Allow user memory access - // initialize heap and Frame allocator + } + // initialize heap and Frame allocator init_frame_allocator(); init_heap(); // remap the kernel use 4K page + unsafe { + super::paging::setup_recursive_mapping(); + } remap_the_kernel(dtb); } @@ -93,7 +97,7 @@ fn remap_the_kernel(dtb: usize) { Linear::new(offset), "dts", ); - // map PLIC for HiFiveU + // map PLIC for HiFiveU & VirtIO let offset = -(KERNEL_OFFSET as isize); ms.push( KERNEL_OFFSET + 0x0C00_2000, @@ -109,6 +113,22 @@ fn remap_the_kernel(dtb: usize) { Linear::new(offset), "plic1", ); + // map UART for HiFiveU + ms.push( + KERNEL_OFFSET + 0x10010000, + KERNEL_OFFSET + 0x10010000 + PAGE_SIZE, + MemoryAttr::default(), + Linear::new(offset), + "uart", + ); + // map UART for VirtIO + ms.push( + KERNEL_OFFSET + 0x10000000, + KERNEL_OFFSET + 0x10000000 + PAGE_SIZE, + MemoryAttr::default(), + Linear::new(offset), + "uart16550", + ); unsafe { ms.activate(); } diff --git a/kernel/src/arch/riscv32/mod.rs b/kernel/src/arch/riscv32/mod.rs index 650e881..1b30ad3 100644 --- a/kernel/src/arch/riscv32/mod.rs +++ b/kernel/src/arch/riscv32/mod.rs @@ -1,6 +1,10 @@ #[cfg(feature = "board_u540")] #[path = "board/u540/mod.rs"] mod board; +#[cfg(not(feature = "board_u540"))] +#[path = "board/virt/mod.rs"] +mod board; + pub mod compiler_rt; pub mod consts; pub mod cpu; @@ -13,19 +17,24 @@ mod sbi; pub mod syscall; pub mod timer; +use self::consts::{KERNEL_OFFSET, MEMORY_OFFSET}; +use core::sync::atomic::{AtomicBool, Ordering}; use log::*; #[no_mangle] -pub extern "C" fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! { - // An initial recursive page table has been set by BBL (shared by all cores) +pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! { + let device_tree_vaddr = device_tree_paddr - MEMORY_OFFSET + KERNEL_OFFSET; unsafe { cpu::set_cpu_id(hartid); } if hartid != BOOT_HART_ID { - while unsafe { !cpu::has_started(hartid) } {} - println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb); + while !AP_CAN_INIT.load(Ordering::Relaxed) {} + println!( + "Hello RISCV! in hart {}, device tree @ {:#x}", + hartid, device_tree_vaddr + ); others_main(); //other_main -> ! } @@ -34,24 +43,25 @@ pub extern "C" fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! { memory::clear_bss(); } - println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb); + println!( + "Hello RISCV! in hart {}, device tree @ {:#x}", + hartid, device_tree_vaddr + ); crate::logging::init(); interrupt::init(); - memory::init(dtb); + memory::init(device_tree_vaddr); timer::init(); // FIXME: init driver on u540 #[cfg(not(feature = "board_u540"))] - crate::drivers::init(dtb); - #[cfg(feature = "board_u540")] + crate::drivers::init(device_tree_vaddr); unsafe { + board::enable_serial_interrupt(); board::init_external_interrupt(); } crate::process::init(); - unsafe { - cpu::start_others(hart_mask); - } + AP_CAN_INIT.store(true, Ordering::Relaxed); crate::kmain(); } @@ -62,6 +72,8 @@ fn others_main() -> ! { crate::kmain(); } +static AP_CAN_INIT: AtomicBool = AtomicBool::new(false); + #[cfg(not(feature = "board_u540"))] const BOOT_HART_ID: usize = 0; #[cfg(feature = "board_u540")] @@ -94,6 +106,8 @@ global_asm!( .endm " ); - -global_asm!(include_str!("boot/entry.asm")); +#[cfg(target_arch = "riscv32")] +global_asm!(include_str!("boot/entry32.asm")); +#[cfg(target_arch = "riscv64")] +global_asm!(include_str!("boot/entry64.asm")); global_asm!(include_str!("boot/trap.asm")); diff --git a/kernel/src/arch/riscv32/paging.rs b/kernel/src/arch/riscv32/paging.rs index 12e61ec..d501d6f 100644 --- a/kernel/src/arch/riscv32/paging.rs +++ b/kernel/src/arch/riscv32/paging.rs @@ -198,7 +198,7 @@ impl InactivePageTable for InactivePageTable0 { fn start(); fn end(); } - let mut entrys: [PageTableEntry; 16] = unsafe { core::mem::uninitialized() }; + let mut entrys: [PageTableEntry; 256] = unsafe { core::mem::uninitialized() }; let entry_start = start as usize >> 22; let entry_end = (end as usize >> 22) + 1; let entry_count = entry_end - entry_start; @@ -299,3 +299,13 @@ impl FrameDeallocator for FrameAllocatorForRiscv { dealloc_frame(frame.start_address().as_usize()); } } + +pub unsafe fn setup_recursive_mapping() { + let frame = satp::read().frame(); + let root_page_table = unsafe { &mut *(frame.start_address().as_usize() as *mut RvPageTable) }; + root_page_table.set_recursive(RECURSIVE_INDEX, frame); + unsafe { + sfence_vma_all(); + } + info!("setup recursive mapping end"); +} diff --git a/kernel/src/arch/riscv32/sbi.rs b/kernel/src/arch/riscv32/sbi.rs index 6a56ff1..babfa79 100644 --- a/kernel/src/arch/riscv32/sbi.rs +++ b/kernel/src/arch/riscv32/sbi.rs @@ -1,4 +1,5 @@ //! Port from sbi.h +#![allow(dead_code)] #[inline(always)] fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize { diff --git a/kernel/src/fs/stdio.rs b/kernel/src/fs/stdio.rs index 6250011..14e8c31 100644 --- a/kernel/src/fs/stdio.rs +++ b/kernel/src/fs/stdio.rs @@ -20,8 +20,6 @@ impl Stdin { self.pushed.notify_one(); } pub fn pop(&self) -> char { - // QEMU v3.0 don't support M-mode external interrupt (bug?) - // So we have to use polling. loop { let ret = self.buf.lock().pop_front(); match ret { diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index a631437..f98f1ad 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -16,9 +16,9 @@ pub type MemorySet = rcore_memory::memory_set::MemorySet; #[cfg(target_arch = "x86_64")] pub type FrameAlloc = bitmap_allocator::BitAlloc16M; -// RISCV has 8M memory +// RISCV has 1G memory #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -pub type FrameAlloc = bitmap_allocator::BitAlloc4K; +pub type FrameAlloc = bitmap_allocator::BitAlloc1M; // Raspberry Pi 3 has 1G memory #[cfg(any(target_arch = "aarch64", target_arch = "mips"))] diff --git a/riscv-pk b/riscv-pk deleted file mode 160000 index 405ea59..0000000 --- a/riscv-pk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 405ea59dd7dd2762c5883822f21d9995bea32b0c diff --git a/tools/opensbi/README.md b/tools/opensbi/README.md new file mode 100644 index 0000000..79ad945 --- /dev/null +++ b/tools/opensbi/README.md @@ -0,0 +1,9 @@ +# OpenSBI + +These are binary release of OpenSBI on this [commit](https://github.com/riscv/opensbi/tree/194dbbe5a13dff2255411c26d249f3ad4ef42c0b) at 2019.04.15. + +- fu540.elf: opensbi-0.3-rv64-bin/platform/sifive/fu540/firmware/fw_jump.elf +- virt_rv32.elf: opensbi-0.3-rv32-bin/platform/qemu/virt/firmware/fw_jump.elf +- virt_rv64.elf: opensbi-0.3-rv64-bin/platform/qemu/virt/firmware/fw_jump.elf + +NOTE: The [official v0.3 release](https://github.com/riscv/opensbi/releases/tag/v0.3) has bug on serial interrupt. diff --git a/tools/opensbi/fu540.elf b/tools/opensbi/fu540.elf new file mode 100755 index 0000000000000000000000000000000000000000..4b76fae3fa3f33f996a051d197eba6b973d5bd53 GIT binary patch literal 359536 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 K&QY4sBSZ zF^hxo!|hIFSCp17!!jAT#$y=z)QDDxvm#zu$k;+A3{Kbz{dA{q8WcZbhT9rcNtVu! zC&%H()ni$?+QUkAj`AYtUuvs07!d)qoPI8rU??Ont<}V0KA7Jidr)J}BE!Jo(}`%QEMUt?v}FHd%mGsUzniX%S7XdH zQ@qrBU3}nuva$k03vZGV0|HF0_!2pUTeR?S8)%?lS#=6o$^r!66)BERT zkO|hLXB@^h(;Jt`|B_exl5+w-EB)Ks#H4LQaz4QGl=mV3ul)M-+v%q$x?xWGTOKjW zjmxJ~Og}}@E9a#D{C`-D{O*fHn#twUAHyq;3H7B1OrzmX*a#*UmYt`r0#B0uz!Zw- zt1SIFS4_VMd4=B-Og~K(MOVGi(tq3|Jk9ib#6Vk@*joFNv`yP-y*P8D<$qEdC@#@^hJPV_*q=n0 l$i((>AFf+cOaB8`057Y&ZrV;rjNcb;So%L}VRGx!{|_9*&CLJ+ literal 0 HcmV?d00001 diff --git a/tools/opensbi/virt_rv32.elf b/tools/opensbi/virt_rv32.elf new file mode 100755 index 0000000000000000000000000000000000000000..1bebfb0521094a6003518835489e8dbfe864f121 GIT binary patch literal 214736 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

B)!rU_-043r2eq%{AV!T-QIt2< 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 literal 0 HcmV?d00001 From 00685d920529c74c8bad5c9c056ea295fcce6b2e Mon Sep 17 00:00:00 2001 From: chyyuu Date: Sat, 20 Apr 2019 09:32:42 +0800 Subject: [PATCH 22/61] set 8MB user stack size, add more flags for sys_clone 8MB is the default linux app stack size on x86_64. gcc app in alpine linux call sys_clone with flags 0x5d0f00. In case of supporting more other potential flags, use panic! instead of warn!, then we can get timely panic-style info. Now python2 hello.py can run correctly, but only one time. I guess the memory management has some problem, maybe there are some memory leak. --- kernel/src/arch/x86_64/consts.rs | 2 +- kernel/src/syscall/proc.rs | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/src/arch/x86_64/consts.rs b/kernel/src/arch/x86_64/consts.rs index 2095e39..0b3a4f9 100644 --- a/kernel/src/arch/x86_64/consts.rs +++ b/kernel/src/arch/x86_64/consts.rs @@ -55,7 +55,7 @@ pub const USER_GRANT_PML4: usize = (USER_GRANT_OFFSET & PML4_MASK) / PML4_SIZE; pub const USER_STACK_OFFSET: usize = USER_GRANT_OFFSET + PML4_SIZE; pub const USER_STACK_PML4: usize = (USER_STACK_OFFSET & PML4_MASK) / PML4_SIZE; /// Size of user stack -pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB +pub const USER_STACK_SIZE: usize = 8 * 1024 * 1024; // 8 MB, the default config of Linux /// Offset to user sigstack pub const USER_SIGSTACK_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 362aef0..89b7765 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -13,7 +13,7 @@ pub fn sys_fork(tf: &TrapFrame) -> SysResult { /// Create a new thread in the current process. /// The new thread's stack pointer will be set to `newsp`, -/// and thread pointer will be set to `newtls`. +/// and thread pointer will be set to `newtls`. /// The child tid will be stored at both `parent_tid` and `child_tid`. /// This is partially implemented for musl only. pub fn sys_clone( @@ -26,16 +26,17 @@ pub fn sys_clone( ) -> SysResult { let clone_flags = CloneFlags::from_bits_truncate(flags); info!( - "clone: flags: {:?}, newsp: {:#x}, parent_tid: {:?}, child_tid: {:?}, newtls: {:#x}", - clone_flags, newsp, parent_tid, child_tid, newtls + "clone: flags: {:?} == {:#x}, newsp: {:#x}, parent_tid: {:?}, child_tid: {:?}, newtls: {:#x}", + clone_flags, flags, newsp, parent_tid, child_tid, newtls ); if flags == 0x4111 || flags == 0x11 { warn!("sys_clone is calling sys_fork instead, ignoring other args"); return sys_fork(tf); } - if flags != 0x7d0f00 { - warn!("sys_clone only support musl pthread_create"); - return Err(SysError::ENOSYS); + if (flags != 0x7d0f00) && (flags!= 0x5d0f00) { //0x5d0f00 is the args from gcc of alpine linux + //warn!("sys_clone only support musl pthread_create"); + panic!("sys_clone only support sys_fork OR musl pthread_create without flags{:x}", flags); + //return Err(SysError::ENOSYS); } { let proc = process(); From c34a420a397e5166f31765b59ca06db06779a380 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 20 Apr 2019 16:31:18 +0800 Subject: [PATCH 23/61] move font8x16 data from code to file --- kernel/src/drivers/console/fonts/font8x16.rs | 4399 +---------------- .../drivers/console/fonts/font8x16_1bpp.raw | Bin 0 -> 3360 bytes 2 files changed, 40 insertions(+), 4359 deletions(-) create mode 100644 kernel/src/drivers/console/fonts/font8x16_1bpp.raw diff --git a/kernel/src/drivers/console/fonts/font8x16.rs b/kernel/src/drivers/console/fonts/font8x16.rs index 7513e85..abea5bf 100644 --- a/kernel/src/drivers/console/fonts/font8x16.rs +++ b/kernel/src/drivers/console/fonts/font8x16.rs @@ -4,4364 +4,8 @@ use super::Font; pub enum Font8x16 {} -impl Font8x16 { - /// font data - /// copied from `linux/lib/fonts/font_8x16.c` - const DATA: [u8; 256 * 16] = [ - /* 0 0x00 '^@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 1 0x01 '^A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x81, /* 10000001 */ - 0xa5, /* 10100101 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 2 0x02 '^B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xdb, /* 11011011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 3 0x03 '^C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 4 0x04 '^D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 5 0x05 '^E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 6 0x06 '^F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 7 0x07 '^G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 8 0x08 '^H' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xe7, /* 11100111 */ - 0xc3, /* 11000011 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - /* 9 0x09 '^I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x42, /* 01000010 */ - 0x42, /* 01000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 10 0x0a '^J' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0x99, /* 10011001 */ - 0xbd, /* 10111101 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0xc3, /* 11000011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - /* 11 0x0b '^K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x1a, /* 00011010 */ - 0x32, /* 00110010 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 12 0x0c '^L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 13 0x0d '^M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x33, /* 00110011 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x70, /* 01110000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 14 0x0e '^N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x67, /* 01100111 */ - 0xe7, /* 11100111 */ - 0xe6, /* 11100110 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 15 0x0f '^O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xdb, /* 11011011 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0x3c, /* 00111100 */ - 0xdb, /* 11011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 16 0x10 '^P' */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0xf0, /* 11110000 */ - 0xf8, /* 11111000 */ - 0xfe, /* 11111110 */ - 0xf8, /* 11111000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 17 0x11 '^Q' */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0e, /* 00001110 */ - 0x1e, /* 00011110 */ - 0x3e, /* 00111110 */ - 0xfe, /* 11111110 */ - 0x3e, /* 00111110 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 18 0x12 '^R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 19 0x13 '^S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 20 0x14 '^T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7b, /* 01111011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 21 0x15 '^U' */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 22 0x16 '^V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 23 0x17 '^W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 24 0x18 '^X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 25 0x19 '^Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 26 0x1a '^Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 27 0x1b '^[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xfe, /* 11111110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 28 0x1c '^\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 29 0x1d '^]' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x28, /* 00101000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x28, /* 00101000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 30 0x1e '^^' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 31 0x1f '^_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 32 0x20 ' ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 33 0x21 '!' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 34 0x22 '"' */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x24, /* 00100100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 35 0x23 '#' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 36 0x24 '$' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x86, /* 10000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 37 0x25 '%' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 38 0x26 '&' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 39 0x27 ''' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 40 0x28 '(' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 41 0x29 ')' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 42 0x2a '*' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0xff, /* 11111111 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 43 0x2b '+' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 44 0x2c ',' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 45 0x2d '-' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 46 0x2e '.' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 47 0x2f '/' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 48 0x30 '0' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 49 0x31 '1' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x38, /* 00111000 */ - 0x78, /* 01111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 50 0x32 '2' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 51 0x33 '3' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x3c, /* 00111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 52 0x34 '4' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x1c, /* 00011100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 53 0x35 '5' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 54 0x36 '6' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 55 0x37 '7' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 56 0x38 '8' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 57 0x39 '9' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 58 0x3a ':' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 59 0x3b ';' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 60 0x3c '<' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 61 0x3d '=' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 62 0x3e '>' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 63 0x3f '?' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 64 0x40 '@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xdc, /* 11011100 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 65 0x41 'A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 66 0x42 'B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 67 0x43 'C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 68 0x44 'D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 69 0x45 'E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 70 0x46 'F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 71 0x47 'G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xde, /* 11011110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x66, /* 01100110 */ - 0x3a, /* 00111010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 72 0x48 'H' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 73 0x49 'I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 74 0x4a 'J' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 75 0x4b 'K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe6, /* 11100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 76 0x4c 'L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 77 0x4d 'M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xee, /* 11101110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 78 0x4e 'N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 79 0x4f 'O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 80 0x50 'P' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 81 0x51 'Q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xde, /* 11011110 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 82 0x52 'R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 83 0x53 'S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 84 0x54 'T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x5a, /* 01011010 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 85 0x55 'U' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 86 0x56 'V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 87 0x57 'W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0xee, /* 11101110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 88 0x58 'X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 89 0x59 'Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 90 0x5a 'Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 91 0x5b '[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 92 0x5c '\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0x70, /* 01110000 */ - 0x38, /* 00111000 */ - 0x1c, /* 00011100 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 93 0x5d ']' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 94 0x5e '^' */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 95 0x5f '_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 96 0x60 '`' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 97 0x61 'a' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 98 0x62 'b' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 99 0x63 'c' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 100 0x64 'd' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 101 0x65 'e' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 102 0x66 'f' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x36, /* 00110110 */ - 0x32, /* 00110010 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 103 0x67 'g' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - /* 104 0x68 'h' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x6c, /* 01101100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 105 0x69 'i' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 106 0x6a 'j' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - /* 107 0x6b 'k' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 108 0x6c 'l' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 109 0x6d 'm' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 110 0x6e 'n' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 111 0x6f 'o' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 112 0x70 'p' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - /* 113 0x71 'q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - /* 114 0x72 'r' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 115 0x73 's' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 116 0x74 't' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0xfc, /* 11111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x36, /* 00110110 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 117 0x75 'u' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 118 0x76 'v' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 119 0x77 'w' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 120 0x78 'x' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 121 0x79 'y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - /* 122 0x7a 'z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 123 0x7b '{' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 124 0x7c '|' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 125 0x7d '}' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 126 0x7e '~' */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 127 0x7f '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 128 0x80 'Ç' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 129 0x81 'ü' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 130 0x82 'é' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 131 0x83 'â' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 132 0x84 'ä' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 133 0x85 'à' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 134 0x86 'å' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 135 0x87 'ç' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 136 0x88 'ê' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 137 0x89 'ë' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 138 0x8a 'è' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 139 0x8b 'ï' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 140 0x8c 'î' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 141 0x8d 'ì' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 142 0x8e 'Ä' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 143 0x8f 'Å' */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 144 0x90 'É' */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 145 0x91 'æ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x6e, /* 01101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 146 0x92 'Æ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3e, /* 00111110 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xce, /* 11001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 147 0x93 'ô' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 148 0x94 'ö' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 149 0x95 'ò' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 150 0x96 'û' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 151 0x97 'ù' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 152 0x98 'ÿ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - /* 153 0x99 'Ö' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 154 0x9a 'Ü' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 155 0x9b '¢' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 156 0x9c '£' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x64, /* 01100100 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xe6, /* 11100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 157 0x9d '¥' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 158 0x9e '₧' */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xf8, /* 11111000 */ - 0xc4, /* 11000100 */ - 0xcc, /* 11001100 */ - 0xde, /* 11011110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 159 0x9f 'ƒ' */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 160 0xa0 'á' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 161 0xa1 'í' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 162 0xa2 'ó' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 163 0xa3 'ú' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 164 0xa4 'ñ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 165 0xa5 'Ñ' */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 166 0xa6 'ª' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 167 0xa7 'º' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 168 0xa8 '¿' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 169 0xa9 '⌐' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 170 0xaa '¬' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 171 0xab '½' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xdc, /* 11011100 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 172 0xac '¼' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x66, /* 01100110 */ - 0xce, /* 11001110 */ - 0x9a, /* 10011010 */ - 0x3f, /* 00111111 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 173 0xad '¡' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 174 0xae '«' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 175 0xaf '»' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 176 0xb0 '░' */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - /* 177 0xb1 '▒' */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - /* 178 0xb2 '▓' */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - /* 179 0xb3 '│' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 180 0xb4 '┤' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 181 0xb5 '╡' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 182 0xb6 '╢' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 183 0xb7 '╖' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 184 0xb8 '╕' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 185 0xb9 '╣' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 186 0xba '║' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 187 0xbb '╗' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 188 0xbc '╝' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 189 0xbd '╜' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 190 0xbe '╛' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 191 0xbf '┐' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 192 0xc0 '└' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 193 0xc1 '┴' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 194 0xc2 '┬' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 195 0xc3 '├' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 196 0xc4 '─' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 197 0xc5 '┼' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 198 0xc6 '╞' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 199 0xc7 '╟' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 200 0xc8 '╚' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 201 0xc9 '╔' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 202 0xca '╩' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 203 0xcb '╦' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 204 0xcc '╠' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 205 0xcd '═' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 206 0xce '╬' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 207 0xcf '╧' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 208 0xd0 '╨' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 209 0xd1 '╤' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 210 0xd2 '╥' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 211 0xd3 '╙' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 212 0xd4 '╘' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 213 0xd5 '╒' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 214 0xd6 '╓' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 215 0xd7 '╫' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - /* 216 0xd8 '╪' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 217 0xd9 '┘' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 218 0xda '┌' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 219 0xdb '█' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - /* 220 0xdc '▄' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - /* 221 0xdd '▌' */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - /* 222 0xde '▐' */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - /* 223 0xdf '▀' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 224 0xe0 'α' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 225 0xe1 'ß' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xd8, /* 11011000 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 226 0xe2 'Γ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 227 0xe3 'π' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 228 0xe4 'Σ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 229 0xe5 'σ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 230 0xe6 'µ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - /* 231 0xe7 'τ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 232 0xe8 'Φ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 233 0xe9 'Θ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 234 0xea 'Ω' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xee, /* 11101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 235 0xeb 'δ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x3e, /* 00111110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 236 0xec '∞' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 237 0xed 'φ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x03, /* 00000011 */ - 0x06, /* 00000110 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xf3, /* 11110011 */ - 0x7e, /* 01111110 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 238 0xee 'ε' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 239 0xef '∩' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 240 0xf0 '≡' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 241 0xf1 '±' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 242 0xf2 '≥' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 243 0xf3 '≤' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 244 0xf4 '⌠' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - /* 245 0xf5 '⌡' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 246 0xf6 '÷' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 247 0xf7 '≈' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 248 0xf8 '°' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 249 0xf9 '·' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 250 0xfa '•' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 251 0xfb '√' */ - 0x00, /* 00000000 */ - 0x0f, /* 00001111 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xec, /* 11101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3c, /* 00111100 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 252 0xfc 'ⁿ' */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 253 0xfd '²' */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x32, /* 00110010 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 254 0xfe '■' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - /* 255 0xff ' ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - ]; -} +// https://github.com/jamwaffles/embedded-graphics/blob/0ec4fc09c55aee733fb9d9cd6525749b8e15766e/embedded-graphics/data/font8x16_1bpp.raw +const FONT_IMAGE: &'static [u8] = include_bytes!("font8x16_1bpp.raw"); impl Font for Font8x16 { const HEIGHT: usize = 16; @@ -4372,6 +16,43 @@ impl Font for Font8x16 { #[inline] fn get(byte: u8, x: usize, y: usize) -> bool { - Self::DATA[byte as usize * 16 + y] & (1 << (7 - x)) != 0 + const FONT_IMAGE_WIDTH: usize = 240; + let char_per_row = FONT_IMAGE_WIDTH / Self::WIDTH; + + // Char _code_ offset from first char, most often a space + // E.g. first char = ' ' (32), target char = '!' (33), offset = 33 - 32 = 1 + let char_offset = char_offset(byte as char) as usize; + let row = char_offset / char_per_row; + + // Top left corner of character, in pixels + let char_x = (char_offset - (row * char_per_row)) * Self::WIDTH; + let char_y = row * Self::HEIGHT; + + // Bit index + // = X pixel offset for char + // + Character row offset (row 0 = 0, row 1 = (192 * 8) = 1536) + // + X offset for the pixel block that comprises this char + // + Y offset for pixel block + let bitmap_bit_index = char_x + x + + (FONT_IMAGE_WIDTH * (char_y + y)); + + let bitmap_byte = bitmap_bit_index / 8; + let bitmap_bit = 7 - (bitmap_bit_index % 8); + + FONT_IMAGE[bitmap_byte] & ((1 << bitmap_bit) as u8) != 0 + } +} + +fn char_offset(c: char) -> u32 { + let fallback = '?' as u32 - ' ' as u32; + if c < ' ' { + return fallback; + } + if c <= '~' { + return c as u32 - ' ' as u32; + } + if c < '¡' || c > 'ÿ' { + return fallback; } + c as u32 - ' ' as u32 - 34 } diff --git a/kernel/src/drivers/console/fonts/font8x16_1bpp.raw b/kernel/src/drivers/console/fonts/font8x16_1bpp.raw new file mode 100644 index 0000000000000000000000000000000000000000..372f9945e6b1b2e2fd36bf925d393ae1183969dc GIT binary patch literal 3360 zcmd6pzl$436vrRtSX?ZJ3Ky>s!o?LXQVcGR#SF%nD_mR^Qkf8jBMdI4P+^uO48lb) zE?oK#F{x56DqgjiD}oS499O9dMwM|P*7?5K)!C;=hZ9odNt$1ud2fEanKvRLV*K`r zS8Dc9_7tfwdCv=uF>i}D#?;^XAQTMu=0hPeteuDuWkmKUOsBz_JoUXLRhHSh&P15e zWT~yCAd`F5&V=(U^pq!sewMVFP&1a({{pjPg(2G6=|p|avfMC7wG0`&N{1?CFyQ3@rz>8#!-wW zR%BotqLWqGy`3A{_4!|XVXO6kBL5oYVa=&W7~Y~pFOKVgKJx*4%;cw=O*V1iM6k)y5+obGt@8^=&Z1C zCSSBk_X4_=lXv1I{h87krZ1rlJT-=E(G@u~ zHQp<|P+ELIVjM@&-B>*kTP<5mbrqM<#z7F<+8zGtPWBFvnhy7Yf7(8{Q2}>oKeqvA z@{)%5Tyl0<^gTO^FLI$AHzucJa-6x%`Rwe~X?05P>#f?NmrAP&yJN~w9D4q95f|km zt{ZHsjFsj=f>ce(S>P7lZ%Q$sK?E zd8N&m4~fsKBS!PnSApmUsIM#X&kI^X72}?pM1OidU&j+7J#zj|f!L_jo_Cg?QaGT~ zuc+%OW|h-pIzCX#D*g@{dTm)ZV<;GLA%}44l40smm}>?{#8{A z?n~U>P0h9L*DCe3+6|TQuqXxQk&FJQOf9_zo3N03n1=~?%2HEl+iQ*Ay!Bi*F$o;su8q545L~lM@OmaXv*5$Aic0mwG>i{QSw2dkEnw^ZE>u z=*QIHZ5RyBujn&~(vJv<5KG5L-yInp4^mf8+rQusfK09yx!>gcd5bB{LQa# zQW11|HE!2}OEgju(ayRF$1*<+79mKA3VRdj_@48=azbReD*J|698yvdb^&9Hy z&f(sE>drLY0O3!24RDR|!=)aSdUVOJ3Yb{PlP{;^e34poson*c=>GN~*Ro4#+E5>X zuFKn0?WhmxovLcmkhN|b#_O7UT>JFOH?IAo~_d*37( z*DBjI_Vn!*RaN{S>*;S@^~!P@&#pq5q#Is695qa*t-{h=zuMg%u6z35dbl^bD@!q1 zU78BpJ Date: Sat, 20 Apr 2019 16:41:52 +0800 Subject: [PATCH 24/61] Append kernel image to fu540.elf, but still not working on HfU --- kernel/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/Makefile b/kernel/Makefile index 63f52ff..af393e3 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -366,7 +366,8 @@ endif ifeq ($(board), u540) .PHONY: install: $(kernel_img) - @$(objcopy) -S -O binary --change-addresses -0x80000000 $< $(build_path)/bin + @$(objcopy) -S -O binary ../tools/opensbi/fu540.elf $(build_path)/bin + @dd if=$< of=$(build_path)/bin bs=131072 seek=16 @../tools/u540/mkimg.sh $(build_path)/bin $(build_path)/sd.img endif From 218bb29cf337e9db010369155bbd99602aec6054 Mon Sep 17 00:00:00 2001 From: Yuhao Zhou Date: Sun, 21 Apr 2019 14:30:02 +0800 Subject: [PATCH 25/61] Fix TimeSpec type. --- kernel/src/syscall/time.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/src/syscall/time.rs b/kernel/src/syscall/time.rs index 2ae76d4..edea0f6 100644 --- a/kernel/src/syscall/time.rs +++ b/kernel/src/syscall/time.rs @@ -53,20 +53,20 @@ impl TimeVal { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct TimeSpec { - sec: u64, - nsec: u64, + sec: usize, + nsec: usize, } impl TimeSpec { pub fn to_duration(&self) -> Duration { - Duration::new(self.sec, self.nsec as u32) + Duration::new(self.sec as u64, self.nsec as u32) } pub fn get_epoch() -> Self { let usec = get_epoch_usec(); TimeSpec { - sec: usec / USEC_PER_SEC, - nsec: usec % USEC_PER_SEC * NSEC_PER_USEC, + sec: (usec / USEC_PER_SEC) as usize, + nsec: (usec % USEC_PER_SEC * NSEC_PER_USEC) as usize, } } } From cf3fd0ec93995ac4aab3290cc183be4c7d92b558 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sun, 21 Apr 2019 15:45:26 +0800 Subject: [PATCH 26/61] Fix ioctl numbers and sys_poll for mipsel --- kernel/src/arch/mipsel/cpu.rs | 8 +++++--- kernel/src/arch/mipsel/interrupt.rs | 8 ++------ kernel/src/drivers/console/fonts/font8x16.rs | 3 +-- kernel/src/fs/stdio.rs | 21 ++++++++++++++++++++ kernel/src/syscall/fs.rs | 21 ++++++++++++++------ kernel/src/syscall/mod.rs | 11 +++++----- kernel/src/syscall/proc.rs | 8 ++++++-- 7 files changed, 56 insertions(+), 24 deletions(-) diff --git a/kernel/src/arch/mipsel/cpu.rs b/kernel/src/arch/mipsel/cpu.rs index 764d472..9ee6b4a 100644 --- a/kernel/src/arch/mipsel/cpu.rs +++ b/kernel/src/arch/mipsel/cpu.rs @@ -1,7 +1,7 @@ -use mips::registers::cp0; -use mips::instructions; use crate::consts::MAX_CPU_NUM; use core::ptr::{read_volatile, write_volatile}; +use mips::instructions; +use mips::registers::cp0; static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM]; @@ -22,7 +22,9 @@ pub unsafe fn start_others(hart_mask: usize) { } pub fn halt() { - unsafe { instructions::wait(); } + unsafe { + instructions::wait(); + } } pub unsafe fn exit_in_qemu(error_code: u8) -> ! { diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index 1036ffb..56757c4 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -201,9 +201,7 @@ fn set_trapframe_register(rt: usize, val: usize, tf: &mut TrapFrame) { } fn reserved_inst(tf: &mut TrapFrame) -> bool { - let inst = unsafe { - *(tf.epc as *const usize) - }; + let inst = unsafe { *(tf.epc as *const usize) }; let opcode = inst >> 26; let rt = (inst >> 16) & 0b11111; @@ -218,9 +216,7 @@ fn reserved_inst(tf: &mut TrapFrame) -> bool { fn _cur_tls(); } - let tls = unsafe { - *(_cur_tls as *const usize) - }; + let tls = unsafe { *(_cur_tls as *const usize) }; set_trapframe_register(rt, tls, tf); info!("Read TLS by rdhdr {:x} to register {:?}", tls, rt); diff --git a/kernel/src/drivers/console/fonts/font8x16.rs b/kernel/src/drivers/console/fonts/font8x16.rs index abea5bf..e559db6 100644 --- a/kernel/src/drivers/console/fonts/font8x16.rs +++ b/kernel/src/drivers/console/fonts/font8x16.rs @@ -33,8 +33,7 @@ impl Font for Font8x16 { // + Character row offset (row 0 = 0, row 1 = (192 * 8) = 1536) // + X offset for the pixel block that comprises this char // + Y offset for pixel block - let bitmap_bit_index = char_x + x - + (FONT_IMAGE_WIDTH * (char_y + y)); + let bitmap_bit_index = char_x + x + (FONT_IMAGE_WIDTH * (char_y + y)); let bitmap_byte = bitmap_bit_index / 8; let bitmap_bit = 7 - (bitmap_bit_index % 8); diff --git a/kernel/src/fs/stdio.rs b/kernel/src/fs/stdio.rs index 14e8c31..28bb934 100644 --- a/kernel/src/fs/stdio.rs +++ b/kernel/src/fs/stdio.rs @@ -41,10 +41,31 @@ lazy_static! { pub static ref STDOUT: Arc = Arc::new(Stdout::default()); } +// 32bits total, command in lower 16bits, size of the parameter structure in the lower 14 bits of the upper 16 bits +// higher 2 bits: 01 = write, 10 = read + +#[cfg(not(target_arch = "mips"))] const TCGETS: u32 = 0x5401; +#[cfg(target_arch = "mips")] +const TCGETS: u32 = 0x540D; + +#[cfg(not(target_arch = "mips"))] const TIOCGPGRP: u32 = 0x540F; +// _IOR('t', 119, int) +#[cfg(target_arch = "mips")] +const TIOCGPGRP: u32 = 0x4_004_74_77; + +#[cfg(not(target_arch = "mips"))] const TIOCSPGRP: u32 = 0x5410; +// _IOW('t', 118, int) +#[cfg(target_arch = "mips")] +const TIOCSPGRP: u32 = 0x8_004_74_76; + +#[cfg(not(target_arch = "mips"))] const TIOCGWINSZ: u32 = 0x5413; +// _IOR('t', 104, struct winsize) +#[cfg(target_arch = "mips")] +const TIOCGWINSZ: u32 = 0x4_008_74_68; // TODO: better way to provide default impl? macro_rules! impl_inode { diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 3c79da0..e859eb9 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -465,7 +465,7 @@ pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult { pub fn sys_ioctl(fd: usize, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { info!( - "ioctl: fd: {}, request: {}, args: {} {} {}", + "ioctl: fd: {}, request: {:x}, args: {} {} {}", fd, request, arg1, arg2, arg3 ); let mut proc = process(); @@ -1032,7 +1032,7 @@ pub struct Stat { blocks: u64, } -#[cfg(not(any(target_arch = "x86_64", target_arch = "mips"))] +#[cfg(not(any(target_arch = "x86_64", target_arch = "mips")))] #[repr(C)] #[derive(Debug)] pub struct Stat { @@ -1174,16 +1174,25 @@ impl From for Stat { size: info.size as u64, blksize: info.blk_size as u32, blocks: info.blocks as u64, - atime: Timespec { sec: info.atime.sec as i32, nsec: info.atime.nsec }, - mtime: Timespec { sec: info.mtime.sec as i32, nsec: info.mtime.nsec }, - ctime: Timespec { sec: info.ctime.sec as i32, nsec: info.ctime.nsec }, + atime: Timespec { + sec: info.atime.sec as i32, + nsec: info.atime.nsec, + }, + mtime: Timespec { + sec: info.mtime.sec as i32, + nsec: info.mtime.nsec, + }, + ctime: Timespec { + sec: info.ctime.sec as i32, + nsec: info.ctime.nsec, + }, __pad1: 0, __pad2: 0, __pad3: 0, } } - #[cfg(not(any(target_arch = "x86_64", target_arch="mips")))] + #[cfg(not(any(target_arch = "x86_64", target_arch = "mips")))] fn from(info: Metadata) -> Self { Stat { dev: info.dev as u64, diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 15498e2..1baea3c 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -350,9 +350,10 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { #[cfg(target_arch = "mips")] fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { let ret = match id { - SYS_FORK => sys_fork(tf), SYS_OPEN => sys_open(args[0] as *const u8, args[1], args[2]), + SYS_POLL => sys_poll(args[0] as *mut PollFd, args[1], args[2]), SYS_DUP2 => sys_dup2(args[0], args[1]), + SYS_FORK => sys_fork(tf), SYS_MMAP2 => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), SYS_FSTAT64 => sys_fstat(args[0], args[1] as *mut Stat), SYS_LSTAT64 => sys_lstat(args[0] as *const u8, args[1] as *mut Stat), @@ -366,10 +367,10 @@ fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option Err(err) + } + Err(err) => Err(err), } - }, + } SYS_GETPGID => { warn!("sys_getpgid is unimplemented"); Ok(0) @@ -381,7 +382,7 @@ fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { warn!("sys_fcntl64 is unimplemented"); Ok(0) - }, + } SYS_SET_THREAD_AREA => { info!("set_thread_area: tls: 0x{:x}", args[0]); extern "C" { diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 89b7765..c6c6b1f 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -33,9 +33,13 @@ pub fn sys_clone( warn!("sys_clone is calling sys_fork instead, ignoring other args"); return sys_fork(tf); } - if (flags != 0x7d0f00) && (flags!= 0x5d0f00) { //0x5d0f00 is the args from gcc of alpine linux + if (flags != 0x7d0f00) && (flags != 0x5d0f00) { + //0x5d0f00 is the args from gcc of alpine linux //warn!("sys_clone only support musl pthread_create"); - panic!("sys_clone only support sys_fork OR musl pthread_create without flags{:x}", flags); + panic!( + "sys_clone only support sys_fork OR musl pthread_create without flags{:x}", + flags + ); //return Err(SysError::ENOSYS); } { From 144090e42dcfab557ecf0ce5d1ad8796a61bef00 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Sun, 21 Apr 2019 17:07:40 +0800 Subject: [PATCH 27/61] add syscall: sys_times partial implementation --- kernel/src/memory.rs | 2 +- kernel/src/syscall/mod.rs | 5 +++-- kernel/src/syscall/time.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index f98f1ad..54c2cff 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -106,7 +106,7 @@ impl Drop for KernelStack { /// Handle page fault at `addr`. /// Return true to continue, false to halt. pub fn handle_page_fault(addr: usize) -> bool { - debug!("page fault @ {:#x}", addr); + // debug!("page fault @ {:#x}", addr); // This is safe as long as page fault never happens in page fault handler unsafe { process_unsafe().vm.handle_page_fault(addr) } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 7bd1a77..a24f34a 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -59,8 +59,8 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]), SYS_MUNMAP => sys_munmap(args[0], args[1]), SYS_BRK => { - warn!("sys_brk is unimplemented"); - Ok(0) + warn!("sys_brk is unimplemented, return -1"); + Err(SysError::ENOMEM) } SYS_RT_SIGACTION => { warn!("sys_sigaction is unimplemented"); @@ -174,6 +174,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { // SYS_GETRLIMIT => sys_getrlimit(), SYS_GETRUSAGE => sys_getrusage(args[0], args[1] as *mut RUsage), SYS_SYSINFO => sys_sysinfo(args[0] as *mut SysInfo), + SYS_TIMES => sys_times(args[0] as *mut Tms), SYS_GETUID => { warn!("sys_getuid is unimplemented"); Ok(0) diff --git a/kernel/src/syscall/time.rs b/kernel/src/syscall/time.rs index dd5cfcd..ff25cb3 100644 --- a/kernel/src/syscall/time.rs +++ b/kernel/src/syscall/time.rs @@ -146,3 +146,33 @@ pub fn sys_getrusage(who: usize, rusage: *mut RUsage) -> SysResult { unsafe { *rusage = new_rusage }; Ok(0) } + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Tms { + tms_utime: u64, /* user time */ + tms_stime: u64, /* system time */ + tms_cutime: u64, /* user time of children */ + tms_cstime: u64, /* system time of children */ +} + + +pub fn sys_times(buf:*mut Tms)-> SysResult { + info!("times: buf: {:?}", buf); + let proc = process(); + proc.vm.check_write_ptr(buf)?; + + let tick_base = *TICK_BASE; + let tick = unsafe { crate::trap::TICK as u64 }; + + let new_buf = Tms { + tms_utime: 0, + tms_stime: 0, + tms_cutime: 0, + tms_cstime: 0, + }; + + unsafe { *buf = new_buf }; + Ok(tick as usize) +} \ No newline at end of file From 1e5f901926a52a3c02e98a2ea5ecb9d201684ec5 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 21 Apr 2019 15:01:52 +0800 Subject: [PATCH 28/61] shrink kstack size, avoid alloc kstack for init thread --- kernel/src/arch/riscv32/boot/entry32.asm | 4 ++-- kernel/src/arch/riscv32/boot/entry64.asm | 4 ++-- kernel/src/memory.rs | 2 +- kernel/src/process/structs.rs | 6 ++---- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/kernel/src/arch/riscv32/boot/entry32.asm b/kernel/src/arch/riscv32/boot/entry32.asm index 22cc0ee..3ea0676 100644 --- a/kernel/src/arch/riscv32/boot/entry32.asm +++ b/kernel/src/arch/riscv32/boot/entry32.asm @@ -8,7 +8,7 @@ _start: # 1. set sp # sp = bootstack + (hartid + 1) * 0x10000 add t0, a0, 1 - slli t0, t0, 16 + slli t0, t0, 14 lui sp, %hi(bootstack) add sp, sp, t0 @@ -32,7 +32,7 @@ _start: .align 12 # page align .global bootstack bootstack: - .space 4096 * 16 * 8 + .space 4096 * 4 * 8 .global bootstacktop bootstacktop: diff --git a/kernel/src/arch/riscv32/boot/entry64.asm b/kernel/src/arch/riscv32/boot/entry64.asm index 69727d5..6fbedbb 100644 --- a/kernel/src/arch/riscv32/boot/entry64.asm +++ b/kernel/src/arch/riscv32/boot/entry64.asm @@ -8,7 +8,7 @@ _start: # 1. set sp # sp = bootstack + (hartid + 1) * 0x10000 add t0, a0, 1 - slli t0, t0, 16 + slli t0, t0, 14 lui sp, %hi(bootstack) add sp, sp, t0 @@ -32,7 +32,7 @@ _start: .align 12 # page align .global bootstack bootstack: - .space 4096 * 16 * 8 + .space 4096 * 4 * 8 .global bootstacktop bootstacktop: diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index 54c2cff..ee152c9 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -77,7 +77,7 @@ pub fn dealloc_frame(target: usize) { } pub struct KernelStack(usize); -const STACK_SIZE: usize = 0x8000; +const STACK_SIZE: usize = 0x4000; impl KernelStack { pub fn new() -> Self { diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index a9982ee..c19cbe7 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -126,10 +126,8 @@ impl Thread { pub unsafe fn new_init() -> Box { Box::new(Thread { context: Context::null(), - kstack: KernelStack::new(), - clear_child_tid: 0, - // safety: this field will never be used - proc: core::mem::uninitialized(), + // safety: other fields will never be used + .. core::mem::uninitialized() }) } From 45c2ec0b17256d6bcbb28f49ac5dd65f04fd6da4 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 21 Apr 2019 23:47:00 +0800 Subject: [PATCH 29/61] works on K210! --- kernel/Cargo.toml | 1 + kernel/Makefile | 27 +- kernel/src/arch/riscv32/board/k210/linker.ld | 49 ++ .../linker64.ld => board/u540/linker.ld} | 0 kernel/src/arch/riscv32/boot/entry_k210.asm | 30 + kernel/src/arch/riscv32/consts.rs | 6 + kernel/src/arch/riscv32/memory.rs | 2 + kernel/src/arch/riscv32/mod.rs | 5 +- kernel/src/fs/stdio.rs | 9 + kernel/src/memory.rs | 18 +- kernel/src/process/structs.rs | 2 +- tools/k210/kflash.py | 829 ++++++++++++++++++ tools/opensbi/README.md | 6 + tools/opensbi/k210.elf | Bin 0 -> 239264 bytes 14 files changed, 968 insertions(+), 16 deletions(-) create mode 100644 kernel/src/arch/riscv32/board/k210/linker.ld rename kernel/src/arch/riscv32/{boot/linker64.ld => board/u540/linker.ld} (100%) create mode 100644 kernel/src/arch/riscv32/boot/entry_k210.asm create mode 100755 tools/k210/kflash.py create mode 100755 tools/opensbi/k210.elf diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index c4ce68c..74a7eb4 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -23,6 +23,7 @@ default = ["sv39"] # Page table sv39 or sv48 (for riscv64) sv39 = [] board_u540 = ["sv39", "link_user"] +board_k210 = ["sv39", "link_user"] # (for aarch64 RaspberryPi3) nographic = [] board_raspi3 = ["bcm2837", "link_user"] diff --git a/kernel/Makefile b/kernel/Makefile index af393e3..f1937d4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -23,8 +23,9 @@ # smp = 1 | 2 | ... SMP core number # graphic = on | off Enable/disable qemu graphical output # board = none Running on QEMU -# | pc Only available on x86_64, run on real pc +# | pc Only available on x86_64, run on real pc # | u540 Only available on riscv64, run on HiFive U540, use Sv39 +# | k210 Only available on riscv64, run on K210, use Sv39 # | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ # pci_passthru = 0000:00:00.1 Only available on x86_64, passthrough the specified PCI device # init = /bin/ls Only available on riscv64, run specified program instead of user shell @@ -59,7 +60,7 @@ ifeq ($(arch), $(filter $(arch), aarch64 mipsel)) export SFSIMG = $(user_dir)/build/$(arch).img else # board is pc or qemu? -ifeq ($(board), pc) +ifeq ($(board), $(filter $(board), pc u540 k210)) #link user img, so use original image export SFSIMG = $(user_dir)/build/$(arch).img else @@ -201,11 +202,6 @@ features += raspi3_use_generic_timer endif endif -ifeq ($(board), u540) -features += sv39 -riscv_pk_args += --enable-sv39 -endif - ifneq ($(board), none) features += board_$(board) endif @@ -325,6 +321,11 @@ ifeq ($(arch), x86_64) @bootimage build $(build_args) @mv target/x86_64/bootimage.bin $(bootimage) else ifeq ($(arch), $(filter $(arch), riscv32 riscv64)) +ifeq ($(board), k210) + @cp src/arch/riscv32/board/k210/linker.ld src/arch/riscv32/boot/linker64.ld +else + @cp src/arch/riscv32/board/u540/linker.ld src/arch/riscv32/boot/linker64.ld +endif @-patch -p0 -N -b \ $(shell rustc --print sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \ src/arch/riscv32/atomic.patch @@ -367,8 +368,16 @@ ifeq ($(board), u540) .PHONY: install: $(kernel_img) @$(objcopy) -S -O binary ../tools/opensbi/fu540.elf $(build_path)/bin - @dd if=$< of=$(build_path)/bin bs=131072 seek=16 - @../tools/u540/mkimg.sh $(build_path)/bin $(build_path)/sd.img + @dd if=$< of=$(build_path)/bin bs=0x20000 seek=16 + @../tools/u540/mkimg.sh $(build_path)/bin $(build_path)/u540.img +endif + +ifeq ($(board), k210) +.PHONY: +install: $(kernel_img) + @$(objcopy) -S -O binary ../tools/opensbi/k210.elf $(build_path)/k210.img + @dd if=$< of=$(build_path)/k210.img bs=0x10000 seek=1 + @python3 ../tools/k210/kflash.py -b 600000 $(build_path)/k210.img endif .PHONY: diff --git a/kernel/src/arch/riscv32/board/k210/linker.ld b/kernel/src/arch/riscv32/board/k210/linker.ld new file mode 100644 index 0000000..7abc05b --- /dev/null +++ b/kernel/src/arch/riscv32/board/k210/linker.ld @@ -0,0 +1,49 @@ +/* Copy from bbl-ucore : https://ring00.github.io/bbl-ucore */ + +/* Simple linker script for the ucore kernel. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_ARCH(riscv) +ENTRY(_start) + +BASE_ADDRESS = 0xffffffffc0010000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text : { + stext = .; + *(.text.entry) + *(.text .text.*) + . = ALIGN(4K); + etext = .; + } + + .rodata : { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data : { + sdata = .; + *(.data .data.*) + edata = .; + } + + .stack : { + *(.bss.stack) + } + + .bss : { + sbss = .; + *(.bss .bss.*) + ebss = .; + } + + PROVIDE(end = .); +} diff --git a/kernel/src/arch/riscv32/boot/linker64.ld b/kernel/src/arch/riscv32/board/u540/linker.ld similarity index 100% rename from kernel/src/arch/riscv32/boot/linker64.ld rename to kernel/src/arch/riscv32/board/u540/linker.ld diff --git a/kernel/src/arch/riscv32/boot/entry_k210.asm b/kernel/src/arch/riscv32/boot/entry_k210.asm new file mode 100644 index 0000000..29a65e0 --- /dev/null +++ b/kernel/src/arch/riscv32/boot/entry_k210.asm @@ -0,0 +1,30 @@ + .section .text.entry + .globl _start +_start: + # a0 == hartid + # pc == 0x80010000 + # sp == 0x8000xxxx + + # 1. set sp + # sp = bootstack + (hartid + 1) * 0x10000 + add t0, a0, 1 + slli t0, t0, 14 + lui sp, %hi(bootstack) + add sp, sp, t0 + + # 1.1 set device tree paddr + # OpenSBI give me 0 ??? + li a1, 0x800003b0 + + # 2. jump to rust_main (absolute address) + lui t0, %hi(rust_main) + addi t0, t0, %lo(rust_main) + jr t0 + + .section .bss.stack + .align 12 # page align + .global bootstack +bootstack: + .space 4096 * 4 * 2 + .global bootstacktop +bootstacktop: diff --git a/kernel/src/arch/riscv32/consts.rs b/kernel/src/arch/riscv32/consts.rs index 3042054..01b9f46 100644 --- a/kernel/src/arch/riscv32/consts.rs +++ b/kernel/src/arch/riscv32/consts.rs @@ -22,10 +22,16 @@ pub const KERNEL_P2_INDEX: usize = (KERNEL_OFFSET >> 12 >> 10) & 0x3ff; #[cfg(target_arch = "riscv64")] pub const KERNEL_P4_INDEX: usize = (KERNEL_OFFSET >> 12 >> 9 >> 9 >> 9) & 0o777; +#[cfg(feature = "board_k210")] +pub const KERNEL_HEAP_SIZE: usize = 0x0020_0000; +#[cfg(not(feature = "board_k210"))] pub const KERNEL_HEAP_SIZE: usize = 0x0080_0000; pub const MEMORY_OFFSET: usize = 0x8000_0000; // TODO: get memory end from device tree +#[cfg(feature = "board_k210")] +pub const MEMORY_END: usize = 0x8060_0000; +#[cfg(not(feature = "board_k210"))] pub const MEMORY_END: usize = 0x8800_0000; // FIXME: rv64 `sh` and `ls` will crash if stack top > 0x80000000 ??? diff --git a/kernel/src/arch/riscv32/memory.rs b/kernel/src/arch/riscv32/memory.rs index af7333b..ef0509b 100644 --- a/kernel/src/arch/riscv32/memory.rs +++ b/kernel/src/arch/riscv32/memory.rs @@ -9,6 +9,8 @@ use riscv::{addr::*, register::sstatus}; /// Initialize the memory management module pub fn init(dtb: usize) { // allow user memory access + // NOTE: In K210 priv v1.9.1, sstatus.SUM is PUM which has opposite meaning! + #[cfg(not(feature = "board_k210"))] unsafe { sstatus::set_sum(); } diff --git a/kernel/src/arch/riscv32/mod.rs b/kernel/src/arch/riscv32/mod.rs index 1b30ad3..f05a082 100644 --- a/kernel/src/arch/riscv32/mod.rs +++ b/kernel/src/arch/riscv32/mod.rs @@ -55,6 +55,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! { // FIXME: init driver on u540 #[cfg(not(feature = "board_u540"))] crate::drivers::init(device_tree_vaddr); + #[cfg(not(feature = "board_k210"))] unsafe { board::enable_serial_interrupt(); board::init_external_interrupt(); @@ -108,6 +109,8 @@ global_asm!( ); #[cfg(target_arch = "riscv32")] global_asm!(include_str!("boot/entry32.asm")); -#[cfg(target_arch = "riscv64")] +#[cfg(all(target_arch = "riscv64", not(feature = "board_k210")))] global_asm!(include_str!("boot/entry64.asm")); +#[cfg(feature = "board_k210")] +global_asm!(include_str!("boot/entry_k210.asm")); global_asm!(include_str!("boot/trap.asm")); diff --git a/kernel/src/fs/stdio.rs b/kernel/src/fs/stdio.rs index 28bb934..3967e41 100644 --- a/kernel/src/fs/stdio.rs +++ b/kernel/src/fs/stdio.rs @@ -20,6 +20,15 @@ impl Stdin { self.pushed.notify_one(); } pub fn pop(&self) -> char { + #[cfg(feature = "board_k210")] + loop { + // polling + let c = crate::arch::io::getchar(); + if c != '\0' { + return c; + } + } + #[cfg(not(feature = "board_k210"))] loop { let ret = self.buf.lock().pop_front(); match ret { diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index ee152c9..3156ff0 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -16,13 +16,21 @@ pub type MemorySet = rcore_memory::memory_set::MemorySet; #[cfg(target_arch = "x86_64")] pub type FrameAlloc = bitmap_allocator::BitAlloc16M; -// RISCV has 1G memory -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +// RISCV, ARM, MIPS has 1G memory +#[cfg(all( + any( + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "aarch64", + target_arch = "mips" + ), + not(feature = "board_k210") +))] pub type FrameAlloc = bitmap_allocator::BitAlloc1M; -// Raspberry Pi 3 has 1G memory -#[cfg(any(target_arch = "aarch64", target_arch = "mips"))] -pub type FrameAlloc = bitmap_allocator::BitAlloc1M; +// K210 has 8M memory +#[cfg(feature = "board_k210")] +pub type FrameAlloc = bitmap_allocator::BitAlloc4K; lazy_static! { pub static ref FRAME_ALLOCATOR: SpinNoIrqLock = diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index c19cbe7..c86751a 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -127,7 +127,7 @@ impl Thread { Box::new(Thread { context: Context::null(), // safety: other fields will never be used - .. core::mem::uninitialized() + ..core::mem::uninitialized() }) } diff --git a/tools/k210/kflash.py b/tools/k210/kflash.py new file mode 100755 index 0000000..518c574 --- /dev/null +++ b/tools/k210/kflash.py @@ -0,0 +1,829 @@ +#!/usr/bin/env python3 +import sys +import time +import zlib +import copy +import struct +from enum import Enum +import binascii +import hashlib +import argparse +import math +import zipfile, tempfile +import json +import re +import os + +BASH_TIPS = dict(NORMAL='\033[0m',BOLD='\033[1m',DIM='\033[2m',UNDERLINE='\033[4m', + DEFAULT='\033[39', RED='\033[31m', YELLOW='\033[33m', GREEN='\033[32m', + BG_DEFAULT='\033[49m', BG_WHITE='\033[107m') + +ERROR_MSG = BASH_TIPS['RED']+BASH_TIPS['BOLD']+'[ERROR]'+BASH_TIPS['NORMAL'] +WARN_MSG = BASH_TIPS['YELLOW']+BASH_TIPS['BOLD']+'[WARN]'+BASH_TIPS['NORMAL'] +INFO_MSG = BASH_TIPS['GREEN']+BASH_TIPS['BOLD']+'[INFO]'+BASH_TIPS['NORMAL'] + +VID_LIST_FOR_AUTO_LOOKUP = "(1A86)|(0403)|(067B)|(10C4)" +# WCH FTDI PL CL +timeout = 0.5 + +MAX_RETRY_TIMES = 10 + +class TimeoutError(Exception): pass + +try: + import serial + import serial.tools.list_ports +except ImportError: + print(ERROR_MSG,'PySerial must be installed, run '+BASH_TIPS['GREEN']+'`pip3 install pyserial`',BASH_TIPS['DEFAULT']) + sys.exit(1) + +# AES is from: https://github.com/ricmoo/pyaes, Copyright by Richard Moore +class AES: + '''Encapsulates the AES block cipher. + You generally should not need this. Use the AESModeOfOperation classes + below instead.''' + @staticmethod + def _compact_word(word): + return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3] + + # Number of rounds by keysize + number_of_rounds = {16: 10, 24: 12, 32: 14} + + # Round constant words + rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ] + + # S-box and Inverse S-box (S is for Substitution) + S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ] + Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] + + # Transformations for encryption + T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ] + T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ] + T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ] + T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ] + + # Transformations for decryption + T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ] + T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ] + T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ] + T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ] + + # Transformations for decryption key expansion + U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ] + U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ] + U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ] + U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ] + + def __init__(self, key): + + if len(key) not in (16, 24, 32): + raise ValueError('Invalid key size') + + rounds = self.number_of_rounds[len(key)] + + # Encryption round keys + self._Ke = [[0] * 4 for i in range(rounds + 1)] + + # Decryption round keys + self._Kd = [[0] * 4 for i in range(rounds + 1)] + + round_key_count = (rounds + 1) * 4 + KC = len(key) // 4 + + # Convert the key into ints + tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in range(0, len(key), 4) ] + + # Copy values into round key arrays + for i in range(0, KC): + self._Ke[i // 4][i % 4] = tk[i] + self._Kd[rounds - (i // 4)][i % 4] = tk[i] + + # Key expansion (fips-197 section 5.2) + rconpointer = 0 + t = KC + while t < round_key_count: + + tt = tk[KC - 1] + tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^ + (self.S[(tt >> 8) & 0xFF] << 16) ^ + (self.S[ tt & 0xFF] << 8) ^ + self.S[(tt >> 24) & 0xFF] ^ + (self.rcon[rconpointer] << 24)) + rconpointer += 1 + + if KC != 8: + for i in range(1, KC): + tk[i] ^= tk[i - 1] + + # Key expansion for 256-bit keys is "slightly different" (fips-197) + else: + for i in range(1, KC // 2): + tk[i] ^= tk[i - 1] + tt = tk[KC // 2 - 1] + + tk[KC // 2] ^= (self.S[ tt & 0xFF] ^ + (self.S[(tt >> 8) & 0xFF] << 8) ^ + (self.S[(tt >> 16) & 0xFF] << 16) ^ + (self.S[(tt >> 24) & 0xFF] << 24)) + + for i in range(KC // 2 + 1, KC): + tk[i] ^= tk[i - 1] + + # Copy values into round key arrays + j = 0 + while j < KC and t < round_key_count: + self._Ke[t // 4][t % 4] = tk[j] + self._Kd[rounds - (t // 4)][t % 4] = tk[j] + j += 1 + t += 1 + + # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3) + for r in range(1, rounds): + for j in range(0, 4): + tt = self._Kd[r][j] + self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^ + self.U2[(tt >> 16) & 0xFF] ^ + self.U3[(tt >> 8) & 0xFF] ^ + self.U4[ tt & 0xFF]) + + def encrypt(self, plaintext): + 'Encrypt a block of plain text using the AES block cipher.' + + if len(plaintext) != 16: + raise ValueError('wrong block length') + + rounds = len(self._Ke) - 1 + (s1, s2, s3) = [1, 2, 3] + a = [0, 0, 0, 0] + + # Convert plaintext to (ints ^ key) + t = [(AES._compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in range(0, 4)] + + # Apply round transforms + for r in range(1, rounds): + for i in range(0, 4): + a[i] = (self.T1[(t[ i ] >> 24) & 0xFF] ^ + self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^ + self.T3[(t[(i + s2) % 4] >> 8) & 0xFF] ^ + self.T4[ t[(i + s3) % 4] & 0xFF] ^ + self._Ke[r][i]) + t = copy.copy(a) + + # The last round is special + result = [ ] + for i in range(0, 4): + tt = self._Ke[rounds][i] + result.append((self.S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((self.S[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((self.S[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) + + return result + + def decrypt(self, ciphertext): + 'Decrypt a block of cipher text using the AES block cipher.' + + if len(ciphertext) != 16: + raise ValueError('wrong block length') + + rounds = len(self._Kd) - 1 + (s1, s2, s3) = [3, 2, 1] + a = [0, 0, 0, 0] + + # Convert ciphertext to (ints ^ key) + t = [(AES._compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in range(0, 4)] + + # Apply round transforms + for r in range(1, rounds): + for i in range(0, 4): + a[i] = (self.T5[(t[ i ] >> 24) & 0xFF] ^ + self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^ + self.T7[(t[(i + s2) % 4] >> 8) & 0xFF] ^ + self.T8[ t[(i + s3) % 4] & 0xFF] ^ + self._Kd[r][i]) + t = copy.copy(a) + + # The last round is special + result = [ ] + for i in range(0, 4): + tt = self._Kd[rounds][i] + result.append((self.Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((self.Si[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((self.Si[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) + + return result + +class AES_128_CBC: + + def __init__(self, key, iv = None): + self._aes = AES(key) + if iv is None: + self._last_cipherblock = [ 0 ] * 16 + elif len(iv) != 16: + raise ValueError('initialization vector must be 16 bytes') + else: + self._last_cipherblock = iv + + + def encrypt(self, plaintext): + if len(plaintext) != 16: + raise ValueError('plaintext block must be 16 bytes') + + precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ] + self._last_cipherblock = self._aes.encrypt(precipherblock) + + return b''.join(map(lambda x: x.to_bytes(1, 'little'), self._last_cipherblock)) + + def decrypt(self, ciphertext): + if len(ciphertext) != 16: + raise ValueError('ciphertext block must be 16 bytes') + + cipherblock = ciphertext + plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ] + self._last_cipherblock = cipherblock + + return b''.join(map(lambda x: x.to_bytes(1, 'little'), plaintext)) + + +ISP_PROG = '789cedbc0d5854d7d53fbacff7805fe85106039189a390d8d4a283420231632aa226cd4b93a8499b54c801d104150543d2c6b7e0308ca84930471d0cf4959808896d53d351c7d6a4682b62faf1d67c28499a467480d168024460d40073d7dae70c1f2726b7efff7f9fe7defb7f8acfcf357b9dfdb1f6da7bafbdf63efbec35a498b4ffe1d79f16642424146458007644a29b2544ddc88e2aa87820412584c80c840132f20132071420f34001b20014208b4001b20414209b8002e430a000391c28401e0114208f040a90470105c8a38102e431400157264724282758c8dff28335194773dddb805fc25c30bf88b2ace3e5756c6fc1547ba72a5888927f90c89113181bfb4790770291c78e656ccc5cb2c61ec1c90cd36c4d1c4bacc9b7106bea0c624d98cb5a137fc85a93b3586bea5ad69a50c25b13b7f1d6e497796bea9bbc35e198684d7c57b4269f13ada99da235810983f461903e0cd28741fa11907e04a41f01e94740fa51907e14a41f05e94741fa31907e0ca41f03e9c7c4273011f1896323e2936f89884f9d11119f30775c7ce20fc7c527678d8b4f5d3b2e3ea1647c7ce2b6f1f1c92f8f8f4f7d737c7cc2b1c8f8c47723e393cf45c6a7764642fa89907e22a49f08e92742fa68481f0de9a3217d34a4bf19d2df0ce96f86f43743fa58481f0be963217d6cc1544be295a91189b2c840fb3011ca1281b4db33c6aec1f6cfa8985a103121d1915042b8190ce39851c2703319d631b384e56c0ce7b095705c22c33b124b786e162338669508dc6c4674cc2e11b92446722495485c326372249798b83b9830c71d2561dc9d4cb8e3ce92702e8519e1482919c1a532231da92523b9bb98518ebb4a46717398d18e3925a3b9bb99318ebb4bc648a01f57424984348319eb9a5132569ac98c73cd2c1927d918d9652b91a54466bc2bb164bc348b99e09a5532419acd44ba6697444a498cd99554629692992857724994740733d17547c944e94ee626d79d253749294cb42ba5245a4a65625ca92531d25dcccdaebb4a6e96e630935c734a26497733b1aebb4b62a17f580a8825016810fbc995387ba7db057dcd953ecfe1954892180c72752ec656d4489222b19f47feb72db791587fe527c02772ae99585fc5df8ddaef5af85deb2249d2b5a02c0582b6a7dae07923f01a89ada84d7b5e97ced0b8fb42bfe3f5df122317f983d6d7f4dfc887dfb21441948a3656162248bba5e2a12bb9f3120a4846c495787ba21a7011df66a9bf9d9cda80ed88e311eac2e4161362de4408b7e0e41db2944f52cc12a3d5abf14e37f01d274fde299b1208d631252a8ab1e54a4cb424116b8d9f44bb7a82d63d5ab9583759ea1853e5ec0eaadddd6394ca569ef2412ec7de74b6ca29407c81285d87808a600b4492e26cb02b79adac3a4162d5d3027ba4accd6e130f115fa5d86b7d0dca7855a272a28cdc02017e4f807225694dc7d96bdc5e49549d13c82b2feced5fd3b1fb2bad0e9bbe1baa836a8a207afb4cd79e2d984eeb50691a5607ebab666698dcdb5b45c75e8905fbc41e11bc76f946323fd1ca0f9519eb8972d3361008abbc28f2aa68c77667e5a2a5c417d3d4ffedf5597615ebc2357407ad357522d60f65c032534c07ed4ae187245a3269e56f429d5d20a1f2b15c9401d268799cc43c30cfdd7dd0befdaa9409e5946836176d2ff40d6b2ad839be93b4779cbd0c7d81d1fb028b72693a93a25157d1d2f0f675c409206f93e8884ba394b66d2db46d9948f5a3149e8134a0a73201f474c8ae6443db46829c674436456cb37b9ca7892fea066d8b6d5916096d598b6dd90bb2f45953b7c1fcd0115479d4d32906ec27d8e3b1ac757c273167e3bc72bcb33d2183515ee42364219fb427146f90850ea011da3c2354e0ef3055380abf8b713c3c0e756728df722a4b15ecc0af81df11f03b037eef87df1999aa80fa3a8af197a9902f948df17fe248e289197463bd336082798ba1bff980a84ac51a9f457ec6005fd3a34b443dca9285b6018e5d6badc486eaef96a8aea3689a990116db48e335fe4c6b2b8b96777200da2af63d682b16ec2c0b7636d4661cea8fd623a17815cc814c7b02c9d7ea0f754820cf38924a3599e6047a5126eb66e9ba2ad568f99a02bdd03f18e83b5d5a5f19ec1b56e14df20aff32f6917f0cef3f09c05bf68eb1df607a6b32c4934097d86622da189c4b2206fb1cc13eb7ec778e74cdfe584917c17ca04ecc0df2e1be3d9fb307feeff291854e1a1fcaece1d23a691c79fd84a132f7a9d036d6919da46aa9c0bc42a993d07e46fbdb9be0071c23d6519de49551a88bd8bfc0dc461cb3196c4f46867e8efd08f23f2cf31128d3d5684120be91cefe505b0d6b27bd6e982fd68de64de5dbdd80365bb753e7b06db8f4749f2ae693233b4526c5dc4a6cb94d217b764e8fd7ac8a166a97310e3e0fd934592abe05fada68ebab75d8f738e089d61a970873050bf332b6259be26cb3635d70bc2a850d4085c1719bd92a0e1db738fe71ec0ed8b7a86fb16f540fcb2e0cd183d62e43fa0a8e75aea147b775b1d750ae23622bd85a830dd97448b375ba2c2803ca0369aed23c4ef6186c1d61b1efd2b6e4f5b6c4fe02fde01581b6df6f86f7656cbbddd537eacb909738682777ffd2684321af5d374a37d8e776bfef48ef2472209e281120bf3f1e74778ebc22d131f03707f4472eed1cc63ba98d79d7a7981f1d97a981a3ba1d48d1c7ff5143395f69fee80c0efc4cce9afa4306fc4cc69ab8163016fcd36de0b7dec2a961307e360378117dea08f0a959f716c877cb9623ca4d3c0be5f1badfc6815fc6815fc6825fc6825fc6805fc6805f16f21304da6e816b638eb8aec37cd405e3932755a5309ff25d76b99c8776ab421f9e757847807ec289ec0c23d16218f1174b443587b16a13b471e994b947c2ee606ce1d7896f27df0b762700795fb726cfe5e49744f4b7a13e591c8c1146fed1678cf951f4ffffba30e93b847817a11ea0ce09b708e05f439da1aea963a94f4eed4439f4df30a8e71691d8c23733d123a227576dde7c8b521d86f514a09e02f54fef80fade01f5bd13ea7b27d43705ea9b02f54d1de8a322ad2bf4a5aad23098fb931858bfb068d794e622c1111f4e3c2e17f84d502f298168fd8dd7fb5ba9ded7a0af94f1d057c28836cf94403bfffda2eae6a91e52f8edc416768d1c29df857db94795f6df301f9cff302fabd83924bf0c0269be82349c754a6768beae711c928866371a77a34d3be2f613731984e7cfafd67ca246e2f1877865d538a6433c6b5c09a972a1ede881396ac91819ca5285305dee3141185f5d50de082cafca0cb2c585ca75550e969b5e39bcdc13dbbf5eaeb86368b9a13261de996cddd7331acab90ae58883f572bdc81dd2e64f0c3b1aa517dd4ea00dc20bd4369a0360fb0e415e601b217fc709f1851473d3f03a59a04ed3968c81bef625e43dfaeb7548df3abc8cc62d5a190d9b6e5cc6894da13206f35f8ef95fc6390adae67d55c436dafd1eea4596d2373a664b74aef1d2b1bd0dd798304e67301ea97b60aee17ee7228e3a91417f470d83be156802ffbe878e3f47dd7ca6aac90c3c33515e944c49a568838e331ee701d24eec2baac0762b7f95448fab146d3253259a896c061f7629f81abf6a2236e922cc9175e0abb9982433ca2431ca534de8d78d86b981e5bc615a39f1e037839db2de1a20437d0d18330c8c9981798cdb3b9fc8ebbba1cebb7b64a939e8abf0f7d2b20fc17a269dd619faeb3c6273b51065d219623d0ceba0037e82f5f7b8ba604d2411f457ad87a19d0e34a1aefa75ff6314b5b93847829f87e3ba9d1cbd1ffd20da1789fd0159e091575825a05f88bfc90fdb49f17dc6f9dfbbb43612da273fe5741deb2ea2b674250773a517d6698e7817e309c07c297407e50902272f16385b6b1db1de5e47fd514723f8d18dd00ed021b476f67fa9ee943898833819edc0134db79a97623d5d8cea8e833a811f5ca7b531f51b06da18da16db199eab6083e55290196c32da0eae610794e3a4beb53cc1496c39dd10de0b654a0ccae2683c88e5331e7f1ded67ca5301b437fdb01e1f297707c6803df91b9d83e2c126609b59aea1cdc2e7e18e78901de61ddf26a917e61ab5bde33fdae97c1c23807f7db66fc8f3eb8ec6c5d0a7d3a0be0d7a7d9b209c43e4322751c1aff0f87b20bc1e7e97319e36f8dd789aa0bf1fd20dd7d88a7d8df1e406e07737f13a0f7fae3a8599b219d6c2c08b965cd48e295130073606824a710ff8cc96fe578abbbebd8fa589c4d358477df7e80fb5be7f44eab07b02ddc087f51bb41deac5374ee887b536941308d27553fa76c22d2cd5e58b67b885af12796218c8770df807e07739635b798d448781decc0b39a554d264005986ca615e8c3eb4d08af2c0faec4c527730685bff3ad8c317aea96138ff8ff958f37166051de91f806d3b0e639267b472611d3fbf05d2c3b88a041de6f640b80b7e9731b6e53d302f8ae82b3ac056b472a04f07e81ef445505f0ed027ed03a05b07e853eb039aad91253b51cafc682fa11d632f737b0506fc877761fc34a3ce921cc120c87b0dfa9d08fd10fc17dcaf82f9327186a0d7e7231b9385e3e76e6f39f65f86492a0d06555718a7f5d1d23e4fa99b24e133b19ca5eb08278eb1e269aa0863cb15c6d8a426184bf374fd384f5b130298df9dda1873d9d01f45ff08fc5956dba768fada3e45bbe5681c3e6fb7905b70ae71e3dea0d3f96b8d7734de0b360aea5b7ca52e3de14a2e9fa09595f62e8cff44943924afc7153fd79a08732384659eef439e1c66e9b395baa8ad0179188c4fc7e74118431582a8f3d9d098f56d957a43bc81b8c82f967ab9a412a2d91e9ebc026b256abf4df17d43e382ff89766914fab10eb019980675268b3c5d5fbd62c231187bc4ebd2f48d32515debf95af7d3f461d41712c8c83509c5df0ded31c91219a94c6ac5b5e92858cbdd0e6bba5174ef8661983509e43bb2b47f942faab5bf3dc13e0dd6a920c3b27e7587c0525b7a5a60b5b5c636ea8fa22df5f0078912b37d60ad04fd7dc0a7e4d240667e3cfaa657d146d0b50adae2c497619df2265d43396631849b853e018c33f47d212d5d3b829c8e3a9883c6b5b24a25fa45b04eabe9266b889db5d680ad813942764ad4b6d23daacd507f58bb281b9b58b40d2877955960b03e554dd25cdf4dadbde84b40dee0e71c1da544c13c59d38af66d24eef5a8e2a95198ce1779fabac6df8ffabf7ed7f7a7b994b57f62d5a20039e67bfb9cfa9418bc6bf3ef778ef48df4cf957cab9afac79edf58ec11ff64df2ce2fef5ce9db9c5b5c42a79c92ba217bc2ca00250c02b3c50c02b1c50c02b2c50c02b0c50c02b0428606331ee19a93b9de4f473ea4e81a1ffb3a79f7bc4abee8c275a19651bfdc571d777161f33dffcc29c9dbeb57fbafa0befcd6bf75c98563add39bda5ec723b6996dcb9d803eb3affd0ec4cff434b4cd49e9c3997cbd3e79c4a5d30ad5710a65f9dd63572c536ff6488df4e2cf29e1c871bb4e58ee7941f48a47c3957d7107efa056b6537b956d467bef682b5b63b3cc134d909394fee5b3af6dcebe96d99f3b3e738a7666d2cd6c769cf3ee726654d477d609fcb2971609757056dce3afb86091b8b99348835014764dae435a4e6c1b96327378b2dd34aad510789756203f40658b92602e284706b2a500bf4b429027bcbfc923418a5e1ed1df57eb7997a567d31bdda2f89a4366bbf5c7c6a8bf62b572257532fecc964b3e7325aa9ccd8b816585f8da82aed0e7a4a8fb38b9aa7974fbe205e569da523a12e3f9c56cafc8d963e652a9325982e80ed18519206e5354f769ecfbc277b4f36bb5218a863a31f6bb8fb4aeac2972fcd1d2bb64c6ed6d654755fa67efe5cba754af703aae47c10ea95dcfd00e4fa80298799bf0d72bbbbd3b44298bf177eedee30e585cd7f077e05db9de9a92743b2a2a4ba1ecfc5b5942a8b9ac5cb6f2d987c615a79893fce09a3fd9a5aca3f50bca27a5e5f92724622d599e57f29cd6ca8e7cc3c33aa112cd58856efb6b44518b37353f386ce37d371f666e60dafc5b12267bc358e0fb726809548e449cc496b2afcb2f0a06d5ed7f63cd0f6d953c0e7810ff61e60e14d39f52823fed3a4ac6bdaa4683676ef791893091a37fdcc00f7c21ad23c3de689127f49fa1ce7c6624793c04c5cbbe7ea9f3bdebb50d65bdbf5df97cfb47cdcfc93dec7af2eef7aa263f5e597b7ccdc3cbd745af9bb7faf5e75ecef0e58b538ee08d756ba51d268e796924530ab46326925f732f72aa61153265efc51d9eb693f81fe5811ae48c214413812be7eee92ad4ac18f991f6d3565c6e48dcf50faeb26cf9b77b05af9b8d4faa933aeac9d644c88c9dce35ce4ac75c734b747d8272ae38488239b5fb20b698a3b9ce093f68866f38656475238535b651b516587b9cb6e4d7e89bcdbb5ab863e27a7b2fb964e7df7bbaf397e1f461c07cac9b1b0be0f6bcb94822af271596ae6c8a74be296942d726e742b0fd584633efb5e2adf8ae3c09abc8f3c73ad24bd2d7f7e616da1f84cdbcaf94fd43e213e79fe67f73cbbe75976c3f955739c61d04649234871c9a29279f2bd238e3ee6c552b8b7b19479f36a5dbeb051fd1ce8c694a93e2559944de26865e52f4cf07bc13b27f88c917947f86a76d47355a3c03eba6e269fb98f1cdfce29dd5d44987a84df0bf3a6645ff8f75a5a0bfbe409ad5a1f415dab7e89b7467591bea5cf79b17cf5de4b41e607f2bd5f0547dd577edf23de9179abcba6819dc85c8fa5efc9958b025e39573259a35a48cc65fed417ee23a507e6c634cf3bfe99ebb352a5a08f7ce63265ce293be39c03a99a373c3c6f4feecdbb1f3e1e95f97bd03cd5ee4bb651bf18d0ee8e8ed683716554ae9fef733dd63d328fb6c4582a5b201040d9caeb63f214f062a15d8bfec92a05bf209f95c64109907fd1a3f3525c6e7b4ce6c3c7b165d3ae682d95f1b3473e1ae5fdd8a5f87ec97ce63ad2d8c42643fb60eb1c296b6259f7be52dfbd353d8cd77104747ca49c3069c7c2167baac2a349ce11e5de4f08b6e64f685b42cc1fd47cf2d1db8f977d8ae5e53f3aef7ce911976beea3c76332cf4389eb8f3cb6764f735cef031d4b2e97b52cba7a7f17acb91e60e6098bfa7eb4ebc264676da6987dbef09e67f63cc3fef4fc1359d0cadcefa087bf5e4afaee503e0823a59917eb1d4bc318e5d9ebc461be8d51362d65168165deb8634fcec2adcc14392c6cc447f58365fce8c24f5ab472a66d7e63b35ed6bd7d3f2ebf6c2ceb9e27f73c79a3f23ed2cafbd9575a79ae22e6cfce079c1b5f0a95760e4a8beb5d74b5ac654ff3fd5da1321f6f564bd73330f7b2d3ca957e77063866c5c72aa90fdee226ca970758ddeea47d5d0a360fe500ed65aa527eac72d1cdab4d89a4243eda6526d16633712fc75dbcda31a3a5d96e92ab8a525089fc809035e5f18ae41263b2a3f2c6afe8acdae3aefc62fca5ca5c7c8755e9c756268f82cfc3ccad979bb6e3aa8063feb22d5df1fb4d6a5336787c2e2e94ff68492ba12c8ce62f48c10d694ad8011295bdb6ca26baed4a4643785f9233debd126295df267107c2582dc572e9905309ff607454f686343deee206934782f25ac613bec59d033edc816e91d2b7baf9ededdb2fa9cb23c976ff647784efcdfa77d39556f0b625afb0a35e95ec024847d4a6e3b806149ff3026782c6e9024e915452af8af6c5a063c9e76beb529ba63055ae46e9bbf5e3f39405228959b1bdbdfa338fd442badf9e5d5ae2356399b34ff7533ae7742fc699ec8ec955fd6612e36f38a88a1db1cab9b6c8510e263e7a49bcdd39dfb3f30411e2b943e5ba56de7dfe7eb719ea69b59db93a5e9141ef1197c75f0067f58be8a678bbf07d9bec231cb8f6cae3b9a2e7a95cb2abadb34ae4f0d7b6f8d64f37dc3fa8dfb9e6fbdd776e9ae3e41237314a143f5198aa3e358bcc35b55e577b9288522dc6603e6afa95e0b517ccb9f4bd478703e41039a5653951267231dc9130f022b710f9a7c7834aee4bc423bd64df90aedc1bb855f3661a9f2e56b45ff1f9db950d4be3b6cfd9aaec6e8b82f98fd5c67c7351dfd27d9b15a1dbe291ee6594c26ea2c4a6c4ba9fc41dca279fe2ea46905b7663ab5a7fd556a8542e35ab3bd33965bb18e9f086310f6c97b3c793623fca06ebf0b50e881da5e02a994a6b0be46b4f72d700b7307013e5260656afdd272f71936df395f3277875492eac65cbb8e832583f464692d1e2fd3b65410c463cae4c6c1085f4aa3371764f6413d5e847cfd31c929a9a4d97232e908be48b670ebe3b5f693d41aac443c206ec07d0574e10754923e4d926aef7026782c60900e7296965bd2c405f11a1afac68b8aa2e8967aaca4e483ff4463ca1880d64fcf2ce977c4f36f59b56a779c76747e475bee4d9b4d3aefc781217b562b0f746b4477da6d7ef634a53021fcafe28b2b57deba54aff9e9dd6fd914cd6ef94bf98c89e9dd5cbb15f55b7c5aca8688ff96ce19b334b6f791b476a94d297e41bddd43ceaed6df122670b2c2739675b3dfb5cffac77e6f64973b6f7156dd8ea3cc8cd1e49fa962891674cd886d6faa50faaddd74979c3b1748fd36b7fe32567ee1f762cd9de67deb0d556eab4ebedf9a3bea5caf86eb2c4c9ccc3f6b0098be7bebc7bda762ae9b4c0c3d86234b7c34bff663db099f8d89456e83179e99c33dd7a00ac29b46b65eeda2a8f04a336c74de0d9bc008f391747bdfe078febbafd77bb695e53020f3d57ef4882bec76fee9f5be9dc72ec056be25764ef7c8fb40546f2f64bbef5ae4f5561044367965b3b8f807d6064ff78821a896ad9a34934cb7dbcbae5d78770a7d777c9fb0658a771b8d33bf10fe8d34fdba98c6f20e8953ad26195ff9cb75f10fabc9ec6bde4175b6c520329f1ff225d696f24fb5ccaca565807384e08c4293985575e68eaf77de6ef879541d17af2f6a57d2ef52957502e137b95de46d1e11188e3b74ee2a81718aedec938fe20b0dc1f9c2ce71138c7612707ab601e7d64eeb033687dabe8ba75ffd25eeb81409ff5b0bfcffa56539f757f63d07a20b7df7ad80ccfa5e07aefd072d59e22d27a7d6e3db66545d6cbd2cb82f5adc67edf2590c8efefd9588c722b6d7b5166d5cfc24ac8d5406e7edef74c77bfa7ac916c83b5519fd97142221bcc56d244babd4ec171a23be89430ef6b5ef42771dd5276797a696dcb9f9befef7de0ea92ae1f75fce4f26f9d6197e767b765d6668b2bcf3f73cf4ff7fc94fdd9f927a766c1fa62e7becd335bda3b7ede0b6b96d9a5419c8dd472989546f041f9da89a0723d0937e58ae5afc2827466eacae56056aab94e9845b86679c069cc736331bec5f0ad3ed2ab3cb4d2a68df1f8ba88273daeef40df514c3d445eef0fced961ca11ca175e84be14769128937a585918c12a7f7addf47195a77ce55cda0b0f16ed552f4e84d92005fcd7d2e012e7e4cdeab589c4737125634d4d0ce24ae060bdf2ce4aa1724df59395ed319738ef16e2295b3977c37c618bc795c228ebcf4cf3acbc4473f0389f64d43698475a2b738f094b9cda9cd74ef26134c04ae2b2bc7904739797492f49776e56dc628c239187354e959dfb7d2958d03f0717bda43c2f8df384a58335ee09572590f6c4b571952baaf364b13c286fe69998f6ca4bb254cc2b4aa34915f3d9f75c4adf091293597d2126bbfa32ccd39c72ae919f0bfd8767a3322b7d51d995fea81595973cae6c06ebacdb8bed5a9d9398ea6ce716cfc55cc67a20914119979d7fe660cc8aea8e98bcea2e456a2368a7212f6e717d4c3efce6aaaf7249d0822e9eafec4df3ee010f04d62ffff88157f9e3ca30d41095d3c933a829941be55551de2f1a7959ca67950d8d04e4ba00725d9651da558d642e0f29d898cc987331d931ad312b622ed66e59f93648dd1195570952f45029200ed7895238795e93c4019254f79e032960fdf35ea757b9ff09a93aaf72454886ffb5b2df2b5fe8fd9f951dfb974e2feaee7b17a66df68d163ec367b22404af557dea562afdc4718733a85e7b27f8e75def7a50362a534ba3a8cbc44765469d8bca8e6aa5326535b2b2043eb42430e395edbef1b9dbfd514f565edae35c82b6f5c76f825ea22e46e5457d4e6593a0752481fd086593782ea6737c2184b9f1ddef7af7b926bb36d453f98ebde3fd73f9cb1ecfc58bb497867cb1831e5cd5e30e04ae05adaf495bc596f6840416ecf7c46ea2af9fb7547f7fdb9f628e8656bd98627aa963c75406e2920e5e5928904757ec733f3ab086c715c086a20db803016b80cfbdd47ac25af299b5933be22e2fba707f8bd8a506a4887da5d34b67961f2adfd588b995cf67e683edcd1b9eda31610ac316eec9ffefb245657b56deb332ce793e3b2d0b56affc70398a57f42dc5758e12dd4dfab4dd0f481d92c899fb110d2fb8d0e7c5146b48cdd850cd7feb9c5d46edc0ebd2b3587bcbcff4da539fc5ffb3e1b58715bfc63f1fd7b2af749382fb12d34bc31a5217eef2b53707afe1da5e354bdc3155ed7191d7bf507b24a6fc8bbde9d54761edc5e3da6bc3626d758f6bfb6d5b7634de9eb7ed1d559a2729ce6e12072d7cf42e5cc7a316607d4fd480b70f258fc98335185df5b988162e6fc7b02c110be8f256dc0fdee3c4f43559941f3013a13126c31ac7d3fdf2980f62f298b48fae38ccf84c32cd3a1b5a3f3aebcbb730e9db7c51190f1fefac1fe80fa8911a290f35d27cff508d343e61d4887879f285b89645cde517998558b745ced0de05b6704837775fc0b2af9dd5a51453574c83961ff9741caebb1f14c88647b495a3642a6f1c9987712cdf35ea86dc8ebab9fdd96d0df4f97770a7a3bdf96ca7358a27edcd3fef5ce8d56494ded1f6b57ede833b64d8ef64b7c4cd55e32e8b5dd8ff602e26289b52214608b9b224157ff442651aee9c293f6826871f511635c39cbf279f2d3c9f7dcfca3d2bd3a02ec9d91b9ab8d7a145762671d61a9e8c7c5af9503465ac40a9b76dd9d51833efe6e753f376fd29f561a0d9239f2e998f35eb5bea5802bdf2e66e526d5f9fae3c1e302549768b20d9960688b065d65ffa8a5457e0e75179dd2f54b92506773da39ab155b0ed657712a73c2c11cd9baab66ff32db8707b9eb5660a73f0dda15aa9b909b55252cfcc7742992c9439adcc37a1bba7da7ef07d28d3e9278fa42bdbfd3ca6fcae57f58bb4dd372c16bc8edf3919dfd6b00eee770219b5c5ba7f16931276c7dc92f4b1beea1f3e7adcb7ccd28eebe93f97dd5f465b29bd6660e76143fdbe5d2961afdb3beb99b13806a6954e84762ef74f6f696fdefd8eb633b9ab71b2f39eecf399027a007eec194c1aed154ee673bd9dde08ed3d09bd6b3ad63ca7af137e4df724afdfb176f2d5b8ae451df75f9ede22f64e2b773f82abbc776e6def680fa08fb827a734d7992b9706fa3a2b476d8ddb3ea378c3f899bcf25817c13db5bf773369e7f3ef29dc53c83e737ee52d506e89b6d7f626a6ad75fb2675f77a84623bf2cefe06741cddcd6a31826f7010a30fbcc856bbef1f3dd7b515e5fc57b73faeadd0263c4757237b6b7f95558f79956c45afbcd4af499ffecbeaef2f72a694baec740ced71ed6bef18f3b990b6a35e291626a1b6e25aa695be512a5e6eef5873c97110e6d2323ea8bf97895603ad415b590f895ace250b8cb37c6d9532f124ff7b77f945cecb07773d5ff1c4efdd95aba3be88b824832c956df8fed19ad814a5af7f5e8255ce677e7da4c6bfbc55990cf5a9bfa4b503da9c351dffd112d5c62cd871ce71900fba1f86789b5e1bffdcf36fb8b73ea16c9e10e6385cc658df9ac0580f1f261ea18d6ccd7196ef68fdbd3bea09e56693e85e4cf709c72a66af685e42d79fe3284d391351f945e567c2024d2a9bab87c4f87c134c576509d6b2d9015e6e4a22fa6a36dde36e241139efbe4053ceec195925994995db4c9e97f6b92b15b94c0a56405e30f3b5bfec1516fcba3e6235ae771ef3ca67dc646c3acc8f905b2ebe51e4a245b3be629bb653d5566c950da2333d7a69bcdde6f693989cc75e70a386eafdfcd62f2a3edb7e71fc17a7dffe61ba92d308e90f09c7bc32aeed731b89dc841cbfb8013913340ebeb52c92d6d6abb05e93716d7fb1e1aadc14cf444b8dd223b85e2b6b80765a5be5bbe4ef1f09eb356d6e1c36a7fc468a440b4aa4a116b42e72b8059db536aef50d3a934dbe287e3eb354f90456074d60ff6b4482f67007f830c43eeab504d36cdcf71fbb67b96faed0ff65fa5db942ceb517c27277bda07a6185f7478c15d30cbda8f8b61af8cdc73433699f652ecade973d2a6b700616bb700e2edf32bdb4fcefaa5428c534c75c76a6c79c0a593bb4750f9104b08fe0aff6ecc999560e36a679f7c7cce7fadc6179e6abce2afaae19ad48bddb8f6f0e1b37bc75196d8309d6c5601f4c74f6cd8d39f562fab6bfe31c4e673613f30ec6c1d4669a1a43f816d61a358599ebfd9af66a241eb46749786ad8fcc37edd1fd152d134b512c134a7560e4de30ade380d4df16ba91753743c3134456eeff014f82e4bf9ac8e95274c25b052613dae3a7c97a99d8b2a321365b4a48723083d935de3d7de73091dc1d019c381f384fab9808229f6ce82dbec09e00d9aae78b5779ce0d9b336a985c55e0bf6f149b55422367c1739dbc5289b45c2cd92e879447fb148f0dcde95223ec11b4fdf936eba52272514442cc4fc588fd4c5e2190b5856314a84c43bbc2ea26c95d8a474c2cae313898d6f215c124fcf2c5813befe0e5e760a03efe0a12f51f906de07eaef12e9f9cc5281603dae14cdd3e4c7b3181dcb3ed7e57f4c1e3f8fe07b583c37ab94818e6695d2b36046b9f18cfac0d90d274f86be93c4736ef4ec6fe258be9d54dc238b84d7ceb63230ebffc7313c8b67b6e1b7265ca76c2211f2d2257635328ea813e2417686f788ef138fd38be76a88e335a1575edfc3549d71316a4f2439b2b39678da22c18f02bfaae674af6c8ec7ef1e789bab8d38e2a4deaa263743cf1cb8ebe89908ab25d01b2d4612df24f11ae44dbf5f4912be93218bc504cf6aab91f1c4239e86bc0e8d8630581033ce09181ee98b68c47390fcb0b3745207abb4d545e1d9737a3e22cf1b89ef6ed5d3ad8c1beaa43afee4f3383c903747b0ef459f7112f9a91e5235ae8c7027385275a681603d6ccb9710ef973012377e19acda7982d89e5a02bc33a4eaec69e26d037e3016e6b09e60f4d956e2790af8bbcf125b5b0fa33e154ba277b711ef098883cf9bbae9f3a4b26050167b829eb63606fb77b439403c3d2740576da4ea53814992e079cf2482df2c447f3a81898e14195ba08d789683e52c9a0456d90c71fae9370d554db3e833af78959681df43a04eabdc498cada8899e77887e3f8df1e239efa764d017a4f9703153b5733ee3290a101be85d0d4491aa9d4b214e73109f233ffac31c06dbc42b1e0dca45515afdccb9f44c0f3d2b717a3dc8504c6550bb27104f00783b90f79d0c8fdf4b6c421db467b7f6fd91fe5e5a7f0f1da4edd252173e709607c7ee90335bd684b9f47b013ccba3b71b0fe34ec2ef97948ddd3c9edf4a0aff4e861a46b86801cf984c251ee93a3d53a0060263944a188fe20ea20ac512f81f67a3c326125fcc1d7d2a8c1f7ad6a263f7a728d78dcec670773254dec1f1d931f05efd4abcbd537649bc572423657311c17e6cb5405c58cc79cada48128c393cbb619d2c818f29d1b3ac491219a90a11bcbc338ed8c446882f92aa32e8e39587fad59d8d34be57b440bf8674382789e41e8fab89752f41bfe8c454f88deff1793cc3603d2041da1e682389f1558afd984e953244ccc311974ecf0c29802a68435fa5d43ff48c47e83b00b0b5b03aaee3b12ed14b170f9c6153c1a878a40051ddf1588f9168bbd0e6e279bb941db5c4965347f02c8eb5a66ee09b8290fda57936a3fd1658b0df23e5c5ad8ccd89ed7ff06b71a90ecd022b0b161ee2d0b2757b66b609ad300ed3084d9b70107caf8681f4f87d8dec4ee79487a4d1d036bd6023f1ec05f49d6d60f76fe1aca93318ccfb0ad87cda3edb41b7a565a07f0be8b88538a6a413ee36d05f29f4819d3c2b2f1141de3868b75ae2a815e95925d49fd58267f68a4d0549e9090574ceb0f0a00b563b8bd6087a81f1e54ea7bac26d35251cecee41173d6fee27129d37bc58260feb8cc9dbbf3e87542c4cb05aa630d0f7f07b2e0efa1e0b7d8f85be179a1778aa2fa7a0b7573303ba1d8fba3527513ff463aa5fd0153d638663cfe5a7e7dd92a479198e78895303fea0a7d54bacb77aa98dd7f8e983fc69c3f9553b26d0b390784664903715d7c7c08bed1be4cd025e119e01fb6a909786630ebf29b93ec85b8cbc3ec8efda202f07795fe1b9f241de7ae40520bf9e419e1379ed905ff7206f07f2ce427e5d83bcbdc8ab87fcae7845e0d5cde79202c160d58e8368377f8ef688d675df21edaca21ea76a4703c178b27696ad6f907f9a2481b785e7240779ad24a91179cb86c4eb26492ee4c5f60ef2349b0df95d1fe44da0361af2bb36c89b0abc5eccefea206f16f0ae627e81415e1af0d0569eed1ee42d065e333d273cc8cb01de51ccefca204fb3cb90df97833c27f008e6d731c8db813c6cb7f641de5ee4c16a71d91743f482bc66c8eff3217a41de51c8ef12f2e077b1ae1b464e47bd2ebba0e2ee1bd899c17edb78e89bfaad962f8e55d24fe734906da0fd5e3d346003b478276e1caff6109e71d5db49646e18e7358cb34cefbb2e76603c4cf1e219ab6b21fed7c703f28ce30179c6f1803ce378409e713c340e961d8765c77e19e27fbdecc61b94dd7883b21b6f5036f206c68ede0f4fb0a1f6a363801433213eb663a80d87e815e5bb3098df405dba0679a1311b7b6590171a9f673b691f8131a795ad8d4f3c4b36288f362607c700f242e3313406a8dcfa780c8d01e485c663680c202f341e43630079a1f1181a03c80b8dc7d018405e68ec85c600f242632f340690171a7bda18d078a1b1b7fbb341dec098ba38c81b18f31706790363b46d903730465b077907917715f26b19a2abd018f50dea3f646fcf7e34c80bd9dbdd1f7a81c7ed4d27fa1a2048bffb4ac0b38cda3946f0912a71bd017314fa49daf77e7826b223d6ad4a15ac72a1ce143a43192d4d059f2e9f512ef8595ccb79dc7e68a778686777bf0dfa119e4b4e4aff90d0df31e06b0472895221f1da373ebbdf367e2b3b303e713f764a80c5713dc893f05bbafe216196ae9d74ff02cf2cd3efaca41a9837fd9afd89a7f6e7e9a1f667b8ed1159b57b3d8976c398ea2eeaf5b4b6e29a821d6e77427140afdd015f68ee401e3e8b76ef20de6ef0f39dddb19e6e2f19621338b507fce06e09c63bac5d6ec7f1be5beffb659cdadd0d79a6619e1db4dc5fe178db7d55cbbb9b609c68b73394f7182def909d0ba56f20de09f439f6a97ee4e1f368b7c0601cafd039d49ea03c63409e0e2acf742a4fa75ede18e84f5a79c2607954ae37a81d68c738a1bcbd0283639ad3ca0db5512357b5d309cf08837c5d5eddee419b0f2ddbe2e5414f1707cb16f91b965d7308e22df37fbd6c910f95adeb83c738a1e7a1f2691eaf621ea1f1e1e28d325279a650799af57a0c97350e9fc59e1da2a71bcb5a8be5ecfee4067ae20d7afa9a0c43f4240c2bfb562c7b59d3103d09372cfb352cfbec0737d09330bcec745edd297034fd19911ba8ff645aff53a138553b0546dd01fee46981c37e15d21daca139fcc603f9743dd88ab22fbb4cedc2f9bad983632e7dc1d03117b217686742e32f645fa86d21e43edce331f09261ad40e898e7b17c9ea5dfe86c94e89a06bf2d6827c50b908fe5ca8b0556fb8e2709d61466625bdc4dd72df45e05c837646364a1986def88ed463be8a883311a08e0596a51e3efbe12e25735a563ddfaf5f85f0ef2a91dead5e3770cf21ba98fa1c76fd7f812c89484f335ac03cc246571378ea58016e7ece5c138b944b365c85f766990efc63c7be99d0384c40f96e5c23ed385fa011d4cd5f8d0b66e68b32689c3b95d7b76d41a7a8672a30cb8270c6903faf35bf43cb19ff56a738324e0f747d1c20452659e40921ab632a0c7d770de0f3d8f5eeca4f242d9095afa46d4e3189cdbdb89fd7b219e2e673fc83e7d9087fa5b06698fdeaef370dc60f83b8361ccfbe8b45018f26142e56b7ad1f63a944df8dd8144edf51a7294ca2a83aca1b2f07b7790270efb01f6a3c1f44dff427a09e5f8124f887e3dbdff5f4c1fdb01e9277d3d7de05f4cbfec73487f53287d685e0ac583e7efa9f8ddca796d0dae8d3d29fa46f35d282df4f509d89f607cb1daf8da1dc47e07f9ff29946fc837088d59ba4f6bea36294460f1db0145ec0ea7fb3b927edf8c263f47e5ae75d13b39a04f11b5a787442f4d27725180c36f8a657c27d15487be08ad038e532cef4169c27befbbc4f71e2c0adcf4be24211df7be4b7aef7d083fb8c3fcc71b8d63adac467ae707b4f50dcba27eb7663b18594aa07242f90cda08df26ff7533fd9eced547d7f40d12eeb15e72c4f10c07f1314d284f9499e60b72a32ca1fc517eec97b4fee02316c4db3be9f782e324116da6d582f716d410657c37fad8c960df21af009ee41de37b49eac7b01a903a546d0f947c5b1cfa0d9d65700f06e2da713f0ee70ef41b42edd5de31e6bcb791c17d070bda1b2fe489df2da2ddc67dc161dfe5e5409ebfaad3ee50413fec06f7a83886dca3e2e9c17b549a08ea1df71eff57ee5109d977ac03dde710b4fe237322c925dcb0effc549e059f9425b6d2527b688f10bff1c3ef7fd472fc469125e042e1d71445b897d87e2a58258b105fdc69c77c6d8293b41fddfd8132294c7427d1f71cadda9a34bdd53d9fbe7f6c86f1c0e037955c5c6390ee29bfd1d8efbbd0d4ef4ea7ef1d3fd5fa48fa5af071f9f6e6b35bc1e65f741f5c86df54659bf1bb1e41c8c779a33da2785a7bf3eeb7c16402afc1d61e614f688f389a643e817bbe275e549d61f49b35fc2e019e7d4f2b4ba26b36facd79f22d1c7e738ef5c3ba99a7d2efb2ceb9a7d2fa9da5df9ee377e9f8fdb9fe5dbaf6dda308763cc32c9785d1ef8ab5740d9fb6938848f76df86e37ac5d0e8b20ee69f07bf3a2b3727804cb1d2ea5e7011d87c0cf3f04724961a44a8036768693e8b0db30bf71908e554b79c677d3c23ef36d78875479b8ca4710f334bc476ad1a76a5804eb48867c66435bb878f27e20f9d48381d9a7aa9c5d4118bbf7c84238a92a9d42e2133a098ce97bb8e430869b1d461e7449e7e5b03056e679a69d9c1ae1fbaf4498332b1e84df7365f32ce28ea77aff84ee437a24da271c754eb4952ce707bf04d7194bba59a5ab8de5bc4e463555e077bbac037edba480ddbabf95eefbf86e127a91e21e1eae9f310dd72630d19b44625bdfcd7a9a1a5959249cf28989e14e629fca17e4a717108537e16f0ec7f791b213e495314df83de0f5ff4fc950a7c970e47f20c31129406548791864a8159814285f154de4c8ff5006adaf66315c8a48fba1237e3ee1a695c15a7004ce157c4af867f69452bf9d4b3f41427725d0bb14f01e05ecc3896b99501fc7feebb8b38c51788944f35d4147234fbf9d55364bd0e6f41c0ea3ecf49ba2f996a0f2909d49e1e7cd757879523502e3b951172647c371a29409746cf98bc3c8401e5b4117a13c5ef49bc01e70c3e208c5821a4827ca7689be2f083d53e6d9257c1e1dce6b73f47f49a26dcb13e08f1687c95231f155fb7b5056f4e3204f3694ae6acb5741df827c58837605f1fe06e5219ebe0349e103787f50374dfba2ff3aca81f3d25079a2c3af07e9f7f9069e6f81fd1bf2431f529777d3138cbaf926e26880f83b857ed40f9615cdeb3a2af6f3ffd25d14a1776743ea84f5f42d28c676efc57d69907197660f1bcb54b12348e72afc4eb85aea575d22f94d7c602486c7908e31be17a57efabdf72181fa09325741645306514d35441e5d43609eec53fb0363e8f7d7ebdee7aaa4ee6bf41dcef2ab6c95b4e3baf2e15562dd8f6bc5363a4fa4485fb0a1bb4d5260be469920cd57749eccbb0abf77f452bf9c617aacc925266be236933581de17275993e74ad6c41f4ad6d4b1c0cb92709f03dfb15a138f814d041b1ac6b06ad829560e279c03bf318579dd9a780e740ab2ed14f0fbe530d05f18e80fef583381fe24d09f04fa13417f229419aeedd967b0caa66efaeda9bf98a7eb01477a09679dceb05696e1611e0f5a4776d2ef32ad964eedfbe154e08b09ecd072d11751c609220769f15415bedba173e9c873ac2cd5b0caa4565176c5eb71cd3056c289bc6533ace93b59e513585b413a3c9f866139d745301d9e0e56c2bb45357c04de251684796f84327216a3b0699c2fe6f4559413cf1fa01faafdc6749db847d0a385d1d7890dd276039dcb12b4e79670e2cb0e5c97c5638c4aefb35876ce117f8cc172697993babf562f2affb856d330f9e34710357c0b513e904848375c3cc32b0b244d96805fd75b8d248be05fc5748b98af5a86f9be4bf3457ba88a15a2c29e0e572ed48e56c56241e14f8f53ced79a7c4468c1b651850cd6c776b7413f3937b41e4a66801dac43ec695a07900175856b25ab85e1e9fb4bf1a8886390ea6b3694ef8a24f88d34d720d2f27d110d5755579cce8b24fa77b63dd0bea2127e3a5215eda22fe2f4c7aa5843ac53dee595259276ff97e51c4fefb18236047b37923b184e9487712feb146b136aec561664114a38f0335e9045d0077e03ad9d09a883f61a07f94b8a08756da9c5be053ae81e0d724abe9bbadf0bb5aba63ff4fbed8c2a6648cac8d360ff8b255fd4e953e0c333280ff5b3e797800d725e97674d009ffa5010df8fdb5a6b21fdcb2cf68d6f95bdda4fe544f9415fddf47be417fdec37d7e7ec66dc3be6f60e3e4f19f63c761b3cefc47c30ac6cd7f2c2751dde0d669dd249e5a0df44437ba10cb4fcbdb4fc5e474338d513f2713c6aed19fb4787379cdee744c74c3294056b1825bc89702724fa8e16fd7a254a1ce88bd08617b8d92502de85604d3d867d01cf6c5cd5de3f0e791f99aaf9a7d6c437616c1f035fed5df0d9ce89d01f446b3283f647ba32c5de694ec43bd64a6742fbfdd2113f0fda5c0ac73aa06f6a9d1648405fd5fa9a3b01ed28fdfd86345df75fefe00ee2bbd9121eefabd14ef935d4e21880beb11ff3069dd572f1a5a0f796d19877b42b1074cfc63cdaa629f735d33ad1726e0d4ca379ef91a66139a1f79294572bdd3aecfda4b6476ba2dfb263de2fb5d0fd0c9acfe4401cbeb31b90f535690adee1806587e6064daeddd5b4aedb25fa5ec81a9764a5748a7b32a6d5ea2e597cdb25b0e3bb3b6839d543ca991e9884630f75af9d2738db3b443f31aae99430f41ed4028271777f39f81e5abf0f2fb9cca4f998d2587aa754d1d531f45e8246899ebdc1fb9c64c8548bd338899ee549dc46b82451c239c371186cd2ec32b03f65926356a9c0cd16456e162fe0d91d7fb109cf98413eaff2b8dec47526aeb1a1df02b50fdc0d60137618cfe25cc7bb97e83d4b3006b53584f3167a0753b27e372adecb940c7e3fdee3940af316f8fd328f6bd6dd4dd03719eafbd374422cf4ab339aefffce21eafbdf84beffe6d87fc9f7efd8fdded77dff85ef51dfff26f4fd374ffa7fc4f7ef88fd2bfafedf767f54e8bea8c13b1b047a37e895a964bf390edb79fe257d9d7409f26bc43d017c9765adf19bb0bddb3b5e787e0dd1d2e3fd67aa083a2bd375acad936ab43573ec05ba0681b5f437c775eed2e22e6bd5e29eedf9967cf5b8bbcf6b7163bbbe39aea06a71cf9ed5e22eeb749c15e8fd576af06eb00d411eef7fa8fab491447f5844aadef393e84f0324fa2cacb50373702f455247837d7cfa2a53b511d6cbffd9cf447363c891fffa8228cf0738bc274a1d43ef8560bf45de6dbabc4dbabc17f1fedfe865f576451c43e4822b77cbdfbf1254cd738847eaa1f7e2a17e6ddc15ea93daa457c0e7001f3e6a16bd77d38677d6f8fdf4de3bdf3d4d41b97b1c912b93d1a7e19517c7d0f942d9f8054bef5c29450af2edfc8254b95d4c55936baecd24e2fe2f1b3abd4dfd0e9744f7127d1bc7f4db36898c35e12a919d6903efb1be562f3a16d27eaeb7ef9ff5f6fd87a309fd516d6c2aff05bef16b02499a84771f8fee8f6e5a00e53d4d6cfff905ea15ead0c8447f7a92c84f0718b9e83f214e04897eff2a499904cfaf5e95201f1674c3501ff6f90bac3a3a5fabcbe60fb96f964978566fefa37a7bbf47fde3d35ed035de1d14b81bbfd652a36cc4638a64b8832682e722e509a03f93c4da9cb5849badf9d4559149b00e3d43acc54dfa993833f1457ed11fd28b4da825fa5cf54dfa59adebe7b0ae9f77868e35d5058035e2955b61bc69fde4b06c827c9c26a28f3f0ff54970ac359f6dc2b10675e0dd75cbf07ce803caf53a76e04edf81312bea7909bf061d6cd1de01da83a13d216acf7f5f779cde9d3b8beeaffc28f47e8fee435ea8e307ee7a049b6b2b6d80320f80bf857ea1307857a5200ede89e89c407d7d7ad74af3b2bf81bd2478df0abd0f5528be8e719470c1a4cdb1d25b78be07cbf0361232f45ca60df709a7b860ddd3a8dd9d3a9e6755b7c4ca0ff1b0664a20b616179e9d6cf706aeb3d0274c479676b3496963b00e53502e8c8b77d4799676b1741e68aa633d813ad6babf45bb6bf340d7f079419fb3607dab8d5d3c2724168b38c7d176db7fb656d35ff1f521ef37687de85e8a763f48fad0bd149a8f50a3a56f1ef30ad8cb0c47924ba0a78753033c5df356483ca82083f3ba38393710617d0bef31c3fdbcc620de2b86bf7d93a47e78ced0f28b605df3967f605f0ff3c3bb64f6394be633f399b4352473d4dcb12569da5d2778cb8aa6e9dc573629a9abb6fd69a31bef53b1dcf2cc5a6dd6cdfde5e40ef3147a0fed3e5ba9cb1efabe695469c9bc39e5e71e516eda4ef0fba5d07724e0974ef4b8123927ff67b7c3eb0a6e745fabd7be09d072c9ae7503554b5bf6966cc5fb449e2b65162ae65dacf6b4f455ed29ff6ac9d676d23c9e3ebd7917197a5f484ca610760bbfd17dd11bfa75ad5eab43bcbb5299e6801ac796fb5549b2800e2755a66f58b061b132ef02af8473ac1c9544e6545a934f46385e936608f35322db88e7c249f094cc33acc91f5acae72be6f7f1aedf198b9fb7ee6b4cc01be6c2a4d1d2f6c6dfbbb7faf03bafc7d6eafaaab8bfcbf13b8968b710e08d047833c14f5af66d9ebe59b8973b501ecb9ce4e7f525cabb12c9e45dca3f7972e33b1094b07068a3b05b14673ad3979835f1a3fa98798ed9614c5f92b2d3cdf2c7bbcf70f1fc8c94c82ae2f84e2959fb02131fd6be7167d43c87b73cd67773d1359fd8d5bbb0de9a1c463eaa079f6e866356d8d8ce174ae24bfc4b9c1b779eab9f0effbf53aff55d8476434c491a331ffa437a49ba6aaae0d03f9b568a5e7f0a5f6c87d6b790631b1e8a066f3d743a7c68fc5302c6571e158876ca5c6cd1521d8d21c7981aa6064ffb8b9fbf513af9e266e7602a22184b393a114b89736ec6affec663698367f927aebd9d94f5b677fcfcabbea58ad84d66a6452f3e6d17cadbf2f13612bd0e7acecd5f977f3ce63cd939781a7e68fc8eafc71f3b3c3edecfa3f7c367ab33b197e29d37cfb53369213da8a6cc517a2e3fc1bbfbc828cc0972593cec7e1e1841d63fd43db52913d32dda11926020ed8004240c25a8cedcb078ce2e5fec94aff0ed917586ab708e33ad7eb8f48437a6b50bc3a5afceb2467493ea1ceb58f87fe1a3c73e5968c5afab7e609dd04d3ef98135127eafb59ae1ff67622ebe95957ab1fab1d4d6b772623e7f6b554cf75beb63fa34b9c1df7e7c93b2b198ff5530781fa018d00178f8d7c1e001c0b3fb83c152c0ab80470109bf0d066f053a376f65eeea9c6c4bceba756bd6dd124e7e3c2fed9ec5e98f5956aeb6cccfcb2a5861f9c19aec1ca841884f99c8bb13a2ac2cb4accf5a5708bf0a73d6adcf2fbc71bcbc356bf2e1490561002c808b2584bf7b3f11002240029800618070c008c04888330a301a300610412ab8b140c7417a19e878a0130091f0db0c888aad2013013701a20131809b019300b1000be016c06480153005301510078807dc0ab80d300df01dc0ed80ef02a603be074800cc00cc04d80089805980d980244032e00ec09d8014402ae02ec01cc0dd003bc83a17e4bc07e8f781ce039a06743ed4351db000b010b008702fe03ec00f00f7439cff0064007e087800f4f020d087e0d962c863096029841f063c02f811847f0c7814f018e027c05b06c80464011e0728806c400e3c5f0ec805ac00ac04de1380270179805580d58035807c78be16b00e50002804de7ac0538022c0d3d0c2cf007e0af819e059c006c07f46ec223f0714034a001b010e4029a47102ca002ec86f13a01cb019b005b015f01ce079c00b00fcb70df062c22ea202b6c3ef1d809d0037a012b00bf27a095005a806fc02f05f80dd801ac0cb803d10ef15c0ab80bd805a401df05f03bc0ed807f825e057805f03de00fc06b01fe2bd09f82dc00338003808fc43002fe030e07780df038e00de02bc0df803a01e7014700cf047c09f00c7010d80138046c049c03b803f03fe02f82be06f80ff06fc1d700af02ee03dc0fb800f00a74186338026c087808f40431fc7ee22ff80df9f00fe09f814dae02cd066887f0e701ee003b4005a016d003fe002e022e033c025c065c0e7802f00ed800e4027e04bc0154017a01bd0030800ae02ae01ae03be02f402fa00fd80208060d7d5fe1ed4c8940c3dfc10fef7f47bc16005e035c05b80538016c055c0c8f783410b2011b000f028201fb01df02bc051c007800b805e40c407c1e0144032e03e4026a010b009500dd80f380ef81070197000f009809c867480544006201bf034602ba0067018f0574033a00bf0f01948f36130381e9007bf4d8062c076c0af0047011f002e007a01114d903fa01a900cb80f90092804ec071c076c027c08b80c88813489800ac8ff00e0af80cb00d34760bb010b00d98067019580a3804f005701e33f867a008aff01361ff016e0610c035e051c055c00f0c0b7005201d97adc038093805380984f4006c0b3801ac061c07d9f68cf4e01cdd67fe3f315ff040aa8007c08b8003c1ee814c0ab800380e3ffd4e23e3b244fa4519f827c804a4032c479f89f83cf6bf43242145101f10a014f038a019b00d88fd6af5e91b53a3b0f66343a29e9b312d8bc35eb722cd9eb57e5df69995a104ec8f7b3d617e458129e9e9a306376ded3b75bd232be3f1082c7645d4eee8fa726cccc7eecd6a905b759ee1a12f39b9e84d372967fd3e35ba72ebfed76cbb73ec61c4c8b4831b9119df90d7c9dda677cfbf32949dffebc79b5462fe8f4aa4ec91a8d46e8344aa7b7ea3441a7769d2ed0e9c33acdd4e9d38670b121bc49a7153addafd3c33a3da9d3533abd6a08c304a5d547a7b71ac2098670b2216c37841718c2193a7d58a72b0ce17c43f86943b8d810de64085718c29586708d21fc9a21bc3f7fb83e0f1bc2470de1938670c62a3d3f9dae3084f30de1a70de162437893215c6108571ac2353a7d4da7470de1933a3da5d30e43f8aa4e89de6fa3560f0f5b0ce15b0de1044338d910b6eb74814e330de1158670be21fcb4215c6c086f32842b0ce14a43b8c6107e4da7fb757ad2103e65087f68082f2f4cb0209d9f6129cc5995bf665dd6ba953905c89f61d19ecfd4a94da7893a9da5d3d93a4dd268c1407e05594f813906c3b7b2002c7201d52a3cd7f3cd1a8897b52e77fdaa9cd58505df5b9753b87edd6acb535979eb7342f1b342f1677e2dfed088cbb374f9b274f9b274f9b274f9b242f20de4f3e08de5d3f329d0f329d0f329d0f32908e593acd33b743a2341a733347d2487ca796850af96ef67e5e5e5aca3cff574857aba422ddd4f73d6adc1070bb2d6657fb768e53a901059645d96c582fc073415656567afcb2900990bf235fe838559ca9396fc3574f68370aece4fcf5bf37856dee083429dffd08a753959d943f8093aff46c2c21f7407fa1cba03a50509df5b8eabbbe14afcdef27559ab728688410af474c3e3c19a442f6ffefad54ae1ca35abbfbd17407c3d9fac99df946e7802e80e5afc449dced2e96c9d26e9f5987923f90a48819ebe404f5fa0a72fd0d31784d227ebf40e9dce48d0e90c4d5f7a3e857a3e857a3e857a3e2b966ae370bb4e8feaf4b24ea31ed6c7fb231a2dd4e98a1fe9e1c5df4e1f87667e92b687a697e559ebf30a2dcb730a951543c2796bb2b2873e2f2804b78986574217c8850eb4727541e1baf554e594bf6a654196be853098d9703ecd7448783053f26fbfe3df7ec7703fe0df7ec7f0f0ffe97e47f48f13526c3356a5596e9d9ab7fe36589bdd69f98ff5859635cb2dab7256ad59f74c384458050ba3071f79f0fb73efbb4f8b6f5bb57448fc82670a96e53cbdb2d0a2e03c956d79fc190b5ded4dcdcbb614ad2c5c816b2c589e6919dda0bcc5ab0bd6e7c3645788b6e99902cc05d3de69c94ab86b2aaef8b266e87426d25b4222fdeffd891ae10d6c61688065ff774b19fc93fe2791b97f39e6767dfec9d6e7995bf5f9ea039d7ffb8f75fea31acdd3e36dd5f9037f1bf47ea1d3ccff343cfffff91fa3d3d1b6bffd3271dcaab6cb9f0a64c4ffab12fdfbefdf7ffffefbf7dfbffffe4ffc8bf8b9367f86a8c540130cd46ea019069a69a0f9065a6ca015065a63a0fb0df4a8819e32d06603ed3050f87f188d30508b812618a8dd40330c34d340f30db4d8402b0cb4c640f71be851033d65a0cd06da61a0a464388d30508b812618a8dd40330c34d340f30db4d8402b0cb4c640f71be851033d65a0cd06da61a064e3701a61a016034d3050bb81661868a681e61b68b1815618688d81ee37d0a3067aca409b0db4c3408963388d30508b812618a8dd40330c34d340f30db4d8402b0cb4c640f71be851033d65a0cd06da61a0a474388d30508b812618a8dd40330c34d340f30db4d8402b0cb4c640f71be851033d65a0cd06da61a0c4399c4618a8c540130cd46ea019069a69a0f9065a6ca015065a63a0fb0df4a8819e32d06603ed305052369c4618a8c540130cd46ea019069a69a0f9065a6ca015065a63a0fb0df4a8819e32d06603ed3050e23250fd2f18d4de8b9f2cd2f8211ad4ff0819d863d07e3003e1642a4f053f2cbfd0dfff05896fca73' + +ISP_PROG = binascii.unhexlify(ISP_PROG) + +#print('ISP_FLASH progam size (compressed)', len(ISP_PROG)) +ISP_PROG = zlib.decompress(ISP_PROG) +#print('ISP_FLASH progam size (decompressed)', len(ISP_PROG)) + +def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█'): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + length - Optional : character length of bar (Int) + fill - Optional : bar fill character (Str) + """ + percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) + filledLength = int(length * iteration // total) + bar = fill * filledLength + '-' * (length - filledLength) + print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r') + # Print New Line on Complete + if iteration == total: + print() + +def slip_reader(port): + partial_packet = None + in_escape = False + + while True: + waiting = port.inWaiting() + read_bytes = port.read(1 if waiting == 0 else waiting) + if read_bytes == b'': + raise Exception("Timed out waiting for packet %s" % ("header" if partial_packet is None else "content")) + for b in read_bytes: + + if type(b) is int: + b = bytes([b]) # python 2/3 compat + + if partial_packet is None: # waiting for packet header + if b == b'\xc0': + partial_packet = b"" + else: + raise Exception('Invalid head of packet (%r)' % b) + elif in_escape: # part-way through escape sequence + in_escape = False + if b == b'\xdc': + partial_packet += b'\xc0' + elif b == b'\xdd': + partial_packet += b'\xdb' + else: + raise Exception('Invalid SLIP escape (%r%r)' % (b'\xdb', b)) + elif b == b'\xdb': # start of escape sequence + in_escape = True + elif b == b'\xc0': # end of packet + yield partial_packet + partial_packet = None + else: # normal byte in packet + partial_packet += b + + +class ISPResponse: + class ISPOperation(Enum): + ISP_ECHO = 0xC1 + ISP_NOP = 0xC2 + ISP_MEMORY_WRITE = 0xC3 + ISP_MEMORY_READ = 0xC4 + ISP_MEMORY_BOOT = 0xC5 + ISP_DEBUG_INFO = 0xD1 + + class ErrorCode(Enum): + ISP_RET_DEFAULT = 0 + ISP_RET_OK = 0xE0 + ISP_RET_BAD_DATA_LEN = 0xE1 + ISP_RET_BAD_DATA_CHECKSUM = 0xE2 + ISP_RET_INVALID_COMMAND = 0xE3 + + @staticmethod + def parse(data): + op = data[0] + reason = data[1] + text = '' + try: + if ISPResponse.ISPOperation(op) == ISPResponse.ISPOperation.ISP_DEBUG_INFO: + text = data[2:].decode() + except ValueError: + print('Warning: recv unknown op', op) + + return (op, reason, text) + + +class FlashModeResponse: + class Operation(Enum): + ISP_DEBUG_INFO = 0xD1 + ISP_NOP = 0xD2 + ISP_FLASH_ERASE = 0xD3 + ISP_FLASH_WRITE = 0xD4 + ISP_REBOOT = 0xD5 + ISP_UARTHS_BAUDRATE_SET = 0xD6 + FLASHMODE_FLASH_INIT = 0xD7 + + class ErrorCode(Enum): + ISP_RET_DEFAULT = 0 + ISP_RET_OK = 0xE0 + ISP_RET_BAD_DATA_LEN = 0xE1 + ISP_RET_BAD_DATA_CHECKSUM = 0xE2 + ISP_RET_INVALID_COMMAND = 0xE3 + + @staticmethod + def parse(data): + op = data[0] + reason = data[1] + text = '' + if FlashModeResponse.Operation(op) == FlashModeResponse.Operation.ISP_DEBUG_INFO: + text = data[2:].decode() + + return (op, reason, text) + + +def chunks(l, n): + """Yield successive n-sized chunks from l.""" + for i in range(0, len(l), n): + yield l[i:i + n] + + +class MAIXLoader: + def change_baudrate(self, baudrate): + print(INFO_MSG,"Selected Baudrate: ", baudrate, BASH_TIPS['DEFAULT']) + out = struct.pack('III', 0, 4, baudrate) + crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF) + out = struct.pack('HH', 0xd6, 0x00) + crc32_checksum + out + self.write(out) + time.sleep(0.05) + self._port.baudrate = baudrate + + def __init__(self, port='/dev/ttyUSB1', baudrate=115200): + # configure the serial connections (the parameters differs on the device you are connecting to) + self._port = serial.Serial( + port=port, + baudrate=baudrate, + parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE, + bytesize=serial.EIGHTBITS, + timeout=0.1 + ) + print(INFO_MSG, "Default baudrate is", baudrate, ", later it may be changed to the value you set.", BASH_TIPS['DEFAULT']) + + self._port.isOpen() + self._slip_reader = slip_reader(self._port) + + """ Read a SLIP packet from the serial port """ + + def read(self): + return next(self._slip_reader) + + """ Write bytes to the serial port while performing SLIP escaping """ + + def write(self, packet): + buf = b'\xc0' \ + + (packet.replace(b'\xdb', b'\xdb\xdd').replace(b'\xc0', b'\xdb\xdc')) \ + + b'\xc0' + #print('[WRITE]', binascii.hexlify(buf)) + return self._port.write(buf) + + def read_loop(self): + out = b'' + # while self._port.inWaiting() > 0: + # out += self._port.read(1) + + # print(out) + while 1: + sys.stdout.write('[RECV] raw data: ') + sys.stdout.write(binascii.hexlify(self._port.read(1)).decode()) + sys.stdout.flush() + + def recv_one_return(self): + timeout_init = time.time() + data = b'' + # find start boarder + #sys.stdout.write('[RECV one return] raw data: ') + while 1: + if time.time() - timeout_init > timeout: + raise TimeoutError + c = self._port.read(1) + #sys.stdout.write(binascii.hexlify(c).decode()) + sys.stdout.flush() + if c == b'\xc0': + break + + in_escape = False + while 1: + if time.time() - timeout_init > timeout: + raise TimeoutError + c = self._port.read(1) + #sys.stdout.write(binascii.hexlify(c).decode()) + sys.stdout.flush() + if c == b'\xc0': + break + + elif in_escape: # part-way through escape sequence + in_escape = False + if c == b'\xdc': + data += b'\xc0' + elif c == b'\xdd': + data += b'\xdb' + else: + raise Exception('Invalid SLIP escape (%r%r)' % (b'\xdb', b)) + elif c == b'\xdb': # start of escape sequence + in_escape = True + + data += c + + #sys.stdout.write('\n') + return data + + def reset_to_isp_kd233(self): + self._port.setDTR (False) + self._port.setRTS (False) + time.sleep(0.01) + #print('-- RESET to LOW, IO16 to HIGH --') + # Pull reset down and keep 10ms + self._port.setDTR (True) + self._port.setRTS (False) + time.sleep(0.01) + #print('-- IO16 to LOW, RESET to HIGH --') + # Pull IO16 to low and release reset + self._port.setRTS (True) + self._port.setDTR (False) + time.sleep(0.01) + + def reset_to_isp_dan(self): + self._port.dtr = False + self._port.rts = False + time.sleep(0.01) + #print('-- RESET to LOW, IO16 to HIGH --') + # Pull reset down and keep 10ms + self._port.dtr = False + self._port.rts = True + time.sleep(0.01) + #print('-- IO16 to LOW, RESET to HIGH --') + # Pull IO16 to low and release reset + self._port.rts = False + self._port.dtr = True + time.sleep(0.01) + + def reset_to_boot(self): + self._port.setDTR (False) + self._port.setRTS (False) + time.sleep(0.01) + #print('-- RESET to LOW --') + # Pull reset down and keep 10ms + self._port.setRTS (False) + self._port.setDTR (True) + time.sleep(0.01) + #print('-- RESET to HIGH, BOOT --') + # Pull IO16 to low and release reset + self._port.setRTS (False) + self._port.setDTR (False) + time.sleep(0.01) + + def greeting(self): + self._port.write(b'\xc0\xc2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0') + op, reason, text = ISPResponse.parse(self.recv_one_return()) + + #print('MAIX return op:', ISPResponse.ISPOperation(op).name, 'reason:', ISPResponse.ErrorCode(reason).name) + + + def flash_greeting(self): + retry_count = 0 + while 1: + self._port.write(b'\xc0\xd2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0') + retry_count = retry_count + 1 + try: + op, reason, text = FlashModeResponse.parse(self.recv_one_return()) + except IndexError: + if retry_count > MAX_RETRY_TIMES: + print(ERROR_MSG,"Failed to Connect to K210's Stub",BASH_TIPS['DEFAULT']) + sys.exit(1) + time.sleep(0.1) + continue + print(WARN_MSG,"Unexcepted Return recevied, retrying...",BASH_TIPS['DEFAULT']) + #print('MAIX return op:', FlashModeResponse.Operation(op).name, 'reason:', + # FlashModeResponse.ErrorCode(reason).name) + if FlashModeResponse.Operation(op) == FlashModeResponse.Operation.ISP_NOP: + print(INFO_MSG,"Boot to Flashmode Successfully",BASH_TIPS['DEFAULT']) + break + else: + if retry_count > MAX_RETRY_TIMES: + print(ERROR_MSG,"Failed to Connect to K210's Stub",BASH_TIPS['DEFAULT']) + sys.exit(1) + print(WARN_MSG,"Unexcepted Return recevied, retrying...",BASH_TIPS['DEFAULT']) + time.sleep(0.1) + continue + + def boot(self, address=0x80000000): + print(INFO_MSG,"Booting From " + hex(address),BASH_TIPS['DEFAULT']) + + out = struct.pack('II', address, 0) + + crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF) + + out = struct.pack('HH', 0xc5, 0x00) + crc32_checksum + out # op: ISP_MEMORY_WRITE: 0xc3 + self.write(out) + + def recv_debug(self): + op, reason, text = ISPResponse.parse(self.recv_one_return()) + #print('[RECV] op:', ISPResponse.ISPOperation(op).name, 'reason:', ISPResponse.ErrorCode(reason).name) + if text: + print('-' * 30) + print(text) + print('-' * 30) + if ISPResponse.ErrorCode(reason) not in (ISPResponse.ErrorCode.ISP_RET_DEFAULT, ISPResponse.ErrorCode.ISP_RET_OK): + print('Failed, retry, errcode=', hex(reason)) + return False + return True + + def flash_recv_debug(self): + op, reason, text = FlashModeResponse.parse(self.recv_one_return()) + #print('[Flash-RECV] op:', FlashModeResponse.Operation(op).name, 'reason:', + # FlashModeResponse.ErrorCode(reason).name) + if text: + print('-' * 30) + print(text) + print('-' * 30) + + if FlashModeResponse.ErrorCode(reason) not in (FlashModeResponse.ErrorCode.ISP_RET_OK, FlashModeResponse.ErrorCode.ISP_RET_OK): + print('Failed, retry') + return False + return True + + def init_flash(self, chip_type): + chip_type = int(chip_type) + print(INFO_MSG,"Selected Flash: ",("In-Chip", "On-Board")[chip_type],BASH_TIPS['DEFAULT']) + out = struct.pack('II', chip_type, 0) + crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF) + + out = struct.pack('HH', 0xd7, 0x00) + crc32_checksum + out + + sent = self.write(out) + op, reason, text = FlashModeResponse.parse(self.recv_one_return()) + #print('MAIX return op:', FlashModeResponse.Operation(op).name, 'reason:', + # FlashModeResponse.ErrorCode(reason).name) + + def flash_dataframe(self, data, address=0x80000000): + DATAFRAME_SIZE = 1024 + data_chunks = chunks(data, DATAFRAME_SIZE) + #print('[DEBUG] flash dataframe | data length:', len(data)) + total_chunk = math.ceil(len(data)/DATAFRAME_SIZE) + + for n, chunk in enumerate(data_chunks): + while 1: + #print('[INFO] sending chunk', i, '@address', hex(address), 'chunklen', len(chunk)) + out = struct.pack('II', address, len(chunk)) + + crc32_checksum = struct.pack('I', binascii.crc32(out + chunk) & 0xFFFFFFFF) + + out = struct.pack('HH', 0xc3, 0x00) + crc32_checksum + out + chunk # op: ISP_MEMORY_WRITE: 0xc3 + sent = self.write(out) + #print('[INFO]', 'sent', sent, 'bytes', 'checksum', binascii.hexlify(crc32_checksum).decode()) + + address += len(chunk) + + if self.recv_debug(): + break + printProgressBar(n+1, total_chunk, prefix = 'Downloading ISP:', suffix = 'Complete', length = 50) + + def dump_to_flash(self, data, address=0): + ''' + typedef struct __attribute__((packed)) { + uint8_t op; + int32_t checksum; // 下面的所有字段都要参与checksum的计算 + uint32_t address; + uint32_t data_len; + uint8_t data_buf[1024]; + } isp_request_t; + ''' + + DATAFRAME_SIZE = 4096 + data_chunks = chunks(data, DATAFRAME_SIZE) + #print('[DEBUG] flash dataframe | data length:', len(data)) + + + + for n, chunk in enumerate(data_chunks): + #print('[INFO] sending chunk', i, '@address', hex(address)) + out = struct.pack('II', address, len(chunk)) + + crc32_checksum = struct.pack('I', binascii.crc32(out + chunk) & 0xFFFFFFFF) + + out = struct.pack('HH', 0xd4, 0x00) + crc32_checksum + out + chunk + #print("[$$$$]", binascii.hexlify(out[:32]).decode()) + retry_count = 0 + while True: + try: + sent = self.write(out) + #print('[INFO]', 'sent', sent, 'bytes', 'checksum', crc32_checksum) + self.flash_recv_debug() + except: + retry_count = retry_count + 1 + if retry_count > MAX_RETRY_TIMES: + print(ERROR_MSG,"Error Count Exceeded, Stop Trying",BASH_TIPS['DEFAULT']) + sys.exit(1) + continue + break + address += len(chunk) + + + + def flash_erase(self): + #print('[DEBUG] erasing spi flash.') + self._port.write(b'\xc0\xd3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0') + op, reason, text = FlashModeResponse.parse(self.recv_one_return()) + #print('MAIX return op:', FlashModeResponse.Operation(op).name, 'reason:', + # FlashModeResponse.ErrorCode(reason).name) + + def install_flash_bootloader(self, data): + # 1. 刷入 flash bootloader + self.flash_dataframe(data, address=0x80000000) + + def flash_firmware(self, firmware_bin: bytes, aes_key: bytes = None, address_offset = 0, sha256Prefix = True): + #print('[DEBUG] flash_firmware DEBUG: aeskey=', aes_key) + + if sha256Prefix == True: + # 固件加上头 + # 格式: SHA256(after)(32bytes) + AES_CIPHER_FLAG (1byte) + firmware_size(4bytes) + firmware_data + aes_cipher_flag = b'\x01' if aes_key else b'\x00' + + # 加密 + if aes_key: + enc = AES_128_CBC(aes_key, iv=b'\x00'*16).encrypt + padded = firmware_bin + b'\x00'*15 # zero pad + firmware_bin = b''.join([enc(padded[i*16:i*16+16]) for i in range(len(padded)//16)]) + + firmware_len = len(firmware_bin) + + data = aes_cipher_flag + struct.pack('I', firmware_len) + firmware_bin + + sha256_hash = hashlib.sha256(data).digest() + + firmware_with_header = data + sha256_hash + + total_chunk = math.ceil(len(firmware_with_header)/4096) + # 3. 分片刷入固件 + data_chunks = chunks(firmware_with_header, 4096) # 4kb for a sector + else: + total_chunk = math.ceil(len(firmware_bin)/4096) + data_chunks = chunks(firmware_bin, 4096) + + for n, chunk in enumerate(data_chunks): + chunk = chunk.ljust(4096, b'\x00') # align by 4kb + + # 3.1 刷入一个dataframe + #print('[INFO]', 'Write firmware data piece') + self.dump_to_flash(chunk, address= n * 4096 + address_offset) + printProgressBar(n+1, total_chunk, prefix = 'Downloading:', suffix = 'Complete', length = 50) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("-p", "--port", help="COM Port", default="DEFAULT") + parser.add_argument("-c", "--chip", help="SPI Flash type, 1 for in-chip, 0 for on-board", default=1) + parser.add_argument("-b", "--baudrate", type=int, help="UART baudrate for uploading firmware", default=115200) + parser.add_argument("-l", "--bootloader", help="bootloader bin path", required=False, default=None) + parser.add_argument("-k", "--key", help="AES key in hex, if you need encrypt your firmware.", required=False, default=None) + parser.add_argument("-v", "--verbose", help="increase output verbosity", default=False, + action="store_true") + parser.add_argument("-t", "--terminal", help="Start a terminal after finish", default=False, action="store_true") + parser.add_argument("firmware", help="firmware bin path") + + args = parser.parse_args() + if args.port == "DEFAULT": + try: + list_port_info = next(serial.tools.list_ports.grep(VID_LIST_FOR_AUTO_LOOKUP)) #Take the first one within the list + print(INFO_MSG,"COM Port Auto Detected, Selected ",list_port_info.device,BASH_TIPS['DEFAULT']) + _port = list_port_info.device + except StopIteration: + print(ERROR_MSG,"No vaild COM Port found in Auto Detect, Check Your Connection or Specify One by"+BASH_TIPS['GREEN']+'`--port/-p`',BASH_TIPS['DEFAULT']) + sys.exit(1) + else: + _port = args.port + print(INFO_MSG,"COM Port Selected Manually: ",_port,BASH_TIPS['DEFAULT']) + + loader = MAIXLoader(port=_port, baudrate=115200) + + + # 1. Greeting. + print(INFO_MSG,"Trying to Enter the ISP Mode...",BASH_TIPS['DEFAULT']) + + retry_count = 0 + + while 1: + retry_count = retry_count + 1 + if retry_count > 15: + print("\n" + ERROR_MSG,"No vaild Kendryte K210 found in Auto Detect, Check Your Connection or Specify One by"+BASH_TIPS['GREEN']+'`-p '+('/dev/ttyUSB0', 'COM3')[sys.platform == 'win32']+'`',BASH_TIPS['DEFAULT']) + sys.exit(1) + try: + print('.', end='') + loader.reset_to_isp_dan() + loader.greeting() + break + except TimeoutError: + pass + + try: + print('_', end='') + loader.reset_to_isp_kd233() + loader.greeting() + break + except TimeoutError: + pass + timeout = 3 + print() + print(INFO_MSG,"Greeting Message Detected, Start Downloading ISP",BASH_TIPS['DEFAULT']) + # 2. flash bootloader and firmware + try: + firmware_bin = open(args.firmware, 'rb') + except FileNotFoundError: + print(ERROR_MSG,'Unable to find the firmware at ', args.firmware, BASH_TIPS['DEFAULT']) + sys.exit(1) + + # install bootloader at 0x80000000 + if args.bootloader: + loader.install_flash_bootloader(open(args.bootloader, 'rb').read()) + else: + loader.install_flash_bootloader(ISP_PROG) + + loader.boot() + + print(INFO_MSG,"Wait For 0.3 second for ISP to Boot", BASH_TIPS['DEFAULT']) + + time.sleep(0.3) + + loader.flash_greeting() + + if args.baudrate != 115200: + loader.change_baudrate(args.baudrate) + + loader.init_flash(args.chip) + + if ".kfpkg" == os.path.splitext(args.firmware)[1]: + print(INFO_MSG,"Extracting KFPKG ... ", BASH_TIPS['DEFAULT']) + firmware_bin.close() + with tempfile.TemporaryDirectory() as tmpdir: + try: + with zipfile.ZipFile(args.firmware) as zf: + zf.extractall(tmpdir) + except zipfile.BadZipFile: + print(ERROR_MSG,'Unable to Decompress the kfpkg, your file might be corrupted.',BASH_TIPS['DEFAULT']) + sys.exit(1) + + fFlashList = open(os.path.join(tmpdir, 'flash-list.json'), "r") + sFlashList = re.sub(r'"address": (.*),', r'"address": "\1",', fFlashList.read()) #Pack the Hex Number in json into str + fFlashList.close() + jsonFlashList = json.loads(sFlashList) + for lBinFiles in jsonFlashList['files']: + print(INFO_MSG,"Writing",lBinFiles['bin'],"into","0x%08x"%int(lBinFiles['address'], 0),BASH_TIPS['DEFAULT']) + firmware_bin = open(os.path.join(tmpdir, lBinFiles["bin"]), "rb") + loader.flash_firmware(firmware_bin.read(), None, int(lBinFiles['address'], 0), lBinFiles['sha256Prefix']) + firmware_bin.close() + else: + if args.key: + aes_key = binascii.a2b_hex(args.key) + if len(aes_key) != 16: + raise ValueError('AES key must by 16 bytes') + + loader.flash_firmware(firmware_bin.read(), aes_key=aes_key) + else: + loader.flash_firmware(firmware_bin.read()) + + # 3. boot + loader.reset_to_boot() + print(INFO_MSG,"Rebooting...", BASH_TIPS['DEFAULT']) + loader._port.close() + + if(args.terminal == True): + import serial.tools.miniterm + sys.argv = [''] + serial.tools.miniterm.main(default_port=_port, default_baudrate=115200, default_dtr=False, default_rts=False) diff --git a/tools/opensbi/README.md b/tools/opensbi/README.md index 79ad945..2546f40 100644 --- a/tools/opensbi/README.md +++ b/tools/opensbi/README.md @@ -7,3 +7,9 @@ These are binary release of OpenSBI on this [commit](https://github.com/riscv/op - virt_rv64.elf: opensbi-0.3-rv64-bin/platform/qemu/virt/firmware/fw_jump.elf NOTE: The [official v0.3 release](https://github.com/riscv/opensbi/releases/tag/v0.3) has bug on serial interrupt. + + + +For K210: It needs some modification. The binary is from this [commit](https://github.com/rcore-os/opensbi/commit/4400a1a7d40b5399b3e07b4bad9fd303885c8c16). + +* k210.elf: build/platform/kendryte/k210/firmware/fw_payload.elf \ No newline at end of file diff --git a/tools/opensbi/k210.elf b/tools/opensbi/k210.elf new file mode 100755 index 0000000000000000000000000000000000000000..221c37ee8d5589a181ed7c08f6d2b08429565d78 GIT binary patch literal 239264 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 Y4ix?{ZpyTNar)=>8|lvo1a literal 0 HcmV?d00001 From 5080ee2579afff7c29fbcdd47be5dea68da95459 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Thu, 25 Apr 2019 10:56:13 +0800 Subject: [PATCH 30/61] add log info for envs in new_user function --- kernel/src/process/structs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index c86751a..d814639 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -196,6 +196,7 @@ impl Thread { args.insert(1, exec_path.into()); args.remove(2); info!("loader args: {:?}", args); + info!("loader envs: {:?}", envs); return Thread::new_user(buf.as_slice(), exec_path, args, envs); } else { warn!("loader specified as {} but failed to read", &loader_path); From 734e01cc465abccb66df6d77c41d150c291db2d3 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Thu, 25 Apr 2019 15:56:30 +0800 Subject: [PATCH 31/61] fix bug: sys_mmap didn't zero clean the anonymous memory We can use delay mode or eager mode(in added comment codes) WRJ's great work! --- crate/memory/src/memory_set/handler/delay.rs | 5 +++++ kernel/src/memory.rs | 2 +- kernel/src/syscall/mem.rs | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/crate/memory/src/memory_set/handler/delay.rs b/crate/memory/src/memory_set/handler/delay.rs index fd7b9d3..4bed477 100644 --- a/crate/memory/src/memory_set/handler/delay.rs +++ b/crate/memory/src/memory_set/handler/delay.rs @@ -44,6 +44,11 @@ impl MemoryHandler for Delay { entry.set_target(frame); entry.set_present(true); entry.update(); + //init with zero for delay mmap mode + let data = pt.get_page_slice_mut(addr); + for x in data { + *x = 0; + } true } } diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index 3156ff0..482f96e 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -114,7 +114,7 @@ impl Drop for KernelStack { /// Handle page fault at `addr`. /// Return true to continue, false to halt. pub fn handle_page_fault(addr: usize) -> bool { - // debug!("page fault @ {:#x}", addr); + debug!("page fault @ {:#x}", addr); // This is safe as long as page fault never happens in page fault handler unsafe { process_unsafe().vm.handle_page_fault(addr) } diff --git a/kernel/src/syscall/mem.rs b/kernel/src/syscall/mem.rs index 0b471c2..aa935ea 100644 --- a/kernel/src/syscall/mem.rs +++ b/kernel/src/syscall/mem.rs @@ -46,9 +46,15 @@ pub fn sys_mmap( addr, addr + len, prot.to_attr(), +// ByFrame::new(GlobalFrameAlloc), //eagle mmap mode Delay::new(GlobalFrameAlloc), "mmap_anon", ); + //init with zero for eagle mmap mode +// let data = unsafe { slice::from_raw_parts_mut(addr as *mut u8, len) }; +// for x in data { +// *x = 0; +// } return Ok(addr); } else { // only check From bac9e77be1c524a1a86163383ab31d913ee51c42 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Thu, 25 Apr 2019 23:14:23 +0800 Subject: [PATCH 32/61] fix bug: sys_sendfile: wrong length of written file --- kernel/src/syscall/fs.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index e859eb9..a236bb7 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -684,7 +684,7 @@ pub fn sys_sendfile( count: usize, ) -> SysResult { info!( - "sendfile: out: {}, in: {}, offset_ptr: {:?}, count: {}", + "sendfile:BEG out: {}, in: {}, offset_ptr: {:?}, count: {}", out_fd, in_fd, offset_ptr, count ); let proc = process(); @@ -705,6 +705,7 @@ pub fn sys_sendfile( // read from specified offset and write new offset back let mut bytes_read = 0; + let mut bytes_written = 0; while bytes_read < count { let len = min(buffer.len(), count - bytes_read); let read_len = in_file.read_at(read_offset, &mut buffer[..len])?; @@ -713,13 +714,20 @@ pub fn sys_sendfile( } bytes_read += read_len; read_offset += read_len; - let mut bytes_written = 0; + + bytes_written = 0; + let mut rlen = read_len; while bytes_written < read_len { - let write_len = out_file.write(&buffer[bytes_written..])?; + let write_len = out_file.write(&buffer[bytes_written..(bytes_written+rlen)])?; if write_len == 0 { + info!( + "sendfile:END_ERR out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, bytes_written {}", + out_fd, in_fd, offset_ptr, count, bytes_read, bytes_written + ); return Err(SysError::EBADF); } bytes_written += write_len; + rlen-=write_len; } } @@ -730,7 +738,11 @@ pub fn sys_sendfile( } else { in_file.seek(SeekFrom::Current(bytes_read as i64))?; } - return Ok(bytes_read); + info!( + "sendfile:END out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, bytes_written {}", + out_fd, in_fd, offset_ptr, count, bytes_read, bytes_written + ); + return Ok(bytes_written); } impl Process { From d8147bd9555b6f6987bbc6e7ea12eb50a04860f7 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Thu, 25 Apr 2019 23:28:03 +0800 Subject: [PATCH 33/61] fix bug:sys_sendfile: the return value: the length of written file --- kernel/src/syscall/fs.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index a236bb7..757f4e0 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -705,7 +705,7 @@ pub fn sys_sendfile( // read from specified offset and write new offset back let mut bytes_read = 0; - let mut bytes_written = 0; + let mut total_written = 0; while bytes_read < count { let len = min(buffer.len(), count - bytes_read); let read_len = in_file.read_at(read_offset, &mut buffer[..len])?; @@ -715,20 +715,21 @@ pub fn sys_sendfile( bytes_read += read_len; read_offset += read_len; - bytes_written = 0; + let mut bytes_written = 0; let mut rlen = read_len; while bytes_written < read_len { let write_len = out_file.write(&buffer[bytes_written..(bytes_written+rlen)])?; if write_len == 0 { info!( - "sendfile:END_ERR out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, bytes_written {}", - out_fd, in_fd, offset_ptr, count, bytes_read, bytes_written + "sendfile:END_ERR out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, bytes_written {}, write_len {}", + out_fd, in_fd, offset_ptr, count, bytes_read, bytes_written, write_len ); return Err(SysError::EBADF); } bytes_written += write_len; rlen-=write_len; } + total_written+=bytes_written; } if !offset_ptr.is_null() { @@ -739,10 +740,10 @@ pub fn sys_sendfile( in_file.seek(SeekFrom::Current(bytes_read as i64))?; } info!( - "sendfile:END out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, bytes_written {}", - out_fd, in_fd, offset_ptr, count, bytes_read, bytes_written + "sendfile:END out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, total_written {}", + out_fd, in_fd, offset_ptr, count, bytes_read, total_written ); - return Ok(bytes_written); + return Ok(total_written); } impl Process { From b0a1614b75fda31258ecb68b869aaf6f64f46d1b Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 26 Apr 2019 01:14:40 +0800 Subject: [PATCH 34/61] reorder syscall by function --- kernel/Makefile | 3 + kernel/src/syscall/mod.rs | 369 +++++++++++++------------------------ kernel/src/syscall/time.rs | 8 +- 3 files changed, 135 insertions(+), 245 deletions(-) diff --git a/kernel/Makefile b/kernel/Makefile index f1937d4..edb5858 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -125,6 +125,7 @@ endif else ifeq ($(arch), riscv32) qemu_opts += \ -machine virt \ + -serial mon:stdio \ -kernel ../tools/opensbi/virt_rv32.elf \ -device loader,addr=0x80400000,file=$(kernel_img) \ -drive file=$(SFSIMG),format=qcow2,id=sfs \ @@ -137,11 +138,13 @@ else ifeq ($(arch), riscv64) ifeq ($(board), u540) qemu_opts += \ -machine virt \ + -serial mon:stdio \ -kernel ../tools/opensbi/fu540.elf \ -device loader,addr=0x80200000,file=$(kernel_img) else qemu_opts += \ -machine virt \ + -serial mon:stdio \ -kernel ../tools/opensbi/virt_rv64.elf \ -device loader,addr=0x80200000,file=$(kernel_img) \ -drive file=$(SFSIMG),format=qcow2,id=sfs \ diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c78351a..ba267b7 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -37,7 +37,7 @@ mod time; #[deny(unreachable_patterns)] pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { let cid = cpu::id(); - let pid = { process().pid.clone() }; + let pid = process().pid.clone(); let tid = processor().tid(); if !pid.is_init() { // we trust pid 0 process @@ -48,50 +48,85 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { // See https://filippo.io/linux-syscall-table/ // And https://fedora.juszkiewicz.com.pl/syscalls.html. let ret = match id { - // 0 + // file SYS_READ => sys_read(args[0], args[1] as *mut u8, args[2]), SYS_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), + SYS_OPENAT => sys_openat(args[0], args[1] as *const u8, args[2], args[3]), SYS_CLOSE => sys_close(args[0]), SYS_FSTAT => sys_fstat(args[0], args[1] as *mut Stat), + SYS_NEWFSTATAT => sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]), SYS_LSEEK => sys_lseek(args[0], args[1] as i64, args[2] as u8), - SYS_MMAP => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]), - // 10 - SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]), - SYS_MUNMAP => sys_munmap(args[0], args[1]), - SYS_BRK => { - warn!("sys_brk is unimplemented, return -1"); - Err(SysError::ENOMEM) - } - SYS_RT_SIGACTION => { - warn!("sys_sigaction is unimplemented"); - Ok(0) - } - SYS_RT_SIGPROCMASK => { - warn!("sys_sigprocmask is unimplemented"); - Ok(0) - } SYS_IOCTL => sys_ioctl(args[0], args[1], args[2], args[3], args[4]), SYS_PREAD64 => sys_pread(args[0], args[1] as *mut u8, args[2], args[3]), SYS_PWRITE64 => sys_pwrite(args[0], args[1] as *const u8, args[2], args[3]), SYS_READV => sys_readv(args[0], args[1] as *const IoVec, args[2]), - // 20 SYS_WRITEV => sys_writev(args[0], args[1] as *const IoVec, args[2]), - SYS_SCHED_YIELD => sys_yield(), - SYS_MADVISE => { - warn!("sys_madvise is unimplemented"); - Ok(0) - } - SYS_NANOSLEEP => sys_nanosleep(args[0] as *const TimeSpec), - SYS_SETITIMER => { - warn!("sys_setitimer is unimplemented"); - Ok(0) - } - SYS_GETPID => sys_getpid(), - // 40 SYS_SENDFILE => sys_sendfile(args[0], args[1], args[2] as *mut usize, args[3]), + SYS_FCNTL => unimplemented("fcntl", Ok(0)), + SYS_FLOCK => unimplemented("flock", Ok(0)), + SYS_FSYNC => sys_fsync(args[0]), + SYS_FDATASYNC => sys_fdatasync(args[0]), + SYS_TRUNCATE => sys_truncate(args[0] as *const u8, args[1]), + SYS_FTRUNCATE => sys_ftruncate(args[0], args[1]), + SYS_GETDENTS64 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]), + SYS_GETCWD => sys_getcwd(args[0] as *mut u8, args[1]), + SYS_CHDIR => sys_chdir(args[0] as *const u8), + SYS_RENAMEAT => sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8), + SYS_MKDIRAT => sys_mkdirat(args[0], args[1] as *const u8, args[2]), + SYS_LINKAT => sys_linkat( + args[0], + args[1] as *const u8, + args[2], + args[3] as *const u8, + args[4], + ), + SYS_UNLINKAT => sys_unlinkat(args[0], args[1] as *const u8, args[2]), + SYS_SYMLINKAT => unimplemented("symlinkat", Err(SysError::EACCES)), + SYS_READLINKAT => { + sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3]) + } + SYS_FCHMOD => unimplemented("fchmod", Ok(0)), + SYS_FCHMODAT => unimplemented("fchmodat", Ok(0)), + SYS_FCHOWN => unimplemented("fchown", Ok(0)), + SYS_FCHOWNAT => unimplemented("fchownat", Ok(0)), + SYS_FACCESSAT => sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]), + SYS_DUP3 => sys_dup2(args[0], args[1]), // TODO: handle `flags` + SYS_PIPE2 => sys_pipe(args[0] as *mut u32), // TODO: handle `flags` + SYS_UTIMENSAT => unimplemented("utimensat", Ok(0)), + + // io multiplexing + SYS_PPOLL => sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec), // ignore sigmask + SYS_EPOLL_CREATE1 => unimplemented("epoll_create1", Err(SysError::ENOSYS)), + + // file system + SYS_STATFS => unimplemented("statfs", Err(SysError::EACCES)), + SYS_FSTATFS => unimplemented("fstatfs", Err(SysError::EACCES)), + SYS_SYNC => sys_sync(), + SYS_MOUNT => unimplemented("mount", Err(SysError::EACCES)), + SYS_UMOUNT2 => unimplemented("umount2", Err(SysError::EACCES)), + + // memory + SYS_BRK => unimplemented("brk", Err(SysError::ENOMEM)), + SYS_MMAP => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]), + SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]), + SYS_MUNMAP => sys_munmap(args[0], args[1]), + SYS_MADVISE => unimplemented("madvise", Ok(0)), + + // signal + SYS_RT_SIGACTION => unimplemented("sigaction", Ok(0)), + SYS_RT_SIGPROCMASK => unimplemented("sigprocmask", Ok(0)), + SYS_SIGALTSTACK => unimplemented("sigaltstack", Ok(0)), + SYS_KILL => sys_kill(args[0], args[1]), + + // schedule + SYS_SCHED_YIELD => sys_yield(), + SYS_SCHED_GETAFFINITY => sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32), + + // socket SYS_SOCKET => sys_socket(args[0], args[1], args[2]), SYS_CONNECT => sys_connect(args[0], args[1] as *const SockAddr, args[2]), SYS_ACCEPT => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), + SYS_ACCEPT4 => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4 SYS_SENDTO => sys_sendto( args[0], args[1] as *const u8, @@ -112,7 +147,6 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { SYS_RECVMSG => sys_recvmsg(args[0], args[1] as *mut MsgHdr, args[2]), SYS_SHUTDOWN => sys_shutdown(args[0], args[1]), SYS_BIND => sys_bind(args[0], args[1] as *const SockAddr, args[2]), - // 50 SYS_LISTEN => sys_listen(args[0], args[1]), SYS_GETSOCKNAME => sys_getsockname(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), SYS_GETPEERNAME => sys_getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), @@ -124,6 +158,8 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { args[3] as *mut u8, args[4] as *mut u32, ), + + // process SYS_CLONE => sys_clone( args[0], args[1], @@ -138,196 +174,73 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { args[2] as *const *const u8, tf, ), - // 60 SYS_EXIT => sys_exit(args[0] as usize), + SYS_EXIT_GROUP => sys_exit_group(args[0]), SYS_WAIT4 => sys_wait4(args[0] as isize, args[1] as *mut i32), // TODO: wait4 - SYS_KILL => sys_kill(args[0], args[1]), - SYS_UNAME => sys_uname(args[0] as *mut u8), - SYS_FCNTL => { - warn!("sys_fcntl is unimplemented"); - Ok(0) - } - SYS_FLOCK => { - warn!("sys_flock is unimplemented"); - Ok(0) - } - SYS_FSYNC => sys_fsync(args[0]), - SYS_FDATASYNC => sys_fdatasync(args[0]), - SYS_TRUNCATE => sys_truncate(args[0] as *const u8, args[1]), - SYS_FTRUNCATE => sys_ftruncate(args[0], args[1]), - SYS_GETCWD => sys_getcwd(args[0] as *mut u8, args[1]), - // 80 - SYS_CHDIR => sys_chdir(args[0] as *const u8), - SYS_FCHMOD => { - warn!("sys_fchmod is unimplemented"); - Ok(0) - } - SYS_FCHOWN => { - warn!("sys_fchown is unimplemented"); - Ok(0) - } - SYS_UMASK => { - warn!("sys_umask is unimplemented"); - Ok(0o777) - } - SYS_GETTIMEOFDAY => sys_gettimeofday(args[0] as *mut TimeVal, args[1] as *const u8), - // SYS_GETRLIMIT => sys_getrlimit(), - SYS_GETRUSAGE => sys_getrusage(args[0], args[1] as *mut RUsage), - SYS_SYSINFO => sys_sysinfo(args[0] as *mut SysInfo), - SYS_TIMES => sys_times(args[0] as *mut Tms), - SYS_GETUID => { - warn!("sys_getuid is unimplemented"); - Ok(0) - } - SYS_GETGID => { - warn!("sys_getgid is unimplemented"); - Ok(0) - } - SYS_SETUID => { - warn!("sys_setuid is unimplemented"); - Ok(0) - } - SYS_GETEUID => { - warn!("sys_geteuid is unimplemented"); - Ok(0) - } - SYS_GETEGID => { - warn!("sys_getegid is unimplemented"); - Ok(0) - } - SYS_SETPGID => { - warn!("sys_setpgid is unimplemented"); - Ok(0) - } - // 110 - SYS_GETPPID => sys_getppid(), - SYS_SETSID => { - warn!("sys_setsid is unimplemented"); - Ok(0) - } - SYS_GETPGID => { - warn!("sys_getpgid is unimplemented"); - Ok(0) - } - SYS_GETGROUPS => { - warn!("sys_getgroups is unimplemented"); - Ok(0) - } - SYS_SETGROUPS => { - warn!("sys_setgroups is unimplemented"); - Ok(0) - } - SYS_SIGALTSTACK => { - warn!("sys_sigaltstack is unimplemented"); - Ok(0) - } - SYS_STATFS => { - warn!("statfs is unimplemented"); - Err(SysError::EACCES) - } - SYS_FSTATFS => { - warn!("fstatfs is unimplemented"); - Err(SysError::EACCES) - } - SYS_SETPRIORITY => sys_set_priority(args[0]), - SYS_PRCTL => { - warn!("prctl is unimplemented"); - Ok(0) - } - // SYS_SETRLIMIT => sys_setrlimit(), - SYS_SYNC => sys_sync(), - SYS_MOUNT => { - warn!("mount is unimplemented"); - Err(SysError::EACCES) - } - SYS_UMOUNT2 => { - warn!("umount2 is unimplemented"); - Err(SysError::EACCES) - } - SYS_REBOOT => sys_reboot( - args[0] as u32, - args[1] as u32, - args[2] as u32, - args[3] as *const u8, - ), - SYS_GETTID => sys_gettid(), + SYS_SET_TID_ADDRESS => unimplemented("set_tid_address", Ok(thread::current().id())), SYS_FUTEX => sys_futex( args[0], args[1] as u32, args[2] as i32, args[3] as *const TimeSpec, ), - SYS_SCHED_GETAFFINITY => sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32), - SYS_GETDENTS64 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]), - SYS_SET_TID_ADDRESS => { - warn!("sys_set_tid_address is unimplemented"); - Ok(thread::current().id()) - } + + // time + SYS_NANOSLEEP => sys_nanosleep(args[0] as *const TimeSpec), + SYS_SETITIMER => unimplemented("setitimer", Ok(0)), + SYS_GETTIMEOFDAY => sys_gettimeofday(args[0] as *mut TimeVal, args[1] as *const u8), SYS_CLOCK_GETTIME => sys_clock_gettime(args[0], args[1] as *mut TimeSpec), - SYS_EXIT_GROUP => sys_exit_group(args[0]), - SYS_OPENAT => sys_openat(args[0], args[1] as *const u8, args[2], args[3]), - SYS_MKDIRAT => sys_mkdirat(args[0], args[1] as *const u8, args[2]), - // SYS_MKNODAT => sys_mknod(), - // 260 - SYS_FCHOWNAT => { - warn!("sys_fchownat is unimplemented"); - Ok(0) - } - SYS_NEWFSTATAT => sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]), - SYS_UNLINKAT => sys_unlinkat(args[0], args[1] as *const u8, args[2]), - SYS_RENAMEAT => sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8), - SYS_LINKAT => sys_linkat( - args[0], - args[1] as *const u8, - args[2], - args[3] as *const u8, - args[4], - ), - SYS_SYMLINKAT => Err(SysError::EACCES), - SYS_READLINKAT => { - sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3]) - } - SYS_FCHMODAT => { - warn!("sys_fchmodat is unimplemented"); - Ok(0) - } - SYS_FACCESSAT => sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]), - SYS_PPOLL => sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec), // ignore sigmask - // 280 - SYS_UTIMENSAT => { - warn!("sys_utimensat is unimplemented"); - Ok(0) - } - SYS_ACCEPT4 => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4 - SYS_EPOLL_CREATE1 => { - warn!("sys_epoll_create1 is unimplemented"); - Err(SysError::ENOSYS) - } - SYS_DUP3 => sys_dup2(args[0], args[1]), // TODO: handle `flags` - SYS_PIPE2 => sys_pipe(args[0] as *mut u32), // TODO: handle `flags` + + // system + SYS_GETPID => sys_getpid(), + SYS_GETTID => sys_gettid(), + SYS_UNAME => sys_uname(args[0] as *mut u8), + SYS_UMASK => unimplemented("umask", Ok(0o777)), + // SYS_GETRLIMIT => sys_getrlimit(), + // SYS_SETRLIMIT => sys_setrlimit(), + SYS_GETRUSAGE => sys_getrusage(args[0], args[1] as *mut RUsage), + SYS_SYSINFO => sys_sysinfo(args[0] as *mut SysInfo), + SYS_TIMES => sys_times(args[0] as *mut Tms), + SYS_GETUID => unimplemented("getuid", Ok(0)), + SYS_GETGID => unimplemented("getgid", Ok(0)), + SYS_SETUID => unimplemented("setuid", Ok(0)), + SYS_GETEUID => unimplemented("geteuid", Ok(0)), + SYS_GETEGID => unimplemented("getegid", Ok(0)), + SYS_SETPGID => unimplemented("setpgid", Ok(0)), + SYS_GETPPID => sys_getppid(), + SYS_SETSID => unimplemented("setsid", Ok(0)), + SYS_GETPGID => unimplemented("getpgid", Ok(0)), + SYS_GETGROUPS => unimplemented("getgroups", Ok(0)), + SYS_SETGROUPS => unimplemented("setgroups", Ok(0)), + SYS_SETPRIORITY => sys_set_priority(args[0]), + SYS_PRCTL => unimplemented("prctl", Ok(0)), SYS_PRLIMIT64 => sys_prlimit64( args[0], args[1], args[2] as *const RLimit, args[3] as *mut RLimit, ), - // custom temporary syscall + SYS_REBOOT => sys_reboot( + args[0] as u32, + args[1] as u32, + args[2] as u32, + args[3] as *const u8, + ), + + // custom SYS_MAP_PCI_DEVICE => sys_map_pci_device(args[0], args[1]), SYS_GET_PADDR => sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2]), _ => { - #[cfg(target_arch = "x86_64")] - let x86_64_ret = x86_64_syscall(id, args, tf); - #[cfg(not(target_arch = "x86_64"))] - let x86_64_ret = None; - - #[cfg(target_arch = "mips")] - let mips_ret = mips_syscall(id, args, tf); - #[cfg(not(target_arch = "mips"))] - let mips_ret = None; - if let Some(ret) = x86_64_ret { - ret - } else if let Some(ret) = mips_ret { + let ret = match () { + #[cfg(target_arch = "x86_64")] + () => x86_64_syscall(id, args, tf), + #[cfg(target_arch = "mips")] + () => mips_syscall(id, args, tf), + #[cfg(all(not(target_arch = "x86_64"), not(target_arch = "mips")))] + () => None, + }; + if let Some(ret) = ret { ret } else { error!("unknown syscall id: {}, args: {:x?}", id, args); @@ -348,6 +261,11 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { } } +fn unimplemented(name: &str, ret: SysResult) -> SysResult { + warn!("{} is unimplemented", name); + ret +} + #[cfg(target_arch = "mips")] fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { let ret = match id { @@ -372,18 +290,7 @@ fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option Err(err), } } - SYS_GETPGID => { - warn!("sys_getpgid is unimplemented"); - Ok(0) - } - SYS_SETPGID => { - warn!("sys_setpgid is unimplemented"); - Ok(0) - } - SYS_FCNTL64 => { - warn!("sys_fcntl64 is unimplemented"); - Ok(0) - } + SYS_FCNTL64 => unimplemented("fcntl64", Ok(0)), SYS_SET_THREAD_AREA => { info!("set_thread_area: tls: 0x{:x}", args[0]); extern "C" { @@ -396,9 +303,7 @@ fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { - return None; - } + _ => return None, }; Some(ret) } @@ -420,37 +325,21 @@ fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option sys_dup2(args[0], args[1]), - SYS_ALARM => { - warn!("sys_alarm is unimplemented"); - Ok(0) - } + SYS_ALARM => unimplemented("alarm", Ok(0)), SYS_FORK => sys_fork(tf), - // use fork for vfork - SYS_VFORK => sys_fork(tf), + SYS_VFORK => sys_fork(tf), // use fork for vfork SYS_RENAME => sys_rename(args[0] as *const u8, args[1] as *const u8), SYS_MKDIR => sys_mkdir(args[0] as *const u8, args[1]), SYS_RMDIR => sys_rmdir(args[0] as *const u8), SYS_LINK => sys_link(args[0] as *const u8, args[1] as *const u8), SYS_UNLINK => sys_unlink(args[0] as *const u8), SYS_READLINK => sys_readlink(args[0] as *const u8, args[1] as *mut u8, args[2]), - // 90 - SYS_CHMOD => { - warn!("sys_chmod is unimplemented"); - Ok(0) - } - SYS_CHOWN => { - warn!("sys_chown is unimplemented"); - Ok(0) - } + SYS_CHMOD => unimplemented("chmod", Ok(0)), + SYS_CHOWN => unimplemented("chown", Ok(0)), SYS_ARCH_PRCTL => sys_arch_prctl(args[0] as i32, args[1], tf), SYS_TIME => sys_time(args[0] as *mut u64), - SYS_EPOLL_CREATE => { - warn!("sys_epoll_create is unimplemented"); - Err(SysError::ENOSYS) - } - _ => { - return None; - } + SYS_EPOLL_CREATE => unimplemented("epoll_create", Err(SysError::ENOSYS)), + _ => return None, }; Some(ret) } diff --git a/kernel/src/syscall/time.rs b/kernel/src/syscall/time.rs index eb49d73..dd2834c 100644 --- a/kernel/src/syscall/time.rs +++ b/kernel/src/syscall/time.rs @@ -147,18 +147,16 @@ pub fn sys_getrusage(who: usize, rusage: *mut RUsage) -> SysResult { Ok(0) } - #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct Tms { - tms_utime: u64, /* user time */ + tms_utime: u64, /* user time */ tms_stime: u64, /* system time */ tms_cutime: u64, /* user time of children */ tms_cstime: u64, /* system time of children */ } - -pub fn sys_times(buf:*mut Tms)-> SysResult { +pub fn sys_times(buf: *mut Tms) -> SysResult { info!("times: buf: {:?}", buf); let proc = process(); proc.vm.check_write_ptr(buf)?; @@ -175,4 +173,4 @@ pub fn sys_times(buf:*mut Tms)-> SysResult { unsafe { *buf = new_buf }; Ok(tick as usize) -} \ No newline at end of file +} From 0d790f2dc52978600f6380c8552a86e8c0b5fcf3 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Fri, 26 Apr 2019 02:34:42 +0800 Subject: [PATCH 35/61] add LOG info in sys_exec and new_user, add env var in run_user_shell --- kernel/src/process/structs.rs | 4 ++-- kernel/src/shell.rs | 2 +- kernel/src/syscall/proc.rs | 14 +++++++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index d814639..4a0f30c 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -195,8 +195,8 @@ impl Thread { args.insert(0, loader_path.into()); args.insert(1, exec_path.into()); args.remove(2); - info!("loader args: {:?}", args); - info!("loader envs: {:?}", envs); + //info!("loader args: {:?}", args); + //info!("loader envs: {:?}", envs); return Thread::new_user(buf.as_slice(), exec_path, args, envs); } else { warn!("loader specified as {} but failed to read", &loader_path); diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index 000ad63..547ed78 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -14,7 +14,7 @@ pub fn run_user_shell() { data.as_slice(), "busybox", vec!["busybox".into(), "sh".into()], - Vec::new(), + vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()], )); } else { processor().manager().add(Thread::new_kernel(shell, 0)); diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index c6c6b1f..f0fc954 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -129,7 +129,7 @@ pub fn sys_exec( envp: *const *const u8, tf: &mut TrapFrame, ) -> SysResult { - info!("exec: name: {:?}, argv: {:?}, envp: {:?}", name, argv, envp); + info!("exec:BEG: name: {:?}, argv: {:?}, envp: {:?}", name, argv, envp); let proc = process(); let exec_name = if name.is_null() { String::from("") @@ -138,6 +138,7 @@ pub fn sys_exec( }; if argv.is_null() { + info!("exec:END:ERR1: exec_name: {:?}, name: {:?}, argv: is NULL", exec_name, name); return Err(SysError::EINVAL); } // Check and copy args to kernel @@ -147,6 +148,7 @@ pub fn sys_exec( proc.vm.check_read_ptr(current_argv)?; while !(*current_argv).is_null() { let arg = proc.vm.check_and_clone_cstr(*current_argv)?; + info!(" arg: {}",arg); args.push(arg); current_argv = current_argv.add(1); } @@ -159,6 +161,7 @@ pub fn sys_exec( proc.vm.check_read_ptr(current_env)?; while !(*current_env).is_null() { let env = proc.vm.check_and_clone_cstr(*current_env)?; + info!(" env: {}",env); envs.push(env); current_env = current_env.add(1); } @@ -166,12 +169,13 @@ pub fn sys_exec( } if args.is_empty() { + info!("exec:END:ERR2: exec_name: {:?}, name: {:?}, args is empty", exec_name, name); return Err(SysError::EINVAL); } info!( - "exec: name: {:?}, args: {:?}, envp: {:?}", - exec_name, args, envs + "exec:STEP2: exec_name: {:?}, name{:?}, args: {:?}, envp: {:?}", + exec_name, name, args, envs ); // Read program file @@ -196,6 +200,10 @@ pub fn sys_exec( ::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack); ::core::mem::swap(current_thread(), &mut *thread); + info!( + "exec:END: exec_name: {:?}", + exec_name + ); Ok(0) } From 091902ae0dfd8f629f10e746336af0825736c320 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Fri, 26 Apr 2019 08:38:53 +0800 Subject: [PATCH 36/61] set 'busybox ash' dynamic-linked app from alpine linux as the default init shell in x86_64 environment --- kernel/src/shell.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index 547ed78..e40911b 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -6,15 +6,30 @@ use crate::process::*; use alloc::string::String; use alloc::vec::Vec; + #[cfg(not(feature = "run_cmdline"))] pub fn run_user_shell() { - if let Ok(inode) = ROOT_INODE.lookup("busybox") { + #[cfg(target_arch = "x86_64")] + let init_shell="/bin/busybox"; + + #[cfg(not(target_arch = "x86_64"))] + let init_shell="/busybox"; + + #[cfg(target_arch = "x86_64")] + let init_envs=vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()]; + + #[cfg(not(target_arch = "x86_64"))] + let init_envs=Vec::new(); + + let init_args=vec!["busybox".into(), "ash".into()]; + + if let Ok(inode) = ROOT_INODE.lookup(init_shell) { let data = inode.read_as_vec().unwrap(); processor().manager().add(Thread::new_user( data.as_slice(), - "busybox", - vec!["busybox".into(), "sh".into()], - vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()], + init_shell, + init_args, + init_envs, )); } else { processor().manager().add(Thread::new_kernel(shell, 0)); From ab62d542fdd0ff11fc2093df97ed17f3e8531ac6 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 26 Apr 2019 11:22:27 +0800 Subject: [PATCH 37/61] allocate pid independently from tid. fix sys_fork return value. --- kernel/src/process/structs.rs | 93 ++++++++++++++++++----------------- kernel/src/syscall/fs.rs | 12 ++--- kernel/src/syscall/net.rs | 6 +-- kernel/src/syscall/proc.rs | 3 +- 4 files changed, 55 insertions(+), 59 deletions(-) diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 4a0f30c..8ef01bc 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -32,41 +32,23 @@ pub struct Thread { /// Pid type /// For strong type separation -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct Pid(Option); +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Pid(usize); impl Pid { - pub fn uninitialized() -> Self { - Pid(None) - } - - /// Return if it was uninitialized before this call - /// When returning true, it usually means this is the first thread - pub fn set_if_uninitialized(&mut self, tid: Tid) -> bool { - if self.0 == None { - self.0 = Some(tid as usize); - true - } else { - false - } - } - pub fn get(&self) -> usize { - self.0.unwrap() + self.0 } /// Return whether this pid represents the init process pub fn is_init(&self) -> bool { - self.0 == Some(0) + self.0 == 0 } } impl fmt::Display for Pid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.0 { - Some(pid) => write!(f, "{}", pid), - None => write!(f, "None"), - } + write!(f, "{}", self.0) } } @@ -103,21 +85,9 @@ impl rcore_thread::Context for Thread { } fn set_tid(&mut self, tid: Tid) { - // set pid=tid if unspecified let mut proc = self.proc.lock(); - if proc.pid.set_if_uninitialized(tid) { - // first thread in the process - // link to its ppid - if let Some(parent) = &proc.parent { - let mut parent = parent.lock(); - parent.children.push(Arc::downgrade(&self.proc)); - } - } // add it to threads proc.threads.push(tid); - PROCESSES - .write() - .insert(proc.pid.get(), Arc::downgrade(&self.proc)); } } @@ -140,18 +110,19 @@ impl Thread { kstack, clear_child_tid: 0, // TODO: kernel thread should not have a process - proc: Arc::new(Mutex::new(Process { + proc: Process { vm, files: BTreeMap::default(), cwd: String::from("/"), futexes: BTreeMap::default(), - pid: Pid::uninitialized(), + pid: Pid(0), parent: None, children: Vec::new(), threads: Vec::new(), child_exit: Arc::new(Condvar::new()), child_exit_code: BTreeMap::new(), - })), + } + .add_to_table(), }) } @@ -290,18 +261,19 @@ impl Thread { }, kstack, clear_child_tid: 0, - proc: Arc::new(Mutex::new(Process { + proc: Process { vm, files, cwd: String::from("/"), futexes: BTreeMap::default(), - pid: Pid::uninitialized(), + pid: Pid(0), parent: None, children: Vec::new(), threads: Vec::new(), child_exit: Arc::new(Condvar::new()), child_exit_code: BTreeMap::new(), - })), + } + .add_to_table(), }) } @@ -330,18 +302,19 @@ impl Thread { context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) }, kstack, clear_child_tid: 0, - proc: Arc::new(Mutex::new(Process { + proc: Process { vm, files, cwd, futexes: BTreeMap::default(), - pid: Pid::uninitialized(), + pid: Pid(0), parent, children: Vec::new(), threads: Vec::new(), child_exit: Arc::new(Condvar::new()), child_exit_code: BTreeMap::new(), - })), + } + .add_to_table(), }) } @@ -365,9 +338,39 @@ impl Thread { } impl Process { - pub fn get_free_fd(&self) -> usize { + /// Assign a pid and put itself to global process table. + fn add_to_table(mut self) -> Arc> { + let mut process_table = PROCESSES.write(); + + // assign pid + let pid = (0..) + .find(|i| match process_table.get(i) { + Some(p) if p.upgrade().is_some() => false, + _ => true, + }) + .unwrap(); + self.pid = Pid(pid); + + // put to process table + let self_ref = Arc::new(Mutex::new(self)); + process_table.insert(pid, Arc::downgrade(&self_ref)); + + // link to parent + if let Some(parent) = &self_ref.lock().parent { + parent.lock().children.push(Arc::downgrade(&self_ref)); + } + + self_ref + } + fn get_free_fd(&self) -> usize { (0..).find(|i| !self.files.contains_key(i)).unwrap() } + /// Add a file to the process, return its fd. + pub fn add_file(&mut self, file_like: FileLike) -> usize { + let fd = self.get_free_fd(); + self.files.insert(fd, file_like); + fd + } pub fn get_futex(&mut self, uaddr: usize) -> Arc { if !self.futexes.contains_key(&uaddr) { self.futexes.insert(uaddr, Arc::new(Condvar::new())); diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 757f4e0..e80cd39 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -277,10 +277,8 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) -> proc.lookup_inode_at(dir_fd, &path, true)? }; - let fd = proc.get_free_fd(); - let file = FileHandle::new(inode, flags.to_options()); - proc.files.insert(fd, FileLike::File(file)); + let fd = proc.add_file(FileLike::File(file)); Ok(fd) } @@ -636,9 +634,7 @@ pub fn sys_pipe(fds: *mut u32) -> SysResult { proc.vm.check_write_array(fds, 2)?; let (read, write) = Pipe::create_pair(); - let read_fd = proc.get_free_fd(); - proc.files.insert( - read_fd, + let read_fd = proc.add_file( FileLike::File(FileHandle::new( Arc::new(read), OpenOptions { @@ -649,9 +645,7 @@ pub fn sys_pipe(fds: *mut u32) -> SysResult { )), ); - let write_fd = proc.get_free_fd(); - proc.files.insert( - write_fd, + let write_fd = proc.add_file( FileLike::File(FileHandle::new( Arc::new(write), OpenOptions { diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index 1372340..34ebb14 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -39,8 +39,7 @@ pub fn sys_socket(domain: usize, socket_type: usize, protocol: usize) -> SysResu }, _ => return Err(SysError::EAFNOSUPPORT), }; - let fd = proc.get_free_fd(); - proc.files.insert(fd, FileLike::Socket(socket)); + let fd = proc.add_file(FileLike::Socket(socket)); Ok(fd) } @@ -237,8 +236,7 @@ pub fn sys_accept(fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResu let socket = proc.get_socket(fd)?; let (new_socket, remote_endpoint) = socket.accept()?; - let new_fd = proc.get_free_fd(); - proc.files.insert(new_fd, FileLike::Socket(new_socket)); + let new_fd = proc.add_file(FileLike::Socket(new_socket)); if !addr.is_null() { let sockaddr_in = SockAddr::from(remote_endpoint); diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index f0fc954..046391b 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -6,7 +6,8 @@ use crate::fs::INodeExt; /// Fork the current process. Return the child's PID. pub fn sys_fork(tf: &TrapFrame) -> SysResult { let new_thread = current_thread().fork(tf); - let pid = processor().manager().add(new_thread); + let pid = new_thread.proc.lock().pid.get(); + processor().manager().add(new_thread); info!("fork: {} -> {}", thread::current().id(), pid); Ok(pid) } From 88b54fdacdf5f24c965ad71574b526c7d9cbca07 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Fri, 26 Apr 2019 14:13:07 +0800 Subject: [PATCH 38/61] fix unknow bug: change busybox from docker, maintain the PATH env vars --- kernel/src/shell.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index e40911b..f604729 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -9,11 +9,17 @@ use alloc::vec::Vec; #[cfg(not(feature = "run_cmdline"))] pub fn run_user_shell() { - #[cfg(target_arch = "x86_64")] - let init_shell="/bin/busybox"; - - #[cfg(not(target_arch = "x86_64"))] - let init_shell="/busybox"; +/// the busybox of alpine linux can not transfer env vars into child process +/// Now we use busybox from +/// https://raw.githubusercontent.com/docker-library/busybox/82bc0333a9ae148fbb4246bcbff1487b3fc0c510/musl/busybox.tar.xz -O busybox.tar.xz +/// This one can transfer env vars! +/// Why??? + +// #[cfg(target_arch = "x86_64")] +// let init_shell="/bin/busybox"; // from alpine linux +// +// #[cfg(not(target_arch = "x86_64"))] + let init_shell="/busybox"; //from docker-library #[cfg(target_arch = "x86_64")] let init_envs=vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()]; From 1974cc585323196bbf44f838d165402d6ecd126d Mon Sep 17 00:00:00 2001 From: chyyuu Date: Fri, 26 Apr 2019 18:57:54 +0800 Subject: [PATCH 39/61] add syscall: sys_getrandom for python3, etc. --- kernel/src/syscall/misc.rs | 15 +++++++++++++++ kernel/src/syscall/mod.rs | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs index ac3ff39..a5367e1 100644 --- a/kernel/src/syscall/misc.rs +++ b/kernel/src/syscall/misc.rs @@ -201,3 +201,18 @@ pub struct RLimit { cur: u64, // soft limit max: u64, // hard limit } + +pub fn sys_getrandom( buf: *mut u8, len: usize, flag: u32) -> SysResult { + + //info!("getrandom: buf: {:?}, len: {:?}, falg {:?}", buf, len,flag); + let mut proc = process(); + proc.vm.check_write_array(buf, len)?; + let slice = unsafe { slice::from_raw_parts_mut(buf, len) }; + let mut i=0; + for elm in slice { + unsafe{ *elm=i+ crate::trap::TICK as u8;} + i+=1; + } + + Ok(len) +} \ No newline at end of file diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index ba267b7..4a5f6c1 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -230,7 +230,9 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { // custom SYS_MAP_PCI_DEVICE => sys_map_pci_device(args[0], args[1]), SYS_GET_PADDR => sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2]), - + //SYS_GETRANDOM => unimplemented("getrandom", Err(SysError::EINVAL)), + SYS_GETRANDOM =>sys_getrandom( args[0] as *mut u8, args[1] as usize, args[2] as u32), + SYS_TKILL => unimplemented("tkill", Ok(0)), _ => { let ret = match () { #[cfg(target_arch = "x86_64")] From c853eda9b3f05685f29290913cbf8e639b47aedb Mon Sep 17 00:00:00 2001 From: chyyuu Date: Fri, 26 Apr 2019 18:58:42 +0800 Subject: [PATCH 40/61] disable so many wait4 LOG info --- kernel/src/syscall/proc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 046391b..c58f8b8 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -62,7 +62,7 @@ pub fn sys_clone( /// Wait for the process exit. /// Return the PID. Store exit code to `wstatus` if it's not null. pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult { - info!("wait4: pid: {}, code: {:?}", pid, wstatus); + //info!("wait4: pid: {}, code: {:?}", pid, wstatus); if !wstatus.is_null() { process().vm.check_write_ptr(wstatus)?; } From 28dbfd66b9c3a2c1b2d383be41c127457e607a07 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Sat, 27 Apr 2019 15:57:34 +0800 Subject: [PATCH 41/61] add more comments and CHANGE Fn name: run_user_shell TO add_user_shell --- .../src/arch/x86_64/interrupt/fast_syscall.rs | 6 ++--- kernel/src/arch/x86_64/mod.rs | 19 +++++++++++----- kernel/src/memory.rs | 22 +++++++++++++++---- kernel/src/process/mod.rs | 2 +- kernel/src/shell.rs | 4 ++-- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/kernel/src/arch/x86_64/interrupt/fast_syscall.rs b/kernel/src/arch/x86_64/interrupt/fast_syscall.rs index 69170ac..89ff76f 100644 --- a/kernel/src/arch/x86_64/interrupt/fast_syscall.rs +++ b/kernel/src/arch/x86_64/interrupt/fast_syscall.rs @@ -10,9 +10,9 @@ pub fn init() { *flags |= EferFlags::SYSTEM_CALL_EXTENSIONS; }); - let mut star = Msr::new(0xC0000081); - let mut lstar = Msr::new(0xC0000082); - let mut sfmask = Msr::new(0xC0000084); + let mut star = Msr::new(0xC0000081); // legacy mode SYSCALL target + let mut lstar = Msr::new(0xC0000082); // long mode SYSCALL target + let mut sfmask = Msr::new(0xC0000084); // EFLAGS mask for syscall // flags to clear on syscall // copy from Linux 5.0 diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 4b5f56c..bec0e26 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -40,26 +40,33 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { memory::init(boot_info); // Now heap is available - gdt::init(); + // Init GDT + gdt::init(); + //get local apic id of cpu cpu::init(); - + // Use IOAPIC instead of PIC, use APIC Timer instead of PIT, init serial&keyboard in x86_64 driver::init(); - + // init pci/bus-based devices ,e.g. Intel 10Gb NIC, ... crate::drivers::init(); - + // init cpu scheduler and process manager, and add user shell app in process manager crate::process::init(); - + //wake up other CPUs AP_CAN_INIT.store(true, Ordering::Relaxed); - + //call the first main function in kernel. crate::kmain(); } /// The entry point for other processors fn other_start() -> ! { + // Init trap handling. idt::init(); + // init gdt gdt::init(); + // init local apic cpu::init(); + // setup fast syscall in xv6-64 interrupt::fast_syscall::init(); + //call the first main function in kernel. crate::kmain(); } diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index 482f96e..fa0c2dc 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -1,3 +1,17 @@ +//! Define the FrameAllocator for physical memory +//! x86_64 -- 64GB +//! AARCH64/MIPS/RV -- 1GB +//! K210(rv64) -- 8MB +//! NOTICE: +//! type FrameAlloc = bitmap_allocator::BitAllocXXX +//! KSTACK_SIZE -- 16KB +//! +//! KERNEL_HEAP_SIZE: +//! x86-64 -- 32MB +//! AARCH64/RV64 -- 8MB +//! MIPS/RV32 -- 2MB +//! mipssim/malta(MIPS) -- 10MB + use super::HEAP_ALLOCATOR; pub use crate::arch::paging::*; use crate::consts::MEMORY_OFFSET; @@ -85,17 +99,17 @@ pub fn dealloc_frame(target: usize) { } pub struct KernelStack(usize); -const STACK_SIZE: usize = 0x4000; +const KSTACK_SIZE: usize = 0x4000; //16KB impl KernelStack { pub fn new() -> Self { use alloc::alloc::{alloc, Layout}; let bottom = - unsafe { alloc(Layout::from_size_align(STACK_SIZE, STACK_SIZE).unwrap()) } as usize; + unsafe { alloc(Layout::from_size_align(KSTACK_SIZE, KSTACK_SIZE).unwrap())} as usize; KernelStack(bottom) } pub fn top(&self) -> usize { - self.0 + STACK_SIZE + self.0 + KSTACK_SIZE } } @@ -105,7 +119,7 @@ impl Drop for KernelStack { unsafe { dealloc( self.0 as _, - Layout::from_size_align(STACK_SIZE, STACK_SIZE).unwrap(), + Layout::from_size_align(KSTACK_SIZE, KSTACK_SIZE).unwrap(), ); } } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 516d29e..d9908a9 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -20,7 +20,7 @@ pub fn init() { } } - crate::shell::run_user_shell(); + crate::shell::add_user_shell(); info!("process: init end"); } diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index f604729..fc4bdce 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -8,7 +8,7 @@ use alloc::vec::Vec; #[cfg(not(feature = "run_cmdline"))] -pub fn run_user_shell() { +pub fn add_user_shell() { /// the busybox of alpine linux can not transfer env vars into child process /// Now we use busybox from /// https://raw.githubusercontent.com/docker-library/busybox/82bc0333a9ae148fbb4246bcbff1487b3fc0c510/musl/busybox.tar.xz -O busybox.tar.xz @@ -43,7 +43,7 @@ pub fn run_user_shell() { } #[cfg(feature = "run_cmdline")] -pub fn run_user_shell() { +pub fn add_user_shell() { let cmdline = CMDLINE.read(); let inode = ROOT_INODE.lookup(&cmdline).unwrap(); let data = inode.read_as_vec().unwrap(); From d55a93172d12fc3f7ab0495c31ecb8fbaa0e65cb Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 27 Apr 2019 21:14:54 +0800 Subject: [PATCH 42/61] Use a patched version of opensbi fu540.elf --- tools/opensbi/README.md | 10 ++++------ tools/opensbi/fu540.elf | Bin 359536 -> 363424 bytes 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/opensbi/README.md b/tools/opensbi/README.md index 2546f40..a992b69 100644 --- a/tools/opensbi/README.md +++ b/tools/opensbi/README.md @@ -2,14 +2,12 @@ These are binary release of OpenSBI on this [commit](https://github.com/riscv/opensbi/tree/194dbbe5a13dff2255411c26d249f3ad4ef42c0b) at 2019.04.15. -- fu540.elf: opensbi-0.3-rv64-bin/platform/sifive/fu540/firmware/fw_jump.elf - virt_rv32.elf: opensbi-0.3-rv32-bin/platform/qemu/virt/firmware/fw_jump.elf - virt_rv64.elf: opensbi-0.3-rv64-bin/platform/qemu/virt/firmware/fw_jump.elf -NOTE: The [official v0.3 release](https://github.com/riscv/opensbi/releases/tag/v0.3) has bug on serial interrupt. +NOTE: The [official v0.3 release](https://github.com/riscv/opensbi/releases/tag/v0.3) has bug on serial interrupt. Also, Rocket-Chip based CPUs (including SiFive Unleashed) seem to have unintended behavior on +For K210 & SiFive Unleashed: It needs some modification. The binary is from this [commit](https://github.com/rcore-os/opensbi/commit/a9638d092756975ceb50073d736a17cef439c7b6). - -For K210: It needs some modification. The binary is from this [commit](https://github.com/rcore-os/opensbi/commit/4400a1a7d40b5399b3e07b4bad9fd303885c8c16). - -* k210.elf: build/platform/kendryte/k210/firmware/fw_payload.elf \ No newline at end of file +* k210.elf: build/platform/kendryte/k210/firmware/fw_payload.elf +* fu540.elf: build/platform/sifive/fu540/firmware/fw_jump.elf diff --git a/tools/opensbi/fu540.elf b/tools/opensbi/fu540.elf index 4b76fae3fa3f33f996a051d197eba6b973d5bd53..5aeeb11873bd88053f51c519003f2dc1db4c6650 100755 GIT binary patch delta 94659 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 z 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 CnD;RN delta 95465 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 Date: Sat, 27 Apr 2019 23:01:44 +0800 Subject: [PATCH 43/61] Add initial support for Rocket Chip platform --- kernel/Cargo.toml | 1 + kernel/Makefile | 3 ++- kernel/src/arch/riscv32/memory.rs | 2 ++ kernel/src/arch/riscv32/mod.rs | 3 ++- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 74a7eb4..9e9791e 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -24,6 +24,7 @@ default = ["sv39"] sv39 = [] board_u540 = ["sv39", "link_user"] board_k210 = ["sv39", "link_user"] +board_rocket_chip = ["sv39", "link_user"] # (for aarch64 RaspberryPi3) nographic = [] board_raspi3 = ["bcm2837", "link_user"] diff --git a/kernel/Makefile b/kernel/Makefile index edb5858..59fb48b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -26,6 +26,7 @@ # | pc Only available on x86_64, run on real pc # | u540 Only available on riscv64, run on HiFive U540, use Sv39 # | k210 Only available on riscv64, run on K210, use Sv39 +# | rocket_chip Only available on riscv64, run on Rocket Chip, use Sv39 # | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ # pci_passthru = 0000:00:00.1 Only available on x86_64, passthrough the specified PCI device # init = /bin/ls Only available on riscv64, run specified program instead of user shell @@ -60,7 +61,7 @@ ifeq ($(arch), $(filter $(arch), aarch64 mipsel)) export SFSIMG = $(user_dir)/build/$(arch).img else # board is pc or qemu? -ifeq ($(board), $(filter $(board), pc u540 k210)) +ifeq ($(board), $(filter $(board), pc u540 k210 rocket_chip)) #link user img, so use original image export SFSIMG = $(user_dir)/build/$(arch).img else diff --git a/kernel/src/arch/riscv32/memory.rs b/kernel/src/arch/riscv32/memory.rs index ef0509b..314c7f2 100644 --- a/kernel/src/arch/riscv32/memory.rs +++ b/kernel/src/arch/riscv32/memory.rs @@ -92,6 +92,8 @@ fn remap_the_kernel(dtb: usize) { Linear::new(offset), "bss", ); + // TODO: dtb on rocket chip + #[cfg(not(feature = "board_rocket_chip"))] ms.push( dtb, dtb + super::consts::MAX_DTB_SIZE, diff --git a/kernel/src/arch/riscv32/mod.rs b/kernel/src/arch/riscv32/mod.rs index f05a082..75b7ccc 100644 --- a/kernel/src/arch/riscv32/mod.rs +++ b/kernel/src/arch/riscv32/mod.rs @@ -53,10 +53,11 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! { memory::init(device_tree_vaddr); timer::init(); // FIXME: init driver on u540 - #[cfg(not(feature = "board_u540"))] + #[cfg(not(any(feature = "board_u540", feature = "board_rocket_chip")))] crate::drivers::init(device_tree_vaddr); #[cfg(not(feature = "board_k210"))] unsafe { + #[cfg(not(feature = "board_rocket_chip"))] board::enable_serial_interrupt(); board::init_external_interrupt(); } From cd2c78dd46ec8c60b24aaec24aab7a729e478d8d Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 27 Apr 2019 23:04:10 +0800 Subject: [PATCH 44/61] Add Rocket Chip platform in README --- README.md | 2 +- crate/memory/src/memory_set/mod.rs | 3 +- kernel/src/arch/riscv32/boot/linker64.ld | 49 ++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 kernel/src/arch/riscv32/boot/linker64.ld diff --git a/README.md b/README.md index 7c5d6bd..35f5a35 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Going to be the next generation teaching operating system. Supported architectures: x86_64, RISCV32/64, AArch64, MIPS32 -Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+ +Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+, Kendryte K210 and FPGA running Rocket Chip ![demo](./docs/2_OSLab/os2atc/demo.png) diff --git a/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index 94d8765..4f0f9a5 100644 --- a/crate/memory/src/memory_set/mod.rs +++ b/crate/memory/src/memory_set/mod.rs @@ -58,7 +58,8 @@ impl MemoryArea { fn check_read_array(&self, ptr: *const S, count: usize) -> bool { // page align ptr as usize >= Page::of_addr(self.start_addr).start_address() - && unsafe { ptr.add(count) as usize } < Page::of_addr(self.end_addr + PAGE_SIZE - 1).start_address() + && unsafe { ptr.add(count) as usize } + < Page::of_addr(self.end_addr + PAGE_SIZE - 1).start_address() } /// Check the array is within the writable memory fn check_write_array(&self, ptr: *mut S, count: usize) -> bool { diff --git a/kernel/src/arch/riscv32/boot/linker64.ld b/kernel/src/arch/riscv32/boot/linker64.ld new file mode 100644 index 0000000..87ca826 --- /dev/null +++ b/kernel/src/arch/riscv32/boot/linker64.ld @@ -0,0 +1,49 @@ +/* Copy from bbl-ucore : https://ring00.github.io/bbl-ucore */ + +/* Simple linker script for the ucore kernel. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_ARCH(riscv) +ENTRY(_start) + +BASE_ADDRESS = 0xffffffffc0200000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text : { + stext = .; + *(.text.entry) + *(.text .text.*) + . = ALIGN(4K); + etext = .; + } + + .rodata : { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data : { + sdata = .; + *(.data .data.*) + edata = .; + } + + .stack : { + *(.bss.stack) + } + + .bss : { + sbss = .; + *(.bss .bss.*) + ebss = .; + } + + PROVIDE(end = .); +} From 1219204d30e50a5d434295607e7e2f177baa58e2 Mon Sep 17 00:00:00 2001 From: chyyuu Date: Sun, 28 Apr 2019 00:11:54 +0800 Subject: [PATCH 45/61] add figure for some important rcore structures --- docs/rcore-structures.drawio | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/rcore-structures.drawio diff --git a/docs/rcore-structures.drawio b/docs/rcore-structures.drawio new file mode 100644 index 0000000..602cca0 --- /dev/null +++ b/docs/rcore-structures.drawio @@ -0,0 +1 @@ +7V1bc6M6Ev4t++Cq5CEu7uDHJDM5u7XJTiqec3tyEVu22WBgBZ4k59evJCRuEjZ2EMycUSo1E4QAof7UdH9qtSbm7e7tF+gn24d4BcKJoa3eJuaniWHouu6g/3DJOy2xXVqygcGKlpUF8+AvQAs1WroPViCtVcziOMyCpF64jKMILLNamQ9h/Fqvto7D+lMTfwO4gvnSD/nS34NVtmUvpmnliX+CYLOlj/ZseuLZX75sYLyP6PMmhrkmP/npnc/uReunW38Vv1aKzM8T8xbGcZb/tXu7BSHuXNZt+XV3LWeLdkMQZV0uMENrD93Zqx8tzLvb7Zsf31tXhp3f5psf7mmHPMJ4CdI0hhPzGv3CZQzBVbaFwEc3uk7Y2SlM6Xtl76wv09dgF/oROrpZx1E2p2c0dLzcBuHq3n+P97ixaYY6jx3dbGMY/IXq+yE6paMCdBpmFCqGg+8WhOFtHOI2fYpi8oDyojm+GX0MBCm67JF1it4oevDfahXv/TRjDYzD0E/S4Jk0GV+48+EmiG7iLIt3tBLtLAAz8NYqBr0QLho1IN6BDL6jKvQC06F4YAPGs/Lj1xJ9xeDYVoBnGxT0FPCb4tal0NEfVO6nYMBpwUAM/4XGHOTEjF4+I1KC8QtoiEUgKT8MNhE6DMEaX4Z7L0Dj75oWZ3GCb5b4yyDa3JM6n6yy5In2AC6K0bXrkAyibbBagQgLMs78zH8ugJbEQZSRLrJv0C/qyFttak9s1PBbdKyXx+gXV4fZbRyhd/EDIkCAIPEKMCy6SfvAsOIxQGXOevyYyFm9/kU+ax/2uczV2Jcw9h2jMfZtjweCJQCCbmqSkMBuXEECrn+Niva4l9TgP33wz04e/CKZSxv8ps6JHI/sXOgXX9G1qLMM7SZ+mxhOiPsC9RERu+Fs8OGlAkXfoGAf9/FAYXCgCOM4WSyp6Ak42iGhENE3ItyOnwZpiLD4L8POj5A3BHMwIOuAgeErsRAekdum8CALD7om8BOGVREmJ1WwQr40PUSdso03ceSHn8vSG+IggxXt6LLOfYxFSGyt/4Ise6cWn7/PYmzgZTtmD4K3IPuj8vef+FZIGPnRJ2bTkYN3dhCh98UXXWlTTbNZSX6pbrHj8mJyVLv6EcAAdRsGe8X6w+972PZD3RPv4RIcEjQVEDJ0N+AcREAQ+lnwrd6S/sXNUwNsvKNhFpUjPS97ZgWPT19uP8/nX57muZ5AA6hCKaD62sP1H4vbx18X//n1gYwxegPI7kD9DNzqeEV8jWYNVoKqPAvK6u1rYLaCrR5MerODNz8TjFJT2ijlvflfwvjZxxf+5sMAqz3ee6PqudI3p2rqJeowPFo4Xb1DWpeogtdtkIE50tD4ma/QTzj10IM8ZnV5eDYnDk+kM6W5V65gEDWVaLS6xkRm2acrP92STtEbupDpNW3qaVZVrelTzXPO0WtMvWK96NVUrGaYh5UsOpCoJS1GBh/Tkm4LICoit0V0Gi3rrEzpEx6xrVAZ/3YdcIbbgFL+ovSqKj175Ea67tVvlHcEdyMCy+K1P4BU7xykCsFZ/94a9jFcCr/wxuFPfI9IYx+649/jFlZvGKQZM7sGkAIwJyPNatxIa9xIMtIcaxQ7stSddYPwCDrHUGmOOabhZ/H8UMXBI8QwfglStEhQmaKDz7NVXLeu8osRXTUeTREdzHzB/mXP00C5oNNc6r+Bwul/2OM3pwdfkiyIozofUDHMG/8rbuBEbsBqAdIBSlmEG3lckcnBJl0iE3YfMraoQh3OizMKEJIAIaKThwWExesR5ClQMNRUx1dSTg8+f8PvrRSGZHyIyOVB8eG6o9qAxUGFTRzIBuxK/rkftQHJpchd898rFSg4W50MXWuEpzi6fdCZ4C7Qda2BjrwNvboQFk9y4fGTTW6NybVW/cBMDFMnIuQDGoy7sl7BNCoz9mQz1tPqCLA7m7HSohosnnZL9un2AgHC3xFtD8J1Ps2dsXCHr8FKTWyf8aVxvnPTlOe1kjgRIWGZ7Be12BcEB+2qNEK0hpMTrJSBIgs24xuwfIQcksmLEDd7iF920dAkNeg8k7lxhZJ+UTK6GWvzc6QpyBYJDNC3PHs/9r3JS1htqnk89RXqHSjC4IlhkeKM6vCMSHqbHR2eNhEOQ3ozKnac4BZt6rLprj8rp45Et2jTmebUxDrVNPeIaGVHt9huR3k7o8rb5j0Exlprao5j0ptzaDcCMmyTdw51UUiGPOfQ5j0CJIFsT6c45vnf6ht86jc4H1KneIJCwcv7BPMmfS73hb9GqnCREqEoCMiDgMCrGxYCjKusQODVDzI2L6Ec/MGgIHDdBoYCH+VQW+tQx8KhlQ8KInIgInLaBsaI8bM6bUZHI75NhMMY8Q4fdsBGaQJBMzB8FXyrydL53x6vvb/BA/WKDj888skILM4275LHlgtug12Aq7W/C0LK5BTkz8QwTTwwtyD8BvCo5s4QpwP/S2Kkr9I8SBrfJIpJpDTXHBDtd/kzxEHv31Vj6ay+NnHbo/SLYiIm0Wv8jaX5u/8C9smPIcyLnN7+EZpK+NUz8NZS+W8FuYn76dy+qenWxvex39U1rlsPVbY8gdkoTJYhizxw7FFMgo8sgkMVraodQRbFmUeMCdk0IVu5eJwWbkHIMBaGro0TqFTwwkaVF9a6CfzE6KaqM4KTGHlLsFxOmp4LOnN3Z6KffnHgdI2H8j6Kg7PioWwWScLCoZpJlo7UZ3RnW/3m+sFT61t5mJjcaCunLdoK9T4OqFoUGWLQ723pRCsOvZ+voOXVhe5q/KrGYt1Z9SvoNpaQCRYZPYFl5kcb9AYlhhuPYyGAJ/vhfog+HZGfgRusD1NOGfcBTX4aZ02sq9cgW24XSK8qWuZUWqZtYu5ARJcIfPJYGX7+Jpc5IDE4ZdDFbp+RYhZ60YzQUcjoFxmioK1BkeEKOF2I9E/+MWJpBchBEAXZxaXIg+GXwvegwhuzoFc6K6jqVEPQV9JmQd2flztL9s+kFXC/zH4YDu3pqRLWrpi0tm4K8oyVP4JE62uh8ruFDVHTBJz0bBeS6nt5OUW9/eDUW2NdjyCTiqEJPljSmDf3rAQVbalUJv1RGJ3zR4ybqURvrjZvmhZd80cU2XKYQ+A1biQ5f4TLx/F8AAgF1TY5g1odbx2h2zWsdlzQGZo99czyh5n+bIp/1khk0BmDjjutTw0g63mqVX70Rlslg3I24zH4fc4L9AhCr6vm8z4a69ui0vS6JrI1pxOcTmWBmxrPoiyvVNbVa0vDUlCrZZ683JdJFcF6nq1jtHwZq865kMjwZDEZnsEJvxadVgShKQ7rRA6rbR7pQJTyoByWx/MyL2k+mrDg/w1gBOjwUsLvWfii+ORhhc+nTVmGwIcLoqpL/lql5pcif1FQ8rDy59eTlqn5Kwm3awl0HpkZoAKS5cJDGJA8KD50gzcK1Xxnyii89lgVGWjobCXKQwNvJVZnQhUWBsOCPbbZqBu83UiwEIHXxQsxGn9aOMgTO3PTRhQ7bzEUYt+navM2CR6iNraVqAt27CNCX8dQeYX9C9wc3+zjpzyIwJchFpqSeO8k0NimnceP8Mdq+JJifyf9bRlSn0hybNFGSzYvfIutkuxf+nxU67cdDRcBuxi+z4Gifs8Y9acHtorkLm/QCwJbA7xbT55B+ysE4MEvVglSDhAHtt6hWvfBS3toiMLGB7Eh3J9xUGzwFsDydcXSlUDU7UrofQtduAXjkEJnQcJVhYCZ3w4qoUIWo35bffOh4odl40W8ReOggOEJwTzYOWEzR48/MS0oT/ACKnhgwfPsH3spPpnNyRNJSmFIwo2ANh4YN4IJZ+wXQhBxG/78DvwXhZvvAjcC3nlg3PC0c9s+USqNmkyfVUBGD4wEnqnKg1Vw0CkXuMDZogoQPQNCQFYPDAievCoBsVjGK3DUeaF/KozIIrrGNlcLg7k5oeGvVossXuQ9qgTft+C9se1N3WwJYNqAbLFGCmGxVv5p73I39bHtRd3kmYliwGOSWwm9d6GbY5uGutkSk6SELk3oztjmn27ylEKp4XPaQEm9Z6kLsokMLfWWODQSobJYxxCZ/5gTUKLvV/SWPrpJp/G2/IFMMjgMpYaBWg4G4vgR91A3krf2TA7PrODx6cvt5/n88zy/6un1PsYro6rpNCqOZqW04m5SYrNyUpCUoyQ567k4Dh2xrA3PzeajsrwfDid4GKoTxaFEH25+Y6z3m5+isfTXYIkXK+PAEiVUYvtRSRgHvGvD9QGfl0Cc+N1zahs76dPjCVuLlKHezJlUl4NrmjE5mM0AHTQzvcpO/8oc0aMrx6l24WEwTP4C07WQLAzNQZ1q27pr1EBnzvSpYZfnjQa2umYzsBx7WnmGddpTJGc20DU+LKmZ5NOHyy26+ZvnLLABeoeaAiDcJ6hBd+hzmKyhvwMqPvE8TWfY9QBFk6W2qAwBU5QEu5gmkqDrWgKS83Voh1Iw0gFfS7KU15qjWior4+kWIh2gp8Q1CuEiz0LUW9jeaB+GF5f5pu3V3XLnBC95kjuW6uBCuyRFnxRCekeIILpxaIS00MJsGRNLMa1k37fsBUGOQ8u+hRrGslcrmqQIXRSpOLTUD6xXVcuaJIldEKc4tNgPsMM4J/MiW9d3TVcWoQQcCOIOh8bBj7ePzlVBpVT223YLnmakjXSYj9eBSWkBhdwdVJpEnenMqug5Xp+ucJeaa09nLPpoOz3W+T4MNX3sLZpYqIb8ndzPApajNRhgwzwIrGZ90zm81Y7D9gkX15cFxHH3mzpBL/aJtK46bBykNTfEMazZEEjgKbZ8LU9OtL2nxDm6yNYNMi3/9yv0kzvMumLW5Ko5M6XN39MnkO7DYlfOYheEZ1iZ1skvip7TPOG51q0oxKuTiSHPvHaNtF9b7iEGBy2+uJzSN7gsbtVvE/CqJ/bssjlTPN01DePlC2oBqjJFmLvovwl0Ui2G6Ck7P/I3AP/lr1YXZVP6f2oQreN/XFQnBCHNHInFjNkzARrYqXKiEHO11V29qOTQCwRIbvn5JJDQ/i8vF0llf9HKHduZv34nFpv5AK5Mjfeaig1danw7M10khFfwUfbF/iWPSCRkNvuyvs8Nm81V8y7nAcG06mrftvl5F+EWCIe2XfsgDFq2O9uofBDnuMnm6QkhRPKWGFXVstVZkBKyRMm8d5mLEj0MK3Omdb5/ZqRHD4AtXD/OYrTJb6D9gK2zgnzaNh9p32K3LYVlSRnUiahjW48U8p1qmleTseaZB6UsCg/qU/Jd95AwR93IxG6wBzOrYet1jfVxGjv4mkbjRmeH86BDGGP7vayOnMDtQ7wCuMb/AQ== \ No newline at end of file From 58271c7c8a8f36913de4bcc134cc68cd0a99cca6 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 28 Apr 2019 15:55:45 +0800 Subject: [PATCH 46/61] convert user ptr to reference on check --- crate/memory/src/memory_set/mod.rs | 42 +++++++++--- kernel/src/syscall/custom.rs | 6 +- kernel/src/syscall/fs.rs | 106 +++++++++++++---------------- kernel/src/syscall/misc.rs | 63 +++++++---------- kernel/src/syscall/net.rs | 53 ++++++--------- kernel/src/syscall/proc.rs | 105 +++++++++++----------------- kernel/src/syscall/time.rs | 26 +++---- 7 files changed, 178 insertions(+), 223 deletions(-) diff --git a/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index 4f0f9a5..decd828 100644 --- a/crate/memory/src/memory_set/mod.rs +++ b/crate/memory/src/memory_set/mod.rs @@ -205,29 +205,55 @@ impl MemorySet { } } /// Check the pointer is within the readable memory - pub fn check_read_ptr(&self, ptr: *const S) -> VMResult<()> { - self.check_read_array(ptr, 1) + pub unsafe fn check_read_ptr(&self, ptr: *const S) -> VMResult<&'static S> { + self.check_read_array(ptr, 1).map(|s| &s[0]) } /// Check the pointer is within the writable memory - pub fn check_write_ptr(&self, ptr: *mut S) -> VMResult<()> { - self.check_write_array(ptr, 1) + pub unsafe fn check_write_ptr(&self, ptr: *mut S) -> VMResult<&'static mut S> { + self.check_write_array(ptr, 1).map(|s| &mut s[0]) } /// Check the array is within the readable memory - pub fn check_read_array(&self, ptr: *const S, count: usize) -> VMResult<()> { + pub unsafe fn check_read_array( + &self, + ptr: *const S, + count: usize, + ) -> VMResult<&'static [S]> { self.areas .iter() .find(|area| area.check_read_array(ptr, count)) - .map(|_| ()) + .map(|_| core::slice::from_raw_parts(ptr, count)) .ok_or(VMError::InvalidPtr) } /// Check the array is within the writable memory - pub fn check_write_array(&self, ptr: *mut S, count: usize) -> VMResult<()> { + pub unsafe fn check_write_array( + &self, + ptr: *mut S, + count: usize, + ) -> VMResult<&'static mut [S]> { self.areas .iter() .find(|area| area.check_write_array(ptr, count)) - .map(|_| ()) + .map(|_| core::slice::from_raw_parts_mut(ptr, count)) .ok_or(VMError::InvalidPtr) } + /// Check the null-end C string pointer array + /// Used for getting argv & envp + pub unsafe fn check_and_clone_cstr_array( + &self, + mut argv: *const *const u8, + ) -> VMResult> { + let mut args = Vec::new(); + loop { + let cstr = *self.check_read_ptr(argv)?; + if cstr.is_null() { + break; + } + let arg = self.check_and_clone_cstr(cstr)?; + args.push(arg); + argv = argv.add(1); + } + Ok(args) + } /// Check the null-end C string is within the readable memory, and is valid. /// If so, clone it to a String. /// diff --git a/kernel/src/syscall/custom.rs b/kernel/src/syscall/custom.rs index e21fa12..d774b91 100644 --- a/kernel/src/syscall/custom.rs +++ b/kernel/src/syscall/custom.rs @@ -43,10 +43,8 @@ pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { /// mapped to a list of virtual addresses. pub fn sys_get_paddr(vaddrs: *const u64, paddrs: *mut u64, count: usize) -> SysResult { let mut proc = process(); - proc.vm.check_read_array(vaddrs, count)?; - proc.vm.check_write_array(paddrs, count)?; - let vaddrs = unsafe { slice::from_raw_parts(vaddrs, count) }; - let paddrs = unsafe { slice::from_raw_parts_mut(paddrs, count) }; + let vaddrs = unsafe { proc.vm.check_read_array(vaddrs, count)? }; + let paddrs = unsafe { proc.vm.check_write_array(paddrs, count)? }; for i in 0..count { let paddr = proc.vm.translate(vaddrs[i] as usize).unwrap_or(0); paddrs[i] = paddr as u64; diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index e80cd39..1c005d9 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -21,8 +21,7 @@ pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { // we trust pid 0 process info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); } - proc.vm.check_write_array(base, len)?; - let slice = unsafe { slice::from_raw_parts_mut(base, len) }; + let slice = unsafe { proc.vm.check_write_array(base, len)? }; let file_like = proc.get_file_like(fd)?; let len = file_like.read(slice)?; Ok(len) @@ -34,8 +33,7 @@ pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { // we trust pid 0 process info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len); } - proc.vm.check_read_array(base, len)?; - let slice = unsafe { slice::from_raw_parts(base, len) }; + let slice = unsafe { proc.vm.check_read_array(base, len)? }; let file_like = proc.get_file_like(fd)?; let len = file_like.write(slice)?; Ok(len) @@ -47,9 +45,7 @@ pub fn sys_pread(fd: usize, base: *mut u8, len: usize, offset: usize) -> SysResu fd, base, len, offset ); let mut proc = process(); - proc.vm.check_write_array(base, len)?; - - let slice = unsafe { slice::from_raw_parts_mut(base, len) }; + let slice = unsafe { proc.vm.check_write_array(base, len)? }; let len = proc.get_file(fd)?.read_at(offset, slice)?; Ok(len) } @@ -60,9 +56,7 @@ pub fn sys_pwrite(fd: usize, base: *const u8, len: usize, offset: usize) -> SysR fd, base, len, offset ); let mut proc = process(); - proc.vm.check_read_array(base, len)?; - - let slice = unsafe { slice::from_raw_parts(base, len) }; + let slice = unsafe { proc.vm.check_read_array(base, len)? }; let len = proc.get_file(fd)?.write_at(offset, slice)?; Ok(len) } @@ -72,8 +66,8 @@ pub fn sys_ppoll(ufds: *mut PollFd, nfds: usize, timeout: *const TimeSpec) -> Sy let timeout_msecs = if timeout.is_null() { 1 << 31 // infinity } else { - proc.vm.check_read_ptr(timeout)?; - unsafe { (*timeout).to_msec() } + let timeout = unsafe { proc.vm.check_read_ptr(timeout)? }; + timeout.to_msec() }; drop(proc); @@ -89,9 +83,8 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu ufds, nfds, timeout_msecs ); } - proc.vm.check_write_array(ufds, nfds)?; - let polls = unsafe { slice::from_raw_parts_mut(ufds, nfds) }; + let polls = unsafe { proc.vm.check_write_array(ufds, nfds)? }; for poll in polls.iter() { if proc.files.get(&(poll.fd as usize)).is_none() { return Err(SysError::EINVAL); @@ -156,9 +149,9 @@ pub fn sys_select( let mut read_fds = FdSet::new(&proc.vm, read, nfds)?; let mut write_fds = FdSet::new(&proc.vm, write, nfds)?; let mut err_fds = FdSet::new(&proc.vm, err, nfds)?; - let timeout_msecs = if timeout as usize != 0 { - proc.vm.check_read_ptr(timeout)?; - unsafe { *timeout }.to_msec() + let timeout_msecs = if !timeout.is_null() { + let timeout = unsafe { proc.vm.check_read_ptr(timeout)? }; + timeout.to_msec() } else { // infinity 1 << 31 @@ -214,7 +207,7 @@ pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResul fd, iov_ptr, iov_count ); let mut proc = process(); - let mut iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, true)?; + let mut iovs = unsafe { IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, true)? }; // read all data to a buf let file_like = proc.get_file_like(fd)?; @@ -234,7 +227,7 @@ pub fn sys_writev(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResu fd, iov_ptr, iov_count ); } - let iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, false)?; + let iovs = unsafe { IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, false)? }; let buf = iovs.read_all_to_vec(); let len = buf.len(); @@ -315,12 +308,12 @@ pub fn sys_getcwd(buf: *mut u8, len: usize) -> SysResult { // we trust pid 0 process info!("getcwd: buf: {:?}, len: {:#x}", buf, len); } - proc.vm.check_write_array(buf, len)?; + let buf = unsafe { proc.vm.check_write_array(buf, len)? }; if proc.cwd.len() + 1 > len { return Err(SysError::ERANGE); } - unsafe { util::write_cstr(buf, &proc.cwd) } - Ok(buf as usize) + unsafe { util::write_cstr(buf.as_mut_ptr(), &proc.cwd) } + Ok(buf.as_ptr() as usize) } pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { @@ -330,19 +323,17 @@ pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { info!("fstat: fd: {}, stat_ptr: {:?}", fd, stat_ptr); let mut proc = process(); - proc.vm.check_write_ptr(stat_ptr)?; + let stat_ref = unsafe { proc.vm.check_write_ptr(stat_ptr)? }; let file = proc.get_file(fd)?; let stat = Stat::from(file.metadata()?); - unsafe { - stat_ptr.write(stat); - } + *stat_ref = stat; Ok(0) } pub fn sys_fstatat(dirfd: usize, path: *const u8, stat_ptr: *mut Stat, flags: usize) -> SysResult { let proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - proc.vm.check_write_ptr(stat_ptr)?; + let stat_ref = unsafe { proc.vm.check_write_ptr(stat_ptr)? }; let flags = AtFlags::from_bits_truncate(flags); info!( "fstatat: dirfd: {}, path: {:?}, stat_ptr: {:?}, flags: {:?}", @@ -351,9 +342,7 @@ pub fn sys_fstatat(dirfd: usize, path: *const u8, stat_ptr: *mut Stat, flags: us let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?; let stat = Stat::from(inode.metadata()?); - unsafe { - stat_ptr.write(stat); - } + *stat_ref = stat; Ok(0) } @@ -368,14 +357,13 @@ pub fn sys_readlink(path: *const u8, base: *mut u8, len: usize) -> SysResult { pub fn sys_readlinkat(dirfd: usize, path: *const u8, base: *mut u8, len: usize) -> SysResult { let proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - proc.vm.check_write_array(base, len)?; + let slice = unsafe { proc.vm.check_write_array(base, len)? }; info!("readlink: path: {:?}, base: {:?}, len: {}", path, base, len); let inode = proc.lookup_inode_at(dirfd, &path, false)?; if inode.metadata()?.type_ == FileType::SymLink { // TODO: recursive link resolution and loop detection - let mut slice = unsafe { slice::from_raw_parts_mut(base, len) }; - let len = inode.read_at(0, &mut slice)?; + let len = inode.read_at(0, slice)?; Ok(len) } else { Err(SysError::EINVAL) @@ -429,13 +417,13 @@ pub fn sys_getdents64(fd: usize, buf: *mut LinuxDirent64, buf_size: usize) -> Sy fd, buf, buf_size ); let mut proc = process(); - proc.vm.check_write_array(buf as *mut u8, buf_size)?; + let buf = unsafe { proc.vm.check_write_array(buf as *mut u8, buf_size)? }; let file = proc.get_file(fd)?; let info = file.metadata()?; if info.type_ != FileType::Dir { return Err(SysError::ENOTDIR); } - let mut writer = unsafe { DirentBufWriter::new(buf, buf_size) }; + let mut writer = DirentBufWriter::new(buf); loop { let name = match file.read_entry() { Err(FsError::EntryNotFound) => break, @@ -631,7 +619,7 @@ pub fn sys_pipe(fds: *mut u32) -> SysResult { info!("pipe: fds: {:?}", fds); let mut proc = process(); - proc.vm.check_write_array(fds, 2)?; + let fds = unsafe { proc.vm.check_write_array(fds, 2)? }; let (read, write) = Pipe::create_pair(); let read_fd = proc.add_file( @@ -656,10 +644,8 @@ pub fn sys_pipe(fds: *mut u32) -> SysResult { )), ); - unsafe { - fds.write(read_fd as u32); - fds.add(1).write(write_fd as u32); - } + fds[0] = read_fd as u32; + fds[1] = write_fd as u32; info!("pipe: created rfd: {} wfd: {}", read_fd, write_fd); @@ -690,8 +676,7 @@ pub fn sys_sendfile( let mut read_offset = if !offset_ptr.is_null() { unsafe { - (*proc_cell.get()).vm.check_read_ptr(offset_ptr)?; - offset_ptr.read() + *(*proc_cell.get()).vm.check_read_ptr(offset_ptr)? } } else { in_file.seek(SeekFrom::Current(0))? as usize @@ -880,18 +865,20 @@ pub struct LinuxDirent64 { name: [u8; 0], } -struct DirentBufWriter { +struct DirentBufWriter<'a> { + buf: &'a mut [u8], ptr: *mut LinuxDirent64, rest_size: usize, written_size: usize, } -impl DirentBufWriter { - unsafe fn new(buf: *mut LinuxDirent64, size: usize) -> Self { +impl<'a> DirentBufWriter<'a> { + fn new(buf: &'a mut [u8]) -> Self { DirentBufWriter { - ptr: buf, - rest_size: size, + ptr: buf.as_mut_ptr() as *mut LinuxDirent64, + rest_size: buf.len(), written_size: 0, + buf, } } fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> bool { @@ -1239,28 +1226,28 @@ pub struct IoVec { pub struct IoVecs(Vec<&'static mut [u8]>); impl IoVecs { - pub fn check_and_new( + pub unsafe fn check_and_new( iov_ptr: *const IoVec, iov_count: usize, vm: &MemorySet, readv: bool, ) -> Result { - vm.check_read_array(iov_ptr, iov_count)?; - let iovs = unsafe { slice::from_raw_parts(iov_ptr, iov_count) }.to_vec(); + let iovs = vm.check_read_array(iov_ptr, iov_count)?.to_vec(); // check all bufs in iov for iov in iovs.iter() { - if iov.len > 0 { - // skip empty iov - if readv { - vm.check_write_array(iov.base, iov.len)?; - } else { - vm.check_read_array(iov.base, iov.len)?; - } + // skip empty iov + if iov.len == 0 { + continue; + } + if readv { + vm.check_write_array(iov.base, iov.len)?; + } else { + vm.check_read_array(iov.base, iov.len)?; } } let slices = iovs .iter() - .map(|iov| unsafe { slice::from_raw_parts_mut(iov.base, iov.len) }) + .map(|iov| slice::from_raw_parts_mut(iov.base, iov.len)) .collect(); Ok(IoVecs(slices)) } @@ -1342,11 +1329,10 @@ impl FdSet { }) } else { let len = (nfds + FD_PER_ITEM - 1) / FD_PER_ITEM; - vm.check_write_array(addr, len)?; if len > MAX_FDSET_SIZE { return Err(SysError::EINVAL); } - let slice = unsafe { slice::from_raw_parts_mut(addr, len) }; + let slice = unsafe { vm.check_write_array(addr, len)? }; let bitset: &'static mut BitSlice = slice.into(); // save the fdset, and clear it diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs index a5367e1..79bda93 100644 --- a/kernel/src/syscall/misc.rs +++ b/kernel/src/syscall/misc.rs @@ -18,16 +18,16 @@ pub fn sys_arch_prctl(code: i32, addr: usize, tf: &mut TrapFrame) -> SysResult { } pub fn sys_uname(buf: *mut u8) -> SysResult { - info!("sched_uname: buf: {:?}", buf); + info!("uname: buf: {:?}", buf); let offset = 65; let strings = ["rCore", "orz", "0.1.0", "1", "machine", "domain"]; let proc = process(); - proc.vm.check_write_array(buf, strings.len() * offset)?; + let buf = unsafe { proc.vm.check_write_array(buf, strings.len() * offset)? }; for i in 0..strings.len() { unsafe { - util::write_cstr(buf.add(i * offset), &strings[i]); + util::write_cstr(&mut buf[i * offset], &strings[i]); } } Ok(0) @@ -39,22 +39,20 @@ pub fn sys_sched_getaffinity(pid: usize, size: usize, mask: *mut u32) -> SysResu pid, size, mask ); let proc = process(); - proc.vm.check_write_array(mask, size / size_of::())?; + let mask = unsafe { proc.vm.check_write_array(mask, size / size_of::())? }; // we only have 4 cpu at most. // so just set it. - unsafe { - *mask = 0b1111; - } + mask[0] = 0b1111; Ok(0) } pub fn sys_sysinfo(sys_info: *mut SysInfo) -> SysResult { let proc = process(); - proc.vm.check_write_ptr(sys_info)?; + let sys_info = unsafe { proc.vm.check_write_ptr(sys_info)? }; let sysinfo = SysInfo::default(); - unsafe { *sys_info = sysinfo }; + *sys_info = sysinfo; Ok(0) } @@ -74,13 +72,11 @@ pub fn sys_futex(uaddr: usize, op: u32, val: i32, timeout: *const TimeSpec) -> S if uaddr % size_of::() != 0 { return Err(SysError::EINVAL); } - process().vm.check_write_ptr(uaddr as *mut AtomicI32)?; - let atomic = unsafe { &mut *(uaddr as *mut AtomicI32) }; + let atomic = unsafe { process().vm.check_write_ptr(uaddr as *mut AtomicI32)? }; let _timeout = if timeout.is_null() { None } else { - process().vm.check_read_ptr(timeout)?; - Some(unsafe { *timeout }) + Some(unsafe { *process().vm.check_read_ptr(timeout)? }) }; const OP_WAIT: u32 = 0; @@ -156,38 +152,32 @@ pub fn sys_prlimit64( match resource { RLIMIT_STACK => { if !old_limit.is_null() { - proc.vm.check_write_ptr(old_limit)?; - unsafe { - *old_limit = RLimit { - cur: USER_STACK_SIZE as u64, - max: USER_STACK_SIZE as u64, - }; - } + let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? }; + *old_limit = RLimit { + cur: USER_STACK_SIZE as u64, + max: USER_STACK_SIZE as u64, + }; } Ok(0) } RLIMIT_NOFILE => { if !old_limit.is_null() { - proc.vm.check_write_ptr(old_limit)?; - unsafe { - *old_limit = RLimit { - cur: 1024, - max: 1024, - }; - } + let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? }; + *old_limit = RLimit { + cur: 1024, + max: 1024, + }; } Ok(0) } RLIMIT_RSS | RLIMIT_AS => { if !old_limit.is_null() { - proc.vm.check_write_ptr(old_limit)?; - unsafe { - // 1GB - *old_limit = RLimit { - cur: 1024 * 1024 * 1024, - max: 1024 * 1024 * 1024, - }; - } + let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? }; + // 1GB + *old_limit = RLimit { + cur: 1024 * 1024 * 1024, + max: 1024 * 1024 * 1024, + }; } Ok(0) } @@ -206,8 +196,7 @@ pub fn sys_getrandom( buf: *mut u8, len: usize, flag: u32) -> SysResult { //info!("getrandom: buf: {:?}, len: {:?}, falg {:?}", buf, len,flag); let mut proc = process(); - proc.vm.check_write_array(buf, len)?; - let slice = unsafe { slice::from_raw_parts_mut(buf, len) }; + let slice = unsafe { proc.vm.check_write_array(buf, len)? }; let mut i=0; for elm in slice { unsafe{ *elm=i+ crate::trap::TICK as u8;} diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index 34ebb14..af28065 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -55,8 +55,7 @@ pub fn sys_setsockopt( fd, level, optname ); let mut proc = process(); - proc.vm.check_read_array(optval, optlen)?; - let data = unsafe { slice::from_raw_parts(optval, optlen) }; + let data = unsafe { proc.vm.check_read_array(optval, optlen)? }; let socket = proc.get_socket(fd)?; socket.setsockopt(level, optname, data) } @@ -73,23 +72,19 @@ pub fn sys_getsockopt( fd, level, optname, optval, optlen ); let proc = process(); - proc.vm.check_write_ptr(optlen)?; + let optlen = unsafe { proc.vm.check_write_ptr(optlen)? }; match level { SOL_SOCKET => match optname { SO_SNDBUF => { - proc.vm.check_write_array(optval, 4)?; - unsafe { - *(optval as *mut u32) = crate::net::TCP_SENDBUF as u32; - *optlen = 4; - } + let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? }; + *optval = crate::net::TCP_SENDBUF as u32; + *optlen = 4; Ok(0) } SO_RCVBUF => { - proc.vm.check_write_array(optval, 4)?; - unsafe { - *(optval as *mut u32) = crate::net::TCP_RECVBUF as u32; - *optlen = 4; - } + let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? }; + *optval = crate::net::TCP_RECVBUF as u32; + *optlen = 4; Ok(0) } _ => Err(SysError::ENOPROTOOPT), @@ -129,9 +124,8 @@ pub fn sys_sendto( ); let mut proc = process(); - proc.vm.check_read_array(base, len)?; - let slice = unsafe { slice::from_raw_parts(base, len) }; + let slice = unsafe { proc.vm.check_read_array(base, len)? }; let endpoint = if addr.is_null() { None } else { @@ -157,10 +151,9 @@ pub fn sys_recvfrom( ); let mut proc = process(); - proc.vm.check_write_array(base, len)?; + let mut slice = unsafe { proc.vm.check_write_array(base, len)? }; let socket = proc.get_socket(fd)?; - let mut slice = unsafe { slice::from_raw_parts_mut(base, len) }; let (result, endpoint) = socket.read(&mut slice); if result.is_ok() && !addr.is_null() { @@ -176,9 +169,8 @@ pub fn sys_recvfrom( pub fn sys_recvmsg(fd: usize, msg: *mut MsgHdr, flags: usize) -> SysResult { info!("recvmsg: fd: {}, msg: {:?}, flags: {}", fd, msg, flags); let mut proc = process(); - proc.vm.check_read_ptr(msg)?; - let hdr = unsafe { &mut *msg }; - let mut iovs = IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &proc.vm, true)?; + let hdr = unsafe { proc.vm.check_write_ptr(msg)? }; + let mut iovs = unsafe { IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &proc.vm, true)? }; let mut buf = iovs.new_buf(true); let socket = proc.get_socket(fd)?; @@ -406,16 +398,16 @@ fn sockaddr_to_endpoint( if len < size_of::() { return Err(SysError::EINVAL); } - proc.vm.check_read_array(addr as *const u8, len)?; + let addr = unsafe { proc.vm.check_read_ptr(addr)? }; unsafe { - match AddressFamily::from((*addr).family) { + match AddressFamily::from(addr.family) { AddressFamily::Internet => { if len < size_of::() { return Err(SysError::EINVAL); } - let port = u16::from_be((*addr).addr_in.sin_port); + let port = u16::from_be(addr.addr_in.sin_port); let addr = IpAddress::from(Ipv4Address::from_bytes( - &u32::from_be((*addr).addr_in.sin_addr).to_be_bytes()[..], + &u32::from_be(addr.addr_in.sin_addr).to_be_bytes()[..], )); Ok(Endpoint::Ip((addr, port).into())) } @@ -425,7 +417,7 @@ fn sockaddr_to_endpoint( return Err(SysError::EINVAL); } Ok(Endpoint::LinkLevel(LinkLevelEndpoint::new( - (*addr).addr_ll.sll_ifindex as usize, + addr.addr_ll.sll_ifindex as usize, ))) } AddressFamily::Netlink => { @@ -433,8 +425,8 @@ fn sockaddr_to_endpoint( return Err(SysError::EINVAL); } Ok(Endpoint::Netlink(NetlinkEndpoint::new( - (*addr).addr_nl.nl_pid, - (*addr).addr_nl.nl_groups, + addr.addr_nl.nl_pid, + addr.addr_nl.nl_groups, ))) } _ => Err(SysError::EINVAL), @@ -456,7 +448,7 @@ impl SockAddr { return Ok(0); } - proc.vm.check_write_ptr(addr_len)?; + let addr_len = unsafe { proc.vm.check_write_ptr(addr_len)? }; let max_addr_len = *addr_len as usize; let full_len = match AddressFamily::from(self.family) { AddressFamily::Internet => size_of::(), @@ -468,12 +460,11 @@ impl SockAddr { let written_len = min(max_addr_len, full_len); if written_len > 0 { - proc.vm.check_write_array(addr as *mut u8, written_len)?; + let target = unsafe { proc.vm.check_write_array(addr as *mut u8, written_len)? }; let source = slice::from_raw_parts(&self as *const SockAddr as *const u8, written_len); - let target = slice::from_raw_parts_mut(addr as *mut u8, written_len); target.copy_from_slice(source); } - addr_len.write(full_len as u32); + *addr_len = full_len as u32; return Ok(0); } } diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index c58f8b8..dd04326 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -43,19 +43,14 @@ pub fn sys_clone( ); //return Err(SysError::ENOSYS); } - { - let proc = process(); - proc.vm.check_write_ptr(parent_tid)?; - proc.vm.check_write_ptr(child_tid)?; - } + let parent_tid_ref = unsafe { process().vm.check_write_ptr(parent_tid)? }; + let child_tid_ref = unsafe { process().vm.check_write_ptr(child_tid)? }; let new_thread = current_thread().clone(tf, newsp, newtls, child_tid as usize); // FIXME: parent pid let tid = processor().manager().add(new_thread); info!("clone: {} -> {}", thread::current().id(), tid); - unsafe { - parent_tid.write(tid as u32); - child_tid.write(tid as u32); - } + *parent_tid_ref = tid as u32; + *child_tid_ref = tid as u32; Ok(tid) } @@ -63,9 +58,11 @@ pub fn sys_clone( /// Return the PID. Store exit code to `wstatus` if it's not null. pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult { //info!("wait4: pid: {}, code: {:?}", pid, wstatus); - if !wstatus.is_null() { - process().vm.check_write_ptr(wstatus)?; - } + let wstatus = if !wstatus.is_null() { + Some(unsafe { process().vm.check_write_ptr(wstatus)? }) + } else { + None + }; #[derive(Debug)] enum WaitFor { AnyChild, @@ -90,10 +87,8 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult { // if found, return if let Some((pid, exit_code)) = find { proc.child_exit_code.remove(&pid); - if !wstatus.is_null() { - unsafe { - wstatus.write(exit_code as i32); - } + if let Some(wstatus) = wstatus { + *wstatus = exit_code as i32; } return Ok(pid); } @@ -124,69 +119,49 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult { } } +/// Replaces the current ** process ** with a new process image +/// +/// `argv` is an array of argument strings passed to the new program. +/// `envp` is an array of strings, conventionally of the form `key=value`, +/// which are passed as environment to the new program. +/// +/// NOTICE: `argv` & `envp` can not be NULL (different from Linux) +/// +/// NOTICE: for multi-thread programs +/// A call to any exec function from a process with more than one thread +/// shall result in all threads being terminated and the new executable image +/// being loaded and executed. pub fn sys_exec( - name: *const u8, + path: *const u8, argv: *const *const u8, envp: *const *const u8, tf: &mut TrapFrame, ) -> SysResult { - info!("exec:BEG: name: {:?}, argv: {:?}, envp: {:?}", name, argv, envp); + info!( + "exec:BEG: path: {:?}, argv: {:?}, envp: {:?}", + path, argv, envp + ); let proc = process(); - let exec_name = if name.is_null() { - String::from("") - } else { - unsafe { proc.vm.check_and_clone_cstr(name)? } - }; - - if argv.is_null() { - info!("exec:END:ERR1: exec_name: {:?}, name: {:?}, argv: is NULL", exec_name, name); - return Err(SysError::EINVAL); - } - // Check and copy args to kernel - let mut args = Vec::new(); - unsafe { - let mut current_argv = argv as *const *const u8; - proc.vm.check_read_ptr(current_argv)?; - while !(*current_argv).is_null() { - let arg = proc.vm.check_and_clone_cstr(*current_argv)?; - info!(" arg: {}",arg); - args.push(arg); - current_argv = current_argv.add(1); - } - } - // Check and copy envs to kernel - let mut envs = Vec::new(); - unsafe { - let mut current_env = envp as *const *const u8; - if !current_env.is_null() { - proc.vm.check_read_ptr(current_env)?; - while !(*current_env).is_null() { - let env = proc.vm.check_and_clone_cstr(*current_env)?; - info!(" env: {}",env); - envs.push(env); - current_env = current_env.add(1); - } - } - } + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + let args = unsafe { proc.vm.check_and_clone_cstr_array(argv)? }; + let envs = unsafe { proc.vm.check_and_clone_cstr_array(envp)? }; if args.is_empty() { - info!("exec:END:ERR2: exec_name: {:?}, name: {:?}, args is empty", exec_name, name); + error!("exec: args is null"); return Err(SysError::EINVAL); } info!( - "exec:STEP2: exec_name: {:?}, name{:?}, args: {:?}, envp: {:?}", - exec_name, name, args, envs + "exec:STEP2: path: {:?}, args: {:?}, envs: {:?}", + path, args, envs ); // Read program file - //let path = args[0].as_str(); - let exec_path = exec_name.as_str(); - let inode = proc.lookup_inode(exec_path)?; + let inode = proc.lookup_inode(&path)?; let buf = inode.read_as_vec()?; // Make new Thread - let mut thread = Thread::new_user(buf.as_slice(), exec_path, args, envs); + let mut thread = Thread::new_user(buf.as_slice(), &path, args, envs); thread.proc.lock().clone_for_exec(&proc); // Activate new page table @@ -201,10 +176,7 @@ pub fn sys_exec( ::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack); ::core::mem::swap(current_thread(), &mut *thread); - info!( - "exec:END: exec_name: {:?}", - exec_name - ); + info!("exec:END: path: {:?}", path); Ok(0) } @@ -337,8 +309,7 @@ pub fn sys_exit_group(exit_code: usize) -> ! { } pub fn sys_nanosleep(req: *const TimeSpec) -> SysResult { - process().vm.check_read_ptr(req)?; - let time = unsafe { req.read() }; + let time = unsafe { *process().vm.check_read_ptr(req)? }; info!("nanosleep: time: {:#?}", time); // TODO: handle spurious wakeup thread::sleep(time.to_duration()); diff --git a/kernel/src/syscall/time.rs b/kernel/src/syscall/time.rs index dd2834c..0fc3f39 100644 --- a/kernel/src/syscall/time.rs +++ b/kernel/src/syscall/time.rs @@ -83,12 +83,10 @@ pub fn sys_gettimeofday(tv: *mut TimeVal, tz: *const u8) -> SysResult { } let proc = process(); - proc.vm.check_write_ptr(tv)?; + let tv = unsafe { proc.vm.check_write_ptr(tv)? }; let timeval = TimeVal::get_epoch(); - unsafe { - *tv = timeval; - } + *tv = timeval; Ok(0) } @@ -96,12 +94,10 @@ pub fn sys_clock_gettime(clock: usize, ts: *mut TimeSpec) -> SysResult { info!("clock_gettime: clock: {:?}, ts: {:?}", clock, ts); let proc = process(); - proc.vm.check_write_ptr(ts)?; + let ts = unsafe { proc.vm.check_write_ptr(ts)? }; let timespec = TimeSpec::get_epoch(); - unsafe { - *ts = timespec; - } + *ts = timespec; Ok(0) } @@ -109,10 +105,8 @@ pub fn sys_time(time: *mut u64) -> SysResult { let sec = get_epoch_usec() / USEC_PER_SEC; if time as usize != 0 { let proc = process(); - proc.vm.check_write_ptr(time)?; - unsafe { - time.write(sec as u64); - } + let time = unsafe { proc.vm.check_write_ptr(time)? }; + *time = sec as u64; } Ok(sec as usize) } @@ -127,7 +121,7 @@ pub struct RUsage { pub fn sys_getrusage(who: usize, rusage: *mut RUsage) -> SysResult { info!("getrusage: who: {}, rusage: {:?}", who, rusage); let proc = process(); - proc.vm.check_write_ptr(rusage)?; + let rusage = unsafe { proc.vm.check_write_ptr(rusage)? }; let tick_base = *TICK_BASE; let tick = unsafe { crate::trap::TICK as u64 }; @@ -143,7 +137,7 @@ pub fn sys_getrusage(who: usize, rusage: *mut RUsage) -> SysResult { usec: (usec % USEC_PER_SEC) as usize, }, }; - unsafe { *rusage = new_rusage }; + *rusage = new_rusage; Ok(0) } @@ -159,7 +153,7 @@ pub struct Tms { pub fn sys_times(buf: *mut Tms) -> SysResult { info!("times: buf: {:?}", buf); let proc = process(); - proc.vm.check_write_ptr(buf)?; + let buf = unsafe { proc.vm.check_write_ptr(buf)? }; let tick_base = *TICK_BASE; let tick = unsafe { crate::trap::TICK as u64 }; @@ -171,6 +165,6 @@ pub fn sys_times(buf: *mut Tms) -> SysResult { tms_cstime: 0, }; - unsafe { *buf = new_buf }; + *buf = new_buf; Ok(tick as usize) } From fc60d2cea2333d0a459e1816a7634d2fb535dcc0 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sun, 28 Apr 2019 19:54:42 +0800 Subject: [PATCH 47/61] Do not poll unrelated files in sys_select --- kernel/src/syscall/fs.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 1c005d9..c06a7d8 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -166,6 +166,9 @@ pub fn sys_select( if fd >= nfds { continue; } + if !err_fds.contains(fd) && !read_fds.contains(fd) && !write_fds.contains(fd) { + continue; + } let status = file_like.poll()?; if status.error && err_fds.contains(fd) { err_fds.set(fd); @@ -1334,6 +1337,7 @@ impl FdSet { } let slice = unsafe { vm.check_write_array(addr, len)? }; let bitset: &'static mut BitSlice = slice.into(); + debug!("bitset {:?}", bitset); // save the fdset, and clear it use alloc::prelude::ToOwned; @@ -1357,7 +1361,11 @@ impl FdSet { /// Check to see whether `fd` is in original `FdSet` /// Fd should be less than nfds fn contains(&self, fd: usize) -> bool { - self.origin[fd] + if fd < self.bitset.len() { + self.origin[fd] + } else { + false + } } } From 27f5c7b2e4375dacf0de548e34896d36cddb60f3 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 28 Apr 2019 23:34:45 +0800 Subject: [PATCH 48/61] detach thread to auto recycle tid. fix #25 --- kernel/Cargo.lock | 2 +- kernel/src/syscall/proc.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 4848e5e..74ae4b9 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -426,7 +426,7 @@ dependencies = [ [[package]] name = "rcore-thread" version = "0.1.0" -source = "git+https://github.com/rcore-os/rcore-thread#7236bfd2e2bde673773214739695bb2925a77ae5" +source = "git+https://github.com/rcore-os/rcore-thread#fd972c7e3aa2b7618f625f143655c16adfd2ca78" dependencies = [ "deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index dd04326..b962d4c 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -7,7 +7,8 @@ use crate::fs::INodeExt; pub fn sys_fork(tf: &TrapFrame) -> SysResult { let new_thread = current_thread().fork(tf); let pid = new_thread.proc.lock().pid.get(); - processor().manager().add(new_thread); + let tid = processor().manager().add(new_thread); + processor().manager().detach(tid); info!("fork: {} -> {}", thread::current().id(), pid); Ok(pid) } @@ -48,6 +49,7 @@ pub fn sys_clone( let new_thread = current_thread().clone(tf, newsp, newtls, child_tid as usize); // FIXME: parent pid let tid = processor().manager().add(new_thread); + processor().manager().detach(tid); info!("clone: {} -> {}", thread::current().id(), tid); *parent_tid_ref = tid as u32; *child_tid_ref = tid as u32; From 5bc6395b2380451d046650303b7baaf96a560a60 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 29 Apr 2019 01:10:06 +0800 Subject: [PATCH 49/61] fix sys_exec --- kernel/src/arch/aarch64/interrupt/context.rs | 10 +--- kernel/src/arch/mipsel/context.rs | 7 +-- kernel/src/arch/riscv32/context.rs | 7 +-- kernel/src/arch/x86_64/interrupt/trapframe.rs | 7 +-- kernel/src/process/structs.rs | 55 +++++++++---------- kernel/src/syscall/proc.rs | 24 ++++---- 6 files changed, 45 insertions(+), 65 deletions(-) diff --git a/kernel/src/arch/aarch64/interrupt/context.rs b/kernel/src/arch/aarch64/interrupt/context.rs index 87f3a4e..03b4414 100644 --- a/kernel/src/arch/aarch64/interrupt/context.rs +++ b/kernel/src/arch/aarch64/interrupt/context.rs @@ -32,7 +32,7 @@ impl TrapFrame { tf.spsr = 0b1101_00_0101; // To EL 1, enable IRQ tf } - fn new_user_thread(entry_addr: usize, sp: usize) -> Self { + pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; tf.sp = sp; @@ -40,9 +40,6 @@ impl TrapFrame { tf.spsr = 0b1101_00_0000; // To EL 0, enable IRQ tf } - pub fn is_user(&self) -> bool { - unimplemented!() - } } /// 新线程的内核栈初始内容 @@ -201,11 +198,6 @@ impl Context { } .push_at(kstack_top, ttbr) } - /// Called at a new user context - /// To get the init TrapFrame in sys_exec - pub unsafe fn get_init_tf(&self) -> TrapFrame { - (*(self.stack_top as *const InitStack)).tf.clone() - } } const ASID_MASK: u16 = 0xffff; diff --git a/kernel/src/arch/mipsel/context.rs b/kernel/src/arch/mipsel/context.rs index ab4e5aa..606fbad 100644 --- a/kernel/src/arch/mipsel/context.rs +++ b/kernel/src/arch/mipsel/context.rs @@ -76,7 +76,7 @@ impl TrapFrame { /// /// The new thread starts at `entry_addr`. /// The stack pointer will be set to `sp`. - fn new_user_thread(entry_addr: usize, sp: usize) -> Self { + pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; tf.sp = sp; @@ -269,9 +269,4 @@ impl Context { } .push_at(kstack_top) } - - /// Used for getting the init TrapFrame of a new user context in `sys_exec`. - pub unsafe fn get_init_tf(&self) -> TrapFrame { - (*(self.sp as *const InitStack)).tf.clone() - } } diff --git a/kernel/src/arch/riscv32/context.rs b/kernel/src/arch/riscv32/context.rs index 51df0c1..c8ac7ea 100644 --- a/kernel/src/arch/riscv32/context.rs +++ b/kernel/src/arch/riscv32/context.rs @@ -40,7 +40,7 @@ impl TrapFrame { /// /// The new thread starts at `entry_addr`. /// The stack pointer will be set to `sp`. - fn new_user_thread(entry_addr: usize, sp: usize) -> Self { + pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; tf.x[2] = sp; @@ -289,9 +289,4 @@ impl Context { } .push_at(kstack_top) } - - /// Used for getting the init TrapFrame of a new user context in `sys_exec`. - pub unsafe fn get_init_tf(&self) -> TrapFrame { - (*(self.sp as *const InitStack)).tf.clone() - } } diff --git a/kernel/src/arch/x86_64/interrupt/trapframe.rs b/kernel/src/arch/x86_64/interrupt/trapframe.rs index d9ab7f7..fe01ee2 100644 --- a/kernel/src/arch/x86_64/interrupt/trapframe.rs +++ b/kernel/src/arch/x86_64/interrupt/trapframe.rs @@ -73,7 +73,7 @@ impl TrapFrame { tf.fpstate_offset = 16; // skip restoring for first time tf } - fn new_user_thread(entry_addr: usize, rsp: usize) -> Self { + pub fn new_user_thread(entry_addr: usize, rsp: usize) -> Self { use crate::arch::gdt; let mut tf = TrapFrame::default(); tf.cs = gdt::UCODE_SELECTOR.0 as usize; @@ -234,9 +234,4 @@ impl Context { } .push_at(kstack_top) } - /// Called at a new user context - /// To get the init TrapFrame in sys_exec - pub unsafe fn get_init_tf(&self) -> TrapFrame { - (*(self.0 as *const InitStack)).tf.clone() - } } diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 8ef01bc..103e300 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -126,13 +126,14 @@ impl Thread { }) } - /// Make a new user process from ELF `data` - pub fn new_user( + /// Construct virtual memory of a new user process from ELF `data`. + /// Return `(MemorySet, entry_point, ustack_top)` + pub fn new_user_vm( data: &[u8], exec_path: &str, mut args: Vec, envs: Vec, - ) -> Box { + ) -> (MemorySet, usize, usize) { // Parse ELF let elf = ElfFile::new(data).expect("failed to read elf"); @@ -159,22 +160,16 @@ impl Thread { // Check interpreter (for dynamic link) if let Ok(loader_path) = elf.get_interpreter() { // assuming absolute path - if let Ok(inode) = crate::fs::ROOT_INODE.lookup_follow(loader_path, FOLLOW_MAX_DEPTH) { - if let Ok(buf) = inode.read_as_vec() { - // Elf loader should not have INTERP - // No infinite loop - args.insert(0, loader_path.into()); - args.insert(1, exec_path.into()); - args.remove(2); - //info!("loader args: {:?}", args); - //info!("loader envs: {:?}", envs); - return Thread::new_user(buf.as_slice(), exec_path, args, envs); - } else { - warn!("loader specified as {} but failed to read", &loader_path); - } - } else { - warn!("loader specified as {} but not found", &loader_path); - } + let inode = crate::fs::ROOT_INODE + .lookup_follow(loader_path, FOLLOW_MAX_DEPTH) + .expect("interpreter not found"); + let buf = inode.read_as_vec().expect("failed to load interpreter"); + // modify args for loader + args[0] = exec_path.into(); + args.insert(0, loader_path.into()); + // Elf loader should not have INTERP + // No infinite loop + return Thread::new_user_vm(buf.as_slice(), exec_path, args, envs); } // Make page table @@ -216,6 +211,19 @@ impl Thread { trace!("{:#x?}", vm); + let entry_addr = elf.header.pt2.entry_point() as usize; + (vm, entry_addr, ustack_top) + } + + /// Make a new user process from ELF `data` + pub fn new_user( + data: &[u8], + exec_path: &str, + mut args: Vec, + envs: Vec, + ) -> Box { + let (vm, entry_addr, ustack_top) = Self::new_user_vm(data, exec_path, args, envs); + let kstack = KernelStack::new(); let mut files = BTreeMap::new(); @@ -253,8 +261,6 @@ impl Thread { )), ); - let entry_addr = elf.header.pt2.entry_point() as usize; - Box::new(Thread { context: unsafe { Context::new_user_thread(entry_addr, ustack_top, kstack.top(), vm.token()) @@ -377,13 +383,6 @@ impl Process { } self.futexes.get(&uaddr).unwrap().clone() } - pub fn clone_for_exec(&mut self, other: &Self) { - self.files = other.files.clone(); - self.cwd = other.cwd.clone(); - self.pid = other.pid.clone(); - self.parent = other.parent.clone(); - self.threads = other.threads.clone(); - } } trait ToMemoryAttr { diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index b962d4c..8114b06 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -143,7 +143,7 @@ pub fn sys_exec( "exec:BEG: path: {:?}, argv: {:?}, envp: {:?}", path, argv, envp ); - let proc = process(); + let mut proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; let args = unsafe { proc.vm.check_and_clone_cstr_array(argv)? }; let envs = unsafe { proc.vm.check_and_clone_cstr_array(envp)? }; @@ -158,25 +158,29 @@ pub fn sys_exec( path, args, envs ); + // Kill other threads + proc.threads.retain(|&tid| { + if tid != processor().tid() { + processor().manager().exit(tid, 1); + } + tid == processor().tid() + }); + // Read program file let inode = proc.lookup_inode(&path)?; - let buf = inode.read_as_vec()?; + let data = inode.read_as_vec()?; // Make new Thread - let mut thread = Thread::new_user(buf.as_slice(), &path, args, envs); - thread.proc.lock().clone_for_exec(&proc); + let (mut vm, entry_addr, ustack_top) = Thread::new_user_vm(data.as_slice(), &path, args, envs); // Activate new page table unsafe { - thread.proc.lock().vm.activate(); + vm.activate(); } + core::mem::swap(&mut proc.vm, &mut vm); // Modify the TrapFrame - *tf = unsafe { thread.context.get_init_tf() }; - - // Swap Context but keep KStack - ::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack); - ::core::mem::swap(current_thread(), &mut *thread); + *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); info!("exec:END: path: {:?}", path); Ok(0) From 72efa797e58d14095635d1642063fb0cabd6905c Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 29 Apr 2019 02:33:44 +0800 Subject: [PATCH 50/61] x86_64: enable interrupt during syscall. set TSS.sp0 through gs. --- kernel/src/arch/x86_64/gdt.rs | 19 +++---------------- kernel/src/arch/x86_64/interrupt/handler.rs | 6 ------ kernel/src/arch/x86_64/interrupt/trap.asm | 15 +++++++-------- kernel/src/arch/x86_64/mod.rs | 2 +- 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/kernel/src/arch/x86_64/gdt.rs b/kernel/src/arch/x86_64/gdt.rs index ed648e3..42c125c 100644 --- a/kernel/src/arch/x86_64/gdt.rs +++ b/kernel/src/arch/x86_64/gdt.rs @@ -39,10 +39,6 @@ pub struct Cpu { } impl Cpu { - pub fn current() -> &'static mut Self { - unsafe { CPUS[super::cpu::id()].as_mut().unwrap() } - } - fn new() -> Self { Cpu { gdt: GlobalDescriptorTable::new(), @@ -72,18 +68,9 @@ impl Cpu { set_cs(KCODE_SELECTOR); // load TSS load_tss(TSS_SELECTOR); - // for fast syscall: - // store address of TSS to kernel_gsbase - let mut kernel_gsbase = Msr::new(0xC0000102); - kernel_gsbase.write(&self.tss as *const _ as u64); - } - - /// 设置从Ring3跳到Ring0时,自动切换栈的地址 - /// - /// 每次进入用户态前,都要调用此函数,才能保证正确返回内核态 - pub fn set_ring0_rsp(&mut self, rsp: usize) { - trace!("gdt.set_ring0_rsp: {:#x}", rsp); - self.tss.privilege_stack_table[0] = VirtAddr::new(rsp as u64); + // store address of TSS to GSBase + let mut gsbase = Msr::new(0xC0000101); + gsbase.write(&self.tss as *const _ as u64); } } diff --git a/kernel/src/arch/x86_64/interrupt/handler.rs b/kernel/src/arch/x86_64/interrupt/handler.rs index 230ee18..de70864 100644 --- a/kernel/src/arch/x86_64/interrupt/handler.rs +++ b/kernel/src/arch/x86_64/interrupt/handler.rs @@ -213,9 +213,3 @@ fn invalid_opcode(tf: &mut TrapFrame) { fn error(tf: &TrapFrame) { crate::trap::error(tf); } - -#[no_mangle] -pub unsafe extern "C" fn set_return_rsp(tf: *const TrapFrame) { - use crate::arch::gdt::Cpu; - Cpu::current().set_ring0_rsp(tf.add(1) as usize); -} diff --git a/kernel/src/arch/x86_64/interrupt/trap.asm b/kernel/src/arch/x86_64/interrupt/trap.asm index d20528d..2f0424b 100644 --- a/kernel/src/arch/x86_64/interrupt/trap.asm +++ b/kernel/src/arch/x86_64/interrupt/trap.asm @@ -49,8 +49,10 @@ __alltraps: .global trap_ret trap_ret: + # store kernel rsp -> TSS.sp0 mov rdi, rsp - call set_return_rsp + add rdi, 720 + mov gs:[4], rdi # pop fp state offset pop rcx @@ -104,8 +106,6 @@ syscall_entry: # - store rip -> rcx # - load rip - # swap in kernel gs - swapgs # store user rsp -> scratch at TSS.sp1 mov gs:[12], rsp # load kernel rsp <- TSS.sp0 @@ -119,11 +119,8 @@ syscall_entry: push 0 # error_code (dummy) push 0 # trap_num (dummy) - # swap out kernel gs - swapgs - # enable interrupt - # sti + sti push rax push rcx @@ -173,8 +170,10 @@ syscall_return: # disable interrupt cli + # store kernel rsp -> TSS.sp0 mov rdi, rsp - call set_return_rsp + add rdi, 720 + mov gs:[4], rdi # pop fp state offset pop rcx diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index bec0e26..f02dd60 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -15,7 +15,7 @@ pub mod rand; pub mod syscall; pub mod timer; -static AP_CAN_INIT: AtomicBool = ATOMIC_BOOL_INIT; +static AP_CAN_INIT: AtomicBool = AtomicBool::new(false); /// The entry point of kernel #[no_mangle] // don't mangle the name of this function From e5894b652cd2c880d67943ff1128f500aa83b858 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Mon, 29 Apr 2019 10:20:51 +0800 Subject: [PATCH 51/61] Format code --- .../src/arch/x86_64/interrupt/fast_syscall.rs | 4 +- kernel/src/drivers/block/virtio_blk.rs | 2 - kernel/src/drivers/mod.rs | 8 ++-- kernel/src/drivers/net/ixgbe.rs | 1 - kernel/src/drivers/net/virtio_net.rs | 1 - kernel/src/memory.rs | 2 +- kernel/src/net/structs.rs | 6 +-- kernel/src/process/structs.rs | 1 - kernel/src/shell.rs | 30 ++++++------ kernel/src/syscall/fs.rs | 48 ++++++++----------- kernel/src/syscall/mem.rs | 10 ++-- kernel/src/syscall/misc.rs | 13 ++--- kernel/src/syscall/mod.rs | 2 +- user | 2 +- 14 files changed, 60 insertions(+), 70 deletions(-) diff --git a/kernel/src/arch/x86_64/interrupt/fast_syscall.rs b/kernel/src/arch/x86_64/interrupt/fast_syscall.rs index 89ff76f..d096b65 100644 --- a/kernel/src/arch/x86_64/interrupt/fast_syscall.rs +++ b/kernel/src/arch/x86_64/interrupt/fast_syscall.rs @@ -10,8 +10,8 @@ pub fn init() { *flags |= EferFlags::SYSTEM_CALL_EXTENSIONS; }); - let mut star = Msr::new(0xC0000081); // legacy mode SYSCALL target - let mut lstar = Msr::new(0xC0000082); // long mode SYSCALL target + let mut star = Msr::new(0xC0000081); // legacy mode SYSCALL target + let mut lstar = Msr::new(0xC0000082); // long mode SYSCALL target let mut sfmask = Msr::new(0xC0000084); // EFLAGS mask for syscall // flags to clear on syscall diff --git a/kernel/src/drivers/block/virtio_blk.rs b/kernel/src/drivers/block/virtio_blk.rs index c992aaf..fd38b64 100644 --- a/kernel/src/drivers/block/virtio_blk.rs +++ b/kernel/src/drivers/block/virtio_blk.rs @@ -12,8 +12,6 @@ use rcore_memory::paging::PageTable; use rcore_memory::PAGE_SIZE; use volatile::Volatile; -use rcore_fs::dev::BlockDevice; - use crate::drivers::BlockDriver; use crate::memory::active_table; use crate::sync::SpinNoIrqLock as Mutex; diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index 104a567..de559ce 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -72,21 +72,21 @@ pub trait Driver: Send + Sync { } // send an ethernet frame, only use it when necessary - fn send(&self, data: &[u8]) -> Option { + fn send(&self, _data: &[u8]) -> Option { unimplemented!("not a net driver") } // get mac address from ip address in arp table - fn get_arp(&self, ip: IpAddress) -> Option { + fn get_arp(&self, _ip: IpAddress) -> Option { unimplemented!("not a net driver") } // block related drivers should implement these - fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { + fn read_block(&self, _block_id: usize, _buf: &mut [u8]) -> bool { unimplemented!("not a block driver") } - fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { + fn write_block(&self, _block_id: usize, _buf: &[u8]) -> bool { unimplemented!("not a block driver") } } diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 115a0bd..139d313 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -15,7 +15,6 @@ use smoltcp::wire::EthernetAddress; use smoltcp::wire::*; use smoltcp::Result; -use crate::memory::active_table; use crate::net::SOCKETS; use crate::sync::FlagsGuard; use crate::sync::SpinNoIrqLock as Mutex; diff --git a/kernel/src/drivers/net/virtio_net.rs b/kernel/src/drivers/net/virtio_net.rs index d149ec3..40c0d31 100644 --- a/kernel/src/drivers/net/virtio_net.rs +++ b/kernel/src/drivers/net/virtio_net.rs @@ -2,7 +2,6 @@ use alloc::alloc::{GlobalAlloc, Layout}; use alloc::format; use alloc::string::String; use alloc::sync::Arc; -use alloc::vec::Vec; use core::mem::size_of; use core::slice; diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index fa0c2dc..8367cbc 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -105,7 +105,7 @@ impl KernelStack { pub fn new() -> Self { use alloc::alloc::{alloc, Layout}; let bottom = - unsafe { alloc(Layout::from_size_align(KSTACK_SIZE, KSTACK_SIZE).unwrap())} as usize; + unsafe { alloc(Layout::from_size_align(KSTACK_SIZE, KSTACK_SIZE).unwrap()) } as usize; KernelStack(bottom) } pub fn top(&self) -> usize { diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 7dcb754..b905fde 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -55,7 +55,7 @@ pub trait Socket: Send + Sync { fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult; fn poll(&self) -> (bool, bool, bool); // (in, out, err) fn connect(&mut self, endpoint: Endpoint) -> SysResult; - fn bind(&mut self, endpoint: Endpoint) -> SysResult { + fn bind(&mut self, _endpoint: Endpoint) -> SysResult { Err(SysError::EINVAL) } fn listen(&mut self) -> SysResult { @@ -73,11 +73,11 @@ pub trait Socket: Send + Sync { fn remote_endpoint(&self) -> Option { None } - fn setsockopt(&mut self, level: usize, opt: usize, data: &[u8]) -> SysResult { + fn setsockopt(&mut self, _level: usize, _opt: usize, _data: &[u8]) -> SysResult { warn!("setsockopt is unimplemented"); Ok(0) } - fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { + fn ioctl(&mut self, _request: usize, _arg1: usize, _arg2: usize, _arg3: usize) -> SysResult { warn!("ioctl is unimplemented for this socket"); Ok(0) } diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 103e300..5c5a292 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -15,7 +15,6 @@ use xmas_elf::{ use crate::arch::interrupt::{Context, TrapFrame}; use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; -use crate::net::SOCKETS; use crate::sync::{Condvar, SpinNoIrqLock as Mutex}; use super::abi::{self, ProcInitInfo}; diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index fc4bdce..61431e8 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -6,28 +6,28 @@ use crate::process::*; use alloc::string::String; use alloc::vec::Vec; - #[cfg(not(feature = "run_cmdline"))] pub fn add_user_shell() { -/// the busybox of alpine linux can not transfer env vars into child process -/// Now we use busybox from -/// https://raw.githubusercontent.com/docker-library/busybox/82bc0333a9ae148fbb4246bcbff1487b3fc0c510/musl/busybox.tar.xz -O busybox.tar.xz -/// This one can transfer env vars! -/// Why??? - -// #[cfg(target_arch = "x86_64")] -// let init_shell="/bin/busybox"; // from alpine linux -// -// #[cfg(not(target_arch = "x86_64"))] - let init_shell="/busybox"; //from docker-library + // the busybox of alpine linux can not transfer env vars into child process + // Now we use busybox from + // https://raw.githubusercontent.com/docker-library/busybox/82bc0333a9ae148fbb4246bcbff1487b3fc0c510/musl/busybox.tar.xz -O busybox.tar.xz + // This one can transfer env vars! + // Why??? + + // #[cfg(target_arch = "x86_64")] + // let init_shell="/bin/busybox"; // from alpine linux + // + // #[cfg(not(target_arch = "x86_64"))] + let init_shell = "/busybox"; //from docker-library #[cfg(target_arch = "x86_64")] - let init_envs=vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()]; + let init_envs = + vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()]; #[cfg(not(target_arch = "x86_64"))] - let init_envs=Vec::new(); + let init_envs = Vec::new(); - let init_args=vec!["busybox".into(), "ash".into()]; + let init_args = vec!["busybox".into(), "ash".into()]; if let Ok(inode) = ROOT_INODE.lookup(init_shell) { let data = inode.read_as_vec().unwrap(); diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index c06a7d8..113a58d 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -625,27 +625,23 @@ pub fn sys_pipe(fds: *mut u32) -> SysResult { let fds = unsafe { proc.vm.check_write_array(fds, 2)? }; let (read, write) = Pipe::create_pair(); - let read_fd = proc.add_file( - FileLike::File(FileHandle::new( - Arc::new(read), - OpenOptions { - read: true, - write: false, - append: false, - }, - )), - ); - - let write_fd = proc.add_file( - FileLike::File(FileHandle::new( - Arc::new(write), - OpenOptions { - read: false, - write: true, - append: false, - }, - )), - ); + let read_fd = proc.add_file(FileLike::File(FileHandle::new( + Arc::new(read), + OpenOptions { + read: true, + write: false, + append: false, + }, + ))); + + let write_fd = proc.add_file(FileLike::File(FileHandle::new( + Arc::new(write), + OpenOptions { + read: false, + write: true, + append: false, + }, + ))); fds[0] = read_fd as u32; fds[1] = write_fd as u32; @@ -678,9 +674,7 @@ pub fn sys_sendfile( let mut buffer = [0u8; 1024]; let mut read_offset = if !offset_ptr.is_null() { - unsafe { - *(*proc_cell.get()).vm.check_read_ptr(offset_ptr)? - } + unsafe { *(*proc_cell.get()).vm.check_read_ptr(offset_ptr)? } } else { in_file.seek(SeekFrom::Current(0))? as usize }; @@ -700,7 +694,7 @@ pub fn sys_sendfile( let mut bytes_written = 0; let mut rlen = read_len; while bytes_written < read_len { - let write_len = out_file.write(&buffer[bytes_written..(bytes_written+rlen)])?; + let write_len = out_file.write(&buffer[bytes_written..(bytes_written + rlen)])?; if write_len == 0 { info!( "sendfile:END_ERR out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, bytes_written {}, write_len {}", @@ -709,9 +703,9 @@ pub fn sys_sendfile( return Err(SysError::EBADF); } bytes_written += write_len; - rlen-=write_len; + rlen -= write_len; } - total_written+=bytes_written; + total_written += bytes_written; } if !offset_ptr.is_null() { diff --git a/kernel/src/syscall/mem.rs b/kernel/src/syscall/mem.rs index aa935ea..dd2b3e2 100644 --- a/kernel/src/syscall/mem.rs +++ b/kernel/src/syscall/mem.rs @@ -46,15 +46,15 @@ pub fn sys_mmap( addr, addr + len, prot.to_attr(), -// ByFrame::new(GlobalFrameAlloc), //eagle mmap mode + // ByFrame::new(GlobalFrameAlloc), //eagle mmap mode Delay::new(GlobalFrameAlloc), "mmap_anon", ); //init with zero for eagle mmap mode -// let data = unsafe { slice::from_raw_parts_mut(addr as *mut u8, len) }; -// for x in data { -// *x = 0; -// } + // let data = unsafe { slice::from_raw_parts_mut(addr as *mut u8, len) }; + // for x in data { + // *x = 0; + // } return Ok(addr); } else { // only check diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs index 79bda93..e7f867c 100644 --- a/kernel/src/syscall/misc.rs +++ b/kernel/src/syscall/misc.rs @@ -192,16 +192,17 @@ pub struct RLimit { max: u64, // hard limit } -pub fn sys_getrandom( buf: *mut u8, len: usize, flag: u32) -> SysResult { - +pub fn sys_getrandom(buf: *mut u8, len: usize, flag: u32) -> SysResult { //info!("getrandom: buf: {:?}, len: {:?}, falg {:?}", buf, len,flag); let mut proc = process(); let slice = unsafe { proc.vm.check_write_array(buf, len)? }; - let mut i=0; + let mut i = 0; for elm in slice { - unsafe{ *elm=i+ crate::trap::TICK as u8;} - i+=1; + unsafe { + *elm = i + crate::trap::TICK as u8; + } + i += 1; } Ok(len) -} \ No newline at end of file +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 4a5f6c1..7b7483c 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -231,7 +231,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { SYS_MAP_PCI_DEVICE => sys_map_pci_device(args[0], args[1]), SYS_GET_PADDR => sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2]), //SYS_GETRANDOM => unimplemented("getrandom", Err(SysError::EINVAL)), - SYS_GETRANDOM =>sys_getrandom( args[0] as *mut u8, args[1] as usize, args[2] as u32), + SYS_GETRANDOM => sys_getrandom(args[0] as *mut u8, args[1] as usize, args[2] as u32), SYS_TKILL => unimplemented("tkill", Ok(0)), _ => { let ret = match () { diff --git a/user b/user index 8dbc0ed..05f0efd 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 8dbc0edb935a62d748aaac39258d4a985de0ae17 +Subproject commit 05f0efd3fda084109e4b6da8ff30ecb1557a267f From ae4badb3cdfbc8d7669cabf6fe9c2a590b5fd873 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Mon, 29 Apr 2019 10:45:04 +0800 Subject: [PATCH 52/61] Force python3.7 for make addr2line --- kernel/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/Makefile b/kernel/Makefile index 59fb48b..4cd58fd 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -386,4 +386,4 @@ endif .PHONY: addr2line: - @python3 ../tools/addr2line.py $(prefix)addr2line $(arch) $(mode) + @python3.7 ../tools/addr2line.py $(prefix)addr2line $(arch) $(mode) From 8024401bd2b48563fd763cfc24b250bb9b42f19f Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 30 Apr 2019 01:45:01 +0800 Subject: [PATCH 53/61] simplify x86_64 consts. keep MemoryArea order by start address --- crate/memory/src/memory_set/mod.rs | 10 +++- kernel/src/arch/x86_64/consts.rs | 96 +----------------------------- 2 files changed, 12 insertions(+), 94 deletions(-) diff --git a/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index decd828..97d0ca3 100644 --- a/crate/memory/src/memory_set/mod.rs +++ b/crate/memory/src/memory_set/mod.rs @@ -310,7 +310,15 @@ impl MemorySet { name, }; self.page_table.edit(|pt| area.map(pt)); - self.areas.push(area); + // keep order by start address + let idx = self + .areas + .iter() + .enumerate() + .find(|(_, other)| start_addr < other.start_addr) + .map(|(i, _)| i) + .unwrap_or(self.areas.len()); + self.areas.insert(idx, area); } /* diff --git a/kernel/src/arch/x86_64/consts.rs b/kernel/src/arch/x86_64/consts.rs index 0b3a4f9..cd44eb2 100644 --- a/kernel/src/arch/x86_64/consts.rs +++ b/kernel/src/arch/x86_64/consts.rs @@ -1,96 +1,6 @@ -// Copy from Redox consts.rs: - -// Because the memory map is so important to not be aliased, it is defined here, in one place -// The lower 256 PML4 entries are reserved for userspace -// Each PML4 entry references up to 512 GB of memory -// The top (511) PML4 is reserved for recursive mapping -// The second from the top (510) PML4 is reserved for the kernel -/// The size of a single PML4 -pub const PML4_SIZE: usize = 0x0000_0080_0000_0000; -pub const PML4_MASK: usize = 0x0000_ff80_0000_0000; - -/// Offset of recursive paging -pub const RECURSIVE_PAGE_OFFSET: usize = (-(PML4_SIZE as isize)) as usize; -pub const RECURSIVE_PAGE_PML4: usize = (RECURSIVE_PAGE_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset of kernel -pub const KERNEL_OFFSET: usize = RECURSIVE_PAGE_OFFSET - PML4_SIZE; -pub const KERNEL_PML4: usize = (KERNEL_OFFSET & PML4_MASK) / PML4_SIZE; - -pub const KERNEL_SIZE: usize = PML4_SIZE; - -/// Offset to kernel heap -pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET - PML4_SIZE; -pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK) / PML4_SIZE; -/// Size of kernel heap -pub const KERNEL_HEAP_SIZE: usize = 32 * 1024 * 1024; // 32 MB - pub const MEMORY_OFFSET: usize = 0; +pub const KERNEL_OFFSET: usize = 0xffffff00_00000000; +pub const KERNEL_HEAP_SIZE: usize = 32 * 1024 * 1024; // 32 MB -/// Offset to kernel percpu variables -//TODO: Use 64-bit fs offset to enable this pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE; -pub const KERNEL_PERCPU_OFFSET: usize = 0xC000_0000; -/// Size of kernel percpu variables -pub const KERNEL_PERCPU_SIZE: usize = 64 * 1024; // 64 KB - -/// Offset to user image -pub const USER_OFFSET: usize = 0; -pub const USER_PML4: usize = (USER_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset to user TCB -pub const USER_TCB_OFFSET: usize = 0xB000_0000; - -/// Offset to user arguments -pub const USER_ARG_OFFSET: usize = USER_OFFSET + PML4_SIZE / 2; - -/// Offset to user heap -pub const USER_HEAP_OFFSET: usize = USER_OFFSET + PML4_SIZE; -pub const USER_HEAP_PML4: usize = (USER_HEAP_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset to user grants -pub const USER_GRANT_OFFSET: usize = USER_HEAP_OFFSET + PML4_SIZE; -pub const USER_GRANT_PML4: usize = (USER_GRANT_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset to user stack -pub const USER_STACK_OFFSET: usize = USER_GRANT_OFFSET + PML4_SIZE; -pub const USER_STACK_PML4: usize = (USER_STACK_OFFSET & PML4_MASK) / PML4_SIZE; -/// Size of user stack +pub const USER_STACK_OFFSET: usize = 0x00008000_00000000 - USER_STACK_SIZE; pub const USER_STACK_SIZE: usize = 8 * 1024 * 1024; // 8 MB, the default config of Linux - -/// Offset to user sigstack -pub const USER_SIGSTACK_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; -pub const USER_SIGSTACK_PML4: usize = (USER_SIGSTACK_OFFSET & PML4_MASK) / PML4_SIZE; -/// Size of user sigstack -pub const USER_SIGSTACK_SIZE: usize = 256 * 1024; // 256 KB - -/// Offset to user TLS -pub const USER_TLS_OFFSET: usize = USER_SIGSTACK_OFFSET + PML4_SIZE; -pub const USER_TLS_PML4: usize = (USER_TLS_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset to user temporary image (used when cloning) -pub const USER_TMP_OFFSET: usize = USER_TLS_OFFSET + PML4_SIZE; -pub const USER_TMP_PML4: usize = (USER_TMP_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset to user temporary heap (used when cloning) -pub const USER_TMP_HEAP_OFFSET: usize = USER_TMP_OFFSET + PML4_SIZE; -pub const USER_TMP_HEAP_PML4: usize = (USER_TMP_HEAP_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset to user temporary page for grants -pub const USER_TMP_GRANT_OFFSET: usize = USER_TMP_HEAP_OFFSET + PML4_SIZE; -pub const USER_TMP_GRANT_PML4: usize = (USER_TMP_GRANT_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset to user temporary stack (used when cloning) -pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_GRANT_OFFSET + PML4_SIZE; -pub const USER_TMP_STACK_PML4: usize = (USER_TMP_STACK_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset to user temporary sigstack (used when cloning) -pub const USER_TMP_SIGSTACK_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE; -pub const USER_TMP_SIGSTACK_PML4: usize = (USER_TMP_SIGSTACK_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset to user temporary tls (used when cloning) -pub const USER_TMP_TLS_OFFSET: usize = USER_TMP_SIGSTACK_OFFSET + PML4_SIZE; -pub const USER_TMP_TLS_PML4: usize = (USER_TMP_TLS_OFFSET & PML4_MASK) / PML4_SIZE; - -/// Offset for usage in other temporary pages -pub const USER_TMP_MISC_OFFSET: usize = USER_TMP_TLS_OFFSET + PML4_SIZE; -pub const USER_TMP_MISC_PML4: usize = (USER_TMP_MISC_OFFSET & PML4_MASK) / PML4_SIZE; From 88e1055eed64e4808591f64c79e810f664f46bd4 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 30 Apr 2019 11:34:31 +0800 Subject: [PATCH 54/61] refactor fork MemorySet, introduce clone_map to MemoryHandler --- .../memory/src/memory_set/handler/byframe.rs | 14 ++++ crate/memory/src/memory_set/handler/delay.rs | 30 +++++++-- crate/memory/src/memory_set/handler/linear.rs | 10 +++ crate/memory/src/memory_set/handler/mod.rs | 23 ++++--- crate/memory/src/memory_set/mod.rs | 51 ++++++--------- kernel/src/process/structs.rs | 65 ++++++++----------- 6 files changed, 109 insertions(+), 84 deletions(-) diff --git a/crate/memory/src/memory_set/handler/byframe.rs b/crate/memory/src/memory_set/handler/byframe.rs index e7f90db..f01eca6 100644 --- a/crate/memory/src/memory_set/handler/byframe.rs +++ b/crate/memory/src/memory_set/handler/byframe.rs @@ -22,6 +22,20 @@ impl MemoryHandler for ByFrame { pt.unmap(addr); } + fn clone_map( + &self, + pt: &mut PageTable, + with: &Fn(&mut FnMut()), + addr: VirtAddr, + attr: &MemoryAttr, + ) { + let data = Vec::from(pt.get_page_slice_mut(addr)); + with(&mut || { + self.map(pt, addr, attr); + pt.get_page_slice_mut(addr).copy_from_slice(&data); + }); + } + fn handle_page_fault(&self, _pt: &mut PageTable, _addr: VirtAddr) -> bool { false } diff --git a/crate/memory/src/memory_set/handler/delay.rs b/crate/memory/src/memory_set/handler/delay.rs index 4bed477..6195091 100644 --- a/crate/memory/src/memory_set/handler/delay.rs +++ b/crate/memory/src/memory_set/handler/delay.rs @@ -16,13 +16,6 @@ impl MemoryHandler for Delay { attr.apply(entry); } - fn map_eager(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr) { - let target = self.allocator.alloc().expect("failed to alloc frame"); - let entry = pt.map(addr, target); - entry.set_present(true); - attr.apply(entry); - } - fn unmap(&self, pt: &mut PageTable, addr: VirtAddr) { let entry = pt.get_entry(addr).expect("failed to get entry"); if entry.present() { @@ -34,6 +27,29 @@ impl MemoryHandler for Delay { pt.unmap(addr); } + fn clone_map( + &self, + pt: &mut PageTable, + with: &Fn(&mut FnMut()), + addr: VirtAddr, + attr: &MemoryAttr, + ) { + let entry = pt.get_entry(addr).expect("failed to get entry"); + if entry.present() { + // eager map and copy data + let data = Vec::from(pt.get_page_slice_mut(addr)); + with(&mut || { + let target = self.allocator.alloc().expect("failed to alloc frame"); + let entry = pt.map(addr, target); + attr.apply(entry); + pt.get_page_slice_mut(addr).copy_from_slice(&data); + }); + } else { + // delay map + with(&mut || self.map(pt, addr, attr)); + } + } + fn handle_page_fault(&self, pt: &mut PageTable, addr: VirtAddr) -> bool { let entry = pt.get_entry(addr).expect("failed to get entry"); if entry.present() { diff --git a/crate/memory/src/memory_set/handler/linear.rs b/crate/memory/src/memory_set/handler/linear.rs index 1e10b90..1645f91 100644 --- a/crate/memory/src/memory_set/handler/linear.rs +++ b/crate/memory/src/memory_set/handler/linear.rs @@ -20,6 +20,16 @@ impl MemoryHandler for Linear { pt.unmap(addr); } + fn clone_map( + &self, + pt: &mut PageTable, + with: &Fn(&mut FnMut()), + addr: VirtAddr, + attr: &MemoryAttr, + ) { + with(&mut || self.map(pt, addr, attr)); + } + fn handle_page_fault(&self, _pt: &mut PageTable, _addr: VirtAddr) -> bool { false } diff --git a/crate/memory/src/memory_set/handler/mod.rs b/crate/memory/src/memory_set/handler/mod.rs index fd6602c..32d6c54 100644 --- a/crate/memory/src/memory_set/handler/mod.rs +++ b/crate/memory/src/memory_set/handler/mod.rs @@ -1,23 +1,28 @@ use super::*; // here may be a interesting part for lab -pub trait MemoryHandler: Debug + 'static { +pub trait MemoryHandler: Debug + Send + Sync + 'static { fn box_clone(&self) -> Box; /// Map `addr` in the page table /// Should set page flags here instead of in page_fault_handler fn map(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr); - /// Map `addr` in the page table eagerly (i.e. no delay allocation) - /// Should set page flags here instead of in page_fault_handler - fn map_eager(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr) { - // override this when pages are allocated lazily - self.map(pt, addr, attr); - } - /// Unmap `addr` in the page table fn unmap(&self, pt: &mut PageTable, addr: VirtAddr); + /// Clone map `addr` from one page table to another. + /// `pt` is the current active page table. + /// `with` is the `InactivePageTable::with` function. + /// Call `with` then use `pt` as target page table inside. + fn clone_map( + &self, + pt: &mut PageTable, + with: &Fn(&mut FnMut()), + addr: VirtAddr, + attr: &MemoryAttr, + ); + /// Handle page fault on `addr` /// Return true if success, false if error fn handle_page_fault(&self, pt: &mut PageTable, addr: VirtAddr) -> bool; @@ -29,7 +34,7 @@ impl Clone for Box { } } -pub trait FrameAllocator: Debug + Clone + 'static { +pub trait FrameAllocator: Debug + Clone + Send + Sync + 'static { fn alloc(&self) -> Option; fn dealloc(&self, target: PhysAddr); } diff --git a/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index 97d0ca3..cf20ed0 100644 --- a/crate/memory/src/memory_set/mod.rs +++ b/crate/memory/src/memory_set/mod.rs @@ -23,8 +23,6 @@ pub struct MemoryArea { name: &'static str, } -unsafe impl Send for MemoryArea {} - impl MemoryArea { /* ** @brief get slice of the content in the memory area @@ -87,31 +85,13 @@ impl MemoryArea { let p3 = Page::of_addr(end_addr - 1) + 1; !(p1 <= p2 || p0 >= p3) } - /* - ** @brief map the memory area to the physice address in a page table - ** @param pt: &mut T::Active the page table to use - ** @retval none - */ + /// Map all pages in the area to page table `pt` fn map(&self, pt: &mut PageTable) { for page in Page::range_of(self.start_addr, self.end_addr) { self.handler.map(pt, page.start_address(), &self.attr); } } - /* - ** @brief map the memory area to the physice address in a page table eagerly - ** @param pt: &mut T::Active the page table to use - ** @retval none - */ - fn map_eager(&self, pt: &mut PageTable) { - for page in Page::range_of(self.start_addr, self.end_addr) { - self.handler.map_eager(pt, page.start_address(), &self.attr); - } - } - /* - ** @brief unmap the memory area from the physice address in a page table - ** @param pt: &mut T::Active the page table to use - ** @retval none - */ + /// Unmap all pages in the area from page table `pt` fn unmap(&self, pt: &mut PageTable) { for page in Page::range_of(self.start_addr, self.end_addr) { self.handler.unmap(pt, page.start_address()); @@ -509,20 +489,29 @@ impl MemorySet { None => false, } } -} -impl Clone for MemorySet { - fn clone(&self) -> Self { - let mut page_table = T::new(); + pub fn clone(&mut self) -> Self { + let new_page_table = T::new(); + let Self { + ref mut page_table, + ref areas, + .. + } = self; page_table.edit(|pt| { - // without CoW, we should allocate the pages eagerly - for area in self.areas.iter() { - area.map_eager(pt); + for area in areas.iter() { + for page in Page::range_of(area.start_addr, area.end_addr) { + area.handler.clone_map( + pt, + &|f| unsafe { new_page_table.with(f) }, + page.start_address(), + &area.attr, + ); + } } }); MemorySet { - areas: self.areas.clone(), - page_table, + areas: areas.clone(), + page_table: new_page_table, } } } diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 5c5a292..3e08ff2 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -14,7 +14,7 @@ use xmas_elf::{ use crate::arch::interrupt::{Context, TrapFrame}; use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH}; -use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; +use crate::memory::{ByFrame, Delay, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; use crate::sync::{Condvar, SpinNoIrqLock as Mutex}; use super::abi::{self, ProcInitInfo}; @@ -181,6 +181,14 @@ impl Thread { let ustack_top = USER_STACK_OFFSET + USER_STACK_SIZE; vm.push( ustack_buttom, + ustack_top - PAGE_SIZE, + MemoryAttr::default().user(), + Delay::new(GlobalFrameAlloc), + "user_stack_delay", + ); + // We are going to write init info now. So map the last page eagerly. + vm.push( + ustack_top - PAGE_SIZE, ustack_top, MemoryAttr::default().user(), ByFrame::new(GlobalFrameAlloc), @@ -284,42 +292,30 @@ impl Thread { /// Fork a new process from current one pub fn fork(&self, tf: &TrapFrame) -> Box { - // Clone memory set, make a new page table - let proc = self.proc.lock(); - let vm = proc.vm.clone(); - let files = proc.files.clone(); - let cwd = proc.cwd.clone(); - drop(proc); - let parent = Some(self.proc.clone()); - debug!("fork: finish clone MemorySet"); - - // MMU: copy data to the new space - // NoMMU: coping data has been done in `vm.clone()` - for area in vm.iter() { - let data = Vec::::from(unsafe { area.as_slice() }); - unsafe { vm.with(|| area.as_slice_mut().copy_from_slice(data.as_slice())) } - } - - debug!("fork: temporary copy data!"); + let mut proc = self.proc.lock(); let kstack = KernelStack::new(); + let vm = proc.vm.clone(); + let context = unsafe { Context::new_fork(tf, kstack.top(), vm.token()) }; + let new_proc = Process { + vm, + files: proc.files.clone(), + cwd: proc.cwd.clone(), + futexes: BTreeMap::default(), + pid: Pid(0), + parent: Some(self.proc.clone()), + children: Vec::new(), + threads: Vec::new(), + child_exit: Arc::new(Condvar::new()), + child_exit_code: BTreeMap::new(), + }.add_to_table(); + // link to parent + proc.children.push(Arc::downgrade(&new_proc)); Box::new(Thread { - context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) }, + context, kstack, clear_child_tid: 0, - proc: Process { - vm, - files, - cwd, - futexes: BTreeMap::default(), - pid: Pid(0), - parent, - children: Vec::new(), - threads: Vec::new(), - child_exit: Arc::new(Condvar::new()), - child_exit_code: BTreeMap::new(), - } - .add_to_table(), + proc: new_proc, }) } @@ -360,11 +356,6 @@ impl Process { let self_ref = Arc::new(Mutex::new(self)); process_table.insert(pid, Arc::downgrade(&self_ref)); - // link to parent - if let Some(parent) = &self_ref.lock().parent { - parent.lock().children.push(Arc::downgrade(&self_ref)); - } - self_ref } fn get_free_fd(&self) -> usize { From a25c8132fe1c7f86d6acb1324c9eb54eda34ec6e Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 30 Apr 2019 13:37:31 +0800 Subject: [PATCH 55/61] delay mapping file --- crate/memory/src/memory_set/handler/delay.rs | 3 +- crate/memory/src/memory_set/handler/file.rs | 108 +++++++++++++++++++ crate/memory/src/memory_set/handler/mod.rs | 2 + kernel/src/fs/file.rs | 4 + kernel/src/process/structs.rs | 94 ++++++++-------- kernel/src/shell.rs | 14 +-- kernel/src/syscall/mem.rs | 28 ++--- kernel/src/syscall/mod.rs | 2 +- kernel/src/syscall/proc.rs | 11 +- 9 files changed, 188 insertions(+), 78 deletions(-) create mode 100644 crate/memory/src/memory_set/handler/file.rs diff --git a/crate/memory/src/memory_set/handler/delay.rs b/crate/memory/src/memory_set/handler/delay.rs index 6195091..ac4e856 100644 --- a/crate/memory/src/memory_set/handler/delay.rs +++ b/crate/memory/src/memory_set/handler/delay.rs @@ -40,9 +40,10 @@ impl MemoryHandler for Delay { let data = Vec::from(pt.get_page_slice_mut(addr)); with(&mut || { let target = self.allocator.alloc().expect("failed to alloc frame"); + let target_data = pt.get_page_slice_mut(addr); let entry = pt.map(addr, target); + target_data.copy_from_slice(&data); attr.apply(entry); - pt.get_page_slice_mut(addr).copy_from_slice(&data); }); } else { // delay map diff --git a/crate/memory/src/memory_set/handler/file.rs b/crate/memory/src/memory_set/handler/file.rs new file mode 100644 index 0000000..09f0acb --- /dev/null +++ b/crate/memory/src/memory_set/handler/file.rs @@ -0,0 +1,108 @@ +use super::*; + +/// Delay mapping a page to an area of a file. +#[derive(Clone)] +pub struct File { + pub file: F, + pub mem_start: usize, + pub file_start: usize, + pub file_end: usize, + pub allocator: T, +} + +pub trait Read: Clone + Send + Sync + 'static { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize; +} + +impl MemoryHandler for File { + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn map(&self, pt: &mut PageTable, addr: usize, attr: &MemoryAttr) { + let entry = pt.map(addr, 0); + entry.set_present(false); + attr.apply(entry); + } + + fn unmap(&self, pt: &mut PageTable, addr: usize) { + let entry = pt.get_entry(addr).expect("failed to get entry"); + if entry.present() { + self.allocator.dealloc(entry.target()); + } + + // PageTable::unmap requires page to be present + entry.set_present(true); + pt.unmap(addr); + } + + fn clone_map( + &self, + pt: &mut PageTable, + with: &Fn(&mut FnMut()), + addr: usize, + attr: &MemoryAttr, + ) { + let entry = pt.get_entry(addr).expect("failed to get entry"); + if entry.present() && !attr.readonly { + // eager map and copy data + let data = Vec::from(pt.get_page_slice_mut(addr)); + with(&mut || { + let target = self.allocator.alloc().expect("failed to alloc frame"); + let target_data = pt.get_page_slice_mut(addr); + let entry = pt.map(addr, target); + target_data.copy_from_slice(&data); + attr.apply(entry); + }); + } else { + // delay map + with(&mut || self.map(pt, addr, attr)); + } + } + + fn handle_page_fault(&self, pt: &mut PageTable, addr: usize) -> bool { + let addr = addr & !(PAGE_SIZE - 1); + let entry = pt.get_entry(addr).expect("failed to get entry"); + if entry.present() { + return false; + } + let frame = self.allocator.alloc().expect("failed to alloc frame"); + entry.set_target(frame); + entry.set_present(true); + let writable = entry.writable(); + entry.set_writable(true); + entry.update(); + + self.fill_data(pt, addr); + + let entry = pt.get_entry(addr).expect("failed to get entry"); + entry.set_writable(writable); + entry.update(); + + true + } +} + +impl File { + fn fill_data(&self, pt: &mut PageTable, addr: VirtAddr) { + let data = pt.get_page_slice_mut(addr); + let file_offset = addr + self.file_start - self.mem_start; + let read_size = (self.file_end as isize - file_offset as isize) + .min(PAGE_SIZE as isize) + .max(0) as usize; + let read_size = self.file.read_at(file_offset, &mut data[..read_size]); + if read_size != PAGE_SIZE { + data[read_size..].iter_mut().for_each(|x| *x = 0); + } + } +} + +impl Debug for File { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + f.debug_struct("FileHandler") + .field("mem_start", &self.mem_start) + .field("file_start", &self.file_start) + .field("file_end", &self.file_end) + .finish() + } +} diff --git a/crate/memory/src/memory_set/handler/mod.rs b/crate/memory/src/memory_set/handler/mod.rs index 32d6c54..6154e96 100644 --- a/crate/memory/src/memory_set/handler/mod.rs +++ b/crate/memory/src/memory_set/handler/mod.rs @@ -42,8 +42,10 @@ pub trait FrameAllocator: Debug + Clone + Send + Sync + 'static { mod byframe; mod delay; mod linear; +mod file; //mod swap; pub use self::byframe::ByFrame; pub use self::delay::Delay; pub use self::linear::Linear; +pub use self::file::{File, Read}; diff --git a/kernel/src/fs/file.rs b/kernel/src/fs/file.rs index 5e1b84f..3979c4d 100644 --- a/kernel/src/fs/file.rs +++ b/kernel/src/fs/file.rs @@ -116,4 +116,8 @@ impl FileHandle { pub fn io_control(&self, cmd: u32, arg: usize) -> Result<()> { self.inode.io_control(cmd, arg) } + + pub fn inode(&self) -> Arc { + self.inode.clone() + } } diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 3e08ff2..251203c 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -14,10 +14,13 @@ use xmas_elf::{ use crate::arch::interrupt::{Context, TrapFrame}; use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH}; -use crate::memory::{ByFrame, Delay, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; +use crate::memory::{ + ByFrame, Delay, File, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet, Read, +}; use crate::sync::{Condvar, SpinNoIrqLock as Mutex}; use super::abi::{self, ProcInitInfo}; +use rcore_fs::vfs::INode; // TODO: avoid pub pub struct Thread { @@ -128,19 +131,25 @@ impl Thread { /// Construct virtual memory of a new user process from ELF `data`. /// Return `(MemorySet, entry_point, ustack_top)` pub fn new_user_vm( - data: &[u8], + inode: &Arc, exec_path: &str, mut args: Vec, envs: Vec, - ) -> (MemorySet, usize, usize) { + ) -> Result<(MemorySet, usize, usize), &'static str> { + // Read data + use crate::fs::INodeExt; + let data = inode + .read_as_vec() + .map_err(|_| "failed to read from INode")?; + // Parse ELF - let elf = ElfFile::new(data).expect("failed to read elf"); + let elf = ElfFile::new(&data)?; // Check ELF type match elf.header.pt2.type_().as_type() { header::Type::Executable => {} header::Type::SharedObject => {} - _ => panic!("ELF is not executable or shared object"), + _ => return Err("ELF is not executable or shared object"), } // Check ELF arch @@ -153,7 +162,7 @@ impl Thread { header::Machine::Other(243) => {} #[cfg(target_arch = "mips")] header::Machine::Mips => {} - machine @ _ => panic!("invalid elf arch: {:?}", machine), + machine @ _ => return Err("invalid ELF arch"), } // Check interpreter (for dynamic link) @@ -161,18 +170,17 @@ impl Thread { // assuming absolute path let inode = crate::fs::ROOT_INODE .lookup_follow(loader_path, FOLLOW_MAX_DEPTH) - .expect("interpreter not found"); - let buf = inode.read_as_vec().expect("failed to load interpreter"); + .map_err(|_| "interpreter not found")?; // modify args for loader args[0] = exec_path.into(); args.insert(0, loader_path.into()); // Elf loader should not have INTERP // No infinite loop - return Thread::new_user_vm(buf.as_slice(), exec_path, args, envs); + return Thread::new_user_vm(&inode, exec_path, args, envs); } // Make page table - let mut vm = elf.make_memory_set(); + let mut vm = elf.make_memory_set(inode); // User stack use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE}; @@ -219,17 +227,17 @@ impl Thread { trace!("{:#x?}", vm); let entry_addr = elf.header.pt2.entry_point() as usize; - (vm, entry_addr, ustack_top) + Ok((vm, entry_addr, ustack_top)) } /// Make a new user process from ELF `data` pub fn new_user( - data: &[u8], + inode: &Arc, exec_path: &str, mut args: Vec, envs: Vec, ) -> Box { - let (vm, entry_addr, ustack_top) = Self::new_user_vm(data, exec_path, args, envs); + let (vm, entry_addr, ustack_top) = Self::new_user_vm(inode, exec_path, args, envs).unwrap(); let kstack = KernelStack::new(); @@ -307,7 +315,8 @@ impl Thread { threads: Vec::new(), child_exit: Arc::new(Condvar::new()), child_exit_code: BTreeMap::new(), - }.add_to_table(); + } + .add_to_table(); // link to parent proc.children.push(Arc::downgrade(&new_proc)); @@ -382,10 +391,12 @@ trait ToMemoryAttr { impl ToMemoryAttr for Flags { fn to_attr(&self) -> MemoryAttr { let mut flags = MemoryAttr::default().user(); - // FIXME: handle readonly if self.is_execute() { flags = flags.execute(); } + if !self.is_write() { + flags = flags.readonly(); + } flags } } @@ -393,7 +404,7 @@ impl ToMemoryAttr for Flags { /// Helper functions to process ELF file trait ElfExt { /// Generate a MemorySet according to the ELF file. - fn make_memory_set(&self) -> MemorySet; + fn make_memory_set(&self, inode: &Arc) -> MemorySet; /// Get interpreter string if it has. fn get_interpreter(&self) -> Result<&str, &str>; @@ -403,7 +414,7 @@ trait ElfExt { } impl ElfExt for ElfFile<'_> { - fn make_memory_set(&self) -> MemorySet { + fn make_memory_set(&self, inode: &Arc) -> MemorySet { debug!("creating MemorySet from ELF"); let mut ms = MemorySet::new(); @@ -411,33 +422,19 @@ impl ElfExt for ElfFile<'_> { if ph.get_type() != Ok(Type::Load) { continue; } - let virt_addr = ph.virtual_addr() as usize; - let mem_size = ph.mem_size() as usize; - let data = match ph.get_data(self).unwrap() { - SegmentData::Undefined(data) => data, - _ => unreachable!(), - }; - - // Get target slice - let target = { - ms.push( - virt_addr, - virt_addr + mem_size, - ph.flags().to_attr(), - ByFrame::new(GlobalFrameAlloc), - "elf", - ); - unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) } - }; - // Copy data - unsafe { - ms.with(|| { - if data.len() != 0 { - target[..data.len()].copy_from_slice(data); - } - target[data.len()..].iter_mut().for_each(|x| *x = 0); - }); - } + ms.push( + ph.virtual_addr() as usize, + ph.virtual_addr() as usize + ph.mem_size() as usize, + ph.flags().to_attr(), + File { + file: INodeForMap(inode.clone()), + mem_start: ph.virtual_addr() as usize, + file_start: ph.offset() as usize, + file_end: ph.offset() as usize + ph.file_size() as usize, + allocator: GlobalFrameAlloc, + }, + "elf", + ); } ms } @@ -479,3 +476,12 @@ impl ElfExt for ElfFile<'_> { } } } + +#[derive(Clone)] +pub struct INodeForMap(pub Arc); + +impl Read for INodeForMap { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize { + self.0.read_at(offset, buf).unwrap() + } +} diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index 61431e8..57bf14c 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -30,9 +30,8 @@ pub fn add_user_shell() { let init_args = vec!["busybox".into(), "ash".into()]; if let Ok(inode) = ROOT_INODE.lookup(init_shell) { - let data = inode.read_as_vec().unwrap(); processor().manager().add(Thread::new_user( - data.as_slice(), + &inode, init_shell, init_args, init_envs, @@ -46,9 +45,8 @@ pub fn add_user_shell() { pub fn add_user_shell() { let cmdline = CMDLINE.read(); let inode = ROOT_INODE.lookup(&cmdline).unwrap(); - let data = inode.read_as_vec().unwrap(); processor().manager().add(Thread::new_user( - data.as_slice(), + &inode, cmdline.split(' ').map(|s| s.into()).collect(), Vec::new(), )); @@ -66,16 +64,14 @@ pub extern "C" fn shell(_arg: usize) -> ! { continue; } let name = cmd.trim().split(' ').next().unwrap(); - if let Ok(file) = ROOT_INODE.lookup(name) { - let data = file.read_as_vec().unwrap(); - let _pid = processor().manager().add(Thread::new_user( - data.as_slice(), + if let Ok(inode) = ROOT_INODE.lookup(name) { + let _tid = processor().manager().add(Thread::new_user( + &inode, &cmd, cmd.split(' ').map(|s| s.into()).collect(), Vec::new(), )); // TODO: wait until process exits, or use user land shell completely - //unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap(); } else { println!("Program not exist"); } diff --git a/kernel/src/syscall/mem.rs b/kernel/src/syscall/mem.rs index dd2b3e2..d108a7c 100644 --- a/kernel/src/syscall/mem.rs +++ b/kernel/src/syscall/mem.rs @@ -1,4 +1,4 @@ -use rcore_memory::memory_set::handler::{ByFrame, Delay}; +use rcore_memory::memory_set::handler::{ByFrame, Delay, File}; use rcore_memory::memory_set::MemoryAttr; use rcore_memory::paging::PageTable; use rcore_memory::Page; @@ -46,35 +46,25 @@ pub fn sys_mmap( addr, addr + len, prot.to_attr(), - // ByFrame::new(GlobalFrameAlloc), //eagle mmap mode Delay::new(GlobalFrameAlloc), "mmap_anon", ); - //init with zero for eagle mmap mode - // let data = unsafe { slice::from_raw_parts_mut(addr as *mut u8, len) }; - // for x in data { - // *x = 0; - // } return Ok(addr); } else { - // only check - let _ = proc.get_file(fd)?; - - // TODO: delay mmap file + let inode = proc.get_file(fd)?.inode(); proc.vm.push( addr, addr + len, prot.to_attr(), - ByFrame::new(GlobalFrameAlloc), + File { + file: INodeForMap(inode), + mem_start: addr, + file_start: offset, + file_end: offset + len, + allocator: GlobalFrameAlloc, + }, "mmap_file", ); - let data = unsafe { slice::from_raw_parts_mut(addr as *mut u8, len) }; - let file = proc.get_file(fd)?; - let read_len = file.read_at(offset, data)?; - if read_len != data.len() { - // use count() to consume the iterator - data[read_len..].iter_mut().map(|x| *x = 0).count(); - } return Ok(addr); } } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 7b7483c..c247f15 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -329,7 +329,7 @@ fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option sys_dup2(args[0], args[1]), SYS_ALARM => unimplemented("alarm", Ok(0)), SYS_FORK => sys_fork(tf), - SYS_VFORK => sys_fork(tf), // use fork for vfork + SYS_VFORK => sys_vfork(tf), SYS_RENAME => sys_rename(args[0] as *const u8, args[1] as *const u8), SYS_MKDIR => sys_mkdir(args[0] as *const u8, args[1]), SYS_RMDIR => sys_rmdir(args[0] as *const u8), diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 8114b06..7fc1f47 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -13,6 +13,10 @@ pub fn sys_fork(tf: &TrapFrame) -> SysResult { Ok(pid) } +pub fn sys_vfork(tf: &TrapFrame) -> SysResult { + sys_fork(tf) +} + /// Create a new thread in the current process. /// The new thread's stack pointer will be set to `newsp`, /// and thread pointer will be set to `newtls`. @@ -168,16 +172,15 @@ pub fn sys_exec( // Read program file let inode = proc.lookup_inode(&path)?; - let data = inode.read_as_vec()?; // Make new Thread - let (mut vm, entry_addr, ustack_top) = Thread::new_user_vm(data.as_slice(), &path, args, envs); + let (mut vm, entry_addr, ustack_top) = Thread::new_user_vm(&inode, &path, args, envs).unwrap(); // Activate new page table + core::mem::swap(&mut proc.vm, &mut vm); unsafe { - vm.activate(); + proc.vm.activate(); } - core::mem::swap(&mut proc.vm, &mut vm); // Modify the TrapFrame *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); From 60cdea81d988a458ef2a503cfad3a727ee1b4fdc Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 30 Apr 2019 16:28:46 +0800 Subject: [PATCH 56/61] fix check user ptr across VMAs --- crate/memory/src/memory_set/mod.rs | 54 ++++++++++++++++++++---------- kernel/src/process/structs.rs | 6 ++-- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index cf20ed0..9eb566a 100644 --- a/crate/memory/src/memory_set/mod.rs +++ b/crate/memory/src/memory_set/mod.rs @@ -3,6 +3,7 @@ use alloc::{boxed::Box, string::String, vec::Vec}; use core::fmt::{Debug, Error, Formatter}; +use core::mem::size_of; use crate::paging::*; @@ -52,16 +53,27 @@ impl MemoryArea { pub fn contains(&self, addr: VirtAddr) -> bool { addr >= self.start_addr && addr < self.end_addr } - /// Check the array is within the readable memory - fn check_read_array(&self, ptr: *const S, count: usize) -> bool { + /// Check the array is within the readable memory. + /// Return the size of space covered in the area. + fn check_read_array(&self, ptr: *const S, count: usize) -> usize { // page align - ptr as usize >= Page::of_addr(self.start_addr).start_address() - && unsafe { ptr.add(count) as usize } - < Page::of_addr(self.end_addr + PAGE_SIZE - 1).start_address() + let min_bound = (ptr as usize).max(Page::of_addr(self.start_addr).start_address()); + let max_bound = unsafe { ptr.add(count) as usize } + .min(Page::of_addr(self.end_addr + PAGE_SIZE - 1).start_address()); + if max_bound >= min_bound { + max_bound - min_bound + } else { + 0 + } } - /// Check the array is within the writable memory - fn check_write_array(&self, ptr: *mut S, count: usize) -> bool { - !self.attr.readonly && self.check_read_array(ptr, count) + /// Check the array is within the writable memory. + /// Return the size of space covered in the area. + fn check_write_array(&self, ptr: *mut S, count: usize) -> usize { + if self.attr.readonly { + 0 + } else { + self.check_read_array(ptr, count) + } } /// Check the null-end C string is within the readable memory, and is valid. /// If so, clone it to a String. @@ -198,11 +210,14 @@ impl MemorySet { ptr: *const S, count: usize, ) -> VMResult<&'static [S]> { - self.areas - .iter() - .find(|area| area.check_read_array(ptr, count)) - .map(|_| core::slice::from_raw_parts(ptr, count)) - .ok_or(VMError::InvalidPtr) + let mut valid_size = 0; + for area in self.areas.iter() { + valid_size += area.check_read_array(ptr, count); + if valid_size == size_of::() * count { + return Ok(core::slice::from_raw_parts(ptr, count)); + } + } + Err(VMError::InvalidPtr) } /// Check the array is within the writable memory pub unsafe fn check_write_array( @@ -210,11 +225,14 @@ impl MemorySet { ptr: *mut S, count: usize, ) -> VMResult<&'static mut [S]> { - self.areas - .iter() - .find(|area| area.check_write_array(ptr, count)) - .map(|_| core::slice::from_raw_parts_mut(ptr, count)) - .ok_or(VMError::InvalidPtr) + let mut valid_size = 0; + for area in self.areas.iter() { + valid_size += area.check_write_array(ptr, count); + if valid_size == size_of::() * count { + return Ok(core::slice::from_raw_parts_mut(ptr, count)); + } + } + Err(VMError::InvalidPtr) } /// Check the null-end C string pointer array /// Used for getting argv & envp diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 251203c..f9f07be 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -189,14 +189,14 @@ impl Thread { let ustack_top = USER_STACK_OFFSET + USER_STACK_SIZE; vm.push( ustack_buttom, - ustack_top - PAGE_SIZE, + ustack_top - PAGE_SIZE * 4, MemoryAttr::default().user(), Delay::new(GlobalFrameAlloc), "user_stack_delay", ); - // We are going to write init info now. So map the last page eagerly. + // We are going to write init info now. So map the last 4 pages eagerly. vm.push( - ustack_top - PAGE_SIZE, + ustack_top - PAGE_SIZE * 4, ustack_top, MemoryAttr::default().user(), ByFrame::new(GlobalFrameAlloc), From bd158e4e74ad556351a59f5c52375c738234c975 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 30 Apr 2019 17:10:35 +0800 Subject: [PATCH 57/61] Do not panic when exec file is invalid --- kernel/src/shell.rs | 9 +++------ kernel/src/syscall/proc.rs | 28 +++++++++++++++++----------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index 57bf14c..84c4367 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -30,12 +30,9 @@ pub fn add_user_shell() { let init_args = vec!["busybox".into(), "ash".into()]; if let Ok(inode) = ROOT_INODE.lookup(init_shell) { - processor().manager().add(Thread::new_user( - &inode, - init_shell, - init_args, - init_envs, - )); + processor() + .manager() + .add(Thread::new_user(&inode, init_shell, init_args, init_envs)); } else { processor().manager().add(Thread::new_kernel(shell, 0)); } diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 7fc1f47..4cb982f 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -174,19 +174,25 @@ pub fn sys_exec( let inode = proc.lookup_inode(&path)?; // Make new Thread - let (mut vm, entry_addr, ustack_top) = Thread::new_user_vm(&inode, &path, args, envs).unwrap(); - - // Activate new page table - core::mem::swap(&mut proc.vm, &mut vm); - unsafe { - proc.vm.activate(); - } + match Thread::new_user_vm(&inode, &path, args, envs) { + Ok((mut vm, entry_addr, ustack_top)) => { + // Activate new page table + core::mem::swap(&mut proc.vm, &mut vm); + unsafe { + proc.vm.activate(); + } - // Modify the TrapFrame - *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); + // Modify the TrapFrame + *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); - info!("exec:END: path: {:?}", path); - Ok(0) + info!("exec:END: path: {:?}", path); + Ok(0) + } + Err(err) => { + info!("exec failed with {}", err); + Err(SysError::EINVAL) + } + } } pub fn sys_yield() -> SysResult { From c885ea6d776d4d1238e5bc8aa9361f18e672f239 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 30 Apr 2019 17:31:29 +0800 Subject: [PATCH 58/61] impl pseudo INode '/proc/self/exe' --- kernel/Cargo.lock | 4 +- kernel/src/fs/mod.rs | 2 + kernel/src/fs/pseudo.rs | 78 +++++++++++++++++++++++++++++++++++ kernel/src/process/structs.rs | 5 ++- kernel/src/syscall/fs.rs | 13 +++++- kernel/src/syscall/mod.rs | 5 +-- kernel/src/syscall/proc.rs | 32 +++++++------- 7 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 kernel/src/fs/pseudo.rs diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 74ae4b9..24ac173 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -402,12 +402,12 @@ dependencies = [ [[package]] name = "rcore-fs" version = "0.1.0" -source = "git+https://github.com/rcore-os/rcore-fs#64d399fe664927f14853c22943a4bdeb34095f99" +source = "git+https://github.com/rcore-os/rcore-fs#6f282baf2fe928d2c9774e526e63125684855221" [[package]] name = "rcore-fs-sfs" version = "0.1.0" -source = "git+https://github.com/rcore-os/rcore-fs#64d399fe664927f14853c22943a4bdeb34095f99" +source = "git+https://github.com/rcore-os/rcore-fs#6f282baf2fe928d2c9774e526e63125684855221" dependencies = [ "bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index 1b772a9..256ce5e 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -10,12 +10,14 @@ pub use self::file::*; pub use self::file_like::*; pub use self::pipe::Pipe; pub use self::stdio::{STDIN, STDOUT}; +pub use self::pseudo::*; mod device; mod file; mod file_like; mod pipe; mod stdio; +mod pseudo; /// Hard link user programs #[cfg(feature = "link_user")] diff --git a/kernel/src/fs/pseudo.rs b/kernel/src/fs/pseudo.rs new file mode 100644 index 0000000..6da58c0 --- /dev/null +++ b/kernel/src/fs/pseudo.rs @@ -0,0 +1,78 @@ +//! Pseudo file system INode + +use alloc::{string::String, sync::Arc, vec::Vec}; +use core::any::Any; + +use rcore_fs::vfs::*; + +pub struct Pseudo { + content: Vec, + type_: FileType, +} + +impl Pseudo { + pub fn new(s: &str, type_: FileType) -> Self { + Pseudo { + content: Vec::from(s.as_bytes()), + type_ + } + } +} + +// TODO: better way to provide default impl? +macro_rules! impl_inode { + () => { + fn set_metadata(&self, _metadata: &Metadata) -> Result<()> { Ok(()) } + fn sync_all(&self) -> Result<()> { Ok(()) } + fn sync_data(&self) -> Result<()> { Ok(()) } + fn resize(&self, _len: usize) -> Result<()> { Err(FsError::NotSupported) } + fn create(&self, _name: &str, _type_: FileType, _mode: u32) -> Result> { Err(FsError::NotDir) } + fn unlink(&self, _name: &str) -> Result<()> { Err(FsError::NotDir) } + fn link(&self, _name: &str, _other: &Arc) -> Result<()> { Err(FsError::NotDir) } + fn move_(&self, _old_name: &str, _target: &Arc, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } + fn find(&self, _name: &str) -> Result> { Err(FsError::NotDir) } + fn get_entry(&self, _id: usize) -> Result { Err(FsError::NotDir) } + fn io_control(&self, cmd: u32, data: usize) -> Result<()> { Err(FsError::NotSupported) } + fn fs(&self) -> Arc { unimplemented!() } + fn as_any_ref(&self) -> &Any { self } + }; +} + +impl INode for Pseudo { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + if offset >= self.content.len() { + return Ok(0); + } + let len = (self.content.len() - offset).min(buf.len()); + buf[..len].copy_from_slice(&self.content[offset..offset + len]); + Ok(len) + } + fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { + Err(FsError::NotSupported) + } + fn poll(&self) -> Result { + Ok(PollStatus { + read: true, + write: false, + error: false, + }) + } + fn metadata(&self) -> Result { + Ok(Metadata { + dev: 0, + inode: 0, + size: self.content.len(), + blk_size: 0, + blocks: 0, + atime: Timespec { sec: 0, nsec: 0 }, + mtime: Timespec { sec: 0, nsec: 0 }, + ctime: Timespec { sec: 0, nsec: 0 }, + type_: self.type_, + mode: 0, + nlinks: 0, + uid: 0, + gid: 0, + }) + } + impl_inode!(); +} diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index f9f07be..bdb72d7 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -59,6 +59,7 @@ pub struct Process { pub vm: MemorySet, pub files: BTreeMap, pub cwd: String, + pub exec_path: String, futexes: BTreeMap>, // relationship @@ -116,6 +117,7 @@ impl Thread { vm, files: BTreeMap::default(), cwd: String::from("/"), + exec_path: String::new(), futexes: BTreeMap::default(), pid: Pid(0), parent: None, @@ -137,7 +139,6 @@ impl Thread { envs: Vec, ) -> Result<(MemorySet, usize, usize), &'static str> { // Read data - use crate::fs::INodeExt; let data = inode .read_as_vec() .map_err(|_| "failed to read from INode")?; @@ -286,6 +287,7 @@ impl Thread { vm, files, cwd: String::from("/"), + exec_path: String::from(exec_path), futexes: BTreeMap::default(), pid: Pid(0), parent: None, @@ -308,6 +310,7 @@ impl Thread { vm, files: proc.files.clone(), cwd: proc.cwd.clone(), + exec_path: proc.exec_path.clone(), futexes: BTreeMap::default(), pid: Pid(0), parent: Some(self.proc.clone()), diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 113a58d..efa0852 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -361,7 +361,10 @@ pub fn sys_readlinkat(dirfd: usize, path: *const u8, base: *mut u8, len: usize) let proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; let slice = unsafe { proc.vm.check_write_array(base, len)? }; - info!("readlink: path: {:?}, base: {:?}, len: {}", path, base, len); + info!( + "readlinkat: dirfd: {}, path: {:?}, base: {:?}, len: {}", + dirfd as isize, path, base, len + ); let inode = proc.lookup_inode_at(dirfd, &path, false)?; if inode.metadata()?.type_ == FileType::SymLink { @@ -753,6 +756,14 @@ impl Process { "lookup_inode_at: dirfd: {:?}, cwd: {:?}, path: {:?}, follow: {:?}", dirfd as isize, self.cwd, path, follow ); + // hard code special path + match path { + "/proc/self/exe" => { + return Ok(Arc::new(Pseudo::new(&self.exec_path, FileType::SymLink))); + } + _ => {} + } + let follow_max_depth = if follow { FOLLOW_MAX_DEPTH } else { 0 }; if dirfd == AT_FDCWD { Ok(ROOT_INODE diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c247f15..45a22a8 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -252,10 +252,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { }; if !pid.is_init() { // we trust pid 0 process - debug!( - "{}:{}:{} syscall id {} ret with {:x?}", - cid, pid, tid, id, ret - ); + info!("=> {:x?}", ret); } match ret { Ok(code) => code as isize, diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 4cb982f..9fcb97e 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -174,25 +174,23 @@ pub fn sys_exec( let inode = proc.lookup_inode(&path)?; // Make new Thread - match Thread::new_user_vm(&inode, &path, args, envs) { - Ok((mut vm, entry_addr, ustack_top)) => { - // Activate new page table - core::mem::swap(&mut proc.vm, &mut vm); - unsafe { - proc.vm.activate(); - } - - // Modify the TrapFrame - *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); + let (mut vm, entry_addr, ustack_top) = + Thread::new_user_vm(&inode, &path, args, envs).map_err(|_| SysError::EINVAL)?; - info!("exec:END: path: {:?}", path); - Ok(0) - } - Err(err) => { - info!("exec failed with {}", err); - Err(SysError::EINVAL) - } + // Activate new page table + core::mem::swap(&mut proc.vm, &mut vm); + unsafe { + proc.vm.activate(); } + + // Modify exec path + proc.exec_path = path.clone(); + + // Modify the TrapFrame + *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); + + info!("exec:END: path: {:?}", path); + Ok(0) } pub fn sys_yield() -> SysResult { From bc1bad3060bc1b0f65b84f273dc54e91d7d27ed5 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 30 Apr 2019 19:21:14 +0800 Subject: [PATCH 59/61] optimize sys_exec: only read ELF header --- kernel/src/process/structs.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index bdb72d7..2ec8dcf 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -20,6 +20,7 @@ use crate::memory::{ use crate::sync::{Condvar, SpinNoIrqLock as Mutex}; use super::abi::{self, ProcInitInfo}; +use core::mem::uninitialized; use rcore_fs::vfs::INode; // TODO: avoid pub @@ -138,9 +139,11 @@ impl Thread { mut args: Vec, envs: Vec, ) -> Result<(MemorySet, usize, usize), &'static str> { - // Read data - let data = inode - .read_as_vec() + // Read ELF header + // 0x3c0: magic number from ld-musl.so + let mut data: [u8; 0x3c0] = unsafe { uninitialized() }; + inode + .read_at(0, &mut data) .map_err(|_| "failed to read from INode")?; // Parse ELF From ba74f93ab885974c5cb58306da7c49008f4af52c Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 30 Apr 2019 19:31:08 +0800 Subject: [PATCH 60/61] x86_64: shrink kernel heap size and remove 'enlarge_heap' --- kernel/src/arch/x86_64/consts.rs | 2 +- kernel/src/arch/x86_64/memory.rs | 32 +------------------------------- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/kernel/src/arch/x86_64/consts.rs b/kernel/src/arch/x86_64/consts.rs index cd44eb2..d872502 100644 --- a/kernel/src/arch/x86_64/consts.rs +++ b/kernel/src/arch/x86_64/consts.rs @@ -1,6 +1,6 @@ pub const MEMORY_OFFSET: usize = 0; pub const KERNEL_OFFSET: usize = 0xffffff00_00000000; -pub const KERNEL_HEAP_SIZE: usize = 32 * 1024 * 1024; // 32 MB +pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024; // 8 MB pub const USER_STACK_OFFSET: usize = 0x00008000_00000000 - USER_STACK_SIZE; pub const USER_STACK_SIZE: usize = 8 * 1024 * 1024; // 8 MB, the default config of Linux diff --git a/kernel/src/arch/x86_64/memory.rs b/kernel/src/arch/x86_64/memory.rs index cadd738..092dc9e 100644 --- a/kernel/src/arch/x86_64/memory.rs +++ b/kernel/src/arch/x86_64/memory.rs @@ -2,9 +2,7 @@ use crate::consts::KERNEL_OFFSET; use bitmap_allocator::BitAlloc; // Depends on kernel use super::{BootInfo, MemoryRegionType}; -use crate::memory::{active_table, alloc_frame, init_heap, FRAME_ALLOCATOR}; -use crate::HEAP_ALLOCATOR; -use alloc::vec::Vec; +use crate::memory::{active_table, init_heap, FRAME_ALLOCATOR}; use log::*; use once::*; use rcore_memory::paging::*; @@ -15,7 +13,6 @@ pub fn init(boot_info: &BootInfo) { init_frame_allocator(boot_info); init_device_vm_map(); init_heap(); - enlarge_heap(); info!("memory: init end"); } @@ -42,30 +39,3 @@ fn init_device_vm_map() { .map(KERNEL_OFFSET + 0xfee00000, 0xfee00000) .update(); } - -fn enlarge_heap() { - let mut page_table = active_table(); - let mut addrs = Vec::new(); - let va_offset = KERNEL_OFFSET + 0xe0000000; - for i in 0..16384 { - let page = alloc_frame().unwrap(); - let va = KERNEL_OFFSET + 0xe0000000 + page; - if let Some((ref mut addr, ref mut len)) = addrs.last_mut() { - if *addr - PAGE_SIZE == va { - *len += PAGE_SIZE; - *addr -= PAGE_SIZE; - continue; - } - } - addrs.push((va, PAGE_SIZE)); - } - for (addr, len) in addrs.into_iter() { - for va in (addr..(addr + len)).step_by(PAGE_SIZE) { - page_table.map(va, va - va_offset).update(); - } - info!("Adding {:#X} {:#X} to heap", addr, len); - unsafe { - HEAP_ALLOCATOR.lock().init(addr, len); - } - } -} From 2f6f8ef9bcfc866c74aa2a553e3cd61cd524dc9b Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 30 Apr 2019 21:32:32 +0800 Subject: [PATCH 61/61] Add syscall timing using rdtsc --- kernel/Cargo.toml | 2 ++ kernel/Makefile | 3 +++ kernel/src/syscall/mod.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 9e9791e..32855b1 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -40,6 +40,8 @@ board_pc = ["link_user"] link_user = [] # Run cmdline instead of user shell, useful for automatic testing run_cmdline = [] +# Add performance profiling +profile = [] [profile.dev] # MUST >= 2 : Enable RVO to avoid stack overflow diff --git a/kernel/Makefile b/kernel/Makefile index 4cd58fd..5de068e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -32,6 +32,7 @@ # init = /bin/ls Only available on riscv64, run specified program instead of user shell # extra_nic = on | off Only available on x86_64, add an additional e1000 nic # u_boot = /path/to/u-boot.bin Only available on aarch64, use u-boot to boot rcore +# . extra_features = profile | ... Add additional features arch ?= riscv64 board ?= none @@ -210,6 +211,8 @@ ifneq ($(board), none) features += board_$(board) endif +features += $(extra_features) + build_args := --target targets/$(target).json --features "$(features)" ifeq ($(mode), release) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 45a22a8..066d0a6 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -31,11 +31,23 @@ mod net; mod proc; mod time; +use spin::Mutex; +use alloc::collections::BTreeMap; + +#[cfg(feature = "profile")] +lazy_static! { + static ref SYSCALL_TIMING: Mutex> = Mutex::new(BTreeMap::new()); +} + /// System call dispatcher // This #[deny(unreachable_patterns)] checks if each match arm is defined // See discussion in https://github.com/oscourse-tsinghua/rcore_plus/commit/17e644e54e494835f1a49b34b80c2c4f15ed0dbe. #[deny(unreachable_patterns)] pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { + #[cfg(feature = "profile")] + let begin_time = unsafe { + core::arch::x86_64::_rdtsc() + }; let cid = cpu::id(); let pid = process().pid.clone(); let tid = processor().tid(); @@ -254,6 +266,21 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { // we trust pid 0 process info!("=> {:x?}", ret); } + #[cfg(feature = "profile")] + { + let end_time = unsafe { + core::arch::x86_64::_rdtsc() + }; + *SYSCALL_TIMING.lock().entry(id).or_insert(0) += end_time - begin_time; + if end_time % 1000 == 0 { + let timing = SYSCALL_TIMING.lock(); + let mut count_vec: Vec<(&usize, &i64)> = timing.iter().collect(); + count_vec.sort_by(|a, b| b.1.cmp(a.1)); + for (id, time) in count_vec.iter().take(5) { + warn!("timing {:03} time {:012}", id, time); + } + } + } match ret { Ok(code) => code as isize, Err(err) => -(err as isize),