summaryrefslogtreecommitdiffstats
path: root/bsps/i386/pc386/start/ldsegs.S
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/i386/pc386/start/ldsegs.S')
-rw-r--r--bsps/i386/pc386/start/ldsegs.S238
1 files changed, 238 insertions, 0 deletions
diff --git a/bsps/i386/pc386/start/ldsegs.S b/bsps/i386/pc386/start/ldsegs.S
new file mode 100644
index 0000000000..b56bf836f0
--- /dev/null
+++ b/bsps/i386/pc386/start/ldsegs.S
@@ -0,0 +1,238 @@
+/*-------------------------------------------------------------------------+
+| ldsegs.s v1.1 - PC386 BSP - 1997/08/07
++--------------------------------------------------------------------------+
+| This file assists the board independent startup code by loading the proper
+| segment register values. The values loaded are board dependent. In addition
+| it contains code to enable the A20 line and to reprogram the PIC to relocate
+| the IRQ interrupt vectors to 0x20 -> 0x2f.
+| NOTE: No stack has been established when this routine is invoked.
+| It returns by jumping back to bspentry.
++--------------------------------------------------------------------------+
+| (C) Copyright 1997 -
+| - NavIST Group - Real-Time Distributed Systems and Industrial Automation
+|
+| http://pandora.ist.utl.pt
+|
+| Instituto Superior Tecnico * Lisboa * PORTUGAL
++--------------------------------------------------------------------------+
+| Disclaimer:
+|
+| This file is provided "AS IS" without warranty of any kind, either
+| expressed or implied.
++--------------------------------------------------------------------------+
+| This code is base on:
+| ldsegs.s,v 1.4 1996/04/20 16:48:30 joel Exp - go32 BSP
+| With the following copyright notice:
+| **************************************************************************
+| * COPYRIGHT (c) 1989-1999.
+| * On-Line Applications Research Corporation (OAR).
+| *
+| * The license and distribution terms for this file may be
+| * found in the file LICENSE in this distribution or at
+| * http://www.rtems.org/license/LICENSE.
+| **************************************************************************
++--------------------------------------------------------------------------*/
+
+#include <rtems/asm.h>
+#include <bsp/tblsizes.h> /* contains sizes of GDT and IDT */
+#include <bspopts.h>
+
+/*----------------------------------------------------------------------------+
+| CODE section
++----------------------------------------------------------------------------*/
+EXTERN (rtems_i8259_masks)
+
+BEGIN_CODE
+
+ EXTERN (_establish_stack)
+ EXTERN (Timer_exit)
+ EXTERN (clockOff)
+
+/*----------------------------------------------------------------------------+
+| pc386_delay
++------------------------------------------------------------------------------
+| Delay is needed after doing I/O.
+|
+| The outb version is OK on most machines BUT the loop version ...
+|
+| will delay for 1us on 1Gz machine, it will take a little bit
+| longer on slower machines, however, it does not matter because we
+| are going to call this function only a few times
+
++----------------------------------------------------------------------------*/
+#define DELAY_USE_OUTB
+
+ .p2align 4
+ .globl _pc386_delay
+ .globl pc386_delay
+pc386_delay:
+_pc386_delay:
+#ifdef DELAY_USE_OUTB
+ outb al, $0x80 # about 1uS delay on most machines
+#else
+ movl $0x200, eax
+pc386_delay1:
+ dec eax
+ jnz pc386_delay1
+#endif
+ ret
+
+/*-------------------------------------------------------------------------+
+| Function: _load_segments
+| Description: Current environment is standard PC booted by grub.
+| So, there is no value in saving current GDT and IDT
+| settings we have to set it up ourseves. (Naturally
+| it will be not so in case we are booted by some
+| boot monitor, however, then it will be different
+| BSP). After that we have to load board segment registers
+| with apropriate values + reprogram PIC.
+| Global Variables: None.
+| Arguments: None.
+| Returns: Nothing.
++--------------------------------------------------------------------------*/
+ .p2align 4
+
+ PUBLIC (_load_segments)
+SYM (_load_segments):
+
+ lgdt SYM(gdtdesc)
+ lidt SYM(IDT_Descriptor)
+
+ /* Load CS, flush prefetched queue */
+ ljmp $0x8, $next_step
+
+next_step:
+ /* Load segment registers */
+ movw $0x10, ax
+ movw ax, ss
+ movw ax, ds
+ movw ax, es
+ movw ax, fs
+ movw ax, gs
+
+/*---------------------------------------------------------------------+
+| 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.
++---------------------------------------------------------------------*/
+
+ movb $0x11, al /* initialization sequence */
+ outb al, $0x20 /* send it to 8259A-1 */
+ call SYM(pc386_delay)
+ outb al, $0xA0 /* and to 8259A-2 */
+ call SYM(pc386_delay)
+
+ movb $0x20, al /* start of hardware int's (0x20) */
+ outb al, $0x21
+ call SYM(pc386_delay)
+ movb $0x28, al /* start of hardware int's 2 (0x28) */
+ outb al, $0xA1
+ call SYM(pc386_delay)
+
+ movb $0x04, al /* 8259-1 is master */
+ outb al, $0x21
+ call SYM(pc386_delay)
+ movb $0x02, al /* 8259-2 is slave */
+ outb al, $0xA1
+ call SYM(pc386_delay)
+
+ movb $0x01, al /* 8086 mode for both */
+ outb al, $0x21
+ call SYM(pc386_delay)
+ outb al, $0xA1
+ call SYM(pc386_delay)
+
+ /*
+ * The IMR values must correspond to the initial value of i8259s_cache.
+ */
+ movb $0xFF, al /* mask off all interrupts for now */
+ outb al, $0xA1
+ call SYM(pc386_delay)
+ movb $0xFB, al /* mask all irq's but irq2 which */
+ outb al, $0x21 /* is cascaded */
+ call SYM(pc386_delay)
+ jmp SYM (_establish_stack) # return to the bsp entry code
+
+/*-------------------------------------------------------------------------+
+| Function: _default_int_handler
+| Description: default interrupt handler
+| Global Variables: None.
+| Arguments: None.
+| Returns: Nothing.
++--------------------------------------------------------------------------*/
+ .p2align 4
+
+/*---------------------------------------------------------------------------+
+| GDT itself
++--------------------------------------------------------------------------*/
+#if GDT_SIZE < NUM_SYSTEM_GDT_DESCRIPTORS
+#error "GDT_SIZE must be at least NUM_SYSTEM_GDT_DESCRIPTORS"
+#endif
+
+BEGIN_DATA
+ .p2align 4
+
+ PUBLIC (_Global_descriptor_table)
+SYM (_Global_descriptor_table):
+
+ /* NULL segment */
+ .word 0, 0
+ .byte 0, 0, 0, 0
+
+ /* code segment */
+ .word 0xffff, 0
+ .byte 0, 0x9e, 0xcf, 0
+
+ /* data segment */
+ .word 0xffff, 0
+ .byte 0, 0x92, 0xcf, 0
+
+ /* gs segment */
+ .word 0xffff, 0
+ .byte 0, 0x92, 0xcf, 0
+
+ /* allocated space for user segments */
+ .rept (GDT_SIZE - NUM_SYSTEM_GDT_DESCRIPTORS)
+ .word 0,0,0,0
+ .endr
+
+/*---------------------------------------------------------------------------+
+| Descriptor of GDT
++--------------------------------------------------------------------------*/
+ PUBLIC(gdtdesc)
+SYM(gdtdesc):
+ .word (GDT_SIZE*8 - 1)
+ .long SYM (_Global_descriptor_table)
+
+/*---------------------------------------------------------------------------+
+| IDT itself
++---------------------------------------------------------------------------*/
+ .p2align 4
+
+ PUBLIC(Interrupt_descriptor_table)
+SYM(Interrupt_descriptor_table):
+ .rept IDT_SIZE
+ .word 0,0,0,0
+ .endr
+
+/*---------------------------------------------------------------------------+
+| Descriptor of IDT
++--------------------------------------------------------------------------*/
+
+ .p2align 4
+ PUBLIC(IDT_Descriptor)
+SYM(IDT_Descriptor):
+ .word (IDT_SIZE*8 - 1)
+ .long SYM (Interrupt_descriptor_table)
+
+END_DATA
+
+ .section .m_hdr
+ .long 0x1BADB002
+ .long 0
+ .long 0xE4524FFE
+END