OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [i386/] [boot/] [setup.S] - Rev 1781

Go to most recent revision | Compare with Previous | Blame | View Log

!
!       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>

! NOTE! These had better be the same as in bootsect.s!
#define __ASSEMBLY__
#include <linux/config.h>
#include <asm/segment.h>
#include <linux/version.h>
#include <linux/compile.h>

! Signature words to ensure LILO loaded us right
#define SIG1    0xAA55
#define SIG2    0x5A5A

INITSEG  = DEF_INITSEG  ! 0x9000, we move boot here - out of the way
SYSSEG   = DEF_SYSSEG   ! 0x1000, system loaded at 0x10000 (65536).
SETUPSEG = DEF_SETUPSEG ! 0x9020, this is the current segment
                        ! ... and the former contents of CS
DELTA_INITSEG = SETUPSEG - INITSEG ! 0x0020

.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text

entry start
start:
        jmp     start_of_setup
! ------------------------ 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
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:      .byte   0        ! unused bits =0 (reserved for future development)
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!
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:   .long   0x1000          ! here loaders can put a different
                                        ! start address for 32-bit code.
                                        !   0x1000 = default for zImage
                                        ! 0x100000 = default for big kernel
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
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.
! ------------------------ end of header ----------------------------------

start_of_setup:
! Bootlin depends on this being done early
        mov     ax,#0x01500
        mov     dl,#0x81
        int     0x13

#ifdef SAFE_RESET_DISK_CONTROLLER
! Reset the disk controller.
        mov     ax,#0x0000
        mov     dl,#0x80
        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
        jne     bad_sig
        cmp     setup_sig2,#SIG2
        jne     bad_sig
        jmp     good_sig1

! Routine to print asciiz-string at DS:SI

prtstr: lodsb
        and     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

prtchr: push    ax
        push    cx
        xor     bh,bh
        mov     cx,#0x01
        mov     ah,#0x0e
        int     0x10
        pop     cx
        pop     ax
        ret

beep:   mov     al,#0x07
        jmp     prtchr
        
no_sig_mess:    .ascii  "No setup signature found ..."
                db      0x00

good_sig1:
        jmp     good_sig

! 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,#8           ! convert to words
        mov     cx,bx
        shr     bx,#3           ! 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
        rep
        movsw

        mov     ax,cs           ! aka #SETUPSEG
        mov     ds,ax
        cmp     setup_sig1,#SIG1
        jne     no_sig
        cmp     setup_sig2,#SIG2
        jne     no_sig
        jmp     good_sig

no_sig:
        lea     si,no_sig_mess
        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
        call    prtstr
        jmp     no_sig_loop
loader_panic_mess: 
        .ascii  "Wrong loader, giving up..."
        db      0

loader_ok:
! Get memory size (extended mem, kB)

#ifndef STANDARD_MEMORY_BIOS_CALL
        push    ebx

        xor     ebx,ebx         ! preload new memory slot with 0k
        mov     [0x1e0], ebx

        mov     ax,#0xe801
        int     0x15
        jc      oldstylemem

        and     ebx, #0xffff    ! clear sign extend
        shl     ebx, 6          ! and go from 64k to 1k chunks
        mov     [0x1e0],ebx     ! store extended memory size

        and     eax, #0xffff    ! clear sign extend
        add     [0x1e0],eax     ! and add lower memory into total size.
  
        ! and fall into the old memory detection code to populate the
        ! compatability slot.

oldstylemem:
        pop     ebx
#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 bootsector

! 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
        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
        rep
        movsb

! Check that there IS a hd1 :-)

        mov     ax,#0x01500
        mov     dl,#0x81
        int     0x13
        jc      no_disk1
        cmp     ah,#3
        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
        cld
        rep
        stosb
is_disk1:

! 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
        jz      no_psmouse
        mov     [0x1ff],#0xaa   ! 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

        mov     [64],ax         ! record the APM BIOS version
        mov     [76],cx         !       and flags
        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     bx,bx
        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],si         ! BIOS code segment length
        mov     [80],di         ! BIOS data segment length
        jmp     done_apm_bios

no_32_apm_bios:
        and     [76], #0xfffd   ! remove 32 bit support bit

done_apm_bios:
#endif

! Now we want to move to protected mode ...

        seg cs
        cmp     realmode_swtch,#0
        jz      rmodeswtch_normal
        seg cs
        callf   far * realmode_swtch
        jmp     rmodeswtch_end
rmodeswtch_normal:
        push    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

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
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,#0x800
        rep
        movsw
        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
        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 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.
        mov     ax,cs
        cmp     ax,#SETUPSEG
        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
        jb      move_self_1
        add     dx,#INITSEG
        sub     dx,ax           ! this will be 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
        rep
        movsb
        jmpi    move_self_here,SETUPSEG ! jump to our final place
move_self_here:
        mov     cx,#move_self_here+0x200
        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
        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.  

#define TEST_ADDR 0x7c

        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
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
        call    delay

! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
! we put them right after the intel-reserved hardware interrupts, at
! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
! messed this up with the original PC, and they haven't been able to
! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
! which is used for the internal hardware interrupts as well. We just
! have to reprogram the 8259's, and it isn't fun.

        mov     al,#0x11                ! initialization sequence
        out     #0x20,al                ! send it to 8259A-1
        call    delay
        out     #0xA0,al                ! and to 8259A-2
        call    delay
        mov     al,#0x20                ! start of hardware int's (0x20)
        out     #0x21,al
        call    delay
        mov     al,#0x28                ! start of hardware int's 2 (0x28)
        out     #0xA1,al
        call    delay
        mov     al,#0x04                ! 8259-1 is master
        out     #0x21,al
        call    delay
        mov     al,#0x02                ! 8259-2 is slave
        out     #0xA1,al
        call    delay
        mov     al,#0x01                ! 8086 mode for both
        out     #0x21,al
        call    delay
        out     #0xA1,al
        call    delay
        mov     al,#0xFF                ! mask off all interrupts for now
        out     #0xA1,al
        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!
        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


kernel_version: .ascii  UTS_RELEASE
                .ascii  " ("
                .ascii  LINUX_COMPILE_BY
                .ascii  "@"
                .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

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.
!
bootsect_helper:
        seg cs
        cmp     word ptr bootsect_es,#0
        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
bootsect_second:
        push    cx
        push    si
        push    bx
        test    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
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

bootsect_gdt:
        .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
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
bootsect_es:
        .word   0

bootsect_panic:
        push    cs
        pop     ds
        cld
        lea     si,bootsect_panic_mess
        call    prtstr
bootsect_panic_loop:
        jmp     bootsect_panic_loop
bootsect_panic_mess:
        .ascii  "INT15 refuses to access high mem, giving up..."
        db      0

! This routine checks that the keyboard command queue is empty
! (after emptying the output buffers)
!
! No timeout is used - if this hangs there is something wrong with
! the machine, and we probably couldn't proceed anyway.
empty_8042:
        call    delay
        in      al,#0x64        ! 8042 status port
        test    al,#1           ! output buffer?
        jz      no_output
        call    delay
        in      al,#0x60        ! read it
        jmp     empty_8042
no_output:
        test    al,#2           ! is input buffer full?
        jnz     empty_8042      ! yes - loop
        ret

!
! 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
        aad
        pop     cx
        ret

!
! Delay is needed after doing I/O
!
delay:
        .word   0x00eb                  ! jmp $+2
        ret

!
! 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)

idt_48:
        .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

!
! Include video setup & detection code
!

#include "video.S"

!
! Setup signature -- must be last
!

setup_sig1:     .word   SIG1
setup_sig2:     .word   SIG2

!
! After this point, there is some free space which is used by the video mode
! handling code to store the temporary mode table (not used by the kernel).
!

modelist:

.text
endtext:
.data
enddata:
.bss
endbss:

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.