[SOLVED] VBE 2: Change bank without v86 or real mode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Karlosoft
Member
Member
Posts: 277
Joined: Thu Feb 14, 2008 10:46 am
Location: Italy
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by Karlosoft »

So could I access to memory as segment:offset?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by Combuster »

Dex: that does *not* make addressing the same. it only makes the *offsets* the same. What it is meant to do is make a GDT entry which holds the same contents for the Descriptor Cache as it would have in real mode. You will still be in protected mode, and forced to stick to any of the segment register values that you did define.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by Dex »

Realmode

Code: Select all

	mov   di,VESA_Info
pmode code

Code: Select all

	mov   edi,VESA_Info
Note: the base of the CODE DATA etc is not zero based, but are the same as realmode DS, that mean anything in that segment can be addresse the same, you will need to make a zero based data too.
It also meens if you put 2mb into edi its really 2mb + what the realmode segment was at bootup, it also makes it very easy to switch between real and pmode.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by Dex »

Combuster , how can the above example of addresing in realmode and pmode not be the same ?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by Combuster »

Combuster , how can the above example of addresing in realmode and pmode not be the same ?
(snip) and forced to stick to any of the segment register values that you did define.
You can no longer put xxx in segment register yyy and expect it to work. In other words, you need some magic for accessing anything that is not your code or data. (like video memory)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by Dex »

magic as in

Code: Select all

mov ax,8h ;8h being linear Data segment
mov es,ax
Or just keeping FS linear Data segment
Thats call coding, not magic.
User avatar
Troy Martin
Member
Member
Posts: 1686
Joined: Fri Apr 18, 2008 4:40 pm
Location: Langley, Vancouver, BC, Canada
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by Troy Martin »

Dex wrote:Combuster , how can the above example of addresing in realmode and pmode not be the same ?
Have you forgotten everything about real mode segmentation?

0x1000:0000 == 0x10000, but when you do 0x1000:0000 in protected mode, the machine craps itself unless you have an appropriate selector at GDT + 0x1000. And it will still probably crap itself if you access null (I think, I'm in a good bit of mouth pain right now.)
It also meens if you put 2mb into edi its really 2mb + what the realmode segment was at bootup, it also makes it very easy to switch between real and pmode.
Wh..what? Unless you're in unreal mode, you can't access 2MB in 16-bit, and then putting 0x200000 into EDI == 2 MB, not 2MB + real mode segment. And how does that affect switching from real mode to protected mode and back? It's still the same painful procedure once you're all in the kernel and such.
Image
Image
Solar wrote:It keeps stunning me how friendly we - as a community - are towards people who start programming "their first OS" who don't even have a solid understanding of pointers, their compiler, or how a OS is structured.
I wish I could add more tex
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by Dex »

Troy Martin wrote:
Dex wrote:Combuster , how can the above example of addresing in realmode and pmode not be the same ?
Have you forgotten everything about real mode segmentation?

0x1000:0000 == 0x10000, but when you do 0x1000:0000 in protected mode, the machine craps itself unless you have an appropriate selector at GDT + 0x1000. And it will still probably crap itself if you access null (I think, I'm in a good bit of mouth pain right now.)
Are you thick ?, IF YOU SET THE BASE OF DATA DESCRIPTORS TO BE 0x1000, THEN HOW WILL IT CRAP ITSELF ?.
In other words base of the code and data descriptors to DS * 16, that is what was in DS at bootup..
Troy Martin wrote:
It also meens if you put 2mb into edi its really 2mb + what the realmode segment was at bootup, it also makes it very easy to switch between real and pmode.
Wh..what? Unless you're in unreal mode, you can't access 2MB in 16-bit, and then putting 0x200000 into EDI == 2 MB, not 2MB + real mode segment. And how does that affect switching from real mode to protected mode and back? It's still the same painful procedure once you're all in the kernel and such.
Where did i say you can break realmode coding rules ?, in the above, i am talking when your in pmode to pmode addressing.
If you do not want to listen to me, maybe you will listen to Christopher Giese

Code: Select all

								; pm1.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	pm1.asm - protected-mode demo code
;	Christopher Giese <geezer[AT]execpc.com>
;	http://www.execpc.com/~geezer/os
;
;	Release date 10/7/98. Distribute freely. ABSOLUTELY NO WARRANTY.
;	Assemble with NASM:	nasm -o pm1.com pm1.asm
;
;	Run this program in "raw" MS-DOS mode, not a Windows DOS box. Do not
;	load EMM386 or other memory managers. Do not load HIMEM.SYS (see
;	below). Clear the screen and hit Enter a few times before running it.
;
;	What you should see:
;	"012345                                           !"
;	" still in real mode!"
;	"  ES,DS still real mode!"
;	"   Finally in protected mode!"
;	"    ES,DS still protected mode!"
;	"     back to BORING old real mode"
;
;	Running the program puts a 4G limit in the segment descriptor
;	cache for ES. This makes 32-bit addresses legal in real mode,
;	when used with ES. Running the program a second time will add
;	an 'R' to the top line.
;
;	If you see the 'R' instead of the '!' the first time you run it,
;	it is because a previous protected-mode program has munged the
;	segment descriptor cache for ES. The most likely culprit is
;	HIMEM.SYS, which is loaded silently and automatically by DOS 7.
;
;	This code was tested with NASM version 0.93 and NASM version 0.97.
;	Please let me know if you have problems with other versions.
;
;	This code was tested on an Intel 486SX-based system and an Intel
;	Pentium-based system. Please let me know of possible problems with
;	other CPUs, especially the 386 or 386SX.
;
;	Though I have tried to be as clear and accurate as possible, there
;	may be errors. Constructive criticism is welcome.
;
; Demonstrates:
;	- Basic 32-bit protected mode.
;	- Linear (flat) memory.
;	- Access to text-mode video memory.
;	- Return to real mode.
;	- "Unreal" mode (flat real, big real).
;	- Effects of the segment descriptor cache.
; See other tutorials for:
;	- Interrupts/exceptions
;	- Virtual 8086 mode
;	- CPU detection (>= 386)
;	- Local Descriptor Tables (LDTs)
;	- Running code in XMS
;	- A20 gate
;	- Multitasking
;	- Task state segments (TSSes)
;	- Privilege
;	- Gates
; Sources:
;   INTEL 80386 PROGRAMMER'S REFERENCE MANUAL 1986
;	http://www.execpc.com/~geezer/os/386intel.zip
;       ftp://ftp.cdrom.com/.20/demos/code/hardware/cpu/386intel.zip
;       http://www.intercom.net/user/jeremyfo/SamOS/Files/386intel.zip
;   Robert Collins' "Intel Secrets" web site:
;       http://www.x86.org
;
[ORG 0x100]
[BITS 16]
;
;
; If you want to skip this commentary and go directly to the code,
; search for the label "start:"
;
; How to get into protected mode? First, you need a GLOBAL DESCRIPTOR
; TABLE (GDT). There is one at the end of this file, at address "gdt:"
; The GDT contains 8-byte DESCRIPTORS for each protected-mode segment.
; Each descriptor contains a 32-bit segment base address, a 20-bit segment
; limit, and 12 bits describing the segment type. The descriptors look
; like this:
;
;           MSB    bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   LSB
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 0  | bit 7<---------------- segment limit------------------->bit 0 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 1  |bit 15<---------------- segment limit------------------->bit 8 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 2  | bit 7<---------------- segment base-------------------->bit 0 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 3  |bit 15<---------------- segment base-------------------->bit 8 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 4  |bit 23<---------------- segment base-------------------->bit 16|
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 5  |   P   |      DPL      | <----------- segment type ----------> |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
; P is the Segment Present bit. It should always be 1.
;
; DPL is the DESCRIPTOR PRIVILEGE LEVEL. For simple code like this, these
; two bits should always be zeroes.
;
; Segment Type (again, for simple code like this) is hex 12 for data
; segments, hex 1A for code segments.
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 6  |   G   |   B   |   0   | avail | bit 19<-- seg limit--->bit 16 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
; G is the Limit Granularity. If zero, the segment limit is in bytes
; (0 to 1M, in 1-byte increments). If one, the segment limit is in 4K PAGES
; (0 to 4G, in 4K increments). For simple code, set this bit to 1, and
; set the segment limit to its highest value (FFFFF hex). You now have
; segments that are 4G in size! The Intel CPUs can address no more than
; 4G of memory, so this is like having no segments at all. No wonder
; protected mode is popular.
;
; B is the Big bit; also called the D (Default) bit. For code segments,
; all instructions will use 32-bit operands and addresses by default
; (BITS 32, in NASM syntax, USE32 in Microsoft syntax) if this bit is set.
; 16-bit protected mode is not very interesting, so set this bit to 1.
;
; None of these notes apply to the NULL descriptor. All of its bytes
; should be set to zero.
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 7  |bit 31<---------------- segment base------------------->bit 24 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
; Build a simple GDT with four descriptors: NULL (all zeroes), linear data
; (lets you use 32-bit addresses), code, and data/stack. (An extra
; descriptor or two is needed to return to real mode.) For simplicity,
; the limits of all descriptors (except NULL and the real-mode descriptors)
; are FFFFF hex, the largest possible limit.
;
; In a real-mode .COM file, CS=DS. To make addressing identical in real
; mode and protected mode, we set the base of the code and data descriptors
; to DS * 16. This number is computed at run-time; the other numbers in
; the GDT can be done at assemble-time.
;
start:	xor ebx,ebx
	mov bx,ds                       ; BX=segment
	shl ebx,4                       ; BX="linear" address of segment base
	mov eax,ebx
	mov [gdt2 + 2],ax               ; set base address of 32-bit segments
	mov [gdt3 + 2],ax
	mov [gdt4 + 2],ax               ; set base address of 16-bit segments
	mov [gdt5 + 2],ax
	shr eax,16
	mov [gdt2 + 4],al
	mov [gdt3 + 4],al
	mov [gdt4 + 4],al
	mov [gdt5 + 4],al

	mov [gdt2 + 7],ah
	mov [gdt3 + 7],ah
	mov [gdt4 + 7],ah
	mov [gdt5 + 7],ah
;
; Now we have a valid GDT. The CPU has a 48-bit register (GDTR) which must
; contain the base address of the GDT, and its limit. We will put those
; values at the address "gdtr", then load the GDTR register from that
; address. The GDT limit is a fixed value:
;       number of descriptors * 8 - 1
; This code uses 5 descriptors (null, linear, code, data, real-mode),
; so the GDT limit is 39. (If you look at the code after "gdtr:", you
; will see that it can accommodate more or fewer descriptors
; "automatically".)
;
; What about the GDT base? This won't work:
;
;       lea eax,[gdt]			; This address is relative to
;       mov [gdtr + 2],eax		; the segment base.
;
; The address of the GDT base (the address to be loaded into the GDTR
; register) is a PHYSICAL address, one that is not translated by
; segmentation. So, we do the translation ourselves, by adding the
; 32-bit segment base address that we put in EBX:
;
        lea eax,[gdt + ebx]             ; EAX=PHYSICAL address of gdt
        mov [gdtr + 2],eax
;
; That's a bit confusing, but eventually you'll get it. (I have been
; hacking at protected mode for over a year, and it STILL confuses me.)
;
; This demo code neither demonstrates nor supports interrupts.
; Shut them off. (My thanks to John Fine for pointing out that INT 0Dh
; is also IRQ 5, and his suggestion that I move the 'cli' here.)
;
	cli
;
; Before entering pmode, we will try to use 32-bit addressing while still
; in real mode. To do this, we have to take over the vector for INT 0Dh
; (the "pseudo GPF").
;
	xor ax,ax
	mov es,ax
	mov edx,[es:0x0D * 4]		; INT 0Dh vector -> EDX
	mov [es:0x0D * 4 + 2],cs
	lea ax,[trap]
	mov [es:0x0D * 4],ax
;
; Try using a 32-bit address in real mode. Depending on "where the CPU's
; been", this may or may not cause interrupt 0Dh.
;
	mov ebx,0xB809A			; ES still 0
	mov byte [es:ebx],'R'		; 'R' in upper right corner of screen
;
; Did it work? There's more info on 32-bit addressing in real mode below.
; Note: the second 'mov' above is 5 bytes long. Modify the 'trap' routine
; below if the 'mov' changes.
;
; If we want to return to real mode when we're done, we must save the
; contents of the CS register. To simplify the return to real mode,
; we also store the return-to-real-mode address, do_rm.
;
	mov ax,cs
	mov [RealModeCS],ax
	lea ax,[do_rm]
	mov [RealModeIP],ax
;
; To (literally) see this code in action, we need a way to access
; text-mode video memory. This memory is at real-mode address B800:0000
; (hex). Let's put the segment for this memory in ES:
;
	mov ax,0xB800
	mov es,ax
;
; Load the GDTR with the base address and limit of the GDT.
;
	lgdt [gdtr]
;
; Set the PE [protected mode enable] bit in register CR0 to begin the
; switch to protected mode.
;
	mov eax,cr0
	or al,1
	mov cr0,eax
;
; We are not yet in full protected mode! Section 10.3 of the INTEL
; 80386 PROGRAMMER'S REFERENCE MANUAL 1986 states:
;
;; Immediately after setting the PE flag, the initialization code must flush
;; the processor's instruction prefetch queue by executing a JMP instruction.
;; The 80386 fetches and decodes instructions and addresses before they are
;; used; however, after a change into protected mode, the prefetched
;; instruction information (which pertains to real-address mode) is no longer
;; valid. A JMP forces the processor to discard the invalid information.
;
; It isn't really necessary to do the JMP right away, as this implies.
; It simply means that protected mode doesn't "kick in" until the segment
; registers are reloaded. Above, we set the ES segment register to 0xB800.
; This is the real-mode segment of the text video memory. With the PE bit
; still set, let's copy a message from the real-mode data segment (DS) to
; the video memory (ES).
;
        lea si,[msg0]                   ; -> "still in real mode!"
        mov di,(80 * 1 + 2) * 2         ; row 1, column 2
        mov cx,38
        cld
        rep movsb
;
; The code above won't work in protected mode. It's there just to
; prove that setting the PE bit is not enough to enter protected mode.
;
; Now do a far jump. This reloads the CS register and flushes the
; real-mode instructions from the prefetch queue. CS is the segment
; register used for instruction fetches, so this is where the switch
; from 16-bit instructions (real-mode) to 32-bit instructions
; (protected-mode) takes place.
;
; But what goes into CS? In real mode, we use the segment address. In
; protected mode, we use a SELECTOR:
;
; MSB  b14  b13  b12  b11  b10   b9   b8   b7   b6   b5   b4   b3   b2   b1   LSB
;+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
;|                                index                           | L  |   RPL   |
;+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
;
; index is a 13-bit index into the GDT. It selects one of the possible 8192
; descriptors in the table. (Note: 8192 descriptors/table, 8 bytes/descriptor.
; The GDT is no larger than 64K.)
;
; If the L bit is set, this selector selects a descriptor from one of the
; LOCAL DESCRIPTOR TABLES (LDT), instead of the GDT. For simple code (like
; this code) or code that doesn't use LDTs, set this bit to 0.
;
; RPL is a 2-bit REQUESTOR PRIVILEGE LEVEL. For simple code: set these bits
; to zero.
;
; Here, we load the hex value 10 into CS. In binary, this is
; 0000 0000 0001 0000. The top thirteen bits are 0000000000010.
; This selector choses descriptor #2 in the GDT (the code segment
; descriptor).
;
	jmp SYS_CODE_SEL:do_pm          ; jumps to do_pm
;
; Real-mode interrupt 0Dh handler:
;
trap:	mov ax,0xB800
	mov fs,ax
	mov byte [fs:0x9C],'!'
	pop ax				; point stacked IP beyond...
	add ax,5			; ...the offending instruction
	push ax
	iret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       Alert! Now in 32-bit protected mode.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
[BITS 32]
do_pm:
;
; Now we are in 32-bit protected mode -- or are we? Besides CS, all of the
; segment registers still contain real-mode values. Let's try using real-
; mode addressing to put another message on the screen.
;
; Here's a potential problem: addressing is still 16-bit real-mode (oops,
; I gave it away!), but instructions are 32-bit. The rep movsb used below
; will read from DS:ESI and write to ES:EDI. We can either make sure the
; top 16 bits of ESI and EDI are zeroed, or use an 16-bit address size
; override prefix with 'rep movsb'.
;
        xor edi,edi
        xor esi,esi

	lea si,[msg1]                   ; -> "ES, DS still real mode!"
        mov di,(80 * 2 + 3) * 2         ; row 2, column 3
        mov ecx,46
        cld
        rep movsb
;
; ARRGH, it works :) Real-mode addressing hangs on.
;
; To enable full protected-mode addressing, we must put valid protected-
; mode selectors in the DS and SS registers:
;
	mov ax,SYS_DATA_SEL
	mov ds,ax
	mov ss,ax
;
; Can we now print out a message to let the world know we've made it?
;
;       mov ax,0xB800
;       mov es,ax
;       mov byte [es:0],'@'
;
; This won't work (which is why it's commented out). Remember, the
; segment registers contain selectors when in protected mode. Looking
; at the GDT, we see four descriptors (and their associated selectors):
;
;       NULL                    0
;       linear data             8       =LINEAR_SEL
;       code                    10 hex  =SYS_CODE_SEL
;       data/stack              18 hex  =SYS_DATA_SEL
;
; Use of the NULL segment/selector/descriptor is forbidden. Trying to
; access video memory via the code segment/selector/descriptor might
; work, but it is a poor programming practice, and will almost certainly
; cause problems down the road. What about SYS_DATA_SEL?
;
;       mov ax,SYS_DATA_SEL
;       mov es,ax
;       mov byte [es:0],'@'
;
; As you may have guessed, that won't work either. It writes to the lowest
; byte of the data/stack segment. Above, we set the base of the data/stack
; segment descriptor to DS * 16. Since this is a .COM file, CS=DS, and
; we end up scribbling on memory 256 bytes before the address "start".
; None of these work, either:
;
;       mov ax,SYS_DATA_SEL
;       mov es,ax
;       mov byte [es:0xB800],'@'        ; writes unknown byte at offset
;                                       ; B800 hex of data segment
;
;       mov ax,SYS_DATA_SEL
;       mov es,ax
;       mov byte [es:0xB8000],'@'       ; writes unknown byte at offset
;                                       ; B8000 hex of data segment
;
; OK, I've beaten the point to death. The answer lies in LINEAR_SEL.
; In real mode, the address of the text-mode video memory is B800:0000
; As a "flat" ("linear"), 32-bit address, this would be 000B8000.
; Because the descriptor referred to by LINEAR_SEL has a base segment
; address of zero, we can simply use the linear address 000B8000 with
; LINEAR_SEL to get at the video memory:
;
	mov ax,LINEAR_SEL
	mov es,ax
;
; Here's a useful debug tip: once you have basic pmode running, with a
; linear selector like this, you can poke single bytes into video memory
; after each questionable piece of code, to see how far the code got:
;
	; questionable PM code here
	mov byte [es:dword 0xB8000],'0'

	; more questionable PM code here
	mov byte [es:dword 0xB8002],'1'

	; still more questionable PM code here
	mov byte [es:dword 0xB8004],'2'

	; (you get the picture)
	mov byte [es:dword 0xB8006],'3'
;
; Because we've chosen the base address of the data segment so that
; addressing works the same in real mode and protected mode, we can
; refer to an address like "msg2" without grief or confusion:
;
	lea esi,[msg2]                  ; -> "Finally in protected mode!"
;
; (though we now use 32-bit registers ESI, EDI, and ECX, instead of 16-bit
; SI, DI, and CX).
;
; With LINEAR_SEL, the screen starts at address B8000 hex. We need to
; add that value to whatever address we compute for a given cursor
; location. Notes:
; - 32-bit addresses like this are ILLEGAL in real mode (but see below)
; - We could've set the base of LINEAR_SEL to B8000 hex (and possibly
;   called it VIDEO_SEL) to avoid this step. A segment with base 0,
;   however, lets us easily get at other "interesting" areas of memory
;   e.g. the ROMs.
;
	mov edi,0xB8000 + (80 * 3 + 4) * 2      ; row 3, column 4
	mov ecx,52
	cld
	rep movsb
;
; OK, enough of protected mode. Can we return to real-mode DOS without
; things crashing and burning? We'll try. Section 14.5 of the INTEL
; 80386 PROGRAMMER'S REFERENCE MANUAL 1986 states:
;
;;  2.  Transfer control to a segment that has a limit of 64K (FFFFH). This
;;      loads the CS register with the limit it needs to have in real mode.
;
; This is not enough! It implies that you could run with a 32-bit protected
; mode segment that is page-granular and has limit 16 (16 * 4K = 64K). The
; segment must also be a 16-bit segment (Default/Big bit set to zero).
; Essentially, we must switch (briefly) to 16-bit protected mode before
; going on to real mode. Fortunately, if the necessary descriptor is
; provided, that's easy to do:
;
	jmp REAL_CODE_SEL:do_16
[BITS 16]
do_16:
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       Now in 16-bit protected mode.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Going back to real mode with the data and stack segments having a limit
; of 4G (0xFFFFF and page granular) can cause problems. Referring again to
; Section 14.5 of the INTEL 80386 PROGRAMMER'S REFERENCE MANUAL 1986:
;
;;  3.  Load segment registers SS, DS, ES, FS, and GS with a selector that
;;      points to a descriptor containing the following values, which are
;;      appropriate to real mode:
;;
;;        Limit = 64K   (FFFFH)
;;        Byte granular (G = 0)
;;        Expand up     (E = 0)
;;        Writable      (W = 1)
;;        Present       (P = 1)
;;        Base = any value
;
; So, we fix that here:
;
	mov ax,REAL_DATA_SEL
	mov ss,ax
	mov ds,ax			; leave ES alone
;
; The rest of the procedure to return to real mode is somewhat like the
; the procedure to enter protected mode. Zero the PE bit in register CR0:
;
	mov eax,cr0
	and al,0xFE
	mov cr0,eax
;
; Now put the real-mode CS value back into CS. There are relatively
; few instructions that change the CS register:
;       jmp (far)       retf            iret		(probably some more)
;
; jmp (far) works:
;
	jmp far [RealModeIP]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       Back in 16-bit real mode.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 16]
;
; We've shut off the PE bit and put a real-mode value back into CS.
; Above, we saw how real-mode addressing hung on even after setting
; the PE bit and jumping to a 32-bit protected-mode code segment.
; Is the reverse true? Can we use 32-bit addressing while in real mode?
;
do_rm:	mov byte [es:dword 0xB8008],'4'
;
; It looks like we can! This is called UNREAL MODE (or "flat real",
; "big real", etc.). Among other uses, unreal mode is useful for bootloaders,
; as you can use INT 13h to load a kernel from disk to conventional memory,
; then use unreal mode to copy it to extended memory.
;
; Each segment register in the x86 CPU has an associated 8-byte descriptor
; register, also in the CPU. This is called the SEGMENT DESCRIPTOR
; CACHE. Loading a selector into a segment register while in protected
; mode reloads the entire cache entry for that segment register. Loading
; a value into a segment register in real mode sets only the base address
; of the cache entry. The segment limit and flag bits are not changed.
;
; This means that we CAN reload the segment register after returning to
; real mode, and we'll still be able to use 32-bit addresses (as long as
; a suitably high segment limit was set while in protected mode).
;
	xor ax,ax
	mov es,ax
	mov byte [es:dword 0xB800A],'5'
;
; Like protected mode in general, unreal mode is very subtle. This code
; fragment, for example, will not work:
;
	lea esi,[msg3]			; -> "ES, DS still protected mode!"
	mov edi,0xB8000 + (80 * 4 + 5) * 2      ; row 4, column 5
	mov ecx,56
	cld
	;rep movsb
;
; The 'rep movsb' is commented out, because that's where the code fails.
; Though addressing is still 32-bit, the code itself is 16-bit. This means
; that 'rep movsb' will use the 16-bit SI, DI, and CX registers. Since
; the value in EDI is at least 0xB8000, the message won't be written to
; video memory, but to some other location.
;
; This behavior is easily fixed with an address size override prefix:
;
	a32				; same as 'db 0x67'
	rep movsb
;
; Before returning to DOS, put real-mode compatible values in the
; segment registers:
;
	mov ax,cs
	mov ds,ax
	mov ss,ax
	mov ax,0xB800
	mov es,ax
;
; Home again:
;
	lea si,[msg4]                   ; -> "back to BORING old real mode"
	mov di,(80 * 5 + 6) * 2         ; row 5, column 6
	mov cx,56
	cld
	rep movsb
;
; Restore the INT 0D interrupt vector:
;
	xor ax,ax
	mov es,ax
	mov [es:0x0D * 4],edx		; EDX -> INT 0x0D vector
;
; Protected mode is no more. It is now safe to re-enable interrupts.
;
	sti
;
; Exit to DOS with errorlevel 0
;
	mov ax,0x4C00
	int 0x21
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RealModeIP:
        dw 0

RealModeCS:
	dw 0
;
; The alternating spaces are treated as attribute bytes by the video
; hardware. This makes the messages an eye-catching black on green.
;
msg0:   db "s t i l l   i n   r e a l   m o d e ! "
msg1:   db "E S ,   D S   s t i l l   r e a l   m o d e ! "
msg2:   db "F i n a l l y   i n   p r o t e c t e d   m o d e ! "
msg3:	db "E S ,   D S   s t i l l   p r o t e c t e d   m o d e ! "
msg4:   db "b a c k   t o   B O R I N G   o l d   r e a l   m o d e "

gdtr:	dw gdt_end - gdt - 1	; GDT limit
	dd gdt                  ; (GDT base gets set above)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	global descriptor table (GDT)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; null descriptor
gdt:	dw 0			; limit 15:0
	dw 0			; base 15:0
	db 0			; base 23:16
	db 0			; type
	db 0			; limit 19:16, flags
	db 0			; base 31:24

; linear data segment descriptor
LINEAR_SEL	equ	$-gdt
	dw 0xFFFF		; limit 0xFFFFF
	dw 0			; base 0
	db 0
	db 0x92			; present, ring 0, data, expand-up, writable
        db 0xCF                 ; page-granular, 32-bit
	db 0

; code segment descriptor
SYS_CODE_SEL	equ	$-gdt
gdt2:   dw 0xFFFF               ; limit 0xFFFFF
	dw 0			; (base gets set above)
	db 0
	db 0x9A			; present, ring 0, code, non-conforming, readable
        db 0xCF                 ; page-granular, 32-bit
	db 0

; data segment descriptor
SYS_DATA_SEL	equ	$-gdt
gdt3:   dw 0xFFFF               ; limit 0xFFFFF
	dw 0			; (base gets set above)
	db 0
	db 0x92			; present, ring 0, data, expand-up, writable
        db 0xCF                 ; page-granular, 32-bit
	db 0

; a code segment descriptor that is 'appropriate' for real mode
; (16-bit, byte-granular, limit=0xFFFF)
REAL_CODE_SEL	equ	$-gdt
gdt4:   dw 0xFFFF
	dw 0			; (base gets set above)
	db 0
	db 0x9A			; present, ring 0, code, non-conforming, readable
	db 0			; byte-granular, 16-bit
	db 0

; a data segment descriptor that is 'appropriate' for real mode
; (16-bit, byte-granular, limit=0xFFFF)
REAL_DATA_SEL	equ	$-gdt
gdt5:   dw 0xFFFF
	dw 0			; (base gets set above)
	db 0
	db 0x92			; present, ring 0, data, expand-up, writable
	db 0			; byte-granular, 16-bit
	db 0

gdt_end:

You have a lot to learn, but i will not help you anymore, i am leaving this forum.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by pcmattman »

Dex wrote:
Troy Martin wrote:
Dex wrote:Combuster , how can the above example of addresing in realmode and pmode not be the same ?
Have you forgotten everything about real mode segmentation?

0x1000:0000 == 0x10000, but when you do 0x1000:0000 in protected mode, the machine craps itself unless you have an appropriate selector at GDT + 0x1000. And it will still probably crap itself if you access null (I think, I'm in a good bit of mouth pain right now.)
Are you thick ?, IF YOU SET THE BASE OF DATA DESCRIPTORS TO BE 0x1000, THEN HOW WILL IT CRAP ITSELF ?.
In other words base of the code and data descriptors to DS * 16, that is what was in DS at bootup..
Uhh, he's talking about setting it in protected mode, after the GDT is set up. At which point you will have problems, and therefore you cannot use addressing in the same style you would use it in real mode (which is Combuster's point).

Code: Select all

mov ax,8h ;8h being linear Data segment
mov es,ax
That's called normal protected mode addressing. This is real real mode addressing:

Code: Select all

mov ax, 1000h
mov es, ax
mov word bx, [es:0]
You simply cannot do that in protected mode in the setup that you're proposing. It doesn't work for all inputs.
User avatar
Karlosoft
Member
Member
Posts: 277
Joined: Thu Feb 14, 2008 10:46 am
Location: Italy
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by Karlosoft »

Well... VESA Protected Functions are working :)
It makes me happy ^_^. The topic is solved
Attachments
screenshot7.png
screenshot7.png (6.89 KiB) Viewed 3011 times
tantrikwizard
Member
Member
Posts: 153
Joined: Sun Jan 07, 2007 9:40 am
Contact:

Re: VBE 2: Change bank without v86 or real mode

Post by tantrikwizard »

Karlosoft wrote:Well... VESA Protected Functions are working :)
It makes me happy ^_^. The topic is solved
Cool. I'm curious if its working on bochs yet. If you wouldnt mind giving it a try and letting me know I'd owe you a beer.
User avatar
Karlosoft
Member
Member
Posts: 277
Joined: Thu Feb 14, 2008 10:46 am
Location: Italy
Contact:

Re: [SOLVED] VBE 2: Change bank without v86 or real mode

Post by Karlosoft »

Yes the protected mode functions work on my version of bochs :)
tantrikwizard
Member
Member
Posts: 153
Joined: Sun Jan 07, 2007 9:40 am
Contact:

Re: [SOLVED] VBE 2: Change bank without v86 or real mode

Post by tantrikwizard »

Karlosoft wrote:Yes the protected mode functions work on my version of bochs :)
thats good news, i'll have to revisit it. Thanks
Post Reply