void *quantizate(float *x, size_t *n, const float factor, int *nbbits) { size_t i; int min, max; void *res; int *q; float real_factor = factor; q = malloc(*n * sizeof(int)); min = max = 0; for (i = 0; i < *n; i++) { if ((i < *n / 2 && is_pow2(i)) || (i > *n / 2 && is_pow2(i - *n / 2))) real_factor *= 1.0f; if (i == *n / 2) real_factor = factor; /*q[i] = sign(x[i]) * sqrtf(abs(x[i]) / real_factor);*/ q[i] = sign(x[i]) * powf(abs(x[i]) / real_factor, 3.0f / 4.0f); /*q[i] = sign(x[i]) * floorf(abs(x[i] / factor));*/ if (q[i] > max) max = q[i]; else if (q[i] < min) min = q[i]; } min = abs(min); max = max > min ? max : min; min = nb_bits(max); res = encode(q, *n, min, n); *nbbits = min; free(q); return res; }
static void texture_set_data(texture_t *tex, const uint8_t *data, int w, int h, int bpp) { uint8_t *buff0 = NULL; int data_type = GL_UNSIGNED_BYTE; if (!is_pow2(w) || !is_pow2(h)) { buff0 = calloc(bpp, tex->tex_w * tex->tex_h); blit(data, w, h, bpp, buff0, tex->tex_w, tex->tex_h); data = buff0; } GL(glGenTextures(1, &tex->tex)); GL(glActiveTexture(GL_TEXTURE0)); GL(glBindTexture(GL_TEXTURE_2D, tex->tex)); GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (tex->flags & TF_MIPMAP)? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)); GL(glTexImage2D(GL_TEXTURE_2D, 0, tex->format, tex->tex_w, tex->tex_h, 0, tex->format, data_type, data)); free(buff0); if (tex->flags & TF_MIPMAP) GL(glGenerateMipmap(GL_TEXTURE_2D)); }
float *dequantizate(uint8_t *x, size_t *n, const float factor, int nbbits) { size_t i; size_t nb_elmts = (((*n - 1) * 8) / nbbits); float *res = malloc(nb_elmts * sizeof(float)); int nb; int offset; float real_factor = factor; offset = 0; for (i = 0; i < nb_elmts; i++) { if ((i < nb_elmts / 2 && is_pow2(i)) || (i > nb_elmts / 2 && is_pow2(i - nb_elmts / 2))) real_factor *= 1.0f; if (i == nb_elmts / 2) real_factor = factor; nb = next_nb(&x, nbbits, &offset); if (nb == 0) res[i] = 0.0f; else /*res[i] = sign(nb) * powf(abs(nb), 2) * real_factor;*/ res[i] = sign(nb) * powf(abs(nb), 4.0f / 3.0f) * real_factor; /*res[i] = sign(nb) * (abs(nb) + 0.5f) * factor;*/ } *n = nb_elmts; return res; }
texture_t gs_create_texture(uint32_t width, uint32_t height, enum gs_color_format color_format, uint32_t levels, const void **data, uint32_t flags) { graphics_t graphics = thread_graphics; bool pow2tex = is_pow2(width) && is_pow2(height); bool uses_mipmaps = (flags & GS_BUILDMIPMAPS || levels != 1); if (uses_mipmaps && !pow2tex) { blog(LOG_WARNING, "Cannot use mipmaps with a " "non-power-of-two texture. Disabling " "mipmaps for this texture."); uses_mipmaps = false; flags &= ~GS_BUILDMIPMAPS; levels = 1; } if (uses_mipmaps && flags & GS_RENDERTARGET) { blog(LOG_WARNING, "Cannot use mipmaps with render targets. " "Disabling mipmaps for this texture."); flags &= ~GS_BUILDMIPMAPS; levels = 1; } return graphics->exports.device_create_texture(graphics->device, width, height, color_format, levels, data, flags); }
static int larger_pow2(int n) { if (is_pow2(n)) return n; while(!is_pow2(n)) n= n&(n-1); return n*2; }
void test_math(void) { test_floor_log2(); test_ceil_log2(); test_exact_log2(); test_hyperfloor(); assert(is_pow2(1)); assert(is_pow2(4096)); assert(!is_pow2(7)); assert(!is_pow2(9999)); }
static int smaller_pow2(int n) { while (!is_pow2(n)) n= n&(n-1); return n; }
static void split_width(int x, int n, int *splitx, int *nx) { int a, newnx, waste; /* if already power of two just use it */ if(is_pow2(x)) { splitx[0]= x; (*nx)++; return; } if(n == 1) { /* last part, we have to go larger */ splitx[0]= larger_pow2(x); (*nx)++; } else { /* two or more parts to go, use smaller part */ splitx[0]= smaller_pow2(x); newnx= ++(*nx); split_width(x-splitx[0], n-1, splitx+1, &newnx); for(waste=0, a=0; a<n; a++) waste += splitx[a]; /* if we waste more space or use the same amount, * revert deeper splits and just use larger */ if(waste >= larger_pow2(x)) { splitx[0]= larger_pow2(x); memset(splitx+1, 0, sizeof(int)*(n-1)); } else *nx= newnx; } }
int BL_Texture::GetPow2(int n) { if(!is_pow2(n)) n = smaller_pow2(n); return n; }
static void resize(struct hmap *hmap, size_t new_mask, const char *where) { struct hmap tmp; size_t i; ovs_assert(is_pow2(new_mask + 1)); hmap_init(&tmp); if (new_mask) { tmp.buckets = xmalloc(sizeof *tmp.buckets * (new_mask + 1)); tmp.mask = new_mask; for (i = 0; i <= tmp.mask; i++) { tmp.buckets[i] = NULL; } } for (i = 0; i <= hmap->mask; i++) { struct hmap_node *node, *next; int count = 0; for (node = hmap->buckets[i]; node; node = next) { next = node->next; hmap_insert_fast(&tmp, node, node->hash); count++; } if (count > 5) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10); COVERAGE_INC(hmap_pathological); VLOG_DBG_RL(&rl, "%s: %d nodes in bucket (%"PRIuSIZE" nodes, %"PRIuSIZE" buckets)", where, count, hmap->n, hmap->mask + 1); } } hmap_swap(hmap, &tmp); hmap_destroy(&tmp); }
void vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_CHANNEL_T *local, VCHIQ_CHANNEL_T *remote) { VCOS_THREAD_ATTR_T attrs; char threadname[8]; static int id = 0; vcos_assert(is_pow2(VCHIQ_CHANNEL_SIZE)); vcos_assert(is_pow2(VCHIQ_NUM_CURRENT_BULKS)); vcos_assert(is_pow2(VCHIQ_NUM_SERVICE_BULKS)); vcos_assert(sizeof(VCHIQ_HEADER_T) == 8); /* we require this for consistency between endpoints */ memset(state, 0, sizeof(VCHIQ_STATE_T)); state->id = id++; /* initialize events and mutex */ vcos_event_create(&state->connect, "vchiq"); vcos_mutex_create(&state->mutex, "vchiq"); /* initialize channel pointers */ state->local = local; state->remote = remote; vchiq_init_channel(local); /* bring up slot handler thread */ vcos_thread_attr_init(&attrs); vcos_thread_attr_setstacksize(&attrs, VCHIQ_SLOT_HANDLER_STACK); vcos_thread_attr_setpriority(&attrs, 5); /* FIXME: should not be hardcoded */ vcos_thread_attr_settimeslice(&attrs, 20); /* FIXME: should not be hardcoded */ strcpy(threadname, "VCHIQ-0"); threadname[6] += state->id % 10; vcos_thread_create(&state->slot_handler_thread, threadname, &attrs, slot_handler_func, state); /* Indicate readiness to the other side */ local->initialised = 1; }
RADCFUNC HRAD3DIMAGE Open_RAD_3D_image( HRAD3D rad_3d, u32 width, u32 height, s32 alpha_pixels, u32 maximum_texture_size ) { if ( ( is_pow2( width ) && is_pow2( height ) ) || ( rad_3d->nonpow2_textures_supported ) ) { return Open_RAD_3D_image_lin( rad_3d, width, height, alpha_pixels, maximum_texture_size ); } else { return Open_RAD_3D_image_pow2( rad_3d, width, height, alpha_pixels, maximum_texture_size ); } }
/* Initializes 'q' as an empty byteq that uses the 'size' bytes of 'buffer' to * store data. 'size' must be a power of 2. * * The caller must ensure that 'buffer' remains available to the byteq as long * as 'q' is in use. */ void byteq_init(struct byteq *q, uint8_t *buffer, size_t size) { ovs_assert(is_pow2(size)); q->buffer = buffer; q->size = size; q->head = q->tail = 0; }
/** Initialize a fixed heap allocator. * @param heap Heap to initialize. * @param mem Memory area to use. * @param size Size of memory area. */ void fixed_heap_init(fixed_heap_t *heap, void *mem, size_t size) { assert(size >= (sizeof(fixed_heap_tag_t) + 8)); assert(is_pow2(size)); /* Create an initial free segment covering the entire chunk. */ heap->tags = mem; heap->tags->next = NULL; heap->tags->data = size; }
UniqueRange Allocate(size_t size, size_t alignment) { ENSURE(is_pow2(alignment)); if(alignment <= (size_t)idxDeleterBits) alignment = idxDeleterBits+1; const size_t alignedSize = round_up(size, alignment); const UniqueRange::pointer p = rtl_AllocateAligned(alignedSize, alignment); return RVALUE(UniqueRange(p, size, idxDeleterAligned)); }
void BL_Texture::InitGLTex(unsigned int *pix,int x,int y,bool mipmap) { if (!is_pow2(x) || !is_pow2(y) ) { InitNonPow2Tex(pix, x,y,mipmap); return; } glBindTexture(GL_TEXTURE_2D, mTexture ); if( mipmap ) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, x, y, GL_RGBA, GL_UNSIGNED_BYTE, pix ); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix ); } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); }
UniqueRange AllocateAligned(size_t size, size_t alignment) { ENSURE(is_pow2(alignment)); alignment = std::max(alignment, allocationAlignment); const size_t alignedSize = round_up(size, alignment); const UniqueRange::pointer p = rtl_AllocateAligned(alignedSize, alignment); static volatile IdxDeleter idxDeleterAligned; if(idxDeleterAligned == 0) // (optional optimization) RegisterUniqueRangeDeleter(FreeAligned, &idxDeleterAligned); return RVALUE(UniqueRange(p, size, idxDeleterAligned)); }
int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size) { WARN_ON(!is_pow2(size)); queue->size = size; queue->read = 0; queue->write = 0; sema_init(&queue->pop, 0); sema_init(&queue->push, 0); queue->storage = kzalloc(size * sizeof(VCHIQ_HEADER_T *), GFP_KERNEL); if (queue->storage == NULL) { vchiu_queue_delete(queue); return 0; } return 1; }
int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size) { vcos_assert(is_pow2(size)); queue->size = size; queue->read = 0; queue->write = 0; vcos_event_create(&queue->pop, "vchiu"); vcos_event_create(&queue->push, "vchiu"); queue->storage = vcos_malloc(size * sizeof(VCHIQ_HEADER_T *), VCOS_FUNCTION); if (queue->storage == NULL) { vchiu_queue_delete(queue); return 0; } return 1; }
int vchiu_queue_init(struct vchiu_queue *queue, int size) { WARN_ON(!is_pow2(size)); queue->size = size; queue->read = 0; queue->write = 0; queue->initialized = 1; init_completion(&queue->pop); init_completion(&queue->push); queue->storage = kcalloc(size, sizeof(struct vchiq_header *), GFP_KERNEL); if (!queue->storage) { vchiu_queue_delete(queue); return 0; } return 1; }
/** * Build a QHT RESET message. * * @param slots amount of slots in the table (power of 2) * @param inf_val infinity value (1) * * @return a /QHT message with a RESET payload. */ pmsg_t * g2_build_qht_reset(int slots, int inf_val) { g2_tree_t *t; char body[6]; void *p = &body[0]; pmsg_t *mb; g_assert(is_pow2(slots)); g_assert(1 == inf_val); /* Only 1-bit patches in G2 */ p = poke_u8(p, G2_QHT_RESET); p = poke_le32(p, slots); p = poke_u8(p, inf_val); t = g2_tree_alloc(G2_NAME(QHT), body, sizeof body); mb = g2_build_pmsg(t); g2_tree_free_null(&t); return mb; }
/* Reallocates 'hindex''s array of buckets to use bitwise mask 'new_mask'. */ static void hindex_resize(struct hindex *hindex, size_t new_mask) { struct hindex tmp; size_t i; ovs_assert(is_pow2(new_mask + 1)); ovs_assert(new_mask != SIZE_MAX); hindex_init(&tmp); if (new_mask) { tmp.buckets = xmalloc(sizeof *tmp.buckets * (new_mask + 1)); tmp.mask = new_mask; for (i = 0; i <= tmp.mask; i++) { tmp.buckets[i] = NULL; } } for (i = 0; i <= hindex->mask; i++) { struct hindex_node *node, *next; int count; count = 0; for (node = hindex->buckets[i]; node; node = next) { struct hindex_node **head = &tmp.buckets[node->hash & tmp.mask]; next = node->d; node->d = *head; *head = node; count++; } if (count > 5) { COVERAGE_INC(hindex_pathological); } } tmp.n_unique = hindex->n_unique; hindex_swap(hindex, &tmp); hindex_destroy(&tmp); }
void* aligned_malloc(const size_t size, size_t alignment) { // Often, the value of alignment is set to the line size of the L1 data cache as // reported by foundation::System::get_l1_data_cache_line_size(). It may happen // that this function returns 0 if the CPU cache information cannot be retrieved. // For convenience we handle this situation here by using a reasonable alignment // value when this happens. if (alignment == 0) alignment = 16; assert(size > 0); assert(is_pow2(alignment)); // Compute the total number of bytes of memory we need to allocate. const size_t total_size = size + sizeof(void*) + (alignment - 1); // Allocate the memory. void** const unaligned_ptr = reinterpret_cast<void**>(malloc(total_size)); // Handle allocation failures. if (!unaligned_ptr) { log_allocation_failure(total_size); return 0; } // Compute the next aligned address. void** const aligned_ptr = align(unaligned_ptr + 1, alignment); // Store the address of the unaligned memory block. *(aligned_ptr - 1) = unaligned_ptr; log_allocation(aligned_ptr, total_size); return aligned_ptr; }
static int64_t p5ioc2_set_tce_mem(struct io_hub *hub, uint64_t address, uint64_t size) { struct p5ioc2 *ioc = iohub_to_p5ioc2(hub); int64_t rc; printf("P5IOC2: set_tce_mem(0x%016llx size 0x%llx)\n", address, size); /* The address passed must be naturally aligned */ if (address && !is_pow2(size)) return OPAL_PARAMETER; if (address & (size - 1)) return OPAL_PARAMETER; ioc->tce_base = address; ioc->tce_size = size; rc = gx_configure_tce_bar(ioc->host_chip, ioc->gx_bus, address, size); if (rc) return OPAL_INTERNAL_ERROR; return OPAL_SUCCESS; }
TexHandle tex_create(uint width, uint height) { assert(width && height); // Validate size int max_size = 0; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size); if(width > max_size || height > max_size) LOG_ERROR("Can't create texture so large!"); if(!(is_pow2(width) && is_pow2(height))) LOG_ERROR("Texture dimensions must be a power of 2"); // Prep pixel data void* data = MEM_ALLOC(4 * width * height); memset(data, 0, 4 * width * height); uint gl_id = _make_gl_texture(data, width, height); MEM_FREE(data); // Fill texture struct Texture new_tex = { .gl_id = gl_id, .file = NULL, .retain_count = 1, .active = true, .scale = 1.0f, .width = width, .height = height }; darray_append(&textures, &new_tex); return textures.size - 1; } TexHandle tex_load(const char* filename) { return tex_load_filter(filename, NULL); } TexHandle tex_load_filter(const char* filename, TexFilter filter) { assert(filename); Texture* tex = DARRAY_DATA_PTR(textures, Texture); // Look if texture is already loaded for(uint i = 0; i < textures.size; ++i) { if(tex[i].active) { if(tex[i].file && strcmp(tex[i].file, filename) == 0) { tex[i].retain_count++; return i; } } } LOG_INFO("Loading texture (with filtering) from file %s", filename); Texture new_tex; PixelFormat fmt; void* data = image_load(filename, &new_tex.width, &new_tex.height, &fmt); if(filter) (*filter)((Color*)data, new_tex.width, new_tex.height); uint gl_id = _make_gl_texture(data, new_tex.width, new_tex.height); new_tex.gl_id = gl_id; new_tex.file = strclone(filename); new_tex.retain_count = 1; new_tex.active = true; new_tex.scale = 1.0f; darray_append(&textures, &new_tex); return textures.size-1; }
static int smaller_pow2(int num) { while (!is_pow2(num)) num= num&(num-1); return num; }
bool BL_Texture::InitCubeMap(int unit, EnvMap *cubemap) { if (!GLEW_ARB_texture_cube_map) { spit("cubemaps not supported"); mOk = false; return mOk; } else if (!cubemap || cubemap->ima->ok==0) { mOk = false; return mOk; } ImBuf *ibuf= BKE_image_get_ibuf(cubemap->ima, NULL); if (ibuf==0) { cubemap->ima->ok = 0; mOk = false; return mOk; } mNeedsDeleted = 1; mType = GL_TEXTURE_CUBE_MAP_ARB; mTexture = 0; mUnit = unit; ActivateUnit(mUnit); BL_TextureMap::iterator mapLook = g_textureManager.find(cubemap->ima->id.name); if (mapLook != g_textureManager.end()) { if (mapLook->second.gl_texture != 0 && mapLook->second.ref_buffer == cubemap->ima) { mTexture = mapLook->second.gl_texture; glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mTexture); mOk = IsValid(); return mOk; } } glGenTextures(1, (GLuint*)&mTexture); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mTexture); // track created units BL_TextureObject obj; obj.gl_texture = mTexture; obj.ref_buffer = cubemap->ima; g_textureManager.insert(std::pair<char*, BL_TextureObject>((char*)cubemap->ima->id.name, obj)); bool needs_split = false; if (!cubemap->cube[0]) { needs_split = true; spit ("Re-Generating texture buffer"); } if (needs_split) my_envmap_split_ima(cubemap, ibuf); if (!is_pow2(cubemap->cube[0]->x) || !is_pow2(cubemap->cube[0]->y)) { spit("invalid envmap size please render with CubeRes @ power of two"); my_free_envmapdata(cubemap); mOk = false; return mOk; } #define SetCubeMapFace(face, num) \ glTexImage2D(face, 0,GL_RGBA, \ cubemap->cube[num]->x, \ cubemap->cube[num]->y, \ 0, GL_RGBA, GL_UNSIGNED_BYTE, \ cubemap->cube[num]->rect) SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 5); SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 3); SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 0); SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 1); SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 2); SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, 4); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); if(GLEW_VERSION_1_2) glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); if (needs_split) my_free_envmapdata(cubemap); glDisable(GL_TEXTURE_CUBE_MAP_ARB); ActivateUnit(0); mOk = IsValid(); return mOk; }
/* Returns true if 'protocol' is a single OFPUTIL_P_* value, false * otherwise. */ bool ofputil_protocol_is_valid(enum ofputil_protocol protocol) { return protocol & OFPUTIL_P_ANY && is_pow2(protocol); }
int buf_ctor(struct buf_s *buf, size_t bsiz, size_t rblk, size_t wblk, int rline, int wline, size_t hpage, size_t ioar, size_t ioaw) { int ret = -1; size_t adj, page, idx, rblki, wblki, bsiza, csiza; if (!buf) { fputs("buf: no buf ?\n", stderr); return -1; } if (bsiz < 2*rblk || bsiz < 2*wblk) { fputs("buf: 'buffer size' must be at least 2*max('read block, 'write block'),\n" " to avoid corner case starvations.\n", stderr); return -1; } memset(buf, 0, sizeof *buf); #ifndef h_mingw page = sysconf(_SC_PAGESIZE); if (page == hpage) { hpage = 0; } page = hpage ? hpage : page; adj = MAX(page, SHMLBA); #else hpage = 0; adj = page = 4096; #endif bsiza = ALIGN(bsiz, adj); if (!(idx = is_pow2(bsiza))) { fprintf(stderr, "buf: 'aligned buffer size' must be power of 2, but is: 0x%zX\n", bsiza); goto out; } buf->mask = (((size_t)1 << idx) - 1); rblki = ALIGN(rblk, ioar); wblki = ALIGN(wblk, ioaw); csiza = ALIGN(rblki + wblki, adj); buf->size = bsiza; preset_shm(buf); if (setup_shm(buf, bsiza, csiza, hpage) < 0) { fputs("buf: falling back to regular malloc()\n", stderr); ret = 1; detach_shm(buf); rm_shm(buf); preset_mal(buf); if (setup_mal(buf, bsiza, csiza, adj) < 0) { detach_mal(buf); ret = -1; goto out; } } else ret = 0; buf->rchunk = buf->chk; buf->wchunk = buf->chk + rblki; buf->flags |= hpage && buf->mapW ? M_HUGE : 0; buf->flags |= rline ? M_LINER : 0; buf->flags |= wline ? M_LINEW : 0; // buf->page = page; buf->ioar = ioar; buf->ioaw = ioaw; buf->rblk = rblk; buf->wblk = wblk; buf->crcw = crc_beg(); buf->crcr = buf->crcw; #if 0 if (rblk < wblk && rline && !wline) { fputs("buf: 'read block' must be greater or equal to 'write block',\n" " if the left side is in the line mode,\n" " and the right side is in the reblocking mode.\n", stderr); goto out; } #endif DEB("\nbuf map: C:%p, B:%p, B+S:%p, W:%p\n", buf->mapC, buf->mapB, buf->mapB + buf->size, buf->mapW); DEB("buf buf: C:%p, B:%p\n", buf->chk, buf->buf); out: if (ret < 0) buf_dtor(buf); fputc('\n', stderr); return ret; }
// read full kernel into obuf[], gzip-decompress into ibuf[], // return decompressed size int PackVmlinuzI386::decompressKernel() { // read whole kernel image obuf.alloc(file_size); fi->seek(0, SEEK_SET); fi->readx(obuf, file_size); { const upx_byte *base = NULL; unsigned relocated = 0; // See startup_32: in linux/arch/i386/boot/compressed/head.S const upx_byte *p = &obuf[setup_size]; unsigned cpa_0 = 0; unsigned cpa_1 = 0; int j; if (0x205<=h.version) { cpa_0 = h.kernel_alignment; cpa_1 = 0u - cpa_0; } else for ((p = &obuf[setup_size]), (j= 0); j < 0x200; ++j, ++p) { if (0==memcmp("\x89\xeb\x81\xc3", p, 4) && 0==memcmp("\x81\xe3", 8+ p, 2)) { // movl %ebp,%ebx // addl $imm.w,%ebx // andl $imm.w,%ebx cpa_0 = 1+ get_te32( 4+ p); cpa_1 = get_te32(10+ p); break; } } for ((p = &obuf[setup_size]), (j= 0); j < 0x200; ++j, ++p) { if (0==memcmp("\x8d\x83", p, 2) // leal d32(%ebx),%eax && 0==memcmp("\xff\xe0", 6+ p, 2) // jmp *%eax ) { relocated = get_te32(2+ p); } if (0==memcmp("\xE8\x00\x00\x00\x00\x5D", p, 6)) { // "call 1f; 1f: pop %ebp" determines actual execution address. // linux-2.6.21 (spring 2007) and later; upx stub needs work // unless LOAD_PHYSICAL_ADDR is known. // Allowed code is: linux-2.6.23/arch/x86/head_32.S 2008-01-01 // call 1f // 1: popl %ebp // subl $1b, %ebp # 32-bit immediate // movl $LOAD_PHYSICAL_ADDR, %ebx // if (0==memcmp("\x81\xed", 6+ p, 2) // subl $imm.w,%ebp && 0==memcmp("\xbb", 12+ p, 1) ) { // movl $imm.w,%ebx physical_start = get_te32(13+ p); } else if (0==memcmp("\x81\xed", 6+ p, 2) // subl $imm.w,%ebp && is_pow2(cpa_0) && (0u-cpa_0)==cpa_1) { base = (5+ p) - get_te32(8+ p); config_physical_align = cpa_0; } else { throwCantPack("Unrecognized relocatable kernel"); } } // Find "ljmp $__BOOT_CS,$__PHYSICAL_START" if any. if (0==memcmp("\xEA\x00\x00", p, 3) && 0==(0xf & p[3]) && 0==p[4]) { /* whole megabyte < 16 MiB */ physical_start = get_te32(1+ p); break; } } if (base && relocated) { p = base + relocated; for (j = 0; j < 0x200; ++j, ++p) { if (0==memcmp("\x01\x9c\x0b", p, 3) // addl %ebx,d32(%ebx,%ecx) ) { page_offset = 0u - get_te32(3+ p); } if (0==memcmp("\x89\xeb", p, 2) // movl %ebp,%ebx && 0==memcmp("\x81\xeb", 2+ p, 2) // subl $imm32,%ebx ) { physical_start = get_te32(4+ p); } } } } checkAlreadyPacked(obuf + setup_size, UPX_MIN(file_size - setup_size, (off_t)1024)); int gzoff = setup_size; if (0x208<=h.version) { gzoff += h.payload_offset; } for (; gzoff < file_size; gzoff++) { // find gzip header (2 bytes magic + 1 byte method "deflated") int off = find(obuf + gzoff, file_size - gzoff, "\x1F\x8B\x08", 3); if (off < 0) break; gzoff += off; const int gzlen = (h.version < 0x208) ? (file_size - gzoff) : h.payload_length; if (gzlen < 256) break; // check gzip flag byte unsigned char flags = obuf[gzoff + 3]; if ((flags & 0xe0) != 0) // reserved bits set continue; //printf("found gzip header at offset %d\n", gzoff); // try to decompress int klen; int fd; off_t fd_pos; for (;;) { klen = -1; fd = -1; fd_pos = -1; // open fi->seek(gzoff, SEEK_SET); fd = dup(fi->getFd()); if (fd < 0) break; gzFile zf = gzdopen(fd, "rb"); if (zf == NULL) break; // estimate gzip-decompressed kernel size & alloc buffer if (ibuf.getSize() == 0) ibuf.alloc(gzlen * 3); // decompress klen = gzread(zf, ibuf, ibuf.getSize()); fd_pos = lseek(fd, 0, SEEK_CUR); gzclose(zf); fd = -1; if (klen != (int)ibuf.getSize()) break; // realloc and try again unsigned s = ibuf.getSize(); ibuf.dealloc(); ibuf.alloc(3 * s / 2); } if (fd >= 0) (void) close(fd); if (klen <= 0) continue; if (klen <= gzlen) continue; if (0x208<=h.version && 0==memcmp("\177ELF", ibuf, 4)) { // Full ELF in theory; for now, try to handle as .bin at physical_start. // Check for PT_LOAD.p_paddr being ascending and adjacent. Elf_LE32_Ehdr const *const ehdr = (Elf_LE32_Ehdr const *)(void const *)ibuf; Elf_LE32_Phdr const *phdr = (Elf_LE32_Phdr const *)(ehdr->e_phoff + (char const *)ehdr); Elf_LE32_Shdr const *shdr = (Elf_LE32_Shdr const *)(ehdr->e_shoff + (char const *)ehdr); unsigned hi_paddr = 0, lo_paddr = 0; unsigned delta_off = 0; for (unsigned j=0; j < ehdr->e_phnum; ++j, ++phdr) { if (phdr->PT_LOAD==phdr->p_type) { unsigned step = (hi_paddr + phdr->p_align - 1) & ~(phdr->p_align - 1); if (0==hi_paddr) { // first PT_LOAD if (physical_start!=phdr->p_paddr) { return 0; } delta_off = phdr->p_paddr - phdr->p_offset; lo_paddr = phdr->p_paddr; hi_paddr = phdr->p_filesz + phdr->p_paddr; } else if (step==phdr->p_paddr && delta_off==(phdr->p_paddr - phdr->p_offset)) { hi_paddr = phdr->p_filesz + phdr->p_paddr; } else { return 0; // Not equivalent to a .bin. Too complex for now. } } } // FIXME: ascending order is only a convention; might need sorting. for (unsigned j=1; j < ehdr->e_shnum; ++j) { if (shdr->SHT_PROGBITS==shdr->sh_type) { // SHT_REL might be intermixed if (shdr->SHF_EXECINSTR & shdr[j].sh_flags) { filter_len += shdr[j].sh_size; // FIXME: include sh_addralign } else { break; } } } memmove(ibuf, (lo_paddr - delta_off) + ibuf, hi_paddr - lo_paddr); // FIXME: set_size // FIXME: .bss ? Apparently handled by head.S } if (opt->force > 0) return klen; // some checks if (fd_pos != file_size) { //printf("fd_pos: %ld, file_size: %ld\n", (long)fd_pos, (long)file_size); // linux-2.6.21.5/arch/i386/boot/compressed/vmlinux.lds // puts .data.compressed ahead of .text, .rodata, etc; // so piggy.o need not be last in bzImage. Alas. //throwCantPack("trailing bytes after kernel image; use option '-f' to force packing"); } // see /usr/src/linux/arch/i386/kernel/head.S // 2.4.x: [cli;] cld; mov $...,%eax if (memcmp(ibuf, "\xFC\xB8", 2) == 0) goto head_ok; if (memcmp(ibuf, "\xFA\xFC\xB8", 3) == 0) goto head_ok; // 2.6.21.5 CONFIG_PARAVIRT mov %cs,%eax; test $3,%eax; jne ...; if (memcmp(ibuf, "\x8c\xc8\xa9\x03\x00\x00\x00\x0f\x85", 9) == 0) goto head_ok; if (memcmp(ibuf, "\x8c\xc8\xa8\x03\x0f\x85", 6) == 0) goto head_ok; // 2.6.x: [cli;] cld; lgdt ... if (memcmp(ibuf, "\xFC\x0F\x01", 3) == 0) goto head_ok; if (memcmp(ibuf, "\xFA\xFC\x0F\x01", 4) == 0) goto head_ok; // 2.6.x+grsecurity+strongswan+openwall+trustix: ljmp $0x10,... if (ibuf[0] == 0xEA && memcmp(ibuf+5, "\x10\x00", 2) == 0) goto head_ok; // x86_64 2.6.x if (0xB8==ibuf[0] // mov $...,%eax && 0x8E==ibuf[5] && 0xD8==ibuf[6] // mov %eax,%ds && 0x0F==ibuf[7] && 0x01==ibuf[8] && 020==(070 & ibuf[9]) // lgdtl && 0xB8==ibuf[14] // mov $...,%eax && 0x0F==ibuf[19] && 0xA2==ibuf[20] // cpuid ) goto head_ok; // cmpw $0x207,0x206(%esi) Debian vmlinuz-2.6.24-12-generic if (0==memcmp("\x66\x81\xbe\x06\x02\x00\x00\x07\x02", ibuf, 9)) goto head_ok; // testb $0x40,0x211(%esi) Fedora vmlinuz-2.6.25-0.218.rc8.git7.fc9.i686 if (0==memcmp("\xf6\x86\x11\x02\x00\x00\x40", ibuf, 7)) goto head_ok; // rex.W prefix for x86_64 if (0x48==ibuf[0]) throwCantPack("x86_64 bzImage is not yet supported"); throwCantPack("unrecognized kernel architecture; use option '-f' to force packing"); head_ok: // FIXME: more checks for special magic bytes in ibuf ??? // FIXME: more checks for kernel architecture ??? return klen; } return 0; }