Trying to load GDT into a psycho-Pentium

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
Hello everybody.

I'm having problems trying to start up a new Pentium-based CPU. It has 8 MB of
RAM (lowest addresses) and 8 MB of FLASH memory (highest addresses).

I can load programs with a PC via JTAG into the FLASH (4 chips of 1Mx16,
arranged as 1 Mibi of 64-bit words), and I can control the CPU with a Microtek
JTAG-ICE (with no trace memory).

I can start the programs, step by step or with a 'go forever' command, and all
my real-mode programs work as expected. But when I try to load the GDT before
switching to protected mode, the program seems to jump to a random address,
where it sometimes stops (perhaps after executing a break instruction) and
sometimes not (in which cause I can stop the ICE, and CS:EIP is pointing to a
random address, anyway)

I tried to stop the program with a HLT instruction after the LGDT instruction,
to no avail.

This is the reset vector, as disassembled by the ICE:

dasm cs:fff0 cs:fff1
// CS:FFF0 FA           CLI
// CS:FFF1 E90CF8       JMP         F800

This is the code from the first jump target. Remeber, I can execute the code
just up to (and excluding) CS:F810.

dasm cs:f800
// CS:F800 FA           CLI
// CS:F801 B001         MOV         AL,01
// CS:F803 B200         MOV         DL,00
// CS:F805 B602         MOV         DH,02
// CS:F807 EE           OUT         DX,AL
// CS:F808 67668D1D4BF8 LEA         EBX,[FFFFF84B]
// CS:F80E FFFF
// CS:F810 67660F011588 LGDT        [FFFFF888]
// CS:F816 F8FFFF
// CS:F819 F4           HLT
// CS:F81A 90           NOP
// CS:F81B 90           NOP

This the GDT length + linear address:

dump fffff888p
// FFFFF888P  17 00 90 F8 FF FF

i.e., length = 0x17 +1 = 24 (3 entries), address = 0xFFFFF890

This is the GDT:

dump fffff890p fffff8a7p word
// FFFFF890P  0000 0000 0000 0000 FFFF 0000 9A00 00CF
// FFFFF8A0P  FFFF 0000 9200 00CF

i.e.:
selector 0 (0x00): null descriptor
selector 1 (0x08): code, 32 GB, read-only
selector 2 (0x10): data, 32 GB, read-write

These are the CPU registers before execution the LGDT instruction:

//      EIP = 0x0000F810
//      ESP = 0x00000000
//      EBP = 0x00000000
//      EAX = 0x00000001
//      EBX = 0xFFFFF84B
//      ECX = 0x00000000
//      EDX = 0x00000200
//      ESI = 0x00000000
//      EDI = 0x00000000
//   EFLAGS = 0x00000002
//          = ivfavrn0oditszapc
//       CS = 0xF000
//       DS = 0x0000
//       ES = 0x0000
//       FS = 0x0000
//       GS = 0x0000
//       SS = 0x0000
//  GDTBASE = 0x00000000
// GDTLIMIT = 0xFFFF
//  IDTBASE = 0x00000000
// IDTLIMIT = 0xFFFF
//     LDTR = 0x0000
//       TR = 0x0000
//      CR0 = 0x60000010
//      CR2 = 0x00000000
//      CR3 = 0x00000000
//      CR4 = 0x00000008
//  LDTBASE = 0x00000000
// LDTLIMIT = 0xFFFF
//   CSBASE = 0xFFFF0000
//   DSBASE = 0x00000000
//   ESBASE = 0x00000000
//   FSBASE = 0x00000000
//   GSBASE = 0x00000000
//   SSBASE = 0x00000000
//  CSLIMIT = 0x0000FFFF
//  DSLIMIT = 0x0000FFFF
//  ESLIMIT = 0x0000FFFF
//  FSLIMIT = 0x0000FFFF
//  GSLIMIT = 0x0000FFFF
//  SSLIMIT = 0x0000FFFF
//     CSAR = 0x00009300
//     DSAR = 0x00009300
//     ESAR = 0x00009300
//     FSAR = 0x00009300
//     GSAR = 0x00009300
//     SSAR = 0x00009300
//    GDTAR = 0x00008200
//    IDTAR = 0x00008200
//    LDTAR = 0x00008200
//  TSSBASE = 0x00000000
// TSSLIMIT = 0x0000FFFF
//    TSSAR = 0x00008200

And these are the CPU register after the LGDT instruction + unknown
instructions:

register
//      EIP = 0x00007D07
//      ESP = 0x0000FFF3
//      EBP = 0x00000000
//      EAX = 0x00000001
//      EBX = 0xFFFFA04B
//      ECX = 0x00005FBE
//      EDX = 0x000001FF
//      ESI = 0x00000000
//      EDI = 0x00000000
//   EFLAGS = 0x00000016
//          = ivfavrn0oditszAPc
//       CS = 0x46BB
//       DS = 0x0000
//       ES = 0x0000
//       FS = 0x0000
//       GS = 0x0000
//       SS = 0x0000
//  GDTBASE = 0x00000000
// GDTLIMIT = 0xFFFF
//  IDTBASE = 0x00000000
// IDTLIMIT = 0xFFFF
//     LDTR = 0x0000
//       TR = 0x0000
//      CR0 = 0x60000010
//      CR2 = 0x00000000
//      CR3 = 0x00000000
//      CR4 = 0x00000008
//  LDTBASE = 0x00000000
// LDTLIMIT = 0xFFFF
//   CSBASE = 0x00046BB0
//   DSBASE = 0x00000000
//   ESBASE = 0x00000000
//   FSBASE = 0x00000000
//   GSBASE = 0x00000000
//   SSBASE = 0x00000000
//  CSLIMIT = 0x0000FFFF
//  DSLIMIT = 0x0000FFFF
//  ESLIMIT = 0x0000FFFF
//  FSLIMIT = 0x0000FFFF
//  GSLIMIT = 0x0000FFFF
//  SSLIMIT = 0x0000FFFF
//     CSAR = 0x00009300
//     DSAR = 0x00009300
//     ESAR = 0x00009300
//     FSAR = 0x00009300
//     GSAR = 0x00009300
//     SSAR = 0x00009300
//    GDTAR = 0x00008200
//    IDTAR = 0x00008200
//    LDTAR = 0x00008200
//  TSSBASE = 0x00000000
// TSSLIMIT = 0x0000FFFF
//    TSSAR = 0x00008200

Can anybody please throw some light ?

--
Ignacio G.T.

Re: Trying to load GDT into a psycho-Pentium
bear in mind the processor WILL do segmentation faults while in real mode, I
don't
remember whether it is a catch-all or if there are more restrictive rules though.
So if you really can't figure things like this out you might hook int 0x0d and
see
if it gets triggered.

It has been a while since I did raw protected mode, but the one thing that jumps
out at me is you are
reading from 0fffff890h with no segment prefix, and with DS=0 where the limit on
DS is 0ffffh according to your dumps.  This is I think what you do get when you
boot...   I am wondering if you may get a segmentation fault under these
conditions?   I don't know for sure on this since I haven't dealt with the
boot-up
process personally.  But if this is the case you can get around it by forcing a
CS: prefix on the faulting instruction and changing the offset accordingly.

David

"Ignacio G.T." wrote:

Quoted text here. Click to load it

Re: Trying to load GDT into a psycho-Pentium

Quoted text here. Click to load it
don't
Quoted text here. Click to load it
though.
Quoted text here. Click to load it
see
Quoted text here. Click to load it

You are right. In fact, after posting the original message, I filled the
interrupt vectors zone with pointers to difrent HLT instructions, and the GP
vector (0x0d) was triggered.

Quoted text here. Click to load it
boot-up
Quoted text here. Click to load it

It sounds reasonable. I'm trying it right now.

Thank you, David.


--
Ignacio G.T.

Re: Trying to load GDT into a psycho-Pentium
On Fri, 01 Oct 2004 09:30:57 GMT, snipped-for-privacy@evomer.yahoo.es (Ignacio G.T.)

Quoted text here. Click to load it
don't
Quoted text here. Click to load it
though.
Quoted text here. Click to load it
see
Quoted text here. Click to load it
jumps
Quoted text here. Click to load it
on
Quoted text here. Click to load it
boot-up
Quoted text here. Click to load it

Bad news, David. I've just tried

  LGDT CS:[FFFFF888]

and the results are the same.

Intel's manual says this, for the LGDT instruction:

===
Real-Address Mode Exceptions
------------------------------------
#UD If source operand is not a memory location.
#GP If a memory operand effective address is outside the CS, DS, ES, FS, or
GS segment limit.
#SS If a memory operand effective address is outside the SS segment limit.
===

We know its a #GP, but I still don't know why. Perhaps I should try copying the
GDT to RAM and trying to load it from there...

--
Ignacio G.T.

Re: Trying to load GDT into a psycho-Pentium
Quoted text here. Click to load it

Well, that has worked. Copy the GTD to RAM (0x0400), copy the GDT descriptor
just after the GDT (0x0418), and load the GDT with LGDT 0x00000418.

Now, switching to protected mode. Stay tuned...

--
Ignacio G.T.

Re: Trying to load GDT into a psycho-Pentium
Quoted text here. Click to load it

Did you try

     LGDT CS:[f888]

Please note that the processor is in *16* bit
mode till the descriptors are in and protected
mode is turned on.

There is somewhere in the back of my trash box
a piece of code that boots an i386 into 32-bit
protected mode. If it is of any help, I could
find it among the dusty backup CD's.

Tauno Voipio
tauno voipio (at) iki fi


Re: Trying to load GDT into a psycho-Pentium
On Fri, 01 Oct 2004 20:14:07 GMT, Tauno Voipio

Quoted text here. Click to load it

Thanks, Tauno. You are right. It works with this:

66 67 2E 0F 01 15 88 F8 00 00

i.e.

LGDT CS:[0000F888]

Quoted text here. Click to load it

That would be great. Just in case I get stuck with the jump to protected mode.

Quoted text here. Click to load it

--
Ignacio G.T.

Re: Trying to load GDT into a psycho-Pentium
Quoted text here. Click to load it

Ignacio,

please send me you working mail address. The yahoo.es address
refused my mail.

Correct my address in the sig in the obvous way to send.

Tauno Voipio
tauno voipio (at) iki fi


Re: Trying to load GDT into a psycho-Pentium
Quoted text here. Click to load it
mode.

Try http://members.tripod.com/protected_mode/ and http://alexfru.narod.ru /

Alex



Re: Trying to load GDT into a psycho-Pentium
that won't work because you have to take into account the base address of CS:...
 which
is FFFF0000.
you should do:

LGDT CS:[F888]

what you did GPFs because the limit on CS is 64K as well, and when you add in
the base
you are out
of range.

David
"Ignacio G.T." wrote:

Quoted text here. Click to load it
G.T.)
Quoted text here. Click to load it
wrote:
Quoted text here. Click to load it
don't
Quoted text here. Click to load it
though.
Quoted text here. Click to load it
and see
Quoted text here. Click to load it
jumps
Quoted text here. Click to load it
limit on
Quoted text here. Click to load it
you
Quoted text here. Click to load it
boot-up
Quoted text here. Click to load it
forcing a
Quoted text here. Click to load it

Re: Trying to load GDT into a psycho-Pentium

Quoted text here. Click to load it

32-bit addresses greater than 0xFFFF are illegal in real mode,
and cause CPU interrupt 13 (the "pseudo-GPF"). Maybe the CPU
jumps to the int 13 vector before HLT is executed.

I don't think the LEA instruction causes an exception because
the 32-bit address is not de-referenced.

Quoted text here. Click to load it


_Something_ has caused a far JMP. The INT 13 vector is stored
in the 32-bit value at memory location 0x34. Is this value
0x46BB7D07 by chance?

P.S. - notice the strange value of CSBASE after reset. If you
change the value of the CS register while still in real mode,
the CS segment descriptor cache (CSBASE) will be reloaded, and your
program will fall down into conventional memory (below 1 megabyte).

P.P.S. - I ran your code through Bochs and got this:

========================================================================
                        Bochs x86 Emulator 2.0
                           December 21, 2002
========================================================================
[0x000ffff0] f000:fff0 (unk. ctxt): cli                       ; fa
<bochs:1> setpmem 0x18 4 0x100dead0        (exception 6 -- illegal instruction)
<bochs:2> setpmem 0x30 4 0x200dead0        (exception 12 -- stack fault)
<bochs:3> setpmem 0x34 4 0x300dead0        (exception 13 -- GPF)
<bochs:4> s
Next at t=1
(0) [0x000ffff1] f000:fff1 (unk. ctxt): jmp f800                  ; e90cf8
<bochs:5> s
Next at t=2
(0) [0x000ff800] f000:f800 (unk. ctxt): cli                       ; fa
<bochs:6> s
Next at t=3
(0) [0x000ff801] f000:f801 (unk. ctxt): mov AL, 01                ; b001
<bochs:7> s
Next at t=4
(0) [0x000ff803] f000:f803 (unk. ctxt): mov DL, 00                ; b200
<bochs:8> s
Next at t=5
(0) [0x000ff805] f000:f805 (unk. ctxt): mov DH, 02                ; b602
<bochs:9> s
Next at t=6
(0) [0x000ff807] f000:f807 (unk. ctxt): out DX, AL                ; ee
<bochs:10> s
Next at t=7
(0) [0x000ff808] f000:f808 (unk. ctxt): lea EBX, DS:fffff84b      ;
66678d1d4bf8ffff
<bochs:11> s
Next at t=8
(0) [0x000ff810] f000:f810 (unk. ctxt): lgdt DS:fffff888          ;
670f011588f8ffff
<bochs:12> s
Next at t=9
(0) [0x0003eba2] 300d:ead2 (unk. ctxt): add DS:[BX+SI], AL        ; 0000
<bochs:13>


Re: Trying to load GDT into a psycho-Pentium

Quoted text here. Click to load it

Mmm. I've read that, although on startup, CS = F000 and EIP = FFF0, the "hidden"
part of CS is 0xFFFF0000, so, in fact, you are accessing the highest part of the
4GB linear address space on startup, although only through CS, not through DS,
ES, ES or GS.

Quoted text here. Click to load it

I agree. In fact, EBX is loaded with FFFFF84B after LEA, and the processor
remains controlled by the ICE at this point.

Quoted text here. Click to load it

You are right. I know now that a GP is being caused by the LGDT instruction.

Quoted text here. Click to load it
66678d1d4bf8ffff
Quoted text here. Click to load it
670f011588f8ffff
Quoted text here. Click to load it

Thank you very much, Chris.

--
Ignacio G.T.

Re: Trying to load GDT into a psycho-Pentium
Looks like you have had some good advice and thinking already.  Rather than try
and understand it all, I'll just add some quick thoughts of my own.

When the processor starts up, it starts in 'real' mode.  It's still actually in
protected mode, but the internal cached versions of descriptor entries are
pre-loaded by the processor reset to use USE16 segment interpretations and to
specify default behavior that 'appears' to be real mode behavior.

In your case, you correctly identify the fact that the CPU, by default, starts
up at the end of 32-bit memory, using CS = F000 and EIP = 0000FFF0.  However,
the CS register's contents are essentially ignored during operation, as they are
meaningless to the actual hardware.  Instead, the hardware uses the "hidden"
cached copies of the descriptor, which on reset for the CS are:

  Value = F000H
  Base = FFFF0000H
  Limit = FFFFH
  AR = Present,
  R/W,
  Accessed

The value, as I said, isn't used by the bus interface unit.  It is always
ignored.  When you load a segment/selector register, the processor looks at CR0
to determine "real or protected" and then either precodes the base and limit
through a fixed calculation on the loaded value (if in real mode) or else goes
out into memory and loads them from the indicated place.  But in no case, not
ever, whether CR0 says real or protected mode, does the processor's BIU ever use
the value field.  It's ignored, except for a tiny moment in time when it first
gets loaded.

So when you say the "hidden part of CS is 0xFFFF0000" what you really mean is
that the base field of the cached area related to CS is that value.

Note that the Limit is still 0xFFFF!

This will be used, whether or not you like it, to validate any offset values you
try and apply when referring to CS.  You need your offset to remain within a 64k
area of where the CS base refers.

I *do* have to disagree with Chris when he says, "32-bit addresses greater than
0xFFFF are illegal in real mode."  It is CR0 that decides what mode your are in,
but that has absolutely nothing to do with what kind of offsets are accepted.
It is strictly the Limit field of the cached region in the CPU associated with
the selector that decides this.  And it does so without any regard whatsoever
for the CR0 status.  You can load up the CS when in protected mode and thereby
control what goes into this cache and then you can switch back to real mode and
the cached Limit field will still operate.  If you set it to some very large
limit, you will be allowed to use very large offsets even while in what is
supposed to be real mode, according to the CR0 condition.  So long as you don't
reload CS while in real mode you won't blow that cached value.  Of course, if
you do change CS while in real mode, that Limit field will immediately get
recoded back to 0xFFFF and your CS segment will again be limited.

One thing to keep in mind is that when the processor first comes out of reset it
does NOT have paging enabled.  Without paging, it is impossible to generate
anything other than 0 for the upper 4 bits of the 36 bit physical addresses.
Instead, only the low-order 32-bits are used.  The initial address executed has
to be found in the flash or ROM that must be located at that place.  The first
JMP you encounter, the one going to 0xF800, does not change the CS.  So these
addresses are still "high."

Your LGDT is executed quite quickly, I gather, after that point.  I assume that
your CR0 still has you in real mode at this point in time and that the Limit
field for the CS still applies and is tiny.  As such, your offset there is far
too big.

Also, take a close look at the description for the LGDT instruction.  I've
usually used a DB 66h before the instruction to force the operand size from the
USE16 I'm currently running in to the USE32 interpretation, because I want the
16-bit limit and 32-bit base, not the 16-bit limit and 24-bit base for the data
I'm pointing to.  Also, you'll need to then change CR0 and perform a JMP to
flush the instruction pipeline to start new instruction interpretations
afterwards.

Does any of that help?

Jon

Re: Trying to load GDT into a psycho-Pentium

Quoted text here. Click to load it

[lots of useful info]

Quoted text here. Click to load it

Yes, Jon. Now I can LGDT using two different approaches and, best of all, I
understand both !

--
Ignacio G.T.

Re: Trying to load GDT into a psycho-Pentium
On Mon, 04 Oct 2004 09:32:16 GMT, snipped-for-privacy@evomer.yahoo.es (Ignacio G.T.)

Quoted text here. Click to load it

Wonderful!

I remember the first time I decided to write code to enter protected mode and
some of the troubles.  And... my excitement when I first turned on the paging
system and remapped the VGA memory to a different linear address and it worked
when I wrote characters there!  (Interrupts disabled, that first time, because
biting off setting up a decent IDT was a bit much.)  I then went back to DOS
mode and exited without crashing, afterwards!  Wonderful feeling getting that
right!

Best of luck!

Jon

Site Timeline