blob: 7c6476ad0cdf6f6b1840468504f5125c08fc181c [file] [log] [blame]
/*
* Copyright (c) 2015 Wind River Systems, Inc.
*
* Licensed 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.
*/
/**
* @file
* @ brief tests for the mem_probe functionalities
*/
#include <stdio.h>
#include <misc/util.h>
#include <linker-defs.h>
#include <misc/debug/mem_safe.h>
#include <tc_util.h>
#include <cache.h>
#define MY_DATA_SIZE 16
const char __aligned(4) real_rodata[MY_DATA_SIZE] = "0123456789abcdef";
char *rodata = (char *)real_rodata;
char __aligned(4) rwdata[MY_DATA_SIZE+1];
char __aligned(4) buffer[MY_DATA_SIZE+1];
#if MY_DATA_SIZE != 16
#error never verified with values other than 16!
#endif
#define ROM_START ((uint32_t)&_image_rom_start)
#define ROM_END ((uint32_t)&_image_rom_end)
#define RAM_START ((uint32_t)&_image_ram_start)
#define RAM_END ((uint32_t)&_image_ram_end)
char * const p_image_rom_start = (char *)ROM_START;
char * const p_image_rom_end = (char *)ROM_END;
char * const p_image_ram_start = (char *)RAM_START;
char * const p_image_ram_end = (char *)RAM_END;
char *rw_data_after_image = (char *)(RAM_END + KB(1));
char *rw_data_after_image_end;
char *ro_data_after_image = (char *)(RAM_END + KB(3));
char *ro_data_after_image_end;
int foo;
static void update_rv(int *rv, int last_result)
{
*rv = *rv == TC_FAIL ? *rv : last_result;
if (last_result == TC_FAIL) {
TC_PRINT("FAIL\n");
} else {
TC_PRINT("PASS\n");
}
}
#define RO 0
#define RW 1
#define INVALID -1
static int mem_range_check(const void *p)
{
uint32_t addr = (uint32_t)p;
if (addr >= ROM_START && addr < ROM_END) {
return RO;
} else if (addr >= RAM_START && addr < RAM_END) {
return RW;
} else {
return INVALID;
}
}
static int test_width(char *mem, int perm, int width, int expected)
{
char *rights_str = perm == SYS_MEM_SAFE_READ ? "READ" :
perm == SYS_MEM_SAFE_WRITE ? "WRITE" :
"INVALID ACCESS";
int mem_type = mem_range_check(mem);
char *mem_range_str = mem_type == RO ? "RO" :
mem_type == RW ? "RW" : "out-of-image";
TC_PRINT("testing %s of %s on %s memory with width %d.......",
expected == 0 ? "SUCCESS" : "FAILURE",
rights_str, mem_range_str, width);
int rv = _mem_probe(mem, perm, width, buffer);
return rv == expected ? TC_PASS : TC_FAIL;
}
static int test_width_read(char *mem, int width, int expected)
{
return test_width(mem, SYS_MEM_SAFE_READ, width, expected);
}
static int test_width_write(char *mem, int width, int expected)
{
return test_width(mem, SYS_MEM_SAFE_WRITE, width, expected);
}
typedef int (*access_func)(void *, char *, size_t, int);
static int test_mem_safe_access(void *p, char *buf, int size,
int width, int perm)
{
int rc;
char *func_str = (perm == SYS_MEM_SAFE_WRITE) ? "write" : "read";
access_func func = (perm == SYS_MEM_SAFE_WRITE) ?
_mem_safe_write : _mem_safe_read;
TC_PRINT("testing SUCCESS of _mem_safe_%s(size: %d, width: %d).......",
func_str, size, width);
rc = func(p, buf, size, width);
if (rc < 0) {
TC_PRINT("(%d)", rc);
return TC_FAIL;
}
if (memcmp(p, buf, size) != 0) {
TC_PRINT("(bad data)");
return TC_FAIL;
}
return TC_PASS;
}
void main(void)
{
int rv = TC_PASS;
int rc; /* temporary return code */
buffer[MY_DATA_SIZE] = '\0';
rwdata[MY_DATA_SIZE] = '\0';
TC_START("safe memory access routines\n");
/****
* _mem_probe()
*/
/* test access perm */
update_rv(&rv, test_width_read(rodata, 1, 0));
update_rv(&rv, test_width_read(rodata, 2, 0));
update_rv(&rv, test_width_read(rodata, 4, 0));
update_rv(&rv, test_width_write(rodata, 1, -EFAULT));
update_rv(&rv, test_width_write(rodata, 2, -EFAULT));
update_rv(&rv, test_width_write(rodata, 4, -EFAULT));
update_rv(&rv, test_width_read(rwdata, 1, 0));
update_rv(&rv, test_width_read(rwdata, 2, 0));
update_rv(&rv, test_width_read(rwdata, 4, 0));
update_rv(&rv, test_width_write(rwdata, 1, 0));
update_rv(&rv, test_width_write(rwdata, 2, 0));
update_rv(&rv, test_width_write(rwdata, 4, 0));
const int invalid_access_right = 3;
update_rv(&rv, test_width(rwdata, invalid_access_right, 4, -EINVAL));
/* test alignments constraints */
update_rv(&rv, test_width_read(rodata, 0, -EINVAL));
update_rv(&rv, test_width_read(rodata, 1, 0));
update_rv(&rv, test_width_read(rodata, 2, 0));
update_rv(&rv, test_width_read(rodata, 3, -EINVAL));
update_rv(&rv, test_width_read(rodata, 4, 0));
update_rv(&rv, test_width_read(rodata, 5, -EINVAL));
update_rv(&rv, test_width_read(rodata, 8, -EINVAL));
/* test image limits */
update_rv(&rv, test_width_read(p_image_rom_start, 1, 0));
update_rv(&rv, test_width_read(p_image_rom_end - 1, 1, 0));
update_rv(&rv, test_width_read(p_image_ram_start, 1, 0));
update_rv(&rv, test_width_read(p_image_ram_end - 1, 1, 0));
update_rv(&rv, test_width_write(p_image_rom_start, 1, -EFAULT));
update_rv(&rv, test_width_write(p_image_rom_end - 1, 1, -EFAULT));
update_rv(&rv, test_width_write(p_image_ram_start, 1, 0));
update_rv(&rv, test_width_write(p_image_ram_end - 1, 1, 0));
update_rv(&rv, test_width_read(p_image_rom_start - 1, 1, -EFAULT));
update_rv(&rv, test_width_read(p_image_ram_end, 1, -EFAULT));
/* test out-of-image valid regions */
rw_data_after_image_end = rw_data_after_image + KB(1);
ro_data_after_image_end = ro_data_after_image + KB(1);
TC_PRINT("testing SUCCESS of adding extra RO region.......");
int region_add_rc = _mem_safe_region_add(ro_data_after_image, KB(1),
SYS_MEM_SAFE_READ);
if (region_add_rc < 0) {
update_rv(&rv, TC_FAIL);
TC_PRINT("FAIL (%d)\n", region_add_rc);
} else {
TC_PRINT("PASS\n");
}
TC_PRINT("testing SUCCESS of adding extra RW region.......");
region_add_rc = _mem_safe_region_add(rw_data_after_image, KB(1),
SYS_MEM_SAFE_WRITE);
if (region_add_rc < 0) {
update_rv(&rv, TC_FAIL);
TC_PRINT("FAIL (%d)\n", region_add_rc);
} else {
TC_PRINT("PASS\n");
}
TC_PRINT("testing FAILURE of adding extra region that won't fit.......");
region_add_rc = _mem_safe_region_add(rw_data_after_image, KB(1),
SYS_MEM_SAFE_WRITE);
if (region_add_rc < 0) {
TC_PRINT("PASS\n");
} else {
TC_PRINT("FAIL\n");
}
update_rv(&rv, test_width_read(ro_data_after_image, 1, 0));
update_rv(&rv, test_width_read(ro_data_after_image_end - 1, 1, 0));
update_rv(&rv, test_width_read(rw_data_after_image, 1, 0));
update_rv(&rv, test_width_read(rw_data_after_image_end - 1, 1, 0));
update_rv(&rv, test_width_write(ro_data_after_image, 1, -EFAULT));
update_rv(&rv, test_width_write(ro_data_after_image_end - 1, 1, -EFAULT));
update_rv(&rv, test_width_write(rw_data_after_image, 1, 0));
update_rv(&rv, test_width_write(rw_data_after_image_end - 1, 1, 0));
update_rv(&rv, test_width_read(ro_data_after_image - 1, 1, -EFAULT));
update_rv(&rv, test_width_read(ro_data_after_image_end, 1, -EFAULT));
update_rv(&rv, test_width_read(rw_data_after_image - 1, 1, -EFAULT));
update_rv(&rv, test_width_read(rw_data_after_image_end, 1, -EFAULT));
/*
* Test the dividing line between rom and ram, even in non-xip images:
* it might hit ROM or invalid memory, but never RAM.
*/
update_rv(&rv, test_width_write(p_image_ram_start - 1, 1, -EFAULT));
TC_PRINT("testing SUCCESS of _mem_probe() reading RO values.......");
(void)_mem_probe(rodata, SYS_MEM_SAFE_READ, 4, buffer);
(void)_mem_probe(rodata+4, SYS_MEM_SAFE_READ, 4, buffer+4);
(void)_mem_probe(rodata+8, SYS_MEM_SAFE_READ, 2, buffer+8);
(void)_mem_probe(rodata+10, SYS_MEM_SAFE_READ, 2, buffer+10);
(void)_mem_probe(rodata+12, SYS_MEM_SAFE_READ, 1, buffer+12);
(void)_mem_probe(rodata+13, SYS_MEM_SAFE_READ, 1, buffer+13);
(void)_mem_probe(rodata+14, SYS_MEM_SAFE_READ, 1, buffer+14);
(void)_mem_probe(rodata+15, SYS_MEM_SAFE_READ, 1, buffer+15);
if (memcmp(rodata, buffer, 16) != 0) {
TC_PRINT("FAIL\n");
update_rv(&rv, TC_FAIL);
} else {
TC_PRINT("PASS\n");
}
memcpy(rwdata, rodata, MY_DATA_SIZE);
memset(buffer, '-', MY_DATA_SIZE);
TC_PRINT("testing SUCCESS of _mem_probe() reading RW values.......");
(void)_mem_probe(rwdata, SYS_MEM_SAFE_READ, 4, buffer);
(void)_mem_probe(rwdata+4, SYS_MEM_SAFE_READ, 4, buffer+4);
(void)_mem_probe(rwdata+8, SYS_MEM_SAFE_READ, 2, buffer+8);
(void)_mem_probe(rwdata+10, SYS_MEM_SAFE_READ, 2, buffer+10);
(void)_mem_probe(rwdata+12, SYS_MEM_SAFE_READ, 1, buffer+12);
(void)_mem_probe(rwdata+13, SYS_MEM_SAFE_READ, 1, buffer+13);
(void)_mem_probe(rwdata+14, SYS_MEM_SAFE_READ, 1, buffer+14);
(void)_mem_probe(rwdata+15, SYS_MEM_SAFE_READ, 1, buffer+15);
if (memcmp(rwdata, buffer, 16) != 0) {
TC_PRINT("FAIL\n");
update_rv(&rv, TC_FAIL);
} else {
TC_PRINT("PASS\n");
}
memcpy(buffer, rodata, MY_DATA_SIZE);
memset(rwdata, '-', MY_DATA_SIZE);
TC_PRINT("testing SUCCESS of _mem_probe() writing values.......");
(void)_mem_probe(rwdata, SYS_MEM_SAFE_WRITE, 4, buffer);
(void)_mem_probe(rwdata+4, SYS_MEM_SAFE_WRITE, 4, buffer+4);
(void)_mem_probe(rwdata+8, SYS_MEM_SAFE_WRITE, 2, buffer+8);
(void)_mem_probe(rwdata+10, SYS_MEM_SAFE_WRITE, 2, buffer+10);
(void)_mem_probe(rwdata+12, SYS_MEM_SAFE_WRITE, 1, buffer+12);
(void)_mem_probe(rwdata+13, SYS_MEM_SAFE_WRITE, 1, buffer+13);
(void)_mem_probe(rwdata+14, SYS_MEM_SAFE_WRITE, 1, buffer+14);
(void)_mem_probe(rwdata+15, SYS_MEM_SAFE_WRITE, 1, buffer+15);
if (memcmp(rwdata, buffer, 16) != 0) {
TC_PRINT("FAIL\n");
update_rv(&rv, TC_FAIL);
} else {
TC_PRINT("PASS\n");
}
/*****
* _mem_safe_read()
*/
memset(buffer, '-', MY_DATA_SIZE);
update_rv(&rv, test_mem_safe_access(rodata, buffer, MY_DATA_SIZE,
0, SYS_MEM_SAFE_READ));
update_rv(&rv, test_mem_safe_access(rodata, buffer, MY_DATA_SIZE,
4, SYS_MEM_SAFE_READ));
update_rv(&rv, test_mem_safe_access(rodata, buffer, MY_DATA_SIZE-2,
2, SYS_MEM_SAFE_READ));
update_rv(&rv, test_mem_safe_access(rodata, buffer, MY_DATA_SIZE-1,
1, SYS_MEM_SAFE_READ));
TC_PRINT("testing FAILURE of _mem_safe_read() with bad params.......");
rc = _mem_safe_read(rodata+1, buffer, MY_DATA_SIZE-1, 2);
if (rc == 0) {
TC_PRINT("FAIL\n");
update_rv(&rv, TC_FAIL);
} else {
TC_PRINT("PASS (%d)\n", rc);
}
/*****
* _mem_safe_write()
*/
memcpy(buffer, rodata, MY_DATA_SIZE);
memset(rwdata, '-', MY_DATA_SIZE);
update_rv(&rv, test_mem_safe_access(rwdata, buffer, MY_DATA_SIZE,
0, SYS_MEM_SAFE_WRITE));
memcpy(buffer, rodata, MY_DATA_SIZE);
memset(rwdata, '-', MY_DATA_SIZE);
update_rv(&rv, test_mem_safe_access(rwdata, buffer, MY_DATA_SIZE,
4, SYS_MEM_SAFE_WRITE));
memcpy(buffer, rodata, MY_DATA_SIZE);
memset(rwdata, '-', MY_DATA_SIZE);
update_rv(&rv, test_mem_safe_access(rwdata, buffer, MY_DATA_SIZE - 2,
2, SYS_MEM_SAFE_WRITE));
memcpy(buffer, rodata, MY_DATA_SIZE);
memset(rwdata, '-', MY_DATA_SIZE);
update_rv(&rv, test_mem_safe_access(rwdata, buffer, MY_DATA_SIZE - 1,
1, SYS_MEM_SAFE_WRITE));
memcpy(buffer, rodata, MY_DATA_SIZE);
memset(rwdata, '-', MY_DATA_SIZE);
TC_PRINT("testing FAILURE of _mem_safe_write() with bad params.......");
rc = _mem_safe_write(rwdata+1, buffer, MY_DATA_SIZE-1, 2);
if (rc == 0) {
TC_PRINT("FAIL\n");
update_rv(&rv, TC_FAIL);
} else {
TC_PRINT("PASS (%d)\n", rc);
}
#if !defined(CONFIG_XIP)
/*****
* _mem_safe_write_to_text_section()
*/
extern void add_ten_to_foo(void);
foo = 0;
memset(buffer, 0x90, 7);
TC_PRINT("testing FAILURE of _mem_safe_write_to_text_section(&data).......");
if (_mem_safe_write_to_text_section(&foo, buffer, 1) == 0) {
TC_PRINT("FAIL\n");
} else {
TC_PRINT("PASS\n");
}
TC_PRINT("testing SUCCESS of _mem_safe_write_to_text_section(&text).......");
add_ten_to_foo();
if (foo != 10) {
TC_PRINT("FAIL\n");
} else {
if (_mem_safe_write_to_text_section((void *)add_ten_to_foo,
buffer, 7) < 0) {
TC_PRINT("FAIL\n");
} else {
sys_cache_flush((vaddr_t)add_ten_to_foo, 7);
add_ten_to_foo();
if (foo != 10) {
TC_PRINT("FAIL\n");
} else {
TC_PRINT("PASS\n");
}
}
}
#endif
TC_END_RESULT(rv);
TC_END_REPORT(rv);
}