diff -uNr grub/configure.in grub-doc/configure.in --- grub/configure.in Thu Oct 5 05:43:25 2000 +++ grub-doc/configure.in Thu Oct 12 13:58:53 2000 @@ -216,6 +216,14 @@ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_REISERFS=1" fi +AC_ARG_ENABLE(diskonchip, + [ --enable-diskonchip enable DiskOnChip 2000 support in Stage 2]) + +if test x"$enable_diskonchip" = xyes; then + FSYS_CFLAGS="$FSYS_CFLAGS -DBDEV_DISKONCHIP=1" +fi + + dnl AC_ARG_ENABLE(tftp, dnl [ --enable-tftp enable TFTP support in Stage 2]) dnl diff -uNr grub/stage2/Makefile.am grub-doc/stage2/Makefile.am --- grub/stage2/Makefile.am Sun Aug 20 13:14:14 2000 +++ grub-doc/stage2/Makefile.am Thu Oct 12 13:59:36 2000 @@ -72,7 +72,7 @@ pre_stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c common.c \ char_io.c cmdline.c disk_io.c gunzip.c fsys_ext2fs.c \ fsys_fat.c fsys_ffs.c fsys_minix.c fsys_reiserfs.c serial.c \ - smp-imps.c stage2.c + smp-imps.c stage2.c bdev_diskonchip.c pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK) diff -uNr grub/stage2/bdev_diskonchip.c grub-doc/stage2/bdev_diskonchip.c --- grub/stage2/bdev_diskonchip.c Thu Jan 1 01:00:00 1970 +++ grub-doc/stage2/bdev_diskonchip.c Thu Oct 12 13:58:53 2000 @@ -0,0 +1,819 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * 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. + */ + +#ifdef BDEV_DISKONCHIP + +/* #define DOC_DEBUG */ + +#include "shared.h" + +#define DoC_M_CDSN_IO 0x800 + +#define DoC_ChipID 0x1000 +#define DoC_DOCStatus 0x1001 +#define DoC_DOCControl 0x1002 +#define DoC_FloorSelect 0x1003 +#define DoC_CDSNControl 0x1004 +#define DoC_CDSNDeviceSelect 0x1005 +#define DoC_ECCConf 0x1006 +#define DoC_2k_ECCStatus 0x1007 + +#define DoC_CDSNSlowIO 0x100d +#define DoC_ECCSyndrome0 0x1010 +#define DoC_ECCSyndrome1 0x1011 +#define DoC_ECCSyndrome2 0x1012 +#define DoC_ECCSyndrome3 0x1013 +#define DoC_ECCSyndrome4 0x1014 +#define DoC_ECCSyndrome5 0x1015 +#define DoC_AliasResolution 0x101b +#define DoC_ConfigInput 0x101c +#define DoC_ReadPipeInit 0x101d +#define DoC_WritePipeTerm 0x101e +#define DoC_LastDataRead 0x101f +#define DoC_NOP 0x1020 + +#define DoC_2k_CDSN_IO 0x1800 + +#define DOC_MODE_RESET 0 +#define DOC_MODE_NORMAL 1 +#define DOC_MODE_RESERVED1 2 +#define DOC_MODE_RESERVED2 3 + +#define DOC_MODE_MDWREN 4 +#define DOC_MODE_CLR_ERR 0x80 + +#define DOC_ChipID_Doc2k 0x20 +#define DOC_ChipID_DocMil 0x30 + +#define CDSN_CTRL_FR_B 0x80 +#define CDSN_CTRL_ECC_IO 0x20 +#define CDSN_CTRL_FLASH_IO 0x10 +#define CDSN_CTRL_WP 8 +#define CDSN_CTRL_ALE 4 +#define CDSN_CTRL_CLE 2 +#define CDSN_CTRL_CE 1 + +#define DOC_ECC_RESET 0 +#define DOC_ECC_ERROR 0x80 +#define DOC_ECC_RW 0x20 +#define DOC_ECC__EN 0x08 +#define DOC_TOGGLE_BIT 0x04 +#define DOC_ECC_RESV 0x02 +/* We have to also set the reserved bit 1 for enable */ +#define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV) + +#define MAX_FLOORS 4 +#define MAX_CHIPS 4 + +#define NAND_CMD_READ0 0 +#define NAND_CMD_READ1 1 +#define NAND_CMD_PAGEPROG 0x10 +#define NAND_CMD_READOOB 0x50 +#define NAND_CMD_ERASE1 0x60 +#define NAND_CMD_STATUS 0x70 +#define NAND_CMD_SEQIN 0x80 +#define NAND_CMD_READID 0x90 +#define NAND_CMD_ERASE2 0xd0 +#define NAND_CMD_RESET 0xff + +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_SAMSUNG 0xec + +#define ERASE_SIZE 0x2000 +#define ERASE_SECT (ERASE_SIZE >> 9) +#define MAX_NFTLS 16 + +#define ERASE_MARK 0x3c69 +#define BLOCK_FREE 0xffff +#define BLOCK_USED 0x5555 +#define BLOCK_IGNORE 0x1111 +#define BLOCK_DELETED 0x0000 + +struct NFTLMediaHeader +{ + char DataOrgID[6]; + unsigned short NumEraseUnits; + unsigned short FirstPhysicalEUN; + unsigned long FormattedSize; + unsigned char UnitSizeFactor; +} __attribute__((packed)); + +struct NFTLrecord +{ + unsigned short MediaUnit, SpareMediaUnit; + struct NFTLMediaHeader MediaHdr; + unsigned short numvunits; + unsigned short lastEUN; /* last + 1 */ +}; + +/* Block Control Information */ + +struct nftl_bci +{ + unsigned char ECCSig[6]; + unsigned short Status; +} __attribute__((packed)); + +/* Unit Control Information */ + +struct nftl_uci0 +{ + unsigned short VirtUnitNum; + unsigned short ReplUnitNum; + unsigned short SpareVirtUnitNum; + unsigned short SpareReplUnitNum; +} __attribute__((packed)); + +struct nftl_uci1 +{ + unsigned long WearInfo; + unsigned short EraseMark; + unsigned short EraseMark1; +} __attribute__((packed)); + +struct nftl_uci2 +{ + unsigned long WriteInh; + unsigned long unused; +} __attribute__((packed)); + +union nftl_uci +{ + struct nftl_uci0 a; + struct nftl_uci1 b; + struct nftl_uci2 c; +}; + +struct nftl_oob +{ + struct nftl_bci b; + union nftl_uci u; +}; + +static int doc_inited = 0; +static volatile unsigned char *docloc = NULL; +static int numchips[MAX_FLOORS]; +static int totalchips=0; +static int chipshift=0; +static unsigned char nftlbuf[512]; + +static struct NFTLrecord NFTLs[MAX_NFTLS]; +static int nNFTLs = 0; + +/* badtable cache */ +static unsigned char badtableblock[512]; +static int badtablestart = -1; +static int badtablenftl = -1; + +static int _DoC_WaitReady(void) +{ + short c=-1; + + while (!(docloc[DoC_CDSNControl] & CDSN_CTRL_FR_B) && --c) + ; + + if (c == 0) + grub_printf("_DoC_WaitReady timed out\n"); + + return (c==0); +} + +static inline int DoC_WaitReady(void) +{ + volatile unsigned char dummy; + int ret = 0; + + dummy = docloc[DoC_CDSNControl]; + dummy = docloc[DoC_CDSNControl]; + dummy = docloc[DoC_CDSNControl]; + dummy = docloc[DoC_CDSNControl]; + + if (!(docloc[DoC_CDSNControl] & CDSN_CTRL_FR_B)) + ret = _DoC_WaitReady(); + + dummy = docloc[DoC_CDSNControl]; + dummy = docloc[DoC_CDSNControl]; + + return ret; +} + +static inline void DoC_Command(unsigned char command, unsigned char xtraflags) +{ + docloc[DoC_CDSNControl] = + CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE; + + docloc[DoC_2k_CDSN_IO] = command; + + docloc[DoC_CDSNControl] = + CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CE; +} + +static int DoC_IdentChip(unsigned char floor, unsigned char chip) +{ + int mfr, id, thischipshift=0; + + docloc[DoC_FloorSelect] = floor; + docloc[DoC_CDSNDeviceSelect] = chip; + + DoC_Command(NAND_CMD_RESET, CDSN_CTRL_WP); + + if (DoC_WaitReady()) + return 0; + + DoC_Command(NAND_CMD_READID, CDSN_CTRL_WP); + + + /* Send a zero address */ + docloc[DoC_CDSNControl] = + CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP | CDSN_CTRL_ALE | CDSN_CTRL_CE; + docloc[DoC_2k_CDSN_IO] = 0; + + docloc[DoC_CDSNControl] = + CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP | CDSN_CTRL_CE; + + mfr = docloc[DoC_2k_CDSN_IO]; + id = docloc[DoC_2k_CDSN_IO]; + + /* + if (mfr != NAND_MFR_TOSHIBA && mfr != NAND_MFR_SAMSUNG) + return 0; + */ + switch (mfr) + { + case NAND_MFR_TOSHIBA: + grub_printf("floor %d, chip %d; ", floor, chip); + grub_printf("manufacturer: Toshiba\n"); + break; + case NAND_MFR_SAMSUNG: + grub_printf("floor %d, chip %d; ", floor, chip); + grub_printf("manufacturer: Samsung\n"); + break; + default: + /* grub_printf("unknown manufacturer code: 0x%x\n", mfr); */ + return 0; + } + + switch (id) { + case 0x64: + case 0xea: + thischipshift = 21; + break; + + case 0x6b: + case 0xe5: + case 0xe3: + thischipshift = 22; + break; + + case 0xe6: + thischipshift = 23; + break; + + case 0x73: + thischipshift = 24; + break; + + case 0x75: + thischipshift = 25; + break; + + default: + } + + if (!chipshift) { + chipshift = thischipshift; + grub_printf("chipshift: %d\n", chipshift); + grub_printf("DiskOnChip NAND chip size: %x Mb\n", 1 << + (chipshift - 20)); + } + + return 1; +} + +static void DoC_ScanChips(void) +{ + unsigned char floor, chip; + int ret; + + for (floor = 0; floor < MAX_FLOORS; floor++) { + ret = 1; + numchips[floor]=0; + for (chip = 0; chip < MAX_CHIPS && ret != 0; chip++) { + ret = DoC_IdentChip(floor, chip); + if (ret) { + numchips[floor]++; + totalchips++; + } + } + } +} + + +static int DoC_Probe(volatile unsigned char *loc) +{ + unsigned char tmp; + unsigned char ChipID; +#ifndef DOC_PASSIVE_PROBE + unsigned char tmp2; +#endif + + if ((loc[0] != 0x55) || (loc[1] != 0xaa)) + return 0; + +#ifndef DOC_PASSIVE_PROBE + tmp2 = loc[DoC_DOCControl]; + + loc[DoC_DOCControl] = + DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET; + loc[DoC_DOCControl] = + DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET; + + loc[DoC_DOCControl] = + DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL; + loc[DoC_DOCControl] = + DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL; +#endif + + ChipID = loc[DoC_ChipID]; + + if (ChipID == DOC_ChipID_DocMil) { + grub_printf("DiskOnChip Millennium found at %x but not supported yet\n", + (unsigned int)loc); + return 0; + } + + if (ChipID != DOC_ChipID_Doc2k) { +#ifndef DOC_PASSIVE_PROBE + loc[DoC_DOCControl] = tmp2; +#endif + return 0; + } + + /* See if the TOGGLE bit is toggling */ + + tmp = loc[DoC_2k_ECCStatus] & DOC_TOGGLE_BIT; + if (tmp == (loc[DoC_2k_ECCStatus] & DOC_TOGGLE_BIT)) { +#ifndef DOC_PASSIVE_PROBE + loc[DoC_DOCControl] = tmp2; +#endif + return 0; + } + + /* OK. We're fairly sure it's a DiskOnChip now. */ + grub_printf("DiskOnChip 2000 found at %x\n", (unsigned int)loc); + docloc = loc; + + DoC_ScanChips(); + + if (!totalchips) + return 0; + grub_printf("Total of %d chips found - total capacity %d Mb\n", + totalchips, totalchips * ( 1 << (chipshift -20))); + return 1; +} + +static int doc_read_oob(unsigned long sector, void *buf) +{ + unsigned char chip, floor; + int di; + + chip = sector >> (chipshift - 9); + floor = 0; + + while (chip >= numchips[floor]) { + chip -= numchips[floor]; + floor++; + if (floor == MAX_FLOORS) + return -1; + } + + /* grub_printf("sector 0x%x is on floor %d, chip %d\n", + sector, floor, chip); */ + + docloc[DoC_FloorSelect] = floor; + docloc[DoC_CDSNDeviceSelect] = chip; + + DoC_Command(NAND_CMD_READOOB, CDSN_CTRL_WP); + + DoC_WaitReady(); + + docloc[DoC_CDSNControl] = + CDSN_CTRL_FLASH_IO |CDSN_CTRL_WP | CDSN_CTRL_ALE | CDSN_CTRL_CE; + + docloc[DoC_2k_CDSN_IO] = 0; + docloc[DoC_2k_CDSN_IO] = sector & 0xff; + docloc[DoC_2k_CDSN_IO] = (sector >> 8) & 0xff; + + docloc[DoC_CDSNControl] = + CDSN_CTRL_FLASH_IO |CDSN_CTRL_WP | CDSN_CTRL_CE; + + DoC_WaitReady(); + + for (di=0; di < 16; di++) { + ((unsigned char *)buf)[di] = docloc[DoC_2k_CDSN_IO]; + } + + return 0; +} + +static int doc_read_sector(unsigned long sector, unsigned char *buf) +{ + unsigned char chip, floor; + int di; + + chip = sector >> (chipshift - 9); + floor = 0; + + // grub_printf("sector %d\n", sector); + + while (chip >= numchips[floor]) { + // grub_printf("Chip %d Not on floor %d (%d chips)\n", chip, floor, numchips[floor]); + chip -= numchips[floor]; + floor++; + if (floor == MAX_FLOORS) + return -1; + } + + // grub_printf("sector 0x%x is on floor %d, chip %d\n", + // sector, floor, chip); + + docloc[DoC_FloorSelect] = floor; + docloc[DoC_CDSNDeviceSelect] = chip; + + DoC_Command(NAND_CMD_READ0, CDSN_CTRL_WP); + + DoC_WaitReady(); + + docloc[DoC_CDSNControl] = + CDSN_CTRL_FLASH_IO |CDSN_CTRL_WP | CDSN_CTRL_ALE | CDSN_CTRL_CE; + + docloc[DoC_2k_CDSN_IO] = 0; + docloc[DoC_2k_CDSN_IO] = sector & 0xff; + docloc[DoC_2k_CDSN_IO] = (sector >> 8) & 0xff; + + docloc[DoC_CDSNControl] = + CDSN_CTRL_FLASH_IO |CDSN_CTRL_WP | CDSN_CTRL_CE; + + DoC_WaitReady(); + + for (di=0; di < 512; di++) { + buf[di] = docloc[DoC_2k_CDSN_IO]; + } + + return 0; +} + +static +void NFTL_setup(unsigned long sect, struct NFTLMediaHeader *hdr) +{ + int i; + unsigned int eun = sect / ERASE_SECT; + struct NFTLrecord *nftl; + + for (i=0; iFirstPhysicalEUN) + { + /* This is a Spare Media Header for an NFTL we've already found */ + printf("Spare Media Header for NFTL %d found in flash sector %d\n", + i, sect); + NFTLs[i].SpareMediaUnit = eun; + return; + } + } + printf("NFTL Media Header found in flash sector %d\n", sect); + + if (hdr->UnitSizeFactor != 0xff) + { + printf("Sorry, we don't support UnitSizeFactor of != 1 yet\n"); + return; + } + + if (nNFTLs >= MAX_NFTLS) + { + printf("Maximum of NFTLs is exceeded\n"); + return; + } + + nftl = &NFTLs[nNFTLs++]; + nftl->MediaHdr = *hdr; + nftl->MediaUnit = eun; + nftl->SpareMediaUnit = 0xffff; + nftl->numvunits = hdr->FormattedSize / ERASE_SIZE; + + nftl->lastEUN = + nftl->MediaHdr.NumEraseUnits + nftl->MediaHdr.FirstPhysicalEUN; +} + +/* read badtable +*/ +static +int isbad(unsigned int nftl_num, int eun) +{ + int flag = 0; + int offset = eun / 512; + if (badtablenftl != nftl_num) + flag = 1; + else if (badtablestart != offset) + flag = 1; + if (flag) + { + doc_read_sector( + NFTLs[nftl_num].MediaUnit * ERASE_SECT + offset + 1, badtableblock + ); + badtablenftl = nftl_num; + badtablestart = offset; + } + return badtableblock[eun % 512] == 0xff ? 0 : 1; +} + +/* virtual block -> physical block hash +*/ +#define max_blk_hash 4096 +#define blk_hash_func(a, b) ((b) & 0x0fff) +static +struct blk_hash_entry +{ + int vblock; + int pblock; + char nftl; +} __attribute__((packed)) blk_hash[max_blk_hash]; + +/* VUN -> firstEUN hash +*/ +#define max_eun_hash 1024 +#define eun_hash_func(a, b) ((b) & 0x03ff) +static +struct eun_hash_entry +{ + unsigned short vun; + unsigned short eun; + char nftl; +} __attribute__((packed)) eun_hash[max_eun_hash]; + +static +int nftl_findsect(unsigned int nftl_num, int block) +{ + struct NFTLrecord *nftl; + unsigned short vun, eun, save_stat, save_eun; + unsigned long sect; + struct nftl_oob oob, oob1; + unsigned int k, n; + + if (nftl_num >= nNFTLs) + return -1; + + nftl = &NFTLs[nftl_num]; + + k = blk_hash_func(nftl_num, block); + if (blk_hash[k].nftl == nftl_num && + blk_hash[k].vblock == block) + return blk_hash[k].pblock; + + blk_hash[k].nftl = nftl_num; + blk_hash[k].vblock = block; + blk_hash[k].pblock = -1; + + /* printf("find virtual sector %d\n", block); */ + vun = block / ERASE_SECT; + block = block % ERASE_SECT; + /* printf("virtual unit number %d, offset %d\n", vun, block); */ + + /* find first eun in a chain */ + n = eun_hash_func(nftl_num, vun); + if (eun_hash[n].nftl == nftl_num && eun_hash[n].vun == vun) + { + eun = eun_hash[n].eun; + if (eun == 0xffff) + return -1; + sect = eun * ERASE_SECT; + /* Read Unit Control Information #0 */ + if (doc_read_oob(sect, &oob) < 0) + return -1; + } + else + { + eun_hash[n].nftl = nftl_num; + eun_hash[n].vun = vun; + eun_hash[n].eun = 0xffff; + eun = nftl->MediaHdr.FirstPhysicalEUN; + sect = eun * ERASE_SECT; + for (; eunlastEUN; eun++, sect += ERASE_SECT) + { + if (isbad(nftl_num, eun)) + { printf("eun %d is bad\n", eun); + continue; + } + /* Read Unit Control Information #0 */ + if (doc_read_oob(sect, &oob) < 0) + return -1; + if (oob.u.a.VirtUnitNum != oob.u.a.SpareVirtUnitNum) + continue; + if (oob.u.a.ReplUnitNum != oob.u.a.SpareReplUnitNum) + continue; + /* find first only! */ + if (oob.u.a.VirtUnitNum == vun) + break; + } + if (eun == nftl->lastEUN) + return -1; + eun_hash[n].eun = eun; + /* printf("was found first eun %d\n", eun); */ + } + + /* walk throw the chain */ + save_stat = BLOCK_FREE; + save_eun = eun; + for (;;) + { + /* read block status */ + if (doc_read_oob(sect + block, &oob1) < 0) + return -1; + /* end of block chain? */ + if (oob1.b.Status == BLOCK_FREE) + { /* printf("block %d in eun %d is BLOCK_FREE\n", block, eun); */ + break; + } + /* remember last 'active' status and EUN */ + if (oob1.b.Status == BLOCK_USED || + oob1.b.Status == BLOCK_DELETED) + { + save_stat = oob1.b.Status; + save_eun = eun; + /* printf("block %d in eun %d is %s\n", + block, eun, save_stat == BLOCK_USED ? "BLOCK_USED" : "BLOCK_DELETED"); + */ + } + /* is it last in eun chain? */ + if (oob.u.a.ReplUnitNum == 0xffff) + { /* printf("eun %d is last in the chain\n", eun); */ + break; + } + /* read next eun in the chain */ + eun = oob.u.a.ReplUnitNum; + sect = eun * ERASE_SECT; + /* printf("read block in next eun %d\n", eun); */ + if (doc_read_oob(sect, &oob) < 0) + return -1; + if (oob.u.a.VirtUnitNum != oob.u.a.SpareVirtUnitNum) + return -1; + if (oob.u.a.ReplUnitNum != oob.u.a.SpareReplUnitNum) + return -1; + } + + if (save_stat == BLOCK_USED) + { /* printf("was found block %d in eun %d\n", + save_eun * ERASE_SECT + block, save_eun); + */ + return + blk_hash[k].pblock = save_eun * ERASE_SECT + block; + } + + return -1; +} + +static +void NFTL_Scan(void) +{ + unsigned long sector; + struct NFTLMediaHeader *hdr = (struct NFTLMediaHeader *)nftlbuf; + + /* total size in sectors */ + unsigned long ssize = totalchips * (1 << (chipshift - 9)); + + printf("Scanning for NFTL Media Header\n"); + + /* Scan for NFTL partitions */ + for (sector=0; sectorDataOrgID, "ANAND")) + { + /* printf("NFTL Media Header found in flash sector %d\n", sector); */ + /* printf("NumEraseUnits: %d\n", hdr->NumEraseUnits); + printf("FirstPhysicalEUN: %d\n", hdr->FirstPhysicalEUN); + printf("FormattedSize: %d\n", hdr->FormattedSize); + printf("UnitSizeFactor: %d\n", hdr->UnitSizeFactor); */ + NFTL_setup(sector, hdr); + } + } +} + +static void doc_find(void) +{ + unsigned long probeloc = 0xc8000; + doc_inited = 1; + + + for (probeloc = 0xc8000; probeloc < 0xf0000; probeloc += 0x2000) { + if (DoC_Probe((unsigned char *)probeloc)) { + NFTL_Scan(); + return; + } + } + + grub_printf("No DiskOnChip found\n"); + return; +} + +int nftl_rawread(int drive, int sector, int byte_offset, int byte_len, char *buf) +{ + int size, block; + +#ifdef DOC_DEBUG + printf( + "nftl_rawread(%d, %d, %d, %d)\n", drive, sector, byte_offset, byte_len + ); +#endif + if (byte_len < 0 || !buf || drive < 0 || drive >= MAX_NFTLS) + { errnum = ERR_BAD_ARGUMENT; return 0; + } + + /* If this is the first time we've been called, + we need to go searching for a DiskOnChip + */ + if (!doc_inited) + { + int i; + doc_find(); + + if (!docloc) + { errnum = ERR_NO_DISK; return 0; + } + + for (i=0; i= nNFTLs) + { errnum = ERR_NO_DISK; return 0; + } + + sector += (byte_offset >> 9); + byte_offset &= 511; + + while (byte_len) + { + size = 512 - byte_offset; + if (byte_len < size) size = byte_len; + + /* virtual unit number */ + block = nftl_findsect(drive, sector); + if (block < 0) + { errnum = ERR_FSYS_CORRUPT; return 0; + } + + if (doc_read_sector(block, nftlbuf) < 0) + { errnum = ERR_FSYS_CORRUPT; return 0; + } + + memcpy(buf, nftlbuf + byte_offset, size); +#ifdef DOC_DEBUG + printf("readed sector %d (%d), bytes %d..%d\n", + sector, block, byte_offset, byte_offset + size - 1); +#endif + sector++; + byte_offset = 0; + byte_len -= size; + buf += size; + } + + errnum = ERR_NONE; + return 1; +} + +#endif /* BDEV_DISKONCHIP */ + diff -uNr grub/stage2/builtins.c grub-doc/stage2/builtins.c --- grub/stage2/builtins.c Mon Oct 9 17:32:59 2000 +++ grub-doc/stage2/builtins.c Thu Oct 12 13:58:53 2000 @@ -2745,6 +2745,19 @@ /* Network drive. */ grub_printf (" (nd):"); } + else if (saved_drive == DISK_ON_CHIP) + { + /* DiskOnChip 2000 */ + grub_printf (" (dc%d", saved_drive & 0x0F); + + if ((saved_partition & 0xFF0000) != 0xFF0000) + grub_printf (",%d", saved_partition >> 16); + + if ((saved_partition & 0x00FF00) != 0x00FF00) + grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a'); + + grub_printf ("):"); + } else if (saved_drive & 0x80) { /* Hard disk drive. */ diff -uNr grub/stage2/disk_io.c grub-doc/stage2/disk_io.c --- grub/stage2/disk_io.c Sat Oct 7 08:19:12 2000 +++ grub-doc/stage2/disk_io.c Thu Oct 12 13:58:53 2000 @@ -115,6 +115,13 @@ if (byte_len <= 0) return 1; +#ifdef BDEV_DISKONCHIP + if ((drive & 0xfffffff0) == DISK_ON_CHIP) + return nftl_rawread( + drive & 0x0000000f, sector, byte_offset, byte_len, buf + ); +#endif + while (byte_len > 0 && !errnum) { int soff, num_sect, bufaddr, track, size = byte_len; @@ -268,7 +275,8 @@ return 1; if (!(current_partition & 0xFF000000uL) - && (current_drive & 0xFFFFFF7F) < 8 + && ((current_drive & 0xFFFFFF7F) < 8 + || (current_drive & 0xFFFFFFF0) == DISK_ON_CHIP) && (current_partition & 0xFF) == 0xFF && ((current_partition & 0xFF00) == 0xFF00 || (current_partition & 0xFF00) < 0x800) @@ -849,19 +857,32 @@ return device + 2; } - if ((*device == 'f' || *device == 'h' || *device == 'n') - && (device += 2, (*(device - 1) != 'd'))) - errnum = ERR_NUMBER_PARSING; + device += 2; - if (ch == 'n') - current_drive = NETWORK_DRIVE; - else +#define MK16(a,b) ( ((a)<<8) + (b) ) + + switch (MK16(ch, *(device-1))) { + case MK16('n','d'): + current_drive = NETWORK_DRIVE; + break; + + case MK16('d','c'): safe_parse_maxint (&device, (int *) ¤t_drive); + disk_choice = 0; + current_drive += DISK_ON_CHIP; + break; + case MK16('h','d'): + case MK16('f','d'): + safe_parse_maxint (&device, (int *) ¤t_drive); disk_choice = 0; if (ch == 'h') current_drive += 0x80; + break; + + default: + errnum = ERR_NUMBER_PARSING; } } diff -uNr grub/stage2/shared.h grub-doc/stage2/shared.h --- grub/stage2/shared.h Fri Sep 29 01:41:42 2000 +++ grub-doc/stage2/shared.h Thu Oct 12 13:58:53 2000 @@ -182,7 +182,7 @@ /* Not bad, perhaps. */ #define NETWORK_DRIVE 0x20 - +#define DISK_ON_CHIP 0xE0 /* * GRUB specific information * (in LSB order) @@ -891,6 +891,12 @@ #endif void init_bios_info (void); + +#ifdef BDEV_DISKONCHIP +extern int nftl_rawread( + int drive, int sector, int byte_offset, int byte_len, char *buf +); +#endif #endif /* ASM_FILE */