diff options
| author | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-04-04 15:09:38 +0200 |
|---|---|---|
| committer | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-04-04 15:09:38 +0200 |
| commit | 870f4dca9d7b5e86544216d0e36863d17aefef62 (patch) | |
| tree | f6186004da976cea19ee5764b795a51f932f77fb /libpsn00b | |
| parent | f7d9c309661f3027d5bfd119b3daf814e26ef589 (diff) | |
Add argument validation to most libpsn00b functions
Diffstat (limited to 'libpsn00b')
| -rw-r--r-- | libpsn00b/include/assert.h | 19 | ||||
| -rw-r--r-- | libpsn00b/psxcd/cdread.c | 2 | ||||
| -rw-r--r-- | libpsn00b/psxcd/common.c | 10 | ||||
| -rw-r--r-- | libpsn00b/psxcd/isofs.c | 13 | ||||
| -rw-r--r-- | libpsn00b/psxcd/misc.c | 8 | ||||
| -rw-r--r-- | libpsn00b/psxetc/dl.c | 13 | ||||
| -rw-r--r-- | libpsn00b/psxetc/interrupts.c | 19 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/common.c | 16 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/env.c | 15 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/font.c | 14 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/image.c | 16 | ||||
| -rw-r--r-- | libpsn00b/psxpress/mdec.c | 6 | ||||
| -rw-r--r-- | libpsn00b/psxspu/common.c | 10 |
13 files changed, 139 insertions, 22 deletions
diff --git a/libpsn00b/include/assert.h b/libpsn00b/include/assert.h index d18a56f..26b2023 100644 --- a/libpsn00b/include/assert.h +++ b/libpsn00b/include/assert.h @@ -25,6 +25,9 @@ void _assert_abort(const char *file, int line, const char *expr); #define assert(expr) #define _sdk_log(fmt, ...) +#define _sdk_assert(expr, fmt, ...) +#define _sdk_validate_args_void(expr) +#define _sdk_validate_args(expr, ret) #else @@ -39,6 +42,22 @@ void _assert_abort(const char *file, int line, const char *expr); printf(fmt __VA_OPT__(,) __VA_ARGS__) #endif +#define _sdk_assert(expr, ret, fmt, ...) \ + if (!(expr)) { \ + _sdk_log(fmt, __VA_ARGS__); \ + return ret; \ + } +#define _sdk_validate_args_void(expr) \ + if (!(expr)) { \ + _sdk_log("invalid args to %s() (%s)\n", __func__, #expr); \ + return; \ + } +#define _sdk_validate_args(expr, ret) \ + if (!(expr)) { \ + _sdk_log("invalid args to %s() (%s)\n", __func__, #expr); \ + return ret; \ + } + #endif #endif diff --git a/libpsn00b/psxcd/cdread.c b/libpsn00b/psxcd/cdread.c index d211a01..1adc255 100644 --- a/libpsn00b/psxcd/cdread.c +++ b/libpsn00b/psxcd/cdread.c @@ -89,6 +89,8 @@ static int _poll_retry(void) { /* Public API */ int CdReadRetry(int sectors, uint32_t *buf, int mode, int attempts) { + _sdk_validate_args((sectors > 0) && buf && (attempts > 0), -1); + if (CdReadSync(1, 0) > 0) { _sdk_log("CdRead() failed, another read in progress (%d sectors pending)\n", _pending_sectors); return 0; diff --git a/libpsn00b/psxcd/common.c b/libpsn00b/psxcd/common.c index c8f01d1..461ab91 100644 --- a/libpsn00b/psxcd/common.c +++ b/libpsn00b/psxcd/common.c @@ -244,6 +244,8 @@ int CdInit(void) { /* Low-level command API */ int CdCommandF(CdlCommand cmd, const void *param, int length) { + _sdk_validate_args(param || (length <= 0), -1); + const uint8_t *_param = (const uint8_t *) param; _last_command = (uint8_t) cmd; @@ -283,7 +285,7 @@ int CdCommandF(CdlCommand cmd, const void *param, int length) { __asm__ volatile(""); CD_REG(0) = 0; - for (; length; length--) + for (; length > 0; length--) CD_REG(2) = *(_param++); CD_REG(0) = 0; @@ -292,6 +294,8 @@ int CdCommandF(CdlCommand cmd, const void *param, int length) { } int CdCommand(CdlCommand cmd, const void *param, int length, uint8_t *result) { + _sdk_validate_args(param || (length <= 0), -1); + /*if (_ack_pending) { _sdk_log("CdCommand(0x%02x) failed, drive busy\n", cmd); return 0; @@ -329,8 +333,10 @@ int CdControlF(CdlCommand cmd, const void *param) { } else { // The command takes a mandatory parameter or no parameter. length = flags & 3; - if (length && !param) + if (length && !param) { + _sdk_log("CdControl() param is required for command 0x%02x\n", cmd); return -1; + } } return CdCommandF(cmd, param, length); diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c index 0ac782b..5fd0536 100644 --- a/libpsn00b/psxcd/isofs.c +++ b/libpsn00b/psxcd/isofs.c @@ -450,6 +450,8 @@ static char* get_filename(char *name, const char *filename) CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) { + _sdk_validate_args(fp && filename, NULL); + int i,j,found_dir,num_dirs; int dir_len; char tpath_rbuff[128]; @@ -553,6 +555,8 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) CdlDIR *CdOpenDir(const char* path) { + _sdk_validate_args(path, NULL); + CdlDIR_INT* dir; int num_dirs; int i,found_dir; @@ -631,6 +635,8 @@ CdlDIR *CdOpenDir(const char* path) int CdReadDir(CdlDIR *dir, CdlFILE* file) { + _sdk_validate_args(dir && file, 0); + CdlDIR_INT* d_dir; ISO_DIR_ENTRY* dir_entry; @@ -683,6 +689,9 @@ int CdReadDir(CdlDIR *dir, CdlFILE* file) void CdCloseDir(CdlDIR *dir) { + if (!dir) + return; + CdlDIR_INT* d_dir; d_dir = (CdlDIR_INT*)dir; @@ -698,6 +707,8 @@ int CdIsoError() int CdGetVolumeLabel(char *label) { + _sdk_validate_args(label, -1); + int i, length = 31; ISO_DESCRIPTOR* descriptor; @@ -761,6 +772,8 @@ static void _scan_callback(CdlIntrResult status, unsigned char *result) int CdLoadSession(int session) { + _sdk_validate_args(session >= 0, -1); + CdlLOC *loc; CdlCB ready_oldcb; char scanbuff[2048]; diff --git a/libpsn00b/psxcd/misc.c b/libpsn00b/psxcd/misc.c index 851fea6..2f04821 100644 --- a/libpsn00b/psxcd/misc.c +++ b/libpsn00b/psxcd/misc.c @@ -33,6 +33,8 @@ static const char *const _unlock_regions[] = { /* Sector DMA transfer functions */ int CdGetSector(void *madr, int size) { + _sdk_validate_args(madr && (size > 0), 0); + //while (!(CD_REG(0) & (1 << 6))) //__asm__ volatile(""); @@ -47,6 +49,8 @@ int CdGetSector(void *madr, int size) { } int CdGetSector2(void *madr, int size) { + _sdk_validate_args(madr && (size > 0), 0); + //while (!(CD_REG(0) & (1 << 6))) //__asm__ volatile(""); @@ -170,6 +174,8 @@ int CdUnlock(CdlRegionCode region) { /* Misc. functions */ int CdGetToc(CdlLOC *toc) { + _sdk_validate_args(toc, 0); + uint8_t result[4]; if (!CdCommand(CdlGetTN, 0, 0, result)) @@ -199,6 +205,8 @@ int CdGetToc(CdlLOC *toc) { } int CdMix(const CdlATV *vol) { + _sdk_validate_args(vol, 0); + CD_REG(0) = 2; CD_REG(2) = vol->val0; CD_REG(3) = vol->val1; diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c index ff712eb..06302e2 100644 --- a/libpsn00b/psxetc/dl.c +++ b/libpsn00b/psxetc/dl.c @@ -112,6 +112,8 @@ static uint32_t _elf_hash(const char *str) { /* Symbol map loading/introspection API */ int DL_InitSymbolMap(int num_entries) { + _sdk_validate_args(num_entries, -1); + if (_symbol_map.entries) DL_UnloadSymbolMap(); @@ -151,6 +153,8 @@ void DL_UnloadSymbolMap(void) { } void DL_AddMapSymbol(const char *name, void *ptr) { + _sdk_validate_args_void(name); + uint32_t hash = _elf_hash(name); int index = _symbol_map.index; _symbol_map.index = index + 1; @@ -168,6 +172,8 @@ void DL_AddMapSymbol(const char *name, void *ptr) { } int DL_ParseSymbolMap(const char *ptr, size_t size) { + _sdk_validate_args(ptr && size, 0); + int entries = 0; // Perform a quick scan over the entire map text and count the number of @@ -232,6 +238,8 @@ int DL_ParseSymbolMap(const char *ptr, size_t size) { } void *DL_GetMapSymbol(const char *name) { + _sdk_validate_args(name, 0); + if (!_symbol_map.entries) { _sdk_log("DL_GetMapSymbol() with no map loaded\n"); return 0; @@ -275,8 +283,7 @@ void *DL_SetResolveCallback(void *(*callback)(DLL *, const char *)) { /* Library loading and linking API */ DLL *DL_CreateDLL(DLL *dll, void *ptr, size_t size, DL_ResolveMode mode) { - if (!dll || !ptr) - return 0; + _sdk_validate_args(dll && ptr && size, 0); dll->ptr = ptr; dll->malloc_ptr = (mode & DL_FREE_ON_DESTROY) ? ptr : 0; @@ -463,6 +470,8 @@ void DL_DestroyDLL(DLL *dll) { } void *DL_GetDLLSymbol(const DLL *dll, const char *name) { + _sdk_validate_args(name, 0); + if (!dll) return DL_GetMapSymbol(name); //return _dl_resolve_callback(0, name); diff --git a/libpsn00b/psxetc/interrupts.c b/libpsn00b/psxetc/interrupts.c index 7c8b206..b7bbd07 100644 --- a/libpsn00b/psxetc/interrupts.c +++ b/libpsn00b/psxetc/interrupts.c @@ -4,6 +4,7 @@ */ #include <stdint.h> +#include <assert.h> #include <psxapi.h> #include <psxetc.h> #include <hwregs_c.h> @@ -99,8 +100,7 @@ static void _global_dma_handler(void) { /* IRQ and DMA handler API */ void *InterruptCallback(IRQ_Channel irq, void (*func)(void)) { - if ((irq < 0) || (irq >= NUM_IRQ_CHANNELS)) - return 0; + _sdk_validate_args((irq >= 0) && (irq < NUM_IRQ_CHANNELS), 0); void *old_callback = _irq_handlers[irq]; _irq_handlers[irq] = func; @@ -116,15 +116,13 @@ void *InterruptCallback(IRQ_Channel irq, void (*func)(void)) { } void *GetInterruptCallback(IRQ_Channel irq) { - if ((irq < 0) || (irq >= NUM_IRQ_CHANNELS)) - return 0; + _sdk_validate_args((irq >= 0) && (irq < NUM_IRQ_CHANNELS), 0); return _irq_handlers[irq]; } void *DMACallback(DMA_Channel dma, void (*func)(void)) { - if ((dma < 0) || (dma >= NUM_DMA_CHANNELS)) - return 0; + _sdk_validate_args((dma >= 0) && (dma < NUM_DMA_CHANNELS), 0); void *old_callback = _dma_handlers[dma]; _dma_handlers[dma] = func; @@ -151,8 +149,7 @@ void *DMACallback(DMA_Channel dma, void (*func)(void)) { } void *GetDMACallback(DMA_Channel dma) { - if ((dma < 0) || (dma >= NUM_DMA_CHANNELS)) - return 0; + _sdk_validate_args((dma >= 0) && (dma < NUM_DMA_CHANNELS), 0); return _dma_handlers[dma]; } @@ -160,8 +157,7 @@ void *GetDMACallback(DMA_Channel dma) { /* DMA channel priority API */ int SetDMAPriority(DMA_Channel dma, int priority) { - if ((dma < 0) || (dma >= NUM_DMA_CHANNELS)) - return -1; + _sdk_validate_args((dma >= 0) && (dma < NUM_DMA_CHANNELS), -1); uint32_t dpcr = DMA_DPCR; uint32_t channel = dpcr >> (dma * 4); @@ -175,8 +171,7 @@ int SetDMAPriority(DMA_Channel dma, int priority) { } int GetDMAPriority(DMA_Channel dma) { - if ((dma < 0) || (dma >= NUM_DMA_CHANNELS)) - return -1; + _sdk_validate_args((dma >= 0) && (dma < NUM_DMA_CHANNELS), -1); uint32_t channel = DMA_DPCR >> (dma * 4); return (channel & 8) ? (channel & 7) : -1; diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index e354261..46f87bc 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -187,6 +187,8 @@ int EnqueueDrawOp( uint32_t arg2, uint32_t arg3 ) { + _sdk_validate_args(func, -1); + // If GPU DMA is currently busy, append the command to the queue instead of // executing it immediately. Note that interrupts must be disabled *prior* // to checking if DMA is busy; disabling them afterwards would create a @@ -263,6 +265,8 @@ void *DrawSyncCallback(void (*func)(void)) { /* OT and primitive drawing API */ void ClearOTagR(uint32_t *ot, size_t length) { + _sdk_validate_args_void(ot && length); + DMA_MADR(DMA_OTC) = (uint32_t) &ot[length - 1]; DMA_BCR(DMA_OTC) = length & 0xffff; DMA_CHCR(DMA_OTC) = 0x11000002; @@ -272,6 +276,8 @@ void ClearOTagR(uint32_t *ot, size_t length) { } void ClearOTag(uint32_t *ot, size_t length) { + _sdk_validate_args_void(ot && length); + // DMA6 only supports writing to RAM in reverse order (last to first), so // the OT has to be cleared in software here. This function is thus much // slower than ClearOTagR(). @@ -285,10 +291,14 @@ void ClearOTag(uint32_t *ot, size_t length) { } void AddPrim(uint32_t *ot, const void *pri) { + _sdk_validate_args_void(ot && pri); + addPrim(ot, pri); } -void DrawPrim(const uint32_t *pri) { +void DrawPrim(const uint32_t *pri) { + _sdk_validate_args_void(pri); + size_t length = getlen(pri); DrawSync(0); @@ -308,10 +318,14 @@ void DrawPrim(const uint32_t *pri) { } int DrawOTag(const uint32_t *ot) { + _sdk_validate_args(ot, -1); + return EnqueueDrawOp((void *) &DrawOTag2, (uint32_t) ot, 0, 0); } void DrawOTag2(const uint32_t *ot) { + _sdk_validate_args_void(ot); + GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0 while (DMA_CHCR(DMA_GPU) & (1 << 24)) diff --git a/libpsn00b/psxgpu/env.c b/libpsn00b/psxgpu/env.c index b90a431..cfe09c0 100644 --- a/libpsn00b/psxgpu/env.c +++ b/libpsn00b/psxgpu/env.c @@ -4,6 +4,7 @@ */ #include <stdint.h> +#include <assert.h> #include <psxgpu.h> #include <hwregs_c.h> @@ -36,6 +37,8 @@ static inline uint32_t _get_window_mask(int size) { /* Drawing API */ DRAWENV *SetDefDrawEnv(DRAWENV *env, int x, int y, int w, int h) { + _sdk_validate_args(env && (w > 0) && (h > 0), 0); + env->clip.x = x; env->clip.y = y; env->clip.w = w; @@ -60,6 +63,8 @@ DRAWENV *SetDefDrawEnv(DRAWENV *env, int x, int y, int w, int h) { } int DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { + _sdk_validate_args(ot && env, -1); + // All commands are grouped into a single display list packet for // performance reasons using tagless primitives (the GPU does not care // about the grouping as the display list is parsed by the CPU). @@ -102,6 +107,8 @@ int DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { } void PutDrawEnv(DRAWENV *env) { + _sdk_validate_args_void(env); + DrawOTagEnv((const uint32_t *) 0x00ffffff, env); } @@ -109,6 +116,8 @@ void PutDrawEnv(DRAWENV *env) { // useful if the DRAWENV structure is never modified (which is the case most of // the time). void PutDrawEnvFast(DRAWENV *env) { + _sdk_validate_args_void(env); + if (!(env->dr_env.tag)) DrawOTagEnv((const uint32_t *) 0x00ffffff, env); else @@ -118,6 +127,8 @@ void PutDrawEnvFast(DRAWENV *env) { /* Display API */ DISPENV *SetDefDispEnv(DISPENV *env, int x, int y, int w, int h) { + _sdk_validate_args(env && (w > 0) && (h > 0), 0); + env->disp.x = x; env->disp.y = y; env->disp.w = w; @@ -136,6 +147,8 @@ DISPENV *SetDefDispEnv(DISPENV *env, int x, int y, int w, int h) { } void PutDispEnv(const DISPENV *env) { + _sdk_validate_args_void(env); + uint32_t h_range, v_range, mode, fb_pos; mode = _gpu_video_mode << 3; @@ -204,6 +217,8 @@ void PutDispEnv(const DISPENV *env) { /* Deprecated "raw" display API */ void PutDispEnvRaw(const DISPENV_RAW *env) { + _sdk_validate_args_void(env); + uint32_t h_range, v_range, fb_pos; h_range = 608 + env->vid_xpos; diff --git a/libpsn00b/psxgpu/font.c b/libpsn00b/psxgpu/font.c index b1c3c7a..c9d60f1 100644 --- a/libpsn00b/psxgpu/font.c +++ b/libpsn00b/psxgpu/font.c @@ -1,4 +1,5 @@ #include <stdint.h> +#include <assert.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -23,6 +24,7 @@ uint16_t _font_clut; extern uint8_t _gpu_debug_font[]; void FntLoad(int x, int y) { + _sdk_validate_args_void((x >= 0) && (y >= 0) && (x < 1024) && (y < 1024)); RECT pos; TIM_IMAGE tim; @@ -66,7 +68,8 @@ void FntLoad(int x, int y) { } int FntOpen(int x, int y, int w, int h, int isbg, int n) { - + _sdk_validate_args((w > 0) && (h > 0) && (n > 0), -1); + int i; // Initialize a text stream @@ -98,7 +101,8 @@ int FntOpen(int x, int y, int w, int h, int isbg, int n) { } int FntPrint(int id, const char *fmt, ...) { - + _sdk_validate_args((id < _nstreams) && fmt, -1); + int n; va_list ap; @@ -124,7 +128,8 @@ int FntPrint(int id, const char *fmt, ...) { } char *FntFlush(int id) { - + _sdk_validate_args(id < _nstreams, 0); + char *opri; SPRT_8 *sprt; DR_TPAGE *tpage; @@ -226,7 +231,8 @@ char *FntFlush(int id) { } char *FntSort(uint32_t *ot, char *pri, int x, int y, const char *text) { - + _sdk_validate_args(ot && pri, 0); + DR_TPAGE *tpage; SPRT_8 *sprt = (SPRT_8*)pri; int i; diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index ba5c445..63bceb6 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -69,6 +69,8 @@ static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { /* VRAM transfer API */ int LoadImage(const RECT *rect, const uint32_t *data) { + _sdk_validate_args(rect && data, -1); + int index = _next_saved_rect; _saved_rects[index] = *rect; @@ -83,6 +85,8 @@ int LoadImage(const RECT *rect, const uint32_t *data) { } int StoreImage(const RECT *rect, uint32_t *data) { + _sdk_validate_args(rect && data, -1); + int index = _next_saved_rect; _saved_rects[index] = *rect; @@ -97,18 +101,26 @@ int StoreImage(const RECT *rect, uint32_t *data) { } int MoveImage(const RECT *rect, int x, int y) { + _sdk_validate_args(rect, -1); + return EnqueueDrawOp((void *) &MoveImage2, (uint32_t) rect, x, y); } void LoadImage2(const RECT *rect, const uint32_t *data) { + _sdk_validate_args_void(rect && data); + _dma_transfer(rect, (uint32_t *) data, 1); } void StoreImage2(const RECT *rect, uint32_t *data) { + _sdk_validate_args_void(rect && data); + _dma_transfer(rect, data, 0); } void MoveImage2(const RECT *rect, int x, int y) { + _sdk_validate_args_void(rect); + while (!(GPU_GP1 & (1 << 26))) __asm__ volatile(""); @@ -131,6 +143,8 @@ void MoveImage2(const RECT *rect, int x, int y) { // returning pointers to them, which become useless once the .TIM file is // unloaded from main RAM. int GsGetTimInfo(const uint32_t *tim, GsIMAGE *info) { + _sdk_validate_args(tim && info, 1); + if ((*(tim++) & 0xffff) != 0x0010) return 1; @@ -157,6 +171,8 @@ int GsGetTimInfo(const uint32_t *tim, GsIMAGE *info) { } int GetTimInfo(const uint32_t *tim, TIM_IMAGE *info) { + _sdk_validate_args(tim && info, 1); + if ((*(tim++) & 0xffff) != 0x0010) return 1; diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c index 394a0ce..b3aa837 100644 --- a/libpsn00b/psxpress/mdec.c +++ b/libpsn00b/psxpress/mdec.c @@ -111,6 +111,8 @@ void DecDCTPutEnv(const DECDCTENV *env, int mono) { } void DecDCTin(const uint32_t *data, int mode) { + _sdk_validate_args_void(data); + uint32_t header = *data; DecDCTinSync(0); @@ -128,6 +130,8 @@ void DecDCTin(const uint32_t *data, int mode) { // data length as an argument rather than parsing it from the first 4 bytes of // the stream. void DecDCTinRaw(const uint32_t *data, size_t length) { + _sdk_validate_args_void(data && length); + if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { _sdk_log("input data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; @@ -157,6 +161,8 @@ int DecDCTinSync(int mode) { } void DecDCTout(uint32_t *data, size_t length) { + _sdk_validate_args_void(data && length); + DecDCToutSync(0); if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c index 1275621..efe1d9e 100644 --- a/libpsn00b/psxspu/common.c +++ b/libpsn00b/psxspu/common.c @@ -164,12 +164,18 @@ void SpuInit(void) { } size_t SpuRead(uint32_t *data, size_t size) { + _sdk_validate_args(data && size, 0); + return _dma_transfer(data, size, 0) * 4; } size_t SpuWrite(const uint32_t *data, size_t size) { - if (_transfer_addr < WRITABLE_AREA_ADDR) + _sdk_validate_args(data && size, 0); + + if (_transfer_addr < WRITABLE_AREA_ADDR) { + _sdk_log("ignoring attempt to write to capture buffers at 0x%05x\n", _transfer_addr); return 0; + } // I/O transfer mode is not that useful, but whatever. if (_transfer_mode) @@ -179,6 +185,8 @@ size_t SpuWrite(const uint32_t *data, size_t size) { } size_t SpuWritePartly(const uint32_t *data, size_t size) { + //_sdk_validate_args(data && size, 0); + size_t _size = SpuWrite(data, size); _transfer_addr += (_size + 1) / 2; |
