[coreboot] r48 - in trunk/filo-0.5: . drivers drivers/flash fs i386 include main
svn at coreboot.org
svn at coreboot.org
Sat May 3 17:03:46 CEST 2008
Author: stepan
Date: 2008-05-03 17:03:45 +0200 (Sat, 03 May 2008)
New Revision: 48
Added:
trunk/filo-0.5/drivers/flash/
trunk/filo-0.5/drivers/flash/Makefile
trunk/filo-0.5/drivers/flash/lxflash.c
trunk/filo-0.5/drivers/flash/lxflash.h
trunk/filo-0.5/fs/fsys_aboot.c
trunk/filo-0.5/i386/artecboot.c
trunk/filo-0.5/include/artecboot.h
Modified:
trunk/filo-0.5/Makefile
trunk/filo-0.5/defconfig
trunk/filo-0.5/fs/Makefile
trunk/filo-0.5/fs/blockdev.c
trunk/filo-0.5/fs/filesys.h
trunk/filo-0.5/fs/vfs.c
trunk/filo-0.5/i386/Makefile
trunk/filo-0.5/i386/defconfig
trunk/filo-0.5/i386/linux_load.c
trunk/filo-0.5/include/fs.h
trunk/filo-0.5/include/lib.h
trunk/filo-0.5/main/console.c
trunk/filo-0.5/main/filo.c
Log:
trying to merge most of ARTECs tree.
Modified: trunk/filo-0.5/Makefile
===================================================================
--- trunk/filo-0.5/Makefile 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/Makefile 2008-05-03 15:03:45 UTC (rev 48)
@@ -13,7 +13,8 @@
endif
PROGRAM_NAME = FILO
-PROGRAM_VERSION = 0.5
+PROGRAM_VERSION = 0.5.5
+
BUILD_INFO = ($(shell whoami)@$(shell hostname)) $(shell LANG=C date)
# for now:
@@ -21,7 +22,7 @@
LIBGCC = $(shell $(CC) -print-libgcc-file-name)
-SUBDIRS = main main/grub fs drivers drivers/usb $(ARCH)
+SUBDIRS = main main/grub fs drivers drivers/usb drivers/flash $(ARCH)
OBJS = $(addsuffix /builtin.o,$(SUBDIRS))
@@ -60,7 +61,7 @@
+$(MAKE) -C $(patsubst _clean_%,%,$@) clean
clean: $(SUBDIRS_CLEAN)
- rm -f filo.elf filo config.h filo.iso null.o builtin.o
+ rm -f filo.elf filo config.h filo.iso
distclean: clean
rm -f Config Config.bak include/arch
Modified: trunk/filo-0.5/defconfig
===================================================================
--- trunk/filo-0.5/defconfig 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/defconfig 2008-05-03 15:03:45 UTC (rev 48)
@@ -18,6 +18,7 @@
#AUTOBOOT_FILE = "mem at 0xfff80000"
#AUTOBOOT_FILE = "hde1 at 0"
#AUTOBOOT_FILE = "uda1:/vmlinuz.elf"
+#AUTOBOOT_FILE = "flashb at 0x00400000,0x154a00 console=tty0 console=ttyS0,115200"
# Time in second before booting AUTOBOOT_FILE
AUTOBOOT_DELAY = 2
@@ -45,6 +46,9 @@
# Driver for USB Storage
USB_DISK = 1
+# Driver for NAND flash storage
+#FLASH_DISK = 1
+
# VGA text console
VGA_CONSOLE = 1
PC_KEYBOARD = 1
@@ -99,4 +103,7 @@
#DEBUG_IDE = 1
#DEBUG_USB = 1
#DEBUG_ELTORITO = 1
+#DEBUG_FLASH = 1
+#DEBUG_ARTECBOOT = 1
+
Added: trunk/filo-0.5/drivers/flash/Makefile
===================================================================
--- trunk/filo-0.5/drivers/flash/Makefile (rev 0)
+++ trunk/filo-0.5/drivers/flash/Makefile 2008-05-03 15:03:45 UTC (rev 48)
@@ -0,0 +1,7 @@
+TOPDIR = ../..
+-include $(TOPDIR)/Config
+
+OBJS-1 :=
+OBJS-$(FLASH_DISK) += lxflash.o
+
+include $(TOPDIR)/makerules
Added: trunk/filo-0.5/drivers/flash/lxflash.c
===================================================================
--- trunk/filo-0.5/drivers/flash/lxflash.c (rev 0)
+++ trunk/filo-0.5/drivers/flash/lxflash.c 2008-05-03 15:03:45 UTC (rev 48)
@@ -0,0 +1,824 @@
+/*******************************************************************************
+ *
+ * Geode LX CS5536 flash driver
+ *
+ * Copyright 2006 Andrei Birjukov <andrei.birjukov at artecdesign.ee> and
+ * Artec Design LLC http://www.artecdesign.ee
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ******************************************************************************/
+
+#include <lib.h>
+#include <fs.h>
+#include <arch/io.h>
+#include "lxflash.h"
+
+#define DEBUG_THIS DEBUG_FLASH
+#include <debug.h>
+
+////////////////////////////////////////////////////////////////////////////////
+// driver globals
+
+static FLASH_INFO g_flashInfo; // flash info structure
+static uint32_t g_deviceID = 0; // flash memory ID
+static uint32_t g_chipID = 0; // chip ID
+static uint16_t g_baseAddr = 0; // port mapped controller IO base address
+
+static uint8_t g_eccTest[MAX_ECC_SIZE]; // used to retrieve/store ECC
+static uint8_t g_eccCalc[MAX_ECC_SIZE];
+
+static uint32_t g_currentPage = (uint32_t)-1;
+static uint8_t g_pageBuf[MAX_PAGE_SIZE];
+static uint8_t *g_pBBT=NULL;
+
+////////////////////////////////////////////////////////////////////////////////
+// ECC structs and routines
+
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+static const uint8_t nand_ecc_precalc_table[] = {
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+
+/**
+ * nand_trans_result - [GENERIC] create non-inverted ECC
+ * @reg2: line parity reg 2
+ * @reg3: line parity reg 3
+ * @ecc_code: ecc
+ *
+ * Creates non-inverted ECC code from line parity
+ */
+static void NAND_transResult(uint8_t reg2, uint8_t reg3,
+ uint8_t *ecc_code)
+{
+ uint8_t a, b, i, tmp1, tmp2;
+
+ /* Initialize variables */
+ a = b = 0x80;
+ tmp1 = tmp2 = 0;
+
+ /* Calculate first ECC byte */
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Calculate second ECC byte */
+ b = 0x80;
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Store two of the ECC bytes */
+ ecc_code[0] = tmp1;
+ ecc_code[1] = tmp2;
+}
+
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block
+ * @dat: raw data
+ * @ecc_code: buffer for ECC
+ */
+int NAND_calculateECC(const uint8_t *dat, uint8_t *ecc_code)
+{
+ uint8_t idx, reg1, reg2, reg3;
+ int j;
+
+ /* Initialize variables */
+ reg1 = reg2 = reg3 = 0;
+ ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
+
+ /* Build up column parity */
+ for(j = 0; j < 256; j++) {
+
+ /* Get CP0 - CP5 from table */
+ idx = nand_ecc_precalc_table[dat[j]];
+ reg1 ^= (idx & 0x3f);
+
+ /* All bit XOR = 1 ? */
+ if (idx & 0x40) {
+ reg3 ^= (uint8_t) j;
+ reg2 ^= ~((uint8_t) j);
+ }
+ }
+
+ /* Create non-inverted ECC code from line parity */
+ NAND_transResult(reg2, reg3, ecc_code);
+
+ /* Calculate final ECC code */
+ ecc_code[0] = ~ecc_code[0];
+ ecc_code[1] = ~ecc_code[1];
+ ecc_code[2] = ((~reg1) << 2) | 0x03;
+ return 0;
+}
+
+/**
+ * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @dat: raw data read from the chip
+ * @read_ecc: ECC from the chip
+ * @calc_ecc: the ECC calculated from raw data
+ *
+ * Detect and correct a 1 bit error for 256 byte block
+ */
+int NAND_correctData(uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+ uint8_t a, b, c, d1, d2, d3, add, bit, i;
+
+ /* Do error detection */
+ d1 = calc_ecc[0] ^ read_ecc[0];
+ d2 = calc_ecc[1] ^ read_ecc[1];
+ d3 = calc_ecc[2] ^ read_ecc[2];
+
+ if ((d1 | d2 | d3) == 0) {
+ /* No errors */
+ return 0;
+ }
+ else {
+ a = (d1 ^ (d1 >> 1)) & 0x55;
+ b = (d2 ^ (d2 >> 1)) & 0x55;
+ c = (d3 ^ (d3 >> 1)) & 0x54;
+
+ /* Found and will correct single bit error in the data */
+ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
+ c = 0x80;
+ add = 0;
+ a = 0x80;
+ for (i=0; i<4; i++) {
+ if (d1 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ c = 0x80;
+ for (i=0; i<4; i++) {
+ if (d2 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ bit = 0;
+ b = 0x04;
+ c = 0x80;
+ for (i=0; i<3; i++) {
+ if (d3 & c)
+ bit |= b;
+ c >>= 2;
+ b >>= 1;
+ }
+ b = 0x01;
+ a = dat[add];
+ a ^= (b << bit);
+ dat[add] = a;
+ return 1;
+ }
+ else {
+ i = 0;
+ while (d1) {
+ if (d1 & 0x01)
+ ++i;
+ d1 >>= 1;
+ }
+ while (d2) {
+ if (d2 & 0x01)
+ ++i;
+ d2 >>= 1;
+ }
+ while (d3) {
+ if (d3 & 0x01)
+ ++i;
+ d3 >>= 1;
+ }
+ if (i == 1) {
+ /* ECC Code Error Correction */
+ read_ecc[0] = calc_ecc[0];
+ read_ecc[1] = calc_ecc[1];
+ read_ecc[2] = calc_ecc[2];
+ return 2;
+ }
+ else {
+ /* Uncorrectable Error */
+ return -1;
+ }
+ }
+ }
+
+ /* Should never happen */
+ return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NAND flash helper functions go here, ported from Windows CE FMD
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_checkStatus()
+//
+// Retrieve the status of the Chip. This function accept a loop number, which
+// is used to do the loop if chip is not ready.
+//
+// dwLoops:
+//
+// 0: no loop
+// 0xffffffff: loop forever
+
+uint8_t NAND_checkStatus(uint32_t dwLoops)
+{
+ int bStop = (dwLoops != (uint32_t) -1);
+ uint8_t ucStatus;
+ int i;
+
+ // There is a 200ns delay (Twb) between the time that the !write-enable line
+ // (!WE) is asserted and the time the ready (R/!B) line is de-asserted. Generate a
+ // delay before querrying the status.
+ for (i=0; i<10; i++)
+ inb(g_baseAddr + IO_NAND_STS);
+
+ while(TRUE)
+ {
+ ucStatus = inb(g_baseAddr + IO_NAND_STS);
+
+ if(((ucStatus & CS_NAND_STS_FLASH_RDY) && // status ready
+ !(ucStatus & CS_NAND_CTLR_BUSY)) || // controller not busy
+ (bStop && !dwLoops)) // non-infinite loop and
+
+ break; // we already pay our due
+
+ dwLoops --;
+ }
+
+ return ucStatus;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NAND command helpers
+
+static __inline void NAND_enableHwECC(int enable)
+{
+ if(enable) outb(0x07, g_baseAddr + IO_NAND_ECC_CTL);
+ else outb(0x02, g_baseAddr + IO_NAND_ECC_CTL);
+}
+
+static void NAND_readHwECC(uint8_t *pData)
+{
+ // read ECC data from status register
+ pData[0] = inb(g_baseAddr + IO_NAND_ECC_MSB);
+ pData[1] = inb(g_baseAddr + IO_NAND_ECC_LSB);
+ pData[2] = inb(g_baseAddr + IO_NAND_ECC_COL);
+}
+
+static __inline void NAND_writeIO(uint8_t b)
+{
+ outb(b, g_baseAddr + IO_NAND_IO);
+}
+
+static __inline void NAND_writeCTL(uint8_t b)
+{
+ outb(b, g_baseAddr + IO_NAND_CTL);
+}
+
+static __inline uint8_t NAND_readDataByte()
+{
+ return inb(g_baseAddr + IO_NAND_DATA);
+}
+
+static void NAND_readData(uint8_t *pData, int nSize)
+{
+ int i, nDwords = nSize/4; // number of double words
+ int nBytes = nSize % 4; // leftover stuff
+
+ if(nSize > 528) return; // oversized buffer?
+
+ // read from port mapped registers,
+ for(i=0; i<nDwords; i++)
+ ((uint32_t*)pData)[i] = inl(g_baseAddr + IO_NAND_DATA);
+
+ for(i=0; i<nBytes; i++)
+ pData[i] = inb(g_baseAddr + IO_NAND_DATA);
+}
+
+static __inline void NAND_writeByte(uint8_t b)
+{
+ outb(b, g_baseAddr + IO_NAND_DATA);
+}
+
+static void NAND_writeData(uint8_t *pData, int nSize)
+{
+ int i;
+ if(nSize > 528) return; // oversized buffer?
+
+ // write byte by byte, pedestrian way
+ for(i=0; i<nSize; i++)
+ NAND_writeByte(pData[i]);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_getStatus()
+//
+// Retrieve the status of the Chip. This function accept a loop number, which
+// is used to do the loop if chip is not ready.
+//
+// dwLoops:
+//
+// 0: no loop
+// 0xffffffff: loop forever
+
+uint8_t NAND_getStatus(uint32_t dwLoops)
+{
+ int bStop = (dwLoops != (uint32_t) -1);
+ uint8_t ucStatus;
+
+ NAND_checkStatus(dwLoops); // wait until ready
+
+ NAND_writeCTL(CS_NAND_CTL_CLE); // latch command
+ NAND_writeIO(CMD_STATUS); // issue read status command
+ NAND_writeCTL(0x00); // enable chip
+
+ while(1)
+ {
+ ucStatus = inb(g_baseAddr + IO_NAND_DATA);
+
+ if((ucStatus & STATUS_READY) || // status ready
+ (bStop && !dwLoops)) // non-infinite loop and
+
+ break; // we already pay our due
+
+ dwLoops--;
+ }
+
+ return ucStatus;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_readFlashID
+//
+// Retrieve the flash chip manufacturer and ID
+
+
+uint32_t NAND_readFlashID()
+{
+ uint32_t dwID=0;
+
+ NAND_writeCTL(0x00); // enable chip
+
+ NAND_checkStatus((uint32_t) -1); // check ready
+
+ NAND_writeCTL(CS_NAND_CTL_CLE); // latch command
+ NAND_writeIO(CMD_READID); // send command
+ NAND_writeCTL(CS_NAND_CTL_ALE); // latch address
+ NAND_writeIO(0x00); // send address
+ NAND_writeCTL(0x00); // enable chip
+
+ NAND_checkStatus((uint32_t) -1);
+
+ dwID = inl(g_baseAddr + IO_NAND_DATA);
+
+ NAND_writeCTL(CS_NAND_CTL_CE); // disable chip
+
+ return dwID;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_isBlockBad
+//
+// Check to see if the given block is bad. A block is bad if the 517th uint8_t on
+// the first or second page is not 0xff.
+//
+// blockID: The block address. We need to convert this to page address
+//
+
+int NAND_isBlockBad(uint32_t blockID)
+{
+ uint8_t pa1, pa2, pa3, ca1, ca2, bData;
+
+ // Get the first page of the block
+ uint32_t dwPageID = blockID * g_flashInfo.pagesPerBlock;
+
+ // for 512-byte page size, use the original addressing scheme
+ if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_512)
+ {
+ // three page address bytes
+ pa1 = (uint8_t) (dwPageID & 0xff);
+ pa2 = (uint8_t) ((dwPageID >> 8) & 0xff);
+ pa3 = (uint8_t) ((dwPageID >> 16) & 0xff);
+ // just one column address byte
+ ca1 = VALIDADDR;
+ }
+ // for 2048-byte page size, we need to add some stuff
+ else if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+ {
+ // three page address bytes
+ pa1 = (uint8_t) (dwPageID & 0xff);
+ pa2 = (uint8_t) ((dwPageID >> 8) & 0xff);
+ pa3 = (uint8_t) ((dwPageID >> 16) & 0xff);
+ // two column address bytes
+ ca1 = 0x0000;
+ ca2 = 0x0008; // point to the 2048-th byte
+ }
+ // unsupported page size
+ else return TRUE;
+
+ // For our NAND flash, we don't have to issue two read command. We just need
+ // to issue one read command and do contiquous read
+
+ NAND_writeCTL(0x00); // enable chip
+ NAND_checkStatus((uint32_t) -1); // check ready
+
+ // Check the first page.
+ NAND_writeCTL(CS_NAND_CTL_CLE); // latch command
+
+ if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+ NAND_writeIO(CMD_READ); // send read command
+ else NAND_writeIO(CMD_READ2); // send read command 2
+ NAND_writeCTL(CS_NAND_CTL_ALE); // latch address
+ NAND_writeIO(ca1); // send Column Address 1
+
+ if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+ NAND_writeIO(ca2); // send Column Address 2
+
+ NAND_writeIO(pa1); // send Page Address 1
+ NAND_writeIO(pa2); // send Page Address 2
+ NAND_writeIO(pa3); // send Page Address 3
+ NAND_writeCTL(0x00); // select chip
+
+ if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+ {
+ NAND_writeCTL(CS_NAND_CTL_CLE); // latch command
+ NAND_writeIO(CMD_READ_2K); // send read command
+ NAND_writeCTL(0x00); // select chip
+ }
+
+ NAND_checkStatus((uint32_t) -1); // check ready
+
+ bData = NAND_readDataByte(); // read out the bad block marker
+ if(bData != 0xff) // no bits may be zeroed
+ {
+ debug("bad block found at address 0x%x\n", blockID);
+ NAND_writeCTL(CS_NAND_CTL_CE); // disable chip
+ return TRUE;
+ }
+
+ NAND_writeCTL(CS_NAND_CTL_CE); // disable chip
+ return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+
+__inline int IsECCWritten(uint8_t *pECC)
+{
+ // FIXME: check only 6 first bytes
+ static uint8_t abNoECC[] = {0xff,0xff,0xff,0xff,0xff,0xff};
+ return (memcmp(pECC, abNoECC, sizeof(abNoECC)) != 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+
+int NAND_initChip(int chipNum)
+{
+ msr_t msr;
+
+ memset(&g_flashInfo, 0, sizeof(g_flashInfo));
+
+ g_chipID = chipNum;
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // init the MSR_DIVIL_BALL_OPTS register, enable flash mode
+
+ msr = rdmsr(MSR_DIVIL_BALL_OPTS);
+ msr.lo &= ~PIN_OPT_IDE;
+ wrmsr(MSR_DIVIL_BALL_OPTS, msr);
+ msr = rdmsr(MSR_DIVIL_BALL_OPTS);
+ debug("MSR_DIVIL_BALL_OPTS = 0x%08x 0x%08x\n", msr.hi, msr.lo);
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // init the MSR_DIVIL_LBAR_FLSHx register, I/O mapped mode, set base address
+
+ msr.hi = SET_FLSH_HIGH;
+ msr.lo = SET_FLSH_LOW;
+ wrmsr(MSR_DIVIL_LBAR_FLSH0 + g_chipID, msr);
+ g_baseAddr = SET_FLSH_LOW; // set the IO base address
+
+ // read the register back
+ msr = rdmsr(MSR_DIVIL_LBAR_FLSH0 + g_chipID);
+ debug("MSR_DIVIL_LBAR_FLSH%d = 0x%08x 0x%08x\n", (int)g_chipID, msr.hi, msr.lo);
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // init the MSR_NANDF_DATA NAND timing register
+
+ msr.hi = 0;
+ msr.lo = SET_NANDF_DATA_LOW;
+ wrmsr(MSR_NANDF_DATA, msr);
+
+ msr = rdmsr(MSR_NANDF_DATA);
+ debug("MSR_NANDF_DATA = 0x%08x 0x%08x\n", msr.hi, msr.lo);
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // init the MSR_NANDF_CTL NAND timing register
+
+ msr.hi = 0;
+ msr.lo = SET_NANDF_CTL_LOW;
+ wrmsr(MSR_NANDF_CTL, msr);
+
+ msr = rdmsr(MSR_NANDF_CTL);
+ debug("MSR_NANDF_CTL = 0x%08x 0x%08x\n", msr.hi, msr.lo);
+
+ // read out flash chip ID
+ g_deviceID = NAND_readFlashID();
+
+ switch(g_deviceID) // allow only known flash chips
+ {
+ case SAMSUNG_NAND_64MB:
+ case SST_NAND_64MB:
+
+ g_flashInfo.numBlocks = 4096;
+ g_flashInfo.pagesPerBlock = 32;
+ g_flashInfo.dataBytesPerPage = 512;
+ g_flashInfo.flashType = FLASH_NAND;
+
+ break;
+
+ case SST_NAND_512MB:
+
+ g_flashInfo.numBlocks = 4096;
+ g_flashInfo.pagesPerBlock = 64;
+ g_flashInfo.dataBytesPerPage = 2048;
+ g_flashInfo.flashType = FLASH_NAND;
+
+ break;
+
+ default:
+ printf("Unsupported flash chip ID: %x\n", g_deviceID);
+ return -1;
+ }
+
+ g_flashInfo.bytesPerBlock = g_flashInfo.dataBytesPerPage * g_flashInfo.pagesPerBlock;
+
+ if(!g_pBBT) g_pBBT = malloc(g_flashInfo.numBlocks);
+ if(!g_pBBT)
+ {
+ printf("Could not allocate bad block table\n");
+ return -1;
+ }
+
+ debug("bad block table allocated, size %d\n", g_flashInfo.numBlocks);
+ memset(g_pBBT, BLOCK_UNKNOWN, g_flashInfo.numBlocks);
+
+ printf("Geode LX flash driver initialized, device ID 0x%x\n", g_deviceID);
+ debug("FlashChip = 0x%x\n", g_chipID);
+ debug("NumBlocks = 0x%x\n", g_flashInfo.numBlocks);
+ debug("PagesPerBlock = 0x%x\n", g_flashInfo.pagesPerBlock);
+ debug("BytesPerPage = 0x%x\n", g_flashInfo.dataBytesPerPage);
+ debug("FlashType = %s\n", g_flashInfo.flashType == FLASH_NAND ? "NAND" : "NOR");
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_readPage
+//
+// Read the content of the sector.
+//
+// startSectorAddr: Starting page address
+// pSectorBuff : Buffer for the data portion
+
+int NAND_readPage(uint32_t pageAddr, uint8_t *pPageBuff)
+{
+ if (!pPageBuff)
+ {
+ debug("Invalid parameters!\n");
+ return ERROR_BAD_PARAMS;
+ }
+
+ // sanity check
+ if (pageAddr < (g_flashInfo.numBlocks * g_flashInfo.pagesPerBlock))
+ {
+ uint8_t bData = 0, bBadBlock = 0, bReserved = 0;
+
+ uint8_t addr1 = (uint8_t)(pageAddr & 0xff);
+ uint8_t addr2 = (uint8_t)((pageAddr >> 8) & 0xff);
+ uint8_t addr3 = (uint8_t)((pageAddr >> 16) & 0xff);
+
+ uint16_t eccSize = 0; // total ECC size
+ uint32_t pageSize = 0;
+
+ NAND_writeCTL(0x00); // enable chip
+ NAND_checkStatus((uint32_t)-1); // check ready
+
+ NAND_writeCTL(CS_NAND_CTL_CLE); // latch command
+ NAND_writeIO(CMD_READ); // send read command
+ NAND_writeCTL(CS_NAND_CTL_ALE); // latch address
+ NAND_writeIO(0x00); // send Column Address 1
+
+ if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+ NAND_writeIO(0x00); // send Column Address 2
+
+ NAND_writeIO(addr1); // send Page Address 1
+ NAND_writeIO(addr2); // send Page Address 2
+ NAND_writeIO(addr3); // send Page Address 3
+ NAND_writeCTL(0x00); // select chip
+
+ if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+ {
+ NAND_writeCTL(CS_NAND_CTL_CLE); // latch command
+ NAND_writeIO(CMD_READ_2K); // send read command
+ NAND_writeCTL(0x00); // select chip
+ }
+
+ NAND_checkStatus((uint32_t) -1); // check ready
+
+ while(pageSize < g_flashInfo.dataBytesPerPage)
+ {
+ // read out the first half of page data
+ NAND_enableHwECC(1); // enable HW ECC calculation
+ NAND_readData(&pPageBuff[pageSize], READ_BLOCK_SIZE);
+ NAND_readHwECC(&g_eccCalc[pageSize / READ_BLOCK_SIZE * 3]);
+ // update counters too
+ pageSize += READ_BLOCK_SIZE;
+ eccSize += 3;
+ }
+
+ debug("read %d bytes from page address %x\n", pageSize, pageAddr);
+ NAND_enableHwECC(0); // disable HW ECC
+
+ // Now read the spare area data
+
+ if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_512)
+ {
+ // Read the ECC info according to Linux MTD format, first part
+ NAND_readData(g_eccTest, 4);
+
+ bBadBlock = NAND_readDataByte(); // bad block byte
+ bReserved = NAND_readDataByte(); // reserved byte
+ // Read the ECC info according to Linux MTD format, second part
+ NAND_readData(&g_eccTest[4], 2);
+
+ // calculate the first part of ECC, use software method
+ //NAND_calculateECC(&pPageBuff[0], &g_eccCalc[0]);
+ // calculate the second part of ECC, use software method
+ //NAND_calculateECC(&pPageBuff[256], &g_eccCalc[3]);
+ }
+ else if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+ {
+ int i;
+ for(i=0; i<40; i++) NAND_readDataByte(); // skip stuff
+ // Read the ECC info according to Linux MTD format (2048 byte page)
+ NAND_readData(g_eccTest, eccSize);
+ }
+
+ // test the data integrity; if the data is invalid, attempt to fix it using ECC
+ if(memcmp(g_eccCalc, g_eccTest, eccSize))
+ {
+ int nRet = 0;
+
+ // If the ECC is all 0xff, then it probably hasn't been written out yet
+ // because the data hasn't been written, so ignore the invalid ECC.
+ if(!IsECCWritten(g_eccTest))
+ {
+ debug("No ECC detected at page 0x%x\n", pageAddr);
+ NAND_writeCTL(CS_NAND_CTL_CE); // disable chip
+ return ERROR_NO_ECC;
+ }
+
+ debug("Page data (page 0x%x) is invalid. Attempting ECC to fix it.\n", pageAddr);
+ nRet = NAND_correctData(&pPageBuff[0], &g_eccTest[0], &g_eccCalc[0]);
+ if(nRet == -1)
+ {
+ debug("ERROR - page data (page 0x%x, first part) Unable to correct invalid data!\n", pageAddr);
+ NAND_writeCTL(CS_NAND_CTL_CE); // disable chip
+ return ERROR_ECC_ERROR1;
+ }
+ else if(nRet == 0) debug("No errors detected (page 0x%x, first part)\n", pageAddr);
+ else debug("Invalid data (page 0x%x, first part) was corrected using ECC!\n", pageAddr);
+
+ // now do the second part
+ nRet = NAND_correctData(&pPageBuff[256], &g_eccTest[3], &g_eccCalc[3]);
+ if(nRet == -1)
+ {
+ debug("ERROR - page data (page 0x%x, second part) Unable to correct invalid data!\n", pageAddr);
+ NAND_writeCTL(CS_NAND_CTL_CE); // disable chip
+ return ERROR_ECC_ERROR2;
+ }
+ else if(nRet == 0) debug("No errors detected (page 0x%x, second part)\n", pageAddr);
+ else debug("Invalid data (page 0x%x, second part) was corrected using ECC!\n", pageAddr);
+ }
+ }
+ else
+ {
+ debug("Page address [%d] is too large\n", pageAddr);
+ return ERROR_BAD_ADDRESS;
+ }
+
+ NAND_writeCTL(CS_NAND_CTL_CE); // disable chip
+ return ERROR_SUCCESS;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FILO interface functions
+
+int flash_probe(int drive)
+{
+ debug("drive %d\n", drive);
+ return NAND_initChip(drive);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+int flash_read(int drive, sector_t sector, void *buffer)
+{
+ int block, nRet;
+ uint32_t pageAddress = sector * DEV_SECTOR_SIZE / g_flashInfo.dataBytesPerPage;
+ uint32_t pageOffset = sector * DEV_SECTOR_SIZE % g_flashInfo.dataBytesPerPage;
+
+ // sanity check
+ if(!g_pBBT || !g_flashInfo.pagesPerBlock)
+ {
+ debug("error: NAND not initialized\n");
+ return -1;
+ }
+
+ // check that the page ID is valid
+ if(pageAddress >= (g_flashInfo.numBlocks * g_flashInfo.pagesPerBlock))
+ {
+ debug("error: sector offset %x out of range\n", sector);
+ return -2;
+ }
+
+ // get block address
+ block = pageAddress / g_flashInfo.pagesPerBlock;
+
+ debug("drive %d, sector %d -> page %d + %d, buffer 0x%08x\n",
+ drive, (unsigned int)sector, pageAddress, pageOffset, (unsigned int)buffer);
+
+ // get the block status first
+ if(g_pBBT[block] == BLOCK_UNKNOWN)
+ {
+ debug("checking block 0x%x status for BBT\n", block);
+ g_pBBT[block] = NAND_isBlockBad(block) ? BLOCK_BAD : BLOCK_GOOD;
+ }
+
+ // return failure immediately if the block is bad
+ if(g_pBBT[block] == BLOCK_BAD)
+ {
+ debug("error: block %x is bad\n", block);
+ return -3;
+ }
+
+ // check if we have just read that page
+ if(g_currentPage == pageAddress)
+ {
+ // should use cache instead
+ memcpy(buffer, g_pageBuf + pageOffset, DEV_SECTOR_SIZE);
+ return ERROR_SUCCESS;
+ }
+
+ // otherwise proceed with normal reading
+ nRet = NAND_readPage(pageAddress, g_pageBuf);
+ memcpy(buffer, g_pageBuf + pageOffset, DEV_SECTOR_SIZE);
+
+ return nRet;
+}
Added: trunk/filo-0.5/drivers/flash/lxflash.h
===================================================================
--- trunk/filo-0.5/drivers/flash/lxflash.h (rev 0)
+++ trunk/filo-0.5/drivers/flash/lxflash.h 2008-05-03 15:03:45 UTC (rev 48)
@@ -0,0 +1,155 @@
+#ifndef LXFLASH_H
+#define LXFLASH_H
+
+#define TRUE 1 // hmm that's quite obvious :)
+#define FALSE 0
+
+typedef struct msr_struct
+{
+ unsigned lo;
+ unsigned hi;
+} msr_t;
+
+static inline msr_t rdmsr(unsigned index)
+{
+ msr_t result;
+ __asm__ __volatile__ (
+ "rdmsr"
+ : "=a" (result.lo), "=d" (result.hi)
+ : "c" (index)
+ );
+ return result;
+}
+
+static inline void wrmsr(unsigned index, msr_t msr)
+{
+ __asm__ __volatile__ (
+ "wrmsr"
+ : /* No outputs */
+ : "c" (index), "a" (msr.lo), "d" (msr.hi)
+ );
+}
+
+typedef struct _FLASH_INFO
+{
+ unsigned long numBlocks;
+ unsigned long bytesPerBlock;
+ unsigned short pagesPerBlock;
+ unsigned short dataBytesPerPage;
+ unsigned short flashType;
+} FLASH_INFO;
+
+// NAND flash controller MSR registers
+
+#define MSR_DIVIL_LBAR_FLSH0 0x51400010 // Flash Chip Select 0
+#define MSR_DIVIL_LBAR_FLSH1 0x51400011 // Flash Chip Select 1
+#define MSR_DIVIL_LBAR_FLSH2 0x51400012 // Flash Chip Select 2
+#define MSR_DIVIL_LBAR_FLSH3 0x51400013 // Flash Chip Select 3
+
+#define MSR_DIVIL_BALL_OPTS 0x51400015
+#define PIN_OPT_IDE (1UL<<0) // 0 for flash, 1 for IDE
+
+#define MSR_NANDF_DATA 0x5140001B
+#define MSR_NANDF_CTL 0x5140001C
+
+// Intended value for LBAR_FLSHx: enabled, PIO, NAND, @0xC000
+
+#define SET_FLSH_HIGH 0x0000FFF3
+#define SET_FLSH_LOW 0x0000C000
+#define SET_NANDF_DATA_LOW 0x01200120
+#define SET_NANDF_CTL_LOW 0x00000120
+
+// ThinCan defaults
+
+#define PAGE_SIZE_512 512
+#define PAGE_SIZE_2048 2048
+#define MAX_PAGE_SIZE 2048
+#define MAX_ECC_SIZE 24
+#define READ_BLOCK_SIZE 256
+
+// VALIDADDR is 5 << 8
+//
+// Explain: 5 means the 6th byte in spare area (517 byte in the page)
+// Shift 8 bit to the left to form the correct address for 16bit port
+//
+#define VALIDADDR 0x05
+#define OEMADDR 0x04 // 5th byte in spare area
+
+// NAND Flash Command. This appears to be generic across all NAND flash chips
+
+#define CMD_READ 0x00 // Read
+#define CMD_READ1 0x01 // Read1
+#define CMD_READ2 0x50 // Read2
+#define CMD_READID 0x90 // ReadID
+#define CMD_READID2 0x91 // Read extended ID
+#define CMD_WRITE 0x80 // Write phase 1
+#define CMD_WRITE2 0x10 // Write phase 2
+#define CMD_ERASE 0x60 // Erase phase 1
+#define CMD_ERASE2 0xd0 // Erase phase 2
+#define CMD_STATUS 0x70 // Status read
+#define CMD_RESET 0xff // Reset
+#define CMD_READ_2K 0x30 // Second cycle read cmd for 2KB flash
+
+// Registers within the NAND flash controller BAR -- memory mapped
+
+#define MM_NAND_DATA 0x00 // 0 to 0x7ff, in fact
+#define MM_NAND_CTL 0x800 // Any even address 0x800-0x80e
+#define MM_NAND_IO 0x801 // Any odd address 0x801-0x80f
+#define MM_NAND_STS 0x810
+#define MM_NAND_ECC_LSB 0x811
+#define MM_NAND_ECC_MSB 0x812
+#define MM_NAND_ECC_COL 0x813
+#define MM_NAND_LAC 0x814
+#define MM_NAND_ECC_CTL 0x815
+
+// Registers within the NAND flash controller BAR -- I/O mapped
+
+#define IO_NAND_DATA 0x00 // 0 to 3, in fact
+#define IO_NAND_CTL 0x04
+#define IO_NAND_IO 0x05
+#define IO_NAND_STS 0x06
+#define IO_NAND_ECC_CTL 0x08
+#define IO_NAND_ECC_LSB 0x09
+#define IO_NAND_ECC_MSB 0x0a
+#define IO_NAND_ECC_COL 0x0b
+#define IO_NAND_LAC 0x0c
+
+#define CS_NAND_CTL_DIST_EN (1<<4) // Enable NAND Distract interrupt
+#define CS_NAND_CTL_RDY_INT_MASK (1<<3) // Enable RDY/BUSY# interrupt
+#define CS_NAND_CTL_ALE (1<<2)
+#define CS_NAND_CTL_CLE (1<<1)
+#define CS_NAND_CTL_CE (1<<0) // Keep low; 1 to reset
+
+#define CS_NAND_STS_FLASH_RDY (1<<3)
+#define CS_NAND_CTLR_BUSY (1<<2)
+#define CS_NAND_CMD_COMP (1<<1)
+#define CS_NAND_DIST_ST (1<<0)
+
+#define CS_NAND_ECC_PARITY (1<<2)
+#define CS_NAND_ECC_CLRECC (1<<1)
+#define CS_NAND_ECC_ENECC (1<<0)
+
+// Status bit pattern, read from chip register
+
+#define STATUS_READY 0x40 // Ready
+#define STATUS_ERROR 0x01 // Error
+
+#define FLASH_NOR 0
+#define FLASH_NAND 1
+
+#define SAMSUNG_NAND_64MB 0xc0a576ec
+#define SST_NAND_64MB 0x76207620
+#define SST_NAND_512MB 0x9580dc20
+
+#define ERROR_SUCCESS 0
+#define ERROR_BAD_PARAMS -1
+#define ERROR_ECC_ERROR1 1
+#define ERROR_ECC_ERROR2 2
+#define ERROR_BAD_ADDRESS 3
+#define ERROR_NO_ECC 4
+
+#define BLOCK_UNKNOWN 0
+#define BLOCK_BAD 2
+#define BLOCK_GOOD 1
+
+#endif
Modified: trunk/filo-0.5/fs/Makefile
===================================================================
--- trunk/filo-0.5/fs/Makefile 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/fs/Makefile 2008-05-03 15:03:45 UTC (rev 48)
@@ -14,5 +14,6 @@
OBJS-$(FSYS_CRAMFS) += mini_inflate.o
OBJS-$(FSYS_SQUASHFS) += fsys_squashfs.o
OBJS-$(FSYS_SQUASHFS) += squashfs_zlib.o
+OBJS-$(ARTEC_BOOT) += fsys_aboot.o
include $(TOPDIR)/makerules
Modified: trunk/filo-0.5/fs/blockdev.c
===================================================================
--- trunk/filo-0.5/fs/blockdev.c 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/fs/blockdev.c 2008-05-03 15:03:45 UTC (rev 48)
@@ -5,8 +5,9 @@
#define DEBUG_THIS DEBUG_BLOCKDEV
#include <debug.h>
-#define NUM_CACHE 64
-static unsigned char buf_cache[NUM_CACHE][512];
+#define NUM_CACHE 64
+
+static unsigned char buf_cache[NUM_CACHE][DEV_SECTOR_SIZE];
static unsigned long cache_sect[NUM_CACHE];
static char dev_name[256];
@@ -44,7 +45,7 @@
unsigned char start_sect[4]; /* unaligned little endian */
unsigned char nr_sects[4]; /* ditto */
} *p;
- unsigned char buf[512];
+ unsigned char buf[DEV_SECTOR_SIZE];
/* PC partition probe */
if (!devread(0, 0, sizeof(buf), buf)) {
@@ -53,7 +54,7 @@
}
if (!has_pc_part_magic(buf)) {
debug("pc partition magic number not found\n");
- //debug_hexdump(buf, 512);
+ //debug_hexdump(buf, DEV_SECTOR_SIZE);
return PARTITION_UNKNOWN;
}
p = (struct pc_partition *) (buf + 0x1be);
@@ -151,6 +152,16 @@
}
*drive = *name - 'a';
name++;
+ }
+ else if (memcmp(name, "flash", 5) == 0) {
+ *type = DISK_FLASH;
+ name += 5;
+ if (*name < 'a' || *name > 'z') {
+ printf("Invalid flash chip\n");
+ return 0;
+ }
+ *drive = *name - 'a';
+ name++;
} else if (memcmp(name, "mem", 3) == 0) {
*type = DISK_MEM;
name += 3;
@@ -198,13 +209,13 @@
}
/* Do simple sanity check first */
- if (offset & 0x1ff) {
- printf("Device offset must be multiple of 512\n");
+ if (offset & DEV_SECTOR_MASK) {
+ printf("Device offset must be multiple of %d\n", DEV_SECTOR_SIZE);
return 0;
}
- if (length & 0x1ff) {
- printf("WARNING: length is rounded up to multiple of 512\n");
- length = (length + 0x1ff) & ~0x1ff;
+ if (length & DEV_SECTOR_MASK) {
+ printf("WARNING: length is rounded up to multiple of %d\n", DEV_SECTOR_SIZE);
+ length = (length + DEV_SECTOR_MASK) & ~DEV_SECTOR_MASK;
}
switch (type) {
@@ -226,11 +237,24 @@
disk_size = (uint32_t) -1; /* FIXME */
break;
#endif
- case DISK_MEM:
- disk_size = 1 << (32 - 9); /* 4GB/512-byte */
+
+#ifdef FLASH_DISK
+ case DISK_FLASH:
+ if(flash_probe(drive) != 0)
+ {
+ debug("failed to open flash\n");
+ return 0;
+ }
+ disk_size = (uint32_t) -1; /* FIXME */
+ break;
+#endif
+
+ case DISK_MEM:
+ disk_size = 1 << (32 - DEV_SECTOR_BITS); /* 4GB/512-byte */
break;
- default:
- printf("Unknown device type %d\n", type);
+
+ default:
+ printf("Unknown device type %d\n", type);
return 0;
}
@@ -265,21 +289,21 @@
}
if (offset) {
- if (offset >= (uint64_t) part_length << 9) {
+ if (offset >= (uint64_t) part_length << DEV_SECTOR_BITS) {
printf("Device offset is too high\n");
return 0;
}
- part_start += offset >> 9;
- part_length -= offset >> 9;
+ part_start += offset >> DEV_SECTOR_BITS;
+ part_length -= offset >> DEV_SECTOR_BITS;
debug("after offset: start %lu, length %lu\n", part_start, part_length);
}
if (length) {
- if (length > (uint64_t) part_length << 9) {
+ if (length > (uint64_t) part_length << DEV_SECTOR_BITS) {
printf("Specified length exceeds the size of device\n");
return 0;
}
- part_length = length >> 9;
+ part_length = length >> DEV_SECTOR_BITS;
debug("after length: length %lu\n", part_length);
using_devsize = 0;
}
@@ -297,7 +321,7 @@
/* If reading memory, just return the memory as the buffer */
if (dev_type == DISK_MEM) {
- unsigned long phys = sector << 9;
+ unsigned long phys = sector << DEV_SECTOR_BITS;
//debug("mem: %#lx\n", phys);
return phys_to_virt(phys);
}
@@ -315,11 +339,19 @@
break;
#endif
#ifdef USB_DISK
- case DISK_USB:
- if (usb_read(dev_drive, sector, buf) != 0)
- goto readerr;
- break;
+ case DISK_USB:
+ if (usb_read(dev_drive, sector, buf) != 0)
+ goto readerr;
+ break;
#endif
+
+#ifdef FLASH_DISK
+ case DISK_FLASH:
+ if (flash_read(dev_drive, sector, buf) != 0)
+ return 0;
+ break;
+#endif
+
default:
printf("read_sector: device not open\n");
return 0;
Modified: trunk/filo-0.5/fs/filesys.h
===================================================================
--- trunk/filo-0.5/fs/filesys.h 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/fs/filesys.h 2008-05-03 15:03:45 UTC (rev 48)
@@ -182,6 +182,12 @@
int squashfs_dir (char *dirname);
#endif
+#ifdef ARTEC_BOOT
+int aboot_mount (void);
+int aboot_read (char *buf, int len);
+int aboot_dir (char *dirname);
+#endif
+
/* This is not a flag actually, but used as if it were a flag. */
#define PC_SLICE_TYPE_HIDDEN_FLAG 0x10
Added: trunk/filo-0.5/fs/fsys_aboot.c
===================================================================
--- trunk/filo-0.5/fs/fsys_aboot.c (rev 0)
+++ trunk/filo-0.5/fs/fsys_aboot.c 2008-05-03 15:03:45 UTC (rev 48)
@@ -0,0 +1,184 @@
+#ifdef ARTEC_BOOT
+
+/*******************************************************************************
+ *
+ * FILO Artecboot Virtual File System
+ *
+ * Copyright 2006 Andrei Birjukov <andrei.birjukov at artecdesign.ee> and
+ * Artec Design LLC http://www.artecdesign.ee
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ******************************************************************************/
+
+#include <lib.h>
+#include <fs.h>
+#include <sys_info.h>
+
+#include "artecboot.h"
+#include "shared.h"
+#include "filesys.h"
+
+#define DEBUG_THIS DEBUG_ARTECBOOT
+#include <debug.h>
+
+static ARTECBOOT_HEADER bootHdr;
+static uint32_t fileStart = 0;
+
+// device read helper, calls the block device read function
+// returns number of bytes parsed fthe stream
+
+int aboot_devread(char* pData, int nSize)
+{
+ char sectorBuf[DEV_SECTOR_SIZE];
+ uint32_t len, total=0;
+ int failCount = 128;
+
+ uint32_t sector = (fileStart + filepos) >> DEV_SECTOR_BITS;
+ uint32_t byteOffset = (fileStart + filepos) & DEV_SECTOR_MASK;
+
+ debug("file start %x, sector %x, offset %d\n", fileStart, sector, byteOffset);
+
+ if (sector + ((nSize + DEV_SECTOR_MASK) >> DEV_SECTOR_BITS) > part_length)
+ {
+ printf("Error: read outside of device device/partition\n");
+ debug("sector=%lu, partition size=%lu, read length=%lu\n",
+ (unsigned long)sector, (unsigned long)part_length, (unsigned long)nSize);
+ return 0;
+ }
+
+ while (nSize > 0)
+ {
+ if (!devread(sector, 0, DEV_SECTOR_SIZE, sectorBuf))
+ {
+ debug("sector 0x%x read failed\n", sector);
+ // do not abort immediately, try some more
+ if((failCount --) == 0) return 0;
+
+ sector ++; // try the next sector
+ total += DEV_SECTOR_SIZE;
+ continue;
+ }
+
+ len = SECTOR_SIZE - byteOffset;
+ if (len > nSize)
+ len = nSize;
+ memcpy(pData, sectorBuf + byteOffset, len);
+
+ sector ++;
+ byteOffset = 0;
+
+ nSize -= len;
+ pData += len;
+ total += len;
+ }
+
+ // return number of bytes read from the stream
+ return total;
+}
+
+int aboot_mount(void)
+{
+ debug("Mounting Artecboot VFS...\n");
+ // clear the boot header
+ memset(&bootHdr, 0, sizeof(bootHdr));
+
+ fileStart = 0;
+ filepos = 0;
+
+ // now read out the boot header
+ if(aboot_devread((char*)&bootHdr, sizeof(ARTECBOOT_HEADER)) < sizeof(ARTECBOOT_HEADER))
+ {
+ debug("Boot error: failed reading the boot image header\n");
+ return 0;
+ }
+
+ // check whether the flash data is valid at all
+ if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC)
+ {
+ debug("No Artecboot signature found, aborting\n");
+ return 0;
+ }
+
+ // check the version number
+ if(bootHdr.bootVersion > CURRENT_VERSION)
+ {
+ debug("Boot error: incompatible version number: %x\n", bootHdr.bootVersion);
+ return 0;
+ }
+
+ // align the partition length to the sector size
+ part_length = ((bootHdr.imageSize - 1) >> DEV_SECTOR_BITS) + 1;
+ return 1;
+}
+
+int aboot_read(char *buf, int len)
+{
+ int read;
+ // sanity check
+ if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC) return 0;
+ debug("reading %d bytes to %x...\n", len, (unsigned int)buf);
+
+ read = aboot_devread(buf, len);
+ filepos += read; // advance current position
+
+ debug("read %d bytes, pos %x\n", read, filepos);
+
+ // returned length may be greater than requested size because of skipped bad blocks
+ if(read >= len) return len;
+ return 0;
+}
+
+int aboot_dir(char *dirname)
+{
+ int nRet = 0;
+ // sanity check
+ if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC) return 0;
+
+ // we can only recognize certain hardcoded filenames
+ if(!strcmp(dirname, ABOOT_FILE_HEADER))
+ {
+ filepos = 0;
+ fileStart = 0;
+ filemax = sizeof(ARTECBOOT_HEADER);
+ nRet = 1;
+ }
+ else if(!strcmp(dirname, ABOOT_FILE_KERNEL))
+ {
+ filepos = 0;
+ fileStart = bootHdr.kernelStart;
+ filemax = bootHdr.kernelSize;
+ nRet = 1;
+ }
+ else if(!strcmp(dirname, ABOOT_FILE_INITRD))
+ {
+ filepos = 0;
+ fileStart = bootHdr.initrdStart;
+ filemax = bootHdr.initrdSize;
+ nRet = 1;
+ }
+ else
+ {
+ // unknown file
+ filepos = 0;
+ filemax = 0;
+ nRet = 0;
+ }
+
+ debug("open file: %s, size %d, dev start %x\n", dirname, filemax, fileStart);
+ return nRet;
+}
+
+#endif
Modified: trunk/filo-0.5/fs/vfs.c
===================================================================
--- trunk/filo-0.5/fs/vfs.c 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/fs/vfs.c 2008-05-03 15:03:45 UTC (rev 48)
@@ -25,33 +25,37 @@
struct fsys_entry fsys_table[] = {
# ifdef FSYS_FAT
- {"fat", fat_mount, fat_read, fat_dir, 0, 0},
+ {"FAT filesystem", fat_mount, fat_read, fat_dir, 0, 0},
# endif
# ifdef FSYS_EXT2FS
- {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},
+ {"EXT2 filesystem", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},
# endif
# ifdef FSYS_MINIX
- {"minix", minix_mount, minix_read, minix_dir, 0, 0},
+ {"MINIX filesystem", minix_mount, minix_read, minix_dir, 0, 0},
# endif
# ifdef FSYS_REISERFS
- {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, 0,
+ {"REISERFS filesystem", reiserfs_mount, reiserfs_read, reiserfs_dir, 0,
reiserfs_embed},
# endif
# ifdef FSYS_JFS
- {"jfs", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed},
+ {"JFS filesystem", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed},
# endif
# ifdef FSYS_XFS
- {"xfs", xfs_mount, xfs_read, xfs_dir, 0, 0},
+ {"XFS filesystem", xfs_mount, xfs_read, xfs_dir, 0, 0},
# endif
# ifdef FSYS_ISO9660
- {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},
+ {"ISO9660 filesystem", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},
# endif
# ifdef FSYS_CRAMFS
- {"cramfs", cramfs_mount, cramfs_read, cramfs_dir, 0, 0},
+ {"CRAM filesystem", cramfs_mount, cramfs_read, cramfs_dir, 0, 0},
# endif
# ifdef FSYS_SQUASHFS
- {"squashfs", squashfs_mount, squashfs_read, squashfs_dir, 0, 0},
+ {"SQUASH filesystem", squashfs_mount, squashfs_read, squashfs_dir, 0, 0},
# endif
+# ifdef ARTEC_BOOT
+ {"Artecboot Virtual Filesystem", aboot_mount, aboot_read, aboot_dir, 0, 0},
+# endif
+
};
/* NULLFS is used to read images from raw device */
@@ -172,11 +176,14 @@
if (len < 0 || len > filemax-filepos)
len = filemax - filepos;
errnum = 0;
- return fsys->read_func(buf, len);
+
+ debug("reading %d bytes, offset 0x%x\n", len, filepos);
+ return fsys->read_func(buf, len);
}
int file_seek(unsigned long offset)
{
+ debug("seeking to 0x%x\n", offset);
filepos = offset;
return filepos;
}
@@ -186,6 +193,13 @@
return filemax;
}
+void file_set_size(unsigned long size)
+{
+ debug("updating file size to %d bytes\n", size);
+ filemax = size;
+ using_devsize = 0;
+}
+
void file_close(void)
{
}
Modified: trunk/filo-0.5/i386/Makefile
===================================================================
--- trunk/filo-0.5/i386/Makefile 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/i386/Makefile 2008-05-03 15:03:45 UTC (rev 48)
@@ -4,5 +4,6 @@
OBJS-1 := context.o switch.o segment.o timer.o sys_info.o
OBJS-$(LINUX_LOADER) += linux_load.o
OBJS-$(MULTIBOOT_IMAGE) += multiboot.o
+OBJS-$(ARTEC_BOOT) += artecboot.o
include $(TOPDIR)/makerules
Added: trunk/filo-0.5/i386/artecboot.c
===================================================================
--- trunk/filo-0.5/i386/artecboot.c (rev 0)
+++ trunk/filo-0.5/i386/artecboot.c 2008-05-03 15:03:45 UTC (rev 48)
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ *
+ * FILO Artecboot loader, enables multiboot through custom header
+ *
+ * Copyright 2006 Andrei Birjukov <andrei.birjukov at artecdesign.ee> and
+ * Artec Design LLC http://www.artecdesign.ee
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ******************************************************************************/
+
+#include <lib.h>
+#include <fs.h>
+#include <sys_info.h>
+#include "artecboot.h"
+#include "../fs/filesys.h"
+
+#define DEBUG_THIS DEBUG_ARTECBOOT
+#include <debug.h>
+
+static ARTECBOOT_HEADER bootHdr;
+
+int artecboot_load(struct sys_info *info, const char *file, const char *cmdline)
+{
+ int i;
+
+ printf("Starting the Artecboot loader...\n");
+ // clear the boot header
+ memset(&bootHdr, 0, sizeof(bootHdr));
+
+ // try opening the boot parameter file
+ if (!file_open(file))
+ {
+ printf("Boot error: failed to open image file: %s\n", file);
+ return LOADER_NOT_SUPPORT;
+ }
+
+ file_seek(0); // seek to the beginning of the parameter file
+
+ // now read out the boot header
+ if(file_read(&bootHdr, sizeof(ARTECBOOT_HEADER)) != sizeof(ARTECBOOT_HEADER))
+ {
+ printf("Boot error: failed reading the boot image header\n");
+ return LOADER_NOT_SUPPORT;
+ }
+
+ // check whether the parameter data is valid at all
+ if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC)
+ {
+ debug("No Artecboot signature found, aborting\n");
+ return LOADER_NOT_SUPPORT;
+ }
+
+ // check the version number
+ if(bootHdr.bootVersion > CURRENT_VERSION)
+ {
+ printf("Boot error: incompatible version number: %x\n", bootHdr.bootVersion);
+ return LOADER_NOT_SUPPORT;
+ }
+
+ // shall we replace the command line?
+ if(bootHdr.bitFlags & FLAG_CMDLINE)
+ {
+ // check the command line and wipe out all junk
+ for(i=0; bootHdr.cmdLine[i] != 0; i++)
+ switch(bootHdr.cmdLine[i])
+ {
+ case '\n':
+ case '\r':
+ bootHdr.cmdLine[i] = ' ';
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ }
+ else if(cmdline)
+ strncpy(bootHdr.cmdLine, cmdline, sizeof(bootHdr.cmdLine));
+
+ // proceed basing on the specified OS type
+ switch(bootHdr.osType)
+ {
+ case OS_LINUX:
+ if(bootHdr.bitFlags & FLAG_INITRD)
+ {
+ char initrdParam[100];
+ if(bootHdr.bitFlags & FLAG_FILESYSTEM)
+ {
+ // we are using a real filesystem, so format the initrd file as usually
+ sprintf(initrdParam, " initrd=%s", bootHdr.initrdFile);
+ }
+ else
+ {
+ // we are using a 'fake' filesystem, so use the image offset
+ sprintf(initrdParam, " initrd=flashb at 0x%x,0x%x",
+ bootHdr.initrdStart, bootHdr.initrdSize);
+ }
+
+ debug("adding initrd parameter: %s\n", initrdParam);
+ strncat(bootHdr.cmdLine, initrdParam, sizeof(bootHdr.cmdLine));
+ }
+
+ printf("Starting Linux loader...\n");
+
+ // if using a real filesystem, load the kernel image from a specified file
+ if(bootHdr.bitFlags & FLAG_FILESYSTEM)
+ linux_load(info, bootHdr.kernelFile, bootHdr.cmdLine);
+ // if using a 'fake' filesystem, consider reading from the same image
+ else
+ {
+ part_start = bootHdr.kernelStart >> DEV_SECTOR_BITS;
+ part_length = ((bootHdr.kernelSize-1) >> DEV_SECTOR_BITS) + 1;
+ filemax = bootHdr.kernelSize;
+ linux_load(info, file, bootHdr.cmdLine);
+ }
+
+ break;
+
+ case OS_WINCE:
+
+ printf("Starting Windows CE loader...\n");
+ // if using a real filesystem, load the kernel image from a specified file
+ if(bootHdr.bitFlags & FLAG_FILESYSTEM)
+ wince_load(info, bootHdr.kernelFile, bootHdr.cmdLine);
+ // if using a 'fake' filesystem, consider reading from the same image
+ else
+ {
+ part_start = bootHdr.kernelStart >> DEV_SECTOR_BITS;
+ part_length = ((bootHdr.kernelSize-1) >> DEV_SECTOR_BITS) + 1;
+ filemax = bootHdr.kernelSize;
+ wince_load(info, file, bootHdr.cmdLine);
+ }
+
+ break;
+
+ default:
+ printf("Boot error: unknown OS type, aborting: %d\n", bootHdr.osType);
+ return LOADER_NOT_SUPPORT;
+ }
+
+ return 0;
+}
Modified: trunk/filo-0.5/i386/defconfig
===================================================================
--- trunk/filo-0.5/i386/defconfig 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/i386/defconfig 2008-05-03 15:03:45 UTC (rev 48)
@@ -3,6 +3,13 @@
# Loader for standard Linux kernel image, a.k.a. /vmlinuz
LINUX_LOADER = 1
+# Loader for Windows CE image
+# Leave disabled for now. Not supported.
+#WINCE_LOADER = 1
+
+# Artecboot loader support
+#ARTEC_BOOT = 1
+
# Boot FILO from Multiboot loader (eg. GRUB)
#MULTIBOOT_IMAGE = 1
Modified: trunk/filo-0.5/i386/linux_load.c
===================================================================
--- trunk/filo-0.5/i386/linux_load.c 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/i386/linux_load.c 2008-05-03 15:03:45 UTC (rev 48)
@@ -164,11 +164,11 @@
uint32_t kern_addr;
if (file_read(hdr, sizeof *hdr) != sizeof *hdr) {
- debug("Can't read Linux header\n");
+ printf("Can't read Linux header\n");
return 0;
}
if (hdr->boot_sector_magic != 0xaa55) {
- debug("Not a Linux kernel image\n");
+ printf("Not a Linux kernel image\n");
return 0;
}
@@ -178,7 +178,7 @@
* Perform a simple (incomplete) sanity check. */
if (hdr->setup_sects >= 16
|| file_size() - (hdr->setup_sects<<9) >= 512<<10) {
- debug("This looks like a bootdisk image but not like Linux...\n");
+ printf("This looks like a bootdisk image but not like Linux...\n");
return 0;
}
Added: trunk/filo-0.5/include/artecboot.h
===================================================================
--- trunk/filo-0.5/include/artecboot.h (rev 0)
+++ trunk/filo-0.5/include/artecboot.h 2008-05-03 15:03:45 UTC (rev 48)
@@ -0,0 +1,34 @@
+// Artecboot header, gives information to loader
+
+#define ARTECBOOT_HEADER_MAGIC 0x10ADFACE
+#define CURRENT_VERSION 0x0102
+
+#define OS_UNKNOWN 0x00
+#define OS_LINUX 0x01
+#define OS_WINCE 0x02
+
+#define FLAG_INITRD 0x0001 // if set, the loader will provide initrd to kernel
+#define FLAG_FILESYSTEM 0x0002 // if set, the loader will use specified file names
+#define FLAG_CMDLINE 0x0004 // if set, the loader will pass the new command line
+
+typedef struct __attribute__ ((packed))
+{
+ unsigned long magicHeader;
+ unsigned short bootVersion;
+ unsigned short headerSize; // also kernel image start
+ unsigned long imageSize; // NB! since 1.02 is the total image/partition size
+ unsigned long bitFlags;
+ unsigned short osType;
+ char cmdLine[256];
+ unsigned long kernelStart; // used with Artecboot VFS / NULLFS
+ unsigned long kernelSize; // used with Artecboot VFS / NULLFS
+ unsigned long initrdStart; // used with Artecboot VFS / NULLFS
+ unsigned long initrdSize; // used with Artecboot VFS / NULLFS
+ char kernelFile[100]; // valid only with FLAG_FILESYSTEM
+ char initrdFile[100]; // valid only with FLAG_FILESYSTEM
+
+} ARTECBOOT_HEADER;
+
+#define ABOOT_FILE_KERNEL "/kernel"
+#define ABOOT_FILE_INITRD "/initrd"
+#define ABOOT_FILE_HEADER "/header"
Modified: trunk/filo-0.5/include/fs.h
===================================================================
--- trunk/filo-0.5/include/fs.h 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/include/fs.h 2008-05-03 15:03:45 UTC (rev 48)
@@ -5,6 +5,10 @@
typedef uint64_t sector_t;
+#define DEV_SECTOR_BITS 9
+#define DEV_SECTOR_SIZE (1<<9)
+#define DEV_SECTOR_MASK (DEV_SECTOR_SIZE-1)
+
#ifdef IDE_DISK
int ide_probe(int drive);
int ide_read(int drive, sector_t sector, void *buffer);
@@ -15,20 +19,29 @@
int usb_read(int drive, sector_t sector, void *buffer);
#endif
+#ifdef FLASH_DISK
+int flash_probe(int drive);
+int flash_read(int drive, sector_t sector, void *buffer);
+#endif
+
#define DISK_IDE 1
#define DISK_MEM 2
#define DISK_USB 3
+#define DISK_FLASH 4
int devopen(const char *name, int *reopen);
int devread(unsigned long sector, unsigned long byte_offset,
unsigned long byte_len, void *buf);
+void dev_set_partition(unsigned long start, unsigned long size);
+void dev_get_partition(unsigned long *start, unsigned long *size);
int file_open(const char *filename);
int file_read(void *buf, unsigned long len);
int file_seek(unsigned long offset);
unsigned long file_size(void);
+void file_set_size(unsigned long size);
-#define PARTITION_UNKNOWN 0xbad6a7
+#define PARTITION_UNKNOWN 0xbad6a7
#ifdef ELTORITO
int open_eltorito_image(int part, unsigned long *start, unsigned long *length);
Modified: trunk/filo-0.5/include/lib.h
===================================================================
--- trunk/filo-0.5/include/lib.h 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/include/lib.h 2008-05-03 15:03:45 UTC (rev 48)
@@ -58,6 +58,8 @@
char *strncpy(char *to, const char *from, int count);
char * strcpy (char *dest, const char *src);
char * strstr (const char *s1, const char *s2);
+int strncat (char *s1, const char *s2, int n);
+int sprintf(char * buf, const char *fmt, ...);
unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base);
unsigned long long strtoull_with_suffix(const char *cp,char **endp,unsigned int base);
@@ -83,4 +85,16 @@
#define linux_load(x,y,z) LOADER_NOT_SUPPORT /* nop */
#endif
+#if WINCE_LOADER
+int wince_load(struct sys_info *, const char *filename, const char *cmdline);
+#else
+#define wince_load(x,y,z) LOADER_NOT_SUPPORT /* nop */
+#endif
+
+#if ARTEC_BOOT
+int artecboot_load(struct sys_info *, const char *filename, const char *cmdline);
+#else
+#define artecboot_load(x,y,z) LOADER_NOT_SUPPORT /* nop */
+#endif
+
#endif /* LIB_H */
Modified: trunk/filo-0.5/main/console.c
===================================================================
--- trunk/filo-0.5/main/console.c 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/main/console.c 2008-05-03 15:03:45 UTC (rev 48)
@@ -1,10 +1,13 @@
#include <arch/stdint.h>
#include <lib.h>
+void video_cls();
+
void console_init(void)
{
#ifdef VGA_CONSOLE
- vga_init();
+ vga_init();
+ video_cls();
#endif
#ifdef SERIAL_CONSOLE
serial_init();
Modified: trunk/filo-0.5/main/filo.c
===================================================================
--- trunk/filo-0.5/main/filo.c 2008-05-03 14:48:04 UTC (rev 47)
+++ trunk/filo-0.5/main/filo.c 2008-05-03 15:03:45 UTC (rev 48)
@@ -49,8 +49,10 @@
param++;
}
+ if (artecboot_load(&sys_info, file, param) == LOADER_NOT_SUPPORT)
if (elf_load(&sys_info, file, param) == LOADER_NOT_SUPPORT)
if (linux_load(&sys_info, file, param) == LOADER_NOT_SUPPORT)
+ if (wince_load(&sys_info, file, param) == LOADER_NOT_SUPPORT)
printf("Unsupported image format\n");
free(file);
}
More information about the coreboot
mailing list