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 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/mman.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdbool.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <nsi_tracing.h>
24 
25 /*
26  * Initialize the flash buffer.
27  * And, if the content is to be kept on disk map it to the the buffer to the file.
28  *
29  * Returns -1 on failure
30  *	    0 on success
31  */
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)32 int flash_mock_init_native(bool flash_in_ram, uint8_t **mock_flash, unsigned int size,
33 			   int *flash_fd, const char *flash_file_path,
34 			   unsigned int erase_value, bool flash_erase_at_start)
35 {
36 	struct stat f_stat;
37 	int rc;
38 
39 	if (flash_in_ram == true) {
40 		*mock_flash = (uint8_t *)malloc(size);
41 		if (*mock_flash == NULL) {
42 			nsi_print_warning("Could not allocate flash in the process heap %s\n",
43 					    strerror(errno));
44 			return -1;
45 		}
46 	} else {
47 		*flash_fd = open(flash_file_path, O_RDWR | O_CREAT, (mode_t)0600);
48 		if (*flash_fd == -1) {
49 			nsi_print_warning("Failed to open flash device file "
50 					"%s: %s\n",
51 					flash_file_path, strerror(errno));
52 			return -1;
53 		}
54 
55 		rc = fstat(*flash_fd, &f_stat);
56 		if (rc) {
57 			nsi_print_warning("Failed to get status of flash device file "
58 					"%s: %s\n",
59 					flash_file_path, strerror(errno));
60 			return -1;
61 		}
62 
63 		if (ftruncate(*flash_fd, size) == -1) {
64 			nsi_print_warning("Failed to resize flash device file "
65 					"%s: %s\n",
66 					flash_file_path, strerror(errno));
67 			return -1;
68 		}
69 
70 		*mock_flash = mmap(NULL, size,
71 				PROT_WRITE | PROT_READ, MAP_SHARED, *flash_fd, 0);
72 		if (*mock_flash == MAP_FAILED) {
73 			nsi_print_warning("Failed to mmap flash device file "
74 					"%s: %s\n",
75 					flash_file_path, strerror(errno));
76 			return -1;
77 		}
78 	}
79 
80 	if ((flash_erase_at_start == true) || (flash_in_ram == true) || (f_stat.st_size == 0)) {
81 		/* Erase the memory unit by pulling all bits to the configured erase value */
82 		(void)memset(*mock_flash, erase_value, size);
83 	}
84 
85 	return 0;
86 }
87 
88 /*
89  * If in RAM: Free the mock buffer
90  * If in disk: unmap the flash file from RAM, close the file, and if configured to do so,
91  * delete the file.
92  */
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)93 void flash_mock_cleanup_native(bool flash_in_ram, int flash_fd, uint8_t *mock_flash,
94 			       unsigned int size, const char *flash_file_path,
95 			       bool flash_rm_at_exit)
96 {
97 
98 	if (flash_in_ram == true) {
99 		if (mock_flash != NULL) {
100 			free(mock_flash);
101 		}
102 		return;
103 	}
104 
105 	if ((mock_flash != MAP_FAILED) && (mock_flash != NULL)) {
106 		munmap(mock_flash, size);
107 	}
108 
109 	if (flash_fd != -1) {
110 		close(flash_fd);
111 	}
112 
113 	if ((flash_rm_at_exit == true) && (flash_file_path != NULL)) {
114 		/* We try to remove the file but do not error out if we can't */
115 		(void) remove(flash_file_path);
116 	}
117 }
118