From 09ec04760fc1f374fc59336aa442b72b11e7a198 Mon Sep 17 00:00:00 2001 From: chenrun1 Date: Wed, 28 Feb 2024 15:06:07 +0800 Subject: [PATCH] cachetest:Tools for testing cache and uncacheable Summary: A tool is provided to test the case of data correctness after cache flush. It requires an uncacheable offset to check whether the uncacheable address is consistent with the data in the buffer after calling up_dcache_flush. Signed-off-by: chenrun1 --- testing/cachetest/Kconfig | 29 ++++ testing/cachetest/Make.defs | 23 +++ testing/cachetest/Makefile | 32 ++++ testing/cachetest/cachetest_main.c | 265 +++++++++++++++++++++++++++++ 4 files changed, 349 insertions(+) create mode 100644 testing/cachetest/Kconfig create mode 100644 testing/cachetest/Make.defs create mode 100644 testing/cachetest/Makefile create mode 100644 testing/cachetest/cachetest_main.c diff --git a/testing/cachetest/Kconfig b/testing/cachetest/Kconfig new file mode 100644 index 000000000..e127d918e --- /dev/null +++ b/testing/cachetest/Kconfig @@ -0,0 +1,29 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config TESTING_CACHETEST + tristate "Cache Test" + default n + ---help--- + Enable a simple Cache test. + +if TESTING_CACHETEST + +config TESTING_CACHETEST_PROGNAME + string "Program name" + default "cachetest" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config TESTING_CACHETEST_PRIORITY + int "Cache test task priority" + default 100 + +config TESTING_CACHETEST_STACKSIZE + int "Cache test stack size" + default DEFAULT_TASK_STACKSIZE + +endif diff --git a/testing/cachetest/Make.defs b/testing/cachetest/Make.defs new file mode 100644 index 000000000..875f334d2 --- /dev/null +++ b/testing/cachetest/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/testing/cachetest/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_TESTING_CACHETEST),) +CONFIGURED_APPS += $(APPDIR)/testing/cachetest +endif diff --git a/testing/cachetest/Makefile b/testing/cachetest/Makefile new file mode 100644 index 000000000..7d84880f9 --- /dev/null +++ b/testing/cachetest/Makefile @@ -0,0 +1,32 @@ +############################################################################ +# apps/testing/cachetest/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# Cache test + +PROGNAME = $(CONFIG_TESTING_CACHETEST_PROGNAME) +PRIORITY = $(CONFIG_TESTING_CACHETEST_PRIORITY) +STACKSIZE = $(CONFIG_TESTING_CACHETEST_STACKSIZE) +MODULE = $(CONFIG_TESTING_CACHETEST) + +MAINSRC = cachetest_main.c + +include $(APPDIR)/Application.mk diff --git a/testing/cachetest/cachetest_main.c b/testing/cachetest/cachetest_main.c new file mode 100644 index 000000000..9496432dc --- /dev/null +++ b/testing/cachetest/cachetest_main.c @@ -0,0 +1,265 @@ +/**************************************************************************** + * apps/testing/cachetest/cachetest_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CACHETEST_PREFIX "CACHE Test: " + +#define OPTARG_TO_VALUE(value, type, base) \ + do \ + { \ + FAR char *ptr; \ + value = (type)strtoul(optarg, &ptr, base); \ + if (*ptr != '\0') \ + { \ + syslog(LOG_ERR, CACHETEST_PREFIX "Parameter error -%c %s\n", ch, \ + optarg); \ + cahcetest_show_usage(); \ + } \ + } while (0) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct cachetest_s +{ + FAR char *wbuf; + FAR char *rbuf; + FAR char *waddr; + uintptr_t offset; + size_t size; + int repeat_num; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cahcetest_show_usage + ****************************************************************************/ + +static void cahcetest_show_usage(void) +{ + printf("\nUsage: %s -s [buffer-size] -f [offset] -n [repeat-number]\n", + CONFIG_TESTING_CACHETEST_PROGNAME); + printf("\nWhere:\n"); + printf(" -s [buffer-size] number of memory alloc for buffer" + "(in bytes). [Default Size: 1MB] \n"); + printf(" -f [offset] offset to uncacheble address [Default: 0]\n"); + printf(" -n [repeat-number] number of repetitions" + " [default value: unlimited].\n"); + exit(EXIT_FAILURE); +} + +/**************************************************************************** + * Name: cachetest_parse_commandline + ****************************************************************************/ + +static void cachetest_parse_commandline(int argc, FAR char **argv, + FAR struct cachetest_s *info) +{ + int ch; + + /* Default size: 1M */ + + memset(info, 0, sizeof(struct cachetest_s)); + info->size = 1024 * 1024; + + while ((ch = getopt(argc, argv, "s::n::f::i")) != ERROR) + { + switch (ch) + { + case 's': + OPTARG_TO_VALUE(info->size, size_t, 10); + break; + case 'n': + OPTARG_TO_VALUE(info->repeat_num, int, 10); + break; + case 'f': + OPTARG_TO_VALUE(info->offset, uintptr_t, 16); + break; + case '?': + cahcetest_show_usage(); + break; + } + } + + info->wbuf = zalloc(info->size); + if (info->wbuf == NULL) + { + syslog(LOG_ERR, CACHETEST_PREFIX "Alloc memory for info->wbuf" + "failed:%d\n", + ENOMEM); + exit(EXIT_FAILURE); + } + + info->rbuf = zalloc(info->size); + if (info->rbuf == NULL) + { + free(info->wbuf); + syslog(LOG_ERR, CACHETEST_PREFIX "Alloc memory for info->rbuf" + "failed:%d\n", + ENOMEM); + exit(EXIT_FAILURE); + } + + info->waddr = zalloc(info->size); + if (info->waddr == NULL) + { + free(info->wbuf); + free(info->rbuf); + syslog(LOG_ERR, CACHETEST_PREFIX "Alloc memory for info->waddr" + "failed:%d\n", + ENOMEM); + exit(EXIT_FAILURE); + } + + syslog(LOG_INFO, CACHETEST_PREFIX "waddr:%p, uncacheble addr start:%p," + "size:%u\n", info->waddr, + (FAR char *)((uintptr_t)info->waddr | info->offset), info->size); +} + +/**************************************************************************** + * Name: cachetest_teardown + ****************************************************************************/ + +static void cachetest_teardown(FAR struct cachetest_s *info) +{ + free(info->waddr); + free(info->rbuf); + free(info->wbuf); +} + +/**************************************************************************** + * Name: cachetest_randchar + ****************************************************************************/ + +static inline char cachetest_randchar(void) +{ + int value = random() % 63; + if (value == 0) + { + return '0'; + } + else if (value <= 10) + { + return value + '0' - 1; + } + else if (value <= 36) + { + return value + 'a' - 11; + } + else + { + return value + 'A' - 37; + } +} + +/**************************************************************************** + * Name: cachetest_randcontext + ****************************************************************************/ + +static void cachetest_randcontext(uint32_t size, FAR void *input) +{ + /* Construct a buffer here and fill it with random characters */ + + int i; + FAR char *tmp; + tmp = input; + for (i = 0; i < size - 1; i++) + { + tmp[i] = cachetest_randchar(); + } + + tmp[i] = '\0'; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cachetest_main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + FAR char *ptr; + struct cachetest_s info; + + /* Prepare parameters */ + + cachetest_parse_commandline(argc, argv, &info); + + /* If there is no set number of times to repeat, it will loop continuously + * by default. + */ + + for (int loop = 1; ((!info.repeat_num) || loop <= info.repeat_num); + loop++) + { + cachetest_randcontext(info.size, info.wbuf); + + /* Get uncacheable address */ + + ptr = (FAR char *)((uintptr_t)info.waddr | info.offset); + + memcpy(info.waddr, info.wbuf, info.size); + + up_flush_dcache((uintptr_t)info.waddr, (uintptr_t)info.waddr + + info.size); + + for (size_t i = 0; i < info.size; i++) + { + info.rbuf[i] = *ptr++; + } + + if (memcmp(info.wbuf, info.rbuf, info.size) != 0) + { + syslog(LOG_ERR, CACHETEST_PREFIX "comparison failed!\n"); + } + else + { + syslog(LOG_INFO, CACHETEST_PREFIX "comparsion success!\n"); + } + + /* To prevent tasks from being occupied all the time, switch + * scheduling through usleep. + */ + + usleep(1); + } + + cachetest_teardown(&info); + + return 0; +}