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@0xfff80000" #AUTOBOOT_FILE = "hde1@0" #AUTOBOOT_FILE = "uda1:/vmlinuz.elf" +#AUTOBOOT_FILE = "flashb@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@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@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@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@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); }