| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include "sw/device/lib/arch/device.h" |
| #include "sw/device/lib/base/log.h" |
| #include "sw/device/lib/base/print.h" |
| #include "sw/device/lib/base/stdasm.h" |
| #include "sw/device/lib/runtime/check.h" |
| #include "sw/device/lib/testing/test_status.h" |
| #include "sw/device/lib/uart.h" |
| |
| // Symbols defined in sw/device/exts/common/flash_link.ld, which we use to |
| // check that the CRT did what it was supposed to. |
| extern char _bss_start; |
| extern char _bss_end; |
| extern char _data_start; |
| extern char _data_end; |
| extern char _data_init_start; |
| |
| // The addresses of the values above. |
| static const uintptr_t bss_start_addr = (uintptr_t)&_bss_start; |
| static const uintptr_t bss_end_addr = (uintptr_t)&_bss_end; |
| static const uintptr_t data_start_addr = (uintptr_t)&_data_start; |
| static const uintptr_t data_end_addr = (uintptr_t)&_data_end; |
| static const uintptr_t data_init_start_addr = (uintptr_t)&_data_init_start; |
| |
| // Ensure that both .bss and .data are non-empty. The compiler will always keep |
| // these symbols, since they're volatile. |
| volatile char ensure_data_exists = 42; |
| volatile char ensure_bss_exists; |
| |
| int main(int argc, char **argv) { |
| // NOTE: we cannot call any external functions until all checks of post-CRT |
| // state are complete; this is to ensure that our checks are not tainted by |
| // external functions. |
| // |
| // Among other things, this means we can't CHECK, since we can't initialize |
| // UART. Thus, any critical failures are handled by returning from main. |
| // To minimize the chance of things going wrong, we don't even bother placing |
| // the checks in their own function. |
| |
| // Test core assumptions above the five addresses above. The test code |
| // must be able to assume these all hold. |
| // |
| // Note that performing these comparisons on their addresses is UB, and will |
| // cause this entire function to get deleted by the compiler. |
| if (&_bss_start > &_bss_end || &_data_start > &_data_end) { |
| // Something has gone terribly wrong and we have no hope of continuing the |
| // test, so we're going to return and let the test time out. |
| // |
| // The best method for debugging a failure like this is to stare at an |
| // instruction trace. |
| return 1; |
| } |
| |
| // Ensure that .bss was *actually* zeroed at the start of execution. If it |
| // wasn't, we note the offset from _bss_start at which it wasn't. |
| char *bss = &_bss_start; |
| ptrdiff_t bss_len = &_bss_end - &_bss_start; |
| int bad_bss_index = -1; |
| for (int i = 0; i < bss_len; ++i) { |
| if (bss[i] != 0) { |
| bad_bss_index = i; |
| break; |
| } |
| } |
| |
| // Similarly, ensure that .data has the values in the init section. |
| char *data = &_data_start; |
| char *data_init = &_data_init_start; |
| ptrdiff_t data_len = &_data_end - &_data_start; |
| int bad_data_index = -1; |
| for (int i = 0; i < data_len; ++i) { |
| if (data[i] != data_init[i]) { |
| bad_data_index = i; |
| break; |
| } |
| } |
| |
| // End of post-CRT checks; begin actual assertions.. |
| test_status_set(kTestStatusInTest); |
| // Initialize the UART to enable logging for non-DV simulation platforms. |
| if (kDeviceType != kDeviceSimDV) { |
| uart_init(kUartBaudrate); |
| base_set_stdout(uart_stdout); |
| } |
| |
| CHECK(bss_start_addr % sizeof(uint32_t) == 0, |
| "_bss_start not word-aligned: 0x%08x", bss_start_addr); |
| CHECK(bss_end_addr % sizeof(uint32_t) == 0, |
| "_bss_end not word-aligned: 0x%08x", bss_end_addr); |
| CHECK(data_start_addr % sizeof(uint32_t) == 0, |
| "_data_start not word-aligned: 0x%08x", data_start_addr); |
| CHECK(data_end_addr % sizeof(uint32_t) == 0, |
| "_data_end not word-aligned: 0x%08x", data_end_addr); |
| CHECK(data_init_start_addr % sizeof(uint32_t) == 0, |
| "_data_init_start not word-aligned: 0x%08x", data_init_start_addr); |
| |
| CHECK(bad_bss_index == -1, "found non-zero .bss byte at *0x%08x == 0x%02x", |
| bss_start_addr + bad_bss_index, (uint32_t)bss[bad_bss_index]); |
| CHECK(bad_data_index == -1, |
| "found bad .data byte at *0x%08x == 0x%02x, expected 0x%02x", |
| data_start_addr + bad_data_index, (uint32_t)data_init[bad_data_index]); |
| |
| test_status_set(kTestStatusPassed); |
| |
| // Unreachable code. |
| return 1; |
| } |