Index: AUTHORS
===================================================================
RCS file: /usr/local/cvsroot/grub/AUTHORS,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -u -r1.1.1.2 -r1.2
--- AUTHORS	10 Feb 2002 16:05:36 -0000	1.1.1.2
+++ AUTHORS	8 Mar 2002 23:18:38 -0000	1.2
@@ -42,3 +42,8 @@
 
 Jason Thomas added Linux DAC960 support and support for hiding/unhiding
 logical partitions.
+
+David Woodhouse <dwmw2@infradead.org> added DiskOnChip support to GRUB.
+Ilguiz Latypov <ilatypov@superbt.com> tested and improved that, 
+Mark Meade <mark@lakeshoremicro.com> added DiskOnChip Millennium support.
+
Index: ChangeLog
===================================================================
RCS file: /usr/local/cvsroot/grub/ChangeLog,v
retrieving revision 1.1.1.5
retrieving revision 1.7
diff -u -r1.1.1.5 -r1.7
--- ChangeLog	22 Jun 2002 00:44:27 -0000	1.1.1.5
+++ ChangeLog	22 Jun 2002 01:19:23 -0000	1.7
@@ -1,3 +1,66 @@
+2002-06-21  Ilguiz Latypov <ilatypov@superbt.com>
+
+	Applied the GRUB patch written by David Woodhouse
+	<dwmw2@infradead.org>.  The patch is a part of Linux MTD
+	project, http://linux-mtd.infradead.org/.  Applied numerous
+	suggestions on DoC Millennium made by Mark Meade 
+	<mark@lakeshoremicro.com>.
+
+	* README_DiskOnChip: New DiskOnChip background information.
+	* configure.in: Added options --enable-diskonchip,
+	--enable-diskonchip-ipl and --enable-diskonchip-biosnetboot.
+	* stage1/Makefile.am: Added explicit DiskOnChip dependency
+	rules.
+	* stage1/doc_stage1.S: Added DoC firmware startup code from
+	the above patch with the following modifications:
+	a) don't read SlowIO when fetching the flash data
+	b) disable CDSN_CTRL_CLE when finishing DoC command
+	c) apply Millennium-specific commands and addresses when DoC
+	   Millennium is detected
+	d) display DoC type (2000 or Millennium) and BIOS window
+	   segment
+	e) remove extra CDSNControl read from doc_wait to save space
+	* stage1/doc_stage1.h: Likewise.
+	* stage1/doc_stage1b.S: Likewise.
+	* stage1/makecsum.c: New DoC compilation helper utility.
+	* stage2/Makefile.am: Added DiskOnChip NFTL block read module.
+	* stage2/asm.S: Set DiskOnChip as a default boot drive.
+	* stage2/bdev_diskonchip.c: New DoC NFTL block read module:
+	a) new flash memory manufacturer/model table after nand_ids.h
+	b) re-use DoC_Address for proper chip identification
+	* stage2/bios.c (get_diskinfo): Simulate BIOS disk information
+	for DoC and network drive to indulge GRUB drive sanity check and
+	command line geometry request.
+	* stage2/boot.c (load_image): Display the start of kernel
+	loading to simplify debugging.
+	* stage2/builtins.c (geometry_func): Return the size of DoC to 
+	command line geometry query.  Return 0's for network drive.
+	(print_root_device): DoC drive name completion.
+	* stage2/char_io.c (memcheck): Flag memory size error.
+	* disk_io.c (rawread): Redirect DoC rawread requests to NFTL
+	block read module.  Log all rawread() requests when run-time
+	debug switch is on.
+	(rawwrite): Deny DoC rawwrite requests as this is not
+	implemented for GRUB yet.
+	(sane_partition): Pass through the (fictitious) DoC drive
+	number.
+	(next_partition): More MBR debug for DoC as this is the first
+	sector of NFTL layer.  Show an error message when MBR is invalid
+	in DoC or other drives.
+	(set_device): Better drive name parsing, including "dc" for DoC.
+	(open_device): More DoC debugging.
+	(setup_part): Likewise.
+	* stage2/shared.h: Added fictitious DoC drive number.  Added the
+	compile-time DoC debug switch.
+	* stage2/stage2.c (try_config_partition): New function to open
+	configuration file in a given partition.
+	(find_config): New function to search for configuration file
+	through pre-set partition, whole disk and partitions 0 to 15.
+	(cmain): Attempt to open configuration file on DoC and first
+	hard disk.
+	(cmain): Do not clear screen on DiskOnChip failure and when 
+	debugging DoC.
+
 2002-06-15  Yoshinori K. Okuji  <okuji@enbug.org>
 
 	* stage2/disk_io.c [SUPPORT_NETBOOT] (GRUB): Defined.
Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/grub/Makefile.am,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- Makefile.am	27 Oct 2001 00:32:08 -0000	1.1.1.1
+++ Makefile.am	22 Jun 2002 01:17:45 -0000	1.2
@@ -1,3 +1,4 @@
+AUTOMAKE_OPTIONS = 1.6
 # Do not change this order if you don't know what you are doing.
 SUBDIRS = netboot stage2 stage1 lib grub util docs
 EXTRA_DIST = BUGS
Index: README_DiskOnChip
===================================================================
RCS file: README_DiskOnChip
diff -N README_DiskOnChip
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ README_DiskOnChip	22 Jun 2002 01:19:09 -0000	1.9
@@ -0,0 +1,115 @@
+	$Id$
+
+HOW TO GET GRUB BOOTING FROM DiskOnChip
+---------------------------------------
+
+(0. You'll need the Linux MTD driver modules loaded and the utils built.
+    These are available at http://linux-mtd.infradead.org/)
+
+ 1. Build a recent GRUB (from the FSF, not the old grub-0.5) with
+
+      aclocal && automake --add-missing && autoconf
+      ./configure --enable-diskonchip-2000 \
+                  --enable-ext2fs \
+                  --disable-ffs --disable-xfs \
+                  --disable-jfs --disable-vstafs --disable-reiserfs \
+                  --disable-minix --disable-fat   # for example
+      make
+      ls -al stage1/grub_firmware
+
+    Change the first configuration option to
+
+       --enable-diskonchip-mil512
+
+    for DoC Millennium.  Use --enable-diskonchip-mil256 if you think your
+    DoC Millennium is built with 256-byte-page flash chips.  DoC 2000 driver
+    can handle both 256 and 512 byte page sizes.
+
+    To activate GRUB through the network boot BIOS option instead of the
+    standard BIOS bootstrap loader, add
+
+      --enable-diskonchip-biosnetboot
+
+ 2. To store the firmware into DiskOnChip, run the Linux MTD utility
+
+      ./doc_loadbios /dev/mtd0 grub_firmware
+
+This assumes that the DiskOnChip is the only (or first) memory device
+for which the driver was loaded - and hence that it's /dev/mtd0
+
+HOW IT WORKS
+------------
+
+The DiskOnChip has a built-in ROM which is recognised as a BIOS extension
+by the system BIOS. This is called the 'IPL ROM', and it attempts to load 
+0x2000 bytes of the next stage, called the 'SPL, from the DiskOnChip.
+
+To make life complex, it doesn't just load the first 0x2000 bytes from the
+DiskOnChip - it loads half of the first 0x4000 bytes instead. Of each 512-byte
+block, it loads the first 256 bytes. 
+This is because of the way that NAND flash blocks are divided into two pages,
+and presumably it's done to save code space in the IPL ROM.
+
+As it loads the SPL, it performs a checksum. Iff the checksum of the SPL is
+equal to 0x55, then it will execute the SPL, which it has loaded to the 
+address 0x2000:0000.
+
+The SPL in turn is responsible for loading the rest of the firmware from the 
+DiskOnChip. Normally, this steals some memory for itself, and installs an
+INT 13h (Disk BIOS) handler to emulate disk access.
+
+We change this. Instead of installing an INT 13h handler, we install an
+INT 19h (bootstrap) handler. This is very small, and is held entirely
+within the first 256 bytes of the SPL with the code which installs it. 
+
+The INT 19h handler, when executed, loads GRUB Stage2 from the DiskOnChip
+to the place where GRUB Stage1 would normally load it, and then passes 
+control to it.
+
+Clear as mud? 
+
+
+NOTE: Grub 0.5, which was the latest version for some time before the FSF
+took over, expects stage2 to be loaded to 0x08000, and executed with CS:IP
+0000:8000.
+
+The versions currently in the FSF CVS repository are slightly different. The
+stage2 now has a 512-byte loader prepended to it, so now we need to load it
+as before but execute it starting as 0000:8200.
+
+I've changed the default behaviour of the DiskOnChip Stage1 over to the new 
+address, because I expect any development of DiskOnChip capability in Grub 
+itself to be added to the CVS version, not the old 0.5 version.
+
+If you are using this with the older grub, change the first few lines of the
+Makefile appropriately.
+
+DW 28/1/00
+
+
+The Millennium's Download Engine won't expose page size differences to
+IPL.  This is unlike DoC 2000 where ROM IPL will load different blocks
+of flash memory depending on flash chip page size.  The page 13 of
+Millennium data sheet
+
+http://www.m-sys.com/files/DataSheets%5Cdoc%5CDiskOnChip_Mil._DS_Rev2.1.pdf
+
+says the following:
+
+  Upon power-up (DIP version) or the negation of the RSTIN# input (TSOP
+  version), the DiskOnChip Millennium downloads the Initial Program Loader
+  (IPL) data into the boot-block from the first 512 bytes of flash memory.
+  As a failsafe mechanism, DiskOnChip Millennium uses its internal Error
+  Detection and Correction (EDC/ECC) logic to verify the integrity of this
+  data. If DiskOnChip Millennium detects an error, it will automatically
+  download the redundant copy of the IPL, which is stored in the following
+  page of the flash memory. The entire download process takes less than 1
+  millisecond. Access to the DiskOnChip Millennium is not permitted before
+  the download process is completed.
+
+The next version of DiskOnChip patch for GRUB will combine all existing
+DoC type options back into one.  The code will find the page size
+through the chip manufacturer and model codes.
+
+--ilatypov
+
Index: configure.in
===================================================================
RCS file: /usr/local/cvsroot/grub/configure.in,v
retrieving revision 1.1.1.3
retrieving revision 1.10
diff -u -r1.1.1.3 -r1.10
--- configure.in	30 May 2002 18:09:13 -0000	1.1.1.3
+++ configure.in	22 Jun 2002 01:17:45 -0000	1.10
@@ -53,9 +53,13 @@
 # We need this for older versions of Autoconf.
 _AM_DEPENDENCIES(CC)
 
-dnl Because recent automake complains about AS, set it here.
-AS="$CC"
-AC_SUBST(AS)
+dnl Because recent automake requires CCAS for assembly code, set it here.
+CCAS="$CC"
+AC_SUBST(CCAS)
+dnl Because recent automake requires CCASFLAGS for assembly code, set it here.
+CCASFLAGS='$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)'
+AC_SUBST(CCASFLAGS)
+
 
 AC_ARG_WITH(binutils,
   [  --with-binutils=DIR     search the directory DIR to find binutils])
@@ -228,6 +232,59 @@
   FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_VSTAFS=1"
 fi
 
+AC_ARG_ENABLE(diskonchip-2000,
+  [  --enable-diskonchip-2000     enable DiskOnChip 2000 support])
+
+AC_ARG_ENABLE(diskonchip-mil512,
+  [  --enable-diskonchip-mil512   enable 512-byte-page DoC Millennium])
+
+AC_ARG_ENABLE(diskonchip-mil256,
+  [  --enable-diskonchip-mil256   enable 256-byte-page DoC Millennium])
+
+AC_ARG_ENABLE(diskonchip-biosnetboot,
+  [  --enable-diskonchip-biosnetboot    hook DiskOnChip to BIOS network boot],
+  [STAGE1_CFLAGS="$STAGE1_CFLAGS -DDOC_BIOS_NETBOOT=1"])
+
+AM_CONDITIONAL(DOC_MIL, 
+  test x$enable_diskonchip_mil512 = xyes -o x$enable_diskonchip_mil256 = xyes)
+
+DOC_MIL_PAGE=
+
+if test x$enable_diskonchip_2000 = xyes \
+   -o x$enable_diskonchip_mil512 = xyes -o x$enable_diskonchip_mil256 = xyes
+then
+  FSYS_CFLAGS="$FSYS_CFLAGS -DBDEV_DISKONCHIP=1"
+  if test x$enable_diskonchip_mil512 = xyes -o x$enable_diskonchip_mil256 = xyes
+  then
+    STAGE1_CFLAGS="$STAGE1_CFLAGS -DDOC_MIL=1"
+    if test x$enable_diskonchip_mil512 = xyes ; then
+      DOC_MIL_PAGE=512
+    else
+      DOC_MIL_PAGE=256
+    fi
+  fi
+  n_doc_drivers=0
+  test x$enable_diskonchip_2000 = xyes && \
+	n_doc_drivers=$((n_doc_drivers + 1))
+  test x$enable_diskonchip_mil512 = xyes && \
+	n_doc_drivers=$((n_doc_drivers + 1))
+  test x$enable_diskonchip_mil256 = xyes && \
+	n_doc_drivers=$((n_doc_drivers + 1))
+  test $n_doc_drivers -ne 1 && {
+    AC_MSG_ERROR([You can enable only one DiskOnChip driver])
+  }
+else
+  if test x$enable_diskonchip_biosnetboot = xyes ; then
+    AC_MSG_ERROR([You must enable at least one DiskOnChip driver])
+  fi
+fi
+
+AM_CONDITIONAL(BDEV_DISKONCHIP, 
+  test x$enable_diskonchip_2000 = xyes \
+    -o x$enable_diskonchip_mil512 = xyes -o x$enable_diskonchip_mil256 = xyes)
+
+AC_SUBST(DOC_MIL_PAGE)
+
 AC_ARG_ENABLE(jfs,
   [  --disable-jfs           disable IBM JFS support in Stage 2])
 
@@ -605,11 +662,6 @@
 AC_SUBST(NET_CFLAGS)
 AC_SUBST(NET_EXTRAFLAGS)
 AC_SUBST(NETBOOT_DRIVERS)
-
-dnl Because recent automake complains about ASFLAGS, set it here.
-ASFLAGS='$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)'
-AC_SUBST(ASFLAGS)
-
 
 dnl Output.
 AC_OUTPUT([Makefile stage1/Makefile stage2/Makefile docs/Makefile \
Index: stage1/Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/grub/stage1/Makefile.am,v
retrieving revision 1.1.1.1
retrieving revision 1.6
diff -u -r1.1.1.1 -r1.6
--- stage1/Makefile.am	27 Oct 2001 00:32:09 -0000	1.1.1.1
+++ stage1/Makefile.am	21 Mar 2002 21:48:53 -0000	1.6
@@ -1,7 +1,84 @@
 pkgdatadir = $(datadir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
-nodist_pkgdata_DATA = stage1
 
-CLEANFILES = $(nodist_pkgdata_DATA)
+if BDEV_DISKONCHIP
+##################### Build DiskOnChip bootloader ######################
+# DiskOnChip stage 1 bootloader from http://linux-mtd.infradead.org/
+# as of Feb 19, 2002
+#
+STAGE2FILE = ../stage2/pre_stage2
+
+if DOC_MIL
+DOC_MIL_CHECKSUM = -m
+else
+DOC_MIL_CHECKSUM =
+endif
+
+grub_firmware: doc_stage1 makecsum $(STAGE2FILE) Makefile
+	./makecsum $(DOC_MIL_CHECKSUM) doc_stage1 $(STAGE2FILE) grub_firmware
+
+doc_stage1.o: doc_stage1.S doc_stage1.h stage2_size.h Makefile
+	$(CC) $(STAGE1_CFLAGS) -fno-builtin -nostdinc -c \
+		-o doc_stage1.o doc_stage1.S
+
+if DOC_MIL
+# DoC Millennium firmware build
+
+doc_stage1b-$(DOC_MIL_PAGE).o: doc_stage1b.S doc_stage1.h \
+		stage2_size.h Makefile
+	$(CC) -o doc_stage1b-$(DOC_MIL_PAGE).o $(STAGE1_CFLAGS) \
+		-DPAGE$(DOC_MIL_PAGE) -fno-builtin -nostdinc -c doc_stage1b.S
+
+doc_stage1-$(DOC_MIL_PAGE).o: doc_stage1.o doc_stage1b-$(DOC_MIL_PAGE).o
+	$(LD) -N -Ttext 0 -o doc_stage1-$(DOC_MIL_PAGE).o \
+		doc_stage1.o doc_stage1b-$(DOC_MIL_PAGE).o
+
+doc_stage1: doc_stage1-$(DOC_MIL_PAGE).bin
+	cp -f doc_stage1-$(DOC_MIL_PAGE).bin doc_stage1
+
+else
+# DoC 2000 firmware build
+
+doc_stage1b-256.o: doc_stage1b.S doc_stage1.h stage2_size.h Makefile
+	$(CC) -o doc_stage1b-256.o $(STAGE1_CFLAGS) \
+		-DPAGE256 -fno-builtin -nostdinc -c doc_stage1b.S
+
+doc_stage1b-512.o: doc_stage1b.S doc_stage1.h stage2_size.h Makefile
+	$(CC) -o doc_stage1b-512.o $(STAGE1_CFLAGS) \
+		-DPAGE512 -fno-builtin -nostdinc -c doc_stage1b.S
+
+doc_stage1-256.o: doc_stage1.o doc_stage1b-256.o
+	$(LD) -N -Ttext 0 -o doc_stage1-256.o doc_stage1.o doc_stage1b-256.o
+
+doc_stage1-512.o: doc_stage1.o doc_stage1b-512.o
+	$(LD) -N -Ttext 0 -o doc_stage1-512.o doc_stage1.o doc_stage1b-512.o
+
+doc_stage1: doc_stage1-256.bin doc_stage1-512.bin
+	cp -f doc_stage1-256.bin doc_stage1
+	dd bs=256 if=doc_stage1-512.bin skip=1 seek=2 count=1 of=doc_stage1
+endif
+
+stage2_size.h: $(STAGE2FILE)
+	-rm -f stage2_size.h
+	set dummy `ls -l $(STAGE2FILE)`; \
+	echo "#define STAGE2_SIZE $$6" > stage2_size.h
+
+%.bin: %.o
+	$(OBJCOPY) -O binary $< $@
+
+# Ignore CFLAGS and LDFLAGS as these are set up for standalone mode
+makecsum: makecsum.c
+	$(CC) -o $@ $<
+
+GRUB_FIRMWARE = grub_firmware
+
+GRUB_FIRMWARE_CLEAN = doc_stage1 *.o *.bin *~ grub_firmware makecsum stage2_size.h
+
+########################################################################
+endif
+
+nodist_pkgdata_DATA = stage1 $(GRUB_FIRMWARE)
+
+CLEANFILES = $(nodist_pkgdata_DATA) $(GRUB_FIRMWARE_CLEAN)
 
 # We can't use builtins or standard includes.
 AM_ASFLAGS = $(STAGE1_CFLAGS) -fno-builtin -nostdinc
@@ -12,3 +89,5 @@
 
 %: %.exec
 	$(OBJCOPY) -O binary $< $@
+
+
Index: stage1/doc_stage1.S
===================================================================
RCS file: stage1/doc_stage1.S
diff -N stage1/doc_stage1.S
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ stage1/doc_stage1.S	22 Jun 2002 01:15:18 -0000	1.11
@@ -0,0 +1,262 @@
+/* -*-Asm-*- */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000 Machine Vision Holdings, Inc.
+ *
+ *  Author: David Woodhouse <dwmw2@infradead.org>
+ *
+ *  $Id$
+ *
+ *  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 "doc_stage1.h"
+	
+	.file	"doc_stage1.S"
+
+	.text
+
+	/* Tell GAS to generate 16-bit instructions so that this code works
+	   in real mode. */
+	.code16
+
+.globl _start; _start:
+
+#ifdef DOC_MIL
+	/*
+	 * _start is in the beginning of DoC Millennium flash memory
+	 */
+	.byte 0x55, 0xAA	/* BIOS extension signature */
+	.byte 0x10		/* BIOS extension size in 512 byte blocks */
+	/*
+	 * The checksum byte at offset 511 of every copy of IPL is the
+	 * complement to 0 of first 511 bytes.  This is because of 2 facts:
+	 * a) the sum of bytes in the BIOS extension window is supposed to 
+	 *    be 0
+	 * b) the whole 8K DoC window is split into 2 aliases of 2 copies
+	 *    of 512 byte IPL in the beginning, 4K of zero-filled area and 
+	 *    again 2 aliases of 2 copies of 512 byte IPL in the end.
+	 */
+	/* BIOS will call far _start + 3 */
+	.org	3
+bios_extension_start:
+	pushw	%cs
+#else
+	pushw	%ds
+#endif
+	cld
+	MSG(doc_bios_scan_start_string)
+
+	/*
+	 * With DoC 2000, _start is loaded at 0x20000 by the IPL,
+	 * and is jumped to with CS:IP 0x2000:0, DS is <DoC segment>.
+	 *
+	 * With DoC Millennium, the flash memory is mapped to offset 0
+	 * of DoC window.  We suppose that BIOS jumps to that offset 
+	 * during the ROM extension scan with CS:IP <DoC segment>:3.
+	 */
+
+	/* What we need to do is:
+	   1. Check the current end-of-memory in the BIOS
+	   2. Reduce it by the amount of memory we need for our INT 19h 
+	   3. Return, and wait for our INT 19h to be called.
+	*/
+
+		/* Find top of memory */
+	xorw	%ax, %ax
+	movw	%ax, %ds
+	movw	0x0413, %ax
+
+		/* Steal 1K from the top */
+	decw	%ax
+	movw	%ax,0x0413
+
+		/* Generate segment address */
+	shlw	$6,%ax
+	movw	%ax,%es
+
+		/* Set up our shiny new INT 19h handler */
+	movw	%es, (DOC_BIOS_HOOK * 4 + 2)
+	movw	$doc_bios_boot_hook, (DOC_BIOS_HOOK * 4)
+
+		/* Copy ourself into the new segment we've just reserved */
+	movw	$0x200, %cx
+	pushw	%cs
+	popw	%ds
+	xorw	%si,%si
+	xorw	%di,%di
+	rep
+	movsw
+
+		/* Store the DiskOnChip segment */
+	popw	%es:doc_seg
+	lret
+
+
+doc_bios_boot_hook:
+	cld
+		/* Say hello */
+	MSG(doc_bios_hook_execed_string)
+#ifndef SHOW_INFO
+	MSG(eol_string)
+#endif
+
+		/* Check where the DiskOnChip is */
+	movw	%cs:doc_seg, %ds
+
+		/* Copy it.... */
+
+		/* Reset DiskOnChip */
+	movw	$BXREG, %bx
+	movb	$DOC_MODE_CLR_ERR + DOC_MODE_MDWREN + DOC_MODE_NORMAL, BX_DOCControl
+	movb	$DOC_MODE_CLR_ERR + DOC_MODE_MDWREN + DOC_MODE_NORMAL, BX_DOCControl
+
+		/* Set the I/O register */
+	movw	$DoC_2k_CDSN_IO, %si
+	movb	BX_ChipID, %al
+	cmpb	$DOC_ChipID_Doc2k, %al
+	je	ioreg_end
+	movw	$DoC_Mil_CDSN_IO, %si
+ioreg_end:
+
+		/* Flash command:	Reset */
+	movb	$NAND_CMD_RESET, %ah
+	call	doc_cmd
+
+
+		/********* Display chip ID and segment ***************/
+#ifdef SHOW_INFO
+	pushw	%bx
+	pushw	%si
+
+	pushw	%bx
+	call	printspace
+	popw	%bx
+
+	movb	BX_ChipID, %al
+	cmpb	$DOC_ChipID_Doc2k, %al
+	movw	$(doc_2k_string), %si	
+	je	print_id
+
+	cmpb	$DOC_ChipID_DocMil, %al
+	movw	$(doc_mil_string), %si	
+	je	print_id
+
+	call	phbyte
+	jmp	print_seg
+
+print_id:
+	call	message
+
+print_seg:
+	call	printspace
+	movw	%ds, %ax
+	call	phword
+	MSG(eol_string)
+	popw	%si
+	popw	%bx
+#endif		/* defined(SHOW_INFO) */
+		/*****************************************************/
+
+		/* 
+		   Basically, we know that the DiskOnChip IPL ROM will 
+		   load only the first 256 bytes of each 512-byte page
+		   from a 512-byte-page device, but it'll load _all_
+		   the data from a 256-byte-page device.
+		   
+		   Therefore, we put the code to handle 256-byte-page
+		   devices at offset 0x100, where we know it won't get
+		   loaded if we're actually on a 512-byte-page device.
+		   We put the code to handle 512-byte-page devices at
+		   0x200, in the knowledge that it'll get loaded to 
+		   offset 0x100 if it's appropriate.
+
+		   Now, we don't have to probe the device, we just 
+		   jump to the code at 0x100, because we _know_ that 
+		   the IPL ROM will have loaded the correct code there.
+		   
+		   This is SICK. I love it. 
+		*/
+
+	jmp	stage1b
+
+	/* Routines used by both 256- and 512- byte/page loaders. */
+
+                /* doc_cmd:      Send a command to the flash chip */
+doc_cmd:
+                /* Enable CLE line to flash */
+        movb    $CDSN_CTRL_FLASH_IO + CDSN_CTRL_WP + CDSN_CTRL_CLE + CDSN_CTRL_CE, BX_CDSNControl
+                /* Dummy */
+        incw    BX_ChipID
+                /* Write the actual command */
+        movb    %ah,BX_SlowIO
+        movb    %ah,(%si)
+                /* Disable CLE */
+        incw    BX_ChipID
+        movb    $CDSN_CTRL_FLASH_IO + CDSN_CTRL_WP + CDSN_CTRL_CE, BX_CDSNControl
+
+                /* doc_wait:     Wait for the DiskOnChip to be ready */
+doc_wait:
+        incw    BX_ChipID
+l38:    
+        testb   $0x80,BX_CDSNControl
+        jz      l38
+        ret
+                
+
+/*
+ * message: write the string pointed to by %si
+ *
+ *   WARNING: trashes %si, %ax, and %bx
+ */
+
+	/*
+	 * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
+	 *	%ah = 0xe	%al = character
+	 *	%bh = page	%bl = foreground color (graphics modes)
+	 */
+1:
+	call	printchar
+.globl message; message:
+	lodsb	%cs:(%si)
+	cmpb	$0, %al
+	jne	1b	/* if not end of string, jmp to display */
+	ret
+
+.globl printspace; printspace:
+	mov	$' ', %al
+.globl printchar; printchar:
+	movb	$0xe, %ah
+	movw	$0x0001, %bx
+	int	$0x10
+	ret
+
+doc_seg:	.word 0
+
+doc_bios_hook_execed_string:	.string "DoC"
+doc_2k_string:	.string "2000"
+doc_mil_string:	.string "Mil"
+eol_string:	.string "\r\n"
+doc_bios_scan_start_string:	.string "DoC found\r\n"
+
+	.org 0x100
+stage1b:	
+
+.globl doc_wait
+.globl doc_cmd
+.globl message
+.globl phword
+.globl phbyte
+
Index: stage1/doc_stage1.h
===================================================================
RCS file: stage1/doc_stage1.h
diff -N stage1/doc_stage1.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ stage1/doc_stage1.h	22 Jun 2002 01:15:18 -0000	1.6
@@ -0,0 +1,141 @@
+/* -*-Asm-*- */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000 Machine Vision Holdings, Inc.
+ *
+ *  Author: David Woodhouse <dwmw2@infradead.org>
+ *
+ *  $Id$
+ *
+ *  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.
+ */
+
+/* SHOW_INFO displays the DiskOnChip ChipID (2000 or Millennium) and
+ * its window segment at the expense of extra code */
+#define SHOW_INFO 1
+
+#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_Mil_CDSN_IO 0x0800
+#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 NAND_CMD_READ0 0
+#define NAND_CMD_READ1 1
+#define NAND_CMD_RESET 0xff
+
+#include "stage2_size.h"
+
+/*
+ *  defines for the code go here
+ */
+
+/*
+ * Whether we hook to the Bootstrap Loader INT 0x19
+ * or to the Diskless Boot INT 0x18
+ * See 
+ *    http://etherboot.sourceforge.net/doc/html/devman-3.html
+ *    http://www.ctyme.com/intr/rb-2270.htm
+ *    http://www.ctyme.com/intr/rb-2241.htm
+ */
+#ifdef DOC_BIOS_NETBOOT
+#define DOC_BIOS_HOOK 0x18
+#else
+#define DOC_BIOS_HOOK 0x19
+#endif
+
+
+#define LOADLEN (((STAGE2_SIZE + 0xff) & ~0xff) >> 8)
+
+#ifdef DOC_MIL
+/*
+ * We place GRUB stage 2 at offset 0x400 of DoC Millennium flash memory
+ * to leave room for 2 copies of stage 1 (IPL) at offset 0.  In this way
+ * the Download Engine can load the backup copy of IPL from offset 0x200.
+ */
+#  define GRUBLOADOFS	0x400
+#else
+/*
+ * DoC 2000 IPL is stored in ROM.  It will download stage 1 from two 256
+ * byte blocks of flash memory.  The first block is at the start.  The
+ * second block is at offset 0x100 if DoC 2000 page size is 256 bytes.  
+ * If the page size is 512 bytes, the second block gest loaded off 0x200.
+ * Stage 2 can be stored at offset 0x300 in both cases.
+ */
+#  define GRUBLOADOFS	0x300
+#endif
+
+#ifdef OLDGRUB /* Loading Erich's old grub */
+# define GRUBSTART	0x8000
+#else /* Loading FSF grub */
+# define GRUBSTART	0x8200
+#endif
+
+#define GRUBLOADSEG	((GRUBSTART - GRUBLOADOFS) >> 4)
+
+	/* Some macros to make it obvious what we're accessing */
+#define BXREG			DoC_CDSNControl
+
+#define BX_ChipID		(DoC_ChipID - BXREG)(%bx)
+#define BX_DOCControl		(DoC_DOCControl - BXREG)(%bx)
+				/* "movb (%bx), %al" takes only 2 bytes */
+#define BX_CDSNControl		(%bx)
+#define BX_SlowIO		(DoC_CDSNSlowIO - BXREG)(%bx)
+#define BX_ReadPipeInit		(DoC_ReadPipeInit - BXREG)(%bx)
+#define BX_LastDataRead		(DoC_LastDataRead - BXREG)(%bx)
+
+			/* Print message string */
+#define MSG(x)	movw $(x), %si; call message
+
Index: stage1/doc_stage1b.S
===================================================================
RCS file: stage1/doc_stage1b.S
diff -N stage1/doc_stage1b.S
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ stage1/doc_stage1b.S	22 Jun 2002 01:15:18 -0000	1.9
@@ -0,0 +1,187 @@
+/* -*-Asm-*- */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000 Red Hat UK Ltd.
+ *
+ *  Author: David Woodhouse <dwmw2@infradead.org>
+ *
+ *  $Id$
+ *
+ *  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 "doc_stage1.h"
+
+	.file "doc_stage1b.S"
+	.code16
+	.text
+stage1b:
+		/* Load %CX with the number of 256-byte blocks to load */	
+	movw	$LOADLEN, %cx
+
+		/* Set up our target address for writing stage2 */
+	movw	$GRUBLOADSEG, %ax
+	movw	%ax, %es
+	movw	$GRUBLOADOFS, %di
+
+		/* Stage2 proper starts at offset 0x300 on the flash. We
+		   have defined the load address GRUBLOADSEG so that
+		   we're loading this to 0x8000:0000 or 0x8000:0200, 
+		   depending on whether this is old or GNU Grub, 
+		   respectively.
+		*/
+
+#ifdef DOC_MIL_KEEP_IPL
+	cmpw	$DoC_2k_CDSN_IO, %si
+	je	mil_spec_end3
+	/* Keep Millennium's original IPL in the first 1K of flash */
+	addw	$0x400, %di
+mil_spec_end3:
+#endif
+
+mainloop:
+
+#ifdef PAGE256
+                /* Send new READ0 command */
+        xorb    %ah, %ah
+#else	
+		/* Send new READ command - is it READ0 or READ1? */
+	movw	%di, %ax
+	andb	$1,%ah
+#endif
+	call	doc_cmd
+
+		/* Start of new block. Set address */
+	movb	$CDSN_CTRL_FLASH_IO + CDSN_CTRL_WP + CDSN_CTRL_ALE + CDSN_CTRL_CE, BX_CDSNControl
+	incw	BX_ChipID
+
+#ifdef PAGE256
+		/* We sent bits 0-7, then 8-15, then 16-23 */
+#else	
+		/* We send bits 0-7, then 9-16, then 17-23 */
+		/* Yes bit 8 is missing. Read the NAND flash specs */		
+#endif
+	movw	%di,%dx
+		/* Bits 0-7 are always zero */
+	movb	$0,BX_SlowIO
+	movb	$0,(%si)
+#ifndef PAGE256
+			/* Bits 9-16 */
+	shrw	$1,%dx
+	.byte	0x80, 0xce /* orb adrbit16, %dh */
+adrbit16:	
+	.byte	0
+#else
+			/* Bits 8-15 */
+#endif
+	movb	%dh,BX_SlowIO
+	movb	%dh,(%si)
+#ifdef PAGE256
+			/* Bits 16-23 */
+#else	
+			/* Bits 17-24 */
+#endif
+	.byte	0xb2 /* movb adrbytehi, %dl */
+adrbytehi:
+	.byte	0
+
+	movb	%dl,BX_SlowIO
+	movb	%dl,(%si)
+
+		/* Clear the ALE line to the flash chip */
+	movb	$CDSN_CTRL_FLASH_IO + CDSN_CTRL_WP + CDSN_CTRL_CE, BX_CDSNControl
+	call	doc_wait
+
+	pushw	%cx		/* Store the 'blocks remaining' count */
+	movw	$0x100, %cx	/* Set up to copy 0x100 bytes */
+	cmpw	$DoC_2k_CDSN_IO, %si
+	je	mil_spec_end1
+	testb	BX_ReadPipeInit, %al /* Millennium should use the */
+	decw	%cx		/* LastDataRead register - Pipeline Reads */
+mil_spec_end1:
+
+readbyte:	
+	movsb			/* movb (%si), %al ; stosb would be more */
+	decw	%si		/* obvious, but would take an extra byte. */
+	loop	readbyte
+
+	cmpw	$DoC_2k_CDSN_IO, %si
+	je	mil_spec_end2
+	movb	BX_LastDataRead, %al
+	stosb
+mil_spec_end2:
+
+	testw	$0xffff, %di	/* Check if we've done a whole 0x10000 bytes */
+	jnz	endloop		/* No - continue regardless */
+		/* Yes - increase %es */
+	movw	%es, %cx
+	addb	$0x10, %ch
+	movw	%cx, %es
+
+#ifndef PAGE256
+	addb	$0x80, %cs:adrbit16	/* Increase bit 16 */
+	jnc	endloop			/* Did it overflow? */
+#endif	
+	incb	%cs:adrbytehi		/* If so, increase the high byte too */
+
+endloop:	
+	popw	%cx		/* Restore the 'blocks remaining' count */
+	loop	mainloop	/* Loop till completely done */
+good:	
+
+	MSG(msgjmp)
+		/* Run it:	 jmpf 0:8200 */
+	.byte	0xea
+	.word	GRUBSTART,0
+
+#ifdef SHOW_INFO
+	.org 0xc0
+	/* Hex output routines, used at one point in debugging */	
+.globl phword; phword:
+        pushw   %ax
+        xchgb   %al,%ah
+        call    phbyte
+        movb    %ah,%al
+        call    phbyte
+        popw    %ax
+        ret
+
+.globl phbyte; phbyte:
+        pushw   %ax
+        movb    %al, %ah
+        shrb    $4,%al
+        call    phnibble
+        movb    %ah, %al
+        call    phnibble
+        popw    %ax
+        ret
+
+.globl phnibble; phnibble:
+        pushw   %ax
+        andb    $0xf,%al
+        addb    $48,%al
+        cmpb    $57,%al
+        jna     ph1
+        add     $7,%al
+ph1:    call	printchar
+        popw    %ax
+        ret
+
+#endif		/* defined(SHOW_INFO) */
+
+msgjmp:		
+	.string "Jumping to Grub\n\r"
+	.org 0xff
+	.byte 0 /* checksum */
Index: stage1/makecsum.c
===================================================================
RCS file: stage1/makecsum.c
diff -N stage1/makecsum.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ stage1/makecsum.c	21 Mar 2002 21:48:53 -0000	1.4
@@ -0,0 +1,219 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+unsigned char buf[16384];
+
+main(int argc, char **argv)
+{
+	int len, i, stubfd, st2fd, outfd, retval = 0;
+	unsigned char checksum = 0;
+	int isMillennium = 0;
+	unsigned char total;
+
+	memset(buf, 0xff, 16384);
+
+	if (argc < 4) {
+		fprintf(stderr, "Usage: makecsum [-m] <stubfile> <stage2> "
+				"<outfile> [checksum]\n");
+		exit(1);
+	}
+
+	i = 1;
+
+	if (!strcmp(argv[i], "-m")) {
+		isMillennium = 1;
+		i++;
+	}
+	
+	stubfd = open(argv[i++], O_RDONLY);
+	if (stubfd < 0) {
+		perror("open stub file");
+		exit(1);
+	}
+
+	st2fd = open(argv[i++], O_RDONLY);
+	if (st2fd < 0) {
+		perror("open stage2 file");
+		close(stubfd);
+		exit(1);
+	}
+
+	outfd = open(argv[i++], O_WRONLY | O_CREAT | O_TRUNC, 0664);
+	if (outfd < 0) {
+		perror("open output file");
+		exit(1);
+	}
+
+	if ((argc >= i + 1) && argv[i][0]) {
+		total = strtoul(argv[i++], NULL, 0);
+	} else {
+		total = isMillennium ? 0x00 : 0x55;
+	}
+
+	if (isMillennium) {
+		len =  read(stubfd, buf, 512);
+		if (len < 0) {
+			perror("read from stub file");
+			close(outfd);
+			close(st2fd);
+			close(stubfd);
+			exit(1);
+		}
+
+		if (len > 512) {
+			fprintf(stderr, "stub file is too large (>512 bytes)\n");
+			close(outfd);
+			close(st2fd);
+			close(stubfd);
+			exit(1);
+		}
+
+		close(stubfd);
+
+		/* Calculate the DoC Millennium IPL checksum for BIOS */
+		buf[511] = 0;
+
+		i = 0;
+		while (i < 511) {
+			checksum += buf[i++];
+		}
+
+		/* Set the slack byte to fix the csum */
+		buf[511] = total - checksum;
+
+		/*
+		 * Write the original buffer twice.
+		 * The second copy will be used by the DoC Millennium
+		 * Download Engine in case the ECC check fails on the 
+		 * first copy.
+		 */
+		for (i = 0; i < 2; i++) {
+			len = write(outfd, buf, 512);
+
+			if (len < 0) {
+				perror("write output file");
+				close(outfd);
+				close(st2fd);
+				exit(1);
+			}
+
+			if (len < 512) {
+				fprintf(stderr, "short write of "
+					"output file (%d bytes < 512)\n", len);
+				close(outfd);
+				close(st2fd);
+				exit(1);
+			}
+		}
+	} else {	/* DoC 2000 */
+		/* Read the stub loader (stage1) */
+
+		len =  read(stubfd,buf,769);
+		if (len < 0) {
+			perror("read from stub file");
+			close(outfd);
+			close(st2fd);
+			close(stubfd);
+			exit(1);
+		}
+
+		if (len > 768) {
+			fprintf(stderr, "stub file is "
+					"too large (>768 bytes)\n");
+			close(outfd);
+			close(st2fd);
+			close(stubfd);
+			exit(1);
+		}
+
+		close(stubfd);
+
+		/* Read enough of the remainder to calculate the csum */
+		
+		len = read(st2fd, buf+768, 16384-768);
+		if (len < 0) {
+			perror("read from stage2 file\n");
+			close(outfd);
+			close(st2fd);
+			exit(1);
+		}
+
+
+		/* Calculate the csum for 512-byte-page devices */
+		buf[767] = 0;
+
+		i=0;
+		while (i<16384) {
+			checksum += buf[i];
+			i++;
+			if ((i >> 8)&1)
+				i += 256;
+		}
+
+		/* Set the slack byte to fix the csum */
+		buf[767] = total - checksum;
+
+		/* Calculate the csum for 256-byte-page devices */
+		checksum = 0;
+
+		buf[511] = 0;
+
+		i=0;
+		while (i<8192) {
+			checksum += buf[i++];
+		}
+
+		/* Set the slack byte to fix the csum */
+		buf[511] = total - checksum;
+
+
+		/* Write the original buffer */
+		len = write(outfd, buf, 16384);
+
+		if (len < 0) {
+			perror("write output file");
+			close(outfd);
+			close(st2fd);
+			exit(1);
+		}
+
+		if (len < 16384) {
+			fprintf(stderr, "short write of "
+				"output file (%d bytes < 16384)\n", len);
+			close(outfd);
+			close(st2fd);
+			exit(1);
+		}
+	}
+
+	/* Now chuck out the rest of the stage2 */
+
+	while (1) {
+		len = read(st2fd, buf, 16384);
+		if (len < 0) {
+			perror("read stage2 file");
+			retval = 1;
+			break;
+		}
+		if (len == 0)
+			break;
+		
+		i = write(outfd, buf, len);
+		if (i < 0) {
+			perror("write output file");
+			retval = 1;
+			break;
+		}
+		if (i<len) {
+			fprintf(stderr, "short write of "
+				"output file (%d bytes < %d)\n", i, len);
+			retval = 1;
+			break;
+		}
+	}
+		
+	close(outfd);
+	close(st2fd);
+	exit(retval);
+}
Index: stage2/Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/grub/stage2/Makefile.am,v
retrieving revision 1.1.1.3
retrieving revision 1.4
diff -u -r1.1.1.3 -r1.4
--- stage2/Makefile.am	22 Jun 2002 00:44:28 -0000	1.1.1.3
+++ stage2/Makefile.am	22 Jun 2002 01:17:45 -0000	1.4
@@ -83,12 +83,12 @@
 
 # For stage2 target.
 pre_stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c char_io.c \
-	cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \
+	cmdline.c common.c console.c bdev_diskonchip.c disk_io.c fsys_ext2fs.c \
 	fsys_fat.c fsys_ffs.c fsys_jfs.c fsys_minix.c fsys_reiserfs.c \
 	fsys_vstafs.c fsys_xfs.c gunzip.c hercules.c md5.c serial.c \
 	smp-imps.c stage2.c
 pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
-pre_stage2_exec_ASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
+pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
 pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK)
 
 if NETBOOT_SUPPORT
@@ -109,7 +109,7 @@
 	echo "#define STAGE2_SIZE $$6" > stage2_size.h
 
 start_exec_SOURCES = start.S
-start_exec_ASFLAGS = $(STAGE2_COMPILE)
+start_exec_CCASFLAGS = $(STAGE2_COMPILE)
 start_exec_LDFLAGS = $(START_LINK)
 
 # XXX: automake doesn't provide a way to specify dependencies for object
@@ -127,7 +127,7 @@
 	stage1_5.c fsys_ext2fs.c bios.c
 e2fs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \
 	-DNO_BLOCK_FILES=1
-e2fs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \
+e2fs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \
 	-DNO_BLOCK_FILES=1
 e2fs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
 
@@ -136,7 +136,7 @@
 	stage1_5.c fsys_fat.c bios.c
 fat_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \
 	-DNO_BLOCK_FILES=1
-fat_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \
+fat_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \
 	-DNO_BLOCK_FILES=1
 fat_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
 
@@ -145,7 +145,7 @@
 	stage1_5.c fsys_ffs.c bios.c
 ffs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \
 	-DNO_BLOCK_FILES=1
-ffs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \
+ffs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \
 	-DNO_BLOCK_FILES=1
 ffs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
 
@@ -154,7 +154,7 @@
 	stage1_5.c fsys_minix.c bios.c
 minix_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \
 	-DNO_BLOCK_FILES=1
-minix_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \
+minix_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \
 	-DNO_BLOCK_FILES=1
 minix_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
 
@@ -163,7 +163,7 @@
 	disk_io.c stage1_5.c fsys_reiserfs.c bios.c
 reiserfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \
 	-DNO_BLOCK_FILES=1
-reiserfs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \
+reiserfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \
 	-DNO_BLOCK_FILES=1
 reiserfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
 
@@ -172,7 +172,7 @@
 	disk_io.c stage1_5.c fsys_vstafs.c bios.c
 vstafs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \
 	-DNO_BLOCK_FILES=1
-vstafs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \
+vstafs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \
 	-DNO_BLOCK_FILES=1
 vstafs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
 
@@ -181,7 +181,7 @@
 	disk_io.c stage1_5.c fsys_jfs.c bios.c
 jfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \
 	-DNO_BLOCK_FILES=1
-jfs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \
+jfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \
 	-DNO_BLOCK_FILES=1
 jfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
 
@@ -190,7 +190,7 @@
 	disk_io.c stage1_5.c fsys_xfs.c bios.c
 xfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \
 	-DNO_BLOCK_FILES=1
-xfs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \
+xfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \
 	-DNO_BLOCK_FILES=1
 xfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
 
@@ -198,7 +198,7 @@
 diskless_exec_SOURCES = $(pre_stage2_exec_SOURCES)
 diskless_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \
 	-DSUPPORT_DISKLESS=1
-diskless_exec_ASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \
+diskless_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \
 	-DSUPPORT_DISKLESS=1
 diskless_exec_LDFLAGS = $(PRE_STAGE2_LINK)
 diskless_exec_LDADD = ../netboot/libdrivers.a
@@ -210,7 +210,7 @@
 
 # For nbloader target.
 nbloader_exec_SOURCES = nbloader.S
-nbloader_exec_ASFLAGS = $(STAGE2_COMPILE)
+nbloader_exec_CCASFLAGS = $(STAGE2_COMPILE)
 nbloader_exec_LDFLAGS = $(NBLOADER_LINK)
 
 # XXX: See the comment for start_exec-start.o.
@@ -223,7 +223,7 @@
 
 # For pxeloader target.
 pxeloader_exec_SOURCES = pxeloader.S
-pxeloader_exec_ASFLAGS = $(STAGE2_COMPILE)
+pxeloader_exec_CCASFLAGS = $(STAGE2_COMPILE)
 pxeloader_exec_LDFLAGS = $(PXELOADER_LINK)
 
 # XXX: See the comment for start_exec-start.o.
Index: stage2/asm.S
===================================================================
RCS file: /usr/local/cvsroot/grub/stage2/asm.S,v
retrieving revision 1.1.1.3
retrieving revision 1.4
diff -u -r1.1.1.3 -r1.4
--- stage2/asm.S	22 Jun 2002 00:44:29 -0000	1.1.1.3
+++ stage2/asm.S	22 Jun 2002 01:18:05 -0000	1.4
@@ -133,7 +133,7 @@
 
 	sti		/* we're safe again */
 
-#ifndef SUPPORT_DISKLESS
+#if !defined(SUPPORT_DISKLESS) && !defined(BDEV_DISKONCHIP)
 	/* save boot drive reference */
 	ADDR32	movb	%dl, EXT_C(boot_drive)
 
@@ -2229,8 +2229,10 @@
 	.long	PROTSTACKINIT
 
 VARIABLE(boot_drive)
-#ifdef SUPPORT_DISKLESS
+#if defined(SUPPORT_DISKLESS)
 	.long	NETWORK_DRIVE
+#elif defined(BDEV_DISKONCHIP)
+	.long	DISK_ON_CHIP
 #else
 	.long	0
 #endif
Index: stage2/bdev_diskonchip.c
===================================================================
RCS file: stage2/bdev_diskonchip.c
diff -N stage2/bdev_diskonchip.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ stage2/bdev_diskonchip.c	15 Mar 2002 22:55:37 -0000	1.9
@@ -0,0 +1,1068 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1996  Erich Boleyn  <erich@uruk.org>
+ *  Copyright (C) 1999  Free Software Foundation, Inc.
+ *  Copyright (C) 2000  David Woodhouse  <dwmw2@infradead.org>
+ *
+ *  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
+
+#include "shared.h"
+
+#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_Mil_CDSN_IO 0x0800
+#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 DoC_is_Millennium(id) (id == DOC_ChipID_DocMil)
+
+#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 DOC_ECC_DIS (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
+
+/*
+ * NAND Flash Device ID Structure
+ *
+ * Structure overview:
+ *
+ *  name - Complete name of device
+ *
+ *  manufacture_id - manufacturer ID code of device.
+ *
+ *  model_id - model ID code of device.
+ *
+ *  chipshift - total number of address bits for the device which
+ *              is used to calculate address offsets and the total
+ *              number of bytes the device is capable of.
+ *
+ *  page256 - denotes if flash device has 256 byte pages or not.
+ *
+ *  pageadrlen - number of bytes minus one needed to hold the
+ *               complete address into the flash array. Keep in
+ *               mind that when a read or write is done to a
+ *               specific address, the address is input serially
+ *               8 bits at a time. This structure member is used
+ *               by the read/write routines as a loop index for
+ *               shifting the address out 8 bits at a time.
+ *
+ *  erasesize - size of an erase block in the flash device.
+ */
+struct nand_flash_dev {
+	char * name;
+	int manufacture_id;
+	int model_id;
+	int chipshift;
+	char page256;
+	char pageaddrlen;
+	unsigned long erasesize;
+};
+
+static struct nand_flash_dev nand_flash_ids[] = {
+	{"Toshiba TC5816BDC",     NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000},
+	{"Toshiba TC5832DC",      NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000},
+	{"Toshiba TH58V128DC",    NAND_MFR_TOSHIBA, 0x73, 24, 0, 2, 0x4000},
+	{"Toshiba TC58256FT/DC",  NAND_MFR_TOSHIBA, 0x75, 25, 0, 2, 0x4000},
+	{"Toshiba TH58512FT",     NAND_MFR_TOSHIBA, 0x76, 26, 0, 3, 0x4000},
+	{"Toshiba TC58V32DC",     NAND_MFR_TOSHIBA, 0xe5, 22, 0, 2, 0x2000},
+	{"Toshiba TC58V64AFT/DC", NAND_MFR_TOSHIBA, 0xe6, 23, 0, 2, 0x2000},
+	{"Toshiba TC58V16BDC",    NAND_MFR_TOSHIBA, 0xea, 21, 1, 2, 0x1000},
+	{"Samsung KM29N16000",    NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000},
+	{"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000},
+	{"Samsung KM29U128T",     NAND_MFR_SAMSUNG, 0x73, 24, 0, 2, 0x4000},
+	{"Samsung KM29U256T",     NAND_MFR_SAMSUNG, 0x75, 25, 0, 2, 0x4000},
+	{"Samsung unknown 64Mb",  NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000},
+	{"Samsung KM29W32000",    NAND_MFR_SAMSUNG, 0xe3, 22, 0, 2, 0x2000},
+	{"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0xe5, 22, 0, 2, 0x2000},
+	{"Samsung KM29U64000",    NAND_MFR_SAMSUNG, 0xe6, 23, 0, 2, 0x2000},
+	{"Samsung KM29W16000",    NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000},
+	{NULL,}
+};
+
+
+#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 unsigned char docid = 0;
+static char *docname = NULL;
+static int eccstatusreg = 0;
+static int ioreg = 0;
+static int numchips[MAX_FLOORS];
+static int totalchips = 0;
+static int chipshift = 0;
+static char page256 = 0;
+static char pageaddrlen = 0;
+static unsigned long erasesize = 0;
+static unsigned long erasesect = 0;
+static int current_floor = -1;
+static int current_chip = -1;
+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;
+
+/* Perform the required delay cycles by reading from the appropriate register */
+static void DoC_Delay(unsigned short cycles)
+{
+	volatile char dummy;
+	int i;
+	
+	for (i = 0; i < cycles; i++) {
+		if (DoC_is_Millennium(docid))
+			dummy = docloc[DoC_NOP];
+		else
+			dummy = docloc[DoC_DOCStatus];
+	}
+	
+}
+
+static int _DoC_WaitReady(void)
+{
+	short c=-1;
+
+	while (!(docloc[DoC_CDSNControl] & CDSN_CTRL_FR_B) && --c)
+		;
+
+	if (c == 0)
+		printf("_DoC_WaitReady timed out\n");
+
+	return (c==0);
+}
+
+static inline int DoC_WaitReady(void)
+{
+	int ret = 0;
+
+	DoC_Delay(4);
+	if (!(docloc[DoC_CDSNControl] & CDSN_CTRL_FR_B))
+		ret = _DoC_WaitReady();
+	DoC_Delay(2);
+
+	return ret;
+}
+
+static inline void slow_write(unsigned char data)
+{
+	if (DoC_is_Millennium(docid)) {
+		docloc[DoC_CDSNSlowIO] = data;
+		DoC_Delay(4);
+	}
+
+	docloc[ioreg] = data;
+}
+
+static inline void DoC_Command(unsigned char command, unsigned char xtraflags)
+{
+	DoC_WaitReady();
+	docloc[DoC_CDSNControl] = 
+		CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE;
+	DoC_Delay(4);
+
+	slow_write(command);
+
+	docloc[DoC_CDSNControl] = 
+		CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CE;
+	DoC_WaitReady();
+}
+
+static void DoC_Address(unsigned long address, unsigned char xtraflags1,
+	unsigned char xtraflags2, int read_cmd)
+{
+	if (read_cmd)
+		DoC_Command(!page256 && (address & 0x100) ? 
+			NAND_CMD_READ1 : NAND_CMD_READ0, CDSN_CTRL_WP);
+
+	xtraflags1 |= CDSN_CTRL_FLASH_IO;
+	docloc[DoC_CDSNControl] = xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE;
+	DoC_Delay(4);
+
+	slow_write(address & 0xff);
+	address >>= 8;
+	if (!page256)
+		address >>= 1;
+	slow_write(address & 0xff);
+	address >>= 8;
+	slow_write(address & 0xff);
+	address >>= 8;
+	if (pageaddrlen > 2) {
+		slow_write(address & 0xff);
+	}
+	DoC_Delay(2);
+
+	docloc[DoC_CDSNControl] = xtraflags1 | xtraflags2 | CDSN_CTRL_CE;
+	DoC_Delay(4);
+
+	DoC_WaitReady();
+}
+
+static int DoC_IdentChip(unsigned char floor, unsigned char chip)
+{
+	int dummy, mfr, id;
+	struct nand_flash_dev *mfr_id;
+
+	docloc[DoC_FloorSelect] = floor;
+	docloc[DoC_CDSNDeviceSelect] = chip;
+
+	DoC_Command(NAND_CMD_RESET, CDSN_CTRL_WP);
+
+	if (DoC_WaitReady())
+		return 0;
+
+	/* Read the NAND chip ID: 1. Send ReadID command */
+	DoC_Command(NAND_CMD_READID, CDSN_CTRL_WP);
+
+	/* Read the NAND chip ID: 2. Send address byte zero */
+        DoC_Address(0, CDSN_CTRL_WP, 0, 0);
+
+	/* Read the manufacturer and device id codes from the device */
+	/* CDSN Slow IO register see Software Requirement 11.4 item 5. */
+	
+	dummy = docloc[DoC_CDSNSlowIO];
+	DoC_Delay(2);
+	mfr = docloc[ioreg];
+
+	dummy = docloc[DoC_CDSNSlowIO];
+	DoC_Delay(2);
+	id = docloc[ioreg];
+
+	if (mfr == 0xff || mfr == 0)
+		return 0;
+
+	/*
+        if (mfr != NAND_MFR_TOSHIBA && mfr != NAND_MFR_SAMSUNG)
+		return 0;
+	*/
+
+        switch (mfr)
+        {
+          case NAND_MFR_TOSHIBA:
+            printf("floor %d, chip %d; ", floor, chip);
+            printf("manufacturer: Toshiba\n");
+            break;
+          case NAND_MFR_SAMSUNG:
+            printf("floor %d, chip %d; ", floor, chip);
+            printf("manufacturer: Samsung\n");
+            break;
+          default:
+            printf("unknown manufacturer code: 0x%x\n", mfr);
+            return 0;
+        }
+
+        for (mfr_id = nand_flash_ids; mfr_id->name != NULL; mfr_id++)
+        {
+          if (mfr_id->manufacture_id == mfr && mfr_id->model_id == id)
+            break;
+        }
+        if (mfr_id->name == NULL)
+        {
+           printf("unknown model id 0x%x\n", (int)id);
+           return 0;
+        }
+        chipshift = mfr_id->chipshift;
+        page256 = mfr_id->page256;
+        pageaddrlen = mfr_id->pageaddrlen;
+        erasesize = mfr_id->erasesize;
+        erasesect = erasesize >> 9;
+	
+        printf("Chip: %s, total size: %d MiB\n", 
+		mfr_id->name, (int) (1 << (chipshift - 20)));
+        printf("       erase unit: %d bytes, page: %d bytes\n", 
+		(int) erasesize, (int) (page256 ? 256 : 512));
+	
+	DoC_WaitReady();
+
+	/* disable the ECC engine */
+	docloc[DoC_ECCConf] = DOC_ECC_RESV;
+
+	DoC_WaitReady();
+	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
+	unsigned int eccstatus;
+	char *name;
+	unsigned int io;
+
+	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_Doc2k) && 
+	    (ChipID != DOC_ChipID_DocMil)) {
+		printf("Unknown ChipID %x at %x\n", ChipID, (unsigned int)loc);
+#ifndef DOC_PASSIVE_PROBE
+		loc[DoC_DOCControl] = tmp2;
+#endif
+		return 0;
+	}
+
+	if (DoC_is_Millennium(ChipID)) {
+		name = "Millennium";
+		eccstatus = DoC_ECCConf;
+		io = DoC_Mil_CDSN_IO;
+	} else {
+		name = "2000";
+		eccstatus = DoC_2k_ECCStatus;
+		io = DoC_2k_CDSN_IO;
+	}
+
+	/* See if the TOGGLE bit is toggling */
+
+	tmp = loc[eccstatus] & DOC_TOGGLE_BIT;
+	if (tmp == (loc[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. */
+	printf("DiskOnChip %s found at %x\n", name, (unsigned int)loc);
+	docloc = loc;
+	docid = ChipID;
+	docname = name;
+	eccstatusreg = eccstatus;
+	ioreg = io;
+
+	DoC_ScanChips();
+
+	if (!totalchips)
+		return 0;
+	printf("Total of %d chips found - total capacity %d MiB\n",
+		    totalchips, totalchips * ( 1 << (chipshift -20)));
+	return 1;
+}
+
+static void doc_select_chip(int chip)
+{
+	docloc[DoC_CDSNControl] = CDSN_CTRL_WP;
+	DoC_Delay(4);
+	docloc[DoC_CDSNDeviceSelect] = chip;
+	current_chip = chip;
+	DoC_Delay(4);
+	docloc[DoC_CDSNControl] = CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | \
+				  CDSN_CTRL_WP;
+	DoC_Delay(4);
+	DoC_WaitReady();
+}
+
+static int doc_select_floor_chip(unsigned long sector)
+{
+	unsigned char chip, floor;
+
+	chip = sector >> (chipshift - 9);
+	floor = 0;
+
+	/* dprintf("sector %d\n", sector); */
+
+	while (chip >= numchips[floor]) {
+		dprintf("Chip %d Not on floor %d (%d chips)\n", 
+			chip, floor, numchips[floor]);
+		chip -= numchips[floor];
+		floor++;
+		if (floor == MAX_FLOORS)
+			return -1;
+	}
+		
+	/*
+	dprintf("sector 0x%x is on floor %d, chip %d\n", sector, floor, chip);
+	*/
+	
+	if (floor != current_floor) {
+		docloc[DoC_FloorSelect] = floor;
+		current_floor = floor;
+		DoC_WaitReady();
+		doc_select_chip(chip);
+	} else if (chip != current_chip) {
+		doc_select_chip(chip);
+	}
+
+	return 1;
+}
+
+static void DoC_ReadBuf(unsigned char *buf, int len)
+{
+	int i;
+	volatile int dummy;
+	unsigned int modulus = 0xffff;
+
+	if (DoC_is_Millennium(docid)) {
+		/* Read the data via the internal pipeline through 
+		   CDSN IO register, see Pipelined Read Operations 11.3 */
+		dummy = docloc[DoC_ReadPipeInit];
+
+		/* Millennium should use the LastDataRead register - 
+		   Pipeline Reads */
+		len--;
+
+		/* This is needed for correct ECC calculation */
+		modulus = 0xff;
+	}
+
+	for (i=0; i < len; i++) {
+		buf[i] = docloc[ioreg + (i & modulus)];
+	}
+
+	if (DoC_is_Millennium(docid)) {
+		buf[i] = docloc[DoC_LastDataRead];
+	}
+}
+
+static int doc_read_oob(unsigned long sector, void *buf)
+{
+	unsigned long ofs = (sector << 9);
+
+	// printf("doc_read_oob %d\n", (unsigned int) sector);
+	doc_select_floor_chip(sector);
+
+	/* update address for 2M x 8bit devices. OOB starts on the second */
+	/* page to maintain compatibility with doc_read_ecc. */
+	if (page256) {
+		/* read from the middle of 512 byte sector */
+		ofs += 0x100;
+	}
+
+	DoC_Command(NAND_CMD_READOOB, CDSN_CTRL_WP);
+	DoC_Address(ofs, CDSN_CTRL_WP, 0, 0);
+
+	/* treat crossing 8-byte OOB data for 2M x 8bit devices */
+	/* Note: datasheet says it should automaticaly wrap to the */
+	/*       next OOB block, but it didn't work here. mf.      */
+	if (page256) {
+		DoC_ReadBuf(buf, 8);
+		DoC_Command(NAND_CMD_READOOB, CDSN_CTRL_WP);
+
+		/* read from the beginning of 512 byte sector */
+		DoC_Address(ofs & (~0x1ff), CDSN_CTRL_WP, 0, 0);
+		DoC_ReadBuf((unsigned char *)buf + 8, 8);
+	} else {
+		DoC_ReadBuf(buf, 16);
+	}
+	DoC_WaitReady();
+        return 0;
+}
+
+static int doc_read_sector(unsigned long sector, unsigned char *buf)
+{
+        unsigned long address = (sector << 9);
+	// printf("doc_read_sector %d\n", (unsigned int) sector);
+	doc_select_floor_chip(sector);
+
+	DoC_Address(address, CDSN_CTRL_WP, 0, 1);
+
+	/* treat crossing 256-byte sector for 2M x 8bits devices */
+	if (page256) {
+		DoC_ReadBuf(buf, 256);
+		DoC_Address(address + 256, CDSN_CTRL_WP, 0, 1);
+		DoC_ReadBuf(buf + 256, 256);
+	} else {
+		DoC_ReadBuf(buf, 512);
+	}
+
+	DoC_WaitReady();
+        return 0;
+}
+
+static
+void NFTL_setup(unsigned long sect, struct NFTLMediaHeader *hdr)
+{
+  int i;
+  unsigned int eun = sect / erasesect;
+  struct NFTLrecord *nftl;
+
+  for (i=0; i<nNFTLs; i++)
+  {
+    if (NFTLs[i].MediaHdr.FirstPhysicalEUN == hdr->FirstPhysicalEUN)
+    {
+      /* 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 / erasesize;
+
+  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 * erasesect + 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;
+
+  /* dprintf("find virtual sector %d\n", block); */
+  vun = block / erasesect;
+  block = block % erasesect;
+  /* dprintf("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 * erasesect;
+    /* 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 * erasesect;
+    for (; eun<nftl->lastEUN; eun++, sect += erasesect)
+    {
+      if (isbad(nftl_num, eun))
+      { dprintf("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;
+    /* dprintf("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)
+    { /* dprintf("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;
+#ifdef DOC_THOROUGH_DEBUG
+      dprintf("block %d in eun %d is %s\n",
+        block, eun, save_stat == BLOCK_USED ? "BLOCK_USED" : "BLOCK_DELETED");
+#endif
+    }
+    /* is it last in eun chain? */
+    if (oob.u.a.ReplUnitNum == 0xffff)
+    { /* dprintf("eun %d is last in the chain\n", eun); */
+      break;
+    }
+    /* read next eun in the chain */
+    eun = oob.u.a.ReplUnitNum;
+    sect = eun * erasesect;
+    /* dprintf("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)
+  { /* dprintf("found block %d in eun %d\n",
+      save_eun * erasesect + block, save_eun); */
+    return
+      blk_hash[k].pblock = save_eun * erasesect + block;
+  }
+
+  return -1;
+}
+
+static int doc_init(void);
+
+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; sector<ssize; sector+=erasesect)
+  {
+    if (doc_read_sector(sector, nftlbuf) < 0)
+      continue;      
+    if (!strcmp(hdr->DataOrgID, "ANAND"))
+    {
+      dprintf("NFTL Media Header found in flash sector %d\n", sector);
+      dprintf("NumEraseUnits: %d\n", hdr->NumEraseUnits);
+      dprintf("FirstPhysicalEUN: %d\n", hdr->FirstPhysicalEUN);
+      dprintf("FormattedSize: %d\n", hdr->FormattedSize);
+      dprintf("UnitSizeFactor: %d\n", hdr->UnitSizeFactor);
+      NFTL_setup(sector, hdr);
+    }
+  }
+}
+
+static void doc_find(void)
+{
+	unsigned long probeloc = 0xc8000;
+	
+
+	for (probeloc = 0xc8000; probeloc < 0xf0000; probeloc += 0x2000) {
+		if (DoC_Probe((unsigned char *)probeloc)) {
+			NFTL_Scan();
+			return;
+		}
+	}
+	
+	printf("No DiskOnChip found\n");
+	return;
+}
+		
+static int doc_init(void)
+{
+  /* If this is the first time we've been called, 
+     we need to go searching for a DiskOnChip
+  */
+  if (!doc_inited)
+  {
+    int i;
+
+    for (i=0; i<max_blk_hash; i++)
+    {
+      blk_hash[i].nftl = -1;
+      blk_hash[i].vblock = -1;
+      blk_hash[i].pblock = -1;
+    }
+    
+    for (i=0; i<max_eun_hash; i++)
+    {
+      eun_hash[i].nftl = -1;
+      eun_hash[i].vun = 0xffff;
+      eun_hash[i].eun = 0xffff;
+    }
+
+    current_floor = -1;
+    current_chip = -1;
+
+    doc_find();
+
+    doc_inited = 1;
+  }
+
+  if (docloc == NULL)
+  {
+    errnum = ERR_NO_DISK;
+    return 0;
+  }
+  return 1;
+}
+
+int nftl_rawread(int drive, int sector, int byte_offset, int byte_len, char *buf)
+{
+  int size, block;
+
+  /* dprintf("nftl_rawread(%d, %d, %d, %d)\n", 
+	drive, sector, byte_offset, byte_len); */
+  if (byte_len < 0 || !buf || drive < 0 || drive >= MAX_NFTLS)
+  { errnum = ERR_BAD_ARGUMENT; return 0;
+  }
+
+  if (!doc_init())
+    return 0;
+
+  if (drive < 0 || drive >= 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;
+    }
+
+#ifdef DOC_THOROUGH_DEBUG
+  {
+    /* int sec = 16352;
+    printf("nftl_rawread: reading sector %d\n", sector);
+    if (doc_read_sector(sec, nftlbuf) < 0) {
+      printf("error\n");
+    } else { */
+      int i = 0;
+      while (i < SECTOR_SIZE) {
+        printf("%x    "
+          "%b %b %b %b %b %b %b %b "
+          "%b %b %b %b %b %b %b %b\n",
+           i, 
+           nftlbuf[i + 0], nftlbuf[i + 1], nftlbuf[i + 2], nftlbuf[i + 3], 
+           nftlbuf[i + 4], nftlbuf[i + 5], nftlbuf[i + 6], nftlbuf[i + 7],
+           nftlbuf[i + 8], nftlbuf[i + 9], nftlbuf[i + 10], nftlbuf[i + 11],
+           nftlbuf[i + 12], nftlbuf[i + 13], nftlbuf[i + 14], nftlbuf[i + 15]);
+        i += 16;
+      }
+      printf("Press any key..."); getkey(); printf("\n");
+    // }
+  }
+#endif
+
+#ifdef DOC_THOROUGH_DEBUG
+    printf("memcpy(0x%x, 0x%x, 0x%x)\n", 
+      (int)buf, (int)(nftlbuf + byte_offset), (int)size);
+#endif
+    if (memcpy(buf, nftlbuf + byte_offset, size) == NULL) {
+	printf("nftl_rawread(): error %d in memcpy() or earlier,"
+		" press any key...", errnum);
+	getkey();
+        printf("\n");
+        errnum = ERR_FSYS_CORRUPT;
+        return 0;
+     }
+#ifdef DOC_THOROUGH_DEBUG
+  {
+    int i = 0;
+    while (i < SECTOR_SIZE) {
+      printf("%x    "
+        "%b %b %b %b %b %b %b %b "
+        "%b %b %b %b %b %b %b %b\n",
+         i, 
+         buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3], 
+         buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7],
+         buf[i + 8], buf[i + 9], buf[i + 10], buf[i + 11],
+         buf[i + 12], buf[i + 13], buf[i + 14], buf[i + 15]);
+      i += 16;
+    }
+    printf("Press any key..."); getkey(); printf("\n");
+  }
+#endif
+
+#ifdef DOC_THOROUGH_DEBUG
+    dprintf("read 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;
+}
+
+int get_diskinfo_diskonchip (int drive, unsigned long *cylinders, 
+	unsigned long *heads, unsigned long *sectors)
+{
+  if (!doc_init())
+    return 1;		// bios.c functions return non-zero on error
+
+  if (drive < 0 || drive >= nNFTLs)
+  { errnum = ERR_NO_DISK; return 1;
+  }
+
+  *sectors = 1;
+  *heads = erasesect;
+  *cylinders = (NFTLs[drive].MediaHdr.FormattedSize >> 9) / (*heads);
+  return 0;
+}
+
+#endif /* BDEV_DISKONCHIP */
+
Index: stage2/bios.c
===================================================================
RCS file: /usr/local/cvsroot/grub/stage2/bios.c,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -u -r1.1.1.2 -r1.4
--- stage2/bios.c	10 Feb 2002 16:05:37 -0000	1.1.1.2
+++ stage2/bios.c	28 Feb 2002 20:24:04 -0000	1.4
@@ -129,6 +129,22 @@
   /* Clear the flags.  */
   geometry->flags = 0;
   
+#ifdef BDEV_DISKONCHIP
+  if ((drive & 0xFFFFFFF0) == DISK_ON_CHIP)
+    {
+      err = get_diskinfo_diskonchip (drive & 0x0000000f,
+		   &geometry->cylinders,
+		   &geometry->heads,
+		   &geometry->sectors);
+      if (err)
+	return err;
+
+      geometry->total_sectors = (geometry->cylinders
+				 * geometry->heads
+				 * geometry->sectors);
+    }
+  else
+#endif
   if (drive & 0x80)
     {
       /* hard disk */
@@ -209,6 +225,13 @@
 			   * geometry->sectors);
 	}
       geometry->total_sectors = total_sectors;
+    }
+  else if (drive == NETWORK_DRIVE)
+    { /* indulge the command line geometry query */
+      geometry->cylinders = 0;
+      geometry->heads = 0;
+      geometry->sectors = 0;
+      geometry->total_sectors = 0;
     }
   else
     {
Index: stage2/boot.c
===================================================================
RCS file: /usr/local/cvsroot/grub/stage2/boot.c,v
retrieving revision 1.1.1.3
retrieving revision 1.4
diff -u -r1.1.1.3 -r1.4
--- stage2/boot.c	30 May 2002 18:09:15 -0000	1.1.1.3
+++ stage2/boot.c	30 May 2002 18:14:31 -0000	1.4
@@ -61,6 +61,8 @@
      buffer by default */
   pu.aout = (struct exec *) buffer;
 
+  printf("Loading kernel image...\n");
+
   if (!grub_open (kernel))
     return KERNEL_TYPE_NONE;
 
Index: stage2/builtins.c
===================================================================
RCS file: /usr/local/cvsroot/grub/stage2/builtins.c,v
retrieving revision 1.1.1.4
retrieving revision 1.7
diff -u -r1.1.1.4 -r1.7
--- stage2/builtins.c	22 Jun 2002 00:44:29 -0000	1.1.1.4
+++ stage2/builtins.c	22 Jun 2002 01:18:05 -0000	1.7
@@ -1356,56 +1356,68 @@
       return 1;
     }
 
-  /* Attempt to read the first sector, because some BIOSes turns out not
-     to support LBA even though they set the bit 0 in the support
-     bitmap, only after reading something actually.  */
-  if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG))
+  if ((current_drive & 0xfffffff0) == DISK_ON_CHIP)
     {
-      errnum = ERR_READ;
-      return 1;
+      msg = "Disk On Chip";
     }
-
-#ifdef GRUB_UTIL
-  ptr = skip_to (0, device);
-  if (*ptr)
+  else if (current_drive == NETWORK_DRIVE)
     {
-      char *cylinder, *head, *sector, *total_sector;
-      int num_cylinder, num_head, num_sector, num_total_sector;
-
-      cylinder = ptr;
-      head = skip_to (0, cylinder);
-      sector = skip_to (0, head);
-      total_sector = skip_to (0, sector);
-      if (! safe_parse_maxint (&cylinder, &num_cylinder)
-	  || ! safe_parse_maxint (&head, &num_head)
-	  || ! safe_parse_maxint (&sector, &num_sector))
-	return 1;
-
-      disks[current_drive].cylinders = num_cylinder;
-      disks[current_drive].heads = num_head;
-      disks[current_drive].sectors = num_sector;
-
-      if (safe_parse_maxint (&total_sector, &num_total_sector))
-	disks[current_drive].total_sectors = num_total_sector;
-      else
-	disks[current_drive].total_sectors
-	  = num_cylinder * num_head * num_sector;
-      errnum = 0;
-
-      geom = disks[current_drive];
-      buf_drive = -1;
+      msg = "Network Drive";
     }
+  else
+    {
+      /* Attempt to read the first sector, because some BIOSes turns out not
+         to support LBA even though they set the bit 0 in the support
+         bitmap, only after reading something actually.  */
+      if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG))
+        {
+          errnum = ERR_READ;
+          return 1;
+        }
+
+#ifdef GRUB_UTIL
+      ptr = skip_to (0, device);
+      if (*ptr)
+        {
+          char *cylinder, *head, *sector, *total_sector;
+          int num_cylinder, num_head, num_sector, num_total_sector;
+
+          cylinder = ptr;
+          head = skip_to (0, cylinder);
+          sector = skip_to (0, head);
+          total_sector = skip_to (0, sector);
+          if (! safe_parse_maxint (&cylinder, &num_cylinder)
+              || ! safe_parse_maxint (&head, &num_head)
+              || ! safe_parse_maxint (&sector, &num_sector))
+            return 1;
+
+          disks[current_drive].cylinders = num_cylinder;
+          disks[current_drive].heads = num_head;
+          disks[current_drive].sectors = num_sector;
+
+          if (safe_parse_maxint (&total_sector, &num_total_sector))
+            disks[current_drive].total_sectors = num_total_sector;
+          else
+            disks[current_drive].total_sectors
+              = num_cylinder * num_head * num_sector;
+          errnum = 0;
+
+          geom = disks[current_drive];
+          buf_drive = -1;
+        }
 #endif /* GRUB_UTIL */
 
 #ifdef GRUB_UTIL
-  msg = device_map[current_drive];
+      msg = device_map[current_drive];
 #else
-  if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)
-    msg = "LBA";
-  else
-    msg = "CHS";
+      if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)
+        msg = "LBA";
+      else
+        msg = "CHS";
 #endif
 
+    }  /* current_drive is not DiskOnChip and not a network drive */
+
   grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, "
 	       "The number of sectors = %d, %s\n",
 	       current_drive,
@@ -3077,6 +3089,19 @@
     {
       /* Network drive.  */
       grub_printf (" (nd):");
+    }
+  else if ((saved_drive & 0xfffffff0) == 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)
     {
Index: stage2/char_io.c
===================================================================
RCS file: /usr/local/cvsroot/grub/stage2/char_io.c,v
retrieving revision 1.1.1.4
retrieving revision 1.7
diff -u -r1.1.1.4 -r1.7
--- stage2/char_io.c	22 Jun 2002 00:44:29 -0000	1.1.1.4
+++ stage2/char_io.c	22 Jun 2002 01:18:05 -0000	1.7
@@ -1157,6 +1157,7 @@
 int
 memcheck (int addr, int len)
 {
+  int memerr = 0;
 #ifdef GRUB_UTIL
   static int start_addr (void)
     {
@@ -1181,22 +1182,38 @@
     }
 
   if (start_addr () <= addr && end_addr () > addr + len)
-    return ! errnum;
+    {
+      memerr = errnum = ERR_WONT_FIT;
+      return ! memerr;
+    }
 #endif /* GRUB_UTIL */
 
+#if MEMORY_DEBUG
+  printf("memcheck(): errnum %d, addr 0x%x, len 0x%x,"
+	" mem_lower 0x%x, mem_upper 0x%x\n",
+	errnum, addr, len, mbi.mem_lower, mbi.mem_upper);
+#endif
+
   if ((addr < RAW_ADDR (0x1000))
       || (addr < RAW_ADDR (0x100000)
 	  && RAW_ADDR (mbi.mem_lower * 1024) < (addr + len))
       || (addr >= RAW_ADDR (0x100000)
 	  && RAW_ADDR (mbi.mem_upper * 1024) < ((addr - 0x100000) + len)))
-    errnum = ERR_WONT_FIT;
+    {
+      printf("memcheck(): error\n");
+      memerr = errnum = ERR_WONT_FIT;
+    }
 
-  return ! errnum;
+  return ! memerr;
 }
 
 void *
 grub_memmove (void *to, const void *from, int len)
 {
+#if MEMORY_DEBUG
+   printf("grub_memmove(): errnum %d, to 0x%x, from 0x%x, len 0x%x\n",
+	errnum, (int) to, (int) from, len);
+#endif
    if (memcheck ((int) to, len))
      {
        /* This assembly code is stolen from
@@ -1227,6 +1244,9 @@
 	 }
      }
 
+#if MEMORY_DEBUG
+   printf("grub_memmove(): errnum %d\n", errnum);
+#endif
    return errnum ? NULL : to;
 }
 
Index: stage2/disk_io.c
===================================================================
RCS file: /usr/local/cvsroot/grub/stage2/disk_io.c,v
retrieving revision 1.1.1.4
retrieving revision 1.8
diff -u -r1.1.1.4 -r1.8
--- stage2/disk_io.c	22 Jun 2002 00:44:29 -0000	1.1.1.4
+++ stage2/disk_io.c	22 Jun 2002 01:18:05 -0000	1.8
@@ -127,9 +127,24 @@
 {
   int slen = (byte_offset + byte_len + SECTOR_SIZE - 1) >> SECTOR_BITS;
 
+#if !defined(STAGE1_5)
+  if (debug)
+    {
+      printf("rawread: drive %d, sector %d, byte_offset %d,"
+	" byte_len %d, buf 0x%x\n", drive, sector, byte_offset, byte_len, buf);
+    }
+#endif
+
   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;
@@ -298,6 +313,16 @@
 int
 rawwrite (int drive, int sector, char *buf)
 {
+
+#ifdef BDEV_DISKONCHIP
+  if ((drive & 0xfffffff0) == DISK_ON_CHIP)
+    {
+      errnum = ERR_WRITE;
+      return 0;
+      /* return nftl_rawrite(drive & 0x0000000f, sector, buf); */
+    }
+#endif
+
   if (sector == 0)
     {
       if (biosdisk (BIOSDISK_READ, drive, &buf_geom, 0, 1, SCRATCHSEG))
@@ -365,15 +390,20 @@
     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)
       && ((current_partition >> 16) == 0xFF
 	  || (current_drive & 0x80)))
-    return 1;
+    {
+      dprintf("sane_partition: yes\n");
+      return 1;
+    }
 
   errnum = ERR_DEV_VALUES;
+  dprintf("sane_partition: no\n");
   return 0;
 }
 #endif /* ! STAGE1_5 */
@@ -618,14 +648,39 @@
 	  pc_slice_no = -1;
 	}
 
+      dprintf("next_pc_slice(): errnum %d\n", errnum);
+      dprintf("next_pc_slice(): reading MBR at sector 0x%x of drive 0x%x\n",
+		*offset, drive);
       /* Read the MBR or the boot sector of the extended partition.  */
       if (! rawread (drive, *offset, 0, SECTOR_SIZE, buf))
-	return 0;
+	{
+	  printf("next_pc_slice: error reading MBR at sector %x"
+		" of drive %x\n", *offset, drive);
+	  return 0;
+	}
+
+#ifdef DOC_THOROUGH_DEBUG
+        {
+	  int i = 0;
+	  while (i < SECTOR_SIZE) {
+	    printf("%x    "
+		"%b %b %b %b %b %b %b %b "
+		"%b %b %b %b %b %b %b %b\n",
+		i, 
+		buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3], 
+		buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7],
+		buf[i + 8], buf[i + 9], buf[i + 10], buf[i + 11],
+		buf[i + 12], buf[i + 13], buf[i + 14], buf[i + 15]);
+	    i += 16;
+	  }
+        }
+#endif
 
       /* Check if it is valid.  */
       if (! PC_MBR_CHECK_SIG (buf))
 	{
 	  errnum = ERR_BAD_PART_TABLE;
+	  printf("next_pc_slice: invalid MBR\n");
 	  return 0;
 	}
 
@@ -675,6 +730,9 @@
 
   /* Start the body of this function.  */
   
+  dprintf("next_partition(): drive %x, current_drive 0x%x\n",
+	drive, current_drive);
+
 #ifndef STAGE1_5
   if (current_drive == NETWORK_DRIVE)
     return 0;
@@ -932,6 +990,8 @@
   current_drive = saved_drive;
   current_partition = 0xFFFFFF;
 
+  dprintf("set_device(): device %s, drive %x\n", device, current_drive);
+
   if (*device == '(' && !*(device + 1))
     /* user has given '(' only, let disk_choice handle what disks we have */
     return device + 1;
@@ -942,7 +1002,7 @@
 	{
 	  char ch = *device;
 
-	  if (*device == 'f' || *device == 'h')
+	  if (ch == 'f' || ch == 'h')
 	    {
 	      /* user has given '([fh]', check for resp. add 'd' and
 		 let disk_choice handle what disks we have */
@@ -957,24 +1017,37 @@
 		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 *) &current_drive);
+	      disk_choice = 0;
+	      current_drive += DISK_ON_CHIP;
+	      break;
 	      
+	    case MK16('h','d'):
+	    case MK16('f','d'):
+	      safe_parse_maxint (&device, (int *) &current_drive);
 	      disk_choice = 0;
 	      if (ch == 'h')
 		current_drive += 0x80;
+	      break;
+	      
+	    default:
+	      errnum = ERR_NUMBER_PARSING;
 	    }
 	}
 
       if (errnum)
-	return 0;
+	 return 0;
 
       if (*device == ')')
 	{
@@ -1056,8 +1129,15 @@
 int
 open_device (void)
 {
+  dprintf("open_device(): errnum %d, current_drive %x, current_partition %x\n",
+	errnum, current_drive, current_partition);
   if (open_partition ())
-    attempt_mount ();
+    {
+      dprintf("open_device(): open_partition() ok, attempt_mount()\n");
+      attempt_mount ();
+    }
+
+  dprintf("open_device(): errnum %d\n", errnum);
 
   if (errnum != ERR_NONE)
     return 0;
@@ -1117,6 +1197,7 @@
   
 #else /* ! STAGE1_5 */
   
+  dprintf("setup_part(): filename %s\n", filename);
   if (*filename == '(')
     {
       if ((filename = set_device (filename)) == 0)
@@ -1150,6 +1231,7 @@
   
 #endif /* ! STAGE1_5 */
   
+  dprintf("setup_part(): errnum %d\n", errnum);
   if (errnum && (*filename == '/' || errnum != ERR_FSYS_MOUNT))
     return 0;
   else
@@ -1534,8 +1616,10 @@
   print_possibilities = 0;
 # endif
 
+  dprintf("grub_open(): errnum %d == 0 ? calling dir_func\n", errnum);
   if (!errnum && (*(fsys_table[fsys_type].dir_func)) (filename))
     {
+      dprintf("grub_open(): dir_func returned success\n");
 #ifndef NO_DECOMPRESSION
       return gunzip_test_header ();
 #else /* NO_DECOMPRESSION */
Index: stage2/shared.h
===================================================================
RCS file: /usr/local/cvsroot/grub/stage2/shared.h,v
retrieving revision 1.1.1.4
retrieving revision 1.8
diff -u -r1.1.1.4 -r1.8
--- stage2/shared.h	22 Jun 2002 00:44:29 -0000	1.1.1.4
+++ stage2/shared.h	22 Jun 2002 01:18:05 -0000	1.8
@@ -27,6 +27,14 @@
 
 #include <config.h>
 
+/* #define DOC_DEBUG */
+
+#ifdef DOC_DEBUG
+	#define dprintf(fmt...)  printf(fmt)
+#else
+	#define dprintf(fmt...)
+#endif
+
 /* Add an underscore to a C symbol in assembler code if needed. */
 #ifdef HAVE_ASM_USCORE
 # define EXT_C(sym) _ ## sym
@@ -183,7 +191,7 @@
 
 /* Not bad, perhaps.  */
 #define NETWORK_DRIVE	0x20
-
+#define DISK_ON_CHIP	0xE0
 /*
  *  GRUB specific information
  *    (in LSB order)
@@ -974,6 +982,14 @@
 #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
+);
+extern int get_diskinfo_diskonchip (int drive, unsigned long *cylinders, 
+	unsigned long *heads, unsigned long *sectors);
+#endif
 
 #endif /* ASM_FILE */
 
Index: stage2/stage2.c
===================================================================
RCS file: /usr/local/cvsroot/grub/stage2/stage2.c,v
retrieving revision 1.1.1.4
retrieving revision 1.9
diff -u -r1.1.1.4 -r1.9
--- stage2/stage2.c	22 Jun 2002 00:44:29 -0000	1.1.1.4
+++ stage2/stage2.c	22 Jun 2002 01:18:05 -0000	1.9
@@ -770,6 +770,46 @@
   return pos;
 }
 
+#ifdef BDEV_DISKONCHIP
+static int
+try_config_partition(int part_no)
+{
+  int is_opened = 0;
+  saved_partition   = 0x0000FFFF | (part_no << 16);
+  current_partition = 0xFFFFFFFF;
+  errnum = ERR_NONE;
+  printf("Attempting to open %s on drive 0x%x, partition 0x%x\n", 
+    config_file, saved_drive, part_no);
+  is_opened = grub_open (config_file);
+  dprintf("grub_open %d, errnum %d\n", is_opened, errnum);
+  return is_opened;
+}
+
+static int
+find_config(int drive_no)
+{
+  int part_no;
+  unsigned long saved_drive2;
+  unsigned long saved_partition2;
+  saved_drive2 = saved_drive;
+  saved_partition2 = saved_partition;
+  saved_drive = drive_no;
+  current_drive = 0xFF;
+  if (try_config_partition(saved_partition >> 16))
+    return 1;
+  if (try_config_partition(0xFF))
+    return 1;
+  for (part_no = 0; part_no < 0x10; part_no++)
+    {
+      if (try_config_partition(part_no))
+        return 1;
+    }
+  saved_partition   = saved_partition2;
+  saved_drive = saved_drive2;
+  current_partition = 0xFFFFFFFF;
+  return 0;
+}
+#endif
 
 /* This is the starting function in C.  */
 void
@@ -813,30 +853,45 @@
 	  do
 	    {
 	      /* STATE 0:  Before any title command.
-		 STATE 1:  In a title command.
-		 STATE >1: In a entry after a title command.  */
+	         STATE 1:  In a title command.
+	         STATE >1: In a entry after a title command.  */
 	      int state = 0, prev_config_len = 0, prev_menu_len = 0;
 	      char *cmdline;
 
 	      /* Try the preset menu first. This will succeed at most once,
-		 because close_preset_menu disables the preset menu.  */
+	         because close_preset_menu disables the preset menu.  */
 	      is_opened = is_preset = open_preset_menu ();
 	      if (! is_opened)
 		{
+#ifdef BDEV_DISKONCHIP
+		  /* Look for configuration file in DiskOnChip 
+		   * by trying to find a file system from its very start.
+		   * If that failed, find_config() will assume there is
+		   * a partition table and will attempt to open partitions
+		   * 0 through 15.
+		   * Next, if the above didn't succeed, perform the same
+		   * search on the first hard disk (BIOS drive 0x80).
+		   */
+		  is_opened = find_config(saved_drive);
+		  if (! is_opened )
+	            is_opened = find_config(0x80);
+		  dprintf("is_opened %d\n", is_opened);
+#else
 		  is_opened = grub_open (config_file);
-		  errnum = ERR_NONE;
+#endif
+		  if (! is_opened)
+	            current_term->flags |= TERM_DUMB;
 		}
 
 	      if (! is_opened)
-		break;
+	        break;
 
 	      /* This is necessary, because the menu must be overrided.  */
 	      reset ();
 	      
 	      cmdline = (char *) CMDLINE_BUF;
-	      while (get_line_from_config (cmdline, NEW_HEAPSIZE,
-					   ! is_preset))
-		{
+	      while (get_line_from_config (cmdline, NEW_HEAPSIZE, ! is_preset))
+	        {
 		  struct builtin *builtin;
 		  
 		  /* Get the pointer to the builtin structure.  */

