yaffsfs.c: Fix NULL dereference in yaffs_unmount2_reldev()
[yaffs2.git] / direct / test-framework / ynorsim.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2018 Aleph One Ltd.
5  *
6  * Created by Charles Manning <charles@aleph1.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include "ynorsim.h"
14
15 #include <stdio.h>
16 #include <fcntl.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
19 #include <time.h>
20
21 #define YNORSIM_FNAME "emfile-nor"
22
23 /* Set YNORSIM_BIT_CHANGES to a a value from 1..30 to
24  *simulate bit flipping as the programming happens.
25  * A low value results in faster simulation with less chance of encountering a partially programmed
26  * word.
27  */
28
29 //#define YNORSIM_BIT_CHANGES 15
30 #define YNORSIM_BIT_CHANGES 2
31
32 #if 0
33 /* Simulate 32MB of flash in 256k byte blocks.
34  * This stuff is x32.
35  */
36
37 #define YNORSIM_BLOCK_SIZE_U32  (256*1024/4)
38 #define YNORSIM_DEV_SIZE_U32    (32*1024 * 1024/4)
39 #else
40 /* Simulate 8MB of flash in 256k byte blocks.
41  * This stuff is x32.
42  */
43
44 #define YNORSIM_BLOCK_SIZE_U32  (256*1024/4)
45 #define YNORSIM_DEV_SIZE_U32    (8*1024 * 1024/4)
46 #endif
47
48 struct nor_sim {
49         int n_blocks;
50         int block_size_bytes;
51         int file_size;
52         u32 *word;
53         int initialised;
54         char *fname;
55         int remaining_ops;
56         int nops_so_far;
57 };
58
59 int ops_multiplier = 500;
60 extern int random_seed;
61 extern int simulate_power_failure;
62
63 static void NorError(struct nor_sim *sim)
64 {
65         printf("Nor error on device %s\n", sim->fname);
66         while (1) {
67         }
68 }
69
70 static void ynorsim_save_image(struct nor_sim *sim)
71 {
72         int h;
73
74         h = open(sim->fname, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
75         write(h, sim->word, sim->file_size);
76         close(h);
77 }
78
79 static void ynorsim_restore_image(struct nor_sim *sim)
80 {
81         int h;
82
83         h = open(sim->fname, O_RDONLY, S_IREAD | S_IWRITE);
84         memset(sim->word, 0xFF, sim->file_size);
85         read(h, sim->word, sim->file_size);
86         close(h);
87 }
88
89 static void ynorsim_power_fail(struct nor_sim *sim)
90 {
91         ynorsim_save_image(sim);
92         exit(1);
93 }
94
95 static void ynorsim_maybe_power_fail(struct nor_sim *sim)
96 {
97         sim->nops_so_far++;
98         sim->remaining_ops--;
99         if (simulate_power_failure && sim->remaining_ops < 1) {
100                 printf("Simulated power failure after %d operations\n",
101                        sim->nops_so_far);
102                 ynorsim_power_fail(sim);
103         }
104 }
105
106 static void ynorsim_ready(struct nor_sim *sim)
107 {
108         if (sim->initialised)
109                 return;
110         srand(random_seed);
111         sim->remaining_ops = 1000000000;
112         sim->remaining_ops =
113             (rand() % 10000) * ops_multiplier * YNORSIM_BIT_CHANGES;
114         ynorsim_restore_image(sim);
115         sim->initialised = 1;
116 }
117
118 /* Public functions. */
119
120 void ynorsim_rd32(struct nor_sim *sim, u32 * addr, u32 * buf, int nwords)
121 {
122         sim = sim;
123         while (nwords > 0) {
124                 *buf = *addr;
125                 buf++;
126                 addr++;
127                 nwords--;
128         }
129 }
130
131 void ynorsim_wr_one_word32(struct nor_sim *sim, u32 * addr, u32 val)
132 {
133         u32 tmp;
134         u32 m;
135         int i;
136
137         tmp = *addr;
138         if (val & ~tmp) {
139                 /* Fail due to trying to change a zero into a 1 */
140                 printf("attempt to set a zero to one (%x)->(%x)\n", tmp, val);
141                 NorError(sim);
142         }
143
144         for (i = 0; i < YNORSIM_BIT_CHANGES; i++) {
145                 m = 1 << (rand() & 31);
146                 if (!(m & val)) {
147                         tmp &= ~m;
148                         *addr = tmp;
149                         ynorsim_maybe_power_fail(sim);
150                 }
151
152         }
153
154         *addr = tmp & val;
155         ynorsim_maybe_power_fail(sim);
156 }
157
158 void ynorsim_wr32(struct nor_sim *sim, u32 * addr, u32 * buf, int nwords)
159 {
160         while (nwords > 0) {
161                 ynorsim_wr_one_word32(sim, addr, *buf);
162                 addr++;
163                 buf++;
164                 nwords--;
165         }
166 }
167
168 void ynorsim_erase(struct nor_sim *sim, u32 * addr)
169 {
170         /* Todo... bit flipping */
171         memset(addr, 0xFF, sim->block_size_bytes);
172 }
173
174 struct nor_sim *ynorsim_initialise(char *name, int n_blocks,
175                                    int block_size_bytes)
176 {
177         struct nor_sim *sim;
178
179         sim = malloc(sizeof(*sim));
180         if (!sim)
181                 return NULL;
182
183         memset(sim, 0, sizeof(*sim));
184         sim->n_blocks = n_blocks;
185         sim->block_size_bytes = block_size_bytes;
186         sim->file_size = n_blocks * block_size_bytes;
187         sim->word = malloc(sim->file_size);
188         sim->fname = strdup(name);
189
190         if(!sim->word)
191                 return NULL;
192
193         ynorsim_ready(sim);
194         return sim;
195 }
196
197 void ynorsim_shutdown(struct nor_sim *sim)
198 {
199         ynorsim_save_image(sim);
200         sim->initialised = 0;
201 }
202
203 u32 *ynorsim_get_base(struct nor_sim *sim)
204 {
205         return sim->word;
206 }