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; +}