diff --git a/include/lwext4/init.h b/include/lwext4/init.h new file mode 100644 index 0000000..f1169ac --- /dev/null +++ b/include/lwext4/init.h @@ -0,0 +1,36 @@ +/* + * \brief Initialize functions + * \author Josef Soentgen + * \date 2017-08-01 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__LWEXT4_INIT_H_ +#define _INCLUDE__LWEXT4_INIT_H_ + +/* Genode includes */ +#include + +namespace Genode { + struct Env; + struct Allocator; +} + +struct ext4_blockdev; + +namespace Lwext4 { + + struct Block_init_failed : Genode::Exception { }; + struct Malloc_init_failed : Genode::Exception { }; + + void malloc_init(Genode::Env &, Genode::Allocator &heap); + struct ext4_blockdev *block_init(Genode::Env &, Genode::Allocator &heap); +} + +#endif /* _INCLUDE__LWEXT4_INIT_H_ */ diff --git a/lib/import/import-lwext4.mk b/lib/import/import-lwext4.mk new file mode 100644 index 0000000..8af1898 --- /dev/null +++ b/lib/import/import-lwext4.mk @@ -0,0 +1,2 @@ +INC_DIR += $(call select_from_ports,lwext4)/include +INC_DIR += $(REP_DIR)/src/lib/lwext4/include diff --git a/lib/mk/lwext4.mk b/lib/mk/lwext4.mk new file mode 100644 index 0000000..bc74fa9 --- /dev/null +++ b/lib/mk/lwext4.mk @@ -0,0 +1,30 @@ +LWEXT4_PORT_DIR := $(call select_from_ports,lwext4) +LWEXT4_DIR := $(LWEXT4_PORT_DIR)/src/lib/lwext4 + +SRC_C := $(notdir $(wildcard $(LWEXT4_DIR)/src/*.c)) +SRC_C += $(notdir $(wildcard $(LWEXT4_DIR)/blockdev/*.c)) + +# from musl +SRC_C += qsort.c + +SRC_CC := block libc.cc + +INC_DIR += $(LWEXT4_PORT_DIR)/include +INC_DIR += $(LWEXT4_DIR)/blockdev +INC_DIR += $(REP_DIR)/src/lib/lwext4/include + +CC_OPT += -DCONFIG_USE_DEFAULT_CFG=1 +CC_OPT += -DCONFIG_HAVE_OWN_ERRNO=1 +CC_OPT += -DCONFIG_HAVE_OWN_ASSERT=1 +CC_OPT += -DCONFIG_BLOCK_DEV_CACHE_SIZE=256 + +LIBS += base + +#SHARED_LIB = yes + +vpath %.c $(LWEXT4_DIR)/src +vpath %.c $(LWEXT4_DIR)/blockdev +vpath qsort.c $(REP_DIR)/src/lib/lwext4/ +vpath %.cc $(REP_DIR)/src/lib/lwext4/ + +CC_CXX_WARN_STRICT = diff --git a/ports/lwext4.hash b/ports/lwext4.hash new file mode 100644 index 0000000..a65a9e2 --- /dev/null +++ b/ports/lwext4.hash @@ -0,0 +1 @@ +b9a1b053ee2b21e441b93196819fb4a4be79d064 diff --git a/ports/lwext4.port b/ports/lwext4.port new file mode 100644 index 0000000..2d83ac0 --- /dev/null +++ b/ports/lwext4.port @@ -0,0 +1,10 @@ +LICENSE := GPL2 +VERSION := git +DOWNLOADS := lwext4.git + +URL(lwext4) := https://github.com/gkostka/lwext4.git +REV(lwext4) := c5f8d135cf3555404f1c4df5617f94f4fc2bac87 +DIR(lwext4) := src/lib/lwext4 + +DIRS := include +DIR_CONTENT(include) := src/lib/lwext4/include/* diff --git a/src/lib/lwext4/block.cc b/src/lib/lwext4/block.cc new file mode 100644 index 0000000..a4af16e --- /dev/null +++ b/src/lib/lwext4/block.cc @@ -0,0 +1,177 @@ +/* + * \brief Block device backend for lwext4 + * \author Josef Soentgen + * \date 2017-08-01 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include + +// #include + +/* library includes */ +#include + +/* compiler includes */ +#include + +/* local libc includes */ +#include +#include +#include +#include +#include +#include + +/* lwext4 includes */ +#include +#include + + +struct Blockdev +{ + struct ext4_blockdev ext4_blockdev; + struct ext4_blockdev_iface ext4_blockdev_iface; + unsigned char ext4_block_buffer[4096]; + + Genode::Env &_env; + Genode::Allocator &_alloc; + Genode::Allocator_avl _tx_alloc { &_alloc }; + + Block::Connection _block { _env, &_tx_alloc, 512*1024 }; + Block::sector_t _block_count { 0 }; + Genode::size_t _block_size { 512 }; + Block::Session::Operations _block_ops { }; + + Blockdev(Genode::Env &env, Genode::Allocator &alloc) + : _env(env), _alloc(alloc) + { + _block.info(&_block_count, &_block_size, &_block_ops); + + if (!_block_ops.supported(Block::Packet_descriptor::READ)) { + throw -1; + } + } + + bool writeable() + { + return _block_ops.supported(Block::Packet_descriptor::WRITE); + } + + Block::Connection& block() { return _block; } + Block::sector_t block_count() const { return _block_count; } + Genode::size_t block_size() const { return _block_size; } +}; + + +static int blockdev_open(struct ext4_blockdev *bdev) { return EOK; } +static int blockdev_close(struct ext4_blockdev *bdev) { return EOK; } + + +static int blockdev_bread(struct ext4_blockdev *bdev, + void *dest, + uint64_t lba, + uint32_t count) +{ + Blockdev &bd = *reinterpret_cast(bdev); + Block::Connection &b = bd.block(); + + Genode::size_t const size = bd.block_size() * count; + + Block::Packet_descriptor p(b.tx()->alloc_packet(size), + Block::Packet_descriptor::READ, + lba, count); + b.tx()->submit_packet(p); + p = b.tx()->get_acked_packet(); + + int result = EIO; + if (p.succeeded() && p.size() == size) { + char const * const content = b.tx()->packet_content(p); + Genode::memcpy(dest, content, size); + result = EOK; + } else { + Genode::error("could not read lba: ", lba, " count: ", count); + } + + b.tx()->release_packet(p); + return result; +} + + +static int blockdev_bwrite(struct ext4_blockdev *bdev, + void const *src, + uint64_t lba, + uint32_t count) +{ + Blockdev &bd = *reinterpret_cast(bdev); + if (!bd.writeable()) { return EIO; } + + Block::Connection &b = bd.block(); + Genode::size_t const size = bd.block_size() * count; + + Block::Packet_descriptor p(b.tx()->alloc_packet(size), + Block::Packet_descriptor::WRITE, + lba, count); + + char * const content = b.tx()->packet_content(p); + Genode::memcpy(content, src, size); + + b.tx()->submit_packet(p); + p = b.tx()->get_acked_packet(); + + int result = EIO; + if (p.succeeded() && p.size() == size) { + result = EOK; + } else { + Genode::error("could not write lba: ", lba, " count: ", count); + } + + b.tx()->release_packet(p); + + return result; +} + +/* + * Genode enviroment + */ +static Genode::Env *_global_env; +static Genode::Allocator *_global_alloc; +static Genode::Constructible _blockdev; + + +struct ext4_blockdev *Lwext4::block_init(Genode::Env &env, Genode::Allocator &alloc) +{ + _global_env = &env; + _global_alloc = &alloc; + + try { _blockdev.construct(env, alloc); } + catch (...) { throw Block_init_failed(); } + + _blockdev->ext4_blockdev.bdif = &_blockdev->ext4_blockdev_iface; + _blockdev->ext4_blockdev.part_offset = 0; + _blockdev->ext4_blockdev.part_size = _blockdev->block_count() + * _blockdev->block_size(); + + _blockdev->ext4_blockdev_iface.ph_bbuf = _blockdev->ext4_block_buffer; + _blockdev->ext4_blockdev_iface.ph_bcnt = _blockdev->block_count(); + _blockdev->ext4_blockdev_iface.ph_bsize = _blockdev->block_size(); + + _blockdev->ext4_blockdev_iface.bread = blockdev_bread; + _blockdev->ext4_blockdev_iface.bwrite = blockdev_bwrite; + _blockdev->ext4_blockdev_iface.close = blockdev_close; + _blockdev->ext4_blockdev_iface.open = blockdev_open; + + return reinterpret_cast(&*_blockdev); +} diff --git a/src/lib/lwext4/include/inttypes.h b/src/lib/lwext4/include/inttypes.h new file mode 100644 index 0000000..29fb14d --- /dev/null +++ b/src/lib/lwext4/include/inttypes.h @@ -0,0 +1,26 @@ +/* + * \brief Libc functions for lwext4 + * \author Josef Soentgen + * \date 2017-08-01 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INTTYPES_H +#define _INTTYPES_H + +#define PRIu16 "u" + +#define PRId32 "d" +#define PRIu32 "u" +#define PRIx32 "x" + +#define PRId64 "lld" +#define PRIu64 "llu" + +#endif /* _INTTYPES_H */ diff --git a/src/lib/lwext4/include/stddef.h b/src/lib/lwext4/include/stddef.h new file mode 100644 index 0000000..1b7ed57 --- /dev/null +++ b/src/lib/lwext4/include/stddef.h @@ -0,0 +1,19 @@ +/* + * \brief Libc functions for lwext4 + * \author Josef Soentgen + * \date 2017-08-01 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _STDDEF_H +#define _STDDEF_H + +typedef long ptrdiff_t; + +#endif /* _STDDEF_H */ diff --git a/src/lib/lwext4/include/stdint.h b/src/lib/lwext4/include/stdint.h new file mode 100644 index 0000000..04f3da0 --- /dev/null +++ b/src/lib/lwext4/include/stdint.h @@ -0,0 +1,29 @@ +/* + * \brief Libc functions for lwext4 + * \author Josef Soentgen + * \date 2017-08-01 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _STDINT_H +#define _STDINT_H + +#include + +typedef unsigned long size_t; + +typedef genode_uint8_t uint8_t; +typedef genode_uint16_t uint16_t; +typedef genode_uint32_t uint32_t; +typedef genode_uint64_t uint64_t; + +typedef genode_int32_t int32_t; +typedef genode_int64_t int64_t; + +#endif /* _STDINT_H */ diff --git a/src/lib/lwext4/include/stdio.h b/src/lib/lwext4/include/stdio.h new file mode 100644 index 0000000..fd0b5f3 --- /dev/null +++ b/src/lib/lwext4/include/stdio.h @@ -0,0 +1,42 @@ +/* + * \brief Libc functions for lwext4 + * \author Josef Soentgen + * \date 2017-08-01 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _STDIO_H +#define _STDIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NULL +# if __cplusplus +# define NULL 0L +# else +# define NULL ((void*)0) +# endif +#endif + +typedef int FILE; + +#define stdout ((FILE*)0) +#define stderr ((FILE*)2) + +int fflush(FILE *); +int printf(char const *, ...); +int puts(char const*); + +#ifdef __cplusplus +} +#endif + +#endif /* _STDIO_H */ diff --git a/src/lib/lwext4/include/stdlib.h b/src/lib/lwext4/include/stdlib.h new file mode 100644 index 0000000..b7e384b --- /dev/null +++ b/src/lib/lwext4/include/stdlib.h @@ -0,0 +1,32 @@ +/* + * \brief Libc functions for lwext4 + * \author Josef Soentgen + * \date 2017-08-01 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _STDLIB_H +#define _STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +void *malloc(size_t); +void *calloc(size_t, size_t); +void *realloc(void *, size_t); +void free(void *); + +void qsort(void *, size_t, size_t, int (*)(void const*, void const *)); + +#ifdef __cplusplus +} +#endif + +#endif /* _STDLIB_H */ diff --git a/src/lib/lwext4/include/string.h b/src/lib/lwext4/include/string.h new file mode 100644 index 0000000..e120eee --- /dev/null +++ b/src/lib/lwext4/include/string.h @@ -0,0 +1,37 @@ +/* + * \brief Libc functions for lwext4 + * \author Josef Soentgen + * \date 2017-08-01 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + + +#ifndef _STRING_H +#define _STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +int memcmp(void const *, void const *, size_t); +void *memcpy(void *, void const *, size_t); +void *memmove(void *, void const *, size_t); +void *memset(void *, int, size_t); + +int strcmp(char const *, char const *); +int strncmp(char const *, char const *, size_t); +char *strcpy(char *, char const *); +char *strncpy(char *, char const *, size_t); +size_t strlen(char const *); + +#ifdef __cplusplus +} +#endif + +#endif /* _STRING_H */ diff --git a/src/lib/lwext4/libc.cc b/src/lib/lwext4/libc.cc new file mode 100644 index 0000000..c92647b --- /dev/null +++ b/src/lib/lwext4/libc.cc @@ -0,0 +1,167 @@ +/* + * \brief Libc functions for lwext4 + * \author Josef Soentgen + * \date 2017-08-01 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include + +/* library includes */ +#include + +/* compiler includes */ +#include + +/* local libc includes */ +#include +#include +#include +#include +#include +#include + + +/* + * Genode enviroment + */ +static Genode::Env *_global_env; +static Genode::Allocator *_global_alloc; + +void Lwext4::malloc_init(Genode::Env &env, Genode::Allocator &alloc) +{ + _global_env = &env; + _global_alloc = &alloc; +} + + +/************* + ** stdio.h ** + *************/ + +int fflush(FILE *) +{ + return 0; +} + + +int printf(char const *fmt, ...) +{ + va_list list; + va_start(list, fmt); + Genode::vprintf(fmt, list); + va_end(list); + + return 0; +} + + +int puts(const char *s) +{ + Genode::printf(s); + return 0; +} + + +/************** + ** stdlib.h ** + **************/ + +void *malloc(size_t sz) +{ + void *addr = _global_alloc->alloc(sz); + return addr; +} + + +void *calloc(size_t n, size_t sz) +{ + /* XXX overflow check */ + size_t size = n * sz; + void *p = malloc(size); + if (p) { Genode::memset(p, 0, size); } + return p; +} + + +void *realloc(void *p, size_t n) +{ + Genode::error(__func__, " not implemented"); + return NULL; +} + + +void free(void *p) +{ + if (p == NULL) { return; } + + _global_alloc->free(p, 0); +} + + +/************** + ** string.h ** + **************/ + +int memcmp(void const *p1, void const *p2, size_t n) +{ + return Genode::memcmp(p1, p2, n); +} + + +void *memcpy(void *d, void const *s, size_t n) +{ + return Genode::memcpy(d, s, n); +} + + +void *memmove(void *d, void const *s, size_t n) +{ + return Genode::memmove(d, s, n); +} + + +void *memset(void *p, int c, size_t n) +{ + return Genode::memset(p, c, n); +} + + +int strcmp(char const *s1, char const *s2) +{ + return Genode::strcmp(s1, s2, ~0UL); +} + + +int strncmp(char const *s1, char const *s2, size_t n) +{ + return Genode::strcmp(s1, s2, n); +} + + +char *strcpy(char *d, char const *s) +{ + return Genode::strncpy(d,s, ~0UL); +} + + +char *strncpy(char *d, char const *s, size_t n) +{ + return Genode::strncpy(d, s, n); +} + + +size_t strlen(char const *s) +{ + return Genode::strlen(s); +} diff --git a/src/lib/lwext4/qsort.c b/src/lib/lwext4/qsort.c new file mode 100644 index 0000000..7b26147 --- /dev/null +++ b/src/lib/lwext4/qsort.c @@ -0,0 +1,257 @@ +/* + * This file was copied from musl rev 8d7a3f40c8de414122eb8eb2131291782ee8ed15 + * and adapted for use in Genode's lwext4 port. + */ + +/* Copyright (C) 2011 by Valentin Ochs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Minor changes by Rich Felker for integration in musl, 2011-04-27. */ + +#include +#include +#include + +/* + * #include "atomic.h" + * + * Instead of pulling this musl internal header in, for use in lwext4, + * copy the fallback functions verbatim. + */ +static inline int a_ctz_64(uint64_t x) +{ + static const char debruijn64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + static const char debruijn32[32] = { + 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, + 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 + }; + if (sizeof(long) < 8) { + uint32_t y = x; + if (!y) { + y = x>>32; + return 32 + debruijn32[(y&-y)*0x076be629 >> 27]; + } + return debruijn32[(y&-y)*0x076be629 >> 27]; + } + return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58]; +} + +static inline int a_ctz_l(unsigned long x) +{ + static const char debruijn32[32] = { + 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, + 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 + }; + if (sizeof(long) == 8) return a_ctz_64(x); + return debruijn32[(x&-x)*0x076be629 >> 27]; +} +#define ntz(x) a_ctz_l((x)) + +typedef int (*cmpfun)(const void *, const void *); + +static inline int pntz(size_t p[2]) { + int r = ntz(p[0] - 1); + if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) { + return r; + } + return 0; +} + +static void cycle(size_t width, unsigned char* ar[], int n) +{ + unsigned char tmp[256]; + size_t l; + int i; + + if(n < 2) { + return; + } + + ar[n] = tmp; + while(width) { + l = sizeof(tmp) < width ? sizeof(tmp) : width; + memcpy(ar[n], ar[0], l); + for(i = 0; i < n; i++) { + memcpy(ar[i], ar[i + 1], l); + ar[i] += l; + } + width -= l; + } +} + +/* shl() and shr() need n > 0 */ +static inline void shl(size_t p[2], int n) +{ + if(n >= 8 * sizeof(size_t)) { + n -= 8 * sizeof(size_t); + p[1] = p[0]; + p[0] = 0; + } + p[1] <<= n; + p[1] |= p[0] >> (sizeof(size_t) * 8 - n); + p[0] <<= n; +} + +static inline void shr(size_t p[2], int n) +{ + if(n >= 8 * sizeof(size_t)) { + n -= 8 * sizeof(size_t); + p[0] = p[1]; + p[1] = 0; + } + p[0] >>= n; + p[0] |= p[1] << (sizeof(size_t) * 8 - n); + p[1] >>= n; +} + +static void sift(unsigned char *head, size_t width, cmpfun cmp, int pshift, size_t lp[]) +{ + unsigned char *rt, *lf; + unsigned char *ar[14 * sizeof(size_t) + 1]; + int i = 1; + + ar[0] = head; + while(pshift > 1) { + rt = head - width; + lf = head - width - lp[pshift - 2]; + + if((*cmp)(ar[0], lf) >= 0 && (*cmp)(ar[0], rt) >= 0) { + break; + } + if((*cmp)(lf, rt) >= 0) { + ar[i++] = lf; + head = lf; + pshift -= 1; + } else { + ar[i++] = rt; + head = rt; + pshift -= 2; + } + } + cycle(width, ar, i); +} + +static void trinkle(unsigned char *head, size_t width, cmpfun cmp, size_t pp[2], int pshift, int trusty, size_t lp[]) +{ + unsigned char *stepson, + *rt, *lf; + size_t p[2]; + unsigned char *ar[14 * sizeof(size_t) + 1]; + int i = 1; + int trail; + + p[0] = pp[0]; + p[1] = pp[1]; + + ar[0] = head; + while(p[0] != 1 || p[1] != 0) { + stepson = head - lp[pshift]; + if((*cmp)(stepson, ar[0]) <= 0) { + break; + } + if(!trusty && pshift > 1) { + rt = head - width; + lf = head - width - lp[pshift - 2]; + if((*cmp)(rt, stepson) >= 0 || (*cmp)(lf, stepson) >= 0) { + break; + } + } + + ar[i++] = stepson; + head = stepson; + trail = pntz(p); + shr(p, trail); + pshift += trail; + trusty = 0; + } + if(!trusty) { + cycle(width, ar, i); + sift(head, width, cmp, pshift, lp); + } +} + +void qsort(void *base, size_t nel, size_t width, cmpfun cmp) +{ + size_t lp[12*sizeof(size_t)]; + size_t i, size = width * nel; + unsigned char *head, *high; + size_t p[2] = {1, 0}; + int pshift = 1; + int trail; + + if (!size) return; + + head = base; + high = head + size - width; + + /* Precompute Leonardo numbers, scaled by element width */ + for(lp[0]=lp[1]=width, i=2; (lp[i]=lp[i-2]+lp[i-1]+width) < size; i++); + + while(head < high) { + if((p[0] & 3) == 3) { + sift(head, width, cmp, pshift, lp); + shr(p, 2); + pshift += 2; + } else { + if(lp[pshift - 1] >= high - head) { + trinkle(head, width, cmp, p, pshift, 0, lp); + } else { + sift(head, width, cmp, pshift, lp); + } + + if(pshift == 1) { + shl(p, 1); + pshift = 0; + } else { + shl(p, pshift - 1); + pshift = 1; + } + } + + p[0] |= 1; + head += width; + } + + trinkle(head, width, cmp, p, pshift, 0, lp); + + while(pshift != 1 || p[0] != 1 || p[1] != 0) { + if(pshift <= 1) { + trail = pntz(p); + shr(p, trail); + pshift += trail; + } else { + shl(p, 2); + pshift -= 2; + p[0] ^= 7; + shr(p, 1); + trinkle(head - lp[pshift] - width, width, cmp, p, pshift + 1, 1, lp); + shl(p, 1); + p[0] |= 1; + trinkle(head - width, width, cmp, p, pshift, 1, lp); + } + head -= width; + } +}