Trying to load GDT into a psycho-Pentium

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.

Reply to
Ignacio G.T.
Loading thread data ...

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:

Reply to
David Lindauer

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.

_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 setpmem 0x18 4 0x100dead0 (exception 6 -- illegal instruction) setpmem 0x30 4 0x200dead0 (exception 12 -- stack fault) setpmem 0x34 4 0x300dead0 (exception 13 -- GPF) s Next at t=1 (0) [0x000ffff1] f000:fff1 (unk. ctxt): jmp f800 ; e90cf8 s Next at t=2 (0) [0x000ff800] f000:f800 (unk. ctxt): cli ; fa s Next at t=3 (0) [0x000ff801] f000:f801 (unk. ctxt): mov AL, 01 ; b001 s Next at t=4 (0) [0x000ff803] f000:f803 (unk. ctxt): mov DL, 00 ; b200 s Next at t=5 (0) [0x000ff805] f000:f805 (unk. ctxt): mov DH, 02 ; b602 s Next at t=6 (0) [0x000ff807] f000:f807 (unk. ctxt): out DX, AL ; ee s Next at t=7 (0) [0x000ff808] f000:f808 (unk. ctxt): lea EBX, DS:fffff84b ;

66678d1d4bf8ffff s Next at t=8 (0) [0x000ff810] f000:f810 (unk. ctxt): lgdt DS:fffff888 ; 670f011588f8ffff s Next at t=9 (0) [0x0003eba2] 300d:ead2 (unk. ctxt): add DS:[BX+SI], AL ; 0000
Reply to
Chris Giese

don't

though.

see

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.

boot-up

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

Thank you, David.

-- Ignacio G.T.

Reply to
Ignacio G.T.

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.

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

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

66678d1d4bf8ffff
670f011588f8ffff

Thank you very much, Chris.

-- Ignacio G.T.

Reply to
Ignacio G.T.

don't

though.

see

jumps

on

boot-up

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.

Reply to
Ignacio G.T.

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.

Reply to
Ignacio G.T.

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

Reply to
Tauno Voipio

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

Reply to
Jonathan Kirwan

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 Fri, 01 Oct 2004 09:30:57 GMT, snipped-for-privacy@evomer.yahoo.es (Ignacio

G.T.)

don't

though.

and see

jumps

limit on

you

boot-up

forcing a

Reply to
David Lindauer

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

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

i.e.

LGDT CS:[0000F888]

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

-- Ignacio G.T.

Reply to
Ignacio G.T.

[lots of useful info]

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

-- Ignacio G.T.

Reply to
Ignacio G.T.

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

Reply to
Jonathan Kirwan

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

Reply to
Tauno Voipio

mode.

Try

formatting link
and
formatting link

Alex

Reply to
Alexei A. Frounze

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.