source: rtems/c/src/lib/libbsp/i386/pc386/startup/ldsegs.S @ 38bfb0d

4.104.114.84.9
Last change on this file since 38bfb0d was 38bfb0d, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 26, 1999 at 9:35:15 PM

Patch from Eric Valette <valette@…> based on a tremendous
bug report from David Decotigny <David.Decotigny@…>:

During the last few days, I've been back working on RTEMS. Let me
remind you that RTEMS didn't boot on our (old) Dell P90 machines (ref:
PC 590) : we could only get a reboot out of them.

1/ The symptoms
---------------

Hopefully, the problem was rather deterministic. The stack couldn't be
written correctly : issueing one or more "push" would always push '0'
onto the stack. The way to solve this was to issue a "pop", such as
"pushl eax ; popl eax". After this "pop", the stack would be writeable
again.

BUT, it will be writable for 8 consecutive "push"s. After these 8
"push"s, the other "push"s are wrong again, and a blank push/pop is
needed.

Considering that the L1 cache lines of this pentium are 32 bytes long,
and that 8 long int are 32 bytes long too, it came to us that there
was a problem with the cache.

Actually, the bug of the push could be shown through memory accesses
directly : writing on an not-in-cache mem location would put 0 until
this mem location is accessed through a single "read". Then, the whole
cache line would be right again.

2/ The consequences
-------------------

Of course, that was the first thing that we've been able to observe ;)
RTEMS could not boot. Actually, when a "call" pushed 0 onto the stack,
the ret could only lead to raise an exception a bit later. Since, in
the early stage, the Interrupt vector points to 0, averything couldn't
get worse : triple fault + reboot.

3/ Explanation
--------------

This cache mechanism corruption only appeared after load_segment()
returned (through a jump). Investigating a bit further shows that this
appears /sometimes/ during the PICs initialization.

"Sometimes" proved to be "When writing something with the 4th bit of
%al set". That is "when writing 0x28 or 0xff" for example. Clearing
this bit would just make the things work right.

Actually, this isn't a bug in the proper PIC initialization (which is
quite academic). It came from the "delay" routine, which theoretically
does nothing but writing to an "inexistant" port (0xed), in order to
lose some time.

BUT, in the special case of our Dell P90, it appears that this 0xed
port does something cruel with the cache mechanism when its 4th bit
(aka bit 3 or 0x8) is set.

I didn't investigate this non-standard behaviour of the P90 any
further : I don't know if this is documented, or if it is just another
(known ?) bug of the early Pentiums. Just notice that we have 5 such
machines, and it has the same effect on the cache mechanism.


  • Property mode set to 100644
File size: 7.2 KB
Line 
1/*-------------------------------------------------------------------------+
2| ldsegs.s v1.1 - PC386 BSP - 1997/08/07
3+--------------------------------------------------------------------------+
4| This file assists the board independent startup code by loading the proper
5| segment register values. The values loaded are board dependent. In addition
6| it contains code to enable the A20 line and to reprogram the PIC to relocate
7| the IRQ interrupt vectors to 0x20 -> 0x2f.
8| NOTE: No stack has been established when this routine is invoked.
9|       It returns by jumping back to bspentry.
10+--------------------------------------------------------------------------+
11| (C) Copyright 1997 -
12| - NavIST Group - Real-Time Distributed Systems and Industrial Automation
13|
14| http://pandora.ist.utl.pt
15|
16| Instituto Superior Tecnico * Lisboa * PORTUGAL
17+--------------------------------------------------------------------------+
18| Disclaimer:
19|
20| This file is provided "AS IS" without warranty of any kind, either
21| expressed or implied.
22+--------------------------------------------------------------------------+
23| This code is base on:
24|   ldsegs.s,v 1.4 1996/04/20 16:48:30 joel Exp - go32 BSP
25| With the following copyright notice:
26| **************************************************************************
27| *  COPYRIGHT (c) 1989-1998.
28| *  On-Line Applications Research Corporation (OAR).
29| *  Copyright assigned to U.S. Government, 1994.
30| *
31| *  The license and distribution terms for this file may be
32| *  found in found in the file LICENSE in this distribution or at
33| *  http://www.OARcorp.com/rtems/license.html.
34| **************************************************************************
35|
36|  $Id$
37|
38| Also based on (from the Linux source tree):
39|   setup.S - Copyright (C) 1991, 1992 Linus Torvalds
40+--------------------------------------------------------------------------*/
41
42
43#include "asm.h"
44
45/*----------------------------------------------------------------------------+
46| CODE section
47+----------------------------------------------------------------------------*/
48EXTERN (rtems_i8259_masks)
49       
50BEGIN_CODE
51
52        EXTERN (_establish_stack)
53        EXTERN (Timer_exit)
54        EXTERN (clockOff)
55
56        .p2align 4
57/*----------------------------------------------------------------------------+
58| delay
59+------------------------------------------------------------------------------
60| Delay is needed after doing I/O. We do it by writing to a non-existent port.
61+----------------------------------------------------------------------------*/
62SYM(delay):
63        outb    al, $0x80       # about 1uS delay
64        ret
65
66/*-------------------------------------------------------------------------+
67|         Function: _load_segments
68|      Description: Current environment is standard PC booted by grub.
69|                   So, there is no value in saving current GDT and IDT
70|                   settings we have to set it up ourseves. (Naturally
71|                   it will be not so in case we are booted by some
72|                   boot monitor, however, then it will be different
73|                   BSP). After that we have to load board segment registers
74|                   with apropriate values +  reprogram PIC.
75| Global Variables: None.
76|        Arguments: None.
77|          Returns: Nothing.
78+--------------------------------------------------------------------------*/
79        .p2align 4
80       
81        PUBLIC (_load_segments)
82SYM (_load_segments):
83
84        lgdt SYM(gdtdesc)
85        lidt SYM(idtdesc)
86
87        /* Load CS, flush prefetched queue */
88        ljmp $0x8, $next_step
89
90next_step:     
91        /* Load segment registers */
92        movw $0x10, ax
93        movw ax, ss
94        movw ax, ds
95        movw ax, es
96        movw ax, fs
97        movw ax, gs
98
99/*---------------------------------------------------------------------+
100| Now we have to reprogram the interrupts :-(. We put them right after
101| the intel-reserved hardware interrupts, at int 0x20-0x2F. There they
102| won't mess up anything. Sadly IBM really messed this up with the
103| original PC, and they haven't been able to rectify it afterwards. Thus
104| the bios puts interrupts at 0x08-0x0f, which is used for the internal
105| hardware interrupts as well. We just have to reprogram the 8259's, and
106| it isn't fun.
107+---------------------------------------------------------------------*/
108
109        movb    $0x11, al               /* initialization sequence          */
110        outb    al, $0x20               /* send it to 8259A-1               */
111        call    SYM(delay)
112        outb    al, $0xA0               /* and to 8259A-2                   */
113        call    SYM(delay)
114       
115        movb    $0x20, al               /* start of hardware int's (0x20)   */
116        outb    al, $0x21
117        call    SYM(delay)
118        movb    $0x28, al               /* start of hardware int's 2 (0x28) */
119        outb    al, $0xA1
120        call    SYM(delay)
121       
122        movb    $0x04, al               /* 8259-1 is master                 */
123        outb    al, $0x21
124        call    SYM(delay)
125        movb    $0x02, al               /* 8259-2 is slave                  */
126        outb    al, $0xA1
127        call    SYM(delay)
128       
129        movb    $0x01, al               /* 8086 mode for both               */
130        outb    al, $0x21
131        call    SYM(delay)
132        outb    al, $0xA1
133        call    SYM(delay)
134       
135        movb    $0xFF, al               /* mask off all interrupts for now  */
136        outb    al, $0xA1
137        call    SYM(delay)
138        movb    $0xFB, al               /* mask all irq's but irq2 which    */
139        outb    al, $0x21               /* is cascaded                      */
140        call    SYM(delay)
141
142        movw    $0xFFFB, SYM(i8259s_cache) /* set up same values in cache */
143       
144        jmp     SYM (_establish_stack)  # return to the bsp entry code
145
146/*-------------------------------------------------------------------------+
147|         Function: _return_to_monitor
148|      Description: Return to board's monitor (we have none so simply restart).
149| Global Variables: None.
150|        Arguments: None.
151|          Returns: Nothing.
152+--------------------------------------------------------------------------*/
153
154        .p2align 4
155       
156        PUBLIC (_return_to_monitor)
157SYM (_return_to_monitor):
158
159        call    SYM (Timer_exit)
160        call    SYM (Clock_exit)
161        jmp     SYM (start)
162
163/*-------------------------------------------------------------------------+
164|         Function: _default_int_handler
165|      Description: default interrupt handler
166| Global Variables: None.
167|        Arguments: None.
168|          Returns: Nothing.
169+--------------------------------------------------------------------------*/
170        .p2align 4
171       
172/*---------------------------------------------------------------------------+
173| GDT itself
174+--------------------------------------------------------------------------*/
175
176        .p2align 4
177               
178        PUBLIC (_Global_descriptor_table)
179SYM (_Global_descriptor_table):
180
181        /* NULL segment */
182        .word 0, 0     
183        .byte 0, 0, 0, 0
184
185        /* code segment */
186        .word 0xffff, 0
187        .byte 0, 0x9e, 0xcf, 0
188
189        /* data segment */
190        .word 0xffff, 0
191        .byte 0, 0x92, 0xcf, 0
192 
193
194/*---------------------------------------------------------------------------+
195| Descriptor of GDT
196+--------------------------------------------------------------------------*/
197SYM (gdtdesc):
198        .word (3*8 - 1) 
199        .long SYM (_Global_descriptor_table)
200
201
202/*---------------------------------------------------------------------------+
203| IDT itself
204+---------------------------------------------------------------------------*/
205        .p2align 4
206       
207        PUBLIC(Interrupt_descriptor_table)
208SYM(Interrupt_descriptor_table):
209        .rept 256
210        .word 0,0,0,0
211        .endr
212       
213/*---------------------------------------------------------------------------+
214| Descriptor of IDT
215+--------------------------------------------------------------------------*/
216SYM(idtdesc):   
217        .word  (256*8 - 1)
218        .long  SYM (Interrupt_descriptor_table)
219       
220END_CODE
221
222END
Note: See TracBrowser for help on using the repository browser.