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 "NHW_NVM_backend.h"
25 
26 /**
27  * At boot, do whatever is necessary for a given storage
28  * (allocate memory, open files etc. )
29  */
nhw_nvm_initialize_data_storage(nvm_storage_state_t * st)30 void nhw_nvm_initialize_data_storage(nvm_storage_state_t *st){
31   struct stat f_stat;
32   int rc;
33 
34   st->fd = -1;
35   st->storage = NULL;
36 
37   if (st->in_ram == true) {
38     st->storage = (uint8_t *)bs_malloc(st->size);
39 
40   } else {
41 
42     bs_create_folders_in_path(st->file_path);
43     st->fd = open(st->file_path, O_RDWR | O_CREAT, (mode_t)0600);
44     if (st->fd == -1) {
45       bs_trace_error_line("%s: Failed to open %s device file %s: %s\n",
46           __func__, st->type_s, st->file_path, strerror(errno));
47     }
48 
49     rc = fstat(st->fd, &f_stat);
50     if (rc) {
51       bs_trace_error_line("%s: Failed to get status of %s device file %s: %s\n",
52           __func__, st->type_s, st->file_path, strerror(errno));
53     }
54 
55     if (ftruncate(st->fd, st->size) == -1) {
56       bs_trace_error_line("%s: Failed to resize %s device file %s: %s\n",
57           __func__, st->type_s, st->file_path, strerror(errno));
58     }
59 
60     st->storage = mmap(NULL, st->size, PROT_WRITE | PROT_READ, MAP_SHARED, st->fd, 0);
61     if (st->storage == MAP_FAILED) {
62       bs_trace_error_line("%s: Failed to mmap %s device file %s: %s\n",
63           __func__, st->type_s, st->file_path, strerror(errno));
64     }
65   }
66 
67   if ((st->erase_at_start == true) || (st->in_ram == true) || (f_stat.st_size == 0)) {
68     /* Erase the memory unit by pulling all bits to the configured erase value */
69     (void)memset(st->storage, 0xFF, st->size);
70   }
71 }
72 
nhw_nvm_init_storage(nvm_storage_state_t * st,struct nhw_nvm_st_args_t * args,size_t size,char * type_s)73 void nhw_nvm_init_storage(nvm_storage_state_t *st, struct nhw_nvm_st_args_t *args,
74                           size_t size, char *type_s)
75 {
76   st->file_path      = args->file;
77   st->erase_at_start = args->erase;
78   st->rm_at_exit     = args->rm;
79   st->in_ram         = args->in_ram;
80   st->size           = size;
81   st->type_s         = type_s;
82 
83   nhw_nvm_initialize_data_storage(st);
84 }
85 
86 /**
87  * Before exiting the program, do whatever is
88  * necessary for a given storage (free'ing heap,
89  * closing file descriptors, etc)
90  */
nhw_nvm_clear_storage(nvm_storage_state_t * st)91 void nhw_nvm_clear_storage(nvm_storage_state_t *st){
92 
93   if (st->in_ram == true) {
94     if (st->storage != NULL) {
95       free(st->storage);
96       st->storage = NULL;
97     }
98     return;
99   }
100 
101   if ((st->storage != MAP_FAILED) && (st->storage != NULL)) {
102     munmap(st->storage, st->size);
103     st->storage = NULL;
104   }
105 
106   if (st->fd != -1) {
107     close(st->fd);
108     st->fd = -1;
109   }
110 
111   if ((st->rm_at_exit == true) && (st->file_path != NULL)) {
112     /* We try to remove the file but do not error out if we can't */
113     (void) remove(st->file_path);
114     st->file_path = NULL;
115   }
116 }
117