aboutsummaryrefslogtreecommitdiff
path: root/pflash.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2015-05-21 09:12:50 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2015-05-21 11:44:57 +0200
commitc9b6e84c9284e5283439135c226638b06ac05193 (patch)
tree54345135a63c6d4372afcde92b2004367eba789d /pflash.c
parent25aa128050881068db3ca3212550024214bfad34 (diff)
downloadqboot-c9b6e84c9284e5283439135c226638b06ac05193.zip
qboot-c9b6e84c9284e5283439135c226638b06ac05193.tar.gz
qboot-c9b6e84c9284e5283439135c226638b06ac05193.tar.bz2
initial support for pflash / cbfs
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'pflash.c')
-rw-r--r--pflash.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/pflash.c b/pflash.c
new file mode 100644
index 0000000..950bc74
--- /dev/null
+++ b/pflash.c
@@ -0,0 +1,63 @@
+#include <stddef.h>
+#include "bios.h"
+#include "pflash.h"
+#include "stdio.h"
+
+#define CLEAR_STATUS_CMD 0x50
+#define READ_STATUS_CMD 0x70
+#define QUERY_CMD 0x98
+#define READ_ARRAY_CMD 0xff
+
+static void *pflash_detect(uint8_t *top_addr)
+{
+ volatile uint8_t *p = top_addr;
+ uint8_t save;
+ int i, blocks, sector_len;
+
+ /* The low byte of the address is part of the command, so it must be 0. */
+ if ((uintptr_t)p & 256)
+ panic();
+
+ p -= 256;
+ for (i = 0; i < 256; i++)
+ if (p[i] != CLEAR_STATUS_CMD)
+ break;
+ if (i == 256)
+ return NULL;
+
+ save = p[i];
+ p[i] = CLEAR_STATUS_CMD;
+ if (p[i] == CLEAR_STATUS_CMD) {
+ /* behaves as RAM */
+ p[i] = save;
+ return NULL;
+ }
+ p[i] = READ_STATUS_CMD;
+ if (p[i] != 0) {
+ /* doesn't behave as flash */
+ return NULL;
+ }
+
+ /* 0x2d-0x2e: blocks_per_device - 1, little endian */
+ /* 0x2f-0x30: sector_len / 256 */
+ p[i] = QUERY_CMD;
+ blocks = p[0x2d] + (p[0x2e] << 8) + 1;
+ sector_len = (p[0x2f] + (p[0x30] << 8)) << 8;
+
+ p[i] = READ_ARRAY_CMD;
+ return top_addr - blocks * sector_len;
+}
+
+void *pflash_base(int n, size_t *size)
+{
+ uint8_t *top = NULL;
+ uint8_t *prev;
+ while (n-- >= 0) {
+ prev = top;
+ top = pflash_detect(top);
+ if (!top)
+ return NULL;
+ *size = prev - top;
+ }
+ return top;
+}