LGDT
LGDT
Does LGDT always depends on DS pointing to the right segment where the GDT table resides?
After setting the GDT with DS = 0x1000, the following code won't print anything
mov bx, 0x0f01
mov eax, 0x0b8000
mov word [ds:eax], bx
But using int 0x10, ah = 0x0e works perfectly.
Any ideas what else I can do?
After setting the GDT with DS = 0x1000, the following code won't print anything
mov bx, 0x0f01
mov eax, 0x0b8000
mov word [ds:eax], bx
But using int 0x10, ah = 0x0e works perfectly.
Any ideas what else I can do?
Re:LGDT
Hi,
A quick checklist:
If "mov dword [0x000B8000],0x0F01" doesn't work, then you've either messed up one of those steps, your DS segment base isn't 0x00000000 or your video card isn't in text mode (or there's some other problem).
The LGDT instruction is effected by segment override prefixes, and is sensitive to the address size and operand size. For example, if 16 bit operands are being used it'll load the GDT base with a "base AND 0x00FFFFFF", which means the GDT base must be below 16 MB unless an operand size override prefix is used in real mode.
Cheers,
Brendan
A quick checklist:
- - enable A20 (optional I guess)
- create a GDT and pointer to this GDT
- do LGDT
- enable protected mode
- load segment registers with descriptors from the GDT
If "mov dword [0x000B8000],0x0F01" doesn't work, then you've either messed up one of those steps, your DS segment base isn't 0x00000000 or your video card isn't in text mode (or there's some other problem).
The LGDT instruction is effected by segment override prefixes, and is sensitive to the address size and operand size. For example, if 16 bit operands are being used it'll load the GDT base with a "base AND 0x00FFFFFF", which means the GDT base must be below 16 MB unless an operand size override prefix is used in real mode.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:LGDT
Hi,
Ok - the last two examples won't work in real mode (you'd get a general protection exception due to GS segment limit) and they're a little tricky...
Cheers,
Brendan
No - consider these examples (all for real mode/unreal mode, in NASM):Alex Buell wrote:'Does DS has to be zero before doing all that? I'm doing unreal mode.
Code: Select all
cs lgdt [myGDT'] ;DS segment not used in any way
Code: Select all
fs lgdt [myGDT'] ;DS segment not used in any way
Code: Select all
mov ax,0x1234
mov ds,ax
lgdt [myGDT'] ;DS segment used with base=0x00012340
Code: Select all
mov ax,0x8000
mov gs,ax
o32 lgdt [dword gs:0xFFF80000] ;GDTR loaded from 0x00000000
Code: Select all
mov ax,0x2000
mov gs,ax
lgdt [dword gs:0xFFF80000] ;GDTR loaded from 0x00FA0000
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:LGDT
Ah! I'm loading the GDT table perfectly - it's writing to the graphic memory at 0x000b8000 that's not working correctly. If I zero out gs and use that as the segment selector, writes to gs:0x000b8000 works. But if I use ds, then I don't see anything at that location; presumably it must be writing elsewhere in memory if that's the case. I wonder if it's actually using DS=0x1000 *and* the segment selector? I'm definitely doing the following when in PM:
mov bx, DATA_SELECTOR
mov ds, bx ; (mov gs, bx)
mov bx, DATA_SELECTOR
mov ds, bx ; (mov gs, bx)
Re:LGDT
Uses ds not gs. We know using gs works perfectly.
[/code]
Code: Select all
[BITS 16]
org 0
; At this point we're loaded into segment 0x1000
start:
call enableA20 ; enable the A20 gate
; debugging
mov ax, 0xb800
mov gs, ax
mov byte [gs:0], '1'
; switch to unreal mode
cli
push ds ; ds = 0x1000 (set in boot sector before jumping here)
xor eax, eax
mov ax, ds
shl eax, 4
add eax, gdt
mov [gdt_info + 2], eax
lgdt [gdt_info]
mov byte [gs:2], '2'
mov eax, cr0
inc ax
mov cr0, eax ; flip into protected mode
mov byte [gs:4], '3'
mov bx, DATA_SELECTOR ; select first descriptor
mov ds, bx
mov byte [gs:6], '4'
dec ax
mov cr0, eax ; flip back to real mode
mov byte [gs:8], '5'
; we're now in unreal mode
pop ds
sti
call showProgress
mov bx, 0x0f01
mov eax, 0x000b8000 ; 32bit!
mov word [dword ds:eax], bx
mov word [dword ds:eax + 2], bx
mov word [dword ds:0x000b8010], 0x0e01
mov byte [gs:10], '6'
call showProgress
.loop:
hlt
jmp .loop
showProgress:
mov ah, 0x0e
mov al, '*'
int 0x10
retn
enableA20:
; omitted for brevity
gdt:
dw 0 ; First GDT entry is always NULL
dw 0
db 0
db 0
db 0
db 0
DATA_SELECTOR equ $ - gdt
dw 0xffff ; Second GDT entry; DATA
dw 0
db 0
db 0x92
db 0xcf
db 0
gdt_end:
gdt_info:
dw gdt_end - gdt - 1 ; last byte in table
dd 0 ; beginning of table
times 512 - ($ - $$) db 0
Re:LGDT
To move into protected mode you need to do a far jump to reload CS. Probably the same going back to real mode.
You should also have 1 segment for code and 1 for data, not 1 for both. Maybe accesses to the code segment work through gs but not ds.
Solve these 2 and you'll be getting somewhere. Real-PM transitions (and back) are a pain and if you can possibly avoid them (by using a bootloader like GRUB) then do so. If you can't avoid them, the best advice I can give is to look at working code.
Here's one of mine from a couple of years ago:
continued...
You should also have 1 segment for code and 1 for data, not 1 for both. Maybe accesses to the code segment work through gs but not ds.
Solve these 2 and you'll be getting somewhere. Real-PM transitions (and back) are a pain and if you can possibly avoid them (by using a bootloader like GRUB) then do so. If you can't avoid them, the best advice I can give is to look at working code.
Here's one of mine from a couple of years ago:
Code: Select all
; Setup code taken from GeekOS, modified for COS by
; Paul Barker ([email protected]).
; Original file Copyright (c) 2001, David H. Hovemeyer <[email protected]>
; $Revision: 1.16 $
; This is free software. You are permitted to use,
; redistribute, and modify it as specified in the file "COPYING-GEEKOS".
; A lot of this code is adapted from Kernel Toolkit 0.2
; and Linux version 2.2.x, so the following copyrights apply:
; Copyright (C) 1991, 1992 Linus Torvalds
; modified by Drew Eckhardt
; modified by Bruce Evans (bde)
; adapted for Kernel Toolkit by Luigi Sgro
Code: Select all
; Block interrupts, since we can't meaningfully handle them yet
; and we no longer need BIOS services.
cli
; Set up IDT and GDT registers
lidt [IDT_Pointer]
lgdt [GDT_Pointer]
; Initialize the interrupt controllers, and enable the
; A20 address line
call Init_PIC
call Enable_A20
; Switch to protected mode!
mov ax, 0x01
lmsw ax
; Jump to 32 bit code.
; NASM probably has a way to express this using
; instruction mnemonics, but I don't know how, so I
; just copied this stuff from Linux/KTK :-)
db 0x66 ; operand size override prefix
db 0xea ; jmp opcode
dd (SETUPSEG<<4) + setup_32 ; want to jump here
dw KERNEL_CS ; ...in the kernel code segment
[BITS 32]
setup_32:
; set up data segment registers
mov ax, KERNEL_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Create the stack for the initial kernel thread, just below the kernel
mov esp, (0xFFF0)
Re:LGDT
Code: Select all
; ----------------------------------------------------------------------
; The GDT. Creates flat 32-bit address space for the kernel
; code, data, and stack. Note that this GDT is just used
; to create an environment where we can start running 32 bit
; code. The kernel will create and manage its own GDT.
; ----------------------------------------------------------------------
GDT:
; Descriptor 0 is not used
dw 0
dw 0
dw 0
dw 0
; Descriptor 1: kernel code segment
dw 0xFFFF ; bytes 0 and 1 of segment size
dw 0x0000 ; bytes 0 and 1 of segment base address
db 0x00 ; byte 2 of segment base address
db 0x9A ; present, DPL=0, non-system, code, non-conforming,
; readable, not accessed
db 0xCF ; granularity=page, 32 bit code, upper nibble of size
db 0x00 ; byte 3 of segment base address
; Descriptor 2: kernel data and stack segment
; NOTE: what Intel calls an "expand-up" segment
; actually means that the stack will grow DOWN,
; towards lower memory. So, we can use this descriptor
; for both data and stack references.
dw 0xFFFF ; bytes 0 and 1 of segment size
dw 0x0000 ; bytes 0 and 1 of segment base address
db 0x00 ; byte 2 of segment base address
db 0x92 ; present, DPL=0, non-system, data, expand-up,
; writable, not accessed
db 0xCF ; granularity=page, big, upper nibble of size
db 0x00 ; byte 3 of segment base address
Hope you can make some sense out of all that.Copyright (c) 2001, David H. Hovemeyer <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Re:LGDT
Hi,
Your problem is that you set DS to a flat segment in protected mode (base=0, limit=4GB), and then pop the old value off the stack in real mode which sets it's base back to 0x00010000 (and doesn't effect it's limit).
Because of this your "mov word [dword ds:0x000b8010], 0x0e01" is actually being written to 0x000C8010.
There was a few other things...
Cheers,
Brendan
Your problem is that you set DS to a flat segment in protected mode (base=0, limit=4GB), and then pop the old value off the stack in real mode which sets it's base back to 0x00010000 (and doesn't effect it's limit).
Because of this your "mov word [dword ds:0x000b8010], 0x0e01" is actually being written to 0x000C8010.
There was a few other things...
Code: Select all
[BITS 16]
org 0
; At this point we're loaded into segment 0x1000
%define BOOT_ADDRESS 0x00010000
start:
call enableA20 ; enable the A20 gate
; debugging
mov ax, 0xb800
mov gs, ax
mov byte [gs:0], '1'
; switch to unreal mode
cli
;Delete-> push ds ; ds = 0x1000 (set in boot sector before jumping here)
lgdt [gdt_info]
mov byte [gs:2], '2'
mov eax, cr0
inc ax
mov cr0, eax ; flip into protected mode
jmp .flush ;**** Needed for some CPUs ****
.flush:
mov byte [gs:4], '3'
mov bx, DATA_SELECTOR ; select first descriptor
mov ds, bx
mov byte [gs:6], '4'
dec ax
mov cr0, eax ; flip back to real mode
mov byte [gs:8], '5'
; we're now in unreal mode
;Delete-> pop ds
sti
call showProgress
mov bx, 0x0f01
mov eax, 0x000b8000 ; 32bit!
mov word [dword ds:eax], bx
mov word [dword ds:eax + 2], bx
mov word [dword ds:0x000b8010], 0x0e01
;<-SNIPPED->
gdt_info:
dw gdt_end - gdt - 1 ; GDT limit
dd gdt + BOOT_ADDRESS ; **** CHANGED **** (GDT address)
times 512 - ($ - $$) db 0
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:LGDT
Hi,
Cheers,
Brendan
None of that is necessary for initializing "unreal mode"...paulbarker wrote: To move into protected mode you need to do a far jump to reload CS. Probably the same going back to real mode.
You should also have 1 segment for code and 1 for data, not 1 for both. Maybe accesses to the code segment work through gs but not ds.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:LGDT
Ah! With the little changes you outlined, the program now work; and I can see the output on the display.Brendan wrote: Your problem is that you set DS to a flat segment in protected mode (base=0, limit=4GB), and then pop the old value off the stack in real mode which sets it's base back to 0x00010000 (and doesn't effect it's limit).
Because of this your "mov word [dword ds:0x000b8010], 0x0e01" is actually being written to 0x000C8010.
Thank you, that's excellent!
Now if I could figure out why the 32 bit writes puts the characters near the top right instead of the top left on the screen... Everything else works as expected.