1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * Backend for the Non-Volatile Memory devices
9  * which can use files on disk or just host RAM
10  * to keep their content.
11  */
12 
13 #include <string.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/mman.h>
22 #include "bs_tracing.h"
23 #include "bs_oswrap.h"
24 #include "bs_compat.h"
25 #include "NHW_NVM_backend.h"
26 
27 /**
28  * At boot, do whatever is necessary for a given storage
29  * (allocate memory, open files etc. )
30  */
nhw_nvm_initialize_data_storage(nvm_storage_state_t * st)31 void nhw_nvm_initialize_data_storage(nvm_storage_state_t *st){
32   struct stat f_stat;
33   int rc;
34 
35   st->fd = -1;
36   st->storage = NULL;
37 
38   if (st->in_ram == true) {
39     st->storage = (uint8_t *)bs_malloc(st->size);
40 
41   } else {
42 
43     _bs_create_folders_in_path(st->file_path);
44     st->fd = open(st->file_path, O_RDWR | O_CREAT, (mode_t)0600);
45     if (st->fd == -1) {
46       bs_trace_error_line("%s: Failed to open %s device file %s: %s\n",
47           __func__, st->type_s, st->file_path, strerror(errno));
48     }
49 
50     rc = fstat(st->fd, &f_stat);
51     if (rc) {
52       bs_trace_error_line("%s: Failed to get status of %s device file %s: %s\n",
53           __func__, st->type_s, st->file_path, strerror(errno));
54     }
55 
56     if (ftruncate(st->fd, st->size) == -1) {
57       bs_trace_error_line("%s: Failed to resize %s device file %s: %s\n",
58           __func__, st->type_s, st->file_path, strerror(errno));
59     }
60 
61     st->storage = mmap(NULL, st->size, PROT_WRITE | PROT_READ, MAP_SHARED, st->fd, 0);
62     if (st->storage == MAP_FAILED) {
63       bs_trace_error_line("%s: Failed to mmap %s device file %s: %s\n",
64           __func__, st->type_s, st->file_path, strerror(errno));
65     }
66   }
67 
68   if ((st->erase_at_start == true) || (st->in_ram == true) || (f_stat.st_size == 0)) {
69     /* Erase the memory unit by pulling all bits to the configured erase value */
70     (void)memset(st->storage, 0xFF, st->size);
71   }
72 }
73 
nhw_nvm_init_storage(nvm_storage_state_t * st,struct nhw_nvm_st_args_t * args,size_t size,char * type_s)74 void nhw_nvm_init_storage(nvm_storage_state_t *st, struct nhw_nvm_st_args_t *args,
75                           size_t size, char *type_s)
76 {
77   st->file_path      = args->file;
78   st->erase_at_start = args->erase;
79   st->rm_at_exit     = args->rm;
80   st->in_ram         = args->in_ram;
81   st->size           = size;
82   st->type_s         = type_s;
83 
84   nhw_nvm_initialize_data_storage(st);
85 }
86 
87 /**
88  * Before exiting the program, do whatever is
89  * necessary for a given storage (free'ing heap,
90  * closing file descriptors, etc)
91  */
nhw_nvm_clear_storage(nvm_storage_state_t * st)92 void nhw_nvm_clear_storage(nvm_storage_state_t *st){
93 
94   if (st->in_ram == true) {
95     if (st->storage != NULL) {
96       free(st->storage);
97       st->storage = NULL;
98     }
99     return;
100   }
101 
102   if ((st->storage != MAP_FAILED) && (st->storage != NULL)) {
103     munmap(st->storage, st->size);
104     st->storage = NULL;
105   }
106 
107   if (st->fd != -1) {
108     close(st->fd);
109     st->fd = -1;
110   }
111 
112   if ((st->rm_at_exit == true) && (st->file_path != NULL)) {
113     /* We try to remove the file but do not error out if we can't */
114     (void) remove(st->file_path);
115     st->file_path = NULL;
116   }
117 }
118