195 lines
4.8 KiB
C
195 lines
4.8 KiB
C
|
/*
|
||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||
|
*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*
|
||
|
* Change Logs:
|
||
|
* Date Author Notes
|
||
|
* 2023-03-17 WangXiaoyao cache API unit test
|
||
|
*/
|
||
|
|
||
|
#ifndef __TEST_CACHE_RV64_H
|
||
|
#define __TEST_CACHE_RV64_H
|
||
|
|
||
|
#ifdef ARCH_RISCV64
|
||
|
#include "riscv_mmu.h"
|
||
|
#include <utest.h>
|
||
|
#include <cache.h>
|
||
|
#include <page.h>
|
||
|
#include <mmu.h>
|
||
|
#include <ioremap.h>
|
||
|
|
||
|
/**
|
||
|
* ==============================================================
|
||
|
* TEST FEATURE
|
||
|
* API under cache.h
|
||
|
* rt_hw_sync_cache_local
|
||
|
*
|
||
|
* rt_hw_cpu_dcache_clean
|
||
|
* rt_hw_cpu_dcache_invalidate
|
||
|
* rt_hw_cpu_dcache_clean_invalidate
|
||
|
* rt_hw_cpu_dcache_clean_all
|
||
|
* rt_hw_cpu_dcache_invalidate_all // meaningless
|
||
|
* rt_hw_cpu_dcache_clean_invalidate_all
|
||
|
* rt_hw_cpu_icache_invalidate
|
||
|
* rt_hw_cpu_icache_invalidate_all
|
||
|
* ==============================================================
|
||
|
*/
|
||
|
|
||
|
/* Ensure the ISA is valid for target ARCHITECTURE */
|
||
|
static void _illegal_instr(void)
|
||
|
{
|
||
|
rt_hw_sync_cache_local(_illegal_instr, 64);
|
||
|
rt_hw_cpu_dcache_clean(_illegal_instr, 64);
|
||
|
rt_hw_cpu_dcache_invalidate(_illegal_instr, 64);
|
||
|
// rt_hw_cpu_dcache_clean_invalidate(_illegal_instr, 64); // C908 ONLY
|
||
|
rt_hw_cpu_dcache_clean_all();
|
||
|
rt_hw_cpu_dcache_invalidate_all(); // !CAREFUL must be inline
|
||
|
// rt_hw_cpu_dcache_clean_invalidate_all(); // C908 ONLY
|
||
|
rt_hw_cpu_icache_invalidate(_illegal_instr, 64);
|
||
|
rt_hw_cpu_icache_invalidate_all();
|
||
|
uassert_true(1);
|
||
|
LOG_I("All ok!");
|
||
|
}
|
||
|
|
||
|
static int _get1(void)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int _get2(void)
|
||
|
{
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
/* hot patching codes and test if the value can be seen by icache */
|
||
|
static void _test_cache_sync(void)
|
||
|
{
|
||
|
uassert_true(1 == _get1());
|
||
|
rt_memcpy(_get1, _get2, _get2 - _get1);
|
||
|
uassert_true(1 == _get1());
|
||
|
rt_hw_sync_cache_local(_get1, _get2 - _get1);
|
||
|
uassert_true(2 == _get1());
|
||
|
LOG_I("%s ok", __func__);
|
||
|
}
|
||
|
|
||
|
/* test clean operation should do and only effect the range specified by writing to a page */
|
||
|
static void _test_dcache_clean(void)
|
||
|
{
|
||
|
const size_t padding = 1024 * 3;
|
||
|
const size_t buf_sz = ARCH_PAGE_SIZE * 2;
|
||
|
|
||
|
char *page = rt_pages_alloc(rt_page_bits(buf_sz));
|
||
|
uassert_true(!!page);
|
||
|
|
||
|
/* after ioremap, we can access system memory to verify outcome */
|
||
|
volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz);
|
||
|
rt_memset(page, 0xab, buf_sz);
|
||
|
rt_hw_cpu_sync();
|
||
|
|
||
|
int _outdate_flag = 0;
|
||
|
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
|
||
|
{
|
||
|
if (remap_nocache[i] != 0xab)
|
||
|
{
|
||
|
_outdate_flag = 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
page[padding - 1] = 0xac;
|
||
|
page[padding + ARCH_PAGE_SIZE] = 0xac;
|
||
|
rt_hw_cpu_dcache_clean(page + padding, ARCH_PAGE_SIZE);
|
||
|
|
||
|
/* free some space in dcache to avoid padding data being written back */
|
||
|
rt_hw_cpu_dcache_invalidate(page + padding, ARCH_PAGE_SIZE);
|
||
|
uassert_true(remap_nocache[padding - 1] != 0xac);
|
||
|
uassert_true(remap_nocache[padding + ARCH_PAGE_SIZE] != 0xac);
|
||
|
|
||
|
int _test_ok = 1;
|
||
|
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
|
||
|
{
|
||
|
if (remap_nocache[i] != 0xab)
|
||
|
{
|
||
|
_test_ok = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
uassert_true(_test_ok);
|
||
|
|
||
|
if (!_outdate_flag)
|
||
|
LOG_W("Cannot guarantee clean works");
|
||
|
else
|
||
|
LOG_I("%s ok", __func__);
|
||
|
|
||
|
rt_pages_free(page, 0);
|
||
|
rt_iounmap(remap_nocache);
|
||
|
}
|
||
|
|
||
|
/* test clean op should do and only effect the range */
|
||
|
static void _test_dcache_invalidate(void)
|
||
|
{
|
||
|
const size_t padding = 1024 * 3;
|
||
|
const size_t buf_sz = ARCH_PAGE_SIZE * 2;
|
||
|
|
||
|
/* prepare */
|
||
|
char *page = rt_pages_alloc(rt_page_bits(buf_sz));
|
||
|
uassert_true(!!page);
|
||
|
|
||
|
volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz);
|
||
|
rt_memset(page, 0x0, buf_sz);
|
||
|
rt_hw_cpu_sync();
|
||
|
|
||
|
int _outdate_flag = 0;
|
||
|
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
|
||
|
{
|
||
|
remap_nocache[i] = 0xab;
|
||
|
rt_hw_cpu_dcache_invalidate((void *)&remap_nocache[i], 1);
|
||
|
}
|
||
|
|
||
|
rt_hw_cpu_dcache_clean_all();
|
||
|
|
||
|
int _test_ok = 1;
|
||
|
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
|
||
|
{
|
||
|
if (remap_nocache[i] == 0xab)
|
||
|
{
|
||
|
_test_ok = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
uassert_true(_test_ok);
|
||
|
|
||
|
LOG_I("%s ok", __func__);
|
||
|
|
||
|
rt_pages_free(page, 0);
|
||
|
rt_iounmap(remap_nocache);
|
||
|
}
|
||
|
|
||
|
static rt_err_t utest_tc_init(void)
|
||
|
{
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
static rt_err_t utest_tc_cleanup(void)
|
||
|
{
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
static void testcase(void)
|
||
|
{
|
||
|
UTEST_UNIT_RUN(_illegal_instr);
|
||
|
#ifdef BOARD_allwinnerd1s
|
||
|
/* thead ISA extension */
|
||
|
UTEST_UNIT_RUN(_test_cache_sync);
|
||
|
/* part of it is hard to test on simulation machine */
|
||
|
UTEST_UNIT_RUN(_test_dcache_clean);
|
||
|
UTEST_UNIT_RUN(_test_dcache_invalidate);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
UTEST_TC_EXPORT(testcase, "testcases.libcpu.cache", utest_tc_init, utest_tc_cleanup, 10);
|
||
|
|
||
|
#endif /* ARCH_RISCV64 */
|
||
|
#endif /* __TEST_CACHE_RV64_H */
|