Align with the latest upstream native simulator 4c595794588f9d7f67fcf0fe05c3db02892a00f9 including: * 4c59579 Makefile: Add option to build native part * 910f934 Makefile: NSI_EXTRA_INCLUDES option and lots of commentary * d9bf489 cmd line parsin: Minor header refactoring * 02f3555 cmd line cleanup: Run as NSI_TASK instead of calling expl. * 2c88173 Split exit call in two * 2b989b4 CPU IF change: nsif_cpu0_cleanup() to return int * e696228 HW scheduler: Add API to get next event time * ae0e9e8 native irq ctrl: Miscellaneous fixes and improvements * 3fd84cd NSI_TASK: Add compile check of valid priority * 7e09fb8 HW events: Change internal storage And two minor updates to the native_sim board, to align with this updated version: * nsif_cpu0_cleanup(void) now must return an int * We need to explicitly tell the native simulator build we want the native components built Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
152 lines
3.6 KiB
C
152 lines
3.6 KiB
C
/*
|
|
* Copyright (c) 2017 Oticon A/S
|
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/*
|
|
* Native simulator entry point (main)
|
|
*
|
|
* Documentation can be found starting in docs/README.md
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include "nsi_cpu_if.h"
|
|
#include "nsi_tasks.h"
|
|
#include "nsi_cmdline_main_if.h"
|
|
#include "nsi_utils.h"
|
|
#include "nsi_hw_scheduler.h"
|
|
|
|
int nsi_exit_inner(int exit_code)
|
|
{
|
|
static int max_exit_code;
|
|
|
|
max_exit_code = NSI_MAX(exit_code, max_exit_code);
|
|
/*
|
|
* nsif_cpu0_cleanup may not return if this is called from a SW thread,
|
|
* but instead it would get nsi_exit() recalled again
|
|
* ASAP from the HW thread
|
|
*/
|
|
int cpu_0_ret = nsif_cpu0_cleanup();
|
|
|
|
max_exit_code = NSI_MAX(cpu_0_ret, max_exit_code);
|
|
|
|
nsi_run_tasks(NSITASK_ON_EXIT_PRE_LEVEL);
|
|
nsi_hws_cleanup();
|
|
nsi_run_tasks(NSITASK_ON_EXIT_POST_LEVEL);
|
|
return max_exit_code;
|
|
}
|
|
|
|
void nsi_exit(int exit_code)
|
|
{
|
|
exit(nsi_exit_inner(exit_code));
|
|
}
|
|
|
|
/**
|
|
* Run all early native_posix initialization steps, including command
|
|
* line parsing and CPU start, until we are ready to let the HW models
|
|
* run via hwm_one_event()
|
|
*/
|
|
static void nsi_init(int argc, char *argv[])
|
|
{
|
|
/*
|
|
* Let's ensure that even if we are redirecting to a file, we get stdout
|
|
* and stderr line buffered (default for console)
|
|
* Note that glibc ignores size. But just in case we set a reasonable
|
|
* number in case somebody tries to compile against a different library
|
|
*/
|
|
setvbuf(stdout, NULL, _IOLBF, 512);
|
|
setvbuf(stderr, NULL, _IOLBF, 512);
|
|
|
|
nsi_run_tasks(NSITASK_PRE_BOOT_1_LEVEL);
|
|
nsif_cpu0_pre_cmdline_hooks();
|
|
|
|
nsi_handle_cmd_line(argc, argv);
|
|
|
|
nsi_run_tasks(NSITASK_PRE_BOOT_2_LEVEL);
|
|
nsif_cpu0_pre_hw_init_hooks();
|
|
|
|
nsi_run_tasks(NSITASK_HW_INIT_LEVEL);
|
|
nsi_hws_init();
|
|
|
|
nsi_run_tasks(NSITASK_PRE_BOOT_3_LEVEL);
|
|
|
|
nsif_cpu0_boot();
|
|
|
|
nsi_run_tasks(NSITASK_FIRST_SLEEP_LEVEL);
|
|
}
|
|
|
|
/**
|
|
* Execute the simulator for at least the specified timeout, then
|
|
* return. Note that this does not affect event timing, so the "next
|
|
* event" may be significantly after the request if the hardware has
|
|
* not been configured to e.g. send an interrupt when expected.
|
|
*/
|
|
void nsi_exec_for(uint64_t us)
|
|
{
|
|
uint64_t start = nsi_hws_get_time();
|
|
|
|
do {
|
|
nsi_hws_one_event();
|
|
} while (nsi_hws_get_time() < (start + us));
|
|
}
|
|
|
|
#ifndef NSI_LIBFUZZER
|
|
|
|
/**
|
|
*
|
|
* Note that this main() is not used when building fuzz cases,
|
|
* as libfuzzer has its own main(),
|
|
* and calls the "OS" through a per-case fuzz test entry point.
|
|
*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
nsi_init(argc, argv);
|
|
while (true) {
|
|
nsi_hws_one_event();
|
|
}
|
|
|
|
/* This line should be unreachable */
|
|
return 1; /* LCOV_EXCL_LINE */
|
|
}
|
|
|
|
#else /* NSI_LIBFUZZER */
|
|
|
|
/**
|
|
* Entry point for fuzzing (when enabled). Works by placing the data
|
|
* into two known symbols, triggering an app-visible interrupt, and
|
|
* then letting the simulator run for a fixed amount of time (intended to be
|
|
* "long enough" to handle the event and reach a quiescent state
|
|
* again)
|
|
*/
|
|
uint8_t *nsi_fuzz_buf, nsi_fuzz_sz;
|
|
|
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz)
|
|
{
|
|
static bool nsi_initialized;
|
|
|
|
if (!nsi_initialized) {
|
|
nsi_init(0, NULL);
|
|
nsi_initialized = true;
|
|
}
|
|
|
|
/* Provide the fuzz data to the embedded OS as an interrupt, with
|
|
* "DMA-like" data placed into nsi_fuzz_buf/sz
|
|
*/
|
|
nsi_fuzz_buf = (void *)data;
|
|
nsi_fuzz_sz = sz;
|
|
hw_irq_ctrl_set_irq(NSI_FUZZ_IRQ);
|
|
|
|
/* Give the OS time to process whatever happened in that
|
|
* interrupt and reach an idle state.
|
|
*/
|
|
nsi_exec_for(NSI_FUZZ_TIME);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* NSI_LIBFUZZER */
|