summaryrefslogtreecommitdiff
path: root/lib/x1000-installer/test_lib/fakenand.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/x1000-installer/test_lib/fakenand.c')
-rw-r--r--lib/x1000-installer/test_lib/fakenand.c270
1 files changed, 0 insertions, 270 deletions
diff --git a/lib/x1000-installer/test_lib/fakenand.c b/lib/x1000-installer/test_lib/fakenand.c
deleted file mode 100644
index 19f1f31cfd..0000000000
--- a/lib/x1000-installer/test_lib/fakenand.c
+++ /dev/null
@@ -1,270 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "nand-x1000.h"
23#include <unistd.h>
24#include <fcntl.h>
25#include <string.h>
26#include <stdio.h>
27#include <stdlib.h>
28
29const char* nand_backing_file = "fakeNAND.bin";
30const char* nand_meta_file = "fakeNAND_meta.bin";
31
32struct nand_trace* nand_trace = NULL;
33size_t nand_trace_capacity = 0;
34size_t nand_trace_length = 0;
35
36static struct nand_trace* nand_trace_cur = NULL;
37
38static int injected_err = 0;
39
40#define METAF_PROGRAMMED 1
41
42static const nand_chip fake_chip = {
43 /* ATO25D1GA */
44 .log2_ppb = 6, /* 64 pages */
45 .page_size = 2048,
46 .oob_size = 64,
47 .nr_blocks = 1024,
48};
49
50void nand_trace_reset(size_t size)
51{
52 nand_trace = realloc(nand_trace, size);
53 nand_trace_capacity = size;
54 nand_trace_length = 0;
55 nand_trace_cur = nand_trace;
56}
57
58void nand_inject_error(int rc)
59{
60 injected_err = rc;
61}
62
63nand_drv* nand_init(void)
64{
65 static bool inited = false;
66 static uint8_t scratch_buf[NAND_DRV_SCRATCHSIZE];
67 static uint8_t page_buf[NAND_DRV_MAXPAGESIZE];
68 static nand_drv d;
69
70 if(!inited) {
71 d.scratch_buf = scratch_buf;
72 d.page_buf = page_buf;
73 d.chip = &fake_chip;
74 inited = true;
75 }
76
77 return &d;
78}
79
80static void lock_assert(bool cond, const char* msg)
81{
82 if(!cond) {
83 fprintf(stderr, "%s\n", msg);
84 fflush(stderr);
85 abort();
86 }
87}
88
89void nand_lock(nand_drv* drv)
90{
91 drv->lock_count++;
92}
93
94void nand_unlock(nand_drv* drv)
95{
96 lock_assert(drv->lock_count > 0, "nand_unlock() called when not locked");
97 drv->lock_count--;
98}
99
100#define CHECK_INJECTED_ERROR \
101 do { int __err = injected_err; injected_err = 0; if(__err) return __err; } while(0)
102
103int nand_open(nand_drv* drv)
104{
105 lock_assert(drv->lock_count > 0, "nand_open(): lock not held");
106 CHECK_INJECTED_ERROR;
107
108 if(drv->refcount > 0) {
109 drv->refcount++;
110 return NAND_SUCCESS;
111 }
112
113 /* leaks an fd on error but this is only testing... */
114 drv->fd = open(nand_backing_file, O_RDWR|O_CREAT, 0644);
115 drv->metafd = open(nand_meta_file, O_RDWR|O_CREAT, 0644);
116 if(drv->fd < 0 || drv->metafd < 0)
117 goto err;
118
119 drv->ppb = 1 << drv->chip->log2_ppb;
120 drv->fpage_size = drv->chip->page_size + drv->chip->oob_size;
121
122 /* make backing file the correct size */
123 if(ftruncate(drv->fd, drv->chip->page_size * drv->ppb * drv->chip->nr_blocks) < 0)
124 goto err;
125 if(ftruncate(drv->metafd, drv->chip->nr_blocks * drv->ppb) < 0)
126 goto err;
127
128 drv->refcount++;
129 return NAND_SUCCESS;
130
131 err:
132 if(drv->fd >= 0)
133 close(drv->fd);
134 if(drv->metafd >= 0)
135 close(drv->metafd);
136 return NAND_ERR_OTHER;
137}
138
139void nand_close(nand_drv* drv)
140{
141 lock_assert(drv->lock_count > 0, "nand_close(): lock not held");
142
143 if(--drv->refcount > 0)
144 return;
145
146 close(drv->fd);
147 close(drv->metafd);
148 drv->fd = -1;
149 drv->metafd = -1;
150}
151
152static int read_meta(nand_drv* drv, nand_page_t page)
153{
154 /* probably won't fail */
155 if(lseek(drv->metafd, page, SEEK_SET) < 0)
156 return NAND_ERR_OTHER;
157 if(read(drv->metafd, drv->scratch_buf, 1) != 1)
158 return NAND_ERR_OTHER;
159
160 return drv->scratch_buf[0];
161}
162
163static int write_meta(nand_drv* drv, nand_page_t page, int val)
164{
165 drv->scratch_buf[0] = val;
166
167 if(lseek(drv->metafd, page, SEEK_SET) < 0)
168 return NAND_ERR_OTHER;
169 if(write(drv->metafd, drv->scratch_buf, 1) != 1)
170 return NAND_ERR_OTHER;
171
172 return NAND_SUCCESS;
173}
174
175static int upd_meta(nand_drv* drv, nand_page_t page, uint8_t clr, uint8_t set)
176{
177 int meta = read_meta(drv, page);
178 if(meta < 0)
179 return meta;
180
181 meta &= ~clr;
182 meta |= set;
183
184 return write_meta(drv, page, meta);
185}
186
187static int page_program(nand_drv* drv, nand_page_t page, const void* buffer,
188 uint8_t clr, uint8_t set)
189{
190 if(lseek(drv->fd, page * drv->chip->page_size, SEEK_SET) < 0)
191 return NAND_ERR_OTHER;
192 if(write(drv->fd, buffer, drv->chip->page_size) != (ssize_t)drv->chip->page_size)
193 return NAND_ERR_PROGRAM_FAIL;
194
195 return upd_meta(drv, page, clr, set);
196}
197
198static void trace(enum nand_trace_type ty, enum nand_trace_exception ex, nand_page_t addr)
199{
200 if(nand_trace_length < nand_trace_capacity) {
201 nand_trace_cur->type = ty;
202 nand_trace_cur->exception = ex;
203 nand_trace_cur->addr = addr;
204 nand_trace_cur++;
205 nand_trace_length++;
206 }
207}
208
209int nand_block_erase(nand_drv* drv, nand_block_t block)
210{
211 lock_assert(drv->lock_count > 0, "nand_block_erase(): lock not held");
212 CHECK_INJECTED_ERROR;
213
214 trace(NTT_ERASE, NTE_NONE, block);
215
216 memset(drv->page_buf, 0xff, drv->fpage_size);
217
218 for(unsigned i = 0; i < drv->ppb; ++i) {
219 int rc = page_program(drv, block + i, drv->page_buf, METAF_PROGRAMMED, 0);
220 if(rc < 0)
221 return NAND_ERR_ERASE_FAIL;
222 }
223
224 return NAND_SUCCESS;
225}
226
227int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer)
228{
229 lock_assert(drv->lock_count > 0, "nand_page_program(): lock not held");
230 CHECK_INJECTED_ERROR;
231
232 int meta = read_meta(drv, page);
233 if(meta < 0)
234 return meta;
235
236 enum nand_trace_exception exception = NTE_NONE;
237 if(meta & METAF_PROGRAMMED)
238 exception = NTE_DOUBLE_PROGRAMMED;
239
240 trace(NTT_PROGRAM, exception, page);
241
242 return page_program(drv, page, buffer, 0, METAF_PROGRAMMED);
243}
244
245int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer)
246{
247 lock_assert(drv->lock_count > 0, "nand_page_read(): lock not held");
248 CHECK_INJECTED_ERROR;
249
250 enum nand_trace_exception exception = NTE_NONE;
251
252 int meta = read_meta(drv, page);
253 if(meta < 0)
254 return meta;
255
256 if(meta & METAF_PROGRAMMED) {
257 if(lseek(drv->fd, page * drv->chip->page_size, SEEK_SET) < 0)
258 return NAND_ERR_OTHER;
259 if(read(drv->fd, buffer, drv->chip->page_size) != (ssize_t)drv->chip->page_size)
260 return NAND_ERR_OTHER;
261 } else {
262 memset(buffer, 0xff, drv->chip->page_size);
263 exception = NTE_CLEARED;
264 }
265
266 trace(NTT_READ, exception, page);
267
268 memset(buffer + drv->chip->page_size, 0xff, drv->chip->oob_size);
269 return NAND_SUCCESS;
270}