From 7b5f42f76a7dce4ed77c424cda814b2a2ec946fd Mon Sep 17 00:00:00 2001 From: juls0730 <62722391+juls0730@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:58:48 -0600 Subject: [PATCH] working acpi table parsing --- Makefile | 43 +- README.md | 15 +- scripts/README.md | 8 +- scripts/font.py | 259 ++++++++++- scripts/initramfs-test.py | 37 ++ src/arch/x86_64/mod.rs | 4 +- src/arch/x86_common/stack_trace.rs | 2 + src/drivers/acpi.rs | 456 ++++++++++--------- src/drivers/fs/fat.rs | 282 ++++++++---- src/drivers/fs/initramfs/compressors/gzip.rs | 5 +- src/drivers/fs/initramfs/mod.rs | 4 +- src/drivers/storage/drive.rs | 74 --- src/drivers/storage/ide.rs | 52 +-- src/drivers/storage/mod.rs | 152 ++++++- src/drivers/video/font.rs | 2 +- src/libs/elf.rs | 15 + src/libs/mod.rs | 3 + src/libs/oncecell.rs | 70 +++ src/libs/uuid.rs | 100 ++++ src/main.rs | 6 +- src/mem/mod.rs | 14 + src/usr/tty.rs | 26 +- 22 files changed, 1171 insertions(+), 458 deletions(-) create mode 100644 scripts/initramfs-test.py delete mode 100644 src/drivers/storage/drive.rs create mode 100644 src/libs/elf.rs create mode 100644 src/libs/oncecell.rs create mode 100644 src/libs/uuid.rs diff --git a/Makefile b/Makefile index 653577f..11f06a7 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,12 @@ ISO_PARTITION_TYPE ?= GPT MODE ?= release ARCH ?= x86_64 MEMORY ?= 512M +# In MB +ISO_SIZE ?= 256 QEMU_OPTS ?= MKSQUASHFS_OPTS ?= GDB ?= +ESP_BITS ?= 16 ISO_PATH = ${ARTIFACTS_PATH}/iso_root INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs @@ -62,6 +65,7 @@ prepare-bin-files: mkdir -p ${ARTIFACTS_PATH} mkdir -p ${ISO_PATH} mkdir -p ${INITRAMFS_PATH} + mkdir -p ${ARTIFACTS_PATH}/mnt copy-initramfs-files: echo "Hello World from Initramfs" > ${INITRAMFS_PATH}/example.txt @@ -87,6 +91,8 @@ run-scripts: python scripts/font.py mv scripts/font.psf ${INITRAMFS_PATH}/ + # python scripts/initramfs-test.py 1000 ${INITRAMFS_PATH}/ + copy-iso-files: # Limine files mkdir -p ${ISO_PATH}/boot/limine @@ -109,35 +115,40 @@ copy-iso-files: partition-iso: copy-iso-files # Make empty ISO of 64M in size - dd if=/dev/zero of=${IMAGE_PATH} bs=1M count=0 seek=64 + dd if=/dev/zero of=${IMAGE_PATH} bs=1M count=0 seek=${ISO_SIZE} ifeq (${ISO_PARTITION_TYPE},GPT) - # Make ISO a GPT disk with 1 partition starting at sector 2048 that is 32768 sectors, or 16MiB, in size - # Then a second partition spanning the rest of the disk - sgdisk ${IMAGE_PATH} -n 1:2048:+32768 -t 1:ef00 -n 2 + parted -s ${IMAGE_PATH} mklabel gpt + parted -s ${IMAGE_PATH} mkpart ESP fat${ESP_BITS} 2048s 34815s + else - # Make ISO a MBR disk with 1 partition starting at sector 2048 that is 32768 sectors, or 16MiB, in size - # Then a second partition spanning the rest of the disk - parted -a none ${IMAGE_PATH} mklabel msdos - parted -a none ${IMAGE_PATH} mkpart primary 2048s 34815s - parted -a none ${IMAGE_PATH} mkpart primary 34816s 100% - parted -a none ${IMAGE_PATH} set 1 boot on + parted -s ${IMAGE_PATH} mklabel msdos + parted -s ${IMAGE_PATH} mkpart primary fat${ESP_BITS} 2048s 34815s endif + # Make ISO with 1 partition starting at sector 2048 that is 32768 sectors, or 16MiB, in size + # Then a second partition spanning the rest of the disk + parted -s ${IMAGE_PATH} mkpart primary 34816s 100% + parted -s ${IMAGE_PATH} set 1 esp on + build-iso: partition-iso copy-initramfs-files ifeq (${ARCH},x86_64) # Install the Limine bootloader for bios installs ./limine/limine bios-install ${IMAGE_PATH} endif - # Make a FAT32 FS and copy files in /bin/iso_root into the ISO starting at 1M or exactly 2048 sectors - mformat -F -i ${IMAGE_PATH}@@1M - mmd -i ${IMAGE_PATH}@@1M ::/EFI ::/EFI/BOOT - mcopy -i ${IMAGE_PATH}@@1M -s ${ISO_PATH}/* ::/ + sudo losetup -Pf --show ${IMAGE_PATH} > loopback_dev + sudo mkfs.fat -F ${ESP_BITS} `cat loopback_dev`p1 + sudo mount `cat loopback_dev`p1 ${ARTIFACTS_PATH}/mnt + sudo cp -r ${ISO_PATH}/* ${ARTIFACTS_PATH}/mnt + sync + sudo umount ${ARTIFACTS_PATH}/mnt + sudo losetup -d `cat loopback_dev` + rm -rf loopback_dev compile-bootloader: @if [ ! -d "limine" ]; then \ echo "Cloning Limine into limine/..."; \ - git clone https://github.com/limine-bootloader/limine.git --branch=v5.x-branch-binary --depth=1; \ + git clone https://github.com/limine-bootloader/limine.git --branch=v6.x-branch-binary --depth=1; \ else \ echo "Folder limine already exists. Skipping clone."; \ fi @@ -182,5 +193,5 @@ line-count: cloc --quiet --exclude-dir=bin --csv src/ | tail -n 1 | awk -F, '{print $$5}' clean: cargo clean - rm -rf bin + rm -rf ${ARTIFACTS_PATH} make clean -C limine \ No newline at end of file diff --git a/README.md b/README.md index 087cf3f..e2247be 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,13 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi - [ ] x86 CPU support - [ ] armv8 CPU support - [ ] File system - - [ ] Block Device support - - [X] IDE device support - - [ ] SATA device support - - [ ] MMC/Nand device support - - [ ] M.2 NVME device support + - [X] FAT file system (read-only rn) + - [ ] Ext2 file system +- [ ] Block Device support + - [X] IDE device support + - [ ] SATA device support + - [ ] MMC/Nand device support + - [ ] M.2 NVME device support - [ ] Basic shell - [X] Basic I/O - [ ] Executing Programs from disk @@ -112,10 +114,11 @@ Some Resources I used over the creation of CappuccinOS: - Wikipedia on various random things - [Squashfs Binary Format](https://dr-emann.github.io/squashfs/squashfs.html) -And mostly for examples of how people did stuff I used these (projects made by people who actually have a clue what they're doing): +And mostly for examples of how people did stuff I used these (projects made by people who might actually have a clue what they're doing): - [MOROS](https://github.com/vinc/moros) - [Felix](https://github.com/mrgian/felix) - [mOS](https://github.com/Moldytzu/mOS) +- [rust_os](https://github.com/thepowersgang/rust_os/tree/master) ## License CappuccinOS is license under the MIT License. Feel free to modify and distribute in accordance with the license. \ No newline at end of file diff --git a/scripts/README.md b/scripts/README.md index 4aac067..a7f873a 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -2,4 +2,10 @@ This folder is responsible for holding all the scripts that are necessary for building CappuccinOS - **demangle-symbols.py**
- This file takes in a symbols file generated by the `nm` program and outputs a symbol file with the symbol names demangled, it uses my library, [rustc_demangle.py](https://github.com/juls0730/rustc_demangle.py) which is a python port of the Rust symbol demangling library [rustc-demangle](https://github.com/rust-lang/rustc-demangle). \ No newline at end of file + This file takes in a symbols file generated by the `nm` program and outputs a symbol file with the symbol names demangled, it uses my library, [rustc_demangle.py](https://github.com/juls0730/rustc_demangle.py) which is a python port of the Rust symbol demangling library [rustc-demangle](https://github.com/rust-lang/rustc-demangle). + +- **font.py**
+ This file takes an array of u8 numbers and exports a PC Screen Font file (2.0) + +- **initramfs-test.py** + This file generates tons of files in the initramfs directory from huge to small files nested in directories, etc. It's intended to test the squashfs driver \ No newline at end of file diff --git a/scripts/font.py b/scripts/font.py index 5aabc28..afe7519 100644 --- a/scripts/font.py +++ b/scripts/font.py @@ -20,7 +20,264 @@ def create_psf2_file(font_data, psf2_file_path): psf2_file.write(psf2_file_content) if __name__ == "__main__": - font_data = [[0x00, 0x00, 0x7E, 0x81, 0x99, 0xA5, 0x85, 0x89, 0x89, 0x81, 0x89, 0x7E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x99, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0xFF],[0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,0x00],[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF,0xFF],[0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00,0x00],[0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00,0x00],[0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00,0x00],[0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00,0x00],[0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xCE, 0xD6, 0xD6, 0xE6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x0E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00,0x00],[0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x6C, 0x38, 0x38, 0x6C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00,0x00],[0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,0x00],[0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0xDC, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78,0x00],[0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C,0x00],[0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00,0x00],[0x00, 0x00, 0xCC, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x10, 0x38, 0x6C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xCC, 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x38, 0x6C, 0x38, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06, 0x3C, 0x00, 0x00,0x00],[0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x18, 0x3C, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0xC6, 0xC6, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,0x00],[0x38, 0x6C, 0x38, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,0x00],[0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36, 0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x3E, 0x6C, 0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00,0x00],[0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78,0x00],[0x00, 0xC6, 0xC6, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00,0x00],[0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x18, 0x18, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0xF8, 0xCC, 0xCC, 0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00,0x00],[0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0x70, 0x00,0x00],[0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x0C, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x76, 0xDC, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,0x00],[0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,0x00],[0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xCE, 0x93, 0x06, 0x0C, 0x1F, 0x00,0x00],[0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xCE, 0x9A, 0x3F, 0x06, 0x0F, 0x00,0x00],[0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11,0x44],[0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,0xAA],[0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD,0x77],[0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,0x36],[0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0xFF],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0xFF],[0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,0xF0],[0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,0x0F],[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC6, 0xFC, 0xC6, 0xC6, 0xFC, 0xC0, 0xC0, 0xC0, 0x00,0x00],[0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x80, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xCF, 0xDB, 0xF3, 0x7E, 0x60, 0xC0, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,0x18],[0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00,0x00],[0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x70, 0x98, 0x30, 0x60, 0xC8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00,0x00],[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00]] + font_data = [ + [0x00, 0x00, 0x7E, 0x81, 0x99, 0xA5, 0x85, 0x89, 0x89, 0x81, 0x89, 0x7E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x99, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00], + [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], + [0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00], + [0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xCE, 0xD6, 0xD6, 0xE6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x0E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00], + [0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x6C, 0x38, 0x38, 0x6C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00], + [0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0xDC, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00], + [0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00], + [0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00], + [0x00, 0x00, 0xCC, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x10, 0x38, 0x6C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xCC, 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x38, 0x6C, 0x38, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06, 0x3C, 0x00, 0x00, 0x00], + [0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x18, 0x3C, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0xC6, 0xC6, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x38, 0x6C, 0x38, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36, 0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x3E, 0x6C, 0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00], + [0x00, 0xC6, 0xC6, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00], + [0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x18, 0x18, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0xF8, 0xCC, 0xCC, 0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0x70, 0x00, 0x00], + [0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x0C, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x76, 0xDC, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00], + [0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xCE, 0x93, 0x06, 0x0C, 0x1F, 0x00, 0x00], + [0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xCE, 0x9A, 0x3F, 0x06, 0x0F, 0x00, 0x00], + [0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44], + [0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA], + [0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36], + [0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], + [0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0], + [0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F], + [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC6, 0xFC, 0xC6, 0xC6, 0xFC, 0xC0, 0xC0, 0xC0, 0x00, 0x00], + [0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x80, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xCF, 0xDB, 0xF3, 0x7E, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], + [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00], + [0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x70, 0x98, 0x30, 0x60, 0xC8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + ] psf2_file_path = "scripts/font.psf" diff --git a/scripts/initramfs-test.py b/scripts/initramfs-test.py new file mode 100644 index 0000000..811cd37 --- /dev/null +++ b/scripts/initramfs-test.py @@ -0,0 +1,37 @@ +import os +import random +import string +import sys + +def generate_random_string(length: int): + return ''.join(random.choices(string.ascii_letters + string.digits, k=length)) + +def generate_random_data(size: int): + return os.urandom(size) + +def create_random_structure(output_dir: str, depth: int, max_depth: int): + if depth >= max_depth: + return + + random_dir = generate_random_string(10) + os.makedirs(os.path.join(output_dir, random_dir)) + + random_file_name = generate_random_string(8) + random_file_path = os.path.join(output_dir, random_dir, random_file_name) + + with open(random_file_path, 'wb') as file: + pass + + create_random_structure(os.path.join(output_dir, random_dir), depth + 1, max_depth) + +if __name__ == "__main__": + if len(sys.argv) < 2 or len(sys.argv) > 3: + print("Usage: initramfs-test.py [output_dir]") + exit(1) + + iterations = int(sys.argv[1]) + output_dir = sys.argv[2] if len(sys.argv) == 3 else "." + + for i in range(iterations): + max_depth = random.randint(0, 3) + create_random_structure(output_dir, 0, max_depth) diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 5511259..38f5c21 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -17,8 +17,8 @@ pub fn push_gprs() { pub fn pop_gprs() { unsafe { core::arch::asm!( - "pop rax", "pop rbx", "pop rcx", "pop rdx", "pop rsi", "pop rdi", "pop rbp", "pop r8", - "pop r9", "pop r10", "pop r11", "pop r12", "pop r13", "pop r14", "pop r15", + "pop r15", "pop r14", "pop r13", "pop r12", "pop r11", "pop r10", "pop r9", "pop r8", + "pop rbp", "pop rdi", "pop rsi", "pop rdx", "pop rcx", "pop rbx", "pop rax" ); } } diff --git a/src/arch/x86_common/stack_trace.rs b/src/arch/x86_common/stack_trace.rs index f8caf33..180ce4f 100644 --- a/src/arch/x86_common/stack_trace.rs +++ b/src/arch/x86_common/stack_trace.rs @@ -20,6 +20,8 @@ pub fn print_stack_trace(max_frames: usize, rbp: u64) { let instruction_pointer = unsafe { (*stackframe).rip }; + crate::print!(" {:#X} ", instruction_pointer); + let instrcution_info = get_function_name(instruction_pointer); if let Ok((function_name, function_offset)) = instrcution_info { diff --git a/src/drivers/acpi.rs b/src/drivers/acpi.rs index e99bbab..4025b0d 100644 --- a/src/drivers/acpi.rs +++ b/src/drivers/acpi.rs @@ -1,260 +1,264 @@ -use crate::{ - libs::{lazy::Lazy, mutex::Mutex}, - log_error, log_info, log_ok, -}; -use alloc::{sync::Arc, vec::Vec}; -use limine::RsdpRequest; +// TODO: reduce the need to derive(Clone, Copy) everything -static RSDP_REQUEST: RsdpRequest = RsdpRequest::new(0); +use alloc::{sync::Arc, vec::Vec}; + +use crate::{ + arch::io::{inw, outb}, + libs::{lazy::Lazy, mutex::Mutex, oncecell::OnceCell}, + log_info, +}; #[repr(C, packed)] -struct Rsdp { +#[derive(Clone, Copy, Debug)] +struct SDTHeader { + pub signature: [u8; 4], + pub length: u32, + pub revision: u8, + pub checksum: u8, + pub oemid: [u8; 6], + pub oem_table_id: [u8; 8], + pub oem_revision: u32, + pub creator_id: u32, + pub creator_revision: u32, +} + +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +pub struct SDT { + pub header: SDTHeader, + pub inner: T, +} + +impl SDT { + unsafe fn new(pointer: *mut u8) -> Self { + let header = *(pointer.cast::()); + let inner = *(pointer.add(core::mem::size_of::()).cast::()); + + return Self { header, inner }; + } +} + +#[repr(C, packed)] +#[derive(Debug)] +struct RSDP { signature: [u8; 8], checksum: u8, oem_id: [u8; 6], revision: u8, - rsdt_address: u32, + rsdt_addr: u32, } #[repr(C, packed)] -struct Xsdp { +struct XSDP { + rsdp: RSDP, + length: u32, - xsdt_address: u64, - extended_checksum: u8, - reserved: [u8; 3], + xsdt_addr: u64, + ext_checksum: u8, + _reserved: [u8; 3], } -pub struct Acpi { - tables: Arc<[*const u8]>, - entries: usize, - v2: bool, +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +struct RSDT { + pointers: u32, } -impl Acpi { - fn has_signature(&self, table_index: usize, signature: &str) -> bool { - unsafe { - let sdt_header: &SdtHeader = &*(self.tables[table_index] as *const SdtHeader); - let st = core::str::from_utf8_unchecked(&sdt_header.signature); - st == signature - } - } - - pub fn list_tables(&self) { - unsafe { - for i in 0..self.entries { - let sdt_header: &SdtHeader = &*(self.tables[i] as *const SdtHeader); - let st = sdt_header.signature; - log_info!("entry {:02}: {:?}", i + 1, sdt_header); - } - } - } - - pub fn get_table(&self, signature: &str) -> Option<*const u8> { - for i in 0..self.entries { - if self.has_signature(i, signature) { - return Some(self.tables[i]); - } - } - - None - } -} - -const RSDP_V1_LENGTH: usize = 20; -const RSDP_V2_EXT_LENGTH: usize = core::mem::size_of::() - RSDP_V1_LENGTH; -const RSDP_SIG: [u8; 8] = *b"RSD PTR "; - -impl Rsdp { - pub fn is_valid(&self) -> bool { - if self.signature != RSDP_SIG { - return false; - } - - let bytes = unsafe { core::slice::from_raw_parts(self as *const Rsdp as *const u8, 20) }; - let sum = bytes.iter().fold(0u8, |sum, &byte| sum.wrapping_add(byte)); - - if sum & 0xFF != 0 { - return false; - } - - return true; - } -} - -impl Xsdp { - pub fn is_valid(&self) -> bool { - let bytes = unsafe { core::slice::from_raw_parts(self as *const Xsdp as *const u8, 20) }; - let sum = bytes.iter().fold(0u8, |sum, &byte| sum.wrapping_add(byte)); - - if sum & 0xFF != 0 { - return false; - } - - return true; - } -} - -static ACPI: Lazy> = Lazy::new(|| { - let acpi = resolve_acpi(); - - if acpi.is_err() { - panic!("Failed to resolve ACPI!"); - } - - Mutex::new(acpi.unwrap()) -}); - -pub fn init_acpi() { - let acpi_lock = ACPI.lock(); - let acpi = acpi_lock.read(); - - log_ok!("Successfully initialized ACPI with {} tables", acpi.entries); - - acpi.list_tables() -} - -#[derive(Debug)] -enum AcpiRootTable { - Rsdp(u32), - Xsdp(u64), -} - -impl AcpiRootTable { - pub fn get_from_bootloader() -> Result { - let rsdp_response = RSDP_REQUEST.get_response().get(); - - if rsdp_response.is_none() { - log_error!("Failed to initialize ACPI: RSDP not found!"); - return Err(()); - } - - let rsdp_address = &rsdp_response.unwrap().address; - - let rsdp_table: &Rsdp = unsafe { &*(rsdp_address.as_ptr().unwrap() as *const Rsdp) }; - - if !rsdp_table.is_valid() { - log_error!("Failed to initialize ACPI: RSDP was not valid!"); - return Err(()); - } - - if rsdp_table.revision == 2 { - let xsdp_table: &Xsdp = unsafe { &*(rsdp_address.as_ptr().unwrap() as *const Xsdp) }; - - if !xsdp_table.is_valid() { - log_error!("Failed to initalize ACPI: XSDP was not valid!"); - return Err(()); - } - - return Ok(AcpiRootTable::Xsdp(xsdp_table.xsdt_address)); - } - - return Ok(AcpiRootTable::Rsdp(rsdp_table.rsdt_address)); - } -} - -fn resolve_acpi() -> Result { - let root_table = AcpiRootTable::get_from_bootloader()?; - - crate::println!("{:?}", root_table); - - let (header_addr, ptr_size, ext_table) = match root_table { - AcpiRootTable::Rsdp(addr) => (addr as u64, core::mem::size_of::(), false), - AcpiRootTable::Xsdp(addr) => (addr, core::mem::size_of::(), true), - }; - - let root_header: &SdtHeader = unsafe { &*(header_addr as *const SdtHeader) }; - - unsafe { - if !ext_table { - if core::str::from_utf8_unchecked(&root_header.signature) != "RSDT" { - log_error!("Invalid root table header, expected RSDT."); - return Err(()); - } - } else { - if core::str::from_utf8_unchecked(&root_header.signature) != "XSDT" { - log_error!("Invalid root table header, expected XSDT."); - return Err(()); - } - } - } - - let mut entries = (root_header.length as usize - core::mem::size_of::()) / ptr_size; - if entries > 48 { - log_error!("Expected at most 48 ACPI tables, got {entries}!"); - entries = 48; - } - - let mut acpi_tables: Vec<*const u8> = Vec::with_capacity(entries); - - for i in 0..entries { - let address = - (header_addr + (core::mem::size_of::() + i * ptr_size) as u64) as *const u8; - - acpi_tables.push(address); - } - - crate::println!("{:?} {}", acpi_tables, entries); - - return Ok(Acpi { - tables: Arc::from(acpi_tables), - entries, - v2: ext_table, - }); +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +struct XSDT { + pointers: u64, } #[derive(Clone, Copy, Debug)] -#[repr(C)] -struct SdtHeader { - signature: [u8; 4], - length: u32, - revision: u8, - checksum: u8, - oem_id: [u8; 6], - oem_table_id: [u8; 8], - oem_revision: u32, - creator_id: u32, - creator_revision: u32, +enum RootSDT { + RSDT(SDT), + XSDT(SDT), } -fn check_rsdt_checksum(table_header: *const SdtHeader) -> bool { - let mut sum: u8 = 0; - - for i in 0..unsafe { (*table_header).length } { - sum += unsafe { *((table_header as *const u8).add(i as usize)) }; +impl RootSDT { + fn header(&self) -> SDTHeader { + return match self { + &RootSDT::RSDT(RSDT) => RSDT.header, + &RootSDT::XSDT(XSDT) => XSDT.header, + }; } - return sum == 0; + fn len(&self) -> usize { + let ptr_size = match self { + &RootSDT::RSDT(_) => 4, + &RootSDT::XSDT(_) => 8, + }; + + return (self.header().length as usize - core::mem::size_of::()) / ptr_size; + } + + unsafe fn get(&self, idx: usize) -> *const u8 { + let mut offset = 0; + + let root_ptr = match self { + &RootSDT::RSDT(RSDT) => { + let ptrs = RSDT.inner.pointers as *const u8; + assert!(!ptrs.is_null()); + ptrs.add(offset) + } + &RootSDT::XSDT(XSDT) => { + let ptrs = XSDT.inner.pointers as *const u8; + assert!(!ptrs.is_null()); + ptrs.add(offset) + } + }; + + for _ in 0..idx { + let header = *root_ptr.add(offset).cast::(); + offset += header.length as usize; + } + + crate::println!("{offset:X?} {idx}"); + + return root_ptr.add(offset); + } +} + +#[derive(Clone, Debug)] +struct ACPI { + root_sdt: RootSDT, + tables: Vec<[u8; 4]>, +} + +static ACPI: OnceCell = OnceCell::new(); + +static RSDP_REQ: limine::RsdpRequest = limine::RsdpRequest::new(0); + +fn resolve_acpi() { + let rsdp_ptr = RSDP_REQ.get_response().get(); + if rsdp_ptr.is_none() { + panic!("RSDP not found!"); + } + + let rsdp = unsafe { &*rsdp_ptr.unwrap().address.as_ptr().unwrap().cast::() }; + + log_info!("RSDP: {rsdp:X?}"); + + // TODO: validate RSDT + let root_sdt = { + if rsdp.revision == 0 { + RootSDT::RSDT(unsafe { SDT::new(rsdp.rsdt_addr as *mut u8) }) + } else { + let xsdt = unsafe { &*rsdp_ptr.unwrap().address.as_ptr().unwrap().cast::() }; + RootSDT::XSDT(unsafe { SDT::new(xsdt.xsdt_addr as *mut u8) }) + } + }; + + log_info!("{root_sdt:X?}"); + + let tables: Vec<[u8; 4]> = (0..root_sdt.len()) + .map(|i| { + let sdt_ptr = unsafe { root_sdt.get(i) }; + let signature = unsafe { core::slice::from_raw_parts(sdt_ptr, 4) }; + let ret = signature.try_into().unwrap(); + ret + }) + .collect(); + + let acpi_table = ACPI { root_sdt, tables }; + + ACPI.set(acpi_table); } #[repr(C, packed)] -struct RSDT { - h: SdtHeader, - pointer_to_other_sdt: *const u8, +#[derive(Clone, Copy, Debug)] +struct GenericAddressStructure { + address_space: u8, + bit_width: u8, + bit_offset: u8, + access_size: u8, + address: u8, } -fn find_fadt(root_sdt: *const RSDT) -> Option { - // unsafe { - // let rsdt = root_sdt.as_ref()?; - // let entries = (rsdt.h.length - core::mem::size_of::() as u32) / 4; +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +struct FADT { + firmware_ctrl: u32, + dsdt: u32, - // let pointer_to_other_sdt = + _reserved: u8, - // for i in 0..entries { - // crate::println!("{i}"); + preferred_power_management_profile: u8, + sci_interrupt: u16, + smi_cmd_port: u32, + acpi_enable: u8, + acpi_disable: u8, + s4biox_req: u8, + pstate_control: u8, + pm1a_event_block: u32, + pm1b_event_block: u32, + pm1a_control_block: u32, + pm1b_control_block: u32, + pm2_control_block: u32, + pm_timer_block: u32, + gpe0_block: u32, + gpe1_block: u32, + pm1_event_length: u8, + pm1_control_length: u8, + pm2_control_length: u8, + pm_timer_length: u8, + gpe0_length: u8, + gpe1_length: u8, + gpe1_base: u8, + c_state_control: u8, + worst_c2_latency: u16, + worst_c3_length: u16, + flush_size: u16, + flush_stride: u16, + duty_offset: u8, + duty_width: u8, + day_alarm: u8, + month_alarm: u8, + century: u8, - // let h_ptr = rsdt.pointer_to_other_sdt[i as usize] as *const AcpiSdtHeader; - // let h = h_ptr.as_ref()?; - // let slice = core::slice::from_raw_parts(h.signature.as_ptr(), 4); + boot_architecture_flags: u16, - // let signature = core::str::from_utf8(slice).ok()?; + _reserved2: u8, + flags: u32, - // if signature == "FACP" { - // return Some(*h_ptr); - // } - // } + reset_reg: GenericAddressStructure, - // // No FACP found - // return None; - // } - None + reset_value: u8, + _reserved3: [u8; 3], + + x_firmware_control: u64, + x_dstd: u64, + + x_pm1a_event_block: GenericAddressStructure, + x_pm1b_event_block: GenericAddressStructure, + x_pm1a_control_block: GenericAddressStructure, + x_pm1b_control_block: GenericAddressStructure, + x_pm2_control_block: GenericAddressStructure, + x_pm_timer_block: GenericAddressStructure, + x_gpe0_block: GenericAddressStructure, + x_gpe1_block: GenericAddressStructure, +} + +pub fn init_acpi() { + resolve_acpi(); + + let fadt = find_table::("FACP").expect("Failed to find FADT"); + + crate::println!("{fadt:X?}"); +} + +pub fn find_table(table_name: &str) -> Option> { + assert_eq!(table_name.len(), 4); + + for (i, table) in ACPI.tables.iter().enumerate() { + if table == table_name.as_bytes() { + let ptr = unsafe { ACPI.root_sdt.get(i).cast::>() }; + crate::println!("Found {table_name} at index {i} {ptr:p}"); + let table = unsafe { *ptr }; + return Some(table); + } + } + + return None; } diff --git a/src/drivers/fs/fat.rs b/src/drivers/fs/fat.rs index 4612d34..d19b4e0 100755 --- a/src/drivers/fs/fat.rs +++ b/src/drivers/fs/fat.rs @@ -5,7 +5,7 @@ use alloc::{ vec::Vec, }; -use crate::drivers::storage::drive::{BlockDevice, GPTPartitionEntry}; +use crate::drivers::storage::{BlockDevice, GPTPartitionEntry}; use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem}; @@ -15,19 +15,23 @@ use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem}; // // Fat Clusters are either one of these types: // -// 0x0FFFFFF8 : End Of cluster Chain -// 0x0FFFFFF7 : Bad Cluster -// 0x00000001 - 0x0FFFFFEF : In use Cluster -// 0x00000000 : Free Cluster +// | fat12 | fat16 | fat32 | Description | +// |---------------|-----------------|-------------------------|-------------------------------| +// | 0xFF8-0xFFF | 0xFFF8-0xFFFF | 0x0FFFFFF8-0x0FFFFFFF | End Of cluster Chain | +// | 0xFF7 | 0xFFF7 | 0x0FFFFFF7 | Bad Cluster | +// | 0x002-0xFEF | 0x0002-0xFFEF | 0x00000002-0x0FFFFFEF | In use Cluster | +// | 0x000 | 0x0000 | 0x00000000 | Free Cluster | // End Of Chain -const EOC: u32 = 0x0FFFFFF8; +const EOC_12: u32 = 0x0FF8; +const EOC_16: u32 = 0xFFF8; +const EOC_32: u32 = 0x0FFFFFF8; #[derive(Clone, Copy, Debug)] enum FatType { - Fat12, - Fat16, - Fat32, + Fat12(Fat16EBPB), + Fat16(Fat16EBPB), + Fat32(Fat32EBPB), } #[repr(C, packed)] @@ -47,10 +51,24 @@ pub struct BIOSParameterBlock { pub head_count: u16, // 10 00 (16) pub hidden_sectors: u32, // 00 00 00 00 pub large_sector_count: u32, // 00 F8 01 00 (129024) - // pub ebpb: [u8; 54], - // --------------------------------- - // - Extended BIOS Parameter Block - - // --------------------------------- + pub ebpb_bytes: [u8; 54], +} + +// Fat 12 and Fat 16 EBPB +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +pub struct Fat16EBPB { + pub drive_number: u8, + _reserved: u8, + pub signature: u8, + pub volume_id: u32, + pub volume_label: [u8; 11], + pub system_identifier_string: [u8; 8], +} + +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +pub struct Fat32EBPB { pub sectors_per_fat_ext: u32, // E1 03 00 00 (993, wtf) pub flags: [u8; 2], // 00 00 pub fat_version: u16, // 00 00 @@ -64,15 +82,12 @@ pub struct BIOSParameterBlock { pub volume_id: u32, // Varies pub volume_label: [u8; 11], // "NO NAME " pub system_identifier_string: [u8; 8], // Always "FAT32 " but never trust the contents of this string (for some reason) - _boot_code: [u8; 420], // ~~code~~ - pub bootable_signature: u16, // 0xAA55 } #[repr(C, packed)] #[derive(Debug)] pub struct FSInfo { pub lead_signature: u32, - _reserved: [u8; 480], pub mid_signature: u32, pub last_known_free_cluster: u32, pub look_for_free_clusters: u32, @@ -83,7 +98,6 @@ pub struct FSInfo { impl FSInfo { pub fn from_bytes(bytes: Arc<[u8]>) -> Self { let lead_signature = u32::from_le_bytes(bytes[0..4].try_into().unwrap()); - let _reserved = bytes[4..484].try_into().unwrap(); let mid_signature = u32::from_le_bytes(bytes[484..488].try_into().unwrap()); let last_known_free_cluster = u32::from_le_bytes(bytes[488..492].try_into().unwrap()); let look_for_free_clusters = u32::from_le_bytes(bytes[492..496].try_into().unwrap()); @@ -92,7 +106,6 @@ impl FSInfo { return Self { lead_signature, - _reserved, mid_signature, last_known_free_cluster, look_for_free_clusters, @@ -150,7 +163,7 @@ pub struct FatFs<'a> { drive: &'a dyn BlockDevice, partition: GPTPartitionEntry, // FAT info - fs_info: FSInfo, + fs_info: Option, fat: Option>, bpb: BIOSParameterBlock, fat_start: u64, @@ -165,56 +178,12 @@ impl<'a> FatFs<'a> { .read(partition.start_sector, 1) .expect("Failed to read FAT32 BIOS Parameter Block!"); - let bpb = unsafe { *(bpb_bytes.clone().as_ptr() as *const BIOSParameterBlock) }; - - let system_identifier = core::str::from_utf8(&bpb.system_identifier_string); - - if system_identifier.is_err() { - return Err(()); - } - - // We're trusting it - if let Ok(system_identifier_string) = system_identifier { - if !system_identifier_string.contains("FAT32") { - return Err(()); - } - } - - let fsinfo_bytes = drive - .read(partition.start_sector + bpb.fsinfo_sector as u64, 1) - .expect("Failed to read FSInfo sector!"); - - let fs_info = FSInfo::from_bytes(fsinfo_bytes); - - let fat_start = partition.start_sector + bpb.reserved_sectors as u64; - - let bytes_per_fat = 512 * bpb.sectors_per_fat_ext as usize; - - let mut fat: Option> = None; - - if crate::KERNEL_FEATURES.fat_in_mem { - let mut fat_vec: Vec = Vec::with_capacity(bytes_per_fat / 4); - - for i in 0..(bpb.sectors_per_fat_ext as usize) { - let sector = drive - .read(fat_start + i as u64, 1) - .expect("Failed to read FAT"); - for j in 0..(512 / 4) { - fat_vec.push(u32::from_le_bytes( - sector[j * 4..(j * 4 + 4)].try_into().unwrap(), - )) - } - } - - fat = Some(Arc::from(fat_vec)); - } else { - crate::log_info!( - "\033[33mWARNING\033[0m: FAT is not being stored in memory, this feature is experimental and file reads are expected to be slower." - ) - } + let bpb = unsafe { *(bpb_bytes.as_ptr().cast::()) }; let (total_sectors, fat_size) = if bpb.total_sectors == 0 { - (bpb.large_sector_count, bpb.sectors_per_fat_ext) + (bpb.large_sector_count, unsafe { + (*bpb.ebpb_bytes.as_ptr().cast::()).sectors_per_fat_ext + }) } else { (bpb.total_sectors as u32, bpb.sectors_per_fat as u32) }; @@ -229,20 +198,104 @@ impl<'a> FatFs<'a> { let total_clusters = total_data_sectors / bpb.sectors_per_cluster as u32; let fat_type = if total_clusters < 4085 { - FatType::Fat12 + FatType::Fat12(unsafe { *bpb.ebpb_bytes.as_ptr().cast::() }) } else if total_clusters < 65525 { - FatType::Fat16 + FatType::Fat16(unsafe { *bpb.ebpb_bytes.as_ptr().cast::() }) } else { - FatType::Fat32 + FatType::Fat32(unsafe { *bpb.ebpb_bytes.as_ptr().cast::() }) }; - crate::println!("Found {fat_type:?} FS"); + let system_ident = match fat_type { + FatType::Fat12(ebpb) => ebpb.system_identifier_string, + FatType::Fat16(ebpb) => ebpb.system_identifier_string, + FatType::Fat32(ebpb) => ebpb.system_identifier_string, + }; + + let system_identifier = core::str::from_utf8(&system_ident); + + if system_identifier.is_err() { + return Err(()); + } + + if let Ok(system_identifier_string) = system_identifier { + match fat_type { + FatType::Fat12(_) => { + if !system_identifier_string.contains("FAT12") { + return Err(()); + } + } + FatType::Fat16(_) => { + if !system_identifier_string.contains("FAT16") { + return Err(()); + } + } + FatType::Fat32(_) => { + if !system_identifier_string.contains("FAT32") { + return Err(()); + } + } + } + } + + let fs_info = match fat_type { + FatType::Fat32(ebpb) => { + let fsinfo_bytes = drive + .read(partition.start_sector + ebpb.fsinfo_sector as u64, 1) + .expect("Failed to read FSInfo sector!"); + + Some(FSInfo::from_bytes(fsinfo_bytes)) + } + _ => None, + }; + + let fat_start = partition.start_sector + bpb.reserved_sectors as u64; let sectors_per_fat = match fat_type { - FatType::Fat32 => bpb.sectors_per_fat_ext as usize, + FatType::Fat32(ebpb) => ebpb.sectors_per_fat_ext as usize, _ => bpb.sectors_per_fat as usize, }; + let bytes_per_fat = 512 * sectors_per_fat; + + let mut fat: Option> = None; + + if crate::KERNEL_FEATURES.fat_in_mem { + let cluster_bytes = match fat_type { + FatType::Fat32(_) => 4, + _ => 2, + }; + + let mut fat_vec: Vec = Vec::with_capacity(bytes_per_fat / cluster_bytes); + + for i in 0..sectors_per_fat { + let sector = drive + .read(fat_start + i as u64, 1) + .expect("Failed to read FAT"); + for j in 0..(512 / cluster_bytes) { + match fat_type { + FatType::Fat32(_) => fat_vec.push(u32::from_le_bytes( + sector[j * cluster_bytes..(j * cluster_bytes + cluster_bytes)] + .try_into() + .unwrap(), + )), + _ => fat_vec.push(u16::from_le_bytes( + sector[j * cluster_bytes..(j * cluster_bytes + cluster_bytes)] + .try_into() + .unwrap(), + ) as u32), + } + } + } + + fat = Some(Arc::from(fat_vec)); + } else { + crate::log_info!( + "\033[33mWARNING\033[0m: FAT is not being stored in memory, this feature is experimental and file reads are expected to be slower." + ) + } + + crate::println!("Found {fat_type:?} FS"); + let cluster_size = bpb.sectors_per_cluster as usize * 512; return Ok(Self { @@ -379,45 +432,66 @@ impl<'a> FatFs<'a> { + (self.bpb.fat_count as usize * fat_size) + root_dir_sectors as usize; - return ((cluster - 2) as isize * self.bpb.sectors_per_cluster as isize) as usize - + first_data_sector; + return ((((cluster.wrapping_sub(2)) as isize) + .wrapping_mul(self.bpb.sectors_per_cluster as isize)) as usize) + .wrapping_add(first_data_sector); + } + + fn sector_to_cluster(&self, sector: usize) -> usize { + let fat_size = self.sectors_per_fat; + let root_dir_sectors = ((self.bpb.root_directory_count * 32) + + (self.bpb.bytes_per_sector - 1)) + / self.bpb.bytes_per_sector; + + let first_data_sector = self.bpb.reserved_sectors as usize + + (self.bpb.fat_count as usize * fat_size) + + root_dir_sectors as usize; + + return (((sector).wrapping_sub(first_data_sector)) + .wrapping_div(self.bpb.sectors_per_cluster as usize)) + .wrapping_add(2); } fn get_next_cluster(&self, cluster: usize) -> u32 { if crate::KERNEL_FEATURES.fat_in_mem { return match self.fat_type { - FatType::Fat12 => { - todo!(); - } - FatType::Fat16 => { - todo!(); - } - FatType::Fat32 => self.fat.as_ref().unwrap()[cluster] & 0x0FFFFFFF, + FatType::Fat12(_) => self.fat.as_ref().unwrap()[cluster] & 0x0FFF, + FatType::Fat16(_) => self.fat.as_ref().unwrap()[cluster] & 0xFFFF, + FatType::Fat32(_) => self.fat.as_ref().unwrap()[cluster] & 0x0FFFFFFF, }; } else { let fat_entry_size = match self.fat_type { - FatType::Fat12 => 1, // 12 bits per entry - FatType::Fat16 => 2, // 16 bits per entry - FatType::Fat32 => 4, // "32" bits per entry + FatType::Fat12(_) => 2, // 12 bits per entry + FatType::Fat16(_) => 2, // 16 bits per entry + FatType::Fat32(_) => 4, // 28S bits per entry }; let entry_offset = cluster * fat_entry_size; let entry_offset_in_sector = entry_offset % 512; + // needs two incase we "straddle a sector" let sector_data = self .drive - .read(self.fat_start + entry_offset as u64 / 512, 1) + .read(self.fat_start + entry_offset as u64 / 512, 2) .expect("Failed to read from FAT!"); match self.fat_type { - FatType::Fat12 => { - todo!(); + FatType::Fat12(_) => { + let cluster_entry_bytes: [u8; 2] = sector_data + [entry_offset_in_sector..entry_offset_in_sector + 2] + .try_into() + .unwrap(); + return (u16::from_le_bytes(cluster_entry_bytes) & 0x0FFF) as u32; } - FatType::Fat16 => { - todo!(); + FatType::Fat16(_) => { + let cluster_entry_bytes: [u8; 2] = sector_data + [entry_offset_in_sector..entry_offset_in_sector + 2] + .try_into() + .unwrap(); + return (u16::from_le_bytes(cluster_entry_bytes) & 0xFFFF) as u32; } - FatType::Fat32 => { + FatType::Fat32(_) => { let cluster_entry_bytes: [u8; 4] = sector_data - [entry_offset_in_sector..=entry_offset_in_sector + 3] + [entry_offset_in_sector..entry_offset_in_sector + 4] .try_into() .unwrap(); return u32::from_le_bytes(cluster_entry_bytes) & 0x0FFFFFFF; @@ -430,7 +504,13 @@ impl<'a> FatFs<'a> { impl<'a> VfsFileSystem for FatFs<'a> { fn open(&self, path: &str) -> Result, ()> { let path_componenets: Vec<&str> = path.trim_start_matches('/').split('/').collect(); - let mut current_cluster = self.bpb.root_dir_cluster as usize; + let mut current_cluster = match self.fat_type { + FatType::Fat32(ebpb) => ebpb.root_dir_cluster as usize, + _ => self.sector_to_cluster( + self.bpb.reserved_sectors as usize + + (self.bpb.fat_count as usize * self.sectors_per_fat), + ), + }; for path in path_componenets { let file_entry: FileEntry = self.find_entry_in_directory(current_cluster, path)?; @@ -497,8 +577,22 @@ impl<'a> VfsFile for FatFile<'a> { cluster = self.fat_fs.get_next_cluster(cluster as usize); - if cluster >= EOC { - break; + match self.fat_fs.fat_type { + FatType::Fat12(_) => { + if cluster >= EOC_12 { + break; + } + } + FatType::Fat16(_) => { + if cluster >= EOC_16 { + break; + } + } + FatType::Fat32(_) => { + if cluster >= EOC_32 { + break; + } + } } } diff --git a/src/drivers/fs/initramfs/compressors/gzip.rs b/src/drivers/fs/initramfs/compressors/gzip.rs index 9f5c7ba..58b4e44 100644 --- a/src/drivers/fs/initramfs/compressors/gzip.rs +++ b/src/drivers/fs/initramfs/compressors/gzip.rs @@ -238,12 +238,13 @@ impl InflateContext { } self.ring.data[self.ring.pointer] = byte; - self.output_buf.push(byte); self.ring.pointer += 1; + self.output_buf.push(byte); } fn peek(&mut self, offset: usize) -> u8 { - self.ring.data[(self.ring.pointer - offset) % 32768] + let index = (self.ring.pointer as usize).wrapping_sub(offset as usize) % 32768; + self.ring.data[index] } fn uncompressed(&mut self) -> Result<(), ()> { diff --git a/src/drivers/fs/initramfs/mod.rs b/src/drivers/fs/initramfs/mod.rs index 5beea59..8780c46 100755 --- a/src/drivers/fs/initramfs/mod.rs +++ b/src/drivers/fs/initramfs/mod.rs @@ -211,9 +211,7 @@ impl Squashfs<'_> { &inode_table[inode_offset..], )); } - _ => { - panic!("Unsupported or unknown inode file type {inode_file_type:?}!") - } + _ => panic!("Unsupported or unknown inode file type {inode_file_type:?}!"), }; } diff --git a/src/drivers/storage/drive.rs b/src/drivers/storage/drive.rs deleted file mode 100644 index 688bd49..0000000 --- a/src/drivers/storage/drive.rs +++ /dev/null @@ -1,74 +0,0 @@ -use alloc::sync::Arc; - -pub trait BlockDevice { - fn sector_count(&self) -> u64; - fn read(&self, sector: u64, sector_count: usize) -> Result, ()>; - fn write(&self, sector: u64, data: &[u8]) -> Result<(), ()>; -} - -#[derive(Clone, Copy, Debug)] -pub struct GPTPartitionEntry { - pub partition_type_guid: [u8; 16], - pub unique_partition_guid: [u8; 16], - pub start_sector: u64, - pub end_sector: u64, - pub attributes: u64, - pub partition_name: [u8; 72], -} - -#[derive(Debug)] -pub struct GPTBlock { - pub header: [u8; 8], // 0x45 0x46 0x49 0x20 0x50 0x41 0x52 0x54 - pub revision: u32, - pub header_size: u32, - pub header_checksum: u32, // CRC32 - _reserved: [u8; 4], - pub header_lba: u64, - pub header_lba_alt: u64, - pub first_usable_block: u64, - pub last_usable_block: u64, - pub guid: [u8; 16], - pub guid_lba: u64, - pub partition_entry_count: u32, - pub partition_entry_size: u32, - pub partition_table_crc: u32, - _reserved2: [u8; 512 - 0x5C], -} - -impl GPTBlock { - pub fn new(data: &[u8; 512]) -> Self { - let header = data[0x00..0x08].try_into().unwrap(); - let revision = u32::from_le_bytes(data[0x08..0x0C].try_into().unwrap()); - let header_size = u32::from_le_bytes(data[0x0C..0x10].try_into().unwrap()); - let header_checksum = u32::from_le_bytes(data[0x10..0x14].try_into().unwrap()); - let _reserved = data[0x14..0x18].try_into().unwrap(); - let header_lba = u64::from_le_bytes(data[0x18..0x20].try_into().unwrap()); - let header_lba_alt = u64::from_le_bytes(data[0x20..0x28].try_into().unwrap()); - let first_usable_block = u64::from_le_bytes(data[0x28..0x30].try_into().unwrap()); - let last_usable_block = u64::from_le_bytes(data[0x30..0x38].try_into().unwrap()); - let guid = data[0x38..0x48].try_into().unwrap(); - let guid_lba = u64::from_le_bytes(data[0x48..0x50].try_into().unwrap()); - let partition_entry_count = u32::from_le_bytes(data[0x50..0x54].try_into().unwrap()); - let partition_entry_size = u32::from_le_bytes(data[0x54..0x58].try_into().unwrap()); - let partition_table_crc = u32::from_le_bytes(data[0x58..0x5C].try_into().unwrap()); - let _reserved2 = data[0x5C..512].try_into().unwrap(); - - GPTBlock { - header, - revision, - header_size, - header_checksum, - _reserved, - header_lba, - header_lba_alt, - first_usable_block, - last_usable_block, - guid, - guid_lba, - partition_entry_count, - partition_entry_size, - partition_table_crc, - _reserved2, - } - } -} diff --git a/src/drivers/storage/ide.rs b/src/drivers/storage/ide.rs index b7ef3f7..499df8d 100755 --- a/src/drivers/storage/ide.rs +++ b/src/drivers/storage/ide.rs @@ -6,12 +6,12 @@ use crate::{ arch::io::{inb, insw, inw, outb, outsw}, drivers::{ fs::fat, - storage::drive::{GPTBlock, GPTPartitionEntry}, + storage::{GPTHeader, GPTPartitionEntry, MBR}, }, - libs::mutex::Mutex, + libs::{mutex::Mutex, uuid::Uuid}, }; -use super::drive::BlockDevice; +use super::BlockDevice; const ATA_SECTOR_SIZE: usize = 512; @@ -564,12 +564,16 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { (sectors * ATA_SECTOR_SIZE as u64) / 1024 / 1024 ); - let mbr_sector = drive.read(0, 1).expect("Failed to read first sector"); + let mbr_sector: MBR = (*drive.read(0, 1).expect("Failed to read first sector")).into(); - let signature: [u8; 2] = mbr_sector[510..].try_into().unwrap(); + if u16::from_le_bytes(mbr_sector.signature) != 0xAA55 { + panic!("MBR is corrupted!"); + } - if u16::from_le_bytes(signature[0..2].try_into().unwrap()) != 0xAA55 { - panic!("First sector is not MBR"); + let mbr_partitions = mbr_sector.partitions(); + + if mbr_partitions[0].partition_type != 0xEE { + panic!("MBR disks are unsupported") } let gpt_sector = drive.read(1, 1).expect("Failed to read sector 2"); @@ -577,14 +581,7 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { let mut array = [0u8; 512]; array.copy_from_slice(&gpt_sector[..512]); - let mut signature = [0u8; 8]; - signature.copy_from_slice(&gpt_sector[0..8]); - - if &signature != b"EFI PART" { - panic!("MBR Disk is unsupported!") - } - - let gpt = GPTBlock::new(&array); + let gpt = GPTHeader::new(&array); let mut partitions: Vec = Vec::with_capacity(gpt.partition_entry_count as usize); @@ -607,27 +604,24 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { for i in 0..gpt.partition_entry_count { let entry_offset = (i * gpt.partition_entry_size) as usize; - let partition_type_guid: [u8; 16] = partition_sector[entry_offset..entry_offset + 16] + let partition_type_guid_bytes: [u8; 16] = partition_sector + [entry_offset..entry_offset + 16] .try_into() .unwrap(); - let mut is_zero = true; + let partition_type_guid = Uuid::from(partition_type_guid_bytes); - for &j in partition_type_guid.iter() { - if j != 0 { - is_zero = false; - } - } - - if is_zero { + if partition_type_guid == "00000000-0000-0000-0000-000000000000 " { continue; } - let unique_partition_guid: [u8; 16] = partition_sector + let unique_partition_guid_bytes: [u8; 16] = partition_sector [entry_offset + 16..entry_offset + 32] .try_into() .unwrap(); + let unique_partition_guid = Uuid::from(unique_partition_guid_bytes); + let start_sector = u64::from_le_bytes( partition_sector[entry_offset + 32..entry_offset + 40] .try_into() @@ -661,6 +655,10 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { } for &partition in partitions.iter() { + if partition.partition_type_guid != "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" { + continue; + } + let fat_fs = fat::FatFs::new(drive, partition); if fat_fs.is_err() { @@ -671,7 +669,7 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { let vfs = crate::drivers::fs::vfs::Vfs::new( Box::new(fat_fs), - &format!("{:?}", partition.partition_type_guid), + &format!("{}", partition.partition_type_guid), ); crate::drivers::fs::vfs::VFS_INSTANCES @@ -692,6 +690,6 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { ); } - crate::println!("{:?}", partitions); + crate::println!("{:X?}", partitions); } } diff --git a/src/drivers/storage/mod.rs b/src/drivers/storage/mod.rs index 37598e7..7edfc82 100644 --- a/src/drivers/storage/mod.rs +++ b/src/drivers/storage/mod.rs @@ -1,2 +1,152 @@ -pub mod drive; pub mod ide; + +use alloc::{sync::Arc, vec::Vec}; + +use crate::libs::uuid::Uuid; + +pub trait BlockDevice { + fn sector_count(&self) -> u64; + fn read(&self, sector: u64, sector_count: usize) -> Result, ()>; + fn write(&self, sector: u64, data: &[u8]) -> Result<(), ()>; +} + +#[derive(Clone, Copy, Debug)] +pub struct MBR { + pub disk_id: [u8; 4], + _reserved: [u8; 2], + pub first_partition: [u8; 16], + pub second_partition: [u8; 16], + pub third_partition: [u8; 16], + pub fourth_partition: [u8; 16], + pub signature: [u8; 2], +} + +impl From<&[u8]> for MBR { + fn from(value: &[u8]) -> Self { + let mut offset = 0; + + if value.len() >= 512 { + offset = 440; + } + + return Self { + disk_id: value[offset..offset + 4].try_into().unwrap(), + _reserved: value[offset + 4..offset + 6].try_into().unwrap(), + first_partition: value[offset + 6..offset + 22].try_into().unwrap(), + second_partition: value[offset + 22..offset + 38].try_into().unwrap(), + third_partition: value[offset + 38..offset + 54].try_into().unwrap(), + fourth_partition: value[offset + 54..offset + 70].try_into().unwrap(), + signature: value[offset + 70..offset + 72].try_into().unwrap(), + }; + } +} + +impl MBR { + pub fn partitions(&self) -> Arc<[MBRPartition]> { + let mut partitions = Vec::new(); + + let raw_partitions = [ + self.first_partition, + self.second_partition, + self.third_partition, + self.fourth_partition, + ]; + + for partition in raw_partitions.iter() { + // if partition bytes are empty + if partition.iter().filter(|&&x| x > 0).count() == 0 { + break; + } + + let partition = MBRPartition { + boot_indicator: partition[0], + partition_start_chs: partition[1..4].try_into().unwrap(), + partition_type: partition[4], + partition_end_chs: partition[4..7].try_into().unwrap(), + partition_start_lba: u32::from_le_bytes(partition[8..12].try_into().unwrap()), + partition_sectors: u32::from_le_bytes(partition[12..16].try_into().unwrap()), + }; + + partitions.push(partition) + } + + return Arc::from(partitions); + } +} + +#[derive(Clone, Copy, Debug)] +pub struct MBRPartition { + pub boot_indicator: u8, + pub partition_start_chs: [u8; 3], + pub partition_type: u8, + pub partition_end_chs: [u8; 3], + pub partition_start_lba: u32, + pub partition_sectors: u32, +} + +#[derive(Clone, Copy, Debug)] +pub struct GPTPartitionEntry { + pub partition_type_guid: Uuid, + pub unique_partition_guid: Uuid, + pub start_sector: u64, + pub end_sector: u64, + pub attributes: u64, + pub partition_name: [u8; 72], +} + +#[derive(Debug)] +pub struct GPTHeader { + pub header: [u8; 8], // 0x45 0x46 0x49 0x20 0x50 0x41 0x52 0x54 + pub revision: u32, + pub header_size: u32, + pub header_checksum: u32, // CRC32 + _reserved: [u8; 4], + pub header_lba: u64, + pub header_lba_alt: u64, + pub first_usable_block: u64, + pub last_usable_block: u64, + pub guid: Uuid, + pub guid_lba: u64, + pub partition_entry_count: u32, + pub partition_entry_size: u32, + pub partition_table_crc: u32, +} + +impl GPTHeader { + pub fn new(data: &[u8]) -> Self { + assert!(data.len() >= 0x5C); + + let header = data[0x00..0x08].try_into().unwrap(); + let revision = u32::from_le_bytes(data[0x08..0x0C].try_into().unwrap()); + let header_size = u32::from_le_bytes(data[0x0C..0x10].try_into().unwrap()); + let header_checksum = u32::from_le_bytes(data[0x10..0x14].try_into().unwrap()); + let _reserved = data[0x14..0x18].try_into().unwrap(); + let header_lba = u64::from_le_bytes(data[0x18..0x20].try_into().unwrap()); + let header_lba_alt = u64::from_le_bytes(data[0x20..0x28].try_into().unwrap()); + let first_usable_block = u64::from_le_bytes(data[0x28..0x30].try_into().unwrap()); + let last_usable_block = u64::from_le_bytes(data[0x30..0x38].try_into().unwrap()); + let guid_bytes: [u8; 16] = data[0x38..0x48].try_into().unwrap(); + let guid = guid_bytes.try_into().unwrap(); + let guid_lba = u64::from_le_bytes(data[0x48..0x50].try_into().unwrap()); + let partition_entry_count = u32::from_le_bytes(data[0x50..0x54].try_into().unwrap()); + let partition_entry_size = u32::from_le_bytes(data[0x54..0x58].try_into().unwrap()); + let partition_table_crc = u32::from_le_bytes(data[0x58..0x5C].try_into().unwrap()); + + Self { + header, + revision, + header_size, + header_checksum, + _reserved, + header_lba, + header_lba_alt, + first_usable_block, + last_usable_block, + guid, + guid_lba, + partition_entry_count, + partition_entry_size, + partition_table_crc, + } + } +} diff --git a/src/drivers/video/font.rs b/src/drivers/video/font.rs index f2c834e..cebffff 100755 --- a/src/drivers/video/font.rs +++ b/src/drivers/video/font.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use crate::{ drivers::fs::{initramfs::INITRAMFS, vfs::VfsFileSystem}, - libs::lazy::Lazy, + libs::{lazy::Lazy, mutex::Mutex}, }; #[derive(Debug)] diff --git a/src/libs/elf.rs b/src/libs/elf.rs new file mode 100644 index 0000000..ae65ddd --- /dev/null +++ b/src/libs/elf.rs @@ -0,0 +1,15 @@ +#[derive(Clone, Copy, Debug)] +pub struct Elf; + +pub fn load_elf(bytes: &[u8]) -> Result { + if &bytes[0..4] != b"\x74ELF" { + return Err(()); + } + + if bytes[5] != 0x02 { + // Only support 64-bit ELF files for now + return Err(()); + } + + return Ok(Elf); +} diff --git a/src/libs/mod.rs b/src/libs/mod.rs index 3886c61..763fec1 100644 --- a/src/libs/mod.rs +++ b/src/libs/mod.rs @@ -1,5 +1,8 @@ +pub mod elf; pub mod lazy; pub mod logging; pub mod math; pub mod mutex; +pub mod oncecell; pub mod util; +pub mod uuid; diff --git a/src/libs/oncecell.rs b/src/libs/oncecell.rs new file mode 100644 index 0000000..f72b22e --- /dev/null +++ b/src/libs/oncecell.rs @@ -0,0 +1,70 @@ +use core::{cell::UnsafeCell, ops::Deref, sync::atomic::AtomicU8}; + +pub struct OnceCell { + state: AtomicU8, + data: UnsafeCell>, +} + +unsafe impl Sync for OnceCell {} + +#[repr(u8)] +enum State { + Uninitialized = 0, + Initializing, + Initialized, +} + +impl From for State { + fn from(value: u8) -> Self { + match value { + 0 => State::Uninitialized, + 1 => State::Initializing, + 2 => State::Initialized, + _ => panic!("Invalid state value"), + } + } +} + +impl OnceCell { + pub const fn new() -> Self { + return OnceCell { + state: AtomicU8::new(State::Uninitialized as u8), + data: UnsafeCell::new(None), + }; + } + + pub fn set(&self, new_data: T) { + let current_state = self.state.load(core::sync::atomic::Ordering::SeqCst); + + match State::from(current_state) { + State::Uninitialized => { + self.state.store( + State::Initializing as u8, + core::sync::atomic::Ordering::SeqCst, + ); + + unsafe { *self.data.get() = Some(new_data) }; + + self.state.store( + State::Initialized as u8, + core::sync::atomic::Ordering::SeqCst, + ); + } + _ => panic!("Tried to initialize data that is alread initialized"), + } + } +} + +impl Deref for OnceCell { + type Target = T; + + fn deref(&self) -> &Self::Target { + if self.state.load(core::sync::atomic::Ordering::SeqCst) == State::Initialized as u8 { + if let Some(value) = unsafe { &*self.data.get() } { + return value; + } + } + + panic!("Attempted to access uninitialized data!") + } +} diff --git a/src/libs/uuid.rs b/src/libs/uuid.rs new file mode 100644 index 0000000..149a750 --- /dev/null +++ b/src/libs/uuid.rs @@ -0,0 +1,100 @@ +use core::fmt::Display; + +use alloc::{string::String, vec::Vec}; + +#[derive(Clone, Copy, Debug)] +pub struct Uuid { + pub a: u32, + pub b: u16, + pub c: u16, + pub d: [u8; 8], +} + +impl From<[u8; 16]> for Uuid { + fn from(value: [u8; 16]) -> Self { + let a = u32::from_le_bytes(value[0..4].try_into().unwrap()); + let b = u16::from_le_bytes(value[4..6].try_into().unwrap()); + let c = u16::from_le_bytes(value[6..8].try_into().unwrap()); + let d = value[8..16].try_into().unwrap(); + + return Self { a, b, c, d }; + } +} + +impl PartialEq for Uuid { + fn eq(&self, other: &Self) -> bool { + return self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d; + } +} + +impl PartialEq<&str> for Uuid { + fn eq(&self, other: &&str) -> bool { + let parts = other.split("-").collect::>(); + + if parts.len() != 5 { + return false; + } + + let a = u32::from_str_radix(parts[0], 16); + let b = u16::from_str_radix(parts[1], 16); + let c = u16::from_str_radix(parts[2], 16); + + if a.is_err() || b.is_err() || c.is_err() { + return false; + } + + let d = { + let part = [parts[3], parts[4]].concat(); + + let mut d_vec = Vec::new(); + let d_parts = part + .trim() + .chars() + .collect::>() + .chunks(2) + .map(|chunk| chunk.iter().collect()) + .collect::>(); + + for d_part in d_parts { + let d_part = u8::from_str_radix(&d_part, 16); + + if d_part.is_err() { + return false; + } + + d_vec.push(d_part.unwrap()); + } + + d_vec + }; + + let d: &[u8] = &d; + + let d: Result<[u8; 8], _> = d.try_into(); + + if d.is_err() { + return false; + } + + let uuid = Uuid { + a: a.unwrap(), + b: b.unwrap(), + c: c.unwrap(), + d: d.unwrap(), + }; + + return self == &uuid; + } +} + +impl Display for Uuid { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:X}-{:X}-{:X}-", self.a, self.b, self.c)?; + + for &byte in &self.d { + write!(f, "{:02X}", byte)?; + } + + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index 333590a..085d274 100755 --- a/src/main.rs +++ b/src/main.rs @@ -30,7 +30,7 @@ pub extern "C" fn _start() -> ! { mem::log_info(); - // drivers::acpi::init_acpi(); + drivers::acpi::init_acpi(); #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] drivers::pci::enumerate_pci_bus(); @@ -117,12 +117,14 @@ fn parse_kernel_cmdline() -> KernelFeatures { #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { - let message = format!("{}", info); + let message = format!("{}\n", info); for ch in message.chars() { write_serial(ch); } + log_error!("{}", info); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { let rbp: u64; diff --git a/src/mem/mod.rs b/src/mem/mod.rs index 7dc4ede..cb0c5a3 100755 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -90,6 +90,20 @@ pub static ALLOCATOR: Allocator = Allocator { }), }; +#[no_mangle] +pub extern "C" fn malloc(size: usize) -> *mut u8 { + let layout = core::alloc::Layout::from_size_align(size, 1).unwrap(); + unsafe { ALLOCATOR.alloc(layout) } +} + +#[no_mangle] +pub extern "C" fn free(ptr: *mut u8, size: usize) { + let layout = core::alloc::Layout::from_size_align(size, 1).unwrap(); + unsafe { + ALLOCATOR.dealloc(ptr, layout); + } +} + pub fn log_info() { crate::log_info!( "Initialized heap with {} of memory at {:#X}", diff --git a/src/usr/tty.rs b/src/usr/tty.rs index 973efe3..ad1529d 100755 --- a/src/usr/tty.rs +++ b/src/usr/tty.rs @@ -8,7 +8,8 @@ use alloc::{ }; use crate::{ - libs::{lazy::Lazy, mutex::Mutex}, + drivers::{fs::vfs::VFS_INSTANCES, serial::write_serial}, + libs::{elf::load_elf, lazy::Lazy, mutex::Mutex}, mem::LabelBytes, }; @@ -781,7 +782,28 @@ pub fn exec(command: &str) { return; } - println!("{:?} {:?}", command, args); + // TODO: check a path and not just /bin/ + if let Ok(program) = VFS_INSTANCES.lock().read()[0].open(&format!("/bin/{}", command)) { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + let program_bytes = program.read().expect("Failed to read program!"); + let program_elf = match load_elf(&program_bytes) { + Ok(elf) => elf, + Err(_) => { + println!("Command not found: {command} (err)"); + return; + } + }; + crate::arch::push_gprs(); + + // execute program + crate::println!("{program_elf:?}"); + + crate::arch::pop_gprs(); + } + } else { + println!("Command not found: {command}"); + } } fn parse_input(input: &str) -> (String, Vec) {