/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * 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 https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 *
 * $Author$
 * $Date$
 * $RCSfile: mem_mgr.c,v $
 * $Revision$
 *
 *---------------------------------------------------------------------------*/

/** @file mem_mgr.c
 *  non-OS library.
 *
 */

#if defined(CC_MTK_LOADER) || defined(CC_MTK_HOTBOOT_START)

#include "x_typedef.h"
#include "x_timer.h"
#include "loader_imghdr.h"
#include <string.h>
#include "x_hal_arm.h"
#include "x_dram.h"
#include "x_bim.h"
#include "x_assert.h"
#include "x_printf.h"
#ifdef CC_MTK_LOADER
#define LOG(level, fmt...)   Printf(fmt)
#endif

#if  !defined(CC_MTK_PRELOADER)
static UINT32 g_u4MemNCPtr =LDR_ALIGN((CC_LOADER_MEM_OFFSET + LOADER_MAX_SIZE*16),0x100000); // for the loader at 0xd00000.
#endif
static UINT32 g_u4MemPtr = LDR_ALIGN((CC_LOADER_MEM_OFFSET + LOADER_MAX_SIZE*16),0x100000)+0x100000; //cached addr is under non-cached

void *x_mem_alloc(UINT32 z_size)
{
#ifdef CC_UBOOT
    return malloc(z_size);
#else /* CC_UBOOT */
    void *p;
    UINT32 u4DramSize;
    u4DramSize = TCMGET_CHANNELA_SIZE() * 0x100000;
    #if defined(CC_LOADER_MMUTBL_PROT) && defined(CC_MTK_LOADER)
    u4DramSize-=(0x4000+0x1000);//exclude the mmu table address
    #endif
    p = (void *)g_u4MemPtr;
    g_u4MemPtr += (z_size + g_u4Dcachelinesize-1) & (0x100000000-g_u4Dcachelinesize);  // for dcacheline-bytes alignment

    if(g_u4MemPtr < DRAM_START || g_u4MemPtr - DRAM_START > u4DramSize - 1)
    {
#ifndef CC_MTK_PRELOADER
#ifdef CC_MTK_LOADER
	LOG(0,"x_mem_alloc failed address+size x%x \n",g_u4MemPtr);
#endif
#endif
	ASSERT(0);
    }
    return p;
#endif /* CC_UBOOT */
}
void *x_mem_alloc_nocache(UINT32 z_size)
{
#if  !defined(CC_MTK_PRELOADER)
    UINT32 u4NCStart=LDR_ALIGN((CC_LOADER_MEM_OFFSET + LOADER_MAX_SIZE*16),0x100000);
    void *p;
    p = (void *)g_u4MemNCPtr;
    if((g_u4MemNCPtr-u4NCStart)>=0x100000)
    {
        Printf("exceed nocache memory size.Please enlarge nocache mem size\n");
        return NULL;
    }
    g_u4MemNCPtr += (z_size + g_u4Dcachelinesize-1) & (0x100000000-g_u4Dcachelinesize);  // for dcacheline-bytes alignment
    return p;
#else
    return NULL;
#endif
}
void x_mem_free(void *pv_mem_block)
{
    /* do nothing. */
}
#if defined(CC_MT5882)||defined(CC_MT5865)||defined(CC_MT5890)||defined(CC_MT5891)||defined(CC_MT5886)||defined(CC_MT5863)||defined(CC_MT5893)||defined(CC_MT5895)
#ifdef __GCC__
void * __memset_chk(void *src, int c, size_t count,size_t dest_len) __attribute__ ((weak));
void * __memset_chk(void *src, int c, size_t count,size_t dest_len)
{
    if(count>dest_len)
    {
        /*memset buffer overflow*/
        //while(1){;}
        ASSERT(0);
    }
    return memset(src,c,count);
}
#endif
#ifndef __GCC__
void *memset(void *src, int c, size_t count)
{
char *xs = src;
while (count--)
	*xs++ = c;
return src;
}
void *memcpy(void *dest, const void *src, size_t count)
{
if(dest==NULL||src ==NULL||count==NULL)
	return NULL;
char *tmp = dest;
const char *s = src;
while (count--)
{
	*tmp = *s;
	tmp++;
	s++;
}
return dest;
}
#endif
#ifndef CC_MTK_PRELOADER
int memcmp(const void *cs, const void *ct, size_t count)
{
const unsigned char *su1, *su2;
int res = 0;
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
	if ((res = *su1 - *su2) != 0)
		break;
	return res;
}

char *strcpy(char *dest, const char *src)
{
char *tmp = dest;
while ((*dest++ = *src++) != '\0')
	/* nothing */;
return tmp;
}

size_t strlen(const char *s)
{
const char *sc;
for (sc = s; *sc != '\0'; ++sc)
	/* nothing */;
return sc - s;
}

char *strncpy(char *dest, const char *src, size_t count)
{
char *tmp = dest;	while (count)
	{
	if ((*tmp = *src) != 0)
		src++;
	tmp++;
	count--;
	}
return dest;
}

int strncmp(const char *cs, const char *ct, size_t count)
{
	unsigned char c1, c2;

	while (count) {
		c1 = *cs++;
		c2 = *ct++;
		if (c1 != c2)
			return c1 < c2 ? -1 : 1;
		if (!c1)
			break;
		count--;
	}
	return 0;
}

int strcmp(const char *cs, const char *ct)
{

    for(;*cs==*ct;++cs,++ct)
    	if(*cs=='\0')
    		return 0;
    	return((*(unsigned char*)cs<*(unsigned char*)ct)?-1:+1);
}


char *strncat(char *dest, const char *src, size_t count)
{
	char *tmp = dest;

	if (count) {
		while (*dest)
			dest++;
		while ((*dest++ = *src++) != 0) {
			if (--count == 0) {
				*dest = '\0';
				break;
			}
		}
	}
	return tmp;
}

char *strcat(char *dest, const char *src)
{
	char *tmp = dest;

	while (*dest)
		dest++;
	while ((*dest++ = *src++) != '\0')
		;
	return tmp;
}
#endif
#ifndef CC_MTK_HOTBOOT_START
int raise(int signum)
{
 return 0;
}
#endif
#endif
#ifndef CC_MTK_PRELOADER
void *x_mem_alloc_virtual(UINT32 z_size)
{
    return x_mem_alloc(z_size);
}

void *
x_mem_realloc(void *pv_mem, UINT32 z_new_size)
{
    return x_mem_alloc(z_new_size);
}

void *
x_mem_calloc(UINT32 ui4_ns, UINT32 z_new_size)
{
    VOID *pv_mem = NULL;
    UINT32  *pui4_mem;

    pv_mem = x_mem_alloc(ui4_ns * z_new_size);

    if (pv_mem != NULL)
    {
        pui4_mem = (UINT32 *) pv_mem;
        memset(pui4_mem, 0, z_new_size);
    }
    return(pv_mem);
}

void *x_memset(void *s, int c, UINT32 n)
{
    return (void *)memset(s, c, n);
}
#endif /* CC_MTK_PRELOADER */

void *x_memcmp(void *dest, const void *src, UINT32 z_size)
{
#if defined(CC_MTK_PRELOADER) && defined(__GCC__)
    UINT8 *pu1Dest = (UINT8*)dest;
    UINT8 *pu1Src = (UINT8*)src;

    for( ; z_size > 0; z_size -= 1)
    {
        if( (*pu1Dest) == (*pu1Src))
        {
            pu1Dest += 1;
            pu1Src +=1;
            continue;
        }
        else if((*pu1Dest) > (*pu1Src))
        {
            return (void*)1;
}
        else
{
            return (void*)-1;
        }
    }
    return (void*)0;
#else
    return (void *)memcmp(dest, src, z_size);
#endif
}

void *x_memcpy(void *dest, const void *src, UINT32 z_size)
{
#if defined(CC_MTK_PRELOADER) && defined(__GCC__)
    UINT8 *pu1Dest = (UINT8*)dest;
    UINT8 *pu1Src = (UINT8*)src;

    for( ; z_size > 0; z_size -= 1)
    {
        *pu1Dest = *(UINT8 *)pu1Src;
        pu1Dest += 1;
        pu1Src +=1;
    }

    return pu1Dest;
#else
    return (void *)memcpy(dest, src, z_size);
#endif
}

void __rt_raise(INT32 signal, INT32 type)
{
}

void __rt_SIGFPE()
{
}

#ifndef CC_MTK_PRELOADER
char *x_strcpy(char *dest, const char *src)
{
    return strcpy(dest, src);
}

char *x_strncpy(char *dest, const char *src, UINT32 n)
{
    return strncpy(dest, src, n);
}

UINT32 x_strlen(const char *s)
{
    return strlen(s);
}

int x_strncmp(const char *s1, const char *s2, UINT32 n)
{
    return strncmp(s1, s2, n);
}

int x_strcmp(const char *s1, const char *s2)
{
    return strcmp(s1, s2);
}

char *x_strncat(char *dest, const char *src, UINT32 n)
{
    return strncat(dest, src, n);
}

char *x_strcat(char *dest, const char *src)
{
    return strcat(dest, src);
}

void x_thread_delay(UINT32 u4Ms)
{
    HAL_Delay_us(u4Ms*1000);
}
#endif /* CC_MTK_PRELOADER */

#endif //CC_MTK_LOADER
