The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: MaxPayne on May 23, 2005, 11:13:23 PM

Title: Global Descriptor Table
Post by: MaxPayne on May 23, 2005, 11:13:23 PM
Hi !

I've got some problems with load Global Descriptor Table. When i try to use: lgdt gdt MASM (ver. 6.11) returns "immidiate operands not allowed". I tried to use registers but it doesn't help.

Greetings

MaxPayne

Title: Re: Global Descriptor Table
Post by: mnemonic on May 23, 2005, 11:23:43 PM
Hi MaxPayne,

welcome in here.

I think you do not use the instruction right.
OPCODES.HLP (\masm32\help\) says:
LGDT - Load Global Descriptor Table (286+ privileged)
        Usage:  LGDT    src
        Modifies flags: None
        Loads a value from an operand into the Global Descriptor Table
        (GDT) register.
                                 Clocks                 Size
        Operands         808x  286   386   486          Bytes
        mem64              -    11    11    11            5

        0F 01 /2 LGDT m16&32 Load m into GDTR

That means you must use a memory location as operand (maybe "gdt" is a reserved word).

Regards
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 23, 2005, 11:38:55 PM
Yes i know, it's not reserved and under gdt hiddes
gdt:
dw 5*8-1
dd gdt

_gdt:
dd 0,0 ; NULL Descriptor
dd 00000FFFFh,000CF9A00h
dd 00000FFFFh,000CF9200h
dd 00000FFFFh,000CFFA00h
dd 00000FFFFh,000CFF200h

Could You give me some working examples, i have no idea how to do that :(
Title: Re: Global Descriptor Table
Post by: mnemonic on May 24, 2005, 12:00:57 AM
Sorry, I never did something before with "lgdt". I only know its meaning from books.
So I don´t have any working code regarding this issue, sorry.

Quote from: MaxPayne on May 23, 2005, 11:38:55 PM
gdt:
dw 5*8-1
dd gdt

_gdt:
dd 0,0 ; NULL Descriptor
dd 00000FFFFh,000CF9A00h
dd 00000FFFFh,000CF9200h
dd 00000FFFFh,000CFFA00h
dd 00000FFFFh,000CFF200h
I don´t know what you´re really doing with that declaration but as long as MASM complains about "immidiate operands not allowed"...
Did you try to use
lgdt offset gdt
Maybe that helps.
Title: Re: Global Descriptor Table
Post by: MichaelW on May 24, 2005, 12:22:43 AM
Hi MaxPayne,

Before I provide an answer, is this supposed to run under Windows? Why DPL=3?

Title: Re: Global Descriptor Table
Post by: AeroASM on May 24, 2005, 06:25:35 AM
He is (you are) trying to make an OS with MASM, which I attempted a couple of months ago and gave up, because MASM physically will not let you use direct immediate operands. I switched to FASM, it is much easier.
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 24, 2005, 06:31:35 AM
Quote from: MichaelW on May 24, 2005, 12:22:43 AM
Hi MaxPayne,

Before I provide an answer, is this supposed to run under Windows? Why DPL=3?



hymm, i'm trying to write something like os and maybe it's true that there could be problems with dpl level, but if does - how could it change gdt ? I thought that assembler is assembler and it should complie... even under windows. Thank You for adsvices and sorry for my English

MaxPayne
Title: Re: Global Descriptor Table
Post by: AeroASM on May 24, 2005, 07:20:51 AM
MASM is a high-level kind of assembler [Aero shields himself from hutch--  :eek] and so not only provides many high level constructs it also tries to protect the coder. MASM was designed only for making programs under Windows and so you never need direct memory access, so they are protecting you from accessing memory directly. As I said, try using NASM or FASM to compile and you should be fine.
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 24, 2005, 07:41:57 AM
Aero -> Thank You very much :).. if I don't ask about this i will be blind for a long time :D. I hadn't found any info saying that MASM is -somekind- high level asm. Once again thanks :)
Title: Re: Global Descriptor Table
Post by: MichaelW on May 24, 2005, 09:04:57 AM
Aero,

MASM was designed for making pretty much any kind of executable, and it can readily assemble things like this. In this case MASM is refusing to assemble an instruction with an operand of the wrong type.

Max,

LGDT and LIDT take a 6-byte data operand in memory, so unless the table descriptor is defined as an FWORD, you must precede the operand with FWORD PTR, as in:

lgdt fword ptr gdt

Title: Re: Global Descriptor Table
Post by: MaxPayne on May 24, 2005, 11:59:11 AM
It works :D Thank You.. I didn't know about this conversion.. maybe i'm using too old books :P.. anyway thank You :)

Greetings

Max
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 25, 2005, 10:28:56 AM
Hi !

I've got new problem :)... everything compile and code looks to be ok but when a EIP goes to lgdt fword ptr gdt_descr program ends and i don't know why ? There is my code:

.model small,stdcall
.386p
.stack 512
.data
   gdt_descr dw 3*8-1
                  dd  gdt
      gdt dd 0,0 ; NULL Descriptor
      dd 00000FFFFh,000CF9A00h ;
      dd 00000FFFFh,000CF9200h ;

.code
  start:
         mov ax,@data
         mov ds,ax 
     
         clli
         mov al,0D1h
         out 064h,al

         mov al,0DFh
         out 060h,al

       ;   xor ax,ax
       ;   mov ax,ds
       ;   shl ax,4
       ;   or eax,dword ptr gdt_descr
       ;        lgdt fword ptr ds:[eax]

        lgdt fword ptr ds:[gdt_descr]    <-------- Everything ends here


        mov eax,cr0
        or eax,01h
        mov cr0,eax

I tried this with other memory models (etc. tiny,small..) and the results were the same - program ends. Ii becomes before i set cr0 register.
Thank You for any help

Greetings

MaxPayne

   
Title: Re: Global Descriptor Table
Post by: AeroASM on May 25, 2005, 10:32:26 AM
Are you running this in real MS-DOS mode or from the Windows console?

The Windows console is just an emulator of DOS and so will not handle these things.
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 25, 2005, 10:54:39 AM
:) I run it on a windows console and under VMware machine. In VMware the program has stops and it doesn't do nothing -  i mean it doesn't execute code after lgdt instruction. Under windows i tried to debug it but when debugger comes to this line and it ends like before.

Greetings

MaxPayne
Title: Re: Global Descriptor Table
Post by: MichaelW on May 25, 2005, 04:04:20 PM
Max,

Windows is terminating your program when it detects the attempt to execute a privileged instruction. To do such things directly the processor must be in real mode. If you are running Windows 9x you can restart in MS-DOS mode. If not, possible choices are a Windows 9x boot diskette (that should be able to access a FAT32 file system) or a DOS boot diskette (that will normally be limited to accessing the diskette). Perhaps I should mention that 386 memory managers run the processor in protected mode, and at least most of them will intercept and block privileged instructions.
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 25, 2005, 04:46:06 PM
But when I run it clear after power on (after POST) there is no memory managers loaded ?  Am i right ?
Title: Re: Global Descriptor Table
Post by: AeroASM on May 25, 2005, 05:14:20 PM
No, there aren't.

memory managers are loaded by the operating system such as Windows or MS-DOS. Therefore to make sure they are not loaded, either load Win9x ms-dos safe mode or make your own OS.
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 25, 2005, 05:18:05 PM
I'm sure - because i run it after POST. I mean that my bootloader execute all this. Bootloader is ok - i check it
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 25, 2005, 05:40:24 PM
I've check it once again.. and there is something streange.. this program fail o this instructions:
...
       cli
       mov eax,cr0
       or eax,01h
       mov cr0,eax
       sti
...
lgdt is allright... but why it crush enterin in pmode?? eaven gdt is wrong it should works, because lgdt doesn't change any segments.. only we have to make a far jmp or retf... strange

Greetings

MaxPayne
Title: Re: Global Descriptor Table
Post by: AeroASM on May 25, 2005, 05:52:57 PM
Just remembered something:

Straightaway after mov cr0,eax you must make the far jump, to do two things:

1. Make the cs register point to a valid segment (probably 0008)
2. Flush the prefetch queue.

Straightaway after the jump you should (not must) set all segment selectors (cs,ds,es,fs,gs,ss) to either a valid segment or 0 (null segment).

When I was making an OS it kept failing... eventually I discovered it was because I had put 16h not 16 into a selector!
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 25, 2005, 06:02:13 PM
Offtopic: Aero are You realy 14 years old ??

Max
Title: Re: Global Descriptor Table
Post by: AeroASM on May 25, 2005, 06:25:49 PM
Actually about 14.3

Why do you ask?
Title: Re: Global Descriptor Table
Post by: MaxPayne on May 25, 2005, 06:35:01 PM
When I was 14, i have only know that ther is something like asm.. nothing more :)

Max
Title: Re: Global Descriptor Table
Post by: MichaelW on May 25, 2005, 08:19:16 PM
Max,

I added the comment on the 386 memory managers because it was not unusual for Windows 9x systems to be running one of these managers for MS-DOS mode. Windows 9x (and the later versions of MS-DOS) included the Microsoft 386 memory manager EMM386.EXE.

A far (inter-segment) jump after the mode switch was necessary for the 386 and 486 to empty the prefetch queue and load the CS descriptor cache. Starting with the Pentium there was no need to empty a prefetch queue, but a far jump is still a reasonable method of loading the CS descriptor cache. AFAIK, unless you have an IDT and the necessary handlers in place, you should not enable interrupts after the mode switch.

Judging from Aero's posts, I too would expect someone older that 14.3 :)


Title: Re: Global Descriptor Table
Post by: MaxPayne on May 25, 2005, 09:00:44 PM
Hi MichaelW !

Thank You for that info. Please correct me if  i'm wrong:

This is my gdt
    gdt_descr:
       dw 3*8-1
       dd offset gdt
    gdt:
      dd 0,0 ; NULL Descriptor
      dd 00000FFFFh,000CF9A00h
      dd 00000FFFFh,000CF9200h

and when i do something like this:

                ....
                lgdt fword ptr gdt_descr
                cli      
   mov eax,cr0
   or eax,01h
   mov cr0,eax

               jmp far pmode ; or db   0eah 
                                    ; dw offset pmode

               pmode:
               ... ;32bit prtoected mode code

What will be in my CS register ?? will it be 0001h - selector ??? Will cpu execute code after pmode: label ??If i want cpu to execute further my code - after pmode: label - what sould i do ?? When i run this code in VMware, it makes "Virtual machine kernel stack fault (hardware reset)..."


Greetings

Title: Re: Global Descriptor Table
Post by: MichaelW on May 26, 2005, 01:46:59 AM
You need to specify the selector and the offset address in the jump instruction. Something like this:

db 0eah
dw offset pmode
dw 8
pmode:

I don't know what kind of segment structure you are using for the real-mode code, but note that this will assemble only if the default address size for the current segment is 16 bits.

Note also that the offset address is encoded as an absolute value rather than a displacement (a relative address). To make this work, you need to ensure that the segment base specified in the code segment descriptor matches the segment base for the segment of the jump instruction, or you need to adjust the offset address to compensate for the difference in the bases.

In my previous post read "load the CS descriptor cache" as "load the code selector into CS". Loading the code selector into CS will cause the processor to load the CS descriptor cache, but your code is just loading the selector into CS.

If your protected mode code uses data, you will need to load a valid selector into DS. If your protected mode code uses the stack, you will need to load a valid selector into SS and set ESP to a useable value.

If you get everything right, then you program should be able to execute in protected mode. But once you are in protected mode you will not be able to call the BIOS functions, so to display anything (without complex code) you will need to write it directly to the display buffer. If your data segment overlaps the display buffer, you could calculate the necessary offset addresses from the segment base and the absolute address of the display buffer. But it would probably be easier to create a segment descriptor for the display buffer (with the base set to B8000h), load the corresponding selector into ES, and access the display buffer using an ES segment override and the normal offset addresses.

Agner Fog has some test programs that switch to protected mode, perform the tests, and then switch back to real mode. You may be able to learn something useful by studying the source.

http://www.agner.org/assem/