Commit 90ff4d27 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.21

parent 0983223c
......@@ -2,7 +2,7 @@
-----------------------
Maintained by Geert Uytterhoeven <geert@linux-m68k.org>
Last revised: November 7, 1998
Last revised: October 7, 1999
0. Introduction
......@@ -304,7 +304,20 @@ applications, please refer to the following documentation:
o linux/include/video/
8. Downloading
8. Mailing list
---------------
There's a _development_ mailing list at linux-fbdev@vuser.vu.union.edu,
controlled by majordomo. Send an email with `help' in the message body to
majordomo@vuser.vu.union.edu for subscription information.
The mailing list is archived at
http://www.mail-archive.com/linux-fbdev@vuser.vu.union.edu/
9. Downloading
--------------
All necessary files can be found at
......@@ -313,8 +326,12 @@ All necessary files can be found at
and on its mirrors.
The latest version of fbset can be found at
http://www.cs.kuleuven.ac.be/~geert/bin/
9. Credits
10. Credits
----------
This readme was written by Geert Uytterhoeven, partly based on the original
......
......@@ -8,9 +8,6 @@
# Copyright (C) 1994 by Linus Torvalds
#
AS86 =$(CROSS_COMPILE)as86 -0 -a
LD86 =$(CROSS_COMPILE)ld86 -0
BOOT_INCL = $(TOPDIR)/include/linux/config.h \
$(TOPDIR)/include/linux/autoconf.h \
$(TOPDIR)/include/asm/boot.h
......@@ -45,40 +42,40 @@ install: $(CONFIGURE) $(BOOTIMAGE)
tools/build: tools/build.c
$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
setup: setup.o
$(LD86) -s -o $@ $<
bootsect: bootsect.o
$(LD) -Ttext 0x0 -s -oformat binary -o $@ $<
setup.o: setup.s
$(AS86) -o $@ $<
bootsect.o: bootsect.s
$(AS) -o $@ $<
setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
bootsect.s: bootsect.S Makefile $(BOOT_INCL)
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bsetup: bsetup.o
$(LD86) -s -o $@ $<
bbootsect: bbootsect.o bsetup
$(LD) -Ttext 0x0 -s -oformat binary $< -R bsetup.o -o $@
bsetup.o: bsetup.s
$(AS86) -o $@ $<
bbootsect.o: bbootsect.s
$(AS) -o $@ $<
bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
$(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bootsect: bootsect.o
$(LD86) -s -o $@ $<
setup: setup.o
$(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $<
bootsect.o: bootsect.s
$(AS86) -o $@ $<
setup.o: setup.s
$(AS) -o $@ $<
bootsect.s: bootsect.S Makefile $(BOOT_INCL)
setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bbootsect: bbootsect.o
$(LD86) -s -o $@ $<
bsetup: bsetup.o
$(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $<
bbootsect.o: bbootsect.s
$(AS86) -o $@ $<
bsetup.o: bsetup.s
$(AS) -o $@ $<
bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
$(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
dep:
......
!
! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
! modified by Drew Eckhardt
! modified by Bruce Evans (bde)
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
! itself out of the way to address 0x90000, and jumps there.
!
! bde - should not jump blindly, there may be systems with only 512K low
! memory. Use int 0x12 to get the top of memory, etc.
!
! It then loads 'setup' directly after itself (0x90200), and the system
! at 0x10000, using BIOS interrupts.
!
! NOTE! currently system is at most (8*65536-4096) bytes long. This should
! be no problem, even in the future. I want to keep it simple. This 508 kB
! kernel size should be enough, especially as this doesn't contain the
! buffer cache as in minix (and especially now that the kernel is
! compressed :-)
!
! The loader has been made as simple as possible, and continuous
! read errors will result in a unbreakable loop. Reboot by hand. It
! loads pretty fast by getting whole tracks at a time whenever possible.
#include <linux/config.h> /* for CONFIG_ROOT_RDONLY */
/*
* 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)
*
* bootsect is loaded at 0x7c00 by the bios-startup routines, and moves
* itself out of the way to address 0x90000, and jumps there.
*
* bde - should not jump blindly, there may be systems with only 512K low
* memory. Use int 0x12 to get the top of memory, etc.
*
* It then loads 'setup' directly after itself (0x90200), and the system
* at 0x10000, using BIOS interrupts.
*
* NOTE! currently system is at most (8*65536-4096) bytes long. This should
* be no problem, even in the future. I want to keep it simple. This 508 kB
* kernel size should be enough, especially as this doesn't contain the
* buffer cache as in minix (and especially now that the kernel is
* compressed :-)
*
* The loader has been made as simple as possible, and continuous
* read errors will result in a unbreakable loop. Reboot by hand. It
* loads pretty fast by getting whole tracks at a time whenever possible.
*/
#include <linux/config.h> /* for CONFIG_ROOT_RDONLY */
#include <asm/boot.h>
.text
SETUPSECS = 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" */
SETUPSECS = 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: number of 16-byte clicks
! to be loaded
! ROOT_DEV & SWAP_DEV are now written by "build".
ROOT_DEV = 0
SWAP_DEV = 0
#ifndef SVGA_MODE
#define SVGA_MODE ASK_VGA
#endif
#ifndef RAMDISK
#define RAMDISK 0
#endif
#ifndef CONFIG_ROOT_RDONLY
#define CONFIG_ROOT_RDONLY 1
#endif
! ld86 requires an entry symbol. This may as well be the usual one.
.globl _main
_main:
.code16
.text
.global _start
_start:
#if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */
int 3
int $0x3
#endif
mov ax,#BOOTSEG
mov ds,ax
mov ax,#INITSEG
mov es,ax
mov cx,#128
sub si,si
sub di,di
movw $BOOTSEG, %ax
movw %ax, %ds
movw $INITSEG, %ax
movw %ax, %es
movw $128, %cx
subw %si, %si
subw %di, %di
cld
rep
movsd
jmpi go,INITSEG
! ax and es already contain INITSEG
go: mov di,#0x4000-12 ! 0x4000 is arbitrary value >= length of
! bootsect + length of setup + room for stack
! 12 is disk parm size
! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
! wouldn't have to worry about this if we checked the top of memory. Also
! my BIOS can be configured to put the wini drive tables in high memory
! instead of in the vector table. The old stack might have clobbered the
! drive table.
mov ds,ax
mov ss,ax ! put stack at INITSEG:0x4000-12.
mov sp,di
/*
* Many BIOS's default disk parameter tables will not
* recognize multi-sector reads beyond the maximum sector number
* specified in the default diskette parameter tables - this may
* mean 7 sectors in some cases.
*
* Since single sector reads are slow and out of the question,
* we must take care of this by creating new parameter tables
* (for the first disk) in RAM. We will set the maximum sector
* count to 36 - the most we will encounter on an ED 2.88.
*
* High doesn't hurt. Low does.
*
* Segments are as follows: ds=es=ss=cs - INITSEG,
* fs = 0, gs is unused.
*/
! cx contains 0 from rep movsd above
mov fs,cx
mov bx,#0x78 ! fs:bx is parameter table address
push ds
seg fs
lds si,(bx) ! ds:si is source
mov cl,#3 ! copy 12 bytes
movsl
ljmp $INITSEG, $go
# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
# wouldn't have to worry about this if we checked the top of memory. Also
# my BIOS can be configured to put the wini drive tables in high memory
# instead of in the vector table. The old stack might have clobbered the
# drive table.
go: movw $0x4000-12, %di # 0x4000 is an arbitrary value >=
# length of bootsect + length of
# setup + room for stack;
# 12 is disk parm size.
movw %ax, %ds # ax and es already contain INITSEG
movw %ax, %ss
movw %di, %sp # put stack at INITSEG:0x4000-12.
# Many BIOS's default disk parameter tables will not recognize
# multi-sector reads beyond the maximum sector number specified
# in the default diskette parameter tables - this may mean 7
# sectors in some cases.
#
# Since single sector reads are slow and out of the question,
# we must take care of this by creating new parameter tables
# (for the first disk) in RAM. We will set the maximum sector
# count to 36 - the most we will encounter on an ED 2.88.
#
# High doesn't hurt. Low does.
#
# Segments are as follows: ds = es = ss = cs - INITSEG, fs = 0,
# and gs is unused.
movw %cx, %fs # set fs to 0
movw $0x78, %bx # fs:bx is parameter table address
pushw %ds
ldsw %fs:(%bx), %si # ds:si is source
movb $3, %cl # copy 12 bytes
cld
push di
pushw %di # di = 0x4000-12.
rep
movsd
pop di
pop ds
movsl
popw %di
popw %ds
movb $36, 0x4(%di) # patch sector count
movw %di, %fs:(%bx)
movw %es, %fs:2(%bx)
movb 4(di),*36 ! patch sector count
seg fs
mov (bx),di
seg fs
mov 2(bx),es
! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.
! Also cx is 0 from rep movsd above.
# Load the setup-sectors directly after the bootblock.
# Note that 'es' is already set up.
# Also, cx = 0 from rep movsl above.
load_setup:
xor ah,ah ! reset FDC
xor dl,dl
int 0x13
xor dx, dx ! drive 0, head 0
mov cl,#0x02 ! sector 2, track 0
mov bx,#0x0200 ! address = 512, in INITSEG
mov ah,#0x02 ! service 2, nr of sectors
mov al,setup_sects ! (assume all on head 0, track 0)
int 0x13 ! read it
jnc ok_load_setup ! ok - continue
push ax ! dump error code
xorb %ah, %ah # reset FDC
xorb %dl, %dl
int $0x13
xorw %dx, %dx # drive 0, head 0
movb $0x02, %cl # sector 2, track 0
movw $0x0200, %bx # address = 512, in INITSEG
movb $0x02, %ah # service 2, "read sector(s)"
movb setup_sects, %al # (assume all on head 0, track 0)
int $0x13 # read it
jnc ok_load_setup # ok - continue
pushw %ax # dump error code
call print_nl
mov bp, sp
movw %sp, %bp
call print_hex
pop ax
popw %ax
jmp load_setup
ok_load_setup:
! Get disk drive parameters, specifically nr of sectors/track
# Get disk drive parameters, specifically nr of sectors/track.
#if 0
! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
! disks. It doesn't work for one of my BIOS's (1987 Award). It was
! fatal not to check the error code.
# bde - the Phoenix BIOS manual says function 0x08 only works for fixed
# disks. It doesn't work for one of my BIOS's (1987 Award). It was
# fatal not to check the error code.
xor dl,dl
mov ah,#0x08 ! AH=8 is get drive parameters
int 0x13
xor ch,ch
#else
xorb %dl, %dl
movb $0x08, %ah # AH=8 is get drive parameters
int $0x13
xorb %ch, %ch
! It seems that there is no BIOS call to get the number of sectors. Guess
! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
! 15 if sector 15 can be read. Otherwise guess 9.
#else
mov si,#disksizes ! table of sizes to try
# It seems that there is no BIOS call to get the number of sectors.
# Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18
# can be read, 15 if sector 15 can be read. Otherwise guess 9.
movw $disksizes, %si # table of sizes to try
probe_loop:
lodsb
cbw ! extend to word
mov sectors, ax
cmp si,#disksizes+4
jae got_sectors ! if all else fails, try 9
xchg ax, cx ! cx = track and sector
xor dx, dx ! drive 0, head 0
xor bl, bl
mov bh,setup_sects
inc bh
shl bh,#1 ! address after setup (es = cs)
mov ax,#0x0201 ! service 2, 1 sector
int 0x13
jc probe_loop ! try next value
cbtw # extend to word
movw %ax, sectors
cmpw $disksizes+4, %si
jae got_sectors # if all else fails, try 9
xchgw %cx, %ax # cx = track and sector
xorw %dx, %dx # drive 0, head 0
xorb %bl, %bl
movb setup_sects, %bh
incb %bh
shlb %bh # address after setup (es = cs)
movw $0x0201, %ax # service 2, 1 sector
int $0x13
jc probe_loop # try next value
#endif
got_sectors:
! Restore es
mov ax,#INITSEG
mov es,ax
! Print some inane message
mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10
mov cx,#9
mov bx,#0x0007 ! page 0, attribute 7 (normal)
mov bp,#msg1
mov ax,#0x1301 ! write string, move cursor
int 0x10
! ok, we've written the message, now
! we want to load the system (at 0x10000)
mov ax,#SYSSEG
mov es,ax ! segment of 0x010000
movw $INITSEG, %ax
movw %ax, %es # set up es
movb $0x03, %ah # read cursor pos
xorb %bh, %bh
int $0x10
movw $9, %cx
movw $0x0007, %bx # page 0, attribute 7 (normal)
movw $msg1, %bp
movw $0x1301, %ax # write string, move cursor
int $0x10 # tell the user we're loading..
movw $SYSSEG, %ax # ok, we've written the message, now
movw %ax, %es # we want to load system (at 0x10000)
call read_it
call kill_motor
call print_nl
! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
! Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8),
! depending on the number of sectors we pretend to know we have.
# After that we check which root-device to use. If the device is
# defined (!= 0), nothing is done and the given device is used.
# Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
# depending on the number of sectors we pretend to know we have.
seg cs
mov ax,root_dev
or ax,ax
movw %cs:root_dev, %ax
orw %ax, %ax
jne root_defined
seg cs
mov bx,sectors
mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
cmp bx,#15
movw %cs:sectors, %bx
movw $0x0208, %ax # /dev/ps0 - 1.2Mb
cmpw $15, %bx
je root_defined
mov al,#0x1c ! /dev/PS0 - 1.44Mb
cmp bx,#18
movb $0x1c, %al # /dev/PS0 - 1.44Mb
cmpw $18, %bx
je root_defined
mov al,#0x20 ! /dev/fd0H2880 - 2.88Mb
cmp bx,#36
movb $0x20, %al # /dev/fd0H2880 - 2.88Mb
cmpw $36, %bx
je root_defined
mov al,#0 ! /dev/fd0 - autodetect
movb $0, %al # /dev/fd0 - autodetect
root_defined:
seg cs
mov root_dev,ax
movw %ax, %cs:root_dev
# After that (everything loaded), we jump to the setup-routine
# loaded directly after the bootblock:
! after that (everything loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:
ljmp $SETUPSEG, $0
jmpi 0,SETUPSEG
# This routine loads the system at address 0x10000, making sure
# no 64kB boundaries are crossed. We try to load it as fast as
# possible, loading whole tracks whenever we can.
! This routine loads the system at address 0x10000, making sure
! no 64kB boundaries are crossed. We try to load it as fast as
! possible, loading whole tracks whenever we can.
!
! in: es - starting address segment (normally 0x1000)
!
sread: .word 0 ! sectors read of current track
head: .word 0 ! current head
track: .word 0 ! current track
# es = starting address segment (normally 0x1000)
sread: .word 0 # sectors read of current track
head: .word 0 # current head
track: .word 0 # current track
read_it:
mov al,setup_sects
inc al
mov sread,al
mov ax,es
test ax,#0x0fff
die: jne die ! es must be at 64kB boundary
xor bx,bx ! bx is starting address within segment
movb setup_sects, %al
incb %al
movb %al, sread
movw %es, %ax
testw $0x0fff, %ax
die: jne die # es must be at 64kB boundary
xorw %bx, %bx # bx is starting address within segment
rp_read:
#ifdef __BIG_KERNEL__
#define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge
! NOTE: as86 can't assemble this
CALL_HIGHLOAD_KLUDGE ! this is within setup.S
lcall bootsect_kludge # in setup.S
#else
mov ax,es
sub ax,#SYSSEG
movw %es, %ax
subw $SYSSEG, %ax
#endif
cmp ax,syssize ! have we loaded all yet?
jbe ok1_read
cmpw syssize, %ax # have we loaded all yet?
jbe ok1_read
ret
ok1_read:
mov ax,sectors
sub ax,sread
mov cx,ax
shl cx,#9
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,#9
movw sectors, %ax
subw sread, %ax
movw %ax, %cx
shlw $9, %cx
addw %bx, %cx
jnc ok2_read
je ok2_read
xorw %ax, %ax
subw %bx, %ax
shrw $9, %ax
ok2_read:
call read_track
mov cx,ax
add ax,sread
cmp ax,sectors
jne ok3_read
mov ax,#1
sub ax,head
jne ok4_read
inc track
call read_track
movw %ax, %cx
addw sread, %ax
cmpw sectors, %ax
jne ok3_read
movw $1, %ax
subw head, %ax
jne ok4_read
incw track
ok4_read:
mov head,ax
xor ax,ax
movw %ax, head
xorw %ax, %ax
ok3_read:
mov sread,ax
shl cx,#9
add bx,cx
jnc rp_read
mov ax,es
add ah,#0x10
mov es,ax
xor bx,bx
jmp rp_read
movw %ax, sread
shlw $9, %cx
addw %cx, %bx
jnc rp_read
movw %es, %ax
addb $0x10, %ah
movw %ax, %es
xorw %bx, %bx
jmp rp_read
read_track:
pusha
pusha
mov ax, #0xe2e ! loading... message 2e = .
mov bx, #7
int 0x10
movw $0xe2e, %ax # loading... message 2e = .
movw $7, %bx
int $0x10
popa
mov dx,track
mov cx,sread
inc cx
mov ch,dl
mov dx,head
mov dh,dl
and dx,#0x0100
mov ah,#2
push dx ! save for error dump
push cx
push bx
push ax
int 0x13
movw track, %dx
movw sread, %cx
incw %cx
movb %dl, %ch
movw head, %dx
movb %dl, %dh
andw $0x0100, %dx
movb $2, %ah
pushw %dx # save for error dump
pushw %cx
pushw %bx
pushw %ax
int $0x13
jc bad_rt
add sp, #8
addw $8, %sp
popa
ret
bad_rt: push ax ! save error code
call print_all ! ah = error, al = read
xor ah,ah
xor dl,dl
int 0x13
add sp, #10
popa
bad_rt:
pushw %ax # save error code
call print_all # ah = error, al = read
xorb %ah, %ah
xorb %dl, %dl
int $0x13
addw $10, %sp
popa
jmp read_track
/*
* print_all is for debugging purposes.
* It will print out all of the registers. The assumption is that this is
* called from a routine, with a stack frame like
* dx
* cx
* bx
* ax
* error
* ret <- sp
*
*/
# print_all is for debugging purposes.
#
# it will print out all of the registers. The assumption is that this is
# called from a routine, with a stack frame like
#
# %dx
# %cx
# %bx
# %ax
# (error)
# ret <- %sp
print_all:
mov cx, #5 ! error code + 4 registers
mov bp, sp
movw $5, %cx # error code + 4 registers
movw %sp, %bp
print_loop:
push cx ! save count left
call print_nl ! nl for readability
cmp cl, #5
jae no_reg ! see if register name is needed
pushw %cx # save count left
call print_nl # nl for readability
cmpb $5, %cl
jae no_reg # see if register name is needed
mov ax, #0xe05 + 'A - 1
sub al, cl
int 0x10
mov al, #'X
int 0x10
mov al, #':
int 0x10
movw $0xe05 + 'A' - 1, %ax
subb %cl, %al
int $0x10
movb $'X', %al
int $0x10
movb $':', %al
int $0x10
no_reg:
add bp, #2 ! next register
call print_hex ! print it
pop cx
addw $2, %bp # next register
call print_hex # print it
popw %cx
loop print_loop
ret
print_nl:
mov ax, #0xe0d ! CR
int 0x10
mov al, #0xa ! LF
int 0x10
movw $0xe0d, %ax # CR
int $0x10
movb $0xa, %al # LF
int $0x10
ret
/*
* print_hex is for debugging purposes, and prints the word
* pointed to by ss:bp in hexadecimal.
*/
# print_hex is for debugging purposes, and prints the word
# pointed to by ss:bp in hexadecimal.
print_hex:
mov cx, #4 ! 4 hex digits
mov dx, (bp) ! load word into dx
movw $4, %cx # 4 hex digits
movw (%bp), %dx # load word into dx
print_digit:
rol dx, #4 ! rotate so that lowest 4 bits are used
mov ax, #0xe0f ! ah = request, al = mask for nybble
and al, dl
add al, #0x90 ! convert al to ASCII hex (four instructions)
rolw $4, %dx # rotate to use low 4 bits
movw $0xe0f, %ax # ah = request
andb %dl, %al # al = mask for nybble
addb $0x90, %al # convert al to ascii hex
daa # in only four instructions!
adc $0x40, %al
daa
adc al, #0x40
daa
int 0x10
int $0x10
loop print_digit
ret
# This procedure turns off the floppy drive motor, so
# that we enter the kernel in a known state, and
# don't have to worry about it later.
/*
* This procedure turns off the floppy drive motor, so
* that we enter the kernel in a known state, and
* don't have to worry about it later.
*/
kill_motor:
push dx
mov dx,#0x3f2
xor al, al
outb
pop dx
pushw %dx
movw $0x3f2, %dx
xorb %al, %al
outw %al, %dx
popw %dx
ret
sectors:
.word 0
disksizes:
.byte 36,18,15,9
sectors: .word 0
disksizes: .byte 36, 18, 15, 9
msg1: .byte 13, 10
.ascii "Loading"
msg1:
.byte 13,10
.ascii "Loading"
# XXX: This is a *very* snug fit.
.org 497
setup_sects:
.byte SETUPSECS
root_flags:
.word CONFIG_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
setup_sects: .byte SETUPSECS
root_flags: .word CONFIG_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
......@@ -39,7 +39,7 @@ piggy.o: $(SYSTEM)
$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
$(LD) -m elf_i386 -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
clean:
......
!
! 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
! (Stephen.Rothwell@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
!
/*
* 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
* (Stephen.Rothwell@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>
*/
#define __ASSEMBLY__
#include <linux/config.h>
......@@ -39,17 +42,20 @@
#include <asm/boot.h>
#include <asm/e820.h>
! Signature words to ensure LILO loaded us right
/* 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
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
......@@ -58,631 +64,617 @@ begdata:
begbss:
.text
entry start
start:
jmp trampoline
! ------------------------ start of header --------------------------------
!
! SETUP-header, must start at CS:2 (old 0x9020:2)
!
.ascii "HdrS" ! Signature for SETUP-header
.word 0x0201 ! Version number of header format
! (must be >= 0x0105
! else old loadlin-1.5 will fail)
realmode_swtch: .word 0,0 ! default_switch,SETUPSEG
# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
.ascii "HdrS" # header signature
.word 0x0201 # 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
! note: above part of header is compatible with loadlin-1.5 (header v1.5),
! must not change it
type_of_loader: .byte 0 ! = 0, old one (LILO, Loadlin,
! Bootlin, SYSLX, bootsect...)
! else it is set by the loader:
! 0xTV: T=0 for LILO
! T=1 for Loadlin
! T=2 for bootsect-loader
! T=3 for SYSLX
! T=4 for ETHERBOOT
! V = version
loadflags: ! flags, unused bits must be zero (RFU)
LOADED_HIGH = 1 ! bit within loadflags,
! if set, then 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!
.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...)
# else it is set by the loader:
# 0xTV: T=0 for LILO
# T=1 for Loadlin
# T=2 for bootsect-loader
# T=3 for SYSLX
# T=4 for ETHERBOOT
# V = version
# 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 0x00
.byte 0
#else
.byte LOADED_HIGH
#endif
setup_move_size: .word 0x8000 ! size to move, when we (setup) are not
! loaded at 0x90000. We will move ourselves
! to 0x90000 then just before jumping into
! the kernel. However, only the loader
! know how much of data behind us also needs
! to be loaded.
code32_start: ! here loaders can put a different
! start address for 32-bit code.
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
.long 0x1000 # 0x1000 = default for zImage
#else
.long 0x100000 ! 0x100000 = default for big kernel
.long 0x100000 # 0x100000 = default for big kernel
#endif
ramdisk_image: .long 0 ! address of loaded ramdisk image
! Here the loader (or kernel generator) puts
! the 32-bit address were it loaded the image.
! This only will be interpreted by the kernel.
ramdisk_size: .long 0 ! its size in bytes
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
.global bootsect_kludge # so that we can see it in bootsect.S
bootsect_kludge:
.word bootsect_helper,SETUPSEG
heap_end_ptr: .word modelist+1024 ! space from here (exclusive) down to
! end of setup code can be used by setup
! for local heap purposes.
.word bootsect_helper, SETUPSEG
heap_end_ptr: .word modelist+1024 # space from here (exclusive) down to
# end of setup code can be used by setup
# for local heap purposes.
trampoline: call start_of_setup
.space 1024
! ------------------------ end of header ----------------------------------
# End of setup header #####################################################
start_of_setup:
! Bootlin depends on this being done early
mov ax,#0x01500
mov dl,#0x81
int 0x13
# Bootlin depends on this being done early
movw $0x01500, %ax
movb $0x81, %dl
int $0x13
#ifdef SAFE_RESET_DISK_CONTROLLER
! Reset the disk controller.
mov ax,#0x0000
mov dl,#0x80
int 0x13
# Reset the disk controller.
movw $0x0000, %ax
movb $0x80, $dl
int $0x13
#endif
! set DS=CS, we know that SETUPSEG == CS at this point
mov ax,cs ! aka #SETUPSEG
mov ds,ax
! Check signature at end of setup
cmp setup_sig1,#SIG1
# 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
cmp setup_sig2,#SIG2
cmpw $SIG2, setup_sig2
jne bad_sig
jmp good_sig1
! Routine to print ASCIIz string at DS:SI
jmp good_sig1
prtstr: lodsb
and al,al
# 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: mov al,#0x20 ! Print single space (fall-thru!)
! Part of above routine, this one just prints ASCII al
fin: ret
prtchr: push ax
push cx
xor bh,bh
mov cx,#0x01
mov ah,#0x0e
int 0x10
pop cx
pop ax
# 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
xorb %bh, %bh
movw $0x01, %cx
movb $0x0e, %ah
int $0x10
popw %cx
popw %ax
ret
beep: mov al,#0x07
beep: movb $0x07, %al
jmp prtchr
no_sig_mess: .ascii "No setup signature found ..."
db 0x00
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
# We now have to find the rest of the setup code/data
bad_sig:
mov ax,cs ! aka #SETUPSEG
sub ax,#DELTA_INITSEG ! aka #INITSEG
mov ds,ax
xor bh,bh
mov bl,[497] ! get setup sects from boot sector
sub bx,#4 ! LILO loads 4 sectors of setup
shl bx,#7 ! convert to dwords (1sect=2^7 dwords)
mov cx,bx
shr bx,#2 ! convert to segment
add bx,#SYSSEG
seg cs
mov start_sys_seg,bx
! Move rest of setup code/data to here
mov di,#2048 ! four sectors loaded by LILO
sub si,si
mov ax,cs ! aka #SETUPSEG
mov es,ax
mov ax,#SYSSEG
mov ds,ax
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 $7, %bx # convert to dwords (1sect=2^7 dwords)
movw %bx, %cx
shrw $2, %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
movw %cs, %ax # aka SETUPSEG
movw %ax, %es
movw $SYSSEG, %ax
movw %ax, %ds
rep
movsd
mov ax,cs ! aka #SETUPSEG
mov ds,ax
cmp setup_sig1,#SIG1
movsl
movw %cs, %ax # aka SETUPSEG
movw %ax, %ds
cmpw $SIG1, setup_sig1
jne no_sig
cmp setup_sig2,#SIG2
cmpw $SIG2, setup_sig2
jne no_sig
jmp good_sig
no_sig:
lea si,no_sig_mess
lea no_sig_mess, %si
call prtstr
no_sig_loop:
jmp no_sig_loop
good_sig:
mov ax,cs ! aka #SETUPSEG
sub ax,#DELTA_INITSEG ! aka #INITSEG
mov ds,ax
! check if an old loader tries to load a big-kernel
seg cs
test byte ptr loadflags,#LOADED_HIGH ! Have we a big kernel?
jz loader_ok ! NO, no danger even for old loaders
! YES, we have a big-kernel
seg cs
cmp byte ptr type_of_loader,#0 ! Have we one of the new loaders?
jnz loader_ok ! YES, OK
! NO, we have an old loader, must give up
push cs
pop ds
lea si,loader_panic_mess
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:
.ascii "Wrong loader: giving up."
db 0
loader_panic_mess: .string "Wrong loader, giving up..."
loader_ok:
! Get memory size (extended mem, kB)
# Get memory size (extended mem, kB)
xor eax, eax
mov dword ptr [0x1e0], eax
xorl %eax, %eax
movl %eax, (0x1e0)
#ifndef STANDARD_MEMORY_BIOS_CALL
mov byte ptr [E820NR], al
! 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].
!
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].
#
meme820:
mov edx, #0x534d4150 ! ascii `SMAP'
xor ebx, ebx ! continuation counter
mov di, #E820MAP ! point into the whitelist
! so we can have the bios
! directly write into it.
movl $0x534d4150, %edx # ascii `SMAP'
xorl %ebx, %ebx # continuation counter
movw $E820MAP, %di # point into the whitelist
# so we can have the bios
# directly write into it.
jmpe820:
mov eax, #0x0000e820 ! e820, upper word zeroed
mov ecx, #20 ! size of the e820rec
push ds ! data record.
pop es
int 0x15 ! make the call
jc bail820 ! fall to e801 if it fails
cmp eax, #0x534d4150 ! check the return is `SMAP'
jne bail820 ! fall to e801 if it fails
! cmp dword ptr [16+di], #1 ! is this usable memory?
! jne again820
! If this is usable memory, we save it by simply advancing di by
! sizeof(e820rec).
!
movl $0x0000e820, %eax # e820, upper word zeroed
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 $0x534d4150, %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:
mov al, byte ptr [E820NR] ! up to 32 good entries, that is
cmp al, #E820MAX
movb (E820NR), %al # up to 32 entries
cmpb $E820MAX, %al
jnl bail820
inc byte ptr [E820NR]
mov ax, di
add ax, #20
mov di, ax
incb (E820NR)
movw %di, %ax
addw $20, %ax
movw %ax, %di
again820:
cmp ebx, #0 ! check to see if ebx is
jne jmpe820 ! set to EOF
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.)
# 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:
mov ax,#0xe801
int 0x15
movw $0xe801, %ax
int $0x15
jc mem88
and edx, #0xffff ! clear sign extend
shl edx, 6 ! and go from 64k to 1k chunks
mov [0x1e0],edx ! store extended memory size
and ecx, #0xffff ! clear sign extend
add [0x1e0],ecx ! and add lower memory into total size.
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.
# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
# 64mb, depending on the bios) in ax.
mem88:
#endif
mov ah,#0x88
int 0x15
mov [2],ax
! Set the keyboard repeat rate to the max
mov ax,#0x0305
xor bx,bx ! clear 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 boot sector
! Get hd0 data
xor ax,ax ! clear ax
mov ds,ax
lds si,[4*0x41]
mov ax,cs ! aka #SETUPSEG
sub ax,#DELTA_INITSEG ! aka #INITSEG
push ax
mov es,ax
mov di,#0x0080
mov cx,#0x10
push cx
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
xor ax,ax ! clear ax
mov ds,ax
lds si,[4*0x46]
pop cx
pop es
mov di,#0x0090
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 :-)
mov ax,#0x01500
mov dl,#0x81
int 0x13
# Check that there IS a hd1 :-)
movw $0x01500, %ax
movb $0x81, %dl
int $0x13
jc no_disk1
cmp ah,#3
cmpb $3, %ah
je is_disk1
no_disk1:
mov ax,cs ! aka #SETUPSEG
sub ax,#DELTA_INITSEG ! aka #INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
xor ax,ax ! clear ax
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
mov ax,cs ! aka #SETUPSEG
sub ax,#DELTA_INITSEG ! aka #INITSEG
mov ds,ax
mov ds,ax
xor ax,ax
mov [0xa0], ax ! set table length to 0
mov ah, #0xc0
# 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 ! puts feature table at es:bx
jc no_mca
push ds
mov ax,es
mov ds,ax
mov ax,cs ! aka #SETUPSEG
sub ax, #DELTA_INITSEG ! aka #INITSEG
mov es,ax
mov si,bx
mov di,#0xa0
mov cx,(si)
add cx,#2 ! table length is a short
cmp cx,#0x10
jc sysdesc_ok
mov cx,#0x10 ! we keep only first 16 bytes
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
pop ds
popw %ds
no_mca:
! Check for PS/2 pointing device
mov ax,cs ! aka #SETUPSEG
sub ax,#DELTA_INITSEG ! aka #INITSEG
mov ds,ax
mov [0x1ff],#0 ! default is no pointing device
int 0x11 ! int 0x11: equipment determination
test al,#0x04 ! check if pointing device installed
# Check for PS/2 pointing device
movw %cs, %ax # aka SETUPSEG
subw $DELTA_INITSEG, %ax # aka INITSEG
movw %ax, %ds
movw $0, (0x1ff) # default is no pointing device
int $0x11 # int 0x11: equipment list
testb $0x04, %al # check if mouse installed
jz no_psmouse
mov [0x1ff],#0xaa ! device present
movw $0xAA, (0x1ff) # device present
no_psmouse:
#ifdef CONFIG_APM
! check for APM BIOS
! NOTE: DS is pointing to the boot sector
!
mov [64],#0 ! version == 0 means no APM BIOS
mov ax,#0x05300 ! APM BIOS installation check
xor bx,bx
int 0x15
jc done_apm_bios ! error -> no APM BIOS
cmp bx,#0x0504d ! check for "PM" signature
jne done_apm_bios ! no signature -> no APM BIOS
and cx,#0x02 ! Is 32 bit supported?
je done_apm_bios ! no ...
mov ax,#0x05304 ! Disconnect first just in case
xor bx,bx
int 0x15 ! ignore return code
mov ax,#0x05303 ! 32 bit connect
xor ebx,ebx
int 0x15
jc no_32_apm_bios ! error
mov [66],ax ! BIOS code segment
mov [68],ebx ! BIOS entry point offset
mov [72],cx ! BIOS 16 bit code segment
mov [74],dx ! BIOS data segment
mov [78],esi ! BIOS code segment length
mov [82],di ! BIOS data segment length
!
! Redo the installation check as the 32 bit connect
! modifies the flags returned on some BIOSs
!
mov ax,#0x05300 ! APM BIOS installation check
xor bx,bx
int 0x15
jc apm_disconnect ! error -> should not happen, tidy up
cmp bx,#0x0504d ! check for "PM" signature
jne apm_disconnect ! no signature -> should not happen, tidy up
mov [64],ax ! record the APM BIOS version
mov [76],cx ! and flags
# 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
xorw %ebx, %ebx
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 length
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
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:
mov ax,#0x05304 ! Disconnect
xor bx,bx
int 0x15 ! ignore return code
apm_disconnect: # Tidy up
movw $0x05304, %ax # Disconnect
xorw %bx, %bx
int $0x15 # ignore return code
jmp done_apm_bios
no_32_apm_bios:
and [76], #0xfffd ! remove 32 bit support bit
andw $0xfffd, (76) # remove 32 bit support bit
done_apm_bios:
#endif
! Now we want to move to protected mode ...
seg cs
cmp realmode_swtch,#0
# Now we want to move to protected mode ...
cmpw $0, %cs:realmode_swtch
jz rmodeswtch_normal
seg cs
callf far * realmode_swtch
call *%cs:realmode_swtch
jmp rmodeswtch_end
rmodeswtch_normal:
push cs
pushw %cs
call default_switch
rmodeswtch_end:
! we get the code32 start address and modify the below 'jmpi'
! (loader may have changed it)
seg cs
mov eax,code32_start
seg cs
mov code32,eax
! Now we move the system to its rightful place
! ...but we check, if we have a big-kernel.
! in this case we *must* not move it ...
seg cs
test byte ptr loadflags,#LOADED_HIGH
jz do_move0 ! we have a normal low loaded zImage
! we have a high loaded big kernel
jmp end_move ! ... and we skip moving
rmodeswtch_end:
# we get the code32 start address and modify the below 'jmpi'
# (loader may have changed it)
movl %cs:code32_start, %eax
movl %eax, %cs:code32
# 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:
mov ax,#0x100 ! start of destination segment
mov bp,cs ! aka #SETUPSEG
sub bp,#DELTA_INITSEG ! aka #INITSEG
seg cs
mov bx,start_sys_seg ! start of source segment
cld ! 'direction'=0, movs moves forward
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:
mov es,ax ! destination segment
inc ah ! instead of add ax,#0x100
mov ds,bx ! source segment
add bx,#0x100
sub di,di
sub si,si
mov cx,#0x400
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 $0x400, %cx
rep
movsd
cmp bx,bp ! we assume start_sys_seg > 0x200,
! so we will perhaps read one page more then
! needed, but never overwrite INITSEG because
! destination is minimum one page below source
movsl
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
! then we load the segment descriptors
end_move:
mov ax,cs ! aka #SETUPSEG ! right, forgot this at first. didn't work :-)
mov ds,ax
! If we have our code not at 0x90000, we need to move it there now.
! We also then need to move the parameters behind it (command line)
! Because we would overwrite the code on the current IP, we move
! it in two steps, jumping high after the first one.
mov ax,cs
cmp ax,#SETUPSEG
# then we load the segment descriptors
movw %cs, %ax # aka SETUPSEG
movw %ax, %ds
# 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
sub ax,#DELTA_INITSEG ! aka #INITSEG
mov dx,ss
cmp dx,ax
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
add dx,#INITSEG
sub dx,ax ! this will be SS after the move
addw $INITSEG, %dx
subw %ax, %dx # this will go into %ss after
# the move
move_self_1:
mov ds,ax
mov ax,#INITSEG ! real INITSEG
mov es,ax
seg cs
mov cx,setup_move_size
std ! we have to move up, so we use direction down
! because the areas may overlap
mov di,cx
dec di
mov si,di
sub cx,#move_self_here+0x200
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
jmpi move_self_here,SETUPSEG ! jump to our final place
ljmp $SETUPSEG, $move_self_here
move_self_here:
mov cx,#move_self_here+0x200
movw $move_self_here+0x200, %cx
rep
movsb
mov ax,#SETUPSEG
mov ds,ax
mov ss,dx
! now we are at the right place
end_move_self:
lidt idt_48 ! load idt with 0,0
lgdt gdt_48 ! load gdt with whatever appropriate
! that was painless, now we enable A20
call empty_8042
mov al,#0xD1 ! command write
out #0x64,al
call empty_8042
mov al,#0xDF ! A20 on
out #0x60,al
movw $SETUPSEG, %ax
movw %ax, %ds
movw %dx, %ss
end_move_self: # now we are at the right place
lidt idt_48 # load idt with 0,0
lgdt gdt_48 # load gdt with whatever is
# appropriate
# that was painless, now we enable a20
call empty_8042
! 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. The memory location used here is the int 0x1f vector,
! which should be safe to use; any *unused* memory location < 0xfff0
! should work here.
movb $0xD1, %al # command write
outb %al, $0x64
call empty_8042
#define TEST_ADDR 0x7c
movb $0xDF, %al # A20 on
outb %al, $0x60
call empty_8042
push ds
xor ax,ax ! segment 0x0000
mov ds,ax
dec ax ! segment 0xffff (HMA)
mov gs,ax
mov bx,[TEST_ADDR] ! we want to restore the value later
# 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. The memory location used here (0x200) is the int 0x80
# vector, which should be safe to use.
push %ds
push %es
xorw %ax, %ax # segment 0x0000
movw %ax, %fs
decw %ax # segment 0xffff (HMA)
movw %ax, %gs
a20_wait:
inc ax
mov [TEST_ADDR],ax
seg gs
cmp ax,[TEST_ADDR+0x10]
je a20_wait ! loop until no longer aliased
mov [TEST_ADDR],bx ! restore original value
pop ds
! make sure any possible coprocessor is properly reset..
xor ax,ax
out #0xf0,al
call delay
out #0xf1,al
incw %ax # unused memory location <0xfff0
movw %ax, %fs:(0x200) # we use the "int 0x80" vector
cmpw %gs:(0x210), %ax # and its corresponding HMA addr
je a20_wait # loop until no longer aliased
# make sure any possible coprocessor is properly reset..
xorw %ax, %ax
outb %al, $0xf0
call delay
! well, that went ok, I hope. Now we mask all interrupts - the rest
! is done in init_IRQ().
outb %al, $0xf1
call delay
mov al,#0xFF ! mask off all interrupts for now
out #0xA1,al
# 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
mov al,#0xFB ! mask all irq's but irq2 which
out #0x21,al ! 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.
!
mov ax,#1 ! protected mode (PE) bit
lmsw ax ! This is it!
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:
xor bx,bx ! Flag to indicate a boot
! NOTE: For high loaded big kernels we need a
! jmpi 0x100000,__KERNEL_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 operant 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)
db 0x66,0xea ! prefix + jmpi-opcode
code32: dd 0x1000 ! will be set to 0x100000 for big kernels
dw __KERNEL_CS
flush_instr:
xorw %bx, %bx # Flag to indicate a boot
# NOTE: For high loaded big kernels we need a
# jmpi 0x100000,__KERNEL_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 operant 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 0x1000 # will be set to 0x100000
# for big kernels
.word __KERNEL_CS
# Here's a bunch of information about your current kernel..
kernel_version: .ascii UTS_RELEASE
.ascii " ("
.ascii LINUX_COMPILE_BY
......@@ -690,191 +682,184 @@ kernel_version: .ascii UTS_RELEASE
.ascii LINUX_COMPILE_HOST
.ascii ") "
.ascii UTS_VERSION
db 0
! This is the default real mode switch routine.
! to be called just before protected mode transition
.byte 0
# This is the default real mode switch routine.
# to be called just before protected mode transition
default_switch:
cli ! no interrupts allowed !
mov al,#0x80 ! disable NMI for the bootup sequence
out #0x70,al
retf
! This routine only gets called, if we get loaded by the simple
! bootsect loader _and_ have a bzImage to load.
! Because there is no place left in the 512 bytes of the boot sector,
! we must emigrate to code space here.
!
cli # no interrupts allowed !
movb $0x80, %al # disable NMI for bootup
# sequence
outb %al, $0x70
lret
# This routine only gets called, if we get loaded by the simple
# bootsect loader _and_ have a bzImage to load.
# Because there is no place left in the 512 bytes of the boot sector,
# we must emigrate to code space here.
bootsect_helper:
seg cs
cmp word ptr bootsect_es,#0
cmpw $0, %cs:bootsect_es
jnz bootsect_second
seg cs
mov byte ptr type_of_loader,#0x20
mov ax,es
shr ax,#4
seg cs
mov byte ptr bootsect_src_base+2,ah
mov ax,es
seg cs
mov bootsect_es,ax
sub ax,#SYSSEG
retf ! nothing else to do for now
movb $0x20, %cs:type_of_loader
movw %es, %ax
shrw $4, %ax
movb %ah, %cs:bootsect_src_base+2
movw %es, %ax
movw %ax, %cs:bootsect_es
subw $SYSSEG, %ax
lret # nothing else to do for now
bootsect_second:
push cx
push si
push bx
test bx,bx ! 64K full ?
pushw %cx
pushw %si
pushw %bx
testw %bx, %bx # 64K full?
jne bootsect_ex
mov cx,#0x8000 ! full 64K move, INT15 moves words
push cs
pop es
mov si,#bootsect_gdt
mov ax,#0x8700
int 0x15
jc bootsect_panic ! this, if INT15 fails
seg cs
mov es,bootsect_es ! we reset es to always point to 0x10000
seg cs
inc byte ptr bootsect_dst_base+2
movw $0x8000, %cx # full 64K, INT15 moves words
pushw %cs
popw %es
movw $bootsect_gdt, %si
movw $0x8700, %ax
int $0x15
jc bootsect_panic # this, if INT15 fails
movw %cs:bootsect_es, %es # we reset %es to always point
incb %cs:bootsect_dst_base+2 # to 0x10000
bootsect_ex:
seg cs
mov ah, byte ptr bootsect_dst_base+2
shl ah,4 ! we now have the number of moved frames in ax
xor al,al
pop bx
pop si
pop cx
retf
movb %cs:bootsect_dst_base+2, %ah
shlb $4, %ah # we now have the number of
# moved frames in %ax
xorb %al, %al
popw %bx
popw %si
popw %cx
lret
bootsect_gdt:
.word 0,0,0,0
.word 0,0,0,0
.word 0, 0, 0, 0
.word 0, 0, 0, 0
bootsect_src:
.word 0xffff
bootsect_src_base:
.byte 0,0,1 ! base = 0x010000
.byte 0x93 ! typbyte
.word 0 ! limit16,base24 =0
.byte 0x00, 0x00, 0x01 # base = 0x010000
.byte 0x93 # typbyte
.word 0 # limit16,base24 =0
bootsect_dst:
.word 0xffff
bootsect_dst_base:
.byte 0,0,0x10 ! base = 0x100000
.byte 0x93 ! typbyte
.word 0 ! limit16,base24 =0
.word 0,0,0,0 ! BIOS CS
.word 0,0,0,0 ! BIOS DS
.byte 0x00, 0x00, 0x10 # base = 0x100000
.byte 0x93 # typbyte
.word 0 # limit16,base24 =0
.word 0, 0, 0, 0 # BIOS CS
.word 0, 0, 0, 0 # BIOS DS
bootsect_es:
.word 0
bootsect_panic:
push cs
pop ds
pushw %cs
popw %ds
cld
lea si,bootsect_panic_mess
leaw bootsect_panic_mess, %si
call prtstr
bootsect_panic_loop:
jmp bootsect_panic_loop
bootsect_panic_mess:
.ascii "INT15 refuses to access high memory. Giving up."
db 0
.string "INT15 refuses to access high mem, giving up."
! 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...
# 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...
empty_8042:
push ecx
mov ecx,#0xFFFFFF
pushl %ecx
movl $0xFFFFFF, %ecx
empty_8042_loop:
dec ecx
jz empty_8042_end_loop
decl %ecx
jz empty_8042_end_loop
call delay
in al,#0x64 ! 8042 status port
test al,#1 ! output buffer?
inb $0x64, %al # 8042 status port
testb $1, %al # output buffer?
jz no_output
call delay
in al,#0x60 ! read it
inb $0x60, %al # read it
jmp empty_8042_loop
no_output:
test al,#2 ! is input buffer full?
jnz empty_8042_loop ! yes - loop
testb $2, %al # is input buffer full?
jnz empty_8042_loop # yes - loop
empty_8042_end_loop:
pop ecx
popl %ecx
ret
!
! Read the CMOS clock. Return the seconds in al
!
# Read the cmos clock. Return the seconds in al
gettime:
push cx
mov ah,#0x02
int 0x1a
mov al,dh ! dh contains the seconds
and al,#0x0f
mov ah,dh
mov cl,#0x04
shr ah,cl
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
pop cx
popw %cx
ret
!
! Delay is needed after doing I/O
!
# Delay is needed after doing I/O
delay:
.word 0x00eb ! jmp $+2
jmp .+2 # jmp $+2
ret
!
! Descriptor tables
!
# Descriptor tables
gdt:
.word 0,0,0,0 ! dummy
.word 0,0,0,0 ! unused
.word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb)
.word 0x0000 ! base address=0
.word 0x9A00 ! code read/exec
.word 0x00CF ! granularity=4096, 386 (+5th nibble of limit)
.word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb)
.word 0x0000 ! base address=0
.word 0x9200 ! data read/write
.word 0x00CF ! granularity=4096, 386 (+5th nibble of limit)
.word 0, 0, 0, 0 # dummy
.word 0, 0, 0, 0 # unused
.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)
idt_48:
.word 0 ! idt limit=0
.word 0,0 ! idt base=0L
.word 0 # idt limit = 0
.word 0, 0 # idt base = 0L
gdt_48:
.word 0x800 ! gdt limit=2048, 256 GDT entries
.word 512+gdt,0x9 ! gdt base = 0X9xxxx
.word 0x8000 # gdt limit=2048,
# 256 GDT entries
!
! Include video setup & detection code
!
.word 512+gdt, 0x9 # gdt base = 0X9xxxx
#include "video.S"
# Include video setup & detection code
!
! Setup signature -- must be last
!
#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).
!
# 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:
......
......@@ -58,27 +58,10 @@ void die(const char * str, ...)
exit(1);
}
/* Reading of ld86 output (Minix format) */
#define MINIX_HEADER_LEN 32
void minix_open(const char *name)
void file_open(const char *name)
{
static byte hdr[] = { 0x01, 0x03, 0x10, 0x04, 0x20, 0x00, 0x00, 0x00 };
static u32 *lb = (u32 *) buf;
if ((fd = open(name, O_RDONLY, 0)) < 0)
die("Unable to open `%s': %m", name);
if (read(fd, buf, MINIX_HEADER_LEN) != MINIX_HEADER_LEN)
die("%s: Unable to read header", name);
if (memcmp(buf, hdr, sizeof(hdr)) || lb[5])
die("%s: Non-Minix header", name);
if (lb[3])
die("%s: Illegal data segment");
if (lb[4])
die("%s: Illegal bss segment");
if (lb[7])
die("%s: Illegal symbol table");
}
void usage(void)
......@@ -125,7 +108,7 @@ int main(int argc, char ** argv)
}
fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
minix_open(argv[1]); /* Copy the boot sector */
file_open(argv[1]);
i = read(fd, buf, sizeof(buf));
fprintf(stderr,"Boot sector %d bytes.\n",i);
if (i != 512)
......@@ -138,7 +121,7 @@ int main(int argc, char ** argv)
die("Write call failed");
close (fd);
minix_open(argv[2]); /* Copy the setup code */
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");
......@@ -146,8 +129,8 @@ int main(int argc, char ** argv)
die("read-error on `setup'");
close (fd);
setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */
/* for compatibility with ancient versions of LILO */
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);
......@@ -161,8 +144,7 @@ int main(int argc, char ** argv)
i += c;
}
if ((fd = open(argv[3], O_RDONLY, 0)) < 0) /* Copy the image itself */
die("Unable to open `%s': %m", argv[3]);
file_open(argv[3]);
if (fstat (fd, &sb))
die("Unable to stat `%s': %m", argv[3]);
sz = sb.st_size;
......@@ -187,7 +169,7 @@ int main(int argc, char ** argv)
}
close(fd);
if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the boot sector */
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)
......
!
! Display adapter & video mode setup, version 2.13 (14-May-99)
!
! Copyright (C) 1995 -- 1999 Martin Mares <mj@ucw.cz>
! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
!
! For further information, look at Documentation/svga.txt.
!
/* 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.
*
*/
#include <linux/config.h> /* for CONFIG_VIDEO_* */
! Enable autodetection of SVGA adapters and modes. If you really need this
! feature, drop me a mail as I think of removing it some day. You can
! always enter `scan' to get the video mode table and then use the real
! video mode numbers (those 4-digit hexadecimal numbers, NOT the menu
! item numbers) which don't rely on any autodetection.
/* Enable autodetection of SVGA adapters and modes. */
#undef CONFIG_VIDEO_SVGA
! Enable autodetection of VESA modes
/* Enable autodetection of VESA modes */
#define CONFIG_VIDEO_VESA
! Enable compacting of mode table
/* Enable compacting of mode table */
#define CONFIG_VIDEO_COMPACT
! Retain screen contents when switching modes
/* Retain screen contents when switching modes */
#define CONFIG_VIDEO_RETAIN
! Enable local mode list
/* Enable local mode list */
#undef CONFIG_VIDEO_LOCAL
! Force 400 scan lines for standard modes (hack to fix bad behaviour
! of certain broken BIOSes -- don't use unless needed)
/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
#undef CONFIG_VIDEO_400_HACK
! A special hack allowing to force specific BIOS mode ID along with specific
! dimensions. Especially useful for certain X-Window graphics mode hacks
! (e.g., 800x600 modes on IBM ThinkPad).
/* 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.
/* 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)
/* Standard BIOS video modes (BIOS number + 0x0100) */
#define VIDEO_FIRST_BIOS 0x0100
! VESA BIOS video modes (VESA number + 0x0200)
/* VESA BIOS video modes (VESA number + 0x0200) */
#define VIDEO_FIRST_VESA 0x0200
! Video7 special modes (BIOS number + 0x0900)
/* Video7 special modes (BIOS number + 0x0900) */
#define VIDEO_FIRST_V7 0x0900
! Special video modes
/* Special video modes */
#define VIDEO_FIRST_SPECIAL 0x0f00
#define VIDEO_80x25 0x0f00
#define VIDEO_8POINT 0x0f01
......@@ -66,14 +68,15 @@
#define VIDEO_80x60 0x0f07
#define VIDEO_GFX_HACK 0x0f08
#define VIDEO_LAST_SPECIAL 0x0f09
! Video modes given by resolution
/* Video modes given by resolution */
#define VIDEO_FIRST_RESOLUTION 0x1000
! The "recalculate timings" flag
/* The "recalculate timings" flag */
#define VIDEO_RECALC 0x8000
! Positions of various video parameters passed to the kernel
! (see also include/linux/tty.h)
/* 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
......@@ -94,530 +97,505 @@
#define PARAM_VESAPM_OFF 0x30
#define PARAM_LFB_PAGES 0x32
! Define DO_STORE according to CONFIG_VIDEO_RETAIN
/* 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
!
! Input:
! DS pointing to the boot sector
video: push ds ! We use different segments
push ds ! FS contains original DS
pop fs
push cs ! DS is equal to CS
pop ds
push cs ! ES is equal to CS
pop es
xor ax,ax
mov gs,ax ! GS is zero
# 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)
call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
#ifdef CONFIG_VIDEO_SELECT
seg fs ! User-selected video mode
mov ax,[0x01fa]
cmp ax,#ASK_VGA ! Bring up the menu
movw %fs:(0x01fa), %ax # User selected video mode
cmpw $ASK_VGA, %ax # Bring up the menu
jz vid2
call mode_set ! Set the mode
call mode_set # Set the mode
jc vid1
lea si,badmdt ! Invalid mode ID
leaw badmdt, %si # Invalid mode ID
call prtstr
vid2: call mode_menu
vid1:
#ifdef CONFIG_VIDEO_RETAIN
call restore_screen ! Restore screen contents
call restore_screen # Restore screen contents
#endif /* CONFIG_VIDEO_RETAIN */
#endif /* CONFIG_VIDEO_SELECT */
call mode_params ! Store mode parameters
pop ds ! Restore original DS
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.
!
# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
basic_detect:
seg fs ! Default is no VGA
movb [PARAM_HAVE_VGA],#0
mov ah,#0x12 ! Check EGA/VGA
mov bl,#0x10
int 0x10
seg fs
mov [PARAM_VIDEO_EGA_BX],bx ! Used for identification of EGA in the kernel
cmp bl,#0x10 ! No, this is a CGA/MDA/HGA card.
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]
mov ax,#0x1a00 ! Check for EGA/VGA discrimination
int 0x10
cmp al,#0x1a ! 1a means VGA, anything else EGA
jne basret
seg fs
incb [PARAM_HAVE_VGA] ! We've detected a VGA
incb [adapter]
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.
!
# 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 [graphic_mode],#0
cmpb $0, graphic_mode
jnz mopar_gr
#endif
mov ah,#0x03 ! Read cursor position
xor bh,bh
int 0x10
seg fs
mov [PARAM_CURSOR_POS],dx
mov ah,#0x0f ! Read page/mode/width
int 0x10
seg fs
mov [PARAM_VIDEO_PAGE],bx
seg fs
mov [PARAM_VIDEO_MODE],ax ! Video mode and screen width
cmp al,#7 ! MDA/HGA => segment differs
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
mov [video_segment],#0xb000
mopar0: seg gs ! Font size
mov ax,[0x485]
seg fs
mov [PARAM_FONT_POINTS],ax ! (valid only on EGA/VGA)
mov ax,[force_size] ! Forced size?
or ax,ax
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
seg fs
mov [PARAM_VIDEO_COLS],ah
seg fs
mov [PARAM_VIDEO_LINES],al
ret
mopar1: mov al,#25
cmpb [adapter],#0 ! If we are on CGA/MDA/HGA, the screen must
jz mopar2 ! have 25 lines.
seg gs ! On EGA/VGA, use the EGA+ BIOS variable
mov al,[0x484] ! containing maximal line number.
inc al
mopar2: seg fs
movb [PARAM_VIDEO_LINES],al
movb %ah, %fs:(PARAM_VIDEO_COLS)
movb %al, %fs:(PARAM_VIDEO_LINES)
ret
#ifdef CONFIG_VIDEO_SELECT
mopar1: movb $25, %al
cmpb $0, adapter # If we are on CGA/MDA/HGA, the
jz mopar2 # screen must have 25 lines.
!
! Fetching of VESA frame buffer parameters
!
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:
lea di,modelist+1024
seg fs
movb [PARAM_HAVE_VGA],#0x23
mov ax,(di+16)
seg fs
mov [PARAM_LFB_LINELENGTH],ax
mov ax,(di+18)
seg fs
mov [PARAM_LFB_WIDTH],ax
mov ax,(di+20)
seg fs
mov [PARAM_LFB_HEIGHT],ax
mov al,(di+25)
mov ah,#0
seg fs
mov [PARAM_LFB_DEPTH],ax
mov al,(di+29)
mov ah,#0
seg fs
mov [PARAM_LFB_PAGES],ax
mov eax,(di+40)
seg fs
mov [PARAM_LFB_BASE],eax
mov eax,(di+31)
seg fs
mov [PARAM_LFB_COLORS],eax
mov eax,(di+35)
seg fs
mov [PARAM_LFB_COLORS+4],eax
! get video mem size
lea di,modelist+1024
mov ax,#0x4f00
int 0x10
xor eax,eax
mov ax,(di+18)
seg fs
mov [PARAM_LFB_SIZE],eax
! get protected mode interface informations
mov ax,#0x4f0a
xor bx,bx
xor di,di
int 0x10
cmp ax,#0x004f
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)
# 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)
# get protected mode interface informations
movw $0x4f0a, %ax
xorw %bx, %bx
xorw %di, %di
int $0x10
cmp $0x004f, %ax
jnz no_pm
seg fs
mov [PARAM_VESAPM_SEG],es
seg fs
mov [PARAM_VESAPM_OFF],di
no_pm:
ret
!
! The video mode menu
!
movw %es, %fs:(PARAM_VESAPM_SEG)
movw %di, %fs:(PARAM_VESAPM_OFF)
no_pm: ret
# The video mode menu
mode_menu:
lea si,keymsg ! "Return/Space/Timeout" message
leaw keymsg, %si # "Return/Space/Timeout" message
call prtstr
call flush
nokey: call getkt
cmp al,#0x0d ! ENTER ?
je listm ! yes - manual mode selection
cmp al,#0x20 ! SPACE ?
je defmd1 ! no - repeat
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 selected => use the 80x25 default
listm: call mode_table ! We need a mode table to be listed
listm0: lea si,name_bann ! Print adapter name
defmd1: ret # No mode chosen? Default 80x25
listm: call mode_table # List mode table
listm0: leaw name_bann, %si # Print adapter name
call prtstr
mov si,[card_name]
or si,si
movw card_name, %si
orw %si, %si
jnz an2
mov al,[adapter]
lea si,old_name
or al,al
movb adapter, %al
leaw old_name, %si
orb %al, %al
jz an1
lea si,ega_name
dec al
leaw ega_name, %si
decb %al
jz an1
lea si,vga_name
leaw vga_name, %si
jmp an1
an2: call prtstr
lea si,svga_name
leaw svga_name, %si
an1: call prtstr
lea si,listhdr ! Table header
leaw listhdr, %si # Table header
call prtstr
mov dl,#0x30 ! DL holds mode number
lea si,modelist
lm1: cmp (si),#ASK_VGA ! End?
movb $0x30, %dl # DL holds mode number
leaw modelist, %si
lm1: cmpw $ASK_VGA, (%si) # End?
jz lm2
mov al,dl ! Menu selection number
movb %dl, %al # Menu selection number
call prtchr
call prtsp2
lodsw
call prthw ! Mode ID
call prthw # Mode ID
call prtsp2
mov al,(si+1)
call prtdec ! Rows
mov al,#0x78 ! 'x'
movb 0x1(%si), %al
call prtdec # Rows
movb $0x78, %al # the letter 'x'
call prtchr
lodsw
call prtdec ! Columns
mov al,#0x0d ! New line
call prtdec # Columns
movb $0x0d, %al # New line
call prtchr
mov al,#0x0a
movb $0x0a, %al
call prtchr
inc dl ! Next character
cmp dl,#0x3a
incb %dl # Next character
cmpb $0x3a, %dl
jnz lm1
mov dl,#0x61
movb $0x61, %dl
jmp lm1
lm2: lea si,prompt ! Mode prompt
lm2: leaw prompt, %si # Mode prompt
call prtstr
lea di,edit_buf ! Editor buffer
leaw edit_buf, %di # Editor buffer
lm3: call getkey
cmp al,#0x0d ! Enter?
cmpb $0x0d, %al # Enter?
jz lment
cmp al,#0x08 ! Backspace?
cmpb $0x08, %al # Backspace?
jz lmbs
cmp al,#0x20 ! Printable?
cmpb $0x20, %al # Printable?
jc lm3
cmp di,#edit_buf+4 ! Enough space?
cmpw $edit_buf+4, %di # Enough space?
jz lm3
stosb
call prtchr
jmp lm3
lmbs: cmp di,#edit_buf ! Backspace
lmbs: cmpw $edit_buf, %di # Backspace
jz lm3
dec di
mov al,#0x08
decw %di
movb $0x08, %al
call prtchr
call prtspc
mov al,#0x08
movb $0x08, %al
call prtchr
jmp lm3
lment: movb (di),#0
lea si,crlft
lment: movb $0, (%di)
leaw crlft, %si
call prtstr
lea si,edit_buf
cmpb (si),#0 ! Empty string => use default mode
leaw edit_buf, %si
cmpb $0, (%si) # Empty string = default mode
jz lmdef
cmpb (si+1),#0 ! One character => menu selection
cmpb $0, 1(%si) # One character = menu selection
jz mnusel
cmp (si),#0x6373 ! "scan" => mode scanning
cmpw $0x6373, (%si) # "scan" => mode scanning
jnz lmhx
cmp (si+2),#0x6e61
cmpw $0x6e61, 2(%si)
jz lmscan
lmhx: xor bx,bx ! Else => mode ID in hex
lmhx: xorw %bx, %bx # Else => mode ID in hex
lmhex: lodsb
or al,al
orb %al, %al
jz lmuse1
sub al,#0x30
subb $0x30, %al
jc lmbad
cmp al,#10
cmpb $10, %al
jc lmhx1
sub al,#7
and al,#0xdf
cmp al,#10
subb $7, %al
andb $0xdf, %al
cmpb $10, %al
jc lmbad
cmp al,#16
cmpb $16, %al
jnc lmbad
lmhx1: shl bx,#4
or bl,al
lmhx1: shlw $4, %bx
orb %al, %bl
jmp lmhex
lmuse1: mov ax,bx
lmuse1: movw %bx, %ax
jmp lmuse
mnusel: lodsb ! Menu selection
xor ah,ah
sub al,#0x30
mnusel: lodsb # Menu selection
xorb %ah, %ah
subb $0x30, %al
jc lmbad
cmp al,#10
cmpb $10, %al
jc lmuse
cmp al,#0x61-0x30
cmpb $0x61-0x30, %al
jc lmbad
sub al,#0x61-0x30-10
cmp al,#36
subb $0x61-0x30-10, %al
cmpb $36, %al
jnc lmbad
lmuse: call mode_set
jc lmdef
lmbad: lea si,unknt
call prtstr
br lm2
lmscan: cmpb [adapter],#0 ! Scanning supported only on EGA/VGA
lmbad: leaw unknt, %si
call prtstr
jmp lm2
lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
jz lmbad
mov [mt_end],#0 ! Scanning of modes: done as new autodetection
movb [scanning],#1
call mode_table
br listm0
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
# Additional parts of mode_set... (relative jumps, you know)
setv7: # Video7 extended modes
DO_STORE
sub bh,#VIDEO_FIRST_V7>>8
mov ax,#0x6f05
int 0x10
subb $VIDEO_FIRST_V7>>8, %bh
movw $0x6f05, %ax
int $0x10
stc
ret
_setrec: br setrec ! Ugly...
_set_80x25: br set_80x25
!
! Aliases for backward compatibility.
!
_setrec: jmp setrec # Ugly...
_set_80x25: jmp set_80x25
# Aliases for backward compatibility.
setalias:
mov ax,#VIDEO_80x25
inc bx
movw $VIDEO_80x25, %ax
incw %bx
jz mode_set
mov al,#VIDEO_8POINT-VIDEO_FIRST_SPECIAL
inc bx
jnz setbad
! Fall-through!
!
! Setting of user mode (AX=mode ID) => CF=success
!
movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
incw %bx
jnz setbad # Fall-through!
# Setting of user mode (AX=mode ID) => CF=success
mode_set:
mov bx,ax
cmp ah,#0xff
movw %ax, %bx
cmpb $0xff, %ah
jz setalias
test ah,#VIDEO_RECALC>>8
testb $VIDEO_RECALC>>8, %ah
jnz _setrec
cmp ah,#VIDEO_FIRST_RESOLUTION>>8
cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
jnc setres
cmp ah,#VIDEO_FIRST_SPECIAL>>8
cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
jz setspc
cmp ah,#VIDEO_FIRST_V7>>8
cmpb $VIDEO_FIRST_V7>>8, %ah
jz setv7
cmp ah,#VIDEO_FIRST_VESA>>8
cmpb $VIDEO_FIRST_VESA>>8, %ah
jnc check_vesa
or ah,ah
orb %ah, %ah
jz setmenu
dec ah
decb %ah
jz setbios
setbad: clc
movb [do_restore],#0 ! The screen needn't be restored
movb $0, do_restore # The screen needn't be restored
ret
setvesa:
DO_STORE
sub bh,#VIDEO_FIRST_VESA>>8
mov ax,#0x4f02 ! VESA BIOS mode set call
int 0x10
cmp ax,#0x004f ! AL=4f if implemented, AH=0 if OK
jnz setbad
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
push bx
mov ah,#0x0f ! Check if really set
int 0x10
pop bx
cmp al,bl
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: xor bh,bh ! Set special mode
cmp bl,#VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL
setspc: xorb %bh, %bh # Set special mode
cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
jnc setbad
add bx,bx
.word 0xa7ff, spec_inits ! JMP [BX+spec_inits]
addw %bx, %bx
.word 0xa7ff, spec_inits # JMP [BX+spec_inits]
setmenu:
or al,al ! 80x25 is an exception
orb %al, %al # 80x25 is an exception
jz _set_80x25
push bx ! Set mode chosen from menu
call mode_table ! Build the mode table
pop ax
shl ax,#2
add si,ax
cmp si,di
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
mov ax,(si) ! Fetch mode ID
movw (%si), %ax # Fetch mode ID
_m_s: jmp mode_set
setres:
push bx ! Set mode chosen by its resolution
setres: pushw %bx # Set mode chosen by resolution
call mode_table
pop bx
xchg bh,bl
popw %bx
xchgb %bl, %bh
setr1: lodsw
cmp ax,#ASK_VGA ! End of the list?
cmpw $ASK_VGA, %ax # End of the list?
jz setbad
lodsw
cmp ax,bx
cmpw %bx, %ax
jnz setr1
mov ax,(si-4) ! Fetch mode ID
movw -4(%si), %ax # Fetch mode ID
jmp _m_s
check_vesa:
lea di,modelist+1024
sub bh,#VIDEO_FIRST_VESA>>8
mov cx,bx ! Get mode information structure
mov ax,#0x4f01
int 0x10
add bh,#VIDEO_FIRST_VESA>>8
cmp ax,#0x004f
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
mov al,(di) ! Check capabilities.
and al,#0x19
cmp al,#0x09
jz setvesa ! this is a text mode
mov al,(di) ! Check capabilities.
and al,#0x99
cmp al,#0x99
jnz _setbad ! to bad, no linear frame buffer
sub bh,#VIDEO_FIRST_VESA>>8
or bx,#0x4000 ! want use linear frame buffer
mov ax,#0x4f02 ! VESA BIOS mode set call
int 0x10
cmp ax,#0x004f ! AL=4f if implemented, AH=0 if OK
jnz _setbad
movb [graphic_mode],#1 ! flag graphic mode
movb [do_restore],#0 ! no screen restore
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: br 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: sub ah,#VIDEO_RECALC>>8 ! Set the base mode
_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
seg gs ! Font size in pixels
mov ax,[0x485]
seg gs ! Number of rows
mov bl,[0x484]
inc bl
mul bl ! Number of visible
dec ax ! scan lines - 1
mov dx,#0x3d4
mov bx,ax
mov al,#0x12 ! Lower 8 bits
mov ah,bl
out dx,ax
mov al,#0x07 ! Bits 8 and 9 in the overflow register
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
xchg ah,al
and ah,#0xbd
shr bh,#1
xchgb %al, %ah
andb $0xbd, %ah
shrb %bh
jnc rct1
or ah,#0x02
rct1: shr bh,#1
orb $0x02, %ah
rct1: shrb %bh
jnc rct2
or ah,#0x40
rct2: mov al,#0x07
out dx,ax
orb $0x40, %ah
rct2: movb $0x07, %al
outw %ax, %dx
stc
rct3: ret
!
! Table of routines for setting of the special modes.
!
# Table of routines for setting of the special modes.
spec_inits:
.word set_80x25
.word set_8pixel
......@@ -629,589 +607,575 @@ spec_inits:
.word set_80x60
.word set_gfx
!
! Set the 80x25 mode. If already set, do nothing.
!
# Set the 80x25 mode. If already set, do nothing.
set_80x25:
mov [force_size],#0x5019 ! Override possibly broken BIOS vars
movw $0x5019, force_size # Override possibly broken BIOS
use_80x25:
#ifdef CONFIG_VIDEO_400_HACK
mov ax,#0x1202 ! Force 400 scan lines
mov bl,#0x30
int 0x10
movw $0x1202, %ax # Force 400 scan lines
movb $0x30, %bl
int $0x10
#else
mov ah,#0x0f ! Get current mode ID
int 0x10
cmp ax,#0x5007 ! Mode 7 (80x25 mono) is the only one available
jz st80 ! on CGA/MDA/HGA and is also available on EGAM
cmp ax,#0x5003 ! Unknown mode => force 80x25 color
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 [adapter],#0 ! CGA/MDA/HGA => mode 3/7 is always 80x25
st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
jz set80
seg gs ! This is EGA+ -- beware of 80x50 etc.
mov al,[0x0484]
or al,al ! Some buggy BIOSes set 0 rows
movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
orb %al, %al # Some buggy BIOS'es set 0 rows
jz set80
cmp al,#24 ! Let's hope this is correct
cmpb $24, %al # It's hopefully correct
jz set80
#endif /* CONFIG_VIDEO_400_HACK */
force3: DO_STORE
mov ax,#0x0003 ! Forced set
int 0x10
movw $0x0003, %ax # Forced set
int $0x10
set80: stc
ret
!
! Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
!
# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
set_8pixel:
DO_STORE
call use_80x25 ! The base is 80x25
call use_80x25 # The base is 80x25
set_8pt:
mov ax,#0x1112 ! Use 8x8 font
xor bl,bl
int 0x10
mov ax,#0x1200 ! Use alternate print screen
mov bl,#0x20
int 0x10
mov ax,#0x1201 ! Turn off cursor emulation
mov bl,#0x34
int 0x10
mov ah,#0x01 ! Define cursor (scan lines 6 to 7)
mov cx,#0x0607
int 0x10
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 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: mov ax,#0x1111 ! Use 9x14 font
xor bl,bl
int 0x10
mov ah,#0x01 ! Define cursor (scan lines 11 to 12)
mov cx,#0x0b0c
int 0x10
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 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
mov ax,#0x1201 ! Set 350 scans
mov bl,#0x30
int 0x10
mov ax,#0x0003 ! Reset video mode
int 0x10
jmp set_8pt ! Use 8-pixel font
!
! Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
!
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
call use_80x25 # Start with real 80x25
DO_STORE
mov dx,#0x3cc ! Get CRTC port
in al,dx
mov dl,#0xd4
ror al,#1 ! Mono or color?
movw $0x3cc, %dx # Get CRTC port
inb %dx, %al
movb $0xd4, %dl
rorb %al # Mono or color?
jc set48a
mov dl,#0xb4
set48a: mov ax,#0x0c11 ! Vertical sync end (also unlocks CR0-7)
movb $0xb4, %dl
set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
call outidx
mov ax,#0x0b06 ! Vertical total
movw $0x0b06, %ax # Vertical total
call outidx
mov ax,#0x3e07 ! (Vertical) overflow
movw $0x3e07, %ax # (Vertical) overflow
call outidx
mov ax,#0xea10 ! Vertical sync start
movw $0xea10, %ax # Vertical sync start
call outidx
mov ax,#0xdf12 ! Vertical display end
movw $0xdf12, %ax # Vertical display end
call outidx
mov ax,#0xe715 ! Vertical blank start
movw $0xe715, %ax # Vertical blank start
call outidx
mov ax,#0x0416 ! Vertical blank end
movw $0x0416, %ax # Vertical blank end
call outidx
push dx
mov dl,#0xcc ! Misc output register (read)
in al,dx
mov dl,#0xc2 ! (write)
and al,#0x0d ! Preserve clock select bits and color bit
or al,#0xe2 ! Set correct sync polarity
out dx,al
pop dx
mov [force_size],#0x501e
stc ! That's all.
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 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
mov ax,#0xdb12 ! VGA vertical display end
mov [force_size],#0x5022
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 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
mov ax,#0xdf12 ! VGA vertical display end
mov [force_size],#0x503c
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
!
# Special hack for ThinkPad graphics
set_gfx:
#ifdef CONFIG_VIDEO_GFX_HACK
mov ax,# VIDEO_GFX_BIOS_AX
mov bx,# VIDEO_GFX_BIOS_BX
int 0x10
mov [force_size],# VIDEO_GFX_DUMMY_RESOLUTION
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 contents to temporary buffer.
store_screen:
cmpb [do_restore],#0 ! Already stored?
cmpb $0, do_restore # Already stored?
jnz stsr
testb [loadflags],#CAN_USE_HEAP ! Have we space for storing?
testb $CAN_USE_HEAP, loadflags # Have we space for storing?
jz stsr
push ax
push bx
push [force_size] ! Don't force specific size
mov [force_size],#0
call mode_params ! Obtain params of current mode
pop [force_size]
seg fs
mov ah,[PARAM_VIDEO_LINES]
seg fs
mov al,[PARAM_VIDEO_COLS]
mov bx,ax ! BX=dimensions
mul ah
mov cx,ax ! CX=number of characters to store
add ax,ax ! Calculate image size
add ax,#modelist+1024+4
cmp ax,[heap_end_ptr]
jnc sts1 ! Unfortunately, out of memory
seg fs ! Store mode params
mov ax,[PARAM_CURSOR_POS]
lea di,modelist+1024
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
mov ax,bx
movw %bx, %ax
stosw
push ds ! Store the screen
mov ds,[video_segment]
xor si,si
pushw %ds # Store the screen
movw video_segment, %ds
xorw %si, %si
rep
movsw
pop ds
incb [do_restore] ! Screen will be restored later
sts1: pop bx
pop ax
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 contents from temporary buffer.
restore_screen:
cmpb [do_restore],#0 ! Has the screen been stored?
cmpb $0, do_restore # Has the screen been stored?
jz res1
call mode_params ! Get parameters of current mode
seg fs
mov cl,[PARAM_VIDEO_LINES]
seg fs
mov ch,[PARAM_VIDEO_COLS]
lea si,modelist+1024 ! Screen buffer
lodsw ! Set cursor position
mov dx,ax
cmp dh,cl
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
mov dh,cl
dec dh
res2: cmp dl,ch
movb %cl, %dh
decb %dh
res2: cmpb %ch, %dl
jc res3
mov dl,ch
dec dl
res3: mov ah,#0x02
mov bh,#0x00
int 0x10
lodsw ! Display size
mov dl,ah ! DL=number of lines
mov ah,#0 ! BX=physical length of orig. line
mov bx,ax
cmp dl,cl ! Too many?
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
push ax
mov al,dl
sub al,cl
mul bl
add si,ax
add si,ax
pop ax
mov dl,cl
res4: cmp al,ch ! Too wide?
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
mov al,ch ! AX=width of src. line
res5: mov cl,#0
xchg cl,ch
mov bp,cx ! BP=width of dest. line
push es
mov es,[video_segment]
xor di,di ! Move the data
add bx,bx ! Convert BX and BP to _bytes_
add bp,bp
res6: push si
push di
mov cx,ax
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
pop di
pop si
add di,bp
add si,bx
dec dl
popw %di
popw %si
addw %bp, %di
addw %bx, %si
decb %dl
jnz res6
pop es ! Done
popw %es # Done
res1: ret
#endif /* CONFIG_VIDEO_RETAIN */
!
! Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
!
outidx: out dx,al
push ax
mov al,ah
inc dx
out dx,al
dec dx
pop ax
# 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.
!
# 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:
mov di,[mt_end] ! Already filled?
or di,di
movw mt_end, %di # Already filled?
orw %di, %di
jnz mtab1x
lea di,modelist ! Store standard modes:
mov eax,#VIDEO_80x25 + 0x50190000 ! The 80x25 mode (ALL)
stosd
mov al,[adapter] ! CGA/MDA/HGA -- no more modes
or al,al
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
dec al
decb %al
jnz mtabv
mov eax,#VIDEO_8POINT + 0x502b0000 ! The 80x43 EGA mode
stosd
movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
stosl
jmp mtabe
mtab1x: jmp mtab1
mtabv: lea si,vga_modes ! All modes for std VGA
mov cx,#vga_modes_end-vga_modes
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.
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 [scanning],#0 ! Mode scan requested?
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
call vesa_modes # Detect VESA VGA modes
#endif /* CONFIG_VIDEO_VESA */
#ifdef CONFIG_VIDEO_SVGA
cmpb [scanning],#0 ! Bypass when scanning
cmpb $0, scanning # Bypass when scanning
jnz mscan2
call svga_modes ! Detect SVGA cards & modes
call svga_modes # Detect SVGA cards & modes
mscan2:
#endif /* CONFIG_VIDEO_SVGA */
mtabe:
#ifdef CONFIG_VIDEO_COMPACT
lea si,modelist ! Compact video mode list if requested.
mov dx,di
mov di,si
cmt1: cmp si,dx ! Scan all modes
leaw modelist, %si
movw %di, %dx
movw %si, %di
cmt1: cmpw %dx, %si # Scan all modes
jz cmt2
lea bx,modelist ! Find in previous entries
mov cx,(si+2)
cmt3: cmp si,bx
leaw modelist, %bx # Find in previous entries
movw 2(%si), %cx
cmt3: cmpw %bx, %si
jz cmt4
cmp cx,(bx+2) ! Found => don't copy this entry
cmpw 2(%bx), %cx # Found => don't copy this entry
jz cmt5
add bx,#4
addw $4, %bx
jmp cmt3
cmt4: movsd ! Copy entry
cmt4: movsl # Copy entry
jmp cmt1
cmt5: add si,#4 ! Skip entry
cmt5: addw $4, %si # Skip entry
jmp cmt1
cmt2:
#endif /* CONFIG_VIDEO_COMPACT */
mov (di),#ASK_VGA ! End marker
mov [mt_end],di
mtab1: lea si,modelist ! Returning: SI=mode list, DI=list end
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
# Modes usable on all standard VGAs
vga_modes:
.word VIDEO_8POINT
.word 0x5032 ! 80x50
.word 0x5032 # 80x50
.word VIDEO_80x43
.word 0x502b ! 80x43
.word 0x502b # 80x43
.word VIDEO_80x28
.word 0x501c ! 80x28
.word 0x501c # 80x28
.word VIDEO_80x30
.word 0x501e ! 80x30
.word 0x501e # 80x30
.word VIDEO_80x34
.word 0x5022 ! 80x34
.word 0x5022 # 80x34
.word VIDEO_80x60
.word 0x503c ! 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.
!
vga_modes_end:
# Detect VESA modes.
#ifdef CONFIG_VIDEO_VESA
vesa_modes:
cmpb [adapter],#2 ! VGA only
cmpb $2, adapter # VGA only
jnz ret0
mov bp,di ! BP=original mode table end
add di,#0x200 ! Buffer space
mov ax,#0x4f00 ! VESA Get card info call
int #0x10
mov di,bp
cmp ax,#0x004f ! Successful?
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
cmp (di+0x200),#0x4556
cmpw $0x4556, 0x200(%di)
jnz ret0
cmp (di+0x202),#0x4153
cmpw $0x4153, 0x202(%di)
jnz ret0
mov [card_name],#vesa_name ! Set name to "VESA VGA"
push gs
lgs si,(di+0x20e) ! GS:SI=mode list
mov cx,#128 ! Iteration limit
vesa1: seg gs ! Get next mode in the list
lodsw
cmp ax,#0xffff ! End of the table?
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
.byte 0x66, 0x65, 0xAD
cmpw $0xffff, %ax # End of the table?
jz vesar
cmp ax,#0x0080 ! Check validity of mode ID
cmpw $0x0080, %ax # Check validity of mode ID
jc vesa2
or ah,ah ! Valid IDs are 0x0000-0x007f and 0x0100-0x07ff
jz vesan ! [Certain BIOSes erroneously report 0x80-0xff]
cmp ax,#0x0800
orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
jz vesan # Certain BIOSes report 0x80-0xff!
cmpw $0x0800, %ax
jnc vesae
vesa2: push cx
mov cx,ax ! Get mode information structure
mov ax,#0x4f01
int 0x10
mov bx,cx ! BX=mode number
add bh,#VIDEO_FIRST_VESA>>8
pop cx
cmp ax,#0x004f
jnz vesan ! Don't report errors (buggy BIOSES :-[ )
mov al,(di) ! Check capabilities. We require
and al,#0x19 ! a color text mode.
cmp al,#0x09
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
cmp (di+8),#0xb800 ! Standard video memory address required
cmpw $0xb800, 8(%di) # Standard video memory address required
jnz vesan
testb (di),#2 ! Mode characteristics supplied?
mov (di),bx ! Store mode number
testb $2, (%di) # Mode characteristics supplied?
movw %bx, (%di) # Store mode number
jz vesa3
xor dx,dx
mov bx,(di+0x12) ! Width
or bh,bh
xorw %dx, %dx
movw 0x12(%di), %bx # Width
orb %bh, %bh
jnz vesan
mov (di+3),bl
mov ax,(di+0x14) ! Height
or ah,ah
movb %bl, 0x3(%di)
movw 0x14(%di), %ax # Height
orb %ah, %ah
jnz vesan
mov (di+2),al
mul bl
cmp ax,#8193 ! Small enough for Linux console driver?
movb %al, 2(%di)
mulb %bl
cmpw $8193, %ax # Small enough for Linux console driver?
jnc vesan
jmp vesaok
vesa3: sub bx,#0x8108 ! This mode has no detailed info specified,
jc vesan ! so it must be a standard VESA mode.
cmp bx,#5
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
mov ax,(bx+vesa_text_mode_table)
mov (di+2),ax
vesaok: add di,#4 ! The mode is valid. Store it.
vesan: loop vesa1 ! Next mode. Limit exceeded => error
vesae: lea si,vesaer
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
mov di,bp ! Discard already found modes.
vesar: pop gs
movw %bp, %di # Discard already found modes.
vesar: popw %gs
ret
!
! Dimensions of standard VESA text modes
!
# Dimensions of standard VESA text modes
vesa_text_mode_table:
db 60, 80 ! 0108
db 25, 132 ! 0109
db 43, 132 ! 010A
db 50, 132 ! 010B
db 60, 132 ! 010C
.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.
!
# Scan for video modes. A bit dirty, but should work.
mode_scan:
mov cx,#0x0100 ! Start with mode 0
scm1: mov ah,#0 ! Test the mode
mov al,cl
int 0x10
mov ah,#0x0f
int 0x10
cmp al,cl
jnz scm2 ! Mode not set
mov dx,#0x3c0 ! Test if it's a text mode
mov al,#0x10 ! Mode bits
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
and al,#0x03
andb $0x03, %al
jnz scm2
mov dl,#0xce ! Another set of mode bits
mov al,#0x06
movb $0xce, %dl # Another set of mode bits
movb $0x06, %al
call inidx
shr al,#1
shrb %al
jc scm2
mov dl,#0xd4 ! Cursor location
mov al,#0x0f
movb $0xd4, %dl # Cursor location
movb $0x0f, %al
call inidx
or al,al
orb %al, %al
jnz scm2
mov ax,cx ! OK, store the mode
movw %cx, %ax # Ok, store the mode
stosw
seg gs ! Number of rows
mov al,[0x484]
inc al
movb %gs:(0x484), %al # Number of rows
incb %al
stosb
seg gs ! Number of columns
mov ax,[0x44a]
movw %gs:(0x44a), %ax # Number of columns
stosb
scm2: inc cl
scm2: incb %cl
jns scm1
mov ax,#0x0003 ! Return back to mode 3
int 0x10
movw $0x0003, %ax # Return back to mode 3
int $0x10
ret
tstidx: out dx,ax ! OUT DX,AX and inidx
inidx: out dx,al ! Read from indexed VGA register
inc dx ! AL=index, DX=index reg port -> AL=data
in al,dx
dec dx
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.
!
# Try to detect type of SVGA card and supply (usually approximate) video
# mode table for it.
#ifdef CONFIG_VIDEO_SVGA
svga_modes:
lea si,svga_table ! Test all known SVGA adapters
leaw svga_table, %si # Test all known SVGA adapters
dosvga: lodsw
mov bp,ax ! Default mode table
or ax,ax
movw %ax, %bp # Default mode table
orw %ax, %ax
jz didsv1
lodsw ! Pointer to test routine
push si
push di
push es
mov bx,#0xc000
mov es,bx
call ax ! Call test routine
pop es
pop di
pop si
or bp,bp
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
mov si,bp ! Found, copy the modes
mov ah,[svga_prefix]
movw %bp, %si # Found, copy the modes
movb svga_prefix, %ah
cpsvga: lodsb
or al,al
orb %al, %al
jz didsv
stosw
movsw
jmp cpsvga
didsv: mov [card_name],si ! Store pointer to card name
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.
!
# 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
......@@ -1230,88 +1194,91 @@ svga_table:
.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
# 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:
mov cx,#0x0f35 ! we store some constants in cl/ch
mov dx,#0x03d4
movb al,#0x38
movw $0x0f35, %cx # we store some constants in cl/ch
movw $0x03d4, %dx
movb $0x38, %al
call inidx
mov bh,al ! store current value of CRT-register 0x38
mov ax,#0x0038
call outidx ! disable writing to special regs
movb al,cl ! check whether we can write special reg 0x35
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 bl,al ! save the current value of CRT reg 0x35
andb al,#0xf0 ! clear bits 0-3
movb ah,al
movb al,cl ! and write it to CRT reg 0x35
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 al,ch ! clear the upper 4 bits
jz s3_2 ! the first test failed. But we have a
movb ah,bl ! second chance
mov al,cl
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: mov ax,cx ! load ah with 0xf and al with 0x35
orb ah,bl ! set the upper 4 bits of ah with the orig value
call outidx ! write ...
call inidx ! ... and reread
andb al,cl ! turn off the upper 4 bits
push ax
movb ah,bl ! restore old value in register 0x35
movb al,cl
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
pop ax
cmp al,ch ! setting lower 4 bits was successful => bad
je no_s3 ! writing is allowed => this is not an S3
s3_1: mov ax,#0x4838 ! allow writing to special regs by putting
call outidx ! magic number into CRT-register 0x38
movb al,cl ! check whether we can write special reg 0x35
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 bl,al
andb al,#0xf0
movb ah,al
movb al,cl
movb %al, %bl
andb $0xf0, %al
movb %al, %ah
movb %cl, %al
call outidx
call inidx
andb al,ch
jnz no_s3 ! no, we can't write => no S3
mov ax,cx
orb ah,bl
andb %ch, %al
jnz no_s3 # no, we can't write => no S3
movw %cx, %ax
orb %bl, %ah
call outidx
call inidx
andb al,ch
push ax
movb ah,bl ! restore old value in register 0x35
movb al,cl
andb %ch, %al
pushw %ax
movb %bl, %ah # restore old value in register 0x35
movb %cl, %al
call outidx
pop ax
cmp al,ch
jne no_s31 ! writing not possible => no S3
movb al,#0x30
call inidx ! now get the S3 id ...
lea di,idS3
mov cx,#0x10
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 ah,bh
movb al,#0x38
movb %bh, %ah
movb $0x38, %al
jmp s3rest
no_s3: movb al,#0x35 ! restore CRT register 0x35
movb ah,bl
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
call outidx
no_s31: xor bp,bp ! Detection failed
s3rest: movb ah,bh
movb al,#0x38 ! restore old value of CRT register 0x38
br outidx
idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
.byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
......@@ -1322,16 +1289,16 @@ s3_md: .byte 0x54, 0x2b, 0x84
.ascii "S3"
.byte 0
! ATI cards.
# ATI cards.
ati_test:
lea si,idati
mov di,#0x31
mov cx,#0x09
leaw idati, %si
movw $0x31, %di
movw $0x09, %cx
repe
cmpsb
je atiok
xor bp,bp
xorw %bp, %bp
atiok: ret
idati: .ascii "761295520"
......@@ -1346,19 +1313,20 @@ ati_md: .byte 0x23, 0x19, 0x84
.ascii "ATI"
.byte 0
! AHEAD
# AHEAD
ahead_test:
mov ax,#0x200f
mov dx,#0x3ce
out dx,ax
inc dx
in al,dx
cmp al,#0x20
movw $0x200f, %ax
movw $0x3ce, %dx
outw %ax, %dx
incw %dx
inb %dx, %al
cmpb $0x20, %al
je isahed
cmp al,#0x21
cmpb $0x21, %al
je isahed
xor bp,bp
xorw %bp, %bp
isahed: ret
ahead_md:
......@@ -1372,23 +1340,23 @@ ahead_md:
.ascii "Ahead"
.byte 0
! Chips & Tech.
# Chips & Tech.
chips_test:
mov dx,#0x3c3
in al,dx
or al,#0x10
out dx,al
mov dx,#0x104
in al,dx
mov bl,al
mov dx,#0x3c3
in al,dx
and al,#0xef
out dx,al
cmp bl,#0xa5
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
xor bp,bp
xorw %bp, %bp
cantok: ret
chips_md:
......@@ -1398,50 +1366,51 @@ chips_md:
.ascii "Chips & Technologies"
.byte 0
! Cirrus Logic 5X0
# Cirrus Logic 5X0
cirrus1_test:
mov dx,#0x3d4
mov al,#0x0c
out dx,al
inc dx
in al,dx
mov bl,al
xor al,al
out dx,al
dec dx
mov al,#0x1f
out dx,al
inc dx
in al,dx
mov bh,al
xor ah,ah
shl al,#4
mov cx,ax
mov al,bh
shr al,#4
add cx,ax
shl cx,#8
add cx,#6
mov ax,cx
mov dx,#0x3c4
out dx,ax
inc dx
in al,dx
and al,al
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
mov al,bh
out dx,al
in al,dx
cmp al,#0x01
movb %bh, %al
outb %al, %dx
inb %dx, %al
cmpb $0x01, %al
je iscirr
nocirr: xor bp,bp
iscirr: mov dx,#0x3d4
mov al,bl
xor ah,ah
shl ax,#8
add ax,#0x0c
out dx,ax
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:
......@@ -1453,46 +1422,49 @@ cirrus1_md:
.ascii "Cirrus Logic 5X0"
.byte 0
! Cirrus Logic 54XX
# Cirrus Logic 54XX
cirrus5_test:
mov dx,#0x3c4
mov al,#6
movw $0x3c4, %dx
movb $6, %al
call inidx
mov bl,al ! BL=backup
mov ax,#6
movb %al, %bl # BL=backup
movw $6, %ax
call tstidx
cmp al,#0x0f
cmpb $0x0f, %al
jne c5fail
mov ax,#0x1206
movw $0x1206, %ax
call tstidx
cmp al,#0x12
cmpb $0x12, %al
jne c5fail
mov al,#0x1e
movb $0x1e, %al
call inidx
mov bh,al
mov ah,bh
and ah,#0xc0
mov al,#0x1e
movb %al, %bh
movb %bh, %ah
andb $0xc0, %ah
movb $0x1e, %al
call tstidx
and al,#0x3f
andb $0x3f, %al
jne c5xx
mov al,#0x1e
mov ah,bh
or ah,#0x3f
movb $0x1e, %al
movb %bh, %ah
orb $0x3f, %ah
call tstidx
xor al,#0x3f
and al,#0x3f
xorb $0x3f, %al
andb $0x3f, %al
c5xx: pushf
mov al,#0x1e
mov ah,bh
out dx,ax
movb $0x1e, %al
movb %bh, %ah
outw %ax, %dx
popf
je c5done
c5fail: xor bp,bp
c5done: mov al,#6
mov ah,bl
out dx,ax
c5fail: xorw %bp, %bp
c5done: movb $6, %al
movb %bl, %ah
outw %ax, %dx
ret
cirrus5_md:
......@@ -1502,37 +1474,42 @@ cirrus5_md:
.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.
# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
# it's misidentified by the Ahead test.
cirrus6_test:
mov dx,#0x3ce
mov al,#0x0a
movw $0x3ce, %dx
movb $0x0a, %al
call inidx
mov bl,al ! BL=backup
mov ax,#0xce0a
movb %al, %bl # BL=backup
movw $0xce0a, %ax
call tstidx
or al,al
orb %al, %al
jne c2fail
mov ax,#0xec0a
movw $0xec0a, %ax
call tstidx
cmp al,#0x01
cmpb $0x01, %al
jne c2fail
mov al,#0xaa
call inidx ! 4X, 5X, 7X and 8X are valid 64XX chip IDs
shr al,#4
sub al,#4
movb $0xaa, %al
call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
shrb $4, %al
subb $4, %al
jz c6done
dec al
decb %al
jz c6done
sub al,#2
subb $2, %al
jz c6done
dec al
decb %al
jz c6done
c2fail: xor bp,bp
c6done: mov al,#0x0a
mov ah,bl
out dx,ax
c2fail: xorw %bp, %bp
c6done: movb $0x0a, %al
movb %bl, %ah
outw %ax, %dx
ret
cirrus6_md:
......@@ -1540,23 +1517,25 @@ cirrus6_md:
.ascii "Cirrus Logic 64XX"
.byte 0
! Everex / Trident
# Everex / Trident
everex_test:
mov ax,#0x7000
xor bx,bx
int 0x10
cmp al,#0x70
movw $0x7000, %ax
xorw %bx, %bx
int $0x10
cmpb $0x70, %al
jne noevrx
shr dx,#4
cmp dx,#0x678
shrw $4, %dx
cmpw $0x678, %dx
je evtrid
cmp dx,#0x236
cmpw $0x236, %dx
jne evrxok
evtrid: lea bp,trident_md
evtrid: leaw trident_md, %bp
evrxok: ret
noevrx: xor bp,bp
noevrx: xorw %bp, %bp
ret
everex_md:
......@@ -1574,28 +1553,27 @@ everex_md:
.ascii "Everex/Trident"
.byte 0
! Genoa.
# Genoa.
genoa_test:
lea si,idgenoa ! Check Genoa 'clues'
xor ax,ax
seg es
mov al,[0x37]
mov di,ax
mov cx,#0x04
dec si
dec di
l1: inc si
inc di
mov al,(si)
test al,al
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
seg es
cmp al,(di)
cmpb %es:(%di), %al
l2: loope l1
or cx,cx
orw %cx, %cx
je isgen
xor bp,bp
xorw %bp, %bp
isgen: ret
idgenoa: .byte 0x77, 0x00, 0x99, 0x66
......@@ -1616,16 +1594,16 @@ genoa_md:
.ascii "Genoa"
.byte 0
! OAK
# OAK
oak_test:
lea si,idoakvga
mov di,#0x08
mov cx,#0x08
leaw idoakvga, %si
movw $0x08, %di
movw $0x08, %cx
repe
cmpsb
je isoak
xor bp,bp
xorw %bp, %bp
isoak: ret
idoakvga: .ascii "OAK VGA "
......@@ -1638,16 +1616,16 @@ oak_md: .byte 0x4e, 0x3c, 0x50
.ascii "OAK"
.byte 0
! WD Paradise.
# WD Paradise.
paradise_test:
lea si,idparadise
mov di,#0x7d
mov cx,#0x04
leaw idparadise, %si
movw $0x7d, %di
movw $0x04, %cx
repe
cmpsb
je ispara
xor bp,bp
xorw %bp, %bp
ispara: ret
idparadise: .ascii "VGA="
......@@ -1661,30 +1639,32 @@ paradise_md:
.ascii "Paradise"
.byte 0
! Trident.
# Trident.
trident_test:
mov dx,#0x3c4
mov al,#0x0e
out dx,al
inc dx
in al,dx
xchg ah,al
xor al,al
out dx,al
in al,dx
xchg al,ah
mov bl,al ! Strange thing ... in the book this wasn't
and bl,#0x02 ! necessary but it worked on my card which
jz setb2 ! is a trident. Without it the screen goes
and al,#0xfd ! blurred ...
jmp clrb2 !
setb2: or al,#0x02 !
clrb2: out dx,al
and ah,#0x0f
cmp ah,#0x02
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
xor bp,bp
xorw %bp, %bp
istrid: ret
trident_md:
......@@ -1699,21 +1679,21 @@ trident_md:
.ascii "Trident"
.byte 0
! Tseng.
# Tseng.
tseng_test:
mov dx,#0x3cd
in al,dx ! Could things be this simple? :-)
mov bl,al
mov al,#0x55
out dx,al
in al,dx
mov ah,al
mov al,bl
out dx,al
cmp ah,#0x55
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: xor bp,bp
isnot: xorw %bp, %bp
istsen: ret
tseng_md:
......@@ -1727,40 +1707,41 @@ tseng_md:
.ascii "Tseng"
.byte 0
! Video7.
# Video7.
video7_test:
mov dx,#0x3cc
in al,dx
mov dx,#0x3b4
and al,#0x01
movw $0x3cc, %dx
inb %dx, %al
movw $0x3b4, %dx
andb $0x01, %al
jz even7
mov dx,#0x3d4
even7: mov al,#0x0c
out dx,al
inc dx
in al,dx
mov bl,al
mov al,#0x55
out dx,al
in al,dx
dec dx
mov al,#0x1f
out dx,al
inc dx
in al,dx
mov bh,al
dec dx
mov al,#0x0c
out dx,al
inc dx
mov al,bl
out dx,al
mov al,#0x55
xor al,#0xea
cmp al,bh
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 [svga_prefix],#VIDEO_FIRST_V7>>8 ! Use special mode switching
movb $VIDEO_FIRST_V7>>8, $svga_prefix # Use special mode switching
ret
video7_md:
......@@ -1774,16 +1755,16 @@ video7_md:
.ascii "Video 7"
.byte 0
! Realtek VGA
# Realtek VGA
realtek_test:
lea si,idrtvga
mov di,#0x45
mov cx,#0x0b
leaw idrtvga, %si
movw $0x45, %di
movw $0x0b, %cx
repe
cmpsb
je isrt
xor bp,bp
xorw %bp, %bp
isrt: ret
idrtvga: .ascii "REALTEK VGA"
......@@ -1800,170 +1781,154 @@ realtek_md:
#endif /* CONFIG_VIDEO_SVGA */
!
! User-defined local mode table (VGA only)
!
# User-defined local mode table (VGA only)
#ifdef CONFIG_VIDEO_LOCAL
local_modes:
lea si,local_mode_table
leaw local_mode_table, %si
locm1: lodsw
or ax,ax
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.
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
.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: xor ah,ah
int 0x16
# 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.
!
# Read a key with a timeout of 30 seconds.
# The hardware clock is used to get the time.
getkt: call gettime
add al,#30 ! Wait 30 seconds
cmp al,#60
addb $30, %al # Wait 30 seconds
cmpb $60, %al
jl lminute
sub al,#60
subb $60, %al
lminute:
mov cl,al
again: mov ah,#0x01
int 0x16
jnz getkey ! key pressed, so get it
movb %al, %cl
again: movb $0x01, %ah
int $0x16
jnz getkey # key pressed, so get it
call gettime
cmp al,cl
cmpb %cl, %al
jne again
mov al,#0x20 ! timeout, return default char `space'
ret
!
! Flush the keyboard buffer
!
movb $0x20, %al # timeout, return `space'
ret
flush: mov ah,#0x01
int 0x16
# Flush the keyboard buffer
flush: movb $0x01, %ah
int $0x16
jz empty
xor ah,ah
int 0x16
xorb %ah, %ah
int $0x16
jmp flush
empty: ret
!
! Print hexadecimal number.
!
empty: ret
prthw: push ax
mov al,ah
# Print hexadecimal number.
prthw: pushw %ax
movb %ah, %al
call prthb
pop ax
prthb: push ax
shr al,#4
popw %ax
prthb: pushw %ax
shrb $4, %al
call prthn
pop ax
and al,#0x0f
prthn: cmp al,#0x0a
popw %ax
andb $0x0f, %al
prthn: cmpb $0x0a, %al
jc prth1
add al,#0x07
prth1: add al,#0x30
br prtchr
!
! Print decimal number (AL).
!
prtdec: push ax
push cx
xor ah,ah ! Clear ah
mov cl,#0x0a
idiv cl
cmp al,#0x09
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: add al,#0x30
lt100: addb $0x30, %al
call prtchr
skip10: mov al,ah
add al,#0x30
skip10: movb %ah, %al
addb $0x30, %al
call prtchr
pop cx
pop ax
popw %cx
popw %ax
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
!
! Messages:
!
# 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
# Status messages
keymsg: .ascii "Press <RETURN> to see video modes available, "
.ascii "<SPACE> to continue or wait 30 secs"
db 0x0d, 0x0a, 0
listhdr: db 0x0d, 0x0a
.byte 0x0d, 0x0a, 0
listhdr: .byte 0x0d, 0x0a
.ascii "Mode: COLSxROWS:"
crlft: db 0x0d, 0x0a, 0
prompt: db 0x0d, 0x0a
.ascii "Enter mode number or `scan': "
db 0
unknt: .ascii "Unknown mode ID. Try again."
db 0
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."
db 0x0d, 0x0a, 0
.byte 0x0d, 0x0a, 0
vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
.ascii "report to <mj@ucw.cz>."
db 0x0d, 0x0a, 0
old_name: .ascii "CGA/MDA/HGA"
db 0
ega_name: .ascii "EGA"
db 0
.byte 0x0d, 0x0a, 0
old_name: .asciz "CGA/MDA/HGA"
ega_name: .asciz "EGA"
svga_name: .ascii " "
vga_name: .ascii "VGA"
db 0
vesa_name: .ascii "VESA"
db 0
name_bann: .ascii "Video adapter: "
db 0
#endif /* CONFIG_VIDEO_SELECT */
vga_name: .asciz "VGA"
vesa_name: .asciz "VESA"
!
! Other variables:
!
name_bann: .asciz "Video adapter: "
#endif /* CONFIG_VIDEO_SELECT */
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
# 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
......@@ -242,6 +242,52 @@ CONFIG_DUMMY=m
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_DEPCA is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
# CONFIG_PCNET32 is not set
# CONFIG_ACENIC is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
# CONFIG_DE4X5 is not set
# CONFIG_DEC_ELCP is not set
# CONFIG_DGRS is not set
CONFIG_EEXPRESS_PRO100=y
# CONFIG_NE2K_PCI is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
#
# Wireless LAN (non-hamradio)
#
# CONFIG_NET_RADIO is not set
#
# Token Ring driver support
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
#
# PCMCIA network devices
#
CONFIG_PCMCIA_PCNET=y
# CONFIG_PCMCIA_3C589 is not set
CONFIG_PCMCIA_RAYCS=y
CONFIG_PCMCIA_NETCARD=y
#
# Amateur Radio support
......
......@@ -42,7 +42,7 @@
#include <asm/system.h>
#include <asm/semaphore.h>
#include "pc_keyb.h" /* mouse enable command.. */
#include <linux/pc_keyb.h> /* mouse enable command.. */
/*
......@@ -134,7 +134,7 @@ static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
}
queue->head = head;
if (queue->fasync)
kill_fasync(queue->fasync, SIGIO);
kill_fasync(queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
}
......
......@@ -130,9 +130,9 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
if [ "$CONFIG_NET_EISA" = "y" ]; then
tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
# tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
fi
# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
# tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
# fi
tristate ' Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
if [ "$CONFIG_ACENIC" != "n" ]; then
bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
......
......@@ -166,16 +166,9 @@ int imm_detect(Scsi_Host_Template * host)
*/
imm_hosts[i].mode = IMM_NIBBLE;
if (modes & PARPORT_MODE_PCPS2)
if (modes & PARPORT_MODE_TRISTATE)
imm_hosts[i].mode = IMM_PS2;
if (modes & PARPORT_MODE_PCECPPS2) {
w_ecr(ppb, 0x20);
imm_hosts[i].mode = IMM_PS2;
}
if (modes & PARPORT_MODE_PCECPEPP)
w_ecr(ppb, 0x80);
/* Done configuration */
imm_pb_release(i);
......
......@@ -459,6 +459,11 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
for (i = 0; i < MAX_NR_CONSOLES; i++)
set_con2fb_map(i, con2fb.framebuffer);
return 0;
case FBIOBLANK:
if (info->blank == 0)
return -EINVAL;
(*info->blank)(arg, info);
return 0;
default:
return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(info),
info);
......
......@@ -26,6 +26,7 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/blk.h>
#include <linux/ide.h> /* IDE xlate */
#include <asm/system.h>
......
......@@ -37,6 +37,31 @@ extern unsigned char pckbd_sysrq_xlate[128];
#define SYSRQ_KEY 0x54
/* resource allocation */
#define kbd_request_region()
#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
"keyboard", NULL)
/* How to access the keyboard macros on this platform. */
#define kbd_read_input() inb(KBD_DATA_REG)
#define kbd_read_status() inb(KBD_STATUS_REG)
#define kbd_write_output(val) outb(val, KBD_DATA_REG)
#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
/* Some stoneage hardware needs delays after some operations. */
#define kbd_pause() do { } while(0)
/*
* Machine specific bits for the PS/2 driver
*/
#define AUX_IRQ 12
#define aux_request_irq(hand, dev_id) \
request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
#endif /* __KERNEL__ */
#endif /* __ASMalpha_KEYBOARD_H */
......@@ -487,6 +487,15 @@ extern inline long strlen_user(const char *str)
return access_ok(VERIFY_READ,str,0) ? __strlen_user(str) : 0;
}
/* Returns: 0 if exception before NUL or reaching the supplied limit (N),
* a value greater than N if the limit would be exceeded, else strlen. */
extern long __strnlen_user(const char *, long);
extern inline long strnlen_user(const char *str, long n)
{
return access_ok(VERIFY_READ,str,0) ? __strnlen_user(str, n) : 0;
}
/*
* About the exception table:
*
......
......@@ -26,6 +26,7 @@
/* #define FBIOSWITCH_MONIBIT 0x460E */
#define FBIOGET_CON2FBMAP 0x460F
#define FBIOPUT_CON2FBMAP 0x4610
#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */
#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
#define FB_TYPE_PLANES 1 /* Non interleaved planes */
......
......@@ -46,9 +46,6 @@
#ifndef OK_TO_RESET_CONTROLLER /* 1 needed for good error recovery */
#define OK_TO_RESET_CONTROLLER 1 /* 0 for use with AH2372A/B interface */
#endif
#ifndef FAKE_FDISK_FOR_EZDRIVE /* 1 to help linux fdisk with EZDRIVE */
#define FAKE_FDISK_FOR_EZDRIVE 1 /* 0 to reduce kernel size */
#endif
#ifndef FANCY_STATUS_DUMPS /* 1 for human-readable drive errors */
#define FANCY_STATUS_DUMPS 1 /* 0 to reduce kernel size */
#endif
......@@ -262,9 +259,7 @@ typedef struct ide_drive_s {
unsigned nice2 : 1; /* flag: give a share in our own bandwidth */
unsigned doorlocking : 1; /* flag: for removable only: door lock/unlock works */
unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */
#if FAKE_FDISK_FOR_EZDRIVE
unsigned remap_0_to_1 : 1; /* flag: partitioned with ezdrive */
#endif /* FAKE_FDISK_FOR_EZDRIVE */
unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */
unsigned ata_flash : 1; /* 1=present, 0=default */
byte media; /* disk, cdrom, tape, floppy, ... */
select_t select; /* basic drive/head select reg value */
......@@ -282,8 +277,9 @@ typedef struct ide_drive_s {
byte sect; /* "real" sectors per track */
byte bios_head; /* BIOS/fdisk/LILO number of heads */
byte bios_sect; /* BIOS/fdisk/LILO sectors per track */
unsigned short bios_cyl; /* BIOS/fdisk/LILO number of cyls */
unsigned short cyl; /* "real" number of cyls */
unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */
unsigned int cyl; /* "real" number of cyls */
unsigned long capacity; /* total number of sectors */
unsigned int drive_data; /* for use by tuneproc/selectproc as needed */
void *hwif; /* actually (ide_hwif_t *) */
wait_queue_head_t wqueue; /* used to wait for drive in open() */
......@@ -624,21 +620,19 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou
/*
* This routine is called from the partition-table code in genhd.c
* to "convert" a drive to a logical geometry with fewer than 1024 cyls.
*
* The second parameter, "xparm", determines exactly how the translation
* will be handled:
* 0 = convert to CHS with fewer than 1024 cyls
* using the same method as Ontrack DiskManager.
* 1 = same as "0", plus offset everything by 63 sectors.
* -1 = similar to "0", plus redirect sector 0 to sector 1.
* >1 = convert to a CHS geometry with "xparm" heads.
*
* Returns 0 if the translation was not possible, if the device was not
* an IDE disk drive, or if a geometry was "forced" on the commandline.
* Returns 1 if the geometry translation was successful.
*/
int ide_xlate_1024 (kdev_t, int, int, const char *);
/*
* Convert kdev_t structure into ide_drive_t * one.
*/
ide_drive_t *get_info_ptr (kdev_t i_rdev);
/*
* Return the current idea about the total capacity of this drive.
*/
unsigned long current_capacity (ide_drive_t *drive);
/*
* Start a reset operation for an IDE interface.
* The caller should return immediately after invoking this.
......
......@@ -823,8 +823,8 @@ extern inline int task_on_runqueue(struct task_struct *p)
extern inline void unhash_process(struct task_struct *p)
{
if (task_on_runqueue(p)) BUG();
nr_threads--;
write_lock_irq(&tasklist_lock);
nr_threads--;
unhash_pid(p);
REMOVE_LINKS(p);
write_unlock_irq(&tasklist_lock);
......
......@@ -326,6 +326,7 @@ struct tty_struct {
#define TTY_HW_COOK_OUT 14
#define TTY_HW_COOK_IN 15
#define TTY_PTY_LOCK 16
#define TTY_NO_WRITE_SPLIT 17
#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
......
......@@ -592,6 +592,12 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
struct task_struct *p;
DECLARE_MUTEX_LOCKED(sem);
if (clone_flags & CLONE_PID) {
/* This is only allowed from the boot up thread */
if (current->pid)
return -EPERM;
}
current->vfork_sem = &sem;
p = alloc_task_struct();
......@@ -610,8 +616,9 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
}
/*
* Counter atomicity is protected by
* the kernel lock
* Counter increases are protected by
* the kernel lock so nr_threads can't
* increase under us (but it may decrease).
*/
if (nr_threads >= max_threads)
goto bad_fork_cleanup_count;
......@@ -711,9 +718,9 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
write_lock_irq(&tasklist_lock);
SET_LINKS(p);
hash_pid(p);
nr_threads++;
write_unlock_irq(&tasklist_lock);
nr_threads++;
wake_up_process(p); /* do this last */
++total_forks;
......@@ -735,8 +742,6 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
__MOD_DEC_USE_COUNT(p->exec_domain->module);
if (p->binfmt && p->binfmt->module)
__MOD_DEC_USE_COUNT(p->binfmt->module);
nr_threads--;
bad_fork_cleanup_count:
if (p->user)
free_uid(p);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment