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