Merge master.kernel.org:/pub/scm/linux/kernel/git/cooloney/blackfin-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 12 Jul 2007 20:25:24 +0000 (13:25 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 12 Jul 2007 20:25:24 +0000 (13:25 -0700)
* master.kernel.org:/pub/scm/linux/kernel/git/cooloney/blackfin-2.6: (30 commits)
  Blackfin serial driver: supporting BF548-EZKIT serial port
  Video Console: Blackfin doesnt support VGA console
  Blackfin arch: Add peripheral io API to gpio header file
  Blackfin arch: set up gpio interrupt IRQ_PJ9 for BF54x ATAPI PATA driver
  Blackfin arch: add missing CONFIG_LARGE_ALLOCS when upstream merging
  Blackfin arch: as pointed out by Robert P. J. Day, update the CPU_FREQ name to match current Kconfig
  Blackfin arch: extract the entry point from the linked kernel
  Blackfin arch: clean up some coding style issues
  Blackfin arch: combine the common code of free_initrd_mem and free_initmem
  Blackfin arch: Add Support for Peripheral PortMux and resouce allocation
  Blackfin arch: use PAGE_SIZE when doing aligns rather than hardcoded values
  Blackfin arch: fix bug set dma_address properly in dma_map_sg
  Blackfin arch: Disable CACHELINE_ALIGNED_L1 for BF54x by default
  Blackfin arch: Port the dm9000 driver to Blackfin by using the correct low-level io routines
  Blackfin arch: There is no CDPRIO Bit in the EBIU_AMGCTL Register of BF54x arch
  Blackfin arch: scrub dead code
  Blackfin arch: Fix Warning add some defines in BF54x header file
  Blackfin arch: add BF54x missing GPIO access functions
  Blackfin arch: Some memory and code optimizations - Fix SYS_IRQS
  Blackfin arch: Enable BF54x PIN/GPIO interrupts
  ...

118 files changed:
Documentation/DocBook/kernel-api.tmpl
Documentation/feature-removal-schedule.txt
Documentation/i2c/busses/i2c-i801
Documentation/i2c/busses/i2c-piix4
Documentation/i2c/busses/i2c-taos-evm [new file with mode: 0644]
Documentation/i2c/chips/max6875
Documentation/i2c/chips/x1205 [deleted file]
Documentation/i2c/summary
Documentation/i2c/writing-clients
Documentation/i386/zero-page.txt
MAINTAINERS
arch/i386/Kconfig.cpu
arch/i386/boot/Makefile
arch/i386/boot/a20.c [new file with mode: 0644]
arch/i386/boot/apm.c [new file with mode: 0644]
arch/i386/boot/bitops.h [new file with mode: 0644]
arch/i386/boot/boot.h [new file with mode: 0644]
arch/i386/boot/bootsect.S [deleted file]
arch/i386/boot/cmdline.c [new file with mode: 0644]
arch/i386/boot/code16gcc.h [new file with mode: 0644]
arch/i386/boot/compressed/Makefile
arch/i386/boot/compressed/head.S
arch/i386/boot/copy.S [new file with mode: 0644]
arch/i386/boot/cpu.c [new file with mode: 0644]
arch/i386/boot/cpucheck.c [new file with mode: 0644]
arch/i386/boot/edd.S [deleted file]
arch/i386/boot/edd.c [new file with mode: 0644]
arch/i386/boot/header.S [new file with mode: 0644]
arch/i386/boot/main.c [new file with mode: 0644]
arch/i386/boot/mca.c [new file with mode: 0644]
arch/i386/boot/memory.c [new file with mode: 0644]
arch/i386/boot/pm.c [new file with mode: 0644]
arch/i386/boot/pmjump.S [new file with mode: 0644]
arch/i386/boot/printf.c [new file with mode: 0644]
arch/i386/boot/setup.S [deleted file]
arch/i386/boot/setup.ld [new file with mode: 0644]
arch/i386/boot/string.c [new file with mode: 0644]
arch/i386/boot/tools/build.c
arch/i386/boot/tty.c [new file with mode: 0644]
arch/i386/boot/version.c [new file with mode: 0644]
arch/i386/boot/vesa.h [new file with mode: 0644]
arch/i386/boot/video-bios.c [new file with mode: 0644]
arch/i386/boot/video-vesa.c [new file with mode: 0644]
arch/i386/boot/video-vga.c [new file with mode: 0644]
arch/i386/boot/video.S [deleted file]
arch/i386/boot/video.c [new file with mode: 0644]
arch/i386/boot/video.h [new file with mode: 0644]
arch/i386/boot/voyager.c [new file with mode: 0644]
arch/i386/kernel/cpu/Makefile
arch/i386/kernel/cpu/addon_cpuid_features.c [new file with mode: 0644]
arch/i386/kernel/cpu/common.c
arch/i386/kernel/cpu/proc.c
arch/i386/kernel/e820.c
arch/i386/kernel/setup.c
arch/i386/kernel/verify_cpu.S [deleted file]
arch/x86_64/Kconfig
arch/x86_64/boot/Makefile
arch/x86_64/boot/bootsect.S [deleted file]
arch/x86_64/boot/compressed/Makefile
arch/x86_64/boot/compressed/head.S
arch/x86_64/boot/install.sh [deleted file]
arch/x86_64/boot/mtools.conf.in [deleted file]
arch/x86_64/boot/setup.S [deleted file]
arch/x86_64/boot/tools/build.c [deleted file]
arch/x86_64/kernel/Makefile
arch/x86_64/kernel/setup.c
arch/x86_64/kernel/verify_cpu.S
drivers/i2c/algos/Kconfig
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-gpio.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-nforce2.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-pmcmsp.c [new file with mode: 0644]
drivers/i2c/busses/i2c-powermac.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-rpx.c [deleted file]
drivers/i2c/busses/i2c-savage4.c
drivers/i2c/busses/i2c-sis5595.c
drivers/i2c/busses/i2c-taos-evm.c [new file with mode: 0644]
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/busses/scx200_acb.c
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/i2c/chips/ds1682.c [new file with mode: 0644]
drivers/i2c/chips/eeprom.c
drivers/i2c/chips/max6875.c
drivers/i2c/chips/tsl2550.c [new file with mode: 0644]
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
drivers/ide/legacy/hd.c
drivers/macintosh/windfarm_smu_sat.c
drivers/rtc/rtc-x1205.c
drivers/video/matrox/matroxfb_crtc2.h
include/asm-i386/boot.h
include/asm-i386/bootparam.h [new file with mode: 0644]
include/asm-i386/cpufeature.h
include/asm-i386/e820.h
include/asm-i386/processor.h
include/asm-i386/required-features.h
include/asm-i386/setup.h
include/asm-x86_64/alternative.h
include/asm-x86_64/boot.h
include/asm-x86_64/bootparam.h [new file with mode: 0644]
include/asm-x86_64/cpufeature.h
include/asm-x86_64/e820.h
include/asm-x86_64/processor.h
include/asm-x86_64/required-features.h [new file with mode: 0644]
include/asm-x86_64/segment.h
include/linux/edd.h
include/linux/i2c.h
include/linux/pci_ids.h
include/linux/screen_info.h
include/linux/serio.h

index 8c5698a8c2e1e071060511353ce457da215f0e5e..46bcff2849bddbffad2817304bbc8964b1cba6e5 100644 (file)
@@ -643,6 +643,60 @@ X!Idrivers/video/console/fonts.c
 !Edrivers/spi/spi.c
   </chapter>
 
+  <chapter id="i2c">
+     <title>I<superscript>2</superscript>C and SMBus Subsystem</title>
+
+     <para>
+       I<superscript>2</superscript>C (or without fancy typography, "I2C")
+       is an acronym for the "Inter-IC" bus, a simple bus protocol which is
+       widely used where low data rate communications suffice.
+       Since it's also a licensed trademark, some vendors use another
+       name (such as "Two-Wire Interface", TWI) for the same bus.
+       I2C only needs two signals (SCL for clock, SDA for data), conserving
+       board real estate and minimizing signal quality issues.
+       Most I2C devices use seven bit addresses, and bus speeds of up
+       to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
+       found wide use.
+       I2C is a multi-master bus; open drain signaling is used to
+       arbitrate between masters, as well as to handshake and to
+       synchronize clocks from slower clients.
+     </para>
+
+     <para>
+       The Linux I2C programming interfaces support only the master
+       side of bus interactions, not the slave side.
+       The programming interface is structured around two kinds of driver,
+       and two kinds of device.
+       An I2C "Adapter Driver" abstracts the controller hardware; it binds
+       to a physical device (perhaps a PCI device or platform_device) and
+       exposes a <structname>struct i2c_adapter</structname> representing
+       each I2C bus segment it manages.
+       On each I2C bus segment will be I2C devices represented by a
+       <structname>struct i2c_client</structname>.  Those devices will
+       be bound to a <structname>struct i2c_driver</structname>,
+       which should follow the standard Linux driver model.
+       (At this writing, a legacy model is more widely used.)
+       There are functions to perform various I2C protocol operations; at
+       this writing all such functions are usable only from task context.
+     </para>
+
+     <para>
+       The System Management Bus (SMBus) is a sibling protocol.  Most SMBus
+       systems are also I2C conformant.  The electrical constraints are
+       tighter for SMBus, and it standardizes particular protocol messages
+       and idioms.  Controllers that support I2C can also support most
+       SMBus operations, but SMBus controllers don't support all the protocol
+       options that an I2C controller will.
+       There are functions to perform various SMBus protocol operations,
+       either using I2C primitives or by issuing SMBus commands to
+       i2c_adapter devices which don't support those I2C operations.
+     </para>
+
+!Iinclude/linux/i2c.h
+!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
+!Edrivers/i2c/i2c-core.c
+  </chapter>
+
   <chapter id="splice">
       <title>splice API</title>
   <para>)
@@ -654,4 +708,5 @@ X!Idrivers/video/console/fonts.c
 !Ffs/splice.c
   </chapter>
 
+
 </book>
index 3a159dac04f56c204651ac31f869b292083de618..281458b47d75689b8141ee3e79c25f492f18999d 100644 (file)
@@ -330,3 +330,10 @@ Who:  Tejun Heo <htejun@gmail.com>
 
 ---------------------------
 
+What:  Legacy RTC drivers (under drivers/i2c/chips)
+When:  November 2007
+Why:   Obsolete. We have a RTC subsystem with better drivers.
+Who:   Jean Delvare <khali@linux-fr.org>
+
+---------------------------
+
index c34f0db78a30f9f66b22f055f92cd95ae024c6dc..fe6406f2f9a66ac9c96216c097f02b0b7b107816 100644 (file)
@@ -5,8 +5,8 @@ Supported adapters:
     '810' and '810E' chipsets)
   * Intel 82801BA (ICH2 - part of the '815E' chipset)
   * Intel 82801CA/CAM (ICH3)
-  * Intel 82801DB (ICH4) (HW PEC supported, 32 byte buffer not supported)
-  * Intel 82801EB/ER (ICH5) (HW PEC supported, 32 byte buffer not supported)
+  * Intel 82801DB (ICH4) (HW PEC supported)
+  * Intel 82801EB/ER (ICH5) (HW PEC supported)
   * Intel 6300ESB
   * Intel 82801FB/FR/FW/FRW (ICH6)
   * Intel 82801G (ICH7)
index 7cbe43fa2701dfb875a7eae69754ecb557e5c043..fa0c786a8bf5a787e6a980dd9dbeef9c283d7b41 100644 (file)
@@ -6,7 +6,7 @@ Supported adapters:
     Datasheet: Publicly available at the Intel website
   * ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges
     Datasheet: Only available via NDA from ServerWorks
-  * ATI IXP200, IXP300, IXP400 and SB600 southbridges
+  * ATI IXP200, IXP300, IXP400, SB600 and SB700 southbridges
     Datasheet: Not publicly available
   * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
     Datasheet: Publicly available at the SMSC website http://www.smsc.com
diff --git a/Documentation/i2c/busses/i2c-taos-evm b/Documentation/i2c/busses/i2c-taos-evm
new file mode 100644 (file)
index 0000000..9146e33
--- /dev/null
@@ -0,0 +1,46 @@
+Kernel driver i2c-taos-evm
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+This is a driver for the evaluation modules for TAOS I2C/SMBus chips.
+The modules include an SMBus master with limited capabilities, which can
+be controlled over the serial port. Virtually all evaluation modules
+are supported, but a few lines of code need to be added for each new
+module to instantiate the right I2C chip on the bus. Obviously, a driver
+for the chip in question is also needed.
+
+Currently supported devices are:
+
+* TAOS TSL2550 EVM
+
+For addtional information on TAOS products, please see
+  http://www.taosinc.com/
+
+
+Using this driver
+-----------------
+
+In order to use this driver, you'll need the serport driver, and the
+inputattach tool, which is part of the input-utils package. The following
+commands will tell the kernel that you have a TAOS EVM on the first
+serial port:
+
+# modprobe serport
+# inputattach --taos-evm /dev/ttyS0
+
+
+Technical details
+-----------------
+
+Only 4 SMBus transaction types are supported by the TAOS evaluation
+modules:
+* Receive Byte
+* Send Byte
+* Read Byte
+* Write Byte
+
+The communication protocol is text-based and pretty simple. It is
+described in a PDF document on the CD which comes with the evaluation
+module. The communication is rather slow, because the serial port has
+to operate at 1200 bps. However, I don't think this is a big concern in
+practice, as these modules are meant for evaluation and testing only.
index 96fec562a8e9020fc92a5d8c1de5676bda953cf8..a0cd8af2f40806a53ac2dc1841be8530d4e59992 100644 (file)
@@ -99,7 +99,7 @@ And then read the data
 
   or
 
-  count = i2c_smbus_read_i2c_block_data(fd, 0x84, buffer);
+  count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer);
 
 The block read should read 16 bytes.
 0x84 is the block read command.
diff --git a/Documentation/i2c/chips/x1205 b/Documentation/i2c/chips/x1205
deleted file mode 100644 (file)
index 09407c9..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-Kernel driver x1205
-===================
-
-Supported chips:
-  * Xicor X1205 RTC
-    Prefix: 'x1205'
-    Addresses scanned: none
-    Datasheet: http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
-
-Authors:
-       Karen Spearel <kas11@tampabay.rr.com>,
-       Alessandro Zummo <a.zummo@towertech.it>
-
-Description
------------
-
-This module aims to provide complete access to the Xicor X1205 RTC.
-Recently Xicor has merged with Intersil, but the chip is
-still sold under the Xicor brand.
-
-This chip is located at address 0x6f and uses a 2-byte register addressing.
-Two bytes need to be written to read a single register, while most
-other chips just require one and take the second one as the data
-to be written. To prevent corrupting unknown chips, the user must
-explicitely set the probe parameter.
-
-example:
-
-modprobe x1205 probe=0,0x6f
-
-The module supports one more option, hctosys, which is used to set the
-software clock from the x1205. On systems where the x1205 is the
-only hardware rtc, this parameter could be used to achieve a correct
-date/time earlier in the system boot sequence.
-
-example:
-
-modprobe x1205 probe=0,0x6f hctosys=1
index aea60bf7e8f0847370e17beec79880307754a5d5..003c7319b8c7a6dbae0881ae513474eea86f727b 100644 (file)
@@ -67,7 +67,6 @@ i2c-proc: The /proc/sys/dev/sensors interface for device (client) drivers
 Algorithm drivers
 -----------------
 
-i2c-algo-8xx:    An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT)
 i2c-algo-bit:    A bit-banging algorithm
 i2c-algo-pcf:    A PCF 8584 style algorithm
 i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT)
@@ -81,6 +80,5 @@ i2c-pcf-epp:     PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatch
 i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit)
 i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT)
 i2c-pport:       Primitive parallel port adapter (uses i2c-algo-bit)
-i2c-rpx:         RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT)
 i2c-velleman:    Velleman K8000 parallel port adapter (uses i2c-algo-bit)
 
index 3d8d36b0ad1262f0a8b4c0fc2fbce21faf07d318..2c170032bf37432790be70fe2e362ba4146c42b1 100644 (file)
@@ -571,7 +571,7 @@ SMBus communication
                                         u8 command, u8 length,
                                         u8 *values);
   extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
-                                           u8 command, u8 *values);
+                                           u8 command, u8 length, u8 *values);
 
 These ones were removed in Linux 2.6.10 because they had no users, but could
 be added back later if needed:
index c04a421f4a7c70290aaf6d6f4eb54af701fd2ae6..75b3680c41eb835e751a242191f2439914166152 100644 (file)
@@ -37,6 +37,7 @@ Offset        Type            Description
 0x1d0  unsigned long   EFI memory descriptor map pointer
 0x1d4  unsigned long   EFI memory descriptor map size
 0x1e0  unsigned long   ALT_MEM_K, alternative mem check, in Kb
+0x1e4  unsigned long   Scratch field for the kernel setup code
 0x1e8  char            number of entries in E820MAP (below)
 0x1e9  unsigned char   number of entries in EDDBUF (below)
 0x1ea  unsigned char   number of entries in EDD_MBR_SIG_BUFFER (below)
index 151f4ef978a4aa5ae82c976e76c8716cafa9f4fb..3db68bf1d2134a9f4c870d3de1f9ff1b69c6e6ba 100644 (file)
@@ -1750,8 +1750,8 @@ T:        http://www.harbaum.org/till/i2c_tiny_usb
 S:     Maintained
 
 i386 BOOT CODE
-P:     Riley H. Williams
-M:     Riley@Williams.Name
+P:     H. Peter Anvin
+M:     hpa@zytor.com
 L:     Linux-Kernel@vger.kernel.org
 S:     Maintained
 
index 5c95ceb7f1225515ab3ad200a8f1e7a278a2ee18..9cbe76c3aa359763c6650aa4a57d97c16ee5d4e4 100644 (file)
@@ -344,8 +344,8 @@ config X86_CMOV
        depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7)
        default y
 
-config X86_MINIMUM_CPU_MODEL
+config X86_MINIMUM_CPU_FAMILY
        int
-       default "4" if X86_XADD || X86_CMPXCHG || X86_BSWAP
-       default "0"
+       default "4" if X86_XADD || X86_CMPXCHG || X86_BSWAP || X86_WP_WORKS_OK
+       default "3"
 
index bfbc32098a4a8ed33237915b9991e96ac001bd75..08678a0a3d191a8a197763bc35202d0c79765b33 100644 (file)
@@ -25,27 +25,56 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
 
 #RAMDISK := -DRAMDISK=512
 
-targets                := vmlinux.bin bootsect bootsect.o \
-                  setup setup.o zImage bzImage
+targets                := vmlinux.bin setup.bin setup.elf zImage bzImage
 subdir-        := compressed
 
+setup-y                += a20.o apm.o cmdline.o copy.o cpu.o cpucheck.o edd.o
+setup-y                += header.o main.o mca.o memory.o pm.o pmjump.o
+setup-y                += printf.o string.o tty.o video.o version.o voyager.o
+
+# The link order of the video-*.o modules can matter.  In particular,
+# video-vga.o *must* be listed first, followed by video-vesa.o.
+# Hardware-specific drivers should follow in the order they should be
+# probed, and video-bios.o should typically be last.
+setup-y                += video-vga.o
+setup-y                += video-vesa.o
+setup-y                += video-bios.o
+
 hostprogs-y    := tools/build
 
 HOSTCFLAGS_build.o := $(LINUXINCLUDE)
 
 # ---------------------------------------------------------------------------
 
+# How to compile the 16-bit code.  Note we always compile for -march=i386,
+# that way we can complain to the user if the CPU is insufficient.
+cflags-i386   := 
+cflags-x86_64 := -m32
+CFLAGS         := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \
+                  $(cflags-$(ARCH)) \
+                  -Wall -Wstrict-prototypes \
+                  -march=i386 -mregparm=3 \
+                  -include $(srctree)/$(src)/code16gcc.h \
+                  -fno-strict-aliasing -fomit-frame-pointer \
+                  $(call cc-option, -ffreestanding) \
+                  $(call cc-option, -fno-toplevel-reorder,\
+                       $(call cc-option, -fno-unit-at-a-time)) \
+                  $(call cc-option, -fno-stack-protector) \
+                  $(call cc-option, -mpreferred-stack-boundary=2)
+AFLAGS         := $(CFLAGS) -D__ASSEMBLY__
+
 $(obj)/zImage:  IMAGE_OFFSET := 0x1000
 $(obj)/zImage:  EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK)
 $(obj)/bzImage: IMAGE_OFFSET := 0x100000
+$(obj)/bzImage: EXTRA_CFLAGS := -D__BIG_KERNEL__
 $(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
 $(obj)/bzImage: BUILDFLAGS   := -b
 
 quiet_cmd_image = BUILD   $@
-cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
+cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/setup.bin \
            $(obj)/vmlinux.bin $(ROOT_DEV) > $@
 
-$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
+$(obj)/zImage $(obj)/bzImage: $(obj)/setup.bin \
                              $(obj)/vmlinux.bin $(obj)/tools/build FORCE
        $(call if_changed,image)
        @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
@@ -53,12 +82,17 @@ $(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
 $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
        $(call if_changed,objcopy)
 
-LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
-LDFLAGS_setup   := -Ttext 0x0 -s --oformat binary -e begtext
+SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
 
-$(obj)/setup $(obj)/bootsect: %: %.o FORCE
+LDFLAGS_setup.elf      := -T
+$(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
        $(call if_changed,ld)
 
+OBJCOPYFLAGS_setup.bin := -O binary
+
+$(obj)/setup.bin: $(obj)/setup.elf FORCE
+       $(call if_changed,objcopy)
+
 $(obj)/compressed/vmlinux: FORCE
        $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
 
diff --git a/arch/i386/boot/a20.c b/arch/i386/boot/a20.c
new file mode 100644 (file)
index 0000000..31348d0
--- /dev/null
@@ -0,0 +1,161 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/a20.c
+ *
+ * Enable A20 gate (return -1 on failure)
+ */
+
+#include "boot.h"
+
+#define MAX_8042_LOOPS 100000
+
+static int empty_8042(void)
+{
+       u8 status;
+       int loops = MAX_8042_LOOPS;
+
+       while (loops--) {
+               io_delay();
+
+               status = inb(0x64);
+               if (status & 1) {
+                       /* Read and discard input data */
+                       io_delay();
+                       (void)inb(0x60);
+               } else if (!(status & 2)) {
+                       /* Buffers empty, finished! */
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+/* Returns nonzero if the A20 line is enabled.  The memory address
+   used as a test is the int $0x80 vector, which should be safe. */
+
+#define A20_TEST_ADDR  (4*0x80)
+#define A20_TEST_SHORT  32
+#define A20_TEST_LONG  2097152 /* 2^21 */
+
+static int a20_test(int loops)
+{
+       int ok = 0;
+       int saved, ctr;
+
+       set_fs(0x0000);
+       set_gs(0xffff);
+
+       saved = ctr = rdfs32(A20_TEST_ADDR);
+
+       while (loops--) {
+               wrfs32(++ctr, A20_TEST_ADDR);
+               io_delay();     /* Serialize and make delay constant */
+               ok = rdgs32(A20_TEST_ADDR+0x10) ^ ctr;
+               if (ok)
+                       break;
+       }
+
+       wrfs32(saved, A20_TEST_ADDR);
+       return ok;
+}
+
+/* Quick test to see if A20 is already enabled */
+static int a20_test_short(void)
+{
+       return a20_test(A20_TEST_SHORT);
+}
+
+/* Longer test that actually waits for A20 to come on line; this
+   is useful when dealing with the KBC or other slow external circuitry. */
+static int a20_test_long(void)
+{
+       return a20_test(A20_TEST_LONG);
+}
+
+static void enable_a20_bios(void)
+{
+       asm volatile("pushfl; int $0x15; popfl"
+                    : : "a" ((u16)0x2401));
+}
+
+static void enable_a20_kbc(void)
+{
+       empty_8042();
+
+       outb(0xd1, 0x64);       /* Command write */
+       empty_8042();
+
+       outb(0xdf, 0x60);       /* A20 on */
+       empty_8042();
+}
+
+static void enable_a20_fast(void)
+{
+       u8 port_a;
+
+       port_a = inb(0x92);     /* Configuration port A */
+       port_a |=  0x02;        /* Enable A20 */
+       port_a &= ~0x01;        /* Do not reset machine */
+       outb(port_a, 0x92);
+}
+
+/*
+ * Actual routine to enable A20; return 0 on ok, -1 on failure
+ */
+
+#define A20_ENABLE_LOOPS 255   /* Number of times to try */
+
+int enable_a20(void)
+{
+       int loops = A20_ENABLE_LOOPS;
+
+#if defined(CONFIG_X86_ELAN)
+       /* Elan croaks if we try to touch the KBC */
+       enable_a20_fast();
+       while (!a20_test_long())
+               ;
+       return 0;
+#elif defined(CONFIG_X86_VOYAGER)
+       /* On Voyager, a20_test() is unsafe? */
+       enable_a20_kbc();
+       return 0;
+#else
+       while (loops--) {
+               /* First, check to see if A20 is already enabled
+                  (legacy free, etc.) */
+               if (a20_test_short())
+                       return 0;
+
+               /* Next, try the BIOS (INT 0x15, AX=0x2401) */
+               enable_a20_bios();
+               if (a20_test_short())
+                       return 0;
+
+               /* Try enabling A20 through the keyboard controller */
+               empty_8042();
+               if (a20_test_short())
+                       return 0; /* BIOS worked, but with delayed reaction */
+
+               enable_a20_kbc();
+               if (a20_test_long())
+                       return 0;
+
+               /* Finally, try enabling the "fast A20 gate" */
+               enable_a20_fast();
+               if (a20_test_long())
+                       return 0;
+       }
+
+       return -1;
+#endif
+}
diff --git a/arch/i386/boot/apm.c b/arch/i386/boot/apm.c
new file mode 100644 (file)
index 0000000..a34087c
--- /dev/null
@@ -0,0 +1,97 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   Original APM BIOS checking by Stephen Rothwell, May 1994
+ *   (sfr@canb.auug.org.au)
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/apm.c
+ *
+ * Get APM BIOS information
+ */
+
+#include "boot.h"
+
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
+
+int query_apm_bios(void)
+{
+       u16 ax, bx, cx, dx, di;
+       u32 ebx, esi;
+       u8 err;
+
+       /* APM BIOS installation check */
+       ax = 0x5300;
+       bx = cx = 0;
+       asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
+                    : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
+                    : : "esi", "edi");
+
+       if (err)
+               return -1;              /* No APM BIOS */
+
+       if (bx != 0x504d)       /* "PM" signature */
+               return -1;
+
+       if (cx & 0x02)          /* 32 bits supported? */
+               return -1;
+
+       /* Disconnect first, just in case */
+       ax = 0x5304;
+       asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
+                    : "+a" (ax)
+                    : : "ebx", "ecx", "edx", "esi", "edi");
+
+       /* Paranoia */
+       ebx = esi = 0;
+       cx = dx = di = 0;
+
+       /* 32-bit connect */
+       asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6"
+                    : "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx),
+                      "+S" (esi), "+D" (di), "=m" (err)
+                    : "a" (0x5303));
+
+       boot_params.apm_bios_info.cseg = ax;
+       boot_params.apm_bios_info.offset = ebx;
+       boot_params.apm_bios_info.cseg_16 = cx;
+       boot_params.apm_bios_info.dseg = dx;
+       boot_params.apm_bios_info.cseg_len = (u16)esi;
+       boot_params.apm_bios_info.cseg_16_len = esi >> 16;
+       boot_params.apm_bios_info.dseg_len = di;
+
+       if (err)
+               return -1;
+
+       /* Redo the installation check as the 32-bit connect;
+          some BIOSes return different flags this way... */
+
+       ax = 0x5300;
+       bx = cx = 0;
+       asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
+                    : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
+                    : : "esi", "edi");
+
+       if (err || bx != 0x504d) {
+               /* Failure with 32-bit connect, try to disconect and ignore */
+               ax = 0x5304;
+               bx = 0;
+               asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
+                            : "+a" (ax), "+b" (bx)
+                            : : "ecx", "edx", "esi", "edi");
+               return -1;
+       }
+
+       boot_params.apm_bios_info.version = ax;
+       boot_params.apm_bios_info.flags = cx;
+       return 0;
+}
+
+#endif
diff --git a/arch/i386/boot/bitops.h b/arch/i386/boot/bitops.h
new file mode 100644 (file)
index 0000000..8dcc8dc
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/bitops.h
+ *
+ * Very simple bitops for the boot code.
+ */
+
+#ifndef BOOT_BITOPS_H
+#define BOOT_BITOPS_H
+#define _LINUX_BITOPS_H                /* Inhibit inclusion of <linux/bitops.h> */
+
+static inline int constant_test_bit(int nr, const void *addr)
+{
+       const u32 *p = (const u32 *)addr;
+       return ((1UL << (nr & 31)) & (p[nr >> 5])) != 0;
+}
+static inline int variable_test_bit(int nr, const void *addr)
+{
+       u8 v;
+       const u32 *p = (const u32 *)addr;
+
+       asm("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr));
+       return v;
+}
+
+#define test_bit(nr,addr) \
+(__builtin_constant_p(nr) ? \
+ constant_test_bit((nr),(addr)) : \
+ variable_test_bit((nr),(addr)))
+
+static inline void set_bit(int nr, void *addr)
+{
+       asm("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr));
+}
+
+#endif /* BOOT_BITOPS_H */
diff --git a/arch/i386/boot/boot.h b/arch/i386/boot/boot.h
new file mode 100644 (file)
index 0000000..0329c4f
--- /dev/null
@@ -0,0 +1,296 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/boot.h
+ *
+ * Header file for the real-mode kernel code
+ */
+
+#ifndef BOOT_BOOT_H
+#define BOOT_BOOT_H
+
+#ifndef __ASSEMBLY__
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/edd.h>
+#include <asm/boot.h>
+#include <asm/bootparam.h>
+
+/* Useful macros */
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+
+extern struct setup_header hdr;
+extern struct boot_params boot_params;
+
+/* Basic port I/O */
+static inline void outb(u8 v, u16 port)
+{
+       asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
+}
+static inline u8 inb(u16 port)
+{
+       u8 v;
+       asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
+       return v;
+}
+
+static inline void outw(u16 v, u16 port)
+{
+       asm volatile("outw %0,%1" : : "a" (v), "dN" (port));
+}
+static inline u16 inw(u16 port)
+{
+       u16 v;
+       asm volatile("inw %1,%0" : "=a" (v) : "dN" (port));
+       return v;
+}
+
+static inline void outl(u32 v, u16 port)
+{
+       asm volatile("outl %0,%1" : : "a" (v), "dn" (port));
+}
+static inline u32 inl(u32 port)
+{
+       u32 v;
+       asm volatile("inl %1,%0" : "=a" (v) : "dN" (port));
+       return v;
+}
+
+static inline void io_delay(void)
+{
+       const u16 DELAY_PORT = 0x80;
+       asm volatile("outb %%al,%0" : : "dN" (DELAY_PORT));
+}
+
+/* These functions are used to reference data in other segments. */
+
+static inline u16 ds(void)
+{
+       u16 seg;
+       asm("movw %%ds,%0" : "=rm" (seg));
+       return seg;
+}
+
+static inline void set_fs(u16 seg)
+{
+       asm volatile("movw %0,%%fs" : : "rm" (seg));
+}
+static inline u16 fs(void)
+{
+       u16 seg;
+       asm("movw %%fs,%0" : "=rm" (seg));
+       return seg;
+}
+
+static inline void set_gs(u16 seg)
+{
+       asm volatile("movw %0,%%gs" : : "rm" (seg));
+}
+static inline u16 gs(void)
+{
+       u16 seg;
+       asm("movw %%gs,%0" : "=rm" (seg));
+       return seg;
+}
+
+typedef unsigned int addr_t;
+
+static inline u8 rdfs8(addr_t addr)
+{
+       u8 v;
+       asm("movb %%fs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr));
+       return v;
+}
+static inline u16 rdfs16(addr_t addr)
+{
+       u16 v;
+       asm("movw %%fs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
+       return v;
+}
+static inline u32 rdfs32(addr_t addr)
+{
+       u32 v;
+       asm("movl %%fs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
+       return v;
+}
+
+static inline void wrfs8(u8 v, addr_t addr)
+{
+       asm volatile("movb %1,%%fs:%0" : "+m" (*(u8 *)addr) : "r" (v));
+}
+static inline void wrfs16(u16 v, addr_t addr)
+{
+       asm volatile("movw %1,%%fs:%0" : "+m" (*(u16 *)addr) : "r" (v));
+}
+static inline void wrfs32(u32 v, addr_t addr)
+{
+       asm volatile("movl %1,%%fs:%0" : "+m" (*(u32 *)addr) : "r" (v));
+}
+
+static inline u8 rdgs8(addr_t addr)
+{
+       u8 v;
+       asm("movb %%gs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr));
+       return v;
+}
+static inline u16 rdgs16(addr_t addr)
+{
+       u16 v;
+       asm("movw %%gs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
+       return v;
+}
+static inline u32 rdgs32(addr_t addr)
+{
+       u32 v;
+       asm("movl %%gs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
+       return v;
+}
+
+static inline void wrgs8(u8 v, addr_t addr)
+{
+       asm volatile("movb %1,%%gs:%0" : "+m" (*(u8 *)addr) : "r" (v));
+}
+static inline void wrgs16(u16 v, addr_t addr)
+{
+       asm volatile("movw %1,%%gs:%0" : "+m" (*(u16 *)addr) : "r" (v));
+}
+static inline void wrgs32(u32 v, addr_t addr)
+{
+       asm volatile("movl %1,%%gs:%0" : "+m" (*(u32 *)addr) : "r" (v));
+}
+
+/* Note: these only return true/false, not a signed return value! */
+static inline int memcmp(const void *s1, const void *s2, size_t len)
+{
+       u8 diff;
+       asm("repe; cmpsb; setnz %0"
+           : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+       return diff;
+}
+
+static inline int memcmp_fs(const void *s1, addr_t s2, size_t len)
+{
+       u8 diff;
+       asm("fs; repe; cmpsb; setnz %0"
+           : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+       return diff;
+}
+static inline int memcmp_gs(const void *s1, addr_t s2, size_t len)
+{
+       u8 diff;
+       asm("gs; repe; cmpsb; setnz %0"
+           : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+       return diff;
+}
+
+static inline int isdigit(int ch)
+{
+       return (ch >= '0') && (ch <= '9');
+}
+
+/* Heap -- available for dynamic lists. */
+#define STACK_SIZE     512     /* Minimum number of bytes for stack */
+
+extern char _end[];
+extern char *HEAP;
+extern char *heap_end;
+#define RESET_HEAP() ((void *)( HEAP = _end ))
+static inline char *__get_heap(size_t s, size_t a, size_t n)
+{
+       char *tmp;
+
+       HEAP = (char *)(((size_t)HEAP+(a-1)) & ~(a-1));
+       tmp = HEAP;
+       HEAP += s*n;
+       return tmp;
+}
+#define GET_HEAP(type, n) \
+       ((type *)__get_heap(sizeof(type),__alignof__(type),(n)))
+
+static inline int heap_free(void)
+{
+       return heap_end-HEAP;
+}
+
+/* copy.S */
+
+void copy_to_fs(addr_t dst, void *src, size_t len);
+void *copy_from_fs(void *dst, addr_t src, size_t len);
+void copy_to_gs(addr_t dst, void *src, size_t len);
+void *copy_from_gs(void *dst, addr_t src, size_t len);
+void *memcpy(void *dst, void *src, size_t len);
+void *memset(void *dst, int c, size_t len);
+
+#define memcpy(d,s,l) __builtin_memcpy(d,s,l)
+#define memset(d,c,l) __builtin_memset(d,c,l)
+
+/* a20.c */
+int enable_a20(void);
+
+/* apm.c */
+int query_apm_bios(void);
+
+/* cmdline.c */
+int cmdline_find_option(const char *option, char *buffer, int bufsize);
+
+/* cpu.c, cpucheck.c */
+int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr);
+int validate_cpu(void);
+
+/* edd.c */
+void query_edd(void);
+
+/* header.S */
+void __attribute__((noreturn)) die(void);
+
+/* mca.c */
+int query_mca(void);
+
+/* memory.c */
+int detect_memory(void);
+
+/* pm.c */
+void __attribute__((noreturn)) go_to_protected_mode(void);
+
+/* pmjump.S */
+void __attribute__((noreturn))
+       protected_mode_jump(u32 entrypoint, u32 bootparams);
+
+/* printf.c */
+int sprintf(char *buf, const char *fmt, ...);
+int vsprintf(char *buf, const char *fmt, va_list args);
+int printf(const char *fmt, ...);
+
+/* string.c */
+int strcmp(const char *str1, const char *str2);
+size_t strnlen(const char *s, size_t maxlen);
+unsigned int atou(const char *s);
+
+/* tty.c */
+void puts(const char *);
+void putchar(int);
+int getchar(void);
+void kbd_flush(void);
+int getchar_timeout(void);
+
+/* video.c */
+void set_video(void);
+
+/* video-vesa.c */
+void vesa_store_edid(void);
+
+/* voyager.c */
+int query_voyager(void);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* BOOT_BOOT_H */
diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S
deleted file mode 100644 (file)
index 011b7a4..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- *     bootsect.S              Copyright (C) 1991, 1992 Linus Torvalds
- *
- *     modified by Drew Eckhardt
- *     modified by Bruce Evans (bde)
- *     modified by Chris Noe (May 1999) (as86 -> gas)
- *     gutted by H. Peter Anvin (Jan 2003)
- *
- * BIG FAT NOTE: We're in real mode using 64k segments.  Therefore segment
- * addresses must be multiplied by 16 to obtain their respective linear
- * addresses. To avoid confusion, linear addresses are written using leading
- * hex while segment addresses are written as segment:offset.
- *
- */
-
-#include <asm/boot.h>
-
-SETUPSECTS     = 4                     /* default nr of setup-sectors */
-BOOTSEG                = 0x07C0                /* original address of boot-sector */
-INITSEG                = DEF_INITSEG           /* we move boot here - out of the way */
-SETUPSEG       = DEF_SETUPSEG          /* setup starts here */
-SYSSEG         = DEF_SYSSEG            /* system loaded at 0x10000 (65536) */
-SYSSIZE                = DEF_SYSSIZE           /* system size: # of 16-byte clicks */
-                                       /* to be loaded */
-ROOT_DEV       = 0                     /* ROOT_DEV is now written by "build" */
-SWAP_DEV       = 0                     /* SWAP_DEV is now written by "build" */
-
-#ifndef SVGA_MODE
-#define SVGA_MODE ASK_VGA
-#endif
-
-#ifndef RAMDISK
-#define RAMDISK 0
-#endif
-
-#ifndef ROOT_RDONLY
-#define ROOT_RDONLY 1
-#endif
-
-.code16
-.text
-
-.global _start
-_start:
-
-       # Normalize the start address
-       jmpl    $BOOTSEG, $start2
-
-start2:
-       movw    %cs, %ax
-       movw    %ax, %ds
-       movw    %ax, %es
-       movw    %ax, %ss
-       movw    $0x7c00, %sp
-       sti
-       cld
-
-       movw    $bugger_off_msg, %si
-
-msg_loop:
-       lodsb
-       andb    %al, %al
-       jz      die
-       movb    $0xe, %ah
-       movw    $7, %bx
-       int     $0x10
-       jmp     msg_loop
-
-die:
-       # Allow the user to press a key, then reboot
-       xorw    %ax, %ax
-       int     $0x16
-       int     $0x19
-
-       # int 0x19 should never return.  In case it does anyway,
-       # invoke the BIOS reset code...
-       ljmp    $0xf000,$0xfff0
-
-
-bugger_off_msg:
-       .ascii  "Direct booting from floppy is no longer supported.\r\n"
-       .ascii  "Please use a boot loader program instead.\r\n"
-       .ascii  "\n"
-       .ascii  "Remove disk and press any key to reboot . . .\r\n"
-       .byte   0
-
-
-       # Kernel attributes; used by setup
-
-       .org 497
-setup_sects:   .byte SETUPSECTS
-root_flags:    .word ROOT_RDONLY
-syssize:       .word SYSSIZE
-swap_dev:      .word SWAP_DEV
-ram_size:      .word RAMDISK
-vid_mode:      .word SVGA_MODE
-root_dev:      .word ROOT_DEV
-boot_flag:     .word 0xAA55
diff --git a/arch/i386/boot/cmdline.c b/arch/i386/boot/cmdline.c
new file mode 100644 (file)
index 0000000..34bb778
--- /dev/null
@@ -0,0 +1,97 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/cmdline.c
+ *
+ * Simple command-line parser for early boot.
+ */
+
+#include "boot.h"
+
+static inline int myisspace(u8 c)
+{
+       return c <= ' ';        /* Close enough approximation */
+}
+
+/*
+ * Find a non-boolean option, that is, "option=argument".  In accordance
+ * with standard Linux practice, if this option is repeated, this returns
+ * the last instance on the command line.
+ *
+ * Returns the length of the argument (regardless of if it was
+ * truncated to fit in the buffer), or -1 on not found.
+ */
+int cmdline_find_option(const char *option, char *buffer, int bufsize)
+{
+       u32 cmdline_ptr = boot_params.hdr.cmd_line_ptr;
+       addr_t cptr;
+       char c;
+       int len = -1;
+       const char *opptr = NULL;
+       char *bufptr = buffer;
+       enum {
+               st_wordstart,   /* Start of word/after whitespace */
+               st_wordcmp,     /* Comparing this word */
+               st_wordskip,    /* Miscompare, skip */
+               st_bufcpy       /* Copying this to buffer */
+       } state = st_wordstart;
+
+       if (!cmdline_ptr || cmdline_ptr >= 0x100000)
+               return -1;      /* No command line, or inaccessible */
+
+       cptr = cmdline_ptr & 0xf;
+       set_fs(cmdline_ptr >> 4);
+
+       while (cptr < 0x10000 && (c = rdfs8(cptr++))) {
+               switch (state) {
+               case st_wordstart:
+                       if (myisspace(c))
+                               break;
+
+                       /* else */
+                       state = st_wordcmp;
+                       opptr = option;
+                       /* fall through */
+
+               case st_wordcmp:
+                       if (c == '=' && !*opptr) {
+                               len = 0;
+                               bufptr = buffer;
+                               state = st_bufcpy;
+                       } else if (myisspace(c)) {
+                               state = st_wordstart;
+                       } else if (c != *opptr++) {
+                               state = st_wordskip;
+                       }
+                       break;
+
+               case st_wordskip:
+                       if (myisspace(c))
+                               state = st_wordstart;
+                       break;
+
+               case st_bufcpy:
+                       if (myisspace(c)) {
+                               state = st_wordstart;
+                       } else {
+                               if (len < bufsize-1)
+                                       *bufptr++ = c;
+                               len++;
+                       }
+                       break;
+               }
+       }
+
+       if (bufsize)
+               *bufptr = '\0';
+
+       return len;
+}
diff --git a/arch/i386/boot/code16gcc.h b/arch/i386/boot/code16gcc.h
new file mode 100644 (file)
index 0000000..3bd8480
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * code16gcc.h
+ *
+ * This file is -include'd when compiling 16-bit C code.
+ * Note: this asm() needs to be emitted before gcc omits any code.
+ * Depending on gcc version, this requires -fno-unit-at-a-time or
+ * -fno-toplevel-reorder.
+ *
+ * Hopefully gcc will eventually have a real -m16 option so we can
+ * drop this hack long term.
+ */
+
+#ifndef __ASSEMBLY__
+asm(".code16gcc");
+#endif
index a661217f33ec4eeba811cb9d987f626f5f7c3838..189fa1dbefcc27ece79bac59fc2d11b83d09e38f 100644 (file)
@@ -9,9 +9,14 @@ targets                := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o \
 EXTRA_AFLAGS   := -traditional
 
 LDFLAGS_vmlinux := -T
-CFLAGS_misc.o += -fPIC
 hostprogs-y    := relocs
 
+CFLAGS  := -m32 -D__KERNEL__ $(LINUX_INCLUDE) -O2 \
+          -fno-strict-aliasing -fPIC \
+          $(call cc-option,-ffreestanding) \
+          $(call cc-option,-fno-stack-protector)
+LDFLAGS := -m elf_i386
+
 $(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
        $(call if_changed,ld)
        @:
index 3517a32aaf4152a67098f70dc43e1f43f16d5851..f35ea2237522c0267139af7666e2875b571dd4b4 100644 (file)
@@ -45,10 +45,10 @@ startup_32:
  * at and where we were actually loaded at.  This can only be done
  * with a short local call on x86.  Nothing  else will tell us what
  * address we are running at.  The reserved chunk of the real-mode
- * data at 0x34-0x3f are used as the stack for this calculation.
- * Only 4 bytes are needed.
+ * data at 0x1e4 (defined as a scratch field) are used as the stack
+ * for this calculation. Only 4 bytes are needed.
  */
-       leal 0x40(%esi), %esp
+       leal (0x1e4+4)(%esi), %esp
        call 1f
 1:     popl %ebp
        subl $1b, %ebp
diff --git a/arch/i386/boot/copy.S b/arch/i386/boot/copy.S
new file mode 100644 (file)
index 0000000..ef127e5
--- /dev/null
@@ -0,0 +1,101 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/copy.S
+ *
+ * Memory copy routines
+ */
+
+       .code16gcc
+       .text
+
+       .globl  memcpy
+       .type   memcpy, @function
+memcpy:
+       pushw   %si
+       pushw   %di
+       movw    %ax, %di
+       movw    %dx, %si
+       pushw   %cx
+       shrw    $2, %cx
+       rep; movsl
+       popw    %cx
+       andw    $3, %cx
+       rep; movsb
+       popw    %di
+       popw    %si
+       ret
+       .size   memcpy, .-memcpy
+
+       .globl  memset
+       .type   memset, @function
+memset:
+       pushw   %di
+       movw    %ax, %di
+       movzbl  %dl, %eax
+       imull   $0x01010101,%eax
+       pushw   %cx
+       shrw    $2, %cx
+       rep; stosl
+       popw    %cx
+       andw    $3, %cx
+       rep; stosb
+       popw    %di
+       ret
+       .size   memset, .-memset
+
+       .globl  copy_from_fs
+       .type   copy_from_fs, @function
+copy_from_fs:
+       pushw   %ds
+       pushw   %fs
+       popw    %ds
+       call    memcpy
+       popw    %ds
+       ret
+       .size   copy_from_fs, .-copy_from_fs
+
+       .globl  copy_to_fs
+       .type   copy_to_fs, @function
+copy_to_fs:
+       pushw   %es
+       pushw   %fs
+       popw    %es
+       call    memcpy
+       popw    %es
+       ret
+       .size   copy_to_fs, .-copy_to_fs
+
+#if 0 /* Not currently used, but can be enabled as needed */
+
+       .globl  copy_from_gs
+       .type   copy_from_gs, @function
+copy_from_gs:
+       pushw   %ds
+       pushw   %gs
+       popw    %ds
+       call    memcpy
+       popw    %ds
+       ret
+       .size   copy_from_gs, .-copy_from_gs
+       .globl  copy_to_gs
+
+       .type   copy_to_gs, @function
+copy_to_gs:
+       pushw   %es
+       pushw   %gs
+       popw    %es
+       call    memcpy
+       popw    %es
+       ret
+       .size   copy_to_gs, .-copy_to_gs
+
+#endif
diff --git a/arch/i386/boot/cpu.c b/arch/i386/boot/cpu.c
new file mode 100644 (file)
index 0000000..2a5c32d
--- /dev/null
@@ -0,0 +1,69 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/cpu.c
+ *
+ * Check for obligatory CPU features and abort if the features are not
+ * present.
+ */
+
+#include "boot.h"
+#include "bitops.h"
+#include <asm/cpufeature.h>
+
+static char *cpu_name(int level)
+{
+       static char buf[6];
+
+       if (level == 64) {
+               return "x86-64";
+       } else {
+               sprintf(buf, "i%d86", level);
+               return buf;
+       }
+}
+
+int validate_cpu(void)
+{
+       u32 *err_flags;
+       int cpu_level, req_level;
+
+       check_cpu(&cpu_level, &req_level, &err_flags);
+
+       if (cpu_level < req_level) {
+               printf("This kernel requires an %s CPU, ",
+                      cpu_name(req_level));
+               printf("but only detected an %s CPU.\n",
+                      cpu_name(cpu_level));
+               return -1;
+       }
+
+       if (err_flags) {
+               int i, j;
+               puts("This kernel requires the following features "
+                    "not present on the CPU:\n");
+
+               for (i = 0; i < NCAPINTS; i++) {
+                       u32 e = err_flags[i];
+
+                       for (j = 0; j < 32; j++) {
+                               if (e & 1)
+                                       printf("%d:%d ", i, j);
+
+                               e >>= 1;
+                       }
+               }
+               putchar('\n');
+               return -1;
+       } else {
+               return 0;
+       }
+}
diff --git a/arch/i386/boot/cpucheck.c b/arch/i386/boot/cpucheck.c
new file mode 100644 (file)
index 0000000..8b0f447
--- /dev/null
@@ -0,0 +1,267 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/cpucheck.c
+ *
+ * Check for obligatory CPU features and abort if the features are not
+ * present.  This code should be compilable as 16-, 32- or 64-bit
+ * code, so be very careful with types and inline assembly.
+ *
+ * This code should not contain any messages; that requires an
+ * additional wrapper.
+ *
+ * As written, this code is not safe for inclusion into the kernel
+ * proper (after FPU initialization, in particular).
+ */
+
+#ifdef _SETUP
+# include "boot.h"
+# include "bitops.h"
+#endif
+#include <linux/types.h>
+#include <asm/cpufeature.h>
+#include <asm/processor-flags.h>
+#include <asm/required-features.h>
+#include <asm/msr-index.h>
+
+struct cpu_features {
+       int level;              /* Family, or 64 for x86-64 */
+       int model;
+       u32 flags[NCAPINTS];
+};
+
+static struct cpu_features cpu;
+static u32 cpu_vendor[3];
+static u32 err_flags[NCAPINTS];
+
+#ifdef CONFIG_X86_64
+static const int req_level = 64;
+#elif defined(CONFIG_X86_MINIMUM_CPU_FAMILY)
+static const int req_level = CONFIG_X86_MINIMUM_CPU_FAMILY;
+#else
+static const int req_level = 3;
+#endif
+
+static const u32 req_flags[NCAPINTS] =
+{
+       REQUIRED_MASK0,
+       REQUIRED_MASK1,
+       REQUIRED_MASK2,
+       REQUIRED_MASK3,
+       REQUIRED_MASK4,
+       REQUIRED_MASK5,
+       REQUIRED_MASK6,
+       REQUIRED_MASK7,
+};
+
+#define A32(a,b,c,d) (((d) << 24)+((c) << 16)+((b) << 8)+(a))
+
+static int is_amd(void)
+{
+       return cpu_vendor[0] == A32('A','u','t','h') &&
+              cpu_vendor[1] == A32('e','n','t','i') &&
+              cpu_vendor[2] == A32('c','A','M','D');
+}
+
+static int is_centaur(void)
+{
+       return cpu_vendor[0] == A32('C','e','n','t') &&
+              cpu_vendor[1] == A32('a','u','r','H') &&
+              cpu_vendor[2] == A32('a','u','l','s');
+}
+
+static int is_transmeta(void)
+{
+       return cpu_vendor[0] == A32('G','e','n','u') &&
+              cpu_vendor[1] == A32('i','n','e','T') &&
+              cpu_vendor[2] == A32('M','x','8','6');
+}
+
+static int has_fpu(void)
+{
+       u16 fcw = -1, fsw = -1;
+       u32 cr0;
+
+       asm("movl %%cr0,%0" : "=r" (cr0));
+       if (cr0 & (X86_CR0_EM|X86_CR0_TS)) {
+               cr0 &= ~(X86_CR0_EM|X86_CR0_TS);
+               asm volatile("movl %0,%%cr0" : : "r" (cr0));
+       }
+
+       asm("fninit ; fnstsw %0 ; fnstcw %1" : "+m" (fsw), "+m" (fcw));
+
+       return fsw == 0 && (fcw & 0x103f) == 0x003f;
+}
+
+static int has_eflag(u32 mask)
+{
+       u32 f0, f1;
+
+       asm("pushfl ; "
+           "pushfl ; "
+           "popl %0 ; "
+           "movl %0,%1 ; "
+           "xorl %2,%1 ; "
+           "pushl %1 ; "
+           "popfl ; "
+           "pushfl ; "
+           "popl %1 ; "
+           "popfl"
+           : "=r" (f0), "=r" (f1)
+           : "g" (mask));
+
+       return !!((f0^f1) & mask);
+}
+
+static void get_flags(void)
+{
+       u32 max_intel_level, max_amd_level;
+       u32 tfms;
+
+       if (has_fpu())
+               set_bit(X86_FEATURE_FPU, cpu.flags);
+
+       if (has_eflag(X86_EFLAGS_ID)) {
+               asm("cpuid"
+                   : "=a" (max_intel_level),
+                     "=b" (cpu_vendor[0]),
+                     "=d" (cpu_vendor[1]),
+                     "=c" (cpu_vendor[2])
+                   : "a" (0));
+
+               if (max_intel_level >= 0x00000001 &&
+                   max_intel_level <= 0x0000ffff) {
+                       asm("cpuid"
+                           : "=a" (tfms),
+                             "=c" (cpu.flags[4]),
+                             "=d" (cpu.flags[0])
+                           : "a" (0x00000001)
+                           : "ebx");
+                       cpu.level = (tfms >> 8) & 15;
+                       cpu.model = (tfms >> 4) & 15;
+                       if (cpu.level >= 6)
+                               cpu.model += ((tfms >> 16) & 0xf) << 4;
+               }
+
+               asm("cpuid"
+                   : "=a" (max_amd_level)
+                   : "a" (0x80000000)
+                   : "ebx", "ecx", "edx");
+
+               if (max_amd_level >= 0x80000001 &&
+                   max_amd_level <= 0x8000ffff) {
+                       u32 eax = 0x80000001;
+                       asm("cpuid"
+                           : "+a" (eax),
+                             "=c" (cpu.flags[6]),
+                             "=d" (cpu.flags[1])
+                           : : "ebx");
+               }
+       }
+}
+
+/* Returns a bitmask of which words we have error bits in */
+static int check_flags(void)
+{
+       u32 err;
+       int i;
+
+       err = 0;
+       for (i = 0; i < NCAPINTS; i++) {
+               err_flags[i] = req_flags[i] & ~cpu.flags[i];
+               if (err_flags[i])
+                       err |= 1 << i;
+       }
+
+       return err;
+}
+
+/*
+ * Returns -1 on error.
+ *
+ * *cpu_level is set to the current CPU level; *req_level to the required
+ * level.  x86-64 is considered level 64 for this purpose.
+ *
+ * *err_flags_ptr is set to the flags error array if there are flags missing.
+ */
+int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)
+{
+       int err;
+
+       memset(&cpu.flags, 0, sizeof cpu.flags);
+       cpu.level = 3;
+
+       if (has_eflag(X86_EFLAGS_AC))
+               cpu.level = 4;
+
+       get_flags();
+       err = check_flags();
+
+       if (test_bit(X86_FEATURE_LM, cpu.flags))
+               cpu.level = 64;
+
+       if (err == 0x01 &&
+           !(err_flags[0] &
+             ~((1 << X86_FEATURE_XMM)|(1 << X86_FEATURE_XMM2))) &&
+           is_amd()) {
+               /* If this is an AMD and we're only missing SSE+SSE2, try to
+                  turn them on */
+
+               u32 ecx = MSR_K7_HWCR;
+               u32 eax, edx;
+
+               asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx));
+               eax &= ~(1 << 15);
+               asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
+
+               get_flags();    /* Make sure it really did something */
+               err = check_flags();
+       } else if (err == 0x01 &&
+                  !(err_flags[0] & ~(1 << X86_FEATURE_CX8)) &&
+                  is_centaur() && cpu.model >= 6) {
+               /* If this is a VIA C3, we might have to enable CX8
+                  explicitly */
+
+               u32 ecx = MSR_VIA_FCR;
+               u32 eax, edx;
+
+               asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx));
+               eax |= (1<<1)|(1<<7);
+               asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
+
+               set_bit(X86_FEATURE_CX8, cpu.flags);
+               err = check_flags();
+       } else if (err == 0x01 && is_transmeta()) {
+               /* Transmeta might have masked feature bits in word 0 */
+
+               u32 ecx = 0x80860004;
+               u32 eax, edx;
+               u32 level = 1;
+
+               asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx));
+               asm("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx));
+               asm("cpuid"
+                   : "+a" (level), "=d" (cpu.flags[0])
+                   : : "ecx", "ebx");
+               asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
+
+               err = check_flags();
+       }
+
+       if (err_flags_ptr)
+               *err_flags_ptr = err ? err_flags : NULL;
+       if (cpu_level_ptr)
+               *cpu_level_ptr = cpu.level;
+       if (req_level_ptr)
+               *req_level_ptr = req_level;
+
+       return (cpu.level < req_level || err) ? -1 : 0;
+}
diff --git a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S
deleted file mode 100644 (file)
index 3432136..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * BIOS Enhanced Disk Drive support
- * Copyright (C) 2002, 2003, 2004 Dell, Inc.
- * by Matt Domsch <Matt_Domsch@dell.com> October 2002
- * conformant to T13 Committee www.t13.org
- *   projects 1572D, 1484D, 1386D, 1226DT
- * disk signature read by Matt Domsch <Matt_Domsch@dell.com>
- *     and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004
- * legacy CHS retrieval by Patrick J. LoPresti <patl@users.sourceforge.net>
- *      March 2004
- * Command line option parsing, Matt Domsch, November 2004
- */
-
-#include <linux/edd.h>
-#include <asm/setup.h>
-
-#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
-
-# It is assumed that %ds == INITSEG here
-
-       movb    $0, (EDD_MBR_SIG_NR_BUF)
-       movb    $0, (EDDNR)
-
-# Check the command line for options:
-# edd=of  disables EDD completely  (edd=off)
-# edd=sk  skips the MBR test    (edd=skipmbr)
-# edd=on  re-enables EDD (edd=on)
-
-       pushl   %esi
-       movw    $edd_mbr_sig_start, %di # Default to edd=on
-
-       movl    %cs:(cmd_line_ptr), %esi
-       andl    %esi, %esi
-       jz      old_cl                  # Old boot protocol?
-
-# Convert to a real-mode pointer in fs:si
-       movl    %esi, %eax
-       shrl    $4, %eax
-       movw    %ax, %fs
-       andw    $0xf, %si
-       jmp     have_cl_pointer
-
-# Old-style boot protocol?
-old_cl:
-       push    %ds                     # aka INITSEG
-       pop     %fs
-
-       cmpw    $0xa33f, (0x20)
-       jne     done_cl                 # No command line at all?
-       movw    (0x22), %si             # Pointer relative to INITSEG
-
-# fs:si has the pointer to the command line now
-have_cl_pointer:
-
-# Loop through kernel command line one byte at a time.  Just in
-# case the loader is buggy and failed to null-terminate the command line
-# terminate if we get close enough to the end of the segment that we
-# cannot fit "edd=XX"...
-cl_atspace:
-       cmpw    $-5, %si                # Watch for segment wraparound
-       jae     done_cl
-       movl    %fs:(%si), %eax
-       andb    %al, %al                # End of line?
-       jz      done_cl
-       cmpl    $EDD_CL_EQUALS, %eax
-       jz      found_edd_equals
-       cmpb    $0x20, %al              # <= space consider whitespace
-       ja      cl_skipword
-       incw    %si
-       jmp     cl_atspace
-
-cl_skipword:
-       cmpw    $-5, %si                # Watch for segment wraparound
-       jae     done_cl
-       movb    %fs:(%si), %al          # End of string?
-       andb    %al, %al
-       jz      done_cl
-       cmpb    $0x20, %al
-       jbe     cl_atspace
-       incw    %si
-       jmp     cl_skipword
-
-found_edd_equals:
-# only looking at first two characters after equals
-# late overrides early on the command line, so keep going after finding something
-       movw    %fs:4(%si), %ax
-       cmpw    $EDD_CL_OFF, %ax        # edd=of
-       je      do_edd_off
-       cmpw    $EDD_CL_SKIP, %ax       # edd=sk
-       je      do_edd_skipmbr
-       cmpw    $EDD_CL_ON, %ax         # edd=on
-       je      do_edd_on
-       jmp     cl_skipword
-do_edd_skipmbr:
-       movw    $edd_start, %di
-       jmp     cl_skipword
-do_edd_off:
-       movw    $edd_done, %di
-       jmp     cl_skipword
-do_edd_on:
-       movw    $edd_mbr_sig_start, %di
-       jmp     cl_skipword
-
-done_cl:
-       popl    %esi
-       jmpw    *%di
-
-# Read the first sector of each BIOS disk device and store the 4-byte signature
-edd_mbr_sig_start:
-       movb    $0x80, %dl                      # from device 80
-       movw    $EDD_MBR_SIG_BUF, %bx           # store buffer ptr in bx
-edd_mbr_sig_read:
-       movl    $0xFFFFFFFF, %eax
-       movl    %eax, (%bx)                     # assume failure
-       pushw   %bx
-       movb    $READ_SECTORS, %ah
-       movb    $1, %al                         # read 1 sector
-       movb    $0, %dh                         # at head 0
-       movw    $1, %cx                         # cylinder 0, sector 0
-       pushw   %es
-       pushw   %ds
-       popw    %es
-       movw    $EDDBUF, %bx                    # disk's data goes into EDDBUF
-       pushw   %dx             # work around buggy BIOSes
-       stc                     # work around buggy BIOSes
-       int     $0x13
-       sti                     # work around buggy BIOSes
-       popw    %dx
-       popw    %es
-       popw    %bx
-       jc      edd_mbr_sig_done                # on failure, we're done.
-       cmpb    $0, %ah         # some BIOSes do not set CF
-       jne     edd_mbr_sig_done                # on failure, we're done.
-       movl    (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR
-       movl    %eax, (%bx)                     # store success
-       incb    (EDD_MBR_SIG_NR_BUF)            # note that we stored something
-       incb    %dl                             # increment to next device
-       addw    $4, %bx                         # increment sig buffer ptr
-       cmpb    $EDD_MBR_SIG_MAX, (EDD_MBR_SIG_NR_BUF)  # Out of space?
-       jb      edd_mbr_sig_read                # keep looping
-edd_mbr_sig_done:
-
-# Do the BIOS Enhanced Disk Drive calls
-# This consists of two calls:
-#    int 13h ah=41h "Check Extensions Present"
-#    int 13h ah=48h "Get Device Parameters"
-#    int 13h ah=08h "Legacy Get Device Parameters"
-#
-# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
-# in the boot_params at EDDBUF.  The first four bytes of which are
-# used to store the device number, interface support map and version
-# results from fn41.  The next four bytes are used to store the legacy
-# cylinders, heads, and sectors from fn08. The following 74 bytes are used to
-# store the results from fn48.  Starting from device 80h, fn41, then fn48
-# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
-# Then the pointer is incremented to store the data for the next call.
-# This repeats until either a device doesn't exist, or until EDDMAXNR
-# devices have been stored.
-# The one tricky part is that ds:si always points EDDEXTSIZE bytes into
-# the structure, and the fn41 and fn08 results are stored at offsets
-# from there.  This removes the need to increment the pointer for
-# every store, and leaves it ready for the fn48 call.
-# A second one-byte buffer, EDDNR, in the boot_params stores
-# the number of BIOS devices which exist, up to EDDMAXNR.
-# In setup.c, copy_edd() stores both boot_params buffers away
-# for later use, as they would get overwritten otherwise.
-# This code is sensitive to the size of the structs in edd.h
-edd_start:
-                                               # %ds points to the bootsector
-                                                       # result buffer for fn48
-       movw    $EDDBUF+EDDEXTSIZE, %si         # in ds:si, fn41 results
-                                               # kept just before that
-       movb    $0x80, %dl                      # BIOS device 0x80
-
-edd_check_ext:
-       movb    $CHECKEXTENSIONSPRESENT, %ah    # Function 41
-       movw    $EDDMAGIC1, %bx                 # magic
-       int     $0x13                           # make the call
-       jc      edd_done                        # no more BIOS devices
-
-       cmpw    $EDDMAGIC2, %bx                 # is magic right?
-       jne     edd_next                        # nope, next...
-
-       movb    %dl, %ds:-8(%si)                # store device number
-       movb    %ah, %ds:-7(%si)                # store version
-       movw    %cx, %ds:-6(%si)                # store extensions
-       incb    (EDDNR)                         # note that we stored something
-
-edd_get_device_params:
-       movw    $EDDPARMSIZE, %ds:(%si)         # put size
-       movw    $0x0, %ds:2(%si)                # work around buggy BIOSes
-       movb    $GETDEVICEPARAMETERS, %ah       # Function 48
-       int     $0x13                           # make the call
-                                               # Don't check for fail return
-                                               # it doesn't matter.
-edd_get_legacy_chs:
-       xorw    %ax, %ax
-       movw    %ax, %ds:-4(%si)
-       movw    %ax, %ds:-2(%si)
-        # Ralf Brown's Interrupt List says to set ES:DI to
-       # 0000h:0000h "to guard against BIOS bugs"
-       pushw   %es
-       movw    %ax, %es
-       movw    %ax, %di
-       pushw   %dx                             # legacy call clobbers %dl
-       movb    $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
-       int     $0x13                           # make the call
-       jc      edd_legacy_done                 # failed
-       movb    %cl, %al                        # Low 6 bits are max
-       andb    $0x3F, %al                      #   sector number
-       movb    %al, %ds:-1(%si)                # Record max sect
-       movb    %dh, %ds:-2(%si)                # Record max head number
-       movb    %ch, %al                        # Low 8 bits of max cyl
-       shr     $6, %cl
-       movb    %cl, %ah                        # High 2 bits of max cyl
-       movw    %ax, %ds:-4(%si)
-
-edd_legacy_done:
-       popw    %dx
-       popw    %es
-       movw    %si, %ax                        # increment si
-       addw    $EDDPARMSIZE+EDDEXTSIZE, %ax
-       movw    %ax, %si
-
-edd_next:
-       incb    %dl                             # increment to next device
-       cmpb    $EDDMAXNR, (EDDNR)              # Out of space?
-       jb      edd_check_ext                   # keep looping
-
-edd_done:
-#endif
diff --git a/arch/i386/boot/edd.c b/arch/i386/boot/edd.c
new file mode 100644 (file)
index 0000000..25a2824
--- /dev/null
@@ -0,0 +1,196 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/edd.c
+ *
+ * Get EDD BIOS disk information
+ */
+
+#include "boot.h"
+#include <linux/edd.h>
+
+#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
+
+struct edd_dapa {
+       u8      pkt_size;
+       u8      rsvd;
+       u16     sector_cnt;
+       u16     buf_off, buf_seg;
+       u64     lba;
+       u64     buf_lin_addr;
+};
+
+/*
+ * Read the MBR (first sector) from a specific device.
+ */
+static int read_mbr(u8 devno, void *buf)
+{
+       struct edd_dapa dapa;
+       u16 ax, bx, cx, dx, si;
+
+       memset(&dapa, 0, sizeof dapa);
+       dapa.pkt_size = sizeof(dapa);
+       dapa.sector_cnt = 1;
+       dapa.buf_off = (size_t)buf;
+       dapa.buf_seg = ds();
+       /* dapa.lba = 0; */
+
+       ax = 0x4200;            /* Extended Read */
+       si = (size_t)&dapa;
+       dx = devno;
+       asm("pushfl; stc; int $0x13; setc %%al; popfl"
+           : "+a" (ax), "+S" (si), "+d" (dx)
+           : "m" (dapa)
+           : "ebx", "ecx", "edi", "memory");
+
+       if (!(u8)ax)
+               return 0;       /* OK */
+
+       ax = 0x0201;            /* Legacy Read, one sector */
+       cx = 0x0001;            /* Sector 0-0-1 */
+       dx = devno;
+       bx = (size_t)buf;
+       asm("pushfl; stc; int $0x13; setc %%al; popfl"
+           : "+a" (ax), "+c" (cx), "+d" (dx), "+b" (bx)
+           : : "esi", "edi", "memory");
+
+       return -(u8)ax;         /* 0 or -1 */
+}
+
+static u32 read_mbr_sig(u8 devno, struct edd_info *ei)
+{
+       int sector_size;
+       char *mbrbuf_ptr, *mbrbuf_end;
+       u32 mbrsig;
+       u32 buf_base, mbr_base;
+       extern char _end[];
+       static char mbr_buf[1024];
+
+       sector_size = ei->params.bytes_per_sector;
+       if (!sector_size)
+               sector_size = 512; /* Best available guess */
+
+       buf_base = (ds() << 4) + (u32)&_end;
+       mbr_base = (buf_base+sector_size-1) & ~(sector_size-1);
+       mbrbuf_ptr = mbr_buf + (mbr_base-buf_base);
+       mbrbuf_end = mbrbuf_ptr + sector_size;
+
+       if (!(boot_params.hdr.loadflags & CAN_USE_HEAP))
+               return 0;
+       if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
+               return 0;
+
+       if (read_mbr(devno, mbrbuf_ptr))
+               return 0;
+
+       mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
+       return mbrsig;
+}
+
+static int get_edd_info(u8 devno, struct edd_info *ei)
+{
+       u16 ax, bx, cx, dx, di;
+
+       memset(ei, 0, sizeof *ei);
+
+       /* Check Extensions Present */
+
+       ax = 0x4100;
+       bx = EDDMAGIC1;
+       dx = devno;
+       asm("pushfl; stc; int $0x13; setc %%al; popfl"
+           : "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx)
+           : : "esi", "edi");
+
+       if ((u8)ax)
+               return -1;      /* No extended information */
+
+       if (bx != EDDMAGIC2)
+               return -1;
+
+       ei->device  = devno;
+       ei->version = ax >> 8;  /* EDD version number */
+       ei->interface_support = cx; /* EDD functionality subsets */
+
+       /* Extended Get Device Parameters */
+
+       ei->params.length = sizeof(ei->params);
+       ax = 0x4800;
+       dx = devno;
+       asm("pushfl; int $0x13; popfl"
+           : "+a" (ax), "+d" (dx)
+           : "S" (&ei->params)
+           : "ebx", "ecx", "edi");
+
+       /* Get legacy CHS parameters */
+
+       /* Ralf Brown recommends setting ES:DI to 0:0 */
+       ax = 0x0800;
+       dx = devno;
+       di = 0;
+       asm("pushw %%es; "
+           "movw %%di,%%es; "
+           "pushfl; stc; int $0x13; setc %%al; popfl; "
+           "popw %%es"
+           : "+a" (ax), "=b" (bx), "=c" (cx), "+d" (dx), "+D" (di)
+           : : "esi");
+
+       if ((u8)ax == 0) {
+               ei->legacy_max_cylinder = (cx >> 8) + ((cx & 0xc0) << 2);
+               ei->legacy_max_head = dx >> 8;
+               ei->legacy_sectors_per_track = cx & 0x3f;
+       }
+
+       return 0;
+}
+
+void query_edd(void)
+{
+       char eddarg[8];
+       int do_mbr = 1;
+       int do_edd = 1;
+       int devno;
+       struct edd_info ei, *edp;
+
+       if (cmdline_find_option("edd", eddarg, sizeof eddarg) > 0) {
+               if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip"))
+                       do_mbr = 0;
+               else if (!strcmp(eddarg, "off"))
+                       do_edd = 0;
+       }
+
+       edp = (struct edd_info *)boot_params.eddbuf;
+
+       if (!do_edd)
+               return;
+
+       for (devno = 0x80; devno < 0x80+EDD_MBR_SIG_MAX; devno++) {
+               /*
+                * Scan the BIOS-supported hard disks and query EDD
+                * information...
+                */
+               get_edd_info(devno, &ei);
+
+               if (boot_params.eddbuf_entries < EDDMAXNR) {
+                       memcpy(edp, &ei, sizeof ei);
+                       edp++;
+                       boot_params.eddbuf_entries++;
+               }
+
+               if (do_mbr) {
+                       u32 mbr_sig;
+                       mbr_sig = read_mbr_sig(devno, &ei);
+                       boot_params.edd_mbr_sig_buffer[devno-0x80] = mbr_sig;
+               }
+       }
+}
+
+#endif
diff --git a/arch/i386/boot/header.S b/arch/i386/boot/header.S
new file mode 100644 (file)
index 0000000..6b9923f
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ *     header.S
+ *
+ *     Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ *     Based on bootsect.S and setup.S
+ *     modified by more people than can be counted
+ *
+ *     Rewritten as a common file by H. Peter Anvin (Apr 2007)
+ *
+ * BIG FAT NOTE: We're in real mode using 64k segments.  Therefore segment
+ * addresses must be multiplied by 16 to obtain their respective linear
+ * addresses. To avoid confusion, linear addresses are written using leading
+ * hex while segment addresses are written as segment:offset.
+ *
+ */
+
+#include <asm/segment.h>
+#include <linux/utsrelease.h>
+#include <asm/boot.h>
+#include <asm/e820.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include "boot.h"
+
+SETUPSECTS     = 4                     /* default nr of setup-sectors */
+BOOTSEG                = 0x07C0                /* original address of boot-sector */
+SYSSEG         = DEF_SYSSEG            /* system loaded at 0x10000 (65536) */
+SYSSIZE                = DEF_SYSSIZE           /* system size: # of 16-byte clicks */
+                                       /* to be loaded */
+ROOT_DEV       = 0                     /* ROOT_DEV is now written by "build" */
+SWAP_DEV       = 0                     /* SWAP_DEV is now written by "build" */
+
+#ifndef SVGA_MODE
+#define SVGA_MODE ASK_VGA
+#endif
+
+#ifndef RAMDISK
+#define RAMDISK 0
+#endif
+
+#ifndef ROOT_RDONLY
+#define ROOT_RDONLY 1
+#endif
+
+       .code16
+       .section ".bstext", "ax"
+
+       .global bootsect_start
+bootsect_start:
+
+       # Normalize the start address
+       ljmp    $BOOTSEG, $start2
+
+start2:
+       movw    %cs, %ax
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %ss
+       xorw    %sp, %sp
+       sti
+       cld
+
+       movw    $bugger_off_msg, %si
+
+msg_loop:
+       lodsb
+       andb    %al, %al
+       jz      bs_die
+       movb    $0xe, %ah
+       movw    $7, %bx
+       int     $0x10
+       jmp     msg_loop
+
+bs_die:
+       # Allow the user to press a key, then reboot
+       xorw    %ax, %ax
+       int     $0x16
+       int     $0x19
+
+       # int 0x19 should never return.  In case it does anyway,
+       # invoke the BIOS reset code...
+       ljmp    $0xf000,$0xfff0
+
+       .section ".bsdata", "a"
+bugger_off_msg:
+       .ascii  "Direct booting from floppy is no longer supported.\r\n"
+       .ascii  "Please use a boot loader program instead.\r\n"
+       .ascii  "\n"
+       .ascii  "Remove disk and press any key to reboot . . .\r\n"
+       .byte   0
+
+
+       # Kernel attributes; used by setup.  This is part 1 of the
+       # header, from the old boot sector.
+
+       .section ".header", "a"
+       .globl  hdr
+hdr:
+setup_sects:   .byte SETUPSECTS
+root_flags:    .word ROOT_RDONLY
+syssize:       .long SYSSIZE
+ram_size:      .word RAMDISK
+vid_mode:      .word SVGA_MODE
+root_dev:      .word ROOT_DEV
+boot_flag:     .word 0xAA55
+
+       # offset 512, entry point
+
+       .globl  _start
+_start:
+               # Explicitly enter this as bytes, or the assembler
+               # tries to generate a 3-byte jump here, which causes
+               # everything else to push off to the wrong offset.
+               .byte   0xeb            # short (2-byte) jump
+               .byte   start_of_setup-1f
+1:
+
+       # Part 2 of the header, from the old setup.S
+
+               .ascii  "HdrS"          # header signature
+               .word   0x0206          # header version number (>= 0x0105)
+                                       # or else old loadlin-1.5 will fail)
+               .globl realmode_swtch
+realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
+start_sys_seg: .word   SYSSEG
+               .word   kernel_version-512 # pointing to kernel version string
+                                       # above section of header is compatible
+                                       # with loadlin-1.5 (header v1.5). Don't
+                                       # change it.
+
+type_of_loader:        .byte   0               # = 0, old one (LILO, Loadlin,
+                                       #      Bootlin, SYSLX, bootsect...)
+                                       # See Documentation/i386/boot.txt for
+                                       # assigned ids
+
+# flags, unused bits must be zero (RFU) bit within loadflags
+loadflags:
+LOADED_HIGH    = 1                     # If set, the kernel is loaded high
+CAN_USE_HEAP   = 0x80                  # If set, the loader also has set
+                                       # heap_end_ptr to tell how much
+                                       # space behind setup.S can be used for
+                                       # heap purposes.
+                                       # Only the loader knows what is free
+#ifndef __BIG_KERNEL__
+               .byte   0
+#else
+               .byte   LOADED_HIGH
+#endif
+
+setup_move_size: .word  0x8000         # size to move, when setup is not
+                                       # loaded at 0x90000. We will move setup
+                                       # to 0x90000 then just before jumping
+                                       # into the kernel. However, only the
+                                       # loader knows how much data behind
+                                       # us also needs to be loaded.
+
+code32_start:                          # here loaders can put a different
+                                       # start address for 32-bit code.
+#ifndef __BIG_KERNEL__
+               .long   0x1000          #   0x1000 = default for zImage
+#else
+               .long   0x100000        # 0x100000 = default for big kernel
+#endif
+
+ramdisk_image: .long   0               # address of loaded ramdisk image
+                                       # Here the loader puts the 32-bit
+                                       # address where it loaded the image.
+                                       # This only will be read by the kernel.
+
+ramdisk_size:  .long   0               # its size in bytes
+
+bootsect_kludge:
+               .long   0               # obsolete
+
+heap_end_ptr:  .word   _end+1024       # (Header version 0x0201 or later)
+                                       # space from here (exclusive) down to
+                                       # end of setup code can be used by setup
+                                       # for local heap purposes.
+
+pad1:          .word   0
+cmd_line_ptr:  .long   0               # (Header version 0x0202 or later)
+                                       # If nonzero, a 32-bit pointer
+                                       # to the kernel command line.
+                                       # The command line should be
+                                       # located between the start of
+                                       # setup and the end of low
+                                       # memory (0xa0000), or it may
+                                       # get overwritten before it
+                                       # gets read.  If this field is
+                                       # used, there is no longer
+                                       # anything magical about the
+                                       # 0x90000 segment; the setup
+                                       # can be located anywhere in
+                                       # low memory 0x10000 or higher.
+
+ramdisk_max:   .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
+                                       # (Header version 0x0203 or later)
+                                       # The highest safe address for
+                                       # the contents of an initrd
+
+kernel_alignment:  .long CONFIG_PHYSICAL_ALIGN #physical addr alignment
+                                               #required for protected mode
+                                               #kernel
+#ifdef CONFIG_RELOCATABLE
+relocatable_kernel:    .byte 1
+#else
+relocatable_kernel:    .byte 0
+#endif
+pad2:                  .byte 0
+pad3:                  .word 0
+
+cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
+                                                #added with boot protocol
+                                                #version 2.06
+
+# End of setup header #####################################################
+
+       .section ".inittext", "ax"
+start_of_setup:
+#ifdef SAFE_RESET_DISK_CONTROLLER
+# Reset the disk controller.
+       movw    $0x0000, %ax            # Reset disk controller
+       movb    $0x80, %dl              # All disks
+       int     $0x13
+#endif
+
+# We will have entired with %cs = %ds+0x20, normalize %cs so
+# it is on par with the other segments.
+       pushw   %ds
+       pushw   $setup2
+       lretw
+
+setup2:
+# Force %es = %ds
+       movw    %ds, %ax
+       movw    %ax, %es
+       cld
+
+# Stack paranoia: align the stack and make sure it is good
+# for both 16- and 32-bit references.  In particular, if we
+# were meant to have been using the full 16-bit segment, the
+# caller might have set %sp to zero, which breaks %esp-based
+# references.
+       andw    $~3, %sp        # dword align (might as well...)
+       jnz     1f
+       movw    $0xfffc, %sp    # Make sure we're not zero
+1:     movzwl  %sp, %esp       # Clear upper half of %esp
+       sti
+
+# Check signature at end of setup
+       cmpl    $0x5a5aaa55, setup_sig
+       jne     setup_bad
+
+# Zero the bss
+       movw    $__bss_start, %di
+       movw    $_end+3, %cx
+       xorl    %eax, %eax
+       subw    %di, %cx
+       shrw    $2, %cx
+       rep; stosl
+
+# Jump to C code (should not return)
+       calll   main
+
+# Setup corrupt somehow...
+setup_bad:
+       movl    $setup_corrupt, %eax
+       calll   puts
+       # Fall through...
+
+       .globl  die
+       .type   die, @function
+die:
+       hlt
+       jmp     die
+
+       .size   die, .-due
+
+       .section ".initdata", "a"
+setup_corrupt:
+       .byte   7
+       .string "No setup signature found..."
diff --git a/arch/i386/boot/main.c b/arch/i386/boot/main.c
new file mode 100644 (file)
index 0000000..7f01f96
--- /dev/null
@@ -0,0 +1,161 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/main.c
+ *
+ * Main module for the real-mode kernel code
+ */
+
+#include "boot.h"
+
+struct boot_params boot_params __attribute__((aligned(16)));
+
+char *HEAP = _end;
+char *heap_end = _end;         /* Default end of heap = no heap */
+
+/*
+ * Copy the header into the boot parameter block.  Since this
+ * screws up the old-style command line protocol, adjust by
+ * filling in the new-style command line pointer instead.
+ */
+#define OLD_CL_MAGIC   0xA33F
+#define OLD_CL_ADDRESS 0x20
+
+static void copy_boot_params(void)
+{
+       struct old_cmdline {
+               u16 cl_magic;
+               u16 cl_offset;
+       };
+       const struct old_cmdline * const oldcmd =
+               (const struct old_cmdline *)OLD_CL_ADDRESS;
+
+       BUILD_BUG_ON(sizeof boot_params != 4096);
+       memcpy(&boot_params.hdr, &hdr, sizeof hdr);
+
+       if (!boot_params.hdr.cmd_line_ptr &&
+           oldcmd->cl_magic == OLD_CL_MAGIC) {
+               /* Old-style command line protocol. */
+               u16 cmdline_seg;
+
+               /* Figure out if the command line falls in the region
+                  of memory that an old kernel would have copied up
+                  to 0x90000... */
+               if (oldcmd->cl_offset < boot_params.hdr.setup_move_size)
+                       cmdline_seg = ds();
+               else
+                       cmdline_seg = 0x9000;
+
+               boot_params.hdr.cmd_line_ptr =
+                       (cmdline_seg << 4) + oldcmd->cl_offset;
+       }
+}
+
+/*
+ * Set the keyboard repeat rate to maximum.  Unclear why this
+ * is done here; this might be possible to kill off as stale code.
+ */
+static void keyboard_set_repeat(void)
+{
+       u16 ax = 0x0305;
+       u16 bx = 0;
+       asm volatile("int $0x16"
+                    : "+a" (ax), "+b" (bx)
+                    : : "ecx", "edx", "esi", "edi");
+}
+
+/*
+ * Get Intel SpeedStep IST information.
+ */
+static void query_speedstep_ist(void)
+{
+       asm("int $0x15"
+           : "=a" (boot_params.speedstep_info[0]),
+             "=b" (boot_params.speedstep_info[1]),
+             "=c" (boot_params.speedstep_info[2]),
+             "=d" (boot_params.speedstep_info[3])
+           : "a" (0x0000e980),  /* IST Support */
+             "d" (0x47534943)); /* Request value */
+}
+
+/*
+ * Tell the BIOS what CPU mode we intend to run in.
+ */
+static void set_bios_mode(void)
+{
+#ifdef CONFIG_X86_64
+       u32 eax, ebx;
+
+       eax = 0xec00;
+       ebx = 2;
+       asm volatile("int $0x15"
+                    : "+a" (eax), "+b" (ebx)
+                    : : "ecx", "edx", "esi", "edi");
+#endif
+}
+
+void main(void)
+{
+       /* First, copy the boot header into the "zeropage" */
+       copy_boot_params();
+
+       /* End of heap check */
+       if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
+               heap_end = (char *)(boot_params.hdr.heap_end_ptr
+                                   +0x200-STACK_SIZE);
+       } else {
+               /* Boot protocol 2.00 only, no heap available */
+               puts("WARNING: Ancient bootloader, some functionality "
+                    "may be limited!\n");
+       }
+
+       /* Make sure we have all the proper CPU support */
+       if (validate_cpu()) {
+               puts("Unable to boot - please use a kernel appropriate "
+                    "for your CPU.\n");
+               die();
+       }
+
+       /* Tell the BIOS what CPU mode we intend to run in. */
+       set_bios_mode();
+
+       /* Detect memory layout */
+       detect_memory();
+
+       /* Set keyboard repeat rate (why?) */
+       keyboard_set_repeat();
+
+       /* Set the video mode */
+       set_video();
+
+       /* Query MCA information */
+       query_mca();
+
+       /* Voyager */
+#ifdef CONFIG_X86_VOYAGER
+       query_voyager();
+#endif
+
+       /* Query SpeedStep IST information */
+       query_speedstep_ist();
+
+       /* Query APM information */
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
+       query_apm_bios();
+#endif
+
+       /* Query EDD information */
+#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
+       query_edd();
+#endif
+       /* Do the last things and invoke protected mode */
+       go_to_protected_mode();
+}
diff --git a/arch/i386/boot/mca.c b/arch/i386/boot/mca.c
new file mode 100644 (file)
index 0000000..9b68bd1
--- /dev/null
@@ -0,0 +1,43 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/mca.c
+ *
+ * Get the MCA system description table
+ */
+
+#include "boot.h"
+
+int query_mca(void)
+{
+       u8 err;
+       u16 es, bx, len;
+
+       asm("pushw %%es ; "
+           "int $0x15 ; "
+           "setc %0 ; "
+           "movw %%es, %1 ; "
+           "popw %%es"
+           : "=acdSDm" (err), "=acdSDm" (es), "=b" (bx)
+           : "a" (0xc000));
+
+       if (err)
+               return -1;      /* No MCA present */
+
+       set_fs(es);
+       len = rdfs16(bx);
+
+       if (len > sizeof(boot_params.sys_desc_table))
+               len = sizeof(boot_params.sys_desc_table);
+
+       copy_from_fs(&boot_params.sys_desc_table, bx, len);
+       return 0;
+}
diff --git a/arch/i386/boot/memory.c b/arch/i386/boot/memory.c
new file mode 100644 (file)
index 0000000..1a2e62d
--- /dev/null
@@ -0,0 +1,99 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/memory.c
+ *
+ * Memory detection code
+ */
+
+#include "boot.h"
+
+#define SMAP   0x534d4150      /* ASCII "SMAP" */
+
+static int detect_memory_e820(void)
+{
+       u32 next = 0;
+       u32 size, id;
+       u8 err;
+       struct e820entry *desc = boot_params.e820_map;
+
+       do {
+               size = sizeof(struct e820entry);
+               id = SMAP;
+               asm("int $0x15; setc %0"
+                   : "=am" (err), "+b" (next), "+d" (id), "+c" (size),
+                     "=m" (*desc)
+                   : "D" (desc), "a" (0xe820));
+
+               if (err || id != SMAP)
+                       break;
+
+               boot_params.e820_entries++;
+               desc++;
+       } while (next && boot_params.e820_entries < E820MAX);
+
+       return boot_params.e820_entries;
+}
+
+static int detect_memory_e801(void)
+{
+       u16 ax, bx, cx, dx;
+       u8 err;
+
+       bx = cx = dx = 0;
+       ax = 0xe801;
+       asm("stc; int $0x15; setc %0"
+           : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));
+
+       if (err)
+               return -1;
+
+       /* Do we really need to do this? */
+       if (cx || dx) {
+               ax = cx;
+               bx = dx;
+       }
+
+       if (ax > 15*1024)
+               return -1;      /* Bogus! */
+
+       /* This ignores memory above 16MB if we have a memory hole
+          there.  If someone actually finds a machine with a memory
+          hole at 16MB and no support for 0E820h they should probably
+          generate a fake e820 map. */
+       boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax;
+
+       return 0;
+}
+
+static int detect_memory_88(void)
+{
+       u16 ax;
+       u8 err;
+
+       ax = 0x8800;
+       asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax));
+
+       boot_params.screen_info.ext_mem_k = ax;
+
+       return -err;
+}
+
+int detect_memory(void)
+{
+       if (detect_memory_e820() > 0)
+               return 0;
+
+       if (!detect_memory_e801())
+               return 0;
+
+       return detect_memory_88();
+}
diff --git a/arch/i386/boot/pm.c b/arch/i386/boot/pm.c
new file mode 100644 (file)
index 0000000..3fa53e1
--- /dev/null
@@ -0,0 +1,170 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/pm.c
+ *
+ * Prepare the machine for transition to protected mode.
+ */
+
+#include "boot.h"
+#include <asm/segment.h>
+
+/*
+ * Invoke the realmode switch hook if present; otherwise
+ * disable all interrupts.
+ */
+static void realmode_switch_hook(void)
+{
+       if (boot_params.hdr.realmode_swtch) {
+               asm volatile("lcallw *%0"
+                            : : "m" (boot_params.hdr.realmode_swtch)
+                            : "eax", "ebx", "ecx", "edx");
+       } else {
+               asm volatile("cli");
+               outb(0x80, 0x70); /* Disable NMI */
+               io_delay();
+       }
+}
+
+/*
+ * A zImage kernel is loaded at 0x10000 but wants to run at 0x1000.
+ * A bzImage kernel is loaded and runs at 0x100000.
+ */
+static void move_kernel_around(void)
+{
+       /* Note: rely on the compile-time option here rather than
+          the LOADED_HIGH flag.  The Qemu kernel loader unconditionally
+          sets the loadflags to zero. */
+#ifndef __BIG_KERNEL__
+       u16 dst_seg, src_seg;
+       u32 syssize;
+
+       dst_seg =  0x1000 >> 4;
+       src_seg = 0x10000 >> 4;
+       syssize = boot_params.hdr.syssize; /* Size in 16-byte paragraphs */
+
+       while (syssize) {
+               int paras  = (syssize >= 0x1000) ? 0x1000 : syssize;
+               int dwords = paras << 2;
+
+               asm volatile("pushw %%es ; "
+                            "pushw %%ds ; "
+                            "movw %1,%%es ; "
+                            "movw %2,%%ds ; "
+                            "xorw %%di,%%di ; "
+                            "xorw %%si,%%si ; "
+                            "rep;movsl ; "
+                            "popw %%ds ; "
+                            "popw %%es"
+                            : "+c" (dwords)
+                            : "rm" (dst_seg), "rm" (src_seg)
+                            : "esi", "edi");
+
+               syssize -= paras;
+               dst_seg += paras;
+               src_seg += paras;
+       }
+#endif
+}
+
+/*
+ * Disable all interrupts at the legacy PIC.
+ */
+static void mask_all_interrupts(void)
+{
+       outb(0xff, 0xa1);       /* Mask all interrupts on the seconday PIC */
+       io_delay();
+       outb(0xfb, 0x21);       /* Mask all but cascade on the primary PIC */
+       io_delay();
+}
+
+/*
+ * Reset IGNNE# if asserted in the FPU.
+ */
+static void reset_coprocessor(void)
+{
+       outb(0, 0xf0);
+       io_delay();
+       outb(0, 0xf1);
+       io_delay();
+}
+
+/*
+ * Set up the GDT
+ */
+#define GDT_ENTRY(flags,base,limit)            \
+       (((u64)(base & 0xff000000) << 32) |     \
+        ((u64)flags << 40) |                   \
+        ((u64)(limit & 0x00ff0000) << 32) |    \
+        ((u64)(base & 0x00ffff00) << 16) |     \
+        ((u64)(limit & 0x0000ffff)))
+
+struct gdt_ptr {
+       u16 len;
+       u32 ptr;
+} __attribute__((packed));
+
+static void setup_gdt(void)
+{
+       /* There are machines which are known to not boot with the GDT
+          being 8-byte unaligned.  Intel recommends 16 byte alignment. */
+       static const u64 boot_gdt[] __attribute__((aligned(16))) = {
+               /* CS: code, read/execute, 4 GB, base 0 */
+               [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff),
+               /* DS: data, read/write, 4 GB, base 0 */
+               [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff),
+       };
+       struct gdt_ptr gdt;
+
+       gdt.len = sizeof(boot_gdt)-1;
+       gdt.ptr = (u32)&boot_gdt + (ds() << 4);
+
+       asm volatile("lgdtl %0" : : "m" (gdt));
+}
+
+/*
+ * Set up the IDT
+ */
+static void setup_idt(void)
+{
+       static const struct gdt_ptr null_idt = {0, 0};
+       asm volatile("lidtl %0" : : "m" (null_idt));
+}
+
+/*
+ * Actual invocation sequence
+ */
+void go_to_protected_mode(void)
+{
+       /* Hook before leaving real mode, also disables interrupts */
+       realmode_switch_hook();
+
+       /* Move the kernel/setup to their final resting places */
+       move_kernel_around();
+
+       /* Enable the A20 gate */
+       if (enable_a20()) {
+               puts("A20 gate not responding, unable to boot...\n");
+               die();
+       }
+
+       /* Reset coprocessor (IGNNE#) */
+       reset_coprocessor();
+
+       /* Mask all interrupts in the PIC */
+       mask_all_interrupts();
+
+       /* Actual transition to protected mode... */
+       setup_idt();
+       setup_gdt();
+       protected_mode_jump(boot_params.hdr.code32_start,
+                           (u32)&boot_params + (ds() << 4));
+}
diff --git a/arch/i386/boot/pmjump.S b/arch/i386/boot/pmjump.S
new file mode 100644 (file)
index 0000000..2e55923
--- /dev/null
@@ -0,0 +1,54 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/pmjump.S
+ *
+ * The actual transition into protected mode
+ */
+
+#include <asm/boot.h>
+#include <asm/segment.h>
+
+       .text
+
+       .globl  protected_mode_jump
+       .type   protected_mode_jump, @function
+
+       .code16
+
+/*
+ * void protected_mode_jump(u32 entrypoint, u32 bootparams);
+ */
+protected_mode_jump:
+       xorl    %ebx, %ebx              # Flag to indicate this is a boot
+       movl    %edx, %esi              # Pointer to boot_params table
+       movl    %eax, 2f                # Patch ljmpl instruction
+       jmp     1f                      # Short jump to flush instruction q.
+
+1:
+       movw    $__BOOT_DS, %cx
+
+       movl    %cr0, %edx
+       orb     $1, %dl                 # Protected mode (PE) bit
+       movl    %edx, %cr0
+
+       movw    %cx, %ds
+       movw    %cx, %es
+       movw    %cx, %fs
+       movw    %cx, %gs
+       movw    %cx, %ss
+
+       # Jump to the 32-bit entrypoint
+       .byte   0x66, 0xea              # ljmpl opcode
+2:     .long   0                       # offset
+       .word   __BOOT_CS               # segment
+
+       .size   protected_mode_jump, .-protected_mode_jump
diff --git a/arch/i386/boot/printf.c b/arch/i386/boot/printf.c
new file mode 100644 (file)
index 0000000..1a09f93
--- /dev/null
@@ -0,0 +1,307 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/printf.c
+ *
+ * Oh, it's a waste of space, but oh-so-yummy for debugging.  This
+ * version of printf() does not include 64-bit support.  "Live with
+ * it."
+ *
+ */
+
+#include "boot.h"
+
+static int skip_atoi(const char **s)
+{
+       int i = 0;
+
+       while (isdigit(**s))
+               i = i * 10 + *((*s)++) - '0';
+       return i;
+}
+
+#define ZEROPAD        1               /* pad with zero */
+#define SIGN   2               /* unsigned/signed long */
+#define PLUS   4               /* show plus */
+#define SPACE  8               /* space if plus */
+#define LEFT   16              /* left justified */
+#define SPECIAL        32              /* 0x */
+#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+static char *number(char *str, long num, int base, int size, int precision,
+                   int type)
+{
+       char c, sign, tmp[66];
+       const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+       int i;
+
+       if (type & LARGE)
+               digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       if (type & LEFT)
+               type &= ~ZEROPAD;
+       if (base < 2 || base > 36)
+               return 0;
+       c = (type & ZEROPAD) ? '0' : ' ';
+       sign = 0;
+       if (type & SIGN) {
+               if (num < 0) {
+                       sign = '-';
+                       num = -num;
+                       size--;
+               } else if (type & PLUS) {
+                       sign = '+';
+                       size--;
+               } else if (type & SPACE) {
+                       sign = ' ';
+                       size--;
+               }
+       }
+       if (type & SPECIAL) {
+               if (base == 16)
+                       size -= 2;
+               else if (base == 8)
+                       size--;
+       }
+       i = 0;
+       if (num == 0)
+               tmp[i++] = '0';
+       else
+               while (num != 0)
+                       tmp[i++] = digits[do_div(num, base)];
+       if (i > precision)
+               precision = i;
+       size -= precision;
+       if (!(type & (ZEROPAD + LEFT)))
+               while (size-- > 0)
+                       *str++ = ' ';
+       if (sign)
+               *str++ = sign;
+       if (type & SPECIAL) {
+               if (base == 8)
+                       *str++ = '0';
+               else if (base == 16) {
+                       *str++ = '0';
+                       *str++ = digits[33];
+               }
+       }
+       if (!(type & LEFT))
+               while (size-- > 0)
+                       *str++ = c;
+       while (i < precision--)
+               *str++ = '0';
+       while (i-- > 0)
+               *str++ = tmp[i];
+       while (size-- > 0)
+               *str++ = ' ';
+       return str;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+       int len;
+       unsigned long num;
+       int i, base;
+       char *str;
+       const char *s;
+
+       int flags;              /* flags to number() */
+
+       int field_width;        /* width of output field */
+       int precision;          /* min. # of digits for integers; max
+                                  number of chars for from string */
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+
+       for (str = buf; *fmt; ++fmt) {
+               if (*fmt != '%') {
+                       *str++ = *fmt;
+                       continue;
+               }
+
+               /* process flags */
+               flags = 0;
+             repeat:
+               ++fmt;          /* this also skips first '%' */
+               switch (*fmt) {
+               case '-':
+                       flags |= LEFT;
+                       goto repeat;
+               case '+':
+                       flags |= PLUS;
+                       goto repeat;
+               case ' ':
+                       flags |= SPACE;
+                       goto repeat;
+               case '#':
+                       flags |= SPECIAL;
+                       goto repeat;
+               case '0':
+                       flags |= ZEROPAD;
+                       goto repeat;
+               }
+
+               /* get field width */
+               field_width = -1;
+               if (isdigit(*fmt))
+                       field_width = skip_atoi(&fmt);
+               else if (*fmt == '*') {
+                       ++fmt;
+                       /* it's the next argument */
+                       field_width = va_arg(args, int);
+                       if (field_width < 0) {
+                               field_width = -field_width;
+                               flags |= LEFT;
+                       }
+               }
+
+               /* get the precision */
+               precision = -1;
+               if (*fmt == '.') {
+                       ++fmt;
+                       if (isdigit(*fmt))
+                               precision = skip_atoi(&fmt);
+                       else if (*fmt == '*') {
+                               ++fmt;
+                               /* it's the next argument */
+                               precision = va_arg(args, int);
+                       }
+                       if (precision < 0)
+                               precision = 0;
+               }
+
+               /* get the conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+                       qualifier = *fmt;
+                       ++fmt;
+               }
+
+               /* default base */
+               base = 10;
+
+               switch (*fmt) {
+               case 'c':
+                       if (!(flags & LEFT))
+                               while (--field_width > 0)
+                                       *str++ = ' ';
+                       *str++ = (unsigned char)va_arg(args, int);
+                       while (--field_width > 0)
+                               *str++ = ' ';
+                       continue;
+
+               case 's':
+                       s = va_arg(args, char *);
+                       len = strnlen(s, precision);
+
+                       if (!(flags & LEFT))
+                               while (len < field_width--)
+                                       *str++ = ' ';
+                       for (i = 0; i < len; ++i)
+                               *str++ = *s++;
+                       while (len < field_width--)
+                               *str++ = ' ';
+                       continue;
+
+               case 'p':
+                       if (field_width == -1) {
+                               field_width = 2 * sizeof(void *);
+                               flags |= ZEROPAD;
+                       }
+                       str = number(str,
+                                    (unsigned long)va_arg(args, void *), 16,
+                                    field_width, precision, flags);
+                       continue;
+
+               case 'n':
+                       if (qualifier == 'l') {
+                               long *ip = va_arg(args, long *);
+                               *ip = (str - buf);
+                       } else {
+                               int *ip = va_arg(args, int *);
+                               *ip = (str - buf);
+                       }
+                       continue;
+
+               case '%':
+                       *str++ = '%';
+                       continue;
+
+                       /* integer number formats - set up the flags and "break" */
+               case 'o':
+                       base = 8;
+                       break;
+
+               case 'X':
+                       flags |= LARGE;
+               case 'x':
+                       base = 16;
+                       break;
+
+               case 'd':
+               case 'i':
+                       flags |= SIGN;
+               case 'u':
+                       break;
+
+               default:
+                       *str++ = '%';
+                       if (*fmt)
+                               *str++ = *fmt;
+                       else
+                               --fmt;
+                       continue;
+               }
+               if (qualifier == 'l')
+                       num = va_arg(args, unsigned long);
+               else if (qualifier == 'h') {
+                       num = (unsigned short)va_arg(args, int);
+                       if (flags & SIGN)
+                               num = (short)num;
+               } else if (flags & SIGN)
+                       num = va_arg(args, int);
+               else
+                       num = va_arg(args, unsigned int);
+               str = number(str, num, base, field_width, precision, flags);
+       }
+       *str = '\0';
+       return str - buf;
+}
+
+int sprintf(char *buf, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i = vsprintf(buf, fmt, args);
+       va_end(args);
+       return i;
+}
+
+int printf(const char *fmt, ...)
+{
+       char printf_buf[1024];
+       va_list args;
+       int printed;
+
+       va_start(args, fmt);
+       printed = vsprintf(printf_buf, fmt, args);
+       va_end(args);
+
+       puts(printf_buf);
+
+       return printed;
+}
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
deleted file mode 100644 (file)
index 6dbcc95..0000000
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- *     setup.S         Copyright (C) 1991, 1992 Linus Torvalds
- *
- * setup.s is responsible for getting the system data from the BIOS,
- * and putting them into the appropriate places in system memory.
- * both setup.s and system has been loaded by the bootblock.
- *
- * This code asks the bios for memory/disk/other parameters, and
- * puts them in a "safe" place: 0x90000-0x901FF, ie where the
- * boot-block used to be. It is then up to the protected mode
- * system to read them from there before the area is overwritten
- * for buffer-blocks.
- *
- * Move PS/2 aux init code to psaux.c
- * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
- *
- * some changes and additional features by Christoph Niemann,
- * March 1993/June 1994 (Christoph.Niemann@linux.org)
- *
- * add APM BIOS checking by Stephen Rothwell, May 1994
- * (sfr@canb.auug.org.au)
- *
- * High load stuff, initrd support and position independency
- * by Hans Lermen & Werner Almesberger, February 1996
- * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
- *
- * Video handling moved to video.S by Martin Mares, March 1996
- * <mj@k332.feld.cvut.cz>
- *
- * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
- * parsons) to avoid loadlin confusion, July 1997
- *
- * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
- * <stiker@northlink.com>
- *
- * Fix to work around buggy BIOSes which don't use carry bit correctly
- * and/or report extended memory in CX/DX for e801h memory size detection 
- * call.  As a result the kernel got wrong figures.  The int15/e801h docs
- * from Ralf Brown interrupt list seem to indicate AX/BX should be used
- * anyway.  So to avoid breaking many machines (presumably there was a reason
- * to orginally use CX/DX instead of AX/BX), we do a kludge to see
- * if CX/DX have been changed in the e801 call and if so use AX/BX .
- * Michael Miller, April 2001 <michaelm@mjmm.org>
- *
- * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
- * by Robert Schwebel, December 2001 <robert@schwebel.de>
- */
-
-#include <asm/segment.h>
-#include <linux/utsrelease.h>
-#include <linux/compile.h>
-#include <asm/boot.h>
-#include <asm/e820.h>
-#include <asm/page.h>
-#include <asm/setup.h>
-       
-/* Signature words to ensure LILO loaded us right */
-#define SIG1   0xAA55
-#define SIG2   0x5A5A
-
-INITSEG  = DEF_INITSEG         # 0x9000, we move boot here, out of the way
-SYSSEG   = DEF_SYSSEG          # 0x1000, system loaded at 0x10000 (65536).
-SETUPSEG = DEF_SETUPSEG                # 0x9020, this is the current segment
-                               # ... and the former contents of CS
-
-DELTA_INITSEG = SETUPSEG - INITSEG     # 0x0020
-
-.code16
-.globl begtext, begdata, begbss, endtext, enddata, endbss
-
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
-
-start:
-       jmp     trampoline
-
-# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
-
-               .ascii  "HdrS"          # header signature
-               .word   0x0206          # header version number (>= 0x0105)
-                                       # or else old loadlin-1.5 will fail)
-realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
-start_sys_seg: .word   SYSSEG
-               .word   kernel_version  # pointing to kernel version string
-                                       # above section of header is compatible
-                                       # with loadlin-1.5 (header v1.5). Don't
-                                       # change it.
-
-type_of_loader:        .byte   0               # = 0, old one (LILO, Loadlin,
-                                       #      Bootlin, SYSLX, bootsect...)
-                                       # See Documentation/i386/boot.txt for
-                                       # assigned ids
-       
-# flags, unused bits must be zero (RFU) bit within loadflags
-loadflags:
-LOADED_HIGH    = 1                     # If set, the kernel is loaded high
-CAN_USE_HEAP   = 0x80                  # If set, the loader also has set
-                                       # heap_end_ptr to tell how much
-                                       # space behind setup.S can be used for
-                                       # heap purposes.
-                                       # Only the loader knows what is free
-#ifndef __BIG_KERNEL__
-               .byte   0
-#else
-               .byte   LOADED_HIGH
-#endif
-
-setup_move_size: .word  0x8000         # size to move, when setup is not
-                                       # loaded at 0x90000. We will move setup 
-                                       # to 0x90000 then just before jumping
-                                       # into the kernel. However, only the
-                                       # loader knows how much data behind
-                                       # us also needs to be loaded.
-
-code32_start:                          # here loaders can put a different
-                                       # start address for 32-bit code.
-#ifndef __BIG_KERNEL__
-               .long   0x1000          #   0x1000 = default for zImage
-#else
-               .long   0x100000        # 0x100000 = default for big kernel
-#endif
-
-ramdisk_image: .long   0               # address of loaded ramdisk image
-                                       # Here the loader puts the 32-bit
-                                       # address where it loaded the image.
-                                       # This only will be read by the kernel.
-
-ramdisk_size:  .long   0               # its size in bytes
-
-bootsect_kludge:
-               .long   0               # obsolete
-
-heap_end_ptr:  .word   modelist+1024   # (Header version 0x0201 or later)
-                                       # space from here (exclusive) down to
-                                       # end of setup code can be used by setup
-                                       # for local heap purposes.
-
-pad1:          .word   0
-cmd_line_ptr:  .long 0                 # (Header version 0x0202 or later)
-                                       # If nonzero, a 32-bit pointer
-                                       # to the kernel command line.
-                                       # The command line should be
-                                       # located between the start of
-                                       # setup and the end of low
-                                       # memory (0xa0000), or it may
-                                       # get overwritten before it
-                                       # gets read.  If this field is
-                                       # used, there is no longer
-                                       # anything magical about the
-                                       # 0x90000 segment; the setup
-                                       # can be located anywhere in
-                                       # low memory 0x10000 or higher.
-
-ramdisk_max:   .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
-                                       # (Header version 0x0203 or later)
-                                       # The highest safe address for
-                                       # the contents of an initrd
-
-kernel_alignment:  .long CONFIG_PHYSICAL_ALIGN         #physical addr alignment
-                                               #required for protected mode
-                                               #kernel
-#ifdef CONFIG_RELOCATABLE
-relocatable_kernel:    .byte 1
-#else
-relocatable_kernel:    .byte 0
-#endif
-pad2:                  .byte 0
-pad3:                  .word 0
-
-cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
-                                                #added with boot protocol
-                                                #version 2.06
-
-trampoline:    call    start_of_setup
-               .align 16
-                                       # The offset at this point is 0x240
-               .space  (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff)
-# End of setup header #####################################################
-
-start_of_setup:
-# Bootlin depends on this being done early
-       movw    $0x01500, %ax
-       movb    $0x81, %dl
-       int     $0x13
-
-#ifdef SAFE_RESET_DISK_CONTROLLER
-# Reset the disk controller.
-       movw    $0x0000, %ax
-       movb    $0x80, %dl
-       int     $0x13
-#endif
-
-# Set %ds = %cs, we know that SETUPSEG = %cs at this point
-       movw    %cs, %ax                # aka SETUPSEG
-       movw    %ax, %ds
-# Check signature at end of setup
-       cmpw    $SIG1, setup_sig1
-       jne     bad_sig
-
-       cmpw    $SIG2, setup_sig2
-       jne     bad_sig
-
-       jmp     good_sig1
-
-# Routine to print asciiz string at ds:si
-prtstr:
-       lodsb
-       andb    %al, %al
-       jz      fin
-
-       call    prtchr
-       jmp     prtstr
-
-fin:   ret
-
-# Space printing
-prtsp2:        call    prtspc          # Print double space
-prtspc:        movb    $0x20, %al      # Print single space (note: fall-thru)
-
-# Part of above routine, this one just prints ascii al
-prtchr:        pushw   %ax
-       pushw   %cx
-       movw    $7,%bx
-       movw    $0x01, %cx
-       movb    $0x0e, %ah
-       int     $0x10
-       popw    %cx
-       popw    %ax
-       ret
-
-beep:  movb    $0x07, %al
-       jmp     prtchr
-       
-no_sig_mess: .string   "No setup signature found ..."
-
-good_sig1:
-       jmp     good_sig
-
-# We now have to find the rest of the setup code/data
-bad_sig:
-       movw    %cs, %ax                        # SETUPSEG
-       subw    $DELTA_INITSEG, %ax             # INITSEG
-       movw    %ax, %ds
-       xorb    %bh, %bh
-       movb    (497), %bl                      # get setup sect from bootsect
-       subw    $4, %bx                         # LILO loads 4 sectors of setup
-       shlw    $8, %bx                         # convert to words (1sect=2^8 words)
-       movw    %bx, %cx
-       shrw    $3, %bx                         # convert to segment
-       addw    $SYSSEG, %bx
-       movw    %bx, %cs:start_sys_seg
-# Move rest of setup code/data to here
-       movw    $2048, %di                      # four sectors loaded by LILO
-       subw    %si, %si
-       pushw   %cs
-       popw    %es
-       movw    $SYSSEG, %ax
-       movw    %ax, %ds
-       rep
-       movsw
-       movw    %cs, %ax                        # aka SETUPSEG
-       movw    %ax, %ds
-       cmpw    $SIG1, setup_sig1
-       jne     no_sig
-
-       cmpw    $SIG2, setup_sig2
-       jne     no_sig
-
-       jmp     good_sig
-
-no_sig:
-       lea     no_sig_mess, %si
-       call    prtstr
-
-no_sig_loop:
-       hlt
-       jmp     no_sig_loop
-
-good_sig:
-       movw    %cs, %ax                        # aka SETUPSEG
-       subw    $DELTA_INITSEG, %ax             # aka INITSEG
-       movw    %ax, %ds
-# Check if an old loader tries to load a big-kernel
-       testb   $LOADED_HIGH, %cs:loadflags     # Do we have a big kernel?
-       jz      loader_ok                       # No, no danger for old loaders.
-
-       cmpb    $0, %cs:type_of_loader          # Do we have a loader that
-                                               # can deal with us?
-       jnz     loader_ok                       # Yes, continue.
-
-       pushw   %cs                             # No, we have an old loader,
-       popw    %ds                             # die. 
-       lea     loader_panic_mess, %si
-       call    prtstr
-
-       jmp     no_sig_loop
-
-loader_panic_mess: .string "Wrong loader, giving up..."
-
-# check minimum cpuid
-# we do this here because it is the last place we can actually
-# show a user visible error message. Later the video modus
-# might be already messed up.
-loader_ok:
-       call verify_cpu
-       testl  %eax,%eax
-       jz      cpu_ok
-       movw    %cs,%ax         # aka SETUPSEG
-       movw    %ax,%ds
-       lea     cpu_panic_mess,%si
-       call    prtstr
-1:     jmp     1b
-
-cpu_panic_mess:
-       .asciz  "PANIC: CPU too old for this kernel."
-
-#include "../kernel/verify_cpu.S"
-
-cpu_ok:
-# Get memory size (extended mem, kB)
-
-       xorl    %eax, %eax
-       movl    %eax, (0x1e0)
-#ifndef STANDARD_MEMORY_BIOS_CALL
-       movb    %al, (E820NR)
-# Try three different memory detection schemes.  First, try
-# e820h, which lets us assemble a memory map, then try e801h,
-# which returns a 32-bit memory size, and finally 88h, which
-# returns 0-64m
-
-# method E820H:
-# the memory map from hell.  e820h returns memory classified into
-# a whole bunch of different types, and allows memory holes and
-# everything.  We scan through this memory map and build a list
-# of the first 32 memory areas, which we return at [E820MAP].
-# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
-
-#define SMAP  0x534d4150
-
-meme820:
-       xorl    %ebx, %ebx                      # continuation counter
-       movw    $E820MAP, %di                   # point into the whitelist
-                                               # so we can have the bios
-                                               # directly write into it.
-
-jmpe820:
-       movl    $0x0000e820, %eax               # e820, upper word zeroed
-       movl    $SMAP, %edx                     # ascii 'SMAP'
-       movl    $20, %ecx                       # size of the e820rec
-       pushw   %ds                             # data record.
-       popw    %es
-       int     $0x15                           # make the call
-       jc      bail820                         # fall to e801 if it fails
-
-       cmpl    $SMAP, %eax                     # check the return is `SMAP'
-       jne     bail820                         # fall to e801 if it fails
-
-#      cmpl    $1, 16(%di)                     # is this usable memory?
-#      jne     again820
-
-       # If this is usable memory, we save it by simply advancing %di by
-       # sizeof(e820rec).
-       #
-good820:
-       movb    (E820NR), %al                   # up to 128 entries
-       cmpb    $E820MAX, %al
-       jae     bail820
-
-       incb    (E820NR)
-       movw    %di, %ax
-       addw    $20, %ax
-       movw    %ax, %di
-again820:
-       cmpl    $0, %ebx                        # check to see if
-       jne     jmpe820                         # %ebx is set to EOF
-bail820:
-
-
-# method E801H:
-# memory size is in 1k chunksizes, to avoid confusing loadlin.
-# we store the 0xe801 memory size in a completely different place,
-# because it will most likely be longer than 16 bits.
-# (use 1e0 because that's what Larry Augustine uses in his
-# alternative new memory detection scheme, and it's sensible
-# to write everything into the same place.)
-
-meme801:
-       stc                                     # fix to work around buggy
-       xorw    %cx,%cx                         # BIOSes which don't clear/set
-       xorw    %dx,%dx                         # carry on pass/error of
-                                               # e801h memory size call
-                                               # or merely pass cx,dx though
-                                               # without changing them.
-       movw    $0xe801, %ax
-       int     $0x15
-       jc      mem88
-
-       cmpw    $0x0, %cx                       # Kludge to handle BIOSes
-       jne     e801usecxdx                     # which report their extended
-       cmpw    $0x0, %dx                       # memory in AX/BX rather than
-       jne     e801usecxdx                     # CX/DX.  The spec I have read
-       movw    %ax, %cx                        # seems to indicate AX/BX 
-       movw    %bx, %dx                        # are more reasonable anyway...
-
-e801usecxdx:
-       andl    $0xffff, %edx                   # clear sign extend
-       shll    $6, %edx                        # and go from 64k to 1k chunks
-       movl    %edx, (0x1e0)                   # store extended memory size
-       andl    $0xffff, %ecx                   # clear sign extend
-       addl    %ecx, (0x1e0)                   # and add lower memory into
-                                               # total size.
-
-# Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
-# 64mb, depending on the bios) in ax.
-mem88:
-
-#endif
-       movb    $0x88, %ah
-       int     $0x15
-       movw    %ax, (2)
-
-# Set the keyboard repeat rate to the max
-       movw    $0x0305, %ax
-       xorw    %bx, %bx
-       int     $0x16
-
-# Check for video adapter and its parameters and allow the
-# user to browse video modes.
-       call    video                           # NOTE: we need %ds pointing
-                                               # to bootsector
-
-# Get hd0 data...
-       xorw    %ax, %ax
-       movw    %ax, %ds
-       ldsw    (4 * 0x41), %si
-       movw    %cs, %ax                        # aka SETUPSEG
-       subw    $DELTA_INITSEG, %ax             # aka INITSEG
-       pushw   %ax
-       movw    %ax, %es
-       movw    $0x0080, %di
-       movw    $0x10, %cx
-       pushw   %cx
-       cld
-       rep
-       movsb
-# Get hd1 data...
-       xorw    %ax, %ax
-       movw    %ax, %ds
-       ldsw    (4 * 0x46), %si
-       popw    %cx
-       popw    %es
-       movw    $0x0090, %di
-       rep
-       movsb
-# Check that there IS a hd1 :-)
-       movw    $0x01500, %ax
-       movb    $0x81, %dl
-       int     $0x13
-       jc      no_disk1
-       
-       cmpb    $3, %ah
-       je      is_disk1
-
-no_disk1:
-       movw    %cs, %ax                        # aka SETUPSEG
-       subw    $DELTA_INITSEG, %ax             # aka INITSEG
-       movw    %ax, %es
-       movw    $0x0090, %di
-       movw    $0x10, %cx
-       xorw    %ax, %ax
-       cld
-       rep
-       stosb
-is_disk1:
-# check for Micro Channel (MCA) bus
-       movw    %cs, %ax                        # aka SETUPSEG
-       subw    $DELTA_INITSEG, %ax             # aka INITSEG
-       movw    %ax, %ds
-       xorw    %ax, %ax
-       movw    %ax, (0xa0)                     # set table length to 0
-       movb    $0xc0, %ah
-       stc
-       int     $0x15                           # moves feature table to es:bx
-       jc      no_mca
-
-       pushw   %ds
-       movw    %es, %ax
-       movw    %ax, %ds
-       movw    %cs, %ax                        # aka SETUPSEG
-       subw    $DELTA_INITSEG, %ax             # aka INITSEG
-       movw    %ax, %es
-       movw    %bx, %si
-       movw    $0xa0, %di
-       movw    (%si), %cx
-       addw    $2, %cx                         # table length is a short
-       cmpw    $0x10, %cx
-       jc      sysdesc_ok
-
-       movw    $0x10, %cx                      # we keep only first 16 bytes
-sysdesc_ok:
-       rep
-       movsb
-       popw    %ds
-no_mca:
-#ifdef CONFIG_X86_VOYAGER
-       movb    $0xff, 0x40     # flag on config found
-       movb    $0xc0, %al
-       mov     $0xff, %ah
-       int     $0x15           # put voyager config info at es:di
-       jc      no_voyager
-       movw    $0x40, %si      # place voyager info in apm table
-       cld
-       movw    $7, %cx
-voyager_rep:
-       movb    %es:(%di), %al
-       movb    %al,(%si)
-       incw    %di
-       incw    %si
-       decw    %cx
-       jnz     voyager_rep
-no_voyager:    
-#endif
-# Check for PS/2 pointing device
-       movw    %cs, %ax                        # aka SETUPSEG
-       subw    $DELTA_INITSEG, %ax             # aka INITSEG
-       movw    %ax, %ds
-       movb    $0, (0x1ff)                     # default is no pointing device
-       int     $0x11                           # int 0x11: equipment list
-       testb   $0x04, %al                      # check if mouse installed
-       jz      no_psmouse
-
-       movb    $0xAA, (0x1ff)                  # device present
-no_psmouse:
-
-#if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
-       movl    $0x0000E980, %eax               # IST Support 
-       movl    $0x47534943, %edx               # Request value
-       int     $0x15
-
-       movl    %eax, (96)
-       movl    %ebx, (100)
-       movl    %ecx, (104)
-       movl    %edx, (108)
-#endif
-
-#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
-# Then check for an APM BIOS...
-                                               # %ds points to the bootsector
-       movw    $0, 0x40                        # version = 0 means no APM BIOS
-       movw    $0x05300, %ax                   # APM BIOS installation check
-       xorw    %bx, %bx
-       int     $0x15
-       jc      done_apm_bios                   # Nope, no APM BIOS
-       
-       cmpw    $0x0504d, %bx                   # Check for "PM" signature
-       jne     done_apm_bios                   # No signature, no APM BIOS
-
-       andw    $0x02, %cx                      # Is 32 bit supported?
-       je      done_apm_bios                   # No 32-bit, no (good) APM BIOS
-
-       movw    $0x05304, %ax                   # Disconnect first just in case
-       xorw    %bx, %bx
-       int     $0x15                           # ignore return code
-       movw    $0x05303, %ax                   # 32 bit connect
-       xorl    %ebx, %ebx
-       xorw    %cx, %cx                        # paranoia :-)
-       xorw    %dx, %dx                        #   ...
-       xorl    %esi, %esi                      #   ...
-       xorw    %di, %di                        #   ...
-       int     $0x15
-       jc      no_32_apm_bios                  # Ack, error. 
-
-       movw    %ax,  (66)                      # BIOS code segment
-       movl    %ebx, (68)                      # BIOS entry point offset
-       movw    %cx,  (72)                      # BIOS 16 bit code segment
-       movw    %dx,  (74)                      # BIOS data segment
-       movl    %esi, (78)                      # BIOS code segment lengths
-       movw    %di,  (82)                      # BIOS data segment length
-# Redo the installation check as the 32 bit connect
-# modifies the flags returned on some BIOSs
-       movw    $0x05300, %ax                   # APM BIOS installation check
-       xorw    %bx, %bx
-       xorw    %cx, %cx                        # paranoia
-       int     $0x15
-       jc      apm_disconnect                  # error -> shouldn't happen
-
-       cmpw    $0x0504d, %bx                   # check for "PM" signature
-       jne     apm_disconnect                  # no sig -> shouldn't happen
-
-       movw    %ax, (64)                       # record the APM BIOS version
-       movw    %cx, (76)                       # and flags
-       jmp     done_apm_bios
-
-apm_disconnect:                                        # Tidy up
-       movw    $0x05304, %ax                   # Disconnect
-       xorw    %bx, %bx
-       int     $0x15                           # ignore return code
-
-       jmp     done_apm_bios
-
-no_32_apm_bios:
-       andw    $0xfffd, (76)                   # remove 32 bit support bit
-done_apm_bios:
-#endif
-
-#include "edd.S"
-
-# Now we want to move to protected mode ...
-       cmpw    $0, %cs:realmode_swtch
-       jz      rmodeswtch_normal
-
-       lcall   *%cs:realmode_swtch
-
-       jmp     rmodeswtch_end
-
-rmodeswtch_normal:
-        pushw  %cs
-       call    default_switch
-
-rmodeswtch_end:
-# Now we move the system to its rightful place ... but we check if we have a
-# big-kernel. In that case we *must* not move it ...
-       testb   $LOADED_HIGH, %cs:loadflags
-       jz      do_move0                        # .. then we have a normal low
-                                               # loaded zImage
-                                               # .. or else we have a high
-                                               # loaded bzImage
-       jmp     end_move                        # ... and we skip moving
-
-do_move0:
-       movw    $0x100, %ax                     # start of destination segment
-       movw    %cs, %bp                        # aka SETUPSEG
-       subw    $DELTA_INITSEG, %bp             # aka INITSEG
-       movw    %cs:start_sys_seg, %bx          # start of source segment
-       cld
-do_move:
-       movw    %ax, %es                        # destination segment
-       incb    %ah                             # instead of add ax,#0x100
-       movw    %bx, %ds                        # source segment
-       addw    $0x100, %bx
-       subw    %di, %di
-       subw    %si, %si
-       movw    $0x800, %cx
-       rep
-       movsw
-       cmpw    %bp, %bx                        # assume start_sys_seg > 0x200,
-                                               # so we will perhaps read one
-                                               # page more than needed, but
-                                               # never overwrite INITSEG
-                                               # because destination is a
-                                               # minimum one page below source
-       jb      do_move
-
-end_move:
-# then we load the segment descriptors
-       movw    %cs, %ax                        # aka SETUPSEG
-       movw    %ax, %ds
-               
-# Check whether we need to be downward compatible with version <=201
-       cmpl    $0, cmd_line_ptr
-       jne     end_move_self           # loader uses version >=202 features
-       cmpb    $0x20, type_of_loader
-       je      end_move_self           # bootsect loader, we know of it
-
-# Boot loader doesnt support boot protocol version 2.02.
-# If we have our code not at 0x90000, we need to move it there now.
-# We also then need to move the params behind it (commandline)
-# Because we would overwrite the code on the current IP, we move
-# it in two steps, jumping high after the first one.
-       movw    %cs, %ax
-       cmpw    $SETUPSEG, %ax
-       je      end_move_self
-
-       cli                                     # make sure we really have
-                                               # interrupts disabled !
-                                               # because after this the stack
-                                               # should not be used
-       subw    $DELTA_INITSEG, %ax             # aka INITSEG
-       movw    %ss, %dx
-       cmpw    %ax, %dx
-       jb      move_self_1
-
-       addw    $INITSEG, %dx
-       subw    %ax, %dx                        # this will go into %ss after
-                                               # the move
-move_self_1:
-       movw    %ax, %ds
-       movw    $INITSEG, %ax                   # real INITSEG
-       movw    %ax, %es
-       movw    %cs:setup_move_size, %cx
-       std                                     # we have to move up, so we use
-                                               # direction down because the
-                                               # areas may overlap
-       movw    %cx, %di
-       decw    %di
-       movw    %di, %si
-       subw    $move_self_here+0x200, %cx
-       rep
-       movsb
-       ljmp    $SETUPSEG, $move_self_here
-
-move_self_here:
-       movw    $move_self_here+0x200, %cx
-       rep
-       movsb
-       movw    $SETUPSEG, %ax
-       movw    %ax, %ds
-       movw    %dx, %ss
-end_move_self:                                 # now we are at the right place
-
-#
-# Enable A20.  This is at the very best an annoying procedure.
-# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
-# AMD Elan bug fix by Robert Schwebel.
-#
-
-#if defined(CONFIG_X86_ELAN)
-       movb $0x02, %al                 # alternate A20 gate
-       outb %al, $0x92                 # this works on SC410/SC520
-a20_elan_wait:
-       call a20_test
-       jz a20_elan_wait
-       jmp a20_done
-#endif
-
-
-A20_TEST_LOOPS         =  32           # Iterations per wait
-A20_ENABLE_LOOPS       = 255           # Total loops to try            
-
-
-#ifndef CONFIG_X86_VOYAGER
-a20_try_loop:
-
-       # First, see if we are on a system with no A20 gate.
-a20_none:
-       call    a20_test
-       jnz     a20_done
-
-       # Next, try the BIOS (INT 0x15, AX=0x2401)
-a20_bios:
-       movw    $0x2401, %ax
-       pushfl                                  # Be paranoid about flags
-       int     $0x15
-       popfl
-
-       call    a20_test
-       jnz     a20_done
-
-       # Try enabling A20 through the keyboard controller
-#endif /* CONFIG_X86_VOYAGER */
-a20_kbc:
-       call    empty_8042
-
-#ifndef CONFIG_X86_VOYAGER
-       call    a20_test                        # Just in case the BIOS worked
-       jnz     a20_done                        # but had a delayed reaction.
-#endif
-
-       movb    $0xD1, %al                      # command write
-       outb    %al, $0x64
-       call    empty_8042
-
-       movb    $0xDF, %al                      # A20 on
-       outb    %al, $0x60
-       call    empty_8042
-
-#ifndef CONFIG_X86_VOYAGER
-       # Wait until a20 really *is* enabled; it can take a fair amount of
-       # time on certain systems; Toshiba Tecras are known to have this
-       # problem.
-a20_kbc_wait:
-       xorw    %cx, %cx
-a20_kbc_wait_loop:
-       call    a20_test
-       jnz     a20_done
-       loop    a20_kbc_wait_loop
-
-       # Final attempt: use "configuration port A"
-a20_fast:
-       inb     $0x92, %al                      # Configuration Port A
-       orb     $0x02, %al                      # "fast A20" version
-       andb    $0xFE, %al                      # don't accidentally reset
-       outb    %al, $0x92
-
-       # Wait for configuration port A to take effect
-a20_fast_wait:
-       xorw    %cx, %cx
-a20_fast_wait_loop:
-       call    a20_test
-       jnz     a20_done
-       loop    a20_fast_wait_loop
-
-       # A20 is still not responding.  Try frobbing it again.
-       # 
-       decb    (a20_tries)
-       jnz     a20_try_loop
-       
-       movw    $a20_err_msg, %si
-       call    prtstr
-
-a20_die:
-       hlt
-       jmp     a20_die
-
-a20_tries:
-       .byte   A20_ENABLE_LOOPS
-
-a20_err_msg:
-       .ascii  "linux: fatal error: A20 gate not responding!"
-       .byte   13, 10, 0
-
-       # If we get here, all is good
-a20_done:
-
-#endif /* CONFIG_X86_VOYAGER */
-# set up gdt and idt and 32bit start address
-       lidt    idt_48                          # load idt with 0,0
-       xorl    %eax, %eax                      # Compute gdt_base
-       movw    %ds, %ax                        # (Convert %ds:gdt to a linear ptr)
-       shll    $4, %eax
-       addl    %eax, code32
-       addl    $gdt, %eax
-       movl    %eax, (gdt_48+2)
-       lgdt    gdt_48                          # load gdt with whatever is
-                                               # appropriate
-
-# make sure any possible coprocessor is properly reset..
-       xorw    %ax, %ax
-       outb    %al, $0xf0
-       call    delay
-
-       outb    %al, $0xf1
-       call    delay
-
-# well, that went ok, I hope. Now we mask all interrupts - the rest
-# is done in init_IRQ().
-       movb    $0xFF, %al                      # mask all interrupts for now
-       outb    %al, $0xA1
-       call    delay
-       
-       movb    $0xFB, %al                      # mask all irq's but irq2 which
-       outb    %al, $0x21                      # is cascaded
-
-# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
-# need no steenking BIOS anyway (except for the initial loading :-).
-# The BIOS-routine wants lots of unnecessary data, and it's less
-# "interesting" anyway. This is how REAL programmers do it.
-#
-# Well, now's the time to actually move into protected mode. To make
-# things as simple as possible, we do no register set-up or anything,
-# we let the gnu-compiled 32-bit programs do that. We just jump to
-# absolute address 0x1000 (or the loader supplied one),
-# in 32-bit protected mode.
-#
-# Note that the short jump isn't strictly needed, although there are
-# reasons why it might be a good idea. It won't hurt in any case.
-       movw    $1, %ax                         # protected mode (PE) bit
-       lmsw    %ax                             # This is it!
-       jmp     flush_instr
-
-flush_instr:
-       xorw    %bx, %bx                        # Flag to indicate a boot
-       xorl    %esi, %esi                      # Pointer to real-mode code
-       movw    %cs, %si
-       subw    $DELTA_INITSEG, %si
-       shll    $4, %esi                        # Convert to 32-bit pointer
-
-# jump to startup_32 in arch/i386/boot/compressed/head.S
-#      
-# NOTE: For high loaded big kernels we need a
-#      jmpi    0x100000,__BOOT_CS
-#
-#      but we yet haven't reloaded the CS register, so the default size 
-#      of the target offset still is 16 bit.
-#      However, using an operand prefix (0x66), the CPU will properly
-#      take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
-#      Manual, Mixing 16-bit and 32-bit code, page 16-6)
-
-       .byte 0x66, 0xea                        # prefix + jmpi-opcode
-code32:        .long   startup_32                      # will be set to %cs+startup_32
-       .word   __BOOT_CS
-.code32
-startup_32:
-       movl $(__BOOT_DS), %eax
-       movl %eax, %ds
-       movl %eax, %es
-       movl %eax, %fs
-       movl %eax, %gs
-       movl %eax, %ss
-
-       xorl %eax, %eax
-1:     incl %eax                               # check that A20 really IS enabled
-       movl %eax, 0x00000000                   # loop forever if it isn't
-       cmpl %eax, 0x00100000
-       je 1b
-
-       # Jump to the 32bit entry point
-       jmpl *(code32_start - start + (DELTA_INITSEG << 4))(%esi)
-.code16
-
-# Here's a bunch of information about your current kernel..
-kernel_version:        .ascii  UTS_RELEASE
-               .ascii  " ("
-               .ascii  LINUX_COMPILE_BY
-               .ascii  "@"
-               .ascii  LINUX_COMPILE_HOST
-               .ascii  ") "
-               .ascii  UTS_VERSION
-               .byte   0
-
-# This is the default real mode switch routine.
-# to be called just before protected mode transition
-default_switch:
-       cli                                     # no interrupts allowed !
-       movb    $0x80, %al                      # disable NMI for bootup
-                                               # sequence
-       outb    %al, $0x70
-       lret
-
-
-#ifndef CONFIG_X86_VOYAGER
-# This routine tests whether or not A20 is enabled.  If so, it
-# exits with zf = 0.
-#
-# The memory address used, 0x200, is the int $0x80 vector, which
-# should be safe.
-
-A20_TEST_ADDR = 4*0x80
-
-a20_test:
-       pushw   %cx
-       pushw   %ax
-       xorw    %cx, %cx
-       movw    %cx, %fs                        # Low memory
-       decw    %cx
-       movw    %cx, %gs                        # High memory area
-       movw    $A20_TEST_LOOPS, %cx
-       movw    %fs:(A20_TEST_ADDR), %ax
-       pushw   %ax
-a20_test_wait:
-       incw    %ax
-       movw    %ax, %fs:(A20_TEST_ADDR)
-       call    delay                           # Serialize and make delay constant
-       cmpw    %gs:(A20_TEST_ADDR+0x10), %ax
-       loope   a20_test_wait
-
-       popw    %fs:(A20_TEST_ADDR)
-       popw    %ax
-       popw    %cx
-       ret     
-
-#endif /* CONFIG_X86_VOYAGER */
-
-# This routine checks that the keyboard command queue is empty
-# (after emptying the output buffers)
-#
-# Some machines have delusions that the keyboard buffer is always full
-# with no keyboard attached...
-#
-# If there is no keyboard controller, we will usually get 0xff
-# to all the reads.  With each IO taking a microsecond and
-# a timeout of 100,000 iterations, this can take about half a
-# second ("delay" == outb to port 0x80). That should be ok,
-# and should also be plenty of time for a real keyboard controller
-# to empty.
-#
-
-empty_8042:
-       pushl   %ecx
-       movl    $100000, %ecx
-
-empty_8042_loop:
-       decl    %ecx
-       jz      empty_8042_end_loop
-
-       call    delay
-
-       inb     $0x64, %al                      # 8042 status port
-       testb   $1, %al                         # output buffer?
-       jz      no_output
-
-       call    delay
-       inb     $0x60, %al                      # read it
-       jmp     empty_8042_loop
-
-no_output:
-       testb   $2, %al                         # is input buffer full?
-       jnz     empty_8042_loop                 # yes - loop
-empty_8042_end_loop:
-       popl    %ecx
-       ret
-
-# Read the cmos clock. Return the seconds in al
-gettime:
-       pushw   %cx
-       movb    $0x02, %ah
-       int     $0x1a
-       movb    %dh, %al                        # %dh contains the seconds
-       andb    $0x0f, %al
-       movb    %dh, %ah
-       movb    $0x04, %cl
-       shrb    %cl, %ah
-       aad
-       popw    %cx
-       ret
-
-# Delay is needed after doing I/O
-delay:
-       outb    %al,$0x80
-       ret
-
-# Descriptor tables
-#
-# NOTE: The intel manual says gdt should be sixteen bytes aligned for
-# efficiency reasons.  However, there are machines which are known not
-# to boot with misaligned GDTs, so alter this at your peril!  If you alter
-# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
-# empty GDT entries (one for NULL and one reserved).
-#
-# NOTE:        On some CPUs, the GDT must be 8 byte aligned.  This is
-# true for the Voyager Quad CPU card which will not boot without
-# This directive.  16 byte aligment is recommended by intel.
-#
-       .align 16
-gdt:
-       .fill GDT_ENTRY_BOOT_CS,8,0
-
-       .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
-       .word   0                               # base address = 0
-       .word   0x9A00                          # code read/exec
-       .word   0x00CF                          # granularity = 4096, 386
-                                               #  (+5th nibble of limit)
-
-       .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
-       .word   0                               # base address = 0
-       .word   0x9200                          # data read/write
-       .word   0x00CF                          # granularity = 4096, 386
-                                               #  (+5th nibble of limit)
-gdt_end:
-       .align  4
-       
-       .word   0                               # alignment byte
-idt_48:
-       .word   0                               # idt limit = 0
-       .word   0, 0                            # idt base = 0L
-
-       .word   0                               # alignment byte
-gdt_48:
-       .word   gdt_end - gdt - 1               # gdt limit
-       .word   0, 0                            # gdt base (filled in later)
-
-# Include video setup & detection code
-
-#include "video.S"
-
-# Setup signature -- must be last
-setup_sig1:    .word   SIG1
-setup_sig2:    .word   SIG2
-
-# After this point, there is some free space which is used by the video mode
-# handling code to store the temporary mode table (not used by the kernel).
-
-modelist:
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
diff --git a/arch/i386/boot/setup.ld b/arch/i386/boot/setup.ld
new file mode 100644 (file)
index 0000000..df9234b
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * setup.ld
+ *
+ * Linker script for the i386 setup code
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+       . = 0;
+       .bstext         : { *(.bstext) }
+       .bsdata         : { *(.bsdata) }
+
+       . = 497;
+       .header         : { *(.header) }
+       .inittext       : { *(.inittext) }
+       .initdata       : { *(.initdata) }
+       .text           : { *(.text*) }
+
+       . = ALIGN(16);
+       .rodata         : { *(.rodata*) }
+
+       .videocards     : {
+               video_cards = .;
+               *(.videocards)
+               video_cards_end = .;
+       }
+
+       . = ALIGN(16);
+       .data           : { *(.data*) }
+
+       .signature      : {
+               setup_sig = .;
+               LONG(0x5a5aaa55)
+       }
+
+
+       . = ALIGN(16);
+       .bss            :
+       {
+               __bss_start = .;
+               *(.bss)
+               __bss_end = .;
+       }
+       . = ALIGN(16);
+       _end = .;
+
+       /DISCARD/ : { *(.note*) }
+
+       . = ASSERT(_end <= 0x8000, "Setup too big!");
+       . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
+}
diff --git a/arch/i386/boot/string.c b/arch/i386/boot/string.c
new file mode 100644 (file)
index 0000000..481a220
--- /dev/null
@@ -0,0 +1,52 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/string.c
+ *
+ * Very basic string functions
+ */
+
+#include "boot.h"
+
+int strcmp(const char *str1, const char *str2)
+{
+       const unsigned char *s1 = (const unsigned char *)str1;
+       const unsigned char *s2 = (const unsigned char *)str2;
+       int delta = 0;
+
+       while (*s1 || *s2) {
+               delta = *s2 - *s1;
+               if (delta)
+                       return delta;
+               s1++;
+               s2++;
+       }
+       return 0;
+}
+
+size_t strnlen(const char *s, size_t maxlen)
+{
+       const char *es = s;
+       while (*es && maxlen) {
+               es++;
+               maxlen--;
+       }
+
+       return (es - s);
+}
+
+unsigned int atou(const char *s)
+{
+       unsigned int i = 0;
+       while (isdigit(*s))
+               i = i * 10 + (*s++ - '0');
+       return i;
+}
index 05798419a6a93f25be4f347d2eea5e6f04e5ddf6..886f47d8a48883a4c3154ab8ffa3ea77f94f9ad9 100644 (file)
@@ -1,13 +1,12 @@
 /*
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1997 Martin Mares
+ *  Copyright (C) 2007 H. Peter Anvin
  */
 
 /*
  * This file builds a disk-image from three different files:
  *
- * - bootsect: compatibility mbr which prints an error message if
- *             someone tries to boot the kernel directly.
  * - setup: 8086 machine code, sets up system parm
  * - system: 80386 code for actual system
  *
@@ -21,6 +20,7 @@
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  * Cross compiling fixes by Gertjan van Wingerde, July 1996
  * Rewritten by Martin Mares, April 1997
+ * Substantially overhauled by H. Peter Anvin, April 2007
  */
 
 #include <stdio.h>
 #include <sys/sysmacros.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/mman.h>
 #include <asm/boot.h>
 
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long u32;
+typedef unsigned char  u8;
+typedef unsigned short u16;
+typedef unsigned long  u32;
 
 #define DEFAULT_MAJOR_ROOT 0
 #define DEFAULT_MINOR_ROOT 0
 
-/* Minimal number of setup sectors (see also bootsect.S) */
-#define SETUP_SECTS 4
+/* Minimal number of setup sectors */
+#define SETUP_SECT_MIN 5
+#define SETUP_SECT_MAX 64
 
-byte buf[1024];
-int fd;
+/* This must be large enough to hold the entire setup */
+u8 buf[SETUP_SECT_MAX*512];
 int is_big_kernel;
 
-void die(const char * str, ...)
+static void die(const char * str, ...)
 {
        va_list args;
        va_start(args, str);
@@ -57,15 +59,9 @@ void die(const char * str, ...)
        exit(1);
 }
 
-void file_open(const char *name)
+static void usage(void)
 {
-       if ((fd = open(name, O_RDONLY, 0)) < 0)
-               die("Unable to open `%s': %m", name);
-}
-
-void usage(void)
-{
-       die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
+       die("Usage: build [-b] setup system [rootdev] [> image]");
 }
 
 int main(int argc, char ** argv)
@@ -73,27 +69,30 @@ int main(int argc, char ** argv)
        unsigned int i, sz, setup_sectors;
        int c;
        u32 sys_size;
-       byte major_root, minor_root;
+       u8 major_root, minor_root;
        struct stat sb;
+       FILE *file;
+       int fd;
+       void *kernel;
 
        if (argc > 2 && !strcmp(argv[1], "-b"))
          {
            is_big_kernel = 1;
            argc--, argv++;
          }
-       if ((argc < 4) || (argc > 5))
+       if ((argc < 3) || (argc > 4))
                usage();
-       if (argc > 4) {
-               if (!strcmp(argv[4], "CURRENT")) {
+       if (argc > 3) {
+               if (!strcmp(argv[3], "CURRENT")) {
                        if (stat("/", &sb)) {
                                perror("/");
                                die("Couldn't stat /");
                        }
                        major_root = major(sb.st_dev);
                        minor_root = minor(sb.st_dev);
-               } else if (strcmp(argv[4], "FLOPPY")) {
-                       if (stat(argv[4], &sb)) {
-                               perror(argv[4]);
+               } else if (strcmp(argv[3], "FLOPPY")) {
+                       if (stat(argv[3], &sb)) {
+                               perror(argv[3]);
                                die("Couldn't stat root device.");
                        }
                        major_root = major(sb.st_rdev);
@@ -108,79 +107,62 @@ int main(int argc, char ** argv)
        }
        fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
 
-       file_open(argv[1]);
-       i = read(fd, buf, sizeof(buf));
-       fprintf(stderr,"Boot sector %d bytes.\n",i);
-       if (i != 512)
-               die("Boot block must be exactly 512 bytes");
+       /* Copy the setup code */
+       file = fopen(argv[1], "r");
+       if (!file)
+               die("Unable to open `%s': %m", argv[1]);
+       c = fread(buf, 1, sizeof(buf), file);
+       if (ferror(file))
+               die("read-error on `setup'");
+       if (c < 1024)
+               die("The setup must be at least 1024 bytes");
        if (buf[510] != 0x55 || buf[511] != 0xaa)
                die("Boot block hasn't got boot flag (0xAA55)");
+       fclose(file);
+
+       /* Pad unused space with zeros */
+       setup_sectors = (c + 511) / 512;
+       if (setup_sectors < SETUP_SECT_MIN)
+               setup_sectors = SETUP_SECT_MIN;
+       i = setup_sectors*512;
+       memset(buf+c, 0, i-c);
+
+       /* Set the default root device */
        buf[508] = minor_root;
        buf[509] = major_root;
-       if (write(1, buf, 512) != 512)
-               die("Write call failed");
-       close (fd);
-
-       file_open(argv[2]);                                 /* Copy the setup code */
-       for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )
-               if (write(1, buf, c) != c)
-                       die("Write call failed");
-       if (c != 0)
-               die("read-error on `setup'");
-       close (fd);
-
-       setup_sectors = (i + 511) / 512;        /* Pad unused space with zeros */
-       /* for compatibility with ancient versions of LILO. */
-       if (setup_sectors < SETUP_SECTS)
-               setup_sectors = SETUP_SECTS;
-       fprintf(stderr, "Setup is %d bytes.\n", i);
-       memset(buf, 0, sizeof(buf));
-       while (i < setup_sectors * 512) {
-               c = setup_sectors * 512 - i;
-               if (c > sizeof(buf))
-                       c = sizeof(buf);
-               if (write(1, buf, c) != c)
-                       die("Write call failed");
-               i += c;
-       }
 
-       file_open(argv[3]);
-       if (fstat (fd, &sb))
-               die("Unable to stat `%s': %m", argv[3]);
+       fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
+
+       /* Open and stat the kernel file */
+       fd = open(argv[2], O_RDONLY);
+       if (fd < 0)
+               die("Unable to open `%s': %m", argv[2]);
+       if (fstat(fd, &sb))
+               die("Unable to stat `%s': %m", argv[2]);
        sz = sb.st_size;
-       fprintf (stderr, "System is %d kB\n", sz/1024);
+       fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
+       kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
+       if (kernel == MAP_FAILED)
+               die("Unable to mmap '%s': %m", argv[2]);
        sys_size = (sz + 15) / 16;
        if (!is_big_kernel && sys_size > DEF_SYSSIZE)
                die("System is too big. Try using bzImage or modules.");
-       while (sz > 0) {
-               int l, n;
-
-               l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
-               if ((n=read(fd, buf, l)) != l) {
-                       if (n < 0)
-                               die("Error reading %s: %m", argv[3]);
-                       else
-                               die("%s: Unexpected EOF", argv[3]);
-               }
-               if (write(1, buf, l) != l)
-                       die("Write failed");
-               sz -= l;
-       }
+
+       /* Patch the setup code with the appropriate size parameters */
+       buf[0x1f1] = setup_sectors-1;
+       buf[0x1f4] = sys_size;
+       buf[0x1f5] = sys_size >> 8;
+       buf[0x1f6] = sys_size >> 16;
+       buf[0x1f7] = sys_size >> 24;
+
+       if (fwrite(buf, 1, i, stdout) != i)
+               die("Writing setup failed");
+
+       /* Copy the kernel code */
+       if (fwrite(kernel, 1, sz, stdout) != sz)
+               die("Writing kernel failed");
        close(fd);
 
-       if (lseek(1, 497, SEEK_SET) != 497)                 /* Write sizes to the bootsector */
-               die("Output: seek failed");
-       buf[0] = setup_sectors;
-       if (write(1, buf, 1) != 1)
-               die("Write of setup sector count failed");
-       if (lseek(1, 500, SEEK_SET) != 500)
-               die("Output: seek failed");
-       buf[0] = (sys_size & 0xff);
-       buf[1] = ((sys_size >> 8) & 0xff);
-       buf[2] = ((sys_size >> 16) & 0xff);
-       buf[3] = ((sys_size >> 24) & 0xff);
-       if (write(1, buf, 4) != 4)
-               die("Write of image length failed");
-
-       return 0;                                           /* Everything is OK */
+       /* Everything is OK */
+       return 0;
 }
diff --git a/arch/i386/boot/tty.c b/arch/i386/boot/tty.c
new file mode 100644 (file)
index 0000000..a8db787
--- /dev/null
@@ -0,0 +1,112 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/tty.c
+ *
+ * Very simple screen I/O
+ * XXX: Probably should add very simple serial I/O?
+ */
+
+#include "boot.h"
+
+/*
+ * These functions are in .inittext so they can be used to signal
+ * error during initialization.
+ */
+
+void __attribute__((section(".inittext"))) putchar(int ch)
+{
+       unsigned char c = ch;
+
+       if (c == '\n')
+               putchar('\r');  /* \n -> \r\n */
+
+       /* int $0x10 is known to have bugs involving touching registers
+          it shouldn't.  Be extra conservative... */
+       asm volatile("pushal; int $0x10; popal"
+                    : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
+}
+
+void __attribute__((section(".inittext"))) puts(const char *str)
+{
+       int n = 0;
+       while (*str) {
+               putchar(*str++);
+               n++;
+       }
+}
+
+/*
+ * Read the CMOS clock through the BIOS, and return the
+ * seconds in BCD.
+ */
+
+static u8 gettime(void)
+{
+       u16 ax = 0x0200;
+       u16 cx, dx;
+
+       asm("int $0x1a"
+           : "+a" (ax), "=c" (cx), "=d" (dx)
+           : : "ebx", "esi", "edi");
+
+       return dx >> 8;
+}
+
+/*
+ * Read from the keyboard
+ */
+int getchar(void)
+{
+       u16 ax = 0;
+       asm("int $0x16" : "+a" (ax));
+
+       return ax & 0xff;
+}
+
+static int kbd_pending(void)
+{
+       u8 pending;
+       asm("int $0x16; setnz %0"
+           : "=rm" (pending)
+           : "a" (0x0100));
+       return pending;
+}
+
+void kbd_flush(void)
+{
+       for (;;) {
+               if (!kbd_pending())
+                       break;
+               getchar();
+       }
+}
+
+int getchar_timeout(void)
+{
+       int cnt = 30;
+       int t0, t1;
+
+       t0 = gettime();
+
+       while (cnt) {
+               if (kbd_pending())
+                       return getchar();
+
+               t1 = gettime();
+               if (t0 != t1) {
+                       cnt--;
+                       t0 = t1;
+               }
+       }
+
+       return 0;               /* Timeout! */
+}
diff --git a/arch/i386/boot/version.c b/arch/i386/boot/version.c
new file mode 100644 (file)
index 0000000..c61462f
--- /dev/null
@@ -0,0 +1,23 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/version.c
+ *
+ * Kernel version string
+ */
+
+#include "boot.h"
+#include <linux/utsrelease.h>
+#include <linux/compile.h>
+
+const char kernel_version[] =
+       UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") "
+       UTS_VERSION;
diff --git a/arch/i386/boot/vesa.h b/arch/i386/boot/vesa.h
new file mode 100644 (file)
index 0000000..ff5b73c
--- /dev/null
@@ -0,0 +1,79 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 1999-2007 H. Peter Anvin - All Rights Reserved
+ *
+ *   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, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef BOOT_VESA_H
+#define BOOT_VESA_H
+
+typedef struct {
+       u16 off, seg;
+} far_ptr;
+
+/* VESA General Information table */
+struct vesa_general_info {
+       u32 signature;          /* 0 Magic number = "VESA" */
+       u16 version;            /* 4 */
+       far_ptr vendor_string;  /* 6 */
+       u32 capabilities;       /* 10 */
+       far_ptr video_mode_ptr; /* 14 */
+       u16 total_memory;       /* 18 */
+
+       u16 oem_software_rev;   /* 20 */
+       far_ptr oem_vendor_name_ptr;    /* 22 */
+       far_ptr oem_product_name_ptr;   /* 26 */
+       far_ptr oem_product_rev_ptr;    /* 30 */
+
+       u8 reserved[222];       /* 34 */
+       u8 oem_data[256];       /* 256 */
+} __attribute__ ((packed));
+
+#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24))
+#define VBE2_MAGIC ('V' + ('B' << 8) + ('E' << 16) + ('2' << 24))
+
+struct vesa_mode_info {
+       u16 mode_attr;          /* 0 */
+       u8 win_attr[2];         /* 2 */
+       u16 win_grain;          /* 4 */
+       u16 win_size;           /* 6 */
+       u16 win_seg[2];         /* 8 */
+       far_ptr win_scheme;     /* 12 */
+       u16 logical_scan;       /* 16 */
+
+       u16 h_res;              /* 18 */
+       u16 v_res;              /* 20 */
+       u8 char_width;          /* 22 */
+       u8 char_height;         /* 23 */
+       u8 memory_planes;       /* 24 */
+       u8 bpp;                 /* 25 */
+       u8 banks;               /* 26 */
+       u8 memory_layout;       /* 27 */
+       u8 bank_size;           /* 28 */
+       u8 image_planes;        /* 29 */
+       u8 page_function;       /* 30 */
+
+       u8 rmask;               /* 31 */
+       u8 rpos;                /* 32 */
+       u8 gmask;               /* 33 */
+       u8 gpos;                /* 34 */
+       u8 bmask;               /* 35 */
+       u8 bpos;                /* 36 */
+       u8 resv_mask;           /* 37 */
+       u8 resv_pos;            /* 38 */
+       u8 dcm_info;            /* 39 */
+
+       u32 lfb_ptr;            /* 40 Linear frame buffer address */
+       u32 offscreen_ptr;      /* 44 Offscreen memory address */
+       u16 offscreen_size;     /* 48 */
+
+       u8 reserved[206];       /* 50 */
+} __attribute__ ((packed));
+
+#endif                         /* LIB_SYS_VESA_H */
diff --git a/arch/i386/boot/video-bios.c b/arch/i386/boot/video-bios.c
new file mode 100644 (file)
index 0000000..afea46c
--- /dev/null
@@ -0,0 +1,125 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/video-bios.c
+ *
+ * Standard video BIOS modes
+ *
+ * We have two options for this; silent and scanned.
+ */
+
+#include "boot.h"
+#include "video.h"
+
+__videocard video_bios;
+
+/* Set a conventional BIOS mode */
+static int set_bios_mode(u8 mode);
+
+static int bios_set_mode(struct mode_info *mi)
+{
+       return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS);
+}
+
+static int set_bios_mode(u8 mode)
+{
+       u16 ax;
+       u8 new_mode;
+
+       ax = mode;              /* AH=0x00 Set Video Mode */
+       asm volatile(INT10
+                    : "+a" (ax)
+                    : : "ebx", "ecx", "edx", "esi", "edi");
+
+       ax = 0x0f00;            /* Get Current Video Mode */
+       asm volatile(INT10
+                    : "+a" (ax)
+                    : : "ebx", "ecx", "edx", "esi", "edi");
+
+       do_restore = 1;         /* Assume video contents was lost */
+       new_mode = ax & 0x7f;   /* Not all BIOSes are clean with the top bit */
+
+       if (new_mode == mode)
+               return 0;       /* Mode change OK */
+
+       if (new_mode != boot_params.screen_info.orig_video_mode) {
+               /* Mode setting failed, but we didn't end up where we
+                  started.  That's bad.  Try to revert to the original
+                  video mode. */
+               ax = boot_params.screen_info.orig_video_mode;
+               asm volatile(INT10
+                            : "+a" (ax)
+                            : : "ebx", "ecx", "edx", "esi", "edi");
+       }
+       return -1;
+}
+
+static int bios_probe(void)
+{
+       u8 mode;
+       u8 saved_mode = boot_params.screen_info.orig_video_mode;
+       u16 crtc;
+       struct mode_info *mi;
+       int nmodes = 0;
+
+       if (adapter != ADAPTER_EGA && adapter != ADAPTER_VGA)
+               return 0;
+
+       set_fs(0);
+       crtc = vga_crtc();
+
+       video_bios.modes = GET_HEAP(struct mode_info, 0);
+
+       for (mode = 0x14; mode <= 0x7f; mode++) {
+               if (heap_free() < sizeof(struct mode_info))
+                       break;
+
+               if (mode_defined(VIDEO_FIRST_BIOS+mode))
+                       continue;
+
+               if (set_bios_mode(mode))
+                       continue;
+
+               /* Try to verify that it's a text mode. */
+
+               /* Attribute Controller: make graphics controller disabled */
+               if (in_idx(0x3c0, 0x10) & 0x01)
+                       continue;
+
+               /* Graphics Controller: verify Alpha addressing enabled */
+               if (in_idx(0x3ce, 0x06) & 0x01)
+                       continue;
+
+               /* CRTC cursor location low should be zero(?) */
+               if (in_idx(crtc, 0x0f))
+                       continue;
+
+               mi = GET_HEAP(struct mode_info, 1);
+               mi->mode = VIDEO_FIRST_BIOS+mode;
+               mi->x = rdfs16(0x44a);
+               mi->y = rdfs8(0x484)+1;
+               nmodes++;
+       }
+
+       set_bios_mode(saved_mode);
+
+       return nmodes;
+}
+
+__videocard video_bios =
+{
+       .card_name      = "BIOS (scanned)",
+       .probe          = bios_probe,
+       .set_mode       = bios_set_mode,
+       .unsafe         = 1,
+       .xmode_first    = VIDEO_FIRST_BIOS,
+       .xmode_n        = 0x80,
+};
diff --git a/arch/i386/boot/video-vesa.c b/arch/i386/boot/video-vesa.c
new file mode 100644 (file)
index 0000000..e6aa9eb
--- /dev/null
@@ -0,0 +1,284 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/video-vesa.c
+ *
+ * VESA text modes
+ */
+
+#include "boot.h"
+#include "video.h"
+#include "vesa.h"
+
+/* VESA information */
+static struct vesa_general_info vginfo;
+static struct vesa_mode_info vminfo;
+
+__videocard video_vesa;
+
+static void vesa_store_mode_params_graphics(void);
+
+static int vesa_probe(void)
+{
+#if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID)
+       u16 ax;
+       u16 mode;
+       addr_t mode_ptr;
+       struct mode_info *mi;
+       int nmodes = 0;
+
+       video_vesa.modes = GET_HEAP(struct mode_info, 0);
+
+       vginfo.signature = VBE2_MAGIC;
+
+       /* Optimistically assume a VESA BIOS is register-clean... */
+       ax = 0x4f00;
+       asm("int $0x10" : "+a" (ax), "=m" (vginfo) : "D" (&vginfo));
+
+       if (ax != 0x004f ||
+           vginfo.signature != VESA_MAGIC ||
+           vginfo.version < 0x0102)
+               return 0;       /* Not present */
+#endif /* CONFIG_VIDEO_VESA || CONFIG_FIRMWARE_EDID */
+#ifdef CONFIG_VIDEO_VESA
+       set_fs(vginfo.video_mode_ptr.seg);
+       mode_ptr = vginfo.video_mode_ptr.off;
+
+       while ((mode = rdfs16(mode_ptr)) != 0xffff) {
+               mode_ptr += 2;
+
+               if (heap_free() < sizeof(struct mode_info))
+                       break;  /* Heap full, can't save mode info */
+
+               if (mode & ~0x1ff)
+                       continue;
+
+               memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
+
+               ax = 0x4f01;
+               asm("int $0x10"
+                   : "+a" (ax), "=m" (vminfo)
+                   : "c" (mode), "D" (&vminfo));
+
+               if (ax != 0x004f)
+                       continue;
+
+               if ((vminfo.mode_attr & 0x15) == 0x05) {
+                       /* Text Mode, TTY BIOS supported,
+                          supported by hardware */
+                       mi = GET_HEAP(struct mode_info, 1);
+                       mi->mode = mode + VIDEO_FIRST_VESA;
+                       mi->x    = vminfo.h_res;
+                       mi->y    = vminfo.v_res;
+                       nmodes++;
+               } else if ((vminfo.mode_attr & 0x99) == 0x99) {
+#ifdef CONFIG_FB
+                       /* Graphics mode, color, linear frame buffer
+                          supported -- register the mode but hide from
+                          the menu.  Only do this if framebuffer is
+                          configured, however, otherwise the user will
+                          be left without a screen. */
+                       mi = GET_HEAP(struct mode_info, 1);
+                       mi->mode = mode + VIDEO_FIRST_VESA;
+                       mi->x = mi->y = 0;
+                       nmodes++;
+#endif
+               }
+       }
+
+       return nmodes;
+#else
+       return 0;
+#endif /* CONFIG_VIDEO_VESA */
+}
+
+static int vesa_set_mode(struct mode_info *mode)
+{
+       u16 ax;
+       int is_graphic;
+       u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA;
+
+       memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
+
+       ax = 0x4f01;
+       asm("int $0x10"
+           : "+a" (ax), "=m" (vminfo)
+           : "c" (vesa_mode), "D" (&vminfo));
+
+       if (ax != 0x004f)
+               return -1;
+
+       if ((vminfo.mode_attr & 0x15) == 0x05) {
+               /* It's a supported text mode */
+               is_graphic = 0;
+       } else if ((vminfo.mode_attr & 0x99) == 0x99) {
+               /* It's a graphics mode with linear frame buffer */
+               is_graphic = 1;
+               vesa_mode |= 0x4000; /* Request linear frame buffer */
+       } else {
+               return -1;      /* Invalid mode */
+       }
+
+
+       ax = 0x4f02;
+       asm volatile("int $0x10"
+                    : "+a" (ax)
+                    : "b" (vesa_mode), "D" (0));
+
+       if (ax != 0x004f)
+               return -1;
+
+       graphic_mode = is_graphic;
+       if (!is_graphic) {
+               /* Text mode */
+               force_x = mode->x;
+               force_y = mode->y;
+               do_restore = 1;
+       } else {
+               /* Graphics mode */
+               vesa_store_mode_params_graphics();
+       }
+
+       return 0;
+}
+
+
+/* Switch DAC to 8-bit mode */
+static void vesa_dac_set_8bits(void)
+{
+       u8 dac_size = 6;
+
+       /* If possible, switch the DAC to 8-bit mode */
+       if (vginfo.capabilities & 1) {
+               u16 ax, bx;
+
+               ax = 0x4f08;
+               bx = 0x0800;
+               asm volatile(INT10
+                            : "+a" (ax), "+b" (bx)
+                            : : "ecx", "edx", "esi", "edi");
+
+               if (ax == 0x004f)
+                       dac_size = bx >> 8;
+       }
+
+       /* Set the color sizes to the DAC size, and offsets to 0 */
+       boot_params.screen_info.red_size = dac_size;
+       boot_params.screen_info.green_size = dac_size;
+       boot_params.screen_info.blue_size = dac_size;
+       boot_params.screen_info.rsvd_size = dac_size;
+
+       boot_params.screen_info.red_pos = 0;
+       boot_params.screen_info.green_pos = 0;
+       boot_params.screen_info.blue_pos = 0;
+       boot_params.screen_info.rsvd_pos = 0;
+}
+
+/* Save the VESA protected mode info */
+static void vesa_store_pm_info(void)
+{
+       u16 ax, bx, di, es;
+
+       ax = 0x4f0a;
+       bx = di = 0;
+       asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es"
+           : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di)
+           : : "ecx", "esi");
+
+       if (ax != 0x004f)
+               return;
+
+       boot_params.screen_info.vesapm_seg = es;
+       boot_params.screen_info.vesapm_off = di;
+}
+
+/*
+ * Save video mode parameters for graphics mode
+ */
+static void vesa_store_mode_params_graphics(void)
+{
+       /* Tell the kernel we're in VESA graphics mode */
+       boot_params.screen_info.orig_video_isVGA = 0x23;
+
+       /* Mode parameters */
+       boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
+       boot_params.screen_info.lfb_linelength = vminfo.logical_scan;
+       boot_params.screen_info.lfb_width = vminfo.h_res;
+       boot_params.screen_info.lfb_height = vminfo.v_res;
+       boot_params.screen_info.lfb_depth = vminfo.bpp;
+       boot_params.screen_info.pages = vminfo.image_planes;
+       boot_params.screen_info.lfb_base = vminfo.lfb_ptr;
+       memcpy(&boot_params.screen_info.red_size,
+              &vminfo.rmask, 8);
+
+       /* General parameters */
+       boot_params.screen_info.lfb_size = vginfo.total_memory;
+
+       if (vminfo.bpp <= 8)
+               vesa_dac_set_8bits();
+
+       vesa_store_pm_info();
+}
+
+/*
+ * Save EDID information for the kernel; this is invoked, separately,
+ * after mode-setting.
+ */
+void vesa_store_edid(void)
+{
+#ifdef CONFIG_FIRMWARE_EDID
+       u16 ax, bx, cx, dx, di;
+
+       /* Apparently used as a nonsense token... */
+       memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info);
+
+       if (vginfo.version < 0x0200)
+               return;         /* EDID requires VBE 2.0+ */
+
+       ax = 0x4f15;            /* VBE DDC */
+       bx = 0x0000;            /* Report DDC capabilities */
+       cx = 0;                 /* Controller 0 */
+       di = 0;                 /* ES:DI must be 0 by spec */
+
+       /* Note: The VBE DDC spec is different from the main VESA spec;
+          we genuinely have to assume all registers are destroyed here. */
+
+       asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es"
+           : "+a" (ax), "+b" (bx)
+           :  "c" (cx), "D" (di)
+           : "esi");
+
+       if (ax != 0x004f)
+               return;         /* No EDID */
+
+       /* BH = time in seconds to transfer EDD information */
+       /* BL = DDC level supported */
+
+       ax = 0x4f15;            /* VBE DDC */
+       bx = 0x0001;            /* Read EDID */
+       cx = 0;                 /* Controller 0 */
+       dx = 0;                 /* EDID block number */
+       di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */
+       asm(INT10
+           : "+a" (ax), "+b" (bx), "+d" (dx)
+           : "c" (cx), "D" (di)
+           : "esi");
+#endif /* CONFIG_FIRMWARE_EDID */
+}
+
+__videocard video_vesa =
+{
+       .card_name      = "VESA",
+       .probe          = vesa_probe,
+       .set_mode       = vesa_set_mode,
+       .xmode_first    = VIDEO_FIRST_VESA,
+       .xmode_n        = 0x200,
+};
diff --git a/arch/i386/boot/video-vga.c b/arch/i386/boot/video-vga.c
new file mode 100644 (file)
index 0000000..700d09a
--- /dev/null
@@ -0,0 +1,260 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/video-vga.c
+ *
+ * Common all-VGA modes
+ */
+
+#include "boot.h"
+#include "video.h"
+
+static struct mode_info vga_modes[] = {
+       { VIDEO_80x25,  80, 25 },
+       { VIDEO_8POINT, 80, 50 },
+       { VIDEO_80x43,  80, 43 },
+       { VIDEO_80x28,  80, 28 },
+       { VIDEO_80x30,  80, 30 },
+       { VIDEO_80x34,  80, 34 },
+       { VIDEO_80x60,  80, 60 },
+};
+
+static struct mode_info ega_modes[] = {
+       { VIDEO_80x25,  80, 25 },
+       { VIDEO_8POINT, 80, 43 },
+};
+
+static struct mode_info cga_modes[] = {
+       { VIDEO_80x25,  80, 25 },
+};
+
+__videocard video_vga;
+
+/* Set basic 80x25 mode */
+static u8 vga_set_basic_mode(void)
+{
+       u16 ax;
+       u8 rows;
+       u8 mode;
+
+#ifdef CONFIG_VIDEO_400_HACK
+       if (adapter >= ADAPTER_VGA) {
+               asm(INT10
+                   : : "a" (0x1202), "b" (0x0030)
+                   : "ecx", "edx", "esi", "edi");
+       }
+#endif
+
+       ax = 0x0f00;
+       asm(INT10
+           : "+a" (ax)
+           : : "ebx", "ecx", "edx", "esi", "edi");
+
+       mode = (u8)ax;
+
+       set_fs(0);
+       rows = rdfs8(0x484);    /* rows minus one */
+
+#ifndef CONFIG_VIDEO_400_HACK
+       if ((ax == 0x5003 || ax == 0x5007) &&
+           (rows == 0 || rows == 24))
+               return mode;
+#endif
+
+       if (mode != 3 && mode != 7)
+               mode = 3;
+
+       /* Set the mode */
+       asm volatile(INT10
+                    : : "a" (mode)
+                    : "ebx", "ecx", "edx", "esi", "edi");
+       do_restore = 1;
+       return mode;
+}
+
+static void vga_set_8font(void)
+{
+       /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
+
+       /* Set 8x8 font */
+       asm volatile(INT10 : : "a" (0x1112), "b" (0));
+
+       /* Use alternate print screen */
+       asm volatile(INT10 : : "a" (0x1200), "b" (0x20));
+
+       /* Turn off cursor emulation */
+       asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
+
+       /* Cursor is scan lines 6-7 */
+       asm volatile(INT10 : : "a" (0x0100), "c" (0x0607));
+}
+
+static void vga_set_14font(void)
+{
+       /* Set 9x14 font - 80x28 on VGA */
+
+       /* Set 9x14 font */
+       asm volatile(INT10 : : "a" (0x1111), "b" (0));
+
+       /* Turn off cursor emulation */
+       asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
+
+       /* Cursor is scan lines 11-12 */
+       asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c));
+}
+
+static void vga_set_80x43(void)
+{
+       /* Set 80x43 mode on VGA (not EGA) */
+
+       /* Set 350 scans */
+       asm volatile(INT10 : : "a" (0x1201), "b" (0x30));
+
+       /* Reset video mode */
+       asm volatile(INT10 : : "a" (0x0003));
+
+       vga_set_8font();
+}
+
+/* I/O address of the VGA CRTC */
+u16 vga_crtc(void)
+{
+       return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
+}
+
+static void vga_set_480_scanlines(int end)
+{
+       u16 crtc;
+       u8  csel;
+
+       crtc = vga_crtc();
+
+       out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
+       out_idx(0x0b, crtc, 0x06); /* Vertical total */
+       out_idx(0x3e, crtc, 0x07); /* Vertical overflow */
+       out_idx(0xea, crtc, 0x10); /* Vertical sync start */
+       out_idx(end, crtc, 0x12); /* Vertical display end */
+       out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
+       out_idx(0x04, crtc, 0x16); /* Vertical blank end */
+       csel = inb(0x3cc);
+       csel &= 0x0d;
+       csel |= 0xe2;
+       outb(csel, 0x3cc);
+}
+
+static void vga_set_80x30(void)
+{
+       vga_set_480_scanlines(0xdf);
+}
+
+static void vga_set_80x34(void)
+{
+       vga_set_14font();
+       vga_set_480_scanlines(0xdb);
+}
+
+static void vga_set_80x60(void)
+{
+       vga_set_8font();
+       vga_set_480_scanlines(0xdf);
+}
+
+static int vga_set_mode(struct mode_info *mode)
+{
+       /* Set the basic mode */
+       vga_set_basic_mode();
+
+       /* Override a possibly broken BIOS */
+       force_x = mode->x;
+       force_y = mode->y;
+
+       switch (mode->mode) {
+       case VIDEO_80x25:
+               break;
+       case VIDEO_8POINT:
+               vga_set_8font();
+               break;
+       case VIDEO_80x43:
+               vga_set_80x43();
+               break;
+       case VIDEO_80x28:
+               vga_set_14font();
+               break;
+       case VIDEO_80x30:
+               vga_set_80x30();
+               break;
+       case VIDEO_80x34:
+               vga_set_80x34();
+               break;
+       case VIDEO_80x60:
+               vga_set_80x60();
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * Note: this probe includes basic information required by all
+ * systems.  It should be executed first, by making sure
+ * video-vga.c is listed first in the Makefile.
+ */
+static int vga_probe(void)
+{
+       static const char *card_name[] = {
+               "CGA/MDA/HGC", "EGA", "VGA"
+       };
+       static struct mode_info *mode_lists[] = {
+               cga_modes,
+               ega_modes,
+               vga_modes,
+       };
+       static int mode_count[] = {
+               sizeof(cga_modes)/sizeof(struct mode_info),
+               sizeof(ega_modes)/sizeof(struct mode_info),
+               sizeof(vga_modes)/sizeof(struct mode_info),
+       };
+       u8 vga_flag;
+
+       asm(INT10
+           : "=b" (boot_params.screen_info.orig_video_ega_bx)
+           : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
+           : "ecx", "edx", "esi", "edi");
+
+       /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
+       if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) {
+               /* EGA/VGA */
+               asm(INT10
+                   : "=a" (vga_flag)
+                   : "a" (0x1a00)
+                   : "ebx", "ecx", "edx", "esi", "edi");
+
+               if (vga_flag == 0x1a) {
+                       adapter = ADAPTER_VGA;
+                       boot_params.screen_info.orig_video_isVGA = 1;
+               } else {
+                       adapter = ADAPTER_EGA;
+               }
+       } else {
+               adapter = ADAPTER_CGA;
+       }
+
+       video_vga.modes = mode_lists[adapter];
+       video_vga.card_name = card_name[adapter];
+       return mode_count[adapter];
+}
+
+__videocard video_vga =
+{
+       .card_name      = "VGA",
+       .probe          = vga_probe,
+       .set_mode       = vga_set_mode,
+};
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
deleted file mode 100644 (file)
index 8143c95..0000000
+++ /dev/null
@@ -1,2043 +0,0 @@
-/*     video.S
- *
- *     Display adapter & video mode setup, version 2.13 (14-May-99)
- *
- *     Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
- *     Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
- *
- *     Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
- *
- *     For further information, look at Documentation/svga.txt.
- *
- */
-
-/* Enable autodetection of SVGA adapters and modes. */
-#undef CONFIG_VIDEO_SVGA
-
-/* Enable autodetection of VESA modes */
-#define CONFIG_VIDEO_VESA
-
-/* Enable compacting of mode table */
-#define CONFIG_VIDEO_COMPACT
-
-/* Retain screen contents when switching modes */
-#define CONFIG_VIDEO_RETAIN
-
-/* Enable local mode list */
-#undef CONFIG_VIDEO_LOCAL
-
-/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
-#undef CONFIG_VIDEO_400_HACK
-
-/* Hack that lets you force specific BIOS mode ID and specific dimensions */
-#undef CONFIG_VIDEO_GFX_HACK
-#define VIDEO_GFX_BIOS_AX 0x4f02       /* 800x600 on ThinkPad */
-#define VIDEO_GFX_BIOS_BX 0x0102
-#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425      /* 100x37 */
-
-/* This code uses an extended set of video mode numbers. These include:
- * Aliases for standard modes
- *     NORMAL_VGA (-1)
- *     EXTENDED_VGA (-2)
- *     ASK_VGA (-3)
- * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
- * of compatibility when extending the table. These are between 0x00 and 0xff.
- */
-#define VIDEO_FIRST_MENU 0x0000
-
-/* Standard BIOS video modes (BIOS number + 0x0100) */
-#define VIDEO_FIRST_BIOS 0x0100
-
-/* VESA BIOS video modes (VESA number + 0x0200) */
-#define VIDEO_FIRST_VESA 0x0200
-
-/* Video7 special modes (BIOS number + 0x0900) */
-#define VIDEO_FIRST_V7 0x0900
-
-/* Special video modes */
-#define VIDEO_FIRST_SPECIAL 0x0f00
-#define VIDEO_80x25 0x0f00
-#define VIDEO_8POINT 0x0f01
-#define VIDEO_80x43 0x0f02
-#define VIDEO_80x28 0x0f03
-#define VIDEO_CURRENT_MODE 0x0f04
-#define VIDEO_80x30 0x0f05
-#define VIDEO_80x34 0x0f06
-#define VIDEO_80x60 0x0f07
-#define VIDEO_GFX_HACK 0x0f08
-#define VIDEO_LAST_SPECIAL 0x0f09
-
-/* Video modes given by resolution */
-#define VIDEO_FIRST_RESOLUTION 0x1000
-
-/* The "recalculate timings" flag */
-#define VIDEO_RECALC 0x8000
-
-/* Positions of various video parameters passed to the kernel */
-/* (see also include/linux/tty.h) */
-#define PARAM_CURSOR_POS       0x00
-#define PARAM_VIDEO_PAGE       0x04
-#define PARAM_VIDEO_MODE       0x06
-#define PARAM_VIDEO_COLS       0x07
-#define PARAM_VIDEO_EGA_BX     0x0a
-#define PARAM_VIDEO_LINES      0x0e
-#define PARAM_HAVE_VGA         0x0f
-#define PARAM_FONT_POINTS      0x10
-
-#define PARAM_LFB_WIDTH                0x12
-#define PARAM_LFB_HEIGHT       0x14
-#define PARAM_LFB_DEPTH                0x16
-#define PARAM_LFB_BASE         0x18
-#define PARAM_LFB_SIZE         0x1c
-#define PARAM_LFB_LINELENGTH   0x24
-#define PARAM_LFB_COLORS       0x26
-#define PARAM_VESAPM_SEG       0x2e
-#define PARAM_VESAPM_OFF       0x30
-#define PARAM_LFB_PAGES                0x32
-#define PARAM_VESA_ATTRIB      0x34
-#define PARAM_CAPABILITIES     0x36
-
-/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
-#ifdef CONFIG_VIDEO_RETAIN
-#define DO_STORE call store_screen
-#else
-#define DO_STORE
-#endif /* CONFIG_VIDEO_RETAIN */
-
-# This is the main entry point called by setup.S
-# %ds *must* be pointing to the bootsector
-video: pushw   %ds             # We use different segments
-       pushw   %ds             # FS contains original DS
-       popw    %fs
-       pushw   %cs             # DS is equal to CS
-       popw    %ds
-       pushw   %cs             # ES is equal to CS
-       popw    %es
-       xorw    %ax, %ax
-       movw    %ax, %gs        # GS is zero
-       cld
-       call    basic_detect    # Basic adapter type testing (EGA/VGA/MDA/CGA)
-#ifdef CONFIG_VIDEO_SELECT
-       movw    %fs:(0x01fa), %ax               # User selected video mode
-       cmpw    $ASK_VGA, %ax                   # Bring up the menu
-       jz      vid2
-
-       call    mode_set                        # Set the mode
-       jc      vid1
-
-       leaw    badmdt, %si                     # Invalid mode ID
-       call    prtstr
-vid2:  call    mode_menu
-vid1:
-#ifdef CONFIG_VIDEO_RETAIN
-       call    restore_screen                  # Restore screen contents
-#endif /* CONFIG_VIDEO_RETAIN */
-       call    store_edid
-#endif /* CONFIG_VIDEO_SELECT */
-       call    mode_params                     # Store mode parameters
-       popw    %ds                             # Restore original DS
-       ret
-
-# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
-basic_detect:
-       movb    $0, %fs:(PARAM_HAVE_VGA)
-       movb    $0x12, %ah      # Check EGA/VGA
-       movb    $0x10, %bl
-       int     $0x10
-       movw    %bx, %fs:(PARAM_VIDEO_EGA_BX)   # Identifies EGA to the kernel
-       cmpb    $0x10, %bl                      # No, it's a CGA/MDA/HGA card.
-       je      basret
-
-       incb    adapter
-       movw    $0x1a00, %ax                    # Check EGA or VGA?
-       int     $0x10
-       cmpb    $0x1a, %al                      # 1a means VGA...
-       jne     basret                          # anything else is EGA.
-       
-       incb    %fs:(PARAM_HAVE_VGA)            # We've detected a VGA
-       incb    adapter
-basret:        ret
-
-# Store the video mode parameters for later usage by the kernel.
-# This is done by asking the BIOS except for the rows/columns
-# parameters in the default 80x25 mode -- these are set directly,
-# because some very obscure BIOSes supply insane values.
-mode_params:
-#ifdef CONFIG_VIDEO_SELECT
-       cmpb    $0, graphic_mode
-       jnz     mopar_gr
-#endif
-       movb    $0x03, %ah                      # Read cursor position
-       xorb    %bh, %bh
-       int     $0x10
-       movw    %dx, %fs:(PARAM_CURSOR_POS)
-       movb    $0x0f, %ah                      # Read page/mode/width
-       int     $0x10
-       movw    %bx, %fs:(PARAM_VIDEO_PAGE)
-       movw    %ax, %fs:(PARAM_VIDEO_MODE)     # Video mode and screen width
-       cmpb    $0x7, %al                       # MDA/HGA => segment differs
-       jnz     mopar0
-
-       movw    $0xb000, video_segment
-mopar0: movw   %gs:(0x485), %ax                # Font size
-       movw    %ax, %fs:(PARAM_FONT_POINTS)    # (valid only on EGA/VGA)
-       movw    force_size, %ax                 # Forced size?
-       orw     %ax, %ax
-       jz      mopar1
-
-       movb    %ah, %fs:(PARAM_VIDEO_COLS)
-       movb    %al, %fs:(PARAM_VIDEO_LINES)
-       ret
-
-mopar1:        movb    $25, %al
-       cmpb    $0, adapter                     # If we are on CGA/MDA/HGA, the
-       jz      mopar2                          # screen must have 25 lines.
-
-       movb    %gs:(0x484), %al                # On EGA/VGA, use the EGA+ BIOS
-       incb    %al                             # location of max lines.
-mopar2: movb   %al, %fs:(PARAM_VIDEO_LINES)
-       ret
-
-#ifdef CONFIG_VIDEO_SELECT
-# Fetching of VESA frame buffer parameters
-mopar_gr:
-       leaw    modelist+1024, %di
-       movb    $0x23, %fs:(PARAM_HAVE_VGA)
-       movw    16(%di), %ax
-       movw    %ax, %fs:(PARAM_LFB_LINELENGTH)
-       movw    18(%di), %ax
-       movw    %ax, %fs:(PARAM_LFB_WIDTH)
-       movw    20(%di), %ax
-       movw    %ax, %fs:(PARAM_LFB_HEIGHT)
-       movb    25(%di), %al
-       movb    $0, %ah
-       movw    %ax, %fs:(PARAM_LFB_DEPTH)
-       movb    29(%di), %al    
-       movb    $0, %ah
-       movw    %ax, %fs:(PARAM_LFB_PAGES)
-       movl    40(%di), %eax
-       movl    %eax, %fs:(PARAM_LFB_BASE)
-       movl    31(%di), %eax
-       movl    %eax, %fs:(PARAM_LFB_COLORS)
-       movl    35(%di), %eax
-       movl    %eax, %fs:(PARAM_LFB_COLORS+4)
-       movw    0(%di), %ax
-       movw    %ax, %fs:(PARAM_VESA_ATTRIB)
-
-# get video mem size
-       leaw    modelist+1024, %di
-       movw    $0x4f00, %ax
-       int     $0x10
-       xorl    %eax, %eax
-       movw    18(%di), %ax
-       movl    %eax, %fs:(PARAM_LFB_SIZE)
-
-# store mode capabilities
-       movl 10(%di), %eax
-       movl %eax, %fs:(PARAM_CAPABILITIES)
-
-# switching the DAC to 8-bit is for <= 8 bpp only
-       movw    %fs:(PARAM_LFB_DEPTH), %ax
-       cmpw    $8, %ax
-       jg      dac_done
-
-# get DAC switching capability
-       xorl    %eax, %eax
-       movb    10(%di), %al
-       testb   $1, %al
-       jz      dac_set
-
-# attempt to switch DAC to 8-bit
-       movw    $0x4f08, %ax
-       movw    $0x0800, %bx
-       int     $0x10
-       cmpw    $0x004f, %ax
-       jne     dac_set
-       movb    %bh, dac_size           # store actual DAC size
-
-dac_set:
-# set color size to DAC size
-       movb    dac_size, %al
-       movb    %al, %fs:(PARAM_LFB_COLORS+0)
-       movb    %al, %fs:(PARAM_LFB_COLORS+2)
-       movb    %al, %fs:(PARAM_LFB_COLORS+4)
-       movb    %al, %fs:(PARAM_LFB_COLORS+6)
-
-# set color offsets to 0
-       movb    $0, %fs:(PARAM_LFB_COLORS+1)
-       movb    $0, %fs:(PARAM_LFB_COLORS+3)
-       movb    $0, %fs:(PARAM_LFB_COLORS+5)
-       movb    $0, %fs:(PARAM_LFB_COLORS+7)
-
-dac_done:
-# get protected mode interface informations
-       movw    $0x4f0a, %ax
-       xorw    %bx, %bx
-       xorw    %di, %di
-       int     $0x10
-       cmp     $0x004f, %ax
-       jnz     no_pm
-
-       movw    %es, %fs:(PARAM_VESAPM_SEG)
-       movw    %di, %fs:(PARAM_VESAPM_OFF)
-no_pm: ret
-
-# The video mode menu
-mode_menu:
-       leaw    keymsg, %si                     # "Return/Space/Timeout" message
-       call    prtstr
-       call    flush
-nokey: call    getkt
-
-       cmpb    $0x0d, %al                      # ENTER ?
-       je      listm                           # yes - manual mode selection
-
-       cmpb    $0x20, %al                      # SPACE ?
-       je      defmd1                          # no - repeat
-
-       call    beep
-       jmp     nokey
-
-defmd1:        ret                                     # No mode chosen? Default 80x25
-
-listm: call    mode_table                      # List mode table
-listm0:        leaw    name_bann, %si                  # Print adapter name
-       call    prtstr
-       movw    card_name, %si
-       orw     %si, %si
-       jnz     an2
-
-       movb    adapter, %al
-       leaw    old_name, %si
-       orb     %al, %al
-       jz      an1
-
-       leaw    ega_name, %si
-       decb    %al
-       jz      an1
-
-       leaw    vga_name, %si
-       jmp     an1
-
-an2:   call    prtstr
-       leaw    svga_name, %si
-an1:   call    prtstr
-       leaw    listhdr, %si                    # Table header
-       call    prtstr
-       movb    $0x30, %dl                      # DL holds mode number
-       leaw    modelist, %si
-lm1:   cmpw    $ASK_VGA, (%si)                 # End?
-       jz      lm2
-
-       movb    %dl, %al                        # Menu selection number
-       call    prtchr
-       call    prtsp2
-       lodsw
-       call    prthw                           # Mode ID
-       call    prtsp2
-       movb    0x1(%si), %al
-       call    prtdec                          # Rows
-       movb    $0x78, %al                      # the letter 'x'
-       call    prtchr
-       lodsw
-       call    prtdec                          # Columns
-       movb    $0x0d, %al                      # New line
-       call    prtchr
-       movb    $0x0a, %al
-       call    prtchr
-       incb    %dl                             # Next character
-       cmpb    $0x3a, %dl
-       jnz     lm1
-
-       movb    $0x61, %dl
-       jmp     lm1
-
-lm2:   leaw    prompt, %si                     # Mode prompt
-       call    prtstr
-       leaw    edit_buf, %di                   # Editor buffer
-lm3:   call    getkey
-       cmpb    $0x0d, %al                      # Enter?
-       jz      lment
-
-       cmpb    $0x08, %al                      # Backspace?
-       jz      lmbs
-
-       cmpb    $0x20, %al                      # Printable?
-       jc      lm3
-
-       cmpw    $edit_buf+4, %di                # Enough space?
-       jz      lm3
-
-       stosb
-       call    prtchr
-       jmp     lm3
-
-lmbs:  cmpw    $edit_buf, %di                  # Backspace
-       jz      lm3
-
-       decw    %di
-       movb    $0x08, %al
-       call    prtchr
-       call    prtspc
-       movb    $0x08, %al
-       call    prtchr
-       jmp     lm3
-       
-lment: movb    $0, (%di)
-       leaw    crlft, %si
-       call    prtstr
-       leaw    edit_buf, %si
-       cmpb    $0, (%si)                       # Empty string = default mode
-       jz      lmdef
-
-       cmpb    $0, 1(%si)                      # One character = menu selection
-       jz      mnusel
-
-       cmpw    $0x6373, (%si)                  # "scan" => mode scanning
-       jnz     lmhx
-
-       cmpw    $0x6e61, 2(%si)
-       jz      lmscan
-
-lmhx:  xorw    %bx, %bx                        # Else => mode ID in hex
-lmhex: lodsb
-       orb     %al, %al
-       jz      lmuse1
-
-       subb    $0x30, %al
-       jc      lmbad
-
-       cmpb    $10, %al
-       jc      lmhx1
-
-       subb    $7, %al
-       andb    $0xdf, %al
-       cmpb    $10, %al
-       jc      lmbad
-
-       cmpb    $16, %al
-       jnc     lmbad
-
-lmhx1: shlw    $4, %bx
-       orb     %al, %bl
-       jmp     lmhex
-
-lmuse1:        movw    %bx, %ax
-       jmp     lmuse
-
-mnusel:        lodsb                                   # Menu selection
-       xorb    %ah, %ah
-       subb    $0x30, %al
-       jc      lmbad
-
-       cmpb    $10, %al
-       jc      lmuse
-       
-       cmpb    $0x61-0x30, %al
-       jc      lmbad
-       
-       subb    $0x61-0x30-10, %al
-       cmpb    $36, %al
-       jnc     lmbad
-
-lmuse: call    mode_set
-       jc      lmdef
-
-lmbad: leaw    unknt, %si
-       call    prtstr
-       jmp     lm2
-lmscan:        cmpb    $0, adapter                     # Scanning only on EGA/VGA
-       jz      lmbad
-
-       movw    $0, mt_end                      # Scanning of modes is
-       movb    $1, scanning                    # done as new autodetection.
-       call    mode_table
-       jmp     listm0
-lmdef: ret
-
-# Additional parts of mode_set... (relative jumps, you know)
-setv7:                                         # Video7 extended modes
-       DO_STORE
-       subb    $VIDEO_FIRST_V7>>8, %bh
-       movw    $0x6f05, %ax
-       int     $0x10
-       stc
-       ret
-
-_setrec:       jmp     setrec                  # Ugly...
-_set_80x25:    jmp     set_80x25
-
-# Aliases for backward compatibility.
-setalias:
-       movw    $VIDEO_80x25, %ax
-       incw    %bx
-       jz      mode_set
-
-       movb    $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
-       incw    %bx
-       jnz     setbad                          # Fall-through!
-
-# Setting of user mode (AX=mode ID) => CF=success
-mode_set:
-       movw    %ax, %fs:(0x01fa)               # Store mode for use in acpi_wakeup.S
-       movw    %ax, %bx
-       cmpb    $0xff, %ah
-       jz      setalias
-
-       testb   $VIDEO_RECALC>>8, %ah
-       jnz     _setrec
-
-       cmpb    $VIDEO_FIRST_RESOLUTION>>8, %ah
-       jnc     setres
-       
-       cmpb    $VIDEO_FIRST_SPECIAL>>8, %ah
-       jz      setspc
-       
-       cmpb    $VIDEO_FIRST_V7>>8, %ah
-       jz      setv7
-       
-       cmpb    $VIDEO_FIRST_VESA>>8, %ah
-       jnc     check_vesa
-       
-       orb     %ah, %ah
-       jz      setmenu
-       
-       decb    %ah
-       jz      setbios
-
-setbad:        clc
-       movb    $0, do_restore                  # The screen needn't be restored
-       ret
-
-setvesa:
-       DO_STORE
-       subb    $VIDEO_FIRST_VESA>>8, %bh
-       movw    $0x4f02, %ax                    # VESA BIOS mode set call
-       int     $0x10
-       cmpw    $0x004f, %ax                    # AL=4f if implemented
-       jnz     setbad                          # AH=0 if OK
-
-       stc
-       ret
-
-setbios:
-       DO_STORE
-       int     $0x10                           # Standard BIOS mode set call
-       pushw   %bx
-       movb    $0x0f, %ah                      # Check if really set
-       int     $0x10
-       popw    %bx
-       cmpb    %bl, %al
-       jnz     setbad
-       
-       stc
-       ret
-
-setspc:        xorb    %bh, %bh                        # Set special mode
-       cmpb    $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
-       jnc     setbad
-       
-       addw    %bx, %bx
-       jmp     *spec_inits(%bx)
-
-setmenu:
-       orb     %al, %al                        # 80x25 is an exception
-       jz      _set_80x25
-       
-       pushw   %bx                             # Set mode chosen from menu
-       call    mode_table                      # Build the mode table
-       popw    %ax
-       shlw    $2, %ax
-       addw    %ax, %si
-       cmpw    %di, %si
-       jnc     setbad
-       
-       movw    (%si), %ax                      # Fetch mode ID
-_m_s:  jmp     mode_set
-
-setres:        pushw   %bx                             # Set mode chosen by resolution
-       call    mode_table
-       popw    %bx
-       xchgb   %bl, %bh
-setr1: lodsw
-       cmpw    $ASK_VGA, %ax                   # End of the list?
-       jz      setbad
-       
-       lodsw
-       cmpw    %bx, %ax
-       jnz     setr1
-       
-       movw    -4(%si), %ax                    # Fetch mode ID
-       jmp     _m_s
-
-check_vesa:
-#ifdef CONFIG_FIRMWARE_EDID
-       leaw    modelist+1024, %di
-       movw    $0x4f00, %ax
-       int     $0x10
-       cmpw    $0x004f, %ax
-       jnz     setbad
-
-       movw    4(%di), %ax
-       movw    %ax, vbe_version
-#endif
-       leaw    modelist+1024, %di
-       subb    $VIDEO_FIRST_VESA>>8, %bh
-       movw    %bx, %cx                        # Get mode information structure
-       movw    $0x4f01, %ax
-       int     $0x10
-       addb    $VIDEO_FIRST_VESA>>8, %bh
-       cmpw    $0x004f, %ax
-       jnz     setbad
-
-       movb    (%di), %al                      # Check capabilities.
-       andb    $0x19, %al
-       cmpb    $0x09, %al
-       jz      setvesa                         # This is a text mode
-
-       movb    (%di), %al                      # Check capabilities.
-       andb    $0x99, %al
-       cmpb    $0x99, %al
-       jnz     _setbad                         # Doh! No linear frame buffer.
-
-       subb    $VIDEO_FIRST_VESA>>8, %bh
-       orw     $0x4000, %bx                    # Use linear frame buffer
-       movw    $0x4f02, %ax                    # VESA BIOS mode set call
-       int     $0x10
-       cmpw    $0x004f, %ax                    # AL=4f if implemented
-       jnz     _setbad                         # AH=0 if OK
-
-       movb    $1, graphic_mode                # flag graphic mode
-       movb    $0, do_restore                  # no screen restore
-       stc
-       ret
-
-_setbad:       jmp     setbad                  # Ugly...
-
-# Recalculate vertical display end registers -- this fixes various
-# inconsistencies of extended modes on many adapters. Called when
-# the VIDEO_RECALC flag is set in the mode ID.
-
-setrec:        subb    $VIDEO_RECALC>>8, %ah           # Set the base mode
-       call    mode_set
-       jnc     rct3
-
-       movw    %gs:(0x485), %ax                # Font size in pixels
-       movb    %gs:(0x484), %bl                # Number of rows
-       incb    %bl
-       mulb    %bl                             # Number of visible
-       decw    %ax                             # scan lines - 1
-       movw    $0x3d4, %dx
-       movw    %ax, %bx
-       movb    $0x12, %al                      # Lower 8 bits
-       movb    %bl, %ah
-       outw    %ax, %dx
-       movb    $0x07, %al              # Bits 8 and 9 in the overflow register
-       call    inidx
-       xchgb   %al, %ah
-       andb    $0xbd, %ah
-       shrb    %bh
-       jnc     rct1
-       orb     $0x02, %ah
-rct1:  shrb    %bh
-       jnc     rct2
-       orb     $0x40, %ah
-rct2:  movb    $0x07, %al
-       outw    %ax, %dx
-       stc
-rct3:  ret
-
-# Table of routines for setting of the special modes.
-spec_inits:
-       .word   set_80x25
-       .word   set_8pixel
-       .word   set_80x43
-       .word   set_80x28
-       .word   set_current
-       .word   set_80x30
-       .word   set_80x34
-       .word   set_80x60
-       .word   set_gfx
-
-# Set the 80x25 mode. If already set, do nothing.
-set_80x25:
-       movw    $0x5019, force_size             # Override possibly broken BIOS
-use_80x25:
-#ifdef CONFIG_VIDEO_400_HACK
-       movw    $0x1202, %ax                    # Force 400 scan lines
-       movb    $0x30, %bl
-       int     $0x10
-#else
-       movb    $0x0f, %ah                      # Get current mode ID
-       int     $0x10
-       cmpw    $0x5007, %ax    # Mode 7 (80x25 mono) is the only one available
-       jz      st80            # on CGA/MDA/HGA and is also available on EGAM
-
-       cmpw    $0x5003, %ax    # Unknown mode, force 80x25 color
-       jnz     force3
-
-st80:  cmpb    $0, adapter     # CGA/MDA/HGA => mode 3/7 is always 80x25
-       jz      set80
-
-       movb    %gs:(0x0484), %al       # This is EGA+ -- beware of 80x50 etc.
-       orb     %al, %al                # Some buggy BIOS'es set 0 rows
-       jz      set80
-       
-       cmpb    $24, %al                # It's hopefully correct
-       jz      set80
-#endif /* CONFIG_VIDEO_400_HACK */
-force3:        DO_STORE
-       movw    $0x0003, %ax                    # Forced set
-       int     $0x10
-set80: stc
-       ret
-
-# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
-set_8pixel:
-       DO_STORE
-       call    use_80x25                       # The base is 80x25
-set_8pt:
-       movw    $0x1112, %ax                    # Use 8x8 font
-       xorb    %bl, %bl
-       int     $0x10
-       movw    $0x1200, %ax                    # Use alternate print screen
-       movb    $0x20, %bl
-       int     $0x10
-       movw    $0x1201, %ax                    # Turn off cursor emulation
-       movb    $0x34, %bl
-       int     $0x10
-       movb    $0x01, %ah                      # Define cursor scan lines 6-7
-       movw    $0x0607, %cx
-       int     $0x10
-set_current:
-       stc
-       ret
-
-# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
-# 80x25 mode with 14-point fonts instead of 16-point.
-set_80x28:
-       DO_STORE
-       call    use_80x25                       # The base is 80x25
-set14: movw    $0x1111, %ax                    # Use 9x14 font
-       xorb    %bl, %bl
-       int     $0x10
-       movb    $0x01, %ah                      # Define cursor scan lines 11-12
-       movw    $0x0b0c, %cx
-       int     $0x10
-       stc
-       ret
-
-# Set the 80x43 mode. This mode is works on all VGA's.
-# It's a 350-scanline mode with 8-pixel font.
-set_80x43:
-       DO_STORE
-       movw    $0x1201, %ax                    # Set 350 scans
-       movb    $0x30, %bl
-       int     $0x10
-       movw    $0x0003, %ax                    # Reset video mode
-       int     $0x10
-       jmp     set_8pt                         # Use 8-pixel font
-
-# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
-set_80x30:
-       call    use_80x25                       # Start with real 80x25
-       DO_STORE
-       movw    $0x3cc, %dx                     # Get CRTC port
-       inb     %dx, %al
-       movb    $0xd4, %dl
-       rorb    %al                             # Mono or color?
-       jc      set48a
-
-       movb    $0xb4, %dl
-set48a:        movw    $0x0c11, %ax            # Vertical sync end (also unlocks CR0-7)
-       call    outidx
-       movw    $0x0b06, %ax                    # Vertical total
-       call    outidx
-       movw    $0x3e07, %ax                    # (Vertical) overflow
-       call    outidx
-       movw    $0xea10, %ax                    # Vertical sync start
-       call    outidx
-       movw    $0xdf12, %ax                    # Vertical display end
-       call    outidx
-       movw    $0xe715, %ax                    # Vertical blank start
-       call    outidx
-       movw    $0x0416, %ax                    # Vertical blank end
-       call    outidx
-       pushw   %dx
-       movb    $0xcc, %dl                      # Misc output register (read)
-       inb     %dx, %al
-       movb    $0xc2, %dl                      # (write)
-       andb    $0x0d, %al      # Preserve clock select bits and color bit
-       orb     $0xe2, %al                      # Set correct sync polarity
-       outb    %al, %dx
-       popw    %dx
-       movw    $0x501e, force_size
-       stc                                     # That's all.
-       ret
-
-# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
-set_80x34:
-       call    set_80x30                       # Set 480 scans
-       call    set14                           # And 14-pt font
-       movw    $0xdb12, %ax                    # VGA vertical display end
-       movw    $0x5022, force_size
-setvde:        call    outidx
-       stc
-       ret
-
-# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
-set_80x60:
-       call    set_80x30                       # Set 480 scans
-       call    set_8pt                         # And 8-pt font
-       movw    $0xdf12, %ax                    # VGA vertical display end
-       movw    $0x503c, force_size
-       jmp     setvde
-
-# Special hack for ThinkPad graphics
-set_gfx:
-#ifdef CONFIG_VIDEO_GFX_HACK
-       movw    $VIDEO_GFX_BIOS_AX, %ax
-       movw    $VIDEO_GFX_BIOS_BX, %bx
-       int     $0x10
-       movw    $VIDEO_GFX_DUMMY_RESOLUTION, force_size
-       stc
-#endif
-       ret
-
-#ifdef CONFIG_VIDEO_RETAIN
-
-# Store screen contents to temporary buffer.
-store_screen:
-       cmpb    $0, do_restore                  # Already stored?
-       jnz     stsr
-
-       testb   $CAN_USE_HEAP, loadflags        # Have we space for storing?
-       jz      stsr
-       
-       pushw   %ax
-       pushw   %bx
-       pushw   force_size                      # Don't force specific size
-       movw    $0, force_size
-       call    mode_params                     # Obtain params of current mode
-       popw    force_size
-       movb    %fs:(PARAM_VIDEO_LINES), %ah
-       movb    %fs:(PARAM_VIDEO_COLS), %al
-       movw    %ax, %bx                        # BX=dimensions
-       mulb    %ah
-       movw    %ax, %cx                        # CX=number of characters
-       addw    %ax, %ax                        # Calculate image size
-       addw    $modelist+1024+4, %ax
-       cmpw    heap_end_ptr, %ax
-       jnc     sts1                            # Unfortunately, out of memory
-
-       movw    %fs:(PARAM_CURSOR_POS), %ax     # Store mode params
-       leaw    modelist+1024, %di
-       stosw
-       movw    %bx, %ax
-       stosw
-       pushw   %ds                             # Store the screen
-       movw    video_segment, %ds
-       xorw    %si, %si
-       rep
-       movsw
-       popw    %ds
-       incb    do_restore                      # Screen will be restored later
-sts1:  popw    %bx
-       popw    %ax
-stsr:  ret
-
-# Restore screen contents from temporary buffer.
-restore_screen:
-       cmpb    $0, do_restore                  # Has the screen been stored?
-       jz      res1
-
-       call    mode_params                     # Get parameters of current mode
-       movb    %fs:(PARAM_VIDEO_LINES), %cl
-       movb    %fs:(PARAM_VIDEO_COLS), %ch
-       leaw    modelist+1024, %si              # Screen buffer
-       lodsw                                   # Set cursor position
-       movw    %ax, %dx
-       cmpb    %cl, %dh
-       jc      res2
-       
-       movb    %cl, %dh
-       decb    %dh
-res2:  cmpb    %ch, %dl
-       jc      res3
-       
-       movb    %ch, %dl
-       decb    %dl
-res3:  movb    $0x02, %ah
-       movb    $0x00, %bh
-       int     $0x10
-       lodsw                                   # Display size
-       movb    %ah, %dl                        # DL=number of lines
-       movb    $0, %ah                         # BX=phys. length of orig. line
-       movw    %ax, %bx
-       cmpb    %cl, %dl                        # Too many?
-       jc      res4
-
-       pushw   %ax
-       movb    %dl, %al
-       subb    %cl, %al
-       mulb    %bl
-       addw    %ax, %si
-       addw    %ax, %si
-       popw    %ax
-       movb    %cl, %dl
-res4:  cmpb    %ch, %al                        # Too wide?
-       jc      res5
-       
-       movb    %ch, %al                        # AX=width of src. line
-res5:  movb    $0, %cl
-       xchgb   %ch, %cl
-       movw    %cx, %bp                        # BP=width of dest. line
-       pushw   %es
-       movw    video_segment, %es
-       xorw    %di, %di                        # Move the data
-       addw    %bx, %bx                        # Convert BX and BP to _bytes_
-       addw    %bp, %bp
-res6:  pushw   %si
-       pushw   %di
-       movw    %ax, %cx
-       rep
-       movsw
-       popw    %di
-       popw    %si
-       addw    %bp, %di
-       addw    %bx, %si
-       decb    %dl
-       jnz     res6
-       
-       popw    %es                             # Done
-res1:  ret
-#endif /* CONFIG_VIDEO_RETAIN */
-
-# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
-outidx:        outb    %al, %dx
-       pushw   %ax
-       movb    %ah, %al
-       incw    %dx
-       outb    %al, %dx
-       decw    %dx
-       popw    %ax
-       ret
-
-# Build the table of video modes (stored after the setup.S code at the
-# `modelist' label. Each video mode record looks like:
-#      .word   MODE-ID         (our special mode ID (see above))
-#      .byte   rows            (number of rows)
-#      .byte   columns         (number of columns)
-# Returns address of the end of the table in DI, the end is marked
-# with a ASK_VGA ID.
-mode_table:
-       movw    mt_end, %di                     # Already filled?
-       orw     %di, %di
-       jnz     mtab1x
-       
-       leaw    modelist, %di                   # Store standard modes:
-       movl    $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
-       stosl
-       movb    adapter, %al                    # CGA/MDA/HGA -- no more modes
-       orb     %al, %al
-       jz      mtabe
-       
-       decb    %al
-       jnz     mtabv
-       
-       movl    $VIDEO_8POINT + 0x502b0000, %eax        # The 80x43 EGA mode
-       stosl
-       jmp     mtabe
-
-mtab1x:        jmp     mtab1
-
-mtabv: leaw    vga_modes, %si                  # All modes for std VGA
-       movw    $vga_modes_end-vga_modes, %cx
-       rep     # I'm unable to use movsw as I don't know how to store a half
-       movsb   # of the expression above to cx without using explicit shr.
-
-       cmpb    $0, scanning                    # Mode scan requested?
-       jz      mscan1
-       
-       call    mode_scan
-mscan1:
-
-#ifdef CONFIG_VIDEO_LOCAL
-       call    local_modes
-#endif /* CONFIG_VIDEO_LOCAL */
-
-#ifdef CONFIG_VIDEO_VESA
-       call    vesa_modes                      # Detect VESA VGA modes
-#endif /* CONFIG_VIDEO_VESA */
-
-#ifdef CONFIG_VIDEO_SVGA
-       cmpb    $0, scanning                    # Bypass when scanning
-       jnz     mscan2
-       
-       call    svga_modes                      # Detect SVGA cards & modes
-mscan2:
-#endif /* CONFIG_VIDEO_SVGA */
-
-mtabe:
-
-#ifdef CONFIG_VIDEO_COMPACT
-       leaw    modelist, %si
-       movw    %di, %dx
-       movw    %si, %di
-cmt1:  cmpw    %dx, %si                        # Scan all modes
-       jz      cmt2
-
-       leaw    modelist, %bx                   # Find in previous entries
-       movw    2(%si), %cx
-cmt3:  cmpw    %bx, %si
-       jz      cmt4
-
-       cmpw    2(%bx), %cx                     # Found => don't copy this entry
-       jz      cmt5
-
-       addw    $4, %bx
-       jmp     cmt3
-
-cmt4:  movsl                                   # Copy entry
-       jmp     cmt1
-
-cmt5:  addw    $4, %si                         # Skip entry
-       jmp     cmt1
-
-cmt2:
-#endif /* CONFIG_VIDEO_COMPACT */
-
-       movw    $ASK_VGA, (%di)                 # End marker
-       movw    %di, mt_end
-mtab1: leaw    modelist, %si                   # SI=mode list, DI=list end
-ret0:  ret
-
-# Modes usable on all standard VGAs
-vga_modes:
-       .word   VIDEO_8POINT
-       .word   0x5032                          # 80x50
-       .word   VIDEO_80x43
-       .word   0x502b                          # 80x43
-       .word   VIDEO_80x28
-       .word   0x501c                          # 80x28
-       .word   VIDEO_80x30
-       .word   0x501e                          # 80x30
-       .word   VIDEO_80x34
-       .word   0x5022                          # 80x34
-       .word   VIDEO_80x60
-       .word   0x503c                          # 80x60
-#ifdef CONFIG_VIDEO_GFX_HACK
-       .word   VIDEO_GFX_HACK
-       .word   VIDEO_GFX_DUMMY_RESOLUTION
-#endif
-
-vga_modes_end:
-# Detect VESA modes.
-
-#ifdef CONFIG_VIDEO_VESA
-vesa_modes:
-       cmpb    $2, adapter                     # VGA only
-       jnz     ret0
-
-       movw    %di, %bp                        # BP=original mode table end
-       addw    $0x200, %di                     # Buffer space
-       movw    $0x4f00, %ax                    # VESA Get card info call
-       int     $0x10
-       movw    %bp, %di
-       cmpw    $0x004f, %ax                    # Successful?
-       jnz     ret0
-       
-       cmpw    $0x4556, 0x200(%di)
-       jnz     ret0
-       
-       cmpw    $0x4153, 0x202(%di)
-       jnz     ret0
-       
-       movw    $vesa_name, card_name           # Set name to "VESA VGA"
-       pushw   %gs
-       lgsw    0x20e(%di), %si                 # GS:SI=mode list
-       movw    $128, %cx                       # Iteration limit
-vesa1:
-# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
-# XXX: lodsw   %gs:(%si), %ax                  # Get next mode in the list
-       gs; lodsw
-       cmpw    $0xffff, %ax                    # End of the table?
-       jz      vesar
-       
-       cmpw    $0x0080, %ax                    # Check validity of mode ID
-       jc      vesa2
-       
-       orb     %ah, %ah                # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
-       jz      vesan                   # Certain BIOSes report 0x80-0xff!
-
-       cmpw    $0x0800, %ax
-       jnc     vesae
-
-vesa2: pushw   %cx
-       movw    %ax, %cx                        # Get mode information structure
-       movw    $0x4f01, %ax
-       int     $0x10
-       movw    %cx, %bx                        # BX=mode number
-       addb    $VIDEO_FIRST_VESA>>8, %bh
-       popw    %cx
-       cmpw    $0x004f, %ax
-       jnz     vesan                   # Don't report errors (buggy BIOSES)
-
-       movb    (%di), %al                      # Check capabilities. We require
-       andb    $0x19, %al                      # a color text mode.
-       cmpb    $0x09, %al
-       jnz     vesan
-       
-       cmpw    $0xb800, 8(%di)         # Standard video memory address required
-       jnz     vesan
-
-       testb   $2, (%di)                       # Mode characteristics supplied?
-       movw    %bx, (%di)                      # Store mode number
-       jz      vesa3
-       
-       xorw    %dx, %dx
-       movw    0x12(%di), %bx                  # Width
-       orb     %bh, %bh
-       jnz     vesan
-       
-       movb    %bl, 0x3(%di)
-       movw    0x14(%di), %ax                  # Height
-       orb     %ah, %ah
-       jnz     vesan
-       
-       movb    %al, 2(%di)
-       mulb    %bl
-       cmpw    $8193, %ax              # Small enough for Linux console driver?
-       jnc     vesan
-
-       jmp     vesaok
-
-vesa3: subw    $0x8108, %bx    # This mode has no detailed info specified,
-       jc      vesan           # so it must be a standard VESA mode.
-
-       cmpw    $5, %bx
-       jnc     vesan
-
-       movw    vesa_text_mode_table(%bx), %ax
-       movw    %ax, 2(%di)
-vesaok:        addw    $4, %di                         # The mode is valid. Store it.
-vesan: loop    vesa1                   # Next mode. Limit exceeded => error
-vesae: leaw    vesaer, %si
-       call    prtstr
-       movw    %bp, %di                        # Discard already found modes.
-vesar: popw    %gs
-       ret
-
-# Dimensions of standard VESA text modes
-vesa_text_mode_table:
-       .byte   60, 80                          # 0108
-       .byte   25, 132                         # 0109
-       .byte   43, 132                         # 010A
-       .byte   50, 132                         # 010B
-       .byte   60, 132                         # 010C
-#endif /* CONFIG_VIDEO_VESA */
-
-# Scan for video modes. A bit dirty, but should work.
-mode_scan:
-       movw    $0x0100, %cx                    # Start with mode 0
-scm1:  movb    $0, %ah                         # Test the mode
-       movb    %cl, %al
-       int     $0x10
-       movb    $0x0f, %ah
-       int     $0x10
-       cmpb    %cl, %al
-       jnz     scm2                            # Mode not set
-
-       movw    $0x3c0, %dx                     # Test if it's a text mode
-       movb    $0x10, %al                      # Mode bits
-       call    inidx
-       andb    $0x03, %al
-       jnz     scm2
-       
-       movb    $0xce, %dl                      # Another set of mode bits
-       movb    $0x06, %al
-       call    inidx
-       shrb    %al
-       jc      scm2
-       
-       movb    $0xd4, %dl                      # Cursor location
-       movb    $0x0f, %al
-       call    inidx
-       orb     %al, %al
-       jnz     scm2
-       
-       movw    %cx, %ax                        # Ok, store the mode
-       stosw
-       movb    %gs:(0x484), %al                # Number of rows
-       incb    %al
-       stosb
-       movw    %gs:(0x44a), %ax                # Number of columns
-       stosb
-scm2:  incb    %cl
-       jns     scm1
-       
-       movw    $0x0003, %ax                    # Return back to mode 3
-       int     $0x10
-       ret
-
-tstidx:        outw    %ax, %dx                        # OUT DX,AX and inidx
-inidx: outb    %al, %dx                        # Read from indexed VGA register
-       incw    %dx                     # AL=index, DX=index reg port -> AL=data
-       inb     %dx, %al
-       decw    %dx
-       ret
-
-# Try to detect type of SVGA card and supply (usually approximate) video
-# mode table for it.
-
-#ifdef CONFIG_VIDEO_SVGA
-svga_modes:
-       leaw    svga_table, %si                 # Test all known SVGA adapters
-dosvga:        lodsw
-       movw    %ax, %bp                        # Default mode table
-       orw     %ax, %ax
-       jz      didsv1
-
-       lodsw                                   # Pointer to test routine
-       pushw   %si
-       pushw   %di
-       pushw   %es
-       movw    $0xc000, %bx
-       movw    %bx, %es
-       call    *%ax                            # Call test routine
-       popw    %es
-       popw    %di
-       popw    %si
-       orw     %bp, %bp
-       jz      dosvga
-       
-       movw    %bp, %si                        # Found, copy the modes
-       movb    svga_prefix, %ah
-cpsvga:        lodsb
-       orb     %al, %al
-       jz      didsv
-       
-       stosw
-       movsw
-       jmp     cpsvga
-
-didsv: movw    %si, card_name                  # Store pointer to card name
-didsv1:        ret
-
-# Table of all known SVGA cards. For each card, we store a pointer to
-# a table of video modes supported by the card and a pointer to a routine
-# used for testing of presence of the card. The video mode table is always
-# followed by the name of the card or the chipset.
-svga_table:
-       .word   ati_md, ati_test
-       .word   oak_md, oak_test
-       .word   paradise_md, paradise_test
-       .word   realtek_md, realtek_test
-       .word   s3_md, s3_test
-       .word   chips_md, chips_test
-       .word   video7_md, video7_test
-       .word   cirrus5_md, cirrus5_test
-       .word   cirrus6_md, cirrus6_test
-       .word   cirrus1_md, cirrus1_test
-       .word   ahead_md, ahead_test
-       .word   everex_md, everex_test
-       .word   genoa_md, genoa_test
-       .word   trident_md, trident_test
-       .word   tseng_md, tseng_test
-       .word   0
-
-# Test routines and mode tables:
-
-# S3 - The test algorithm was taken from the SuperProbe package
-# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
-s3_test:
-       movw    $0x0f35, %cx    # we store some constants in cl/ch
-       movw    $0x03d4, %dx
-       movb    $0x38, %al
-       call    inidx
-       movb    %al, %bh        # store current CRT-register 0x38
-       movw    $0x0038, %ax
-       call    outidx          # disable writing to special regs
-       movb    %cl, %al        # check whether we can write special reg 0x35
-       call    inidx
-       movb    %al, %bl        # save the current value of CRT reg 0x35
-       andb    $0xf0, %al      # clear bits 0-3
-       movb    %al, %ah
-       movb    %cl, %al        # and write it to CRT reg 0x35
-       call    outidx
-       call    inidx           # now read it back
-       andb    %ch, %al        # clear the upper 4 bits
-       jz      s3_2            # the first test failed. But we have a
-
-       movb    %bl, %ah        # second chance
-       movb    %cl, %al
-       call    outidx
-       jmp     s3_1            # do the other tests
-
-s3_2:  movw    %cx, %ax        # load ah with 0xf and al with 0x35
-       orb     %bl, %ah        # set the upper 4 bits of ah with the orig value
-       call    outidx          # write ...
-       call    inidx           # ... and reread 
-       andb    %cl, %al        # turn off the upper 4 bits
-       pushw   %ax
-       movb    %bl, %ah        # restore old value in register 0x35
-       movb    %cl, %al
-       call    outidx
-       popw    %ax
-       cmpb    %ch, %al        # setting lower 4 bits was successful => bad
-       je      no_s3           # writing is allowed => this is not an S3
-
-s3_1:  movw    $0x4838, %ax    # allow writing to special regs by putting
-       call    outidx          # magic number into CRT-register 0x38
-       movb    %cl, %al        # check whether we can write special reg 0x35
-       call    inidx
-       movb    %al, %bl
-       andb    $0xf0, %al
-       movb    %al, %ah
-       movb    %cl, %al
-       call    outidx
-       call    inidx
-       andb    %ch, %al
-       jnz     no_s3           # no, we can't write => no S3
-
-       movw    %cx, %ax
-       orb     %bl, %ah
-       call    outidx
-       call    inidx
-       andb    %ch, %al
-       pushw   %ax
-       movb    %bl, %ah        # restore old value in register 0x35
-       movb    %cl, %al
-       call    outidx
-       popw    %ax
-       cmpb    %ch, %al
-       jne     no_s31          # writing not possible => no S3
-       movb    $0x30, %al
-       call    inidx           # now get the S3 id ...
-       leaw    idS3, %di
-       movw    $0x10, %cx
-       repne
-       scasb
-       je      no_s31
-
-       movb    %bh, %ah
-       movb    $0x38, %al
-       jmp     s3rest
-
-no_s3: movb    $0x35, %al      # restore CRT register 0x35
-       movb    %bl, %ah
-       call    outidx
-no_s31:        xorw    %bp, %bp        # Detection failed
-s3rest:        movb    %bh, %ah
-       movb    $0x38, %al      # restore old value of CRT register 0x38
-       jmp     outidx
-
-idS3:  .byte   0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
-       .byte   0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
-
-s3_md: .byte   0x54, 0x2b, 0x84
-       .byte   0x55, 0x19, 0x84
-       .byte   0
-       .ascii  "S3"
-       .byte   0
-
-# ATI cards.
-ati_test:
-       leaw    idati, %si
-       movw    $0x31, %di
-       movw    $0x09, %cx
-       repe
-       cmpsb
-       je      atiok
-
-       xorw    %bp, %bp
-atiok: ret
-
-idati: .ascii  "761295520"
-
-ati_md:        .byte   0x23, 0x19, 0x84
-       .byte   0x33, 0x2c, 0x84
-       .byte   0x22, 0x1e, 0x64
-       .byte   0x21, 0x19, 0x64
-       .byte   0x58, 0x21, 0x50
-       .byte   0x5b, 0x1e, 0x50
-       .byte   0
-       .ascii  "ATI"
-       .byte   0
-
-# AHEAD
-ahead_test:
-       movw    $0x200f, %ax
-       movw    $0x3ce, %dx
-       outw    %ax, %dx
-       incw    %dx
-       inb     %dx, %al
-       cmpb    $0x20, %al
-       je      isahed
-
-       cmpb    $0x21, %al
-       je      isahed
-       
-       xorw    %bp, %bp
-isahed:        ret
-
-ahead_md:
-       .byte   0x22, 0x2c, 0x84
-       .byte   0x23, 0x19, 0x84
-       .byte   0x24, 0x1c, 0x84
-       .byte   0x2f, 0x32, 0xa0
-       .byte   0x32, 0x22, 0x50
-       .byte   0x34, 0x42, 0x50
-       .byte   0
-       .ascii  "Ahead"
-       .byte   0
-
-# Chips & Tech.
-chips_test:
-       movw    $0x3c3, %dx
-       inb     %dx, %al
-       orb     $0x10, %al
-       outb    %al, %dx
-       movw    $0x104, %dx
-       inb     %dx, %al
-       movb    %al, %bl
-       movw    $0x3c3, %dx
-       inb     %dx, %al
-       andb    $0xef, %al
-       outb    %al, %dx
-       cmpb    $0xa5, %bl
-       je      cantok
-       
-       xorw    %bp, %bp
-cantok:        ret
-
-chips_md:
-       .byte   0x60, 0x19, 0x84
-       .byte   0x61, 0x32, 0x84
-       .byte   0
-       .ascii  "Chips & Technologies"
-       .byte   0
-
-# Cirrus Logic 5X0
-cirrus1_test:
-       movw    $0x3d4, %dx
-       movb    $0x0c, %al
-       outb    %al, %dx
-       incw    %dx
-       inb     %dx, %al
-       movb    %al, %bl
-       xorb    %al, %al
-       outb    %al, %dx
-       decw    %dx
-       movb    $0x1f, %al
-       outb    %al, %dx
-       incw    %dx
-       inb     %dx, %al
-       movb    %al, %bh
-       xorb    %ah, %ah
-       shlb    $4, %al
-       movw    %ax, %cx
-       movb    %bh, %al
-       shrb    $4, %al
-       addw    %ax, %cx
-       shlw    $8, %cx
-       addw    $6, %cx
-       movw    %cx, %ax
-       movw    $0x3c4, %dx
-       outw    %ax, %dx
-       incw    %dx
-       inb     %dx, %al
-       andb    %al, %al
-       jnz     nocirr
-       
-       movb    %bh, %al
-       outb    %al, %dx
-       inb     %dx, %al
-       cmpb    $0x01, %al
-       je      iscirr
-
-nocirr:        xorw    %bp, %bp
-iscirr: movw   $0x3d4, %dx
-       movb    %bl, %al
-       xorb    %ah, %ah
-       shlw    $8, %ax
-       addw    $0x0c, %ax
-       outw    %ax, %dx
-       ret
-
-cirrus1_md:
-       .byte   0x1f, 0x19, 0x84
-       .byte   0x20, 0x2c, 0x84
-       .byte   0x22, 0x1e, 0x84
-       .byte   0x31, 0x25, 0x64
-       .byte   0
-       .ascii  "Cirrus Logic 5X0"
-       .byte   0
-
-# Cirrus Logic 54XX
-cirrus5_test:
-       movw    $0x3c4, %dx
-       movb    $6, %al
-       call    inidx
-       movb    %al, %bl                        # BL=backup
-       movw    $6, %ax
-       call    tstidx
-       cmpb    $0x0f, %al
-       jne     c5fail
-       
-       movw    $0x1206, %ax
-       call    tstidx
-       cmpb    $0x12, %al
-       jne     c5fail
-       
-       movb    $0x1e, %al
-       call    inidx
-       movb    %al, %bh
-       movb    %bh, %ah
-       andb    $0xc0, %ah
-       movb    $0x1e, %al
-       call    tstidx
-       andb    $0x3f, %al
-       jne     c5xx
-       
-       movb    $0x1e, %al
-       movb    %bh, %ah
-       orb     $0x3f, %ah
-       call    tstidx
-       xorb    $0x3f, %al
-       andb    $0x3f, %al
-c5xx:  pushf
-       movb    $0x1e, %al
-       movb    %bh, %ah
-       outw    %ax, %dx
-       popf
-       je      c5done
-
-c5fail:        xorw    %bp, %bp
-c5done:        movb    $6, %al
-       movb    %bl, %ah
-       outw    %ax, %dx
-       ret
-
-cirrus5_md:
-       .byte   0x14, 0x19, 0x84
-       .byte   0x54, 0x2b, 0x84
-       .byte   0
-       .ascii  "Cirrus Logic 54XX"
-       .byte   0
-
-# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
-# it's misidentified by the Ahead test.
-cirrus6_test:
-       movw    $0x3ce, %dx
-       movb    $0x0a, %al
-       call    inidx
-       movb    %al, %bl        # BL=backup
-       movw    $0xce0a, %ax
-       call    tstidx
-       orb     %al, %al
-       jne     c2fail
-       
-       movw    $0xec0a, %ax
-       call    tstidx
-       cmpb    $0x01, %al
-       jne     c2fail
-       
-       movb    $0xaa, %al
-       call    inidx           # 4X, 5X, 7X and 8X are valid 64XX chip ID's. 
-       shrb    $4, %al
-       subb    $4, %al
-       jz      c6done
-       
-       decb    %al
-       jz      c6done
-       
-       subb    $2, %al
-       jz      c6done
-       
-       decb    %al
-       jz      c6done
-       
-c2fail:        xorw    %bp, %bp
-c6done:        movb    $0x0a, %al
-       movb    %bl, %ah
-       outw    %ax, %dx
-       ret
-
-cirrus6_md:
-       .byte   0
-       .ascii  "Cirrus Logic 64XX"
-       .byte   0
-
-# Everex / Trident
-everex_test:
-       movw    $0x7000, %ax
-       xorw    %bx, %bx
-       int     $0x10
-       cmpb    $0x70, %al
-       jne     noevrx
-       
-       shrw    $4, %dx
-       cmpw    $0x678, %dx
-       je      evtrid
-       
-       cmpw    $0x236, %dx
-       jne     evrxok
-
-evtrid:        leaw    trident_md, %bp
-evrxok:        ret
-
-noevrx:        xorw    %bp, %bp
-       ret
-
-everex_md:
-       .byte   0x03, 0x22, 0x50
-       .byte   0x04, 0x3c, 0x50
-       .byte   0x07, 0x2b, 0x64
-       .byte   0x08, 0x4b, 0x64
-       .byte   0x0a, 0x19, 0x84
-       .byte   0x0b, 0x2c, 0x84
-       .byte   0x16, 0x1e, 0x50
-       .byte   0x18, 0x1b, 0x64
-       .byte   0x21, 0x40, 0xa0
-       .byte   0x40, 0x1e, 0x84
-       .byte   0
-       .ascii  "Everex/Trident"
-       .byte   0
-
-# Genoa.
-genoa_test:
-       leaw    idgenoa, %si                    # Check Genoa 'clues'
-       xorw    %ax, %ax
-       movb    %es:(0x37), %al
-       movw    %ax, %di
-       movw    $0x04, %cx
-       decw    %si
-       decw    %di
-l1:    incw    %si
-       incw    %di
-       movb    (%si), %al
-       testb   %al, %al
-       jz      l2
-
-       cmpb    %es:(%di), %al
-l2:    loope   l1
-       orw     %cx, %cx
-       je      isgen
-       
-       xorw    %bp, %bp
-isgen: ret
-
-idgenoa: .byte 0x77, 0x00, 0x99, 0x66
-
-genoa_md:
-       .byte   0x58, 0x20, 0x50
-       .byte   0x5a, 0x2a, 0x64
-       .byte   0x60, 0x19, 0x84
-       .byte   0x61, 0x1d, 0x84
-       .byte   0x62, 0x20, 0x84
-       .byte   0x63, 0x2c, 0x84
-       .byte   0x64, 0x3c, 0x84
-       .byte   0x6b, 0x4f, 0x64
-       .byte   0x72, 0x3c, 0x50
-       .byte   0x74, 0x42, 0x50
-       .byte   0x78, 0x4b, 0x64
-       .byte   0
-       .ascii  "Genoa"
-       .byte   0
-
-# OAK
-oak_test:
-       leaw    idoakvga, %si
-       movw    $0x08, %di
-       movw    $0x08, %cx
-       repe
-       cmpsb
-       je      isoak
-       
-       xorw    %bp, %bp
-isoak: ret
-
-idoakvga: .ascii  "OAK VGA "
-
-oak_md: .byte  0x4e, 0x3c, 0x50
-       .byte   0x4f, 0x3c, 0x84
-       .byte   0x50, 0x19, 0x84
-       .byte   0x51, 0x2b, 0x84
-       .byte   0
-       .ascii  "OAK"
-       .byte   0
-
-# WD Paradise.
-paradise_test:
-       leaw    idparadise, %si
-       movw    $0x7d, %di
-       movw    $0x04, %cx
-       repe
-       cmpsb
-       je      ispara
-       
-       xorw    %bp, %bp
-ispara:        ret
-
-idparadise:    .ascii  "VGA="
-
-paradise_md:
-       .byte   0x41, 0x22, 0x50
-       .byte   0x47, 0x1c, 0x84
-       .byte   0x55, 0x19, 0x84
-       .byte   0x54, 0x2c, 0x84
-       .byte   0
-       .ascii  "Paradise"
-       .byte   0
-
-# Trident.
-trident_test:
-       movw    $0x3c4, %dx
-       movb    $0x0e, %al
-       outb    %al, %dx
-       incw    %dx
-       inb     %dx, %al
-       xchgb   %al, %ah
-       xorb    %al, %al
-       outb    %al, %dx
-       inb     %dx, %al
-       xchgb   %ah, %al
-       movb    %al, %bl        # Strange thing ... in the book this wasn't
-       andb    $0x02, %bl      # necessary but it worked on my card which
-       jz      setb2           # is a trident. Without it the screen goes
-                               # blurred ...
-       andb    $0xfd, %al
-       jmp     clrb2           
-
-setb2: orb     $0x02, %al      
-clrb2: outb    %al, %dx
-       andb    $0x0f, %ah
-       cmpb    $0x02, %ah
-       je      istrid
-
-       xorw    %bp, %bp
-istrid:        ret
-
-trident_md:
-       .byte   0x50, 0x1e, 0x50
-       .byte   0x51, 0x2b, 0x50
-       .byte   0x52, 0x3c, 0x50
-       .byte   0x57, 0x19, 0x84
-       .byte   0x58, 0x1e, 0x84
-       .byte   0x59, 0x2b, 0x84
-       .byte   0x5a, 0x3c, 0x84
-       .byte   0
-       .ascii  "Trident"
-       .byte   0
-
-# Tseng.
-tseng_test:
-       movw    $0x3cd, %dx
-       inb     %dx, %al        # Could things be this simple ! :-)
-       movb    %al, %bl
-       movb    $0x55, %al
-       outb    %al, %dx
-       inb     %dx, %al
-       movb    %al, %ah
-       movb    %bl, %al
-       outb    %al, %dx
-       cmpb    $0x55, %ah
-       je      istsen
-
-isnot: xorw    %bp, %bp
-istsen:        ret
-
-tseng_md:
-       .byte   0x26, 0x3c, 0x50
-       .byte   0x2a, 0x28, 0x64
-       .byte   0x23, 0x19, 0x84
-       .byte   0x24, 0x1c, 0x84
-       .byte   0x22, 0x2c, 0x84
-       .byte   0x21, 0x3c, 0x84
-       .byte   0
-       .ascii  "Tseng"
-       .byte   0
-
-# Video7.
-video7_test:
-       movw    $0x3cc, %dx
-       inb     %dx, %al
-       movw    $0x3b4, %dx
-       andb    $0x01, %al
-       jz      even7
-
-       movw    $0x3d4, %dx
-even7: movb    $0x0c, %al
-       outb    %al, %dx
-       incw    %dx
-       inb     %dx, %al
-       movb    %al, %bl
-       movb    $0x55, %al
-       outb    %al, %dx
-       inb     %dx, %al
-       decw    %dx
-       movb    $0x1f, %al
-       outb    %al, %dx
-       incw    %dx
-       inb     %dx, %al
-       movb    %al, %bh
-       decw    %dx
-       movb    $0x0c, %al
-       outb    %al, %dx
-       incw    %dx
-       movb    %bl, %al
-       outb    %al, %dx
-       movb    $0x55, %al
-       xorb    $0xea, %al
-       cmpb    %bh, %al
-       jne     isnot
-       
-       movb    $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
-       ret
-
-video7_md:
-       .byte   0x40, 0x2b, 0x50
-       .byte   0x43, 0x3c, 0x50
-       .byte   0x44, 0x3c, 0x64
-       .byte   0x41, 0x19, 0x84
-       .byte   0x42, 0x2c, 0x84
-       .byte   0x45, 0x1c, 0x84
-       .byte   0
-       .ascii  "Video 7"
-       .byte   0
-
-# Realtek VGA
-realtek_test:
-       leaw    idrtvga, %si
-       movw    $0x45, %di
-       movw    $0x0b, %cx
-       repe
-       cmpsb
-       je      isrt
-       
-       xorw    %bp, %bp
-isrt:  ret
-
-idrtvga:       .ascii  "REALTEK VGA"
-
-realtek_md:
-       .byte   0x1a, 0x3c, 0x50
-       .byte   0x1b, 0x19, 0x84
-       .byte   0x1c, 0x1e, 0x84
-       .byte   0x1d, 0x2b, 0x84
-       .byte   0x1e, 0x3c, 0x84
-       .byte   0
-       .ascii  "REALTEK"
-       .byte   0
-
-#endif /* CONFIG_VIDEO_SVGA */
-
-# User-defined local mode table (VGA only)
-#ifdef CONFIG_VIDEO_LOCAL
-local_modes:
-       leaw    local_mode_table, %si
-locm1: lodsw
-       orw     %ax, %ax
-       jz      locm2
-       
-       stosw
-       movsw
-       jmp     locm1
-
-locm2: ret
-
-# This is the table of local video modes which can be supplied manually
-# by the user. Each entry consists of mode ID (word) and dimensions
-# (byte for column count and another byte for row count). These modes
-# are placed before all SVGA and VESA modes and override them if table
-# compacting is enabled. The table must end with a zero word followed
-# by NUL-terminated video adapter name.
-local_mode_table:
-       .word   0x0100                          # Example: 40x25
-       .byte   25,40
-       .word   0
-       .ascii  "Local"
-       .byte   0
-#endif /* CONFIG_VIDEO_LOCAL */
-
-# Read a key and return the ASCII code in al, scan code in ah
-getkey:        xorb    %ah, %ah
-       int     $0x16
-       ret
-
-# Read a key with a timeout of 30 seconds.
-# The hardware clock is used to get the time.
-getkt: call    gettime
-       addb    $30, %al                        # Wait 30 seconds
-       cmpb    $60, %al
-       jl      lminute
-
-       subb    $60, %al
-lminute:
-       movb    %al, %cl
-again: movb    $0x01, %ah
-       int     $0x16
-       jnz     getkey                          # key pressed, so get it
-
-       call    gettime
-       cmpb    %cl, %al
-       jne     again
-
-       movb    $0x20, %al                      # timeout, return `space'
-       ret
-
-# Flush the keyboard buffer
-flush: movb    $0x01, %ah
-       int     $0x16
-       jz      empty
-       
-       xorb    %ah, %ah
-       int     $0x16
-       jmp     flush
-
-empty: ret
-
-# Print hexadecimal number.
-prthw: pushw   %ax
-       movb    %ah, %al
-       call    prthb
-       popw    %ax
-prthb: pushw   %ax
-       shrb    $4, %al
-       call    prthn
-       popw    %ax
-       andb    $0x0f, %al
-prthn: cmpb    $0x0a, %al
-       jc      prth1
-
-       addb    $0x07, %al
-prth1: addb    $0x30, %al
-       jmp     prtchr
-
-# Print decimal number in al
-prtdec:        pushw   %ax
-       pushw   %cx
-       xorb    %ah, %ah
-       movb    $0x0a, %cl
-       idivb   %cl
-       cmpb    $0x09, %al
-       jbe     lt100
-
-       call    prtdec
-       jmp     skip10
-
-lt100: addb    $0x30, %al
-       call    prtchr
-skip10:        movb    %ah, %al
-       addb    $0x30, %al
-       call    prtchr  
-       popw    %cx
-       popw    %ax
-       ret
-
-store_edid:
-#ifdef CONFIG_FIRMWARE_EDID
-       pushw   %es                             # just save all registers
-       pushw   %ax
-       pushw   %bx
-       pushw   %cx
-       pushw   %dx
-       pushw   %di
-
-       pushw   %fs
-       popw    %es
-
-       movl    $0x13131313, %eax               # memset block with 0x13
-       movw    $32, %cx
-       movw    $0x140, %di
-       cld
-       rep
-       stosl
-
-       cmpw    $0x0200, vbe_version            # only do EDID on >= VBE2.0
-       jl      no_edid
-
-       pushw   %es                             # save ES
-       xorw    %di, %di                        # Report Capability
-       pushw   %di
-       popw    %es                             # ES:DI must be 0:0
-       movw    $0x4f15, %ax
-       xorw    %bx, %bx
-       xorw    %cx, %cx
-       int     $0x10
-       popw    %es                             # restore ES
-
-       cmpb    $0x00, %ah                      # call successful
-       jne     no_edid
-
-       cmpb    $0x4f, %al                      # function supported
-       jne     no_edid
-
-       movw    $0x4f15, %ax                    # do VBE/DDC
-       movw    $0x01, %bx
-       movw    $0x00, %cx
-       movw    $0x00, %dx
-       movw    $0x140, %di
-       int     $0x10
-
-no_edid:
-       popw    %di                             # restore all registers
-       popw    %dx
-       popw    %cx
-       popw    %bx
-       popw    %ax
-       popw    %es
-#endif
-       ret
-
-# VIDEO_SELECT-only variables
-mt_end:                .word   0       # End of video mode table if built
-edit_buf:      .space  6       # Line editor buffer
-card_name:     .word   0       # Pointer to adapter name
-scanning:      .byte   0       # Performing mode scan
-do_restore:    .byte   0       # Screen contents altered during mode change
-svga_prefix:   .byte   VIDEO_FIRST_BIOS>>8     # Default prefix for BIOS modes
-graphic_mode:  .byte   0       # Graphic mode with a linear frame buffer
-dac_size:      .byte   6       # DAC bit depth
-vbe_version:   .word   0       # VBE bios version
-
-# Status messages
-keymsg:                .ascii  "Press <RETURN> to see video modes available, "
-               .ascii  "<SPACE> to continue or wait 30 secs"
-               .byte   0x0d, 0x0a, 0
-
-listhdr:       .byte   0x0d, 0x0a
-               .ascii  "Mode:    COLSxROWS:"
-
-crlft:         .byte   0x0d, 0x0a, 0
-
-prompt:                .byte   0x0d, 0x0a
-               .asciz  "Enter mode number or `scan': "
-
-unknt:         .asciz  "Unknown mode ID. Try again."
-
-badmdt:                .ascii  "You passed an undefined mode number."
-               .byte   0x0d, 0x0a, 0
-
-vesaer:                .ascii  "Error: Scanning of VESA modes failed. Please "
-               .ascii  "report to <mj@ucw.cz>."
-               .byte   0x0d, 0x0a, 0
-
-old_name:      .asciz  "CGA/MDA/HGA"
-
-ega_name:      .asciz  "EGA"
-
-svga_name:     .ascii  " "
-
-vga_name:      .asciz  "VGA"
-
-vesa_name:     .asciz  "VESA"
-
-name_bann:     .asciz  "Video adapter: "
-#endif /* CONFIG_VIDEO_SELECT */
-
-# Other variables:
-adapter:       .byte   0       # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
-video_segment: .word   0xb800  # Video memory segment
-force_size:    .word   0       # Use this size instead of the one in BIOS vars
diff --git a/arch/i386/boot/video.c b/arch/i386/boot/video.c
new file mode 100644 (file)
index 0000000..3bb3573
--- /dev/null
@@ -0,0 +1,456 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 1991, 1992 Linus Torvalds
+ *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/video.c
+ *
+ * Select video mode
+ */
+
+#include "boot.h"
+#include "video.h"
+#include "vesa.h"
+
+/*
+ * Mode list variables
+ */
+static struct card_info cards[];    /* List of cards to probe for */
+
+/*
+ * Common variables
+ */
+int adapter;                   /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
+u16 video_segment;
+int force_x, force_y;  /* Don't query the BIOS for cols/rows */
+
+int do_restore = 0;    /* Screen contents changed during mode flip */
+int graphic_mode;      /* Graphic mode with linear frame buffer */
+
+static void store_cursor_position(void)
+{
+       u16 curpos;
+       u16 ax, bx;
+
+       ax = 0x0300;
+       bx = 0;
+       asm(INT10
+           : "=d" (curpos), "+a" (ax), "+b" (bx)
+           : : "ecx", "esi", "edi");
+
+       boot_params.screen_info.orig_x = curpos;
+       boot_params.screen_info.orig_y = curpos >> 8;
+}
+
+static void store_video_mode(void)
+{
+       u16 ax, page;
+
+       /* N.B.: the saving of the video page here is a bit silly,
+          since we pretty much assume page 0 everywhere. */
+       ax = 0x0f00;
+       asm(INT10
+           : "+a" (ax), "=b" (page)
+           : : "ecx", "edx", "esi", "edi");
+
+       /* Not all BIOSes are clean with respect to the top bit */
+       boot_params.screen_info.orig_video_mode = ax & 0x7f;
+       boot_params.screen_info.orig_video_page = page;
+}
+
+/*
+ * Store the video mode parameters for later usage by the kernel.
+ * This is done by asking the BIOS except for the rows/columns
+ * parameters in the default 80x25 mode -- these are set directly,
+ * because some very obscure BIOSes supply insane values.
+ */
+static void store_mode_params(void)
+{
+       u16 font_size;
+       int x, y;
+
+       /* For graphics mode, it is up to the mode-setting driver
+          (currently only video-vesa.c) to store the parameters */
+       if (graphic_mode)
+               return;
+
+       store_cursor_position();
+       store_video_mode();
+
+       if (boot_params.screen_info.orig_video_mode == 0x07) {
+               /* MDA, HGC, or VGA in monochrome mode */
+               video_segment = 0xb000;
+       } else {
+               /* CGA, EGA, VGA and so forth */
+               video_segment = 0xb800;
+       }
+
+       set_fs(0);
+       font_size = rdfs16(0x485); /* Font size, BIOS area */
+       boot_params.screen_info.orig_video_points = font_size;
+
+       x = rdfs16(0x44a);
+       y = (adapter == ADAPTER_CGA) ? 25 : rdfs8(0x484)+1;
+
+       if (force_x)
+               x = force_x;
+       if (force_y)
+               y = force_y;
+
+       boot_params.screen_info.orig_video_cols  = x;
+      &n