/********************************************************/
/* ntapi: Native API core library */
/* Copyright (C) 2013--2021 SysDeer Technologies, LLC */
/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
/********************************************************/
#include <ntapi/nt_status.h>
#include <ntapi/nt_blitter.h>
#include <ntapi/nt_sync.h>
#include <ntapi/ntapi.h>
#include <ntapi/nt_atomic.h>
#include "ntapi_blitter.h"
#include "ntapi_impl.h"
static int __blt_popcount(uintptr_t mask)
{
/* todo: check cpuid, use at_popcount */
uintptr_t i;
int ret;
for (i=0,ret=0; i<8*sizeof(uintptr_t); i++)
if (mask & ((uintptr_t)1<<i))
ret++;
return ret;
}
int32_t __fastcall __ntapi_blt_alloc(
__out nt_blitter ** blitter,
__in nt_blitter_params * params)
{
int32_t status;
nt_blitter * blt_ctx;
size_t blt_ctx_size;
size_t params_size;
size_t ptrs,i;
/* alignment */
if (params->block_count % sizeof(uintptr_t))
return NT_STATUS_INVALID_PARAMETER;
else if (!params->region && (params->block_size % sizeof(uintptr_t)))
return NT_STATUS_INVALID_PARAMETER;
/* blt control block allocation */
ptrs = params->block_count / (8 * sizeof(uintptr_t));
blt_ctx = (nt_blitter *)0;
blt_ctx_size = (size_t)&((nt_blitter *)0)->bits;
/* user-provided bitmap? */
if (!params->bitmap)
blt_ctx_size += ptrs * sizeof(uintptr_t);
/* alloc */
status = __ntapi->zw_allocate_virtual_memory(
NT_CURRENT_PROCESS_HANDLE,
(void **)&blt_ctx,
0,
&blt_ctx_size,
NT_MEM_COMMIT,
NT_PAGE_READWRITE);
if (status) return (status);
/* init control block */
__ntapi->tt_aligned_block_memset(
blt_ctx,
0,(size_t)&((nt_blitter *)0)->bits);
blt_ctx->addr = blt_ctx;
blt_ctx->size = blt_ctx_size;
blt_ctx->ptrs = ptrs;
/* init bitmap */
blt_ctx->bitmap = params->bitmap
? (uintptr_t *)params->bitmap
: blt_ctx->bits;
if (!(params->flags & NT_BLITTER_PRESERVE_BITS))
__ntapi->tt_aligned_block_memset(
blt_ctx->bitmap,(-1),
ptrs * sizeof(uintptr_t));
/* info structure */
blt_ctx->info.info_size = sizeof(nt_blitter_info);
blt_ctx->info.block_count = params->block_count;
blt_ctx->info.block_size = params->block_size;
if (params->flags & NT_BLITTER_ENABLE_BLOCK_ARRAY)
/* allocate in place */
blt_ctx->info.region_size = params->block_count * params->block_size;
else
/* use pointer array */
blt_ctx->info.region_size = params->block_count * sizeof(uintptr_t);
/* allocate region */
if (params->region)
blt_ctx->info.region_addr = params->region;
else
status = __ntapi->zw_allocate_virtual_memory(
NT_CURRENT_PROCESS_HANDLE,
&blt_ctx->info.region_addr,
0,
&blt_ctx->info.region_size,
NT_MEM_COMMIT,
NT_PAGE_READWRITE);
if (status) {
__ntapi->blt_free(blt_ctx);
return status;
}
if (params->flags & NT_BLITTER_PRESERVE_BITS)
for (i=0,blt_ctx->info.blocks_avail=0; i<ptrs; i++)
blt_ctx->info.blocks_avail += __blt_popcount(blt_ctx->bitmap[i]);
else
blt_ctx->info.blocks_avail = params->block_count;
if (params->flags & NT_BLITTER_ENABLE_BLOCK_ARRAY)
blt_ctx->info.blocks_cached = params->block_count;
/* init block array */
if (!params->region)
__ntapi->tt_aligned_block_memset(
blt_ctx->info.region_addr,
0,blt_ctx->info.region_size);
/* copy params */
if (params->params_size < sizeof(nt_blitter_params))
params_size = params->params_size;
else
params_size = sizeof(nt_blitter_params);
__ntapi->tt_aligned_block_memcpy(
(uintptr_t *)&blt_ctx->params,
(uintptr_t *)params,
params_size);
/* update params */
blt_ctx->params.lock_tries = params->lock_tries
? params->lock_tries
: __NT_BLITTER_DEFAULT_LOCK_TRIES;
blt_ctx->params.round_trips = params->round_trips
? params->round_trips
: __NT_BLITTER_DEFAULT_ROUND_TRIPS;
*blitter = blt_ctx;
return NT_STATUS_SUCCESS;
}