hello all,
i am using the masm32 compiler along with its linker and wrote 16-bit asm code to enter CPU into protected mode. I did before several years ago and entered p-mode successful but this time it is brush-up thing. Now the following line in my asm returns error code:
lgdt [gdtPtr]
with gdtPtr is the pointer to GDT structure. Rechecked everything but when during compilation this line causes error:
A2085: instruction or register is not accepted in current CPU mode.
I tried many things like putting .586p but still no avail. I can not figure out why it is throwing this error, I have never seen it in the past.
has any has their ears rining bell or something??
Once compiler it has to run from DOS environment (not from Windows box virtual DOS) , the real DOS.
However during compilation it should not matter.
Thanks.,
use .686p
http://masm32.com/board/index.php?topic=4029.msg42766#msg42766 (http://masm32.com/board/index.php?topic=4029.msg42766#msg42766)
you used only two words to reply, but it solved my problem :lol: :t :greensml:
yah, i'm efficient that way :lol:
BUMMER! :( it turns out i build wrong file with does not have the lgdt instruction. Back to sad reality I build the file and even with .686p, it is stll not building. Any other ideas??
One minute for Google, five minutes to test:
include \masm32\include\masm32rt.inc
.686p
GDT STRUCT
limitStorage dw ?
baseStorage dd ?
GDT ENDS
.code
mygdt GDT <?>
start:
inkey "it assembles"
exit
lgdt mygdt
end start
the first 2 lines of Jochen's code tell you what's happening :biggrin:
the masm32rt.inc file sets the processor to .486
so, the .686p line has to go after the include
this builds, but raises a priviledged instruction exception, as one might expect
;###############################################################################################
INCLUDE \Masm32\Include\Masm32rt.inc
.686p
;###############################################################################################
.DATA?
tablex FWORD ?
;###############################################################################################
.CODE
;***********************************************************************************************
main PROC
lgdt tablex
inkey
exit
main ENDP
;###############################################################################################
END main
still not working.
I did
.486
.686p
I am using the more elaborate old way of declaring the segments. I am wondering if that is the cause:
.486
.686p
include macros.inc
sta segment para stack use16 'stack'
db 100h dup(0)
sta ends
data segment para public 'data'
str0 db 'test string in asmfile.asm$'
str1 db 'str1$'
acpiPtr db 'RSD PTR$'
bdaPtr db 0f8h, 03h, '$'
; dw gdt_end - gdt - 1 ;last byte in table
; dd gdt ;start of table
gdtPtrSize db 0,0
gdtPtrAddr db 0,0,0,0
; 0:15 - limit 0:15
; 15:31 - base 0:15
; 0:7 - base 16:23
; 8:15 - access byte
; 16:19 - limit 16:19
; 20:23 - flags
; 24:31 - base 24:31
; entry0 - not used
; entry1 - dw ffff - limit 0:15
; db 0 -
; base 0:31 = 00000000h
; limit 0:19 = ffffffh
; access byte = 10010010b?
; flags = 1100b?
; gdt start
; entry 0 (always unused)
gdt dd 0,0 ; entry 0 is always unused
; entry 1
flatdesc dw 0ffffh ; limit 0:15
db 0, 0 ; base 0:15
db 0 ; base 16:23
db 10010010b ; access byte
; 1 - present (yes)
; 00 - privilige 00
; 1?
; 0 - data selector
; 0 - can only executed from ring set in priv level.
; 1 - readable code segment
; 0 - accessed bit. cpu sets this bit when accessed.
db 11001111b ; limit 16:19 flag
; 1 - granularity bit - 1 limit is in 4KiB blocks
; 1 - Sz - 32-bit protected mode
; 00 - ??
db 0 ; base 24:31
gdtEnd dw 0
data ends
code segment para public use16 'code'
assume cs:code, ds:data,ss:sta
M_EXTERNDEF
main proc far
mov ax, DATA
mov ds, ax
...
switchPmode:
; must run from DOS not WINDOWS!!!
;
; create PTR TO GDT
; create GDT and fill up.
; load GDT
; disable all INT-s
; switch to pmode
; fetch data
; enable all INT-s back
; display fetched data.
; Check if already in protected mode
mov eax, cr0
test al, 01h
jz pmodeTestDone
M_PRINTF "\nSystem is already in protected mode"
jmp exit
pmodeTestDone:
M_PRINTF "\nSwitching to protecte mode"
; disable interrupts
cli
; DS=0
sub ax, ax
mov ds, ax
lgdt [gdtPtr]
mov eax, cr0
or al, 01h
mov cr0, eax
jmp $+2
; DS = set segment descriptor entry 1 in GDT
mov bx, 08h
mov ds, bx
; grab memory from ext.memory
; ...
; exit protected mode
mov eax, cr0
and eax, 0fffffffeh
mov cr0, eax
; enable back interrupts
sti
exit:
mov ax, 4c00h
int 21h
main endp
; input
; DS:BP - pointer to string ($) terminated.
code ends
end main
i don't think lgdt supports direct addressing - i believe it has to be immediate
... or register indirect
if you don't declare the table as type FWORD, use FWORD PTR
immediate
lgdt fword ptr tablex
register indirect - in this case, you must use FWORD PTR
mov ebx,offset tablex
lgdt fword ptr [ebx]
ok thanks a lot. have to put that stupid .386 in another inc file to work it all. Got hint from another google page " where it says .386 .286 etc.," must be placed in include file before the file that contains lgdt instruction. Anyways moving on. !!
Quote from: ggmasm32 on November 02, 2015, 03:50:51 PMI am using the more elaborate old way of declaring the segments. I am wondering if that is the cause:
You are not obliged to do it the modern way, assembler is a tolerant language 8)
However, it looks clearer IMHO when using a structure:
GDT STRUCT
limitStorage dw ?
baseStorage dd ?
GDT ENDS
.data?
mygdt GDT <?>
.code
.686p
lgdt mygdtAssembles fine as 16-bit code. Anyway, keep trying :t
yeah just for "historical" reasons, I need to do it the old fashioned way :)
it is just how i did it when I was doing asm dev job. since then i moved on and did something else. :)
Even more historical would be accessing part of CR0 register with SMSW and LMSW instructions. The old 286 style. ;) Obviously on 386+ direct access to CR0 is preferred method.
Out of curiosity: why are you using .486 and .686p keyword one after another? I haven't used MASM for years so maybe there is a good reason for it?
I aint going back to 286 :). That belongs to generation before I reached adolescence.
For the 486 ad 686p i am just there to keep what works. May be I will clean up afterward.
.686p is enough - you can delete the .486
each time you name a new processor, the old setting is tossed out, with the exception of .87, .287, etc
Quote from: dedndave on November 10, 2015, 11:42:56 AM
.686p is enough - you can delete the .486
each time you name a new processor, the old setting is tossed out, with the exception of .87, .287, etc
That was my assumption but I wasn't sure. As for 286 protected mode related instruction there is one reason to still use them on 386+: SMSW is not privilege instruction hence it can be used to detect if DOS is running in real or protected/v86 mode without causing an exception. I guess there are very few people who remember protected mode programming on 286. It was so brain damaged. Probably finding a code example for 286 PM would be a challenge by itself today.
it wasn't that long ago - lol
you would set up the boot vector, then cause a triple-fault (something like that) to get back to real mode
very slow
meant to put it here:
my next step would be going to pmode with interrupts enabled. That translates to creating IDT from scratch. I presume this is going to be monumental task to translate every vector into IDT (at least that I think will be needed).
I have attempted few times in the past and given up with lack of resource, material. I looked into linux kernel source code that seemed to do this briefly.
Once I get over this, this would be a tremendous boost to my main pet project: minix kernel design.
I am so unsure about whether I can successfully create IDT and go in and out of pmode without hanging the system, I am even considering if someone can implement this for me for some moderate amount of bounty :).
Hi,
You could look in the source code for LILO and GRUB
and see if there is anything that helps.
Regards,
Steve N.
The usual way for a simple IDT is
- int 00 through 1F are for CPU exceptions etc
- int 20 through 2F (really, any two blocks of 8 ) are re-mapped IRQs
- unused ints all point to the same gate which is just an iret
You can then use an int for your own code, just replace the default gate with a custom one (like linux's int 80)
The FASM board OS Construction (http://board.flatassembler.net/forum.php?f=11) has lots and lots of examples.
thanks i do remember long time ago, if i repeated print out the vector through 0x00-3xff address, some of the mere constantly changing. I could not explain it at that time. Then the logical question arises: if particular IVT is changing a value to different then how do i know which one to use when translating. How do I know whether it is correct one. etc.,
i suggest you read info that is posted on osdev.org
http://forum.osdev.org/ (http://forum.osdev.org/)
beware - they are not very friendly over there
they assume you are an expert
before asking any questions, read everything in the world (i guess they have)
but - a good place to browse and get code snippets
ok i will thanks., i know people who know too much get cranky at times. I sometimes do it too.