1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Part of flash simulator which interacts with the host OS
7  *
8  * When building for the native simulator, this file is built in the
9  * native simulator runner/host context, and not in Zephyr/embedded context.
10  */
11 
12 #undef _POSIX_C_SOURCE
13 /* Note: This is used only for interaction with the host C library, and is therefore exempt of
14  * coding guidelines rule A.4&5 which applies to the embedded code using embedded libraries
15  */
16 #define _POSIX_C_SOURCE 200809L
17 
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/mman.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <nsi_tracing.h>
30 
31 /*
32  * Initialize the flash buffer.
33  * And, if the content is to be kept on disk map it to the the buffer to the file.
34  *
35  * Returns -1 on failure
36  *	    0 on success
37  */
flash_mock_init_native(bool flash_in_ram,uint8_t ** mock_flash,unsigned int size,int * flash_fd,const char * flash_file_path,unsigned int erase_value,bool flash_erase_at_start)38 int flash_mock_init_native(bool flash_in_ram, uint8_t **mock_flash, unsigned int size,
39 			   int *flash_fd, const char *flash_file_path,
40 			   unsigned int erase_value, bool flash_erase_at_start)
41 {
42 	struct stat f_stat;
43 	int rc;
44 
45 	if (flash_in_ram == true) {
46 		*mock_flash = (uint8_t *)malloc(size);
47 		if (*mock_flash == NULL) {
48 			nsi_print_warning("Could not allocate flash in the process heap %s\n",
49 					    strerror(errno));
50 			return -1;
51 		}
52 	} else {
53 		*flash_fd = open(flash_file_path, O_RDWR | O_CREAT, (mode_t)0600);
54 		if (*flash_fd == -1) {
55 			nsi_print_warning("Failed to open flash device file "
56 					"%s: %s\n",
57 					flash_file_path, strerror(errno));
58 			return -1;
59 		}
60 
61 		rc = fstat(*flash_fd, &f_stat);
62 		if (rc) {
63 			nsi_print_warning("Failed to get status of flash device file "
64 					"%s: %s\n",
65 					flash_file_path, strerror(errno));
66 			return -1;
67 		}
68 
69 		if (ftruncate(*flash_fd, size) == -1) {
70 			nsi_print_warning("Failed to resize flash device file "
71 					"%s: %s\n",
72 					flash_file_path, strerror(errno));
73 			return -1;
74 		}
75 
76 		*mock_flash = mmap(NULL, size,
77 				PROT_WRITE | PROT_READ, MAP_SHARED, *flash_fd, 0);
78 		if (*mock_flash == MAP_FAILED) {
79 			nsi_print_warning("Failed to mmap flash device file "
80 					"%s: %s\n",
81 					flash_file_path, strerror(errno));
82 			return -1;
83 		}
84 	}
85 
86 	if ((flash_erase_at_start == true) || (flash_in_ram == true) || (f_stat.st_size == 0)) {
87 		/* Erase the memory unit by pulling all bits to the configured erase value */
88 		(void)memset(*mock_flash, erase_value, size);
89 	}
90 
91 	return 0;
92 }
93 
94 /*
95  * If in RAM: Free the mock buffer
96  * If in disk: unmap the flash file from RAM, close the file, and if configured to do so,
97  * delete the file.
98  */
flash_mock_cleanup_native(bool flash_in_ram,int flash_fd,uint8_t * mock_flash,unsigned int size,const char * flash_file_path,bool flash_rm_at_exit)99 void flash_mock_cleanup_native(bool flash_in_ram, int flash_fd, uint8_t *mock_flash,
100 			       unsigned int size, const char *flash_file_path,
101 			       bool flash_rm_at_exit)
102 {
103 
104 	if (flash_in_ram == true) {
105 		if (mock_flash != NULL) {
106 			free(mock_flash);
107 		}
108 		return;
109 	}
110 
111 	if ((mock_flash != MAP_FAILED) && (mock_flash != NULL)) {
112 		munmap(mock_flash, size);
113 	}
114 
115 	if (flash_fd != -1) {
116 		close(flash_fd);
117 	}
118 
119 	if ((flash_rm_at_exit == true) && (flash_file_path != NULL)) {
120 		/* We try to remove the file but do not error out if we can't */
121 		(void) remove(flash_file_path);
122 	}
123 }
124