From b123e15b3c8f605b24e5226d472d9b1d976fc485 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Apr 2020 19:07:49 +0800 Subject: [PATCH] SDRAM loader --- Cargo.lock | 47 ++- Cargo.toml | 3 +- README.md | 6 + remote_run.sh | 4 +- runtime.bin | Bin 0 -> 142268 bytes runtime/build.rs | 18 ++ runtime/link.x | 71 +++++ runtime/src/main.rs | 14 +- shell.nix | 1 + szl/Cargo.toml | 17 ++ szl/build.rs | 48 ++++ link.x => szl/link.x | 0 szl/src/main.rs | 68 +++++ szl/src/unlzma.c | 670 +++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 945 insertions(+), 22 deletions(-) create mode 100644 README.md create mode 100755 runtime.bin create mode 100644 runtime/build.rs create mode 100644 runtime/link.x create mode 100644 szl/Cargo.toml create mode 100644 szl/build.rs rename link.x => szl/link.x (100%) create mode 100644 szl/src/main.rs create mode 100644 szl/src/unlzma.c diff --git a/Cargo.lock b/Cargo.lock index 52d0206c..9b53e063 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,6 +42,22 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" +[[package]] +name = "cstr_core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8758514b5f03968703f1db1f1e196e031d5268f5295ff99a5bf345008790ba85" +dependencies = [ + "cty", + "memchr", +] + +[[package]] +name = "cty" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3" + [[package]] name = "dyld" version = "0.1.0" @@ -134,7 +150,7 @@ dependencies = [ [[package]] name = "libasync" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#614b1ef350edd8576fc71292fc89cf79a1810aba" dependencies = [ "embedded-hal", "libcortex_a9", @@ -146,7 +162,7 @@ dependencies = [ [[package]] name = "libboard_zynq" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#614b1ef350edd8576fc71292fc89cf79a1810aba" dependencies = [ "bit_field", "embedded-hal", @@ -161,7 +177,7 @@ dependencies = [ [[package]] name = "libcortex_a9" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#614b1ef350edd8576fc71292fc89cf79a1810aba" dependencies = [ "bit_field", "libregister", @@ -170,7 +186,7 @@ dependencies = [ [[package]] name = "libregister" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#614b1ef350edd8576fc71292fc89cf79a1810aba" dependencies = [ "bit_field", "vcell", @@ -180,7 +196,7 @@ dependencies = [ [[package]] name = "libsupport_zynq" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#614b1ef350edd8576fc71292fc89cf79a1810aba" dependencies = [ "compiler_builtins", "libboard_zynq", @@ -193,9 +209,9 @@ dependencies = [ [[package]] name = "linked_list_allocator" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1070ea54beccbfd3a3987aca6440f94cc1e0b447c2d979d8c7f761e265417e4" +checksum = "d6b60501dd4c850950bb43f970d544f6ce04e0ca021da2db2538fbe9d923f19e" [[package]] name = "log" @@ -212,6 +228,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6" +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + [[package]] name = "nb" version = "0.1.2" @@ -319,6 +341,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "szl" +version = "0.1.0" +dependencies = [ + "cstr_core", + "libboard_zynq", + "libcortex_a9", + "libsupport_zynq", + "log", +] + [[package]] name = "unicode-xid" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 49dffcba..db8f74b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ [workspace] members = [ "libdyld", - "runtime" + "runtime", + "szl" ] [profile.dev] diff --git a/README.md b/README.md new file mode 100644 index 00000000..39428402 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +Build with: + +```shell +cargo xbuild -p runtime --release +cargo xbuild -p szl --release +``` diff --git a/remote_run.sh b/remote_run.sh index 7166b194..dfccd2e8 100755 --- a/remote_run.sh +++ b/remote_run.sh @@ -8,6 +8,6 @@ TARGET_FOLDER=/tmp/zynq-\$USER ssh $TARGET_HOST "mkdir -p $TARGET_FOLDER" rsync openocd/* $TARGET_HOST:$TARGET_FOLDER -rsync target/armv7-none-eabihf/release/runtime $TARGET_HOST:$TARGET_FOLDER +rsync target/armv7-none-eabihf/release/szl $TARGET_HOST:$TARGET_FOLDER rsync build/top.bit $TARGET_HOST:$TARGET_FOLDER -ssh $TARGET_HOST "cd $TARGET_FOLDER; openocd -f zc706.cfg -c 'pld load 0 top.bit; load_image runtime; resume 0; exit'" +ssh $TARGET_HOST "cd $TARGET_FOLDER; openocd -f zc706.cfg -c 'pld load 0 top.bit; load_image szl; resume 0; exit'" diff --git a/runtime.bin b/runtime.bin new file mode 100755 index 0000000000000000000000000000000000000000..82fe7ef30e1cbbd2b1cd0f275ee64a2fba1be798 GIT binary patch literal 142268 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

RyyLviQNB6t8l=W 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 z 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 SDRAM + + .rodata : ALIGN(4) + { + *(.rodata .rodata.*); + } > SDRAM + + .data : ALIGN(4) + { + *(.data .data.*); + } > SDRAM + + .bss (NOLOAD) : ALIGN(0x4000) + { + /* Aligned to 16 kB */ + KEEP(*(.bss.l1_table)); + *(.bss .bss.*); + . = ALIGN(4); + } > SDRAM + __bss_start = ADDR(.bss); + __bss_end = ADDR(.bss) + SIZEOF(.bss); + + .heap (NOLOAD) : ALIGN(0x1000) + { + . += HEAP_SIZE; + } > SDRAM + __heap_start = ADDR(.heap); + __heap_end = ADDR(.heap) + SIZEOF(.heap); + + .stack (NOLOAD) : ALIGN(0x1000) + { + . += STACK_SIZE; + } > SDRAM + __stack_end = ADDR(.stack); + __stack_start = ADDR(.stack) + SIZEOF(.stack); + + /DISCARD/ : + { + /* Unused exception related info that only wastes space */ + *(.ARM.exidx); + *(.ARM.exidx.*); + *(.ARM.extab.*); + } +} diff --git a/runtime/src/main.rs b/runtime/src/main.rs index 447bf4c8..85e338b8 100644 --- a/runtime/src/main.rs +++ b/runtime/src/main.rs @@ -8,10 +8,7 @@ extern crate log; use core::{cmp, str}; use log::info; -use libboard_zynq::{ - self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll}, - timer::GlobalTimer, -}; +use libboard_zynq::timer::GlobalTimer; use libsupport_zynq::{logger, ram}; mod proto; @@ -42,14 +39,7 @@ pub fn main_core0() { log::set_max_level(log::LevelFilter::Debug); info!("NAR3 starting..."); - const CPU_FREQ: u32 = 800_000_000; - - ArmPll::setup(2 * CPU_FREQ); - Clocks::set_cpu_freq(CPU_FREQ); - IoPll::setup(1_000_000_000); - libboard_zynq::stdio::drop_uart(); // reinitialize UART after clocking change - let mut ddr = zynq::ddr::DdrRam::new(); - ram::init_alloc(&mut ddr); + ram::init_alloc_linker(); info!("Detected gateware: {}", identifier_read(&mut [0; 64])); diff --git a/shell.nix b/shell.nix index 949d7c31..f4f429dc 100644 --- a/shell.nix +++ b/shell.nix @@ -34,6 +34,7 @@ in rustPlatform.rust.rustc rustPlatform.rust.cargo rustcSrc + pkgs.clang_9 pkgs.cacert pkgs.cargo-xbuild diff --git a/szl/Cargo.toml b/szl/Cargo.toml new file mode 100644 index 00000000..96689877 --- /dev/null +++ b/szl/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "szl" +description = "Simple Zynq Loader" +version = "0.1.0" +authors = ["M-Labs"] +edition = "2018" + +[features] +target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706"] +default = ["target_zc706"] + +[dependencies] +log = "0.4" +cstr_core = { version = "0.2", default-features = false } +libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } +libsupport_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } +libcortex_a9 = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } diff --git a/szl/build.rs b/szl/build.rs new file mode 100644 index 00000000..57a0b117 --- /dev/null +++ b/szl/build.rs @@ -0,0 +1,48 @@ +use std::process::Command; +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::{Path, PathBuf}; + +fn main() { + // FIXME: this is dirty and unreliable. How to depend on the output of the runtime build? + let payload = "../target/armv7-none-eabihf/release/runtime"; + + let out = env::var("OUT_DIR").unwrap(); + let out_dir = &PathBuf::from(&out); + let status = Command::new("llvm-objcopy") + .args(&["-O", "binary", payload, &format!("{}/payload.bin", out)]) + .status().unwrap(); + assert!(status.success()); + let status = Command::new("lzma") + .args(&["--keep", "-f", &format!("{}/payload.bin", out)]) + .status().unwrap(); + assert!(status.success()); + println!("cargo:rerun-if-changed={}", payload); + + let status = Command::new("clang") + .args(&["-target", "armv7-unknown-linux", "-fno-stack-protector", + "src/unlzma.c", "-O2", "-c", "-fPIC", "-o", + &format!("{}/unlzma.o", out)]) + .status().unwrap(); + assert!(status.success()); + let status = Command::new("llvm-ar") + .args(&["crus", "libunlzma.a", "unlzma.o"]) + .current_dir(&Path::new(&out)) + .status().unwrap(); + assert!(status.success()); + println!("cargo:rustc-link-search=native={}", out); + println!("cargo:rustc-link-lib=static=unlzma"); + println!("cargo:rerun-if-changed=src/unlzma.c"); + + // Put the linker script somewhere the linker can find it + File::create(out_dir.join("link.x")) + .unwrap() + .write_all(include_bytes!("link.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out_dir.display()); + + // Only re-run the build script when link.x is changed, + // instead of when any part of the source code changes. + println!("cargo:rerun-if-changed=link.x"); +} diff --git a/link.x b/szl/link.x similarity index 100% rename from link.x rename to szl/link.x diff --git a/szl/src/main.rs b/szl/src/main.rs new file mode 100644 index 00000000..c5f46bed --- /dev/null +++ b/szl/src/main.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] + +extern crate log; + +use core::mem; +use log::{info, error}; +use cstr_core::CStr; + +use libboard_zynq::{ + self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll}, + timer::GlobalTimer, +}; +use libsupport_zynq::{boot, logger}; + + +static mut STACK_CORE1: [u32; 512] = [0; 512]; + +extern "C" { + fn unlzma_simple(buf: *const u8, in_len: i32, + output: *mut u8, + error: extern fn(*const u8)) -> i32; +} + +extern fn lzma_error(message: *const u8) { + error!("LZMA error: {}", unsafe { CStr::from_ptr(message) }.to_str().unwrap()); +} + +#[no_mangle] +pub fn main_core0() { + GlobalTimer::start(); + let _ = logger::init(); + log::set_max_level(log::LevelFilter::Debug); + info!("Simple Zynq Loader starting"); + + const CPU_FREQ: u32 = 800_000_000; + + ArmPll::setup(2 * CPU_FREQ); + Clocks::set_cpu_freq(CPU_FREQ); + IoPll::setup(1_000_000_000); + libboard_zynq::stdio::drop_uart(); // reinitialize UART after clocking change + let mut ddr = zynq::ddr::DdrRam::new(); + + let payload = include_bytes!(concat!(env!("OUT_DIR"), "/payload.bin.lzma")); + info!("decompressing payload"); + let result = unsafe { + unlzma_simple(payload.as_ptr(), payload.len() as i32, ddr.ptr(), lzma_error) + }; + if result < 0 { + error!("decompression failed"); + } else { + let core1_stack = unsafe { &mut STACK_CORE1[..] }; + boot::Core1::start(core1_stack); + info!("executing payload"); + unsafe { + (mem::transmute::<*mut u8, fn()>(ddr.ptr::()))(); + } + } + + loop {} +} + +#[no_mangle] +pub fn main_core1() { + unsafe { + (mem::transmute::(0x00100000))(); + } +} diff --git a/szl/src/unlzma.c b/szl/src/unlzma.c new file mode 100644 index 00000000..47cd052a --- /dev/null +++ b/szl/src/unlzma.c @@ -0,0 +1,670 @@ +/* + *Taken from: Lzma decompressor for Linux kernel. Shamelessly snarfed + *from busybox 1.1.1 + * + *Linux kernel adaptation + *Copyright (C) 2006 Alain < alain@knaff.lu > + * + *Based on small lzma deflate implementation/Small range coder + *implementation for lzma. + *Copyright (C) 2006 Aurelien Jacobs < aurel@gnuage.org > + * + *Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/) + *Copyright (C) 1999-2005 Igor Pavlov + * + *Copyrights of the parts, see headers below. + * + * + *This program is free software; you can redistribute it and/or + *modify it under the terms of the GNU Lesser General Public + *License as published by the Free Software Foundation; either + *version 2.1 of the License, or (at your option) any later version. + * + *This program is distributed in the hope that it will be useful, + *but WITHOUT ANY WARRANTY; without even the implied warranty of + *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + *Lesser General Public License for more details. + * + *You should have received a copy of the GNU Lesser General Public + *License along with this library; if not, write to the Free Software + *Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define NULL ((void *)0) +#define alloca(size) __builtin_alloca(size) +#define malloc alloca +static inline void free(void *p) {} + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +static long long read_int(unsigned char *ptr, int size) +{ + int i; + long long ret = 0; + + for (i = 0; i < size; i++) + ret = (ret << 8) | ptr[size-i-1]; + return ret; +} + +#define ENDIAN_CONVERT(x) \ + x = (typeof(x))read_int((unsigned char *)&x, sizeof(x)) + + +/* Small range coder implementation for lzma. + *Copyright (C) 2006 Aurelien Jacobs < aurel@gnuage.org > + * + *Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/) + *Copyright (c) 1999-2005 Igor Pavlov + */ + +#define LZMA_IOBUF_SIZE 0x10000 + +struct rc { + int (*fill)(void*, unsigned int); + unsigned char *ptr; + unsigned char *buffer; + unsigned char *buffer_end; + int buffer_size; + unsigned int code; + unsigned int range; + unsigned int bound; + void (*error)(char *); +}; + + +#define RC_TOP_BITS 24 +#define RC_MOVE_BITS 5 +#define RC_MODEL_TOTAL_BITS 11 + + +static int nofill(void *buffer, unsigned int len) +{ + return -1; +} + +/* Called twice: once at startup and once in rc_normalize() */ +static void rc_read(struct rc *rc) +{ + rc->buffer_size = rc->fill((char *)rc->buffer, LZMA_IOBUF_SIZE); + if (rc->buffer_size <= 0) + rc->error("unexpected EOF"); + rc->ptr = rc->buffer; + rc->buffer_end = rc->buffer + rc->buffer_size; +} + +/* Called once */ +static inline void rc_init(struct rc *rc, + int (*fill)(void*, unsigned int), + unsigned char *buffer, int buffer_size) +{ + if (fill) + rc->fill = fill; + else + rc->fill = nofill; + rc->buffer = buffer; + rc->buffer_size = buffer_size; + rc->buffer_end = rc->buffer + rc->buffer_size; + rc->ptr = rc->buffer; + + rc->code = 0; + rc->range = 0xFFFFFFFF; +} + +static inline void rc_init_code(struct rc *rc) +{ + int i; + + for (i = 0; i < 5; i++) { + if (rc->ptr >= rc->buffer_end) + rc_read(rc); + rc->code = (rc->code << 8) | *rc->ptr++; + } +} + + +/* Called twice, but one callsite is in inline'd rc_is_bit_0_helper() */ +static void rc_do_normalize(struct rc *rc) +{ + if (rc->ptr >= rc->buffer_end) + rc_read(rc); + rc->range <<= 8; + rc->code = (rc->code << 8) | *rc->ptr++; +} +static inline void rc_normalize(struct rc *rc) +{ + if (rc->range < (1 << RC_TOP_BITS)) + rc_do_normalize(rc); +} + +/* Called 9 times */ +/* Why rc_is_bit_0_helper exists? + *Because we want to always expose (rc->code < rc->bound) to optimizer + */ +static inline unsigned int rc_is_bit_0_helper(struct rc *rc, unsigned short int *p) +{ + rc_normalize(rc); + rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS); + return rc->bound; +} +static inline int rc_is_bit_0(struct rc *rc, unsigned short int *p) +{ + unsigned int t = rc_is_bit_0_helper(rc, p); + return rc->code < t; +} + +/* Called ~10 times, but very small, thus inlined */ +static inline void rc_update_bit_0(struct rc *rc, unsigned short int *p) +{ + rc->range = rc->bound; + *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS; +} +static inline void rc_update_bit_1(struct rc *rc, unsigned short int *p) +{ + rc->range -= rc->bound; + rc->code -= rc->bound; + *p -= *p >> RC_MOVE_BITS; +} + +/* Called 4 times in unlzma loop */ +static int rc_get_bit(struct rc *rc, unsigned short int *p, int *symbol) +{ + if (rc_is_bit_0(rc, p)) { + rc_update_bit_0(rc, p); + *symbol *= 2; + return 0; + } else { + rc_update_bit_1(rc, p); + *symbol = *symbol * 2 + 1; + return 1; + } +} + +/* Called once */ +static inline int rc_direct_bit(struct rc *rc) +{ + rc_normalize(rc); + rc->range >>= 1; + if (rc->code >= rc->range) { + rc->code -= rc->range; + return 1; + } + return 0; +} + +/* Called twice */ +static inline void +rc_bit_tree_decode(struct rc *rc, unsigned short int *p, int num_levels, int *symbol) +{ + int i = num_levels; + + *symbol = 1; + while (i--) + rc_get_bit(rc, p + *symbol, symbol); + *symbol -= 1 << num_levels; +} + + +/* + * Small lzma deflate implementation. + * Copyright (C) 2006 Aurelien Jacobs < aurel@gnuage.org > + * + * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/) + * Copyright (C) 1999-2005 Igor Pavlov + */ + + +struct lzma_header { + unsigned char pos; + unsigned int dict_size; + unsigned long long int dst_size; +} __attribute__ ((packed)) ; + + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LZMA_NUM_POS_BITS_MAX 4 + +#define LZMA_LEN_NUM_LOW_BITS 3 +#define LZMA_LEN_NUM_MID_BITS 3 +#define LZMA_LEN_NUM_HIGH_BITS 8 + +#define LZMA_LEN_CHOICE 0 +#define LZMA_LEN_CHOICE_2 (LZMA_LEN_CHOICE + 1) +#define LZMA_LEN_LOW (LZMA_LEN_CHOICE_2 + 1) +#define LZMA_LEN_MID (LZMA_LEN_LOW \ + + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS))) +#define LZMA_LEN_HIGH (LZMA_LEN_MID \ + +(1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS))) +#define LZMA_NUM_LEN_PROBS (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS)) + +#define LZMA_NUM_STATES 12 +#define LZMA_NUM_LIT_STATES 7 + +#define LZMA_START_POS_MODEL_INDEX 4 +#define LZMA_END_POS_MODEL_INDEX 14 +#define LZMA_NUM_FULL_DISTANCES (1 << (LZMA_END_POS_MODEL_INDEX >> 1)) + +#define LZMA_NUM_POS_SLOT_BITS 6 +#define LZMA_NUM_LEN_TO_POS_STATES 4 + +#define LZMA_NUM_ALIGN_BITS 4 + +#define LZMA_MATCH_MIN_LEN 2 + +#define LZMA_IS_MATCH 0 +#define LZMA_IS_REP (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)) +#define LZMA_IS_REP_G0 (LZMA_IS_REP + LZMA_NUM_STATES) +#define LZMA_IS_REP_G1 (LZMA_IS_REP_G0 + LZMA_NUM_STATES) +#define LZMA_IS_REP_G2 (LZMA_IS_REP_G1 + LZMA_NUM_STATES) +#define LZMA_IS_REP_0_LONG (LZMA_IS_REP_G2 + LZMA_NUM_STATES) +#define LZMA_POS_SLOT (LZMA_IS_REP_0_LONG \ + + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)) +#define LZMA_SPEC_POS (LZMA_POS_SLOT \ + +(LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS)) +#define LZMA_ALIGN (LZMA_SPEC_POS \ + + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX) +#define LZMA_LEN_CODER (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS)) +#define LZMA_REP_LEN_CODER (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS) +#define LZMA_LITERAL (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS) + + +struct writer { + unsigned char *buffer; + unsigned char previous_byte; + int buffer_pos; + int bufsize; + int global_pos; + int(*flush)(void*, unsigned int); + struct lzma_header *header; +}; + +struct cstate { + int state; + unsigned int rep0, rep1, rep2, rep3; +}; + +static inline int get_pos(struct writer *wr) +{ + return + wr->global_pos + wr->buffer_pos; +} + +static inline unsigned char peek_old_byte(struct writer *wr, + unsigned int offs) +{ + if (!wr->flush) { + int pos; + while (offs > wr->header->dict_size) + offs -= wr->header->dict_size; + pos = wr->buffer_pos - offs; + return wr->buffer[pos]; + } else { + unsigned int pos = wr->buffer_pos - offs; + while (pos >= wr->header->dict_size) + pos += wr->header->dict_size; + return wr->buffer[pos]; + } + +} + +static inline int write_byte(struct writer *wr, unsigned char byte) +{ + wr->buffer[wr->buffer_pos++] = wr->previous_byte = byte; + if (wr->flush && wr->buffer_pos == wr->header->dict_size) { + wr->buffer_pos = 0; + wr->global_pos += wr->header->dict_size; + if (wr->flush((char *)wr->buffer, wr->header->dict_size) + != wr->header->dict_size) + return -1; + } + return 0; +} + + +static inline int copy_byte(struct writer *wr, unsigned int offs) +{ + return write_byte(wr, peek_old_byte(wr, offs)); +} + +static inline int copy_bytes(struct writer *wr, + unsigned int rep0, int len) +{ + do { + if (copy_byte(wr, rep0)) + return -1; + len--; + } while (len != 0 && wr->buffer_pos < wr->header->dst_size); + + return len; +} + +static inline int process_bit0(struct writer *wr, struct rc *rc, + struct cstate *cst, unsigned short int *p, + int pos_state, unsigned short int *prob, + int lc, unsigned int literal_pos_mask) { + int mi = 1; + rc_update_bit_0(rc, prob); + prob = (p + LZMA_LITERAL + + (LZMA_LIT_SIZE + * (((get_pos(wr) & literal_pos_mask) << lc) + + (wr->previous_byte >> (8 - lc)))) + ); + + if (cst->state >= LZMA_NUM_LIT_STATES) { + int match_byte = peek_old_byte(wr, cst->rep0); + do { + int bit; + unsigned short int *prob_lit; + + match_byte <<= 1; + bit = match_byte & 0x100; + prob_lit = prob + 0x100 + bit + mi; + if (rc_get_bit(rc, prob_lit, &mi)) { + if (!bit) + break; + } else { + if (bit) + break; + } + } while (mi < 0x100); + } + while (mi < 0x100) { + unsigned short int *prob_lit = prob + mi; + rc_get_bit(rc, prob_lit, &mi); + } + if (cst->state < 4) + cst->state = 0; + else if (cst->state < 10) + cst->state -= 3; + else + cst->state -= 6; + + return write_byte(wr, mi); +} + +static inline int process_bit1(struct writer *wr, struct rc *rc, + struct cstate *cst, unsigned short int *p, + int pos_state, unsigned short int *prob) { + int offset; + unsigned short int *prob_len; + int num_bits; + int len; + + rc_update_bit_1(rc, prob); + prob = p + LZMA_IS_REP + cst->state; + if (rc_is_bit_0(rc, prob)) { + rc_update_bit_0(rc, prob); + cst->rep3 = cst->rep2; + cst->rep2 = cst->rep1; + cst->rep1 = cst->rep0; + cst->state = cst->state < LZMA_NUM_LIT_STATES ? 0 : 3; + prob = p + LZMA_LEN_CODER; + } else { + rc_update_bit_1(rc, prob); + prob = p + LZMA_IS_REP_G0 + cst->state; + if (rc_is_bit_0(rc, prob)) { + rc_update_bit_0(rc, prob); + prob = (p + LZMA_IS_REP_0_LONG + + (cst->state << + LZMA_NUM_POS_BITS_MAX) + + pos_state); + if (rc_is_bit_0(rc, prob)) { + rc_update_bit_0(rc, prob); + + cst->state = cst->state < LZMA_NUM_LIT_STATES ? + 9 : 11; + return copy_byte(wr, cst->rep0); + } else { + rc_update_bit_1(rc, prob); + } + } else { + unsigned int distance; + + rc_update_bit_1(rc, prob); + prob = p + LZMA_IS_REP_G1 + cst->state; + if (rc_is_bit_0(rc, prob)) { + rc_update_bit_0(rc, prob); + distance = cst->rep1; + } else { + rc_update_bit_1(rc, prob); + prob = p + LZMA_IS_REP_G2 + cst->state; + if (rc_is_bit_0(rc, prob)) { + rc_update_bit_0(rc, prob); + distance = cst->rep2; + } else { + rc_update_bit_1(rc, prob); + distance = cst->rep3; + cst->rep3 = cst->rep2; + } + cst->rep2 = cst->rep1; + } + cst->rep1 = cst->rep0; + cst->rep0 = distance; + } + cst->state = cst->state < LZMA_NUM_LIT_STATES ? 8 : 11; + prob = p + LZMA_REP_LEN_CODER; + } + + prob_len = prob + LZMA_LEN_CHOICE; + if (rc_is_bit_0(rc, prob_len)) { + rc_update_bit_0(rc, prob_len); + prob_len = (prob + LZMA_LEN_LOW + + (pos_state << + LZMA_LEN_NUM_LOW_BITS)); + offset = 0; + num_bits = LZMA_LEN_NUM_LOW_BITS; + } else { + rc_update_bit_1(rc, prob_len); + prob_len = prob + LZMA_LEN_CHOICE_2; + if (rc_is_bit_0(rc, prob_len)) { + rc_update_bit_0(rc, prob_len); + prob_len = (prob + LZMA_LEN_MID + + (pos_state << + LZMA_LEN_NUM_MID_BITS)); + offset = 1 << LZMA_LEN_NUM_LOW_BITS; + num_bits = LZMA_LEN_NUM_MID_BITS; + } else { + rc_update_bit_1(rc, prob_len); + prob_len = prob + LZMA_LEN_HIGH; + offset = ((1 << LZMA_LEN_NUM_LOW_BITS) + + (1 << LZMA_LEN_NUM_MID_BITS)); + num_bits = LZMA_LEN_NUM_HIGH_BITS; + } + } + + rc_bit_tree_decode(rc, prob_len, num_bits, &len); + len += offset; + + if (cst->state < 4) { + int pos_slot; + + cst->state += LZMA_NUM_LIT_STATES; + prob = + p + LZMA_POS_SLOT + + ((len < + LZMA_NUM_LEN_TO_POS_STATES ? len : + LZMA_NUM_LEN_TO_POS_STATES - 1) + << LZMA_NUM_POS_SLOT_BITS); + rc_bit_tree_decode(rc, prob, + LZMA_NUM_POS_SLOT_BITS, + &pos_slot); + if (pos_slot >= LZMA_START_POS_MODEL_INDEX) { + int i, mi; + num_bits = (pos_slot >> 1) - 1; + cst->rep0 = 2 | (pos_slot & 1); + if (pos_slot < LZMA_END_POS_MODEL_INDEX) { + cst->rep0 <<= num_bits; + prob = p + LZMA_SPEC_POS + + cst->rep0 - pos_slot - 1; + } else { + num_bits -= LZMA_NUM_ALIGN_BITS; + while (num_bits--) + cst->rep0 = (cst->rep0 << 1) | + rc_direct_bit(rc); + prob = p + LZMA_ALIGN; + cst->rep0 <<= LZMA_NUM_ALIGN_BITS; + num_bits = LZMA_NUM_ALIGN_BITS; + } + i = 1; + mi = 1; + while (num_bits--) { + if (rc_get_bit(rc, prob + mi, &mi)) + cst->rep0 |= i; + i <<= 1; + } + } else + cst->rep0 = pos_slot; + if (++(cst->rep0) == 0) + return 0; + if (cst->rep0 > wr->header->dict_size + || cst->rep0 > get_pos(wr)) + return -1; + } + + len += LZMA_MATCH_MIN_LEN; + + return copy_bytes(wr, cst->rep0, len); +} + + + +int unlzma(unsigned char *buf, int in_len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *output, + int *posp, + void(*error)(char *x) + ) +{ + struct lzma_header header; + int lc, pb, lp; + unsigned int pos_state_mask; + unsigned int literal_pos_mask; + unsigned short int *p; + int num_probs; + struct rc rc; + int i, mi; + struct writer wr; + struct cstate cst; + unsigned char *inbuf; + int ret = -1; + + rc.error = error; + + if (buf) + inbuf = buf; + else + inbuf = malloc(LZMA_IOBUF_SIZE); + if (!inbuf) { + error("Could not allocate input bufer"); + goto exit_0; + } + + cst.state = 0; + cst.rep0 = cst.rep1 = cst.rep2 = cst.rep3 = 1; + + wr.header = &header; + wr.flush = flush; + wr.global_pos = 0; + wr.previous_byte = 0; + wr.buffer_pos = 0; + + rc_init(&rc, fill, inbuf, in_len); + + for (i = 0; i < sizeof(header); i++) { + if (rc.ptr >= rc.buffer_end) + rc_read(&rc); + ((unsigned char *)&header)[i] = *rc.ptr++; + } + + if (header.pos >= (9 * 5 * 5)) { + error("bad header"); + goto exit_1; + } + + mi = 0; + lc = header.pos; + while (lc >= 9) { + mi++; + lc -= 9; + } + pb = 0; + lp = mi; + while (lp >= 5) { + pb++; + lp -= 5; + } + pos_state_mask = (1 << pb) - 1; + literal_pos_mask = (1 << lp) - 1; + + ENDIAN_CONVERT(header.dict_size); + ENDIAN_CONVERT(header.dst_size); + + if (header.dict_size == 0) + header.dict_size = 1; + + if (output) + wr.buffer = output; + else { + wr.bufsize = MIN(header.dst_size, header.dict_size); + wr.buffer = malloc(wr.bufsize); + } + if (wr.buffer == NULL) + goto exit_1; + + num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)); + p = (unsigned short int *) malloc(num_probs * sizeof(*p)); + if (p == 0) + goto exit_2; + num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp)); + for (i = 0; i < num_probs; i++) + p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1; + + rc_init_code(&rc); + + while (get_pos(&wr) < header.dst_size) { + int pos_state = get_pos(&wr) & pos_state_mask; + unsigned short int *prob = p + LZMA_IS_MATCH + + (cst.state << LZMA_NUM_POS_BITS_MAX) + pos_state; + if (rc_is_bit_0(&rc, prob)) { + if (process_bit0(&wr, &rc, &cst, p, pos_state, prob, + lc, literal_pos_mask)) { + error("LZMA data is corrupt"); + goto exit_3; + } + } else { + if (process_bit1(&wr, &rc, &cst, p, pos_state, prob)) { + error("LZMA data is corrupt"); + goto exit_3; + } + if (cst.rep0 == 0) + break; + } + if (rc.buffer_size <= 0) + goto exit_3; + } + + if (posp) + *posp = rc.ptr-rc.buffer; + if (!wr.flush || wr.flush(wr.buffer, wr.buffer_pos) == wr.buffer_pos) + ret = 0; +exit_3: + free(p); +exit_2: + if (!output) + free(wr.buffer); +exit_1: + if (!buf) + free(inbuf); +exit_0: + return ret; +} + +int unlzma_simple(unsigned char *buf, int in_len, + unsigned char *output, + void(*error)(char *x)) +{ + return unlzma(buf, in_len, NULL, NULL, output, NULL, error); +}