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
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
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 :(
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.
Hi MaxPayne,
Before I provide an answer, is this supposed to run under Windows? Why DPL=3?
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.
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
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.
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 :)
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
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
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
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.
:) 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
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.
But when I run it clear after power on (after POST) there is no memory managers loaded ? Am i right ?
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.
I'm sure - because i run it after POST. I mean that my bootloader execute all this. Bootloader is ok - i check it
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
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!
Offtopic: Aero are You realy 14 years old ??
Max
Actually about 14.3
Why do you ask?
When I was 14, i have only know that ther is something like asm.. nothing more :)
Max
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 :)
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
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/