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/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/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 fd7b9d3..ac4e856 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,30 @@ 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 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: VirtAddr) -> bool { let entry = pt.get_entry(addr).expect("failed to get entry"); if entry.present() { @@ -44,6 +61,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/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/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..6154e96 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); } @@ -37,8 +42,10 @@ pub trait FrameAllocator: Debug + Clone + '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/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index 77eddc1..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::*; @@ -23,8 +24,6 @@ pub struct MemoryArea { name: &'static str, } -unsafe impl Send for MemoryArea {} - impl MemoryArea { /* ** @brief get slice of the content in the memory area @@ -54,13 +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 { - ptr as usize >= self.start_addr && unsafe { ptr.add(count) as usize } <= self.end_addr + /// 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 + 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. @@ -84,31 +97,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()); @@ -202,28 +197,60 @@ 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<()> { - self.areas - .iter() - .find(|area| area.check_read_array(ptr, count)) - .map(|_| ()) - .ok_or(VMError::InvalidPtr) + pub unsafe fn check_read_array( + &self, + ptr: *const S, + count: usize, + ) -> VMResult<&'static [S]> { + 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 fn check_write_array(&self, ptr: *mut S, count: usize) -> VMResult<()> { - self.areas - .iter() - .find(|area| area.check_write_array(ptr, count)) - .map(|_| ()) - .ok_or(VMError::InvalidPtr) + pub unsafe fn check_write_array( + &self, + ptr: *mut S, + count: usize, + ) -> VMResult<&'static mut [S]> { + 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 + 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. @@ -281,7 +308,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); } /* @@ -472,20 +507,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/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 diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 4848e5e..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)", @@ -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/Cargo.toml b/kernel/Cargo.toml index a226293..32855b1 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -19,9 +19,12 @@ authors = [ ] [features] +default = ["sv39"] # Page table sv39 or sv48 (for riscv64) 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"] @@ -37,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 d21f3f5..5de068e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -23,18 +23,21 @@ # 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 +# | 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 # 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 -mode ?= debug -LOG ?= debug +mode ?= release +LOG ?= graphic ?= off smp ?= 4 pci_passthru ?= @@ -59,7 +62,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 rocket_chip)) #link user img, so use original image export SFSIMG = $(user_dir)/build/$(arch).img else @@ -124,7 +127,9 @@ endif else ifeq ($(arch), riscv32) qemu_opts += \ -machine virt \ - -kernel $(kernel_img) \ + -serial mon:stdio \ + -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 +137,21 @@ qemu_net_opts += \ -device virtio-net-device,netdev=net0 else ifeq ($(arch), riscv64) +ifeq ($(board), u540) qemu_opts += \ -machine virt \ - -kernel $(kernel_img) \ + -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 \ -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 @@ -192,15 +207,12 @@ 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 +features += $(extra_features) + build_args := --target targets/$(target).json --features "$(features)" ifeq ($(mode), release) @@ -297,28 +309,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 +327,12 @@ 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) +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 @@ -383,10 +374,19 @@ endif ifeq ($(board), u540) .PHONY: install: $(kernel_img) - @$(objcopy) -S -O binary --change-addresses -0x80000000 $< $(build_path)/bin - @../tools/u540/mkimg.sh $(build_path)/bin $(build_path)/sd.img + @$(objcopy) -S -O binary ../tools/opensbi/fu540.elf $(build_path)/bin + @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: addr2line: - @python3 ../tools/addr2line.py $(prefix)addr2line $(arch) $(mode) + @python3.7 ../tools/addr2line.py $(prefix)addr2line $(arch) $(mode) 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/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/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/compiler_rt.rs b/kernel/src/arch/mipsel/compiler_rt.rs deleted file mode 100644 index 04ed3c3..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 "C" fn abort() { - panic!("abort"); -} diff --git a/kernel/src/arch/mipsel/consts.rs b/kernel/src/arch/mipsel/consts.rs index 48b1b82..84ae103 100644 --- a/kernel/src/arch/mipsel/consts.rs +++ b/kernel/src/arch/mipsel/consts.rs @@ -6,7 +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 = 0x70000000 - USER_STACK_SIZE; pub const MAX_DTB_SIZE: usize = 0x2000; diff --git a/kernel/src/arch/mipsel/context.rs b/kernel/src/arch/mipsel/context.rs index 69f9016..606fbad 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 { @@ -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; @@ -120,6 +120,7 @@ impl InitStack { extern "C" { fn trap_return(); + fn _cur_tls(); } /// Saved registers for kernel context switches. @@ -130,17 +131,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 +196,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) @@ -214,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) @@ -226,8 +231,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), + context: ContextData::new(satp, tls), tf: { let mut tf = tf.clone(); // fork function's ret value, the new process is 0 @@ -253,20 +259,14 @@ 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 }, } .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/mipsel/cpu.rs b/kernel/src/arch/mipsel/cpu.rs index 932744a..9ee6b4a 100644 --- a/kernel/src/arch/mipsel/cpu.rs +++ b/kernel/src/arch/mipsel/cpu.rs @@ -1,5 +1,6 @@ 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]; @@ -21,7 +22,9 @@ 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) -> ! { diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index bc60547..56757c4 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -70,6 +70,17 @@ 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; + } + } + E::CoprocessorUnusable => { + tf.epc = tf.epc + 4; + } _ => { error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); crate::trap::error(tf) @@ -149,6 +160,75 @@ 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 { + extern "C" { + fn _cur_tls(); + } + + 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; + } + } + + false +} + fn page_fault(tf: &mut TrapFrame) { // TODO: set access/dirty bit let addr = tf.vaddr; @@ -164,6 +244,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/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; 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/board/u540/linker.ld b/kernel/src/arch/riscv32/board/u540/linker.ld index 6bbe85b..87ca826 100644 --- a/kernel/src/arch/riscv32/board/u540/linker.ld +++ b/kernel/src/arch/riscv32/board/u540/linker.ld @@ -6,7 +6,7 @@ OUTPUT_ARCH(riscv) ENTRY(_start) -BASE_ADDRESS = 0xffffffffc0020000; +BASE_ADDRESS = 0xffffffffc0200000; SECTIONS { 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..3ea0676 --- /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, 14 + 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 * 4 * 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..6fbedbb --- /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, 14 + 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 * 4 * 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/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/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..01b9f46 100644 --- a/kernel/src/arch/riscv32/consts.rs +++ b/kernel/src/arch/riscv32/consts.rs @@ -22,17 +22,17 @@ 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; +#[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; -#[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 +#[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 ??? pub const USER_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE; 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/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..314c7f2 100644 --- a/kernel/src/arch/riscv32/memory.rs +++ b/kernel/src/arch/riscv32/memory.rs @@ -8,13 +8,19 @@ 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(); - } // 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); } @@ -86,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, @@ -93,7 +101,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 +117,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..75b7ccc 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,27 @@ 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")] + #[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(); } crate::process::init(); - unsafe { - cpu::start_others(hart_mask); - } + AP_CAN_INIT.store(true, Ordering::Relaxed); crate::kmain(); } @@ -62,6 +74,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 +108,10 @@ global_asm!( .endm " ); - -global_asm!(include_str!("boot/entry.asm")); +#[cfg(target_arch = "riscv32")] +global_asm!(include_str!("boot/entry32.asm")); +#[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/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/arch/x86_64/consts.rs b/kernel/src/arch/x86_64/consts.rs index 2095e39..d872502 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 = 8 * 1024 * 1024; // 8 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_SIZE: usize = 1024 * 1024; // 1 MB - -/// 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; +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/gdt.rs b/kernel/src/arch/x86_64/gdt.rs index 90e5037..42c125c 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 { @@ -42,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(), @@ -75,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/fast_syscall.rs b/kernel/src/arch/x86_64/interrupt/fast_syscall.rs index 69170ac..d096b65 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/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/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/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); - } - } -} diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 4b5f56c..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 @@ -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/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/console/fonts/font8x16.rs b/kernel/src/drivers/console/fonts/font8x16.rs index 7513e85..e559db6 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,42 @@ 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 0000000..372f994 Binary files /dev/null and b/kernel/src/drivers/console/fonts/font8x16_1bpp.raw differ 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/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/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/fs/stdio.rs b/kernel/src/fs/stdio.rs index 6250011..3967e41 100644 --- a/kernel/src/fs/stdio.rs +++ b/kernel/src/fs/stdio.rs @@ -20,8 +20,15 @@ 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. + #[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 { @@ -43,10 +50,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/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/memory.rs b/kernel/src/memory.rs index a631437..8367cbc 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; @@ -16,14 +30,22 @@ pub type MemorySet = rcore_memory::memory_set::MemorySet; #[cfg(target_arch = "x86_64")] pub type FrameAlloc = bitmap_allocator::BitAlloc16M; -// RISCV has 8M memory -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -pub type FrameAlloc = bitmap_allocator::BitAlloc4K; - -// Raspberry Pi 3 has 1G memory -#[cfg(any(target_arch = "aarch64", target_arch = "mips"))] +// 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; +// K210 has 8M memory +#[cfg(feature = "board_k210")] +pub type FrameAlloc = bitmap_allocator::BitAlloc4K; + lazy_static! { pub static ref FRAME_ALLOCATOR: SpinNoIrqLock = SpinNoIrqLock::new(FrameAlloc::default()); @@ -77,17 +99,17 @@ pub fn dealloc_frame(target: usize) { } pub struct KernelStack(usize); -const STACK_SIZE: usize = 0x8000; +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 } } @@ -97,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/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/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/mod.rs b/kernel/src/process/mod.rs index fca611d..d9908a9 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -20,45 +20,93 @@ pub fn init() { } } - crate::shell::run_user_shell(); + crate::shell::add_user_shell(); info!("process: init end"); } 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/process/structs.rs b/kernel/src/process/structs.rs index 0bf6781..2ec8dcf 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -14,11 +14,14 @@ 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::memory::{ + ByFrame, Delay, File, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet, Read, +}; use crate::sync::{Condvar, SpinNoIrqLock as Mutex}; use super::abi::{self, ProcInitInfo}; +use core::mem::uninitialized; +use rcore_fs::vfs::INode; // TODO: avoid pub pub struct Thread { @@ -32,41 +35,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) } } @@ -75,6 +60,7 @@ pub struct Process { pub vm: MemorySet, pub files: BTreeMap, pub cwd: String, + pub exec_path: String, futexes: BTreeMap>, // relationship @@ -103,21 +89,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)); } } @@ -126,10 +100,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() }) } @@ -142,60 +114,77 @@ 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("/"), + exec_path: String::new(), 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(), }) } - /// Make a new user process from ELF `data` - pub fn new_user<'a, Iter>(data: &[u8], exec_path: &str, args: Iter) -> Box - where - Iter: Iterator, - { + /// Construct virtual memory of a new user process from ELF `data`. + /// Return `(MemorySet, entry_point, ustack_top)` + pub fn new_user_vm( + inode: &Arc, + exec_path: &str, + mut args: Vec, + envs: Vec, + ) -> Result<(MemorySet, usize, usize), &'static str> { + // 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 - 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 + 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 @ _ => return Err("invalid ELF arch"), } - // Check interpreter + // 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 - 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()); - } 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) + .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(&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}; @@ -204,6 +193,14 @@ impl Thread { let ustack_top = USER_STACK_OFFSET + USER_STACK_SIZE; vm.push( ustack_buttom, + 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 4 pages eagerly. + vm.push( + ustack_top - PAGE_SIZE * 4, ustack_top, MemoryAttr::default().user(), ByFrame::new(GlobalFrameAlloc), @@ -214,8 +211,8 @@ impl Thread { // Make init info let init_info = ProcInitInfo { - args: args.map(|s| String::from(s)).collect(), - envs: BTreeMap::new(), + args, + envs, auxv: { let mut map = BTreeMap::new(); if let Some(phdr_vaddr) = elf.get_phdr_vaddr() { @@ -233,6 +230,19 @@ impl Thread { trace!("{:#x?}", vm); + let entry_addr = elf.header.pt2.entry_point() as usize; + Ok((vm, entry_addr, ustack_top)) + } + + /// Make a new user process from ELF `data` + pub fn new_user( + inode: &Arc, + exec_path: &str, + mut args: Vec, + envs: Vec, + ) -> Box { + let (vm, entry_addr, ustack_top) = Self::new_user_vm(inode, exec_path, args, envs).unwrap(); + let kstack = KernelStack::new(); let mut files = BTreeMap::new(); @@ -270,66 +280,57 @@ 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()) }, kstack, clear_child_tid: 0, - proc: Arc::new(Mutex::new(Process { + proc: Process { vm, files, cwd: String::from("/"), + exec_path: String::from(exec_path), 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(), }) } /// 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 mut proc = self.proc.lock(); + let kstack = KernelStack::new(); 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())) } + let context = unsafe { Context::new_fork(tf, kstack.top(), vm.token()) }; + let new_proc = Process { + 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()), + children: Vec::new(), + threads: Vec::new(), + child_exit: Arc::new(Condvar::new()), + child_exit_code: BTreeMap::new(), } - - debug!("fork: temporary copy data!"); - let kstack = KernelStack::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: Arc::new(Mutex::new(Process { - vm, - files, - cwd, - futexes: BTreeMap::default(), - pid: Pid::uninitialized(), - parent, - children: Vec::new(), - threads: Vec::new(), - child_exit: Arc::new(Condvar::new()), - child_exit_code: BTreeMap::new(), - })), + proc: new_proc, }) } @@ -353,22 +354,40 @@ 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)); + + 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())); } 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 { @@ -378,10 +397,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 } } @@ -389,7 +410,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>; @@ -399,7 +420,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(); @@ -407,33 +428,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), - "", - ); - 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 } @@ -475,3 +482,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 9b2690e..84c4367 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -7,25 +7,46 @@ 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("rust/sh") { - let data = inode.read_as_vec().unwrap(); +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 + + #[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) { processor() .manager() - .add(Thread::new_user(data.as_slice(), "rust/sh", "sh".split(' '))); + .add(Thread::new_user(&inode, init_shell, init_args, init_envs)); } else { processor().manager().add(Thread::new_kernel(shell, 0)); } } #[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(); - processor() - .manager() - .add(Thread::new_user(data.as_slice(), cmdline.split(' '))); + processor().manager().add(Thread::new_user( + &inode, + cmdline.split(' ').map(|s| s.into()).collect(), + Vec::new(), + )); } pub extern "C" fn shell(_arg: usize) -> ! { @@ -40,13 +61,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(), &cmd, cmd.split(' '))); + 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/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 4ad87e7..efa0852 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; @@ -20,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) @@ -33,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) @@ -46,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) } @@ -59,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) } @@ -71,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); @@ -80,14 +75,16 @@ 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(); - proc.vm.check_write_array(ufds, nfds)?; + if !proc.pid.is_init() { + // we trust pid 0 process + info!( + "poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}", + ufds, nfds, timeout_msecs + ); + } - 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); @@ -152,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 @@ -169,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); @@ -210,7 +210,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)?; @@ -222,12 +222,15 @@ 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(); - let iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, false)?; + if !proc.pid.is_init() { + // we trust pid 0 process + info!( + "writev: fd: {}, iov: {:?}, count: {}", + fd, iov_ptr, iov_count + ); + } + 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(); @@ -253,7 +256,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) { @@ -267,13 +270,11 @@ 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(); - 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) } @@ -297,10 +298,10 @@ 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)?; + let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?; Ok(0) } @@ -310,46 +311,41 @@ 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 { - 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 { 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: {:?}", - dirfd, path, stat_ptr, flags + 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); - } + *stat_ref = stat; Ok(0) } @@ -364,14 +360,16 @@ 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)?; - info!("readlink: path: {:?}, base: {:?}, len: {}", path, base, len); + let slice = unsafe { proc.vm.check_write_array(base, len)? }; + info!( + "readlinkat: dirfd: {}, path: {:?}, base: {:?}, len: {}", + dirfd as isize, 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) }; - let len = inode.read_at(0, &mut slice)?; + let len = inode.read_at(0, slice)?; Ok(len) } else { Err(SysError::EINVAL) @@ -425,13 +423,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, @@ -459,7 +457,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(); @@ -525,13 +523,13 @@ 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); 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) } @@ -546,11 +544,11 @@ 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); - 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); } @@ -590,12 +588,12 @@ 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); - 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) } @@ -610,11 +608,11 @@ 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); - 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); @@ -627,39 +625,29 @@ 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.get_free_fd(); - proc.files.insert( - read_fd, - FileLike::File(FileHandle::new( - Arc::new(read), - OpenOptions { - read: true, - write: false, - append: false, - }, - )), - ); - - let write_fd = proc.get_free_fd(); - proc.files.insert( - write_fd, - 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, + }, + ))); - unsafe { - *fds = read_fd as u32; - *(fds.add(1)) = 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); @@ -671,69 +659,70 @@ 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:BEG 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; - } - } - return Ok(bytes_read); + + let mut read_offset = if !offset_ptr.is_null() { + unsafe { *(*proc_cell.get()).vm.check_read_ptr(offset_ptr)? } } 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; + 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])?; + if read_len == 0 { + break; + } + bytes_read += read_len; + read_offset += read_len; + + 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 {}, 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() { unsafe { - *offset = read_offset; + offset_ptr.write(read_offset); } - return Ok(bytes_read); + } else { + in_file.seek(SeekFrom::Current(bytes_read as i64))?; } + info!( + "sendfile:END out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, total_written {}", + out_fd, in_fd, offset_ptr, count, bytes_read, total_written + ); + return Ok(total_written); } impl Process { @@ -761,13 +750,20 @@ impl Process { &self, dirfd: usize, path: &str, - // follow: bool, + follow: bool, ) -> 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 ); + // 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 @@ -783,7 +779,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) } } @@ -877,18 +873,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 { @@ -988,7 +986,55 @@ pub struct Stat { ctime: Timespec, } -#[cfg(not(target_arch = "x86_64"))] +#[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)] +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 { @@ -1117,7 +1163,38 @@ 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: 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")))] fn from(info: Metadata) -> Self { Stat { dev: info.dev as u64, @@ -1149,7 +1226,7 @@ pub struct IoVec { /// Starting address base: *mut u8, /// Number of bytes to transfer - len: u64, + len: usize, } /// A valid IoVecs request from user @@ -1157,28 +1234,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 as usize)?; - } else { - vm.check_read_array(iov.base, iov.len as usize)?; - } + // 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 as usize) }) + .map(|iov| slice::from_raw_parts_mut(iov.base, iov.len)) .collect(); Ok(IoVecs(slices)) } @@ -1260,12 +1337,12 @@ 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(); + debug!("bitset {:?}", bitset); // save the fdset, and clear it use alloc::prelude::ToOwned; @@ -1289,7 +1366,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 + } } } diff --git a/kernel/src/syscall/mem.rs b/kernel/src/syscall/mem.rs index 1c5bee9..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; @@ -51,24 +51,20 @@ pub fn sys_mmap( ); 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); } } @@ -123,6 +119,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/misc.rs b/kernel/src/syscall/misc.rs index ac3ff39..e7f867c 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) } @@ -201,3 +191,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(); + 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; + } + i += 1; + } + + Ok(len) +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 1545af6..066d0a6 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -31,13 +31,25 @@ 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 pid = process().pid.clone(); let tid = processor().tid(); if !pid.is_init() { // we trust pid 0 process @@ -48,50 +60,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"); - Ok(0) - } - 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_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_GETPID => sys_getpid(), - // 40 - SYS_SENDFILE => sys_sendfile(args[0], args[1], args[3] as *mut usize, args[4]), + 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 +159,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 +170,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,180 +186,75 @@ 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_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_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_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], - args[1] as *const u8, - args[2], - args[3] as *const u8, - args[4], - ), - SYS_SYMLINKAT => Err(SysError::EACCES), - 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]), - + //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)), _ => { - #[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; - if let Some(ret) = x86_64_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); @@ -321,10 +264,22 @@ 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); + } + #[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, @@ -332,6 +287,53 @@ 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 { + 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), + 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 => unimplemented("fcntl64", Ok(0)), + SYS_SET_THREAD_AREA => { + info!("set_thread_area: tls: 0x{:x}", args[0]); + 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 { @@ -349,37 +351,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_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), 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/net.rs b/kernel/src/syscall/net.rs index 1372340..af28065 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) } @@ -56,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) } @@ -74,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), @@ -130,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 { @@ -158,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() { @@ -177,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)?; @@ -237,8 +228,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); @@ -408,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())) } @@ -427,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 => { @@ -435,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), @@ -458,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::(), @@ -470,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 1159ff3..9fcb97e 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -6,14 +6,20 @@ 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(); + let tid = processor().manager().add(new_thread); + processor().manager().detach(tid); info!("fork: {} -> {}", thread::current().id(), pid); 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`. +/// 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,40 +32,43 @@ 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); - } - { - let proc = process(); - proc.vm.check_write_ptr(parent_tid)?; - proc.vm.check_write_ptr(child_tid)?; + 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 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); + processor().manager().detach(tid); 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) } /// 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); - if !wstatus.is_null() { - process().vm.check_write_ptr(wstatus)?; - } + //info!("wait4: pid: {}, code: {:?}", pid, wstatus); + let wstatus = if !wstatus.is_null() { + Some(unsafe { process().vm.check_write_ptr(wstatus)? }) + } else { + None + }; #[derive(Debug)] enum WaitFor { AnyChild, @@ -84,10 +93,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); } @@ -118,75 +125,71 @@ 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: name: {:?}, argv: {:?} envp: {:?}", name, argv, envp); - let proc = process(); - let exec_name = if name.is_null() { - String::from("") - } else { - unsafe { proc.vm.check_and_clone_cstr(name)? } - }; + info!( + "exec:BEG: path: {:?}, argv: {:?}, envp: {:?}", + path, argv, envp + ); + 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)? }; - if argv.is_null() { - 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)?; - 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; -// 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() { + error!("exec: args is null"); return Err(SysError::EINVAL); } - info!("EXEC: name:{:?} , args {:?}", exec_name, args); + info!( + "exec:STEP2: path: {:?}, args: {:?}, envs: {:?}", + 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 path = args[0].as_str(); - let exec_path = exec_name.as_str(); - let inode = proc.lookup_inode(exec_path)?; - let buf = inode.read_as_vec()?; + let inode = proc.lookup_inode(&path)?; // Make new Thread - let iter = args.iter().map(|s| s.as_str()); - let mut thread = Thread::new_user(buf.as_slice(), exec_path, iter); - thread.proc.lock().clone_for_exec(&proc); + let (mut vm, entry_addr, ustack_top) = + Thread::new_user_vm(&inode, &path, args, envs).map_err(|_| SysError::EINVAL)?; // Activate new page table + core::mem::swap(&mut proc.vm, &mut vm); unsafe { - thread.proc.lock().vm.activate(); + proc.vm.activate(); } - // Modify the TrapFrame - *tf = unsafe { thread.context.get_init_tf() }; + // Modify exec path + proc.exec_path = path.clone(); - // Swap Context but keep KStack - ::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack); - ::core::mem::swap(current_thread(), &mut *thread); + // Modify the TrapFrame + *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); + info!("exec:END: path: {:?}", path); Ok(0) } @@ -319,8 +322,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 dd5cfcd..0fc3f39 100644 --- a/kernel/src/syscall/time.rs +++ b/kernel/src/syscall/time.rs @@ -33,20 +33,20 @@ fn get_epoch_usec() -> u64 { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct TimeVal { - sec: u64, - usec: u64, + sec: usize, + usec: usize, } impl TimeVal { pub fn to_msec(&self) -> u64 { - self.sec * MSEC_PER_SEC + self.usec / USEC_PER_MSEC + (self.sec as u64) * MSEC_PER_SEC + (self.usec as u64) / USEC_PER_MSEC } pub fn get_epoch() -> Self { let usec = get_epoch_usec(); TimeVal { - sec: usec / USEC_PER_SEC, - usec: usec % USEC_PER_SEC, + sec: (usec / USEC_PER_SEC) as usize, + usec: (usec % USEC_PER_SEC) as usize, } } } @@ -54,24 +54,24 @@ impl TimeVal { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct TimeSpec { - sec: u64, - nsec: u64, + sec: usize, + nsec: usize, } impl TimeSpec { pub fn to_msec(&self) -> u64 { - self.sec * MSEC_PER_SEC + self.nsec / NSEC_PER_MSEC + (self.sec as u64) * MSEC_PER_SEC + (self.nsec as u64) / NSEC_PER_MSEC } 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, } } } @@ -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 }; @@ -135,14 +129,42 @@ pub fn sys_getrusage(who: usize, rusage: *mut RUsage) -> SysResult { let usec = (tick - tick_base) * USEC_PER_TICK as u64; let new_rusage = RUsage { utime: TimeVal { - sec: usec / USEC_PER_SEC, - usec: usec % USEC_PER_SEC, + sec: (usec / USEC_PER_SEC) as usize, + usec: (usec % USEC_PER_SEC) as usize, }, stime: TimeVal { - sec: usec / USEC_PER_SEC, - usec: usec % USEC_PER_SEC, + sec: (usec / USEC_PER_SEC) as usize, + usec: (usec % USEC_PER_SEC) as usize, }, }; - unsafe { *rusage = new_rusage }; + *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(); + let buf = unsafe { 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, + }; + + *buf = new_buf; + Ok(tick as usize) +} 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/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 new file mode 100644 index 0000000..a992b69 --- /dev/null +++ b/tools/opensbi/README.md @@ -0,0 +1,13 @@ +# OpenSBI + +These are binary release of OpenSBI on this [commit](https://github.com/riscv/opensbi/tree/194dbbe5a13dff2255411c26d249f3ad4ef42c0b) at 2019.04.15. + +- 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. 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). + +* 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 new file mode 100755 index 0000000..5aeeb11 Binary files /dev/null and b/tools/opensbi/fu540.elf differ diff --git a/tools/opensbi/k210.elf b/tools/opensbi/k210.elf new file mode 100755 index 0000000..221c37e Binary files /dev/null and b/tools/opensbi/k210.elf differ diff --git a/tools/opensbi/virt_rv32.elf b/tools/opensbi/virt_rv32.elf new file mode 100755 index 0000000..1bebfb0 Binary files /dev/null and b/tools/opensbi/virt_rv32.elf differ diff --git a/tools/opensbi/virt_rv64.elf b/tools/opensbi/virt_rv64.elf new file mode 100755 index 0000000..6e941c0 Binary files /dev/null and b/tools/opensbi/virt_rv64.elf differ diff --git a/user b/user index 8dbc0ed..05f0efd 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 8dbc0edb935a62d748aaac39258d4a985de0ae17 +Subproject commit 05f0efd3fda084109e4b6da8ff30ecb1557a267f