News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

enter protected mode but lgdr instruction not accepted

Started by ggmasm32, November 01, 2015, 09:01:17 PM

Previous topic - Next topic

ggmasm32

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.,


ggmasm32

you used only two words to reply, but it solved my problem  :lol: :t :greensml:

dedndave


ggmasm32

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??

jj2007

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

dedndave

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

ggmasm32

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








dedndave

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]


ggmasm32

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. !!

jj2007

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 mygdt


Assembles fine as 16-bit code. Anyway, keep trying :t

ggmasm32

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. :)

ACP

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?

ASM beyond Repair https://corexor.wordpress.com blog about assembly related stuff

ggmasm32

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.

dedndave

.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