Page 1 of 1

How to access data I had before switching to protected mode?

Posted: Sun May 17, 2015 8:33 am
by StillTrying
Hi again all.

So yesterday I got into protected mode for the first time, but now I'm not sure how to go about this.

Yesterday when jumping into protected mode, I was still within my 512 bootsector limit. Now I have moved the kernel code into it's own file which will be on the next sector of the disk. Thanks to a couple of you a couple of days ago I learned how to read sectors off the disk and jump to it.

In my current build, before switching to protected mode I load the second sector off the disk to 0x7E00, which should hopefully put me right next to my boot loader. But then after switching to protected mode... how do I jump to my kernel?

I will post the files I think relevant -

boot.asm - The bootsector

Code: Select all

[bits 16]; We are in 16 bit Real Mode

org	0x7c00; We are loaded by BIOS at 0x7C00

start:  jmp loader; jump to start

real_mode_msg db "Testing A20, ",0;
A20_on db "A20 is enabled.",0;
A20_off db "A20 is disabled. ",0;
bios_attempt db "Calling BIOS. ",0;
disk_load db "Loading kernel off disk..",0;
disk_loaded db "kernel loaded.",0;
start_drive db 0;

kernel_offset dw 0x7E00;


;*************************************************;
;	Bootloader Entry Point
;*************************************************;

loader:
	xor	ax,ax;
	mov	ds,ax;
	mov	es,ax;
    	mov     [start_drive], dl       ; save drive number
    	cli                             ; Set up stack
    	mov     ss,ax;
    	mov     sp,0x7bff;
    	sti;
	mov 	si, real_mode_msg;
	call 	print_string;
	call 	test_A20;		Test if A20 gate is on
	cmp	ax, 1;
	jne	.Failed;
	mov	si, A20_on;
	call 	print_string;
	jmp	.continue;
.Failed:
	mov	si, A20_off;
	call	print_string;
	mov	si, bios_attempt;
	call	print_string;
	call	enable_A20_bios;	The bios call works on VirtualBox
	mov 	si, real_mode_msg;
	call 	print_string;
	call 	test_A20;
	cmp	ax, 1;
	jne	.bios_failed;
	mov	si, A20_on;
	call 	print_string;
	jmp	.continue;
.bios_failed:
	mov	si, A20_off;
	call	print_string;
.continue:

	; Load the kernel off the disk to 0000:7E00h
	mov 	si, disk_load;
	call	print_string;
	xor	ax, ax;
	mov	es, ax;
	mov	bx, [kernel_offset];
	call reset_drive;
	mov	cl, 2;
	mov	al, 1;
	mov	dl, [start_drive];
	call	read_sector;
	mov 	si, disk_loaded;
	call	print_string;

	call 	switch; switch to protected mode
	jmp $

%include "real_mode\print_string.asm";
%include "real_mode\read_sector.asm";
%include "real_mode\test_A20.asm";
%include "real_mode\gdt.asm";

; we get here after the switch to PM mode
pmode:
``	; Now I need to jump to my kernel
	cli;
	hlt;
	jmp $;

times 510 - ($-$$) db 0			; We have to be 512 bytes. Clear the rest of the bytes with 0

dw 0xAA55				; Boot Signature

gdt.asm - The table and few macros ( TBH NOT FULLY UNDERSTOOD, I've been reading material but it's not soaking in )

Code: Select all

; GDT Table
gdt_start :

gdt_null: 	; the mandatory null descriptor
	dd 0x0 	; 'dd ' means define double word ( i.e. 4 bytes )
	dd 0x0

gdt_code : 	; the code segment descriptor
	; base =0x0 , limit =0 xfffff ,
	; 1st flags : ( present )1 ( privilege )00 ( descriptor type )1 -> 1001 b
	; type flags : ( code )1 ( conforming )0 ( readable )1 ( accessed )0 -> 1010 b
	; 2nd flags : ( granularity )1 (32 - bit default )1 (64 - bit seg )0 ( AVL )0 -> 1100 b
	
	dw 0xffff 	; Limit ( bits 0 -15)
	dw 0x0 		; Base ( bits 0 -15)
	db 0x0 		; Base ( bits 16 -23)
	db 10011010b 	; 1st flags , type flags
	db 11001111b 	; 2nd flags , Limit ( bits 16 -19)
	db 0x0 	; Base ( bits 24 -31)

gdt_data : 	; the data segment descriptor
	; Same as code segment except for the type flags :
	; type flags : ( code )0 ( expand down )0 ( writable )1 ( accessed )0 -> 0010 b
	dw 0xffff 	; Limit ( bits 0 -15)
	dw 0x0 		; Base ( bits 0 -15)
	db 0x0 		; Base ( bits 16 -23)
	db 10010010b 	; 1st flags , type flags
	db 11001111b 	; 2nd flags , Limit ( bits 16 -19)
	db 0x0 		; Base ( bits 24 -31)

gdt_end : 	; The reason for putting a label at the end of the
		; GDT is so we can have the assembler calculate
		; the size of the GDT for the GDT decriptor ( below )

; GDT descriptior
gdt_descriptor :
	dw gdt_end - gdt_start - 1 	; Size of our GDT , always less one
	dd gdt_start			; of the true size
	 			

; Define some handy constants for the GDT segment descriptor offsets , which
; are what segment registers must contain when in protected mode. For example ,
; when we set DS = 0 x10 in PM , the CPU knows that we mean it to use the
; segment described at offset 0 x10 ( i.e. 16 bytes ) in our GDT , which in our
; case is the DATA segment (0 x0 -> NULL ; 0x08 -> CODE ; 0 x10 -> DATA )
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start


[bits 16]

switch:
	cli;
	lgdt [gdt_descriptor] 	; Load our global descriptor table , which defines
	sti			; the protected mode segments ( e.g. for code and data )
	mov eax , cr0 		; To make the switch to protected mode , we set
	or eax , 0x1 		; the first bit of CR0 , a control register
	mov cr0 , eax

	jmp CODE_SEG:init_pm 	; Make a far jump ( i.e. to a new segment ) to our 32- bit
				; code. This also forces the CPU to flush its cache of
				; pre - fetched and real - mode decoded instructions , which can
				; cause problems.
bits 32
; Initialise registers and the stack once in PM.
init_pm:
	mov ax , DATA_SEG 	; Now in PM , our old segments are meaningless ,
	mov ds , ax 		; so we point our segment registers to the
	mov ss , ax 		; data selector we defined in our GDT
	mov es , ax
	mov fs , ax
	mov gs , ax
	mov ebp , 0x90000 	; Update our stack position so it is right
	mov esp , ebp 		; at the top of the free space.
	call pmode 		; Finally , call some well - known label

Hope someone could give me some insight, sorry to be a bother if it's a silly question.

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 8:43 am
by Roman
Since you load your kernel at real mode address 0:0x7E00, the physical address is 0x7E00. You can just jump to 0x7E00, if I haven't missed anything.

Some other problems:
1) Why do you leave dots and commas after each line? It's not necessary, if you use YASM/NASM.
2) Are you sure you want to have your switch routine separated and be called?
3) Leave interrupts turned off since you enter protected 32-bit mode until you setup your own IDT.

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 8:51 am
by StillTrying
Roman wrote:Since you load your kernel at real mode address 0:0x7E00, the physical address is 0x7E00. You can just jump to 0x7E00, if I haven't missed anything.

Some other problems:
1) Why do you leave dots and commas after each line? It's not necessary, if you use YASM/NASM.
2) Are you sure you want to have your switch routine separated and be called?
3) Leave interrupts turned off until you setup your own IDT.

Thanks for you reply, Roman.

So I can just directly jump? I thought that would have defeated the purose of protected mode, but I don't have a full understanding of what it is.

I leave trailing semi-colons because I find the lines a little easier to read, and I can write comments next to lines when I need to.

Yes, I know about the interrupts, I wondered why it kept triple faulting :)


EDIT - Jumping to 0x7E00 also causes a triple fault.

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 8:58 am
by Roman
So I can just directly jump? I thought that would have defeated the purose of protected mode, but I don't have a full understanding of what it is.
I see a flat setup here, this way you only have more memory and 32-but registers as benefits, I think.

Have tried it in Bochs? It should tell you about the reason.
EDIT: Place some stub code in the second sector, something like this:

Code: Select all

mov eax, 0xDEADBEEF
cli
hlt
And check the EAX register in QEMU/Bochs debugger. For example, in QEMU: info registers (also use the -monitor stdio flag when launching QEMU).

You should also check, if the sector is at the right place with, for example, pmemsave QEMU command.

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 9:33 am
by StillTrying
I tried using BOCHS before, but my attempts at getting it to work failed.

Is this log output of any use?
00:00:10.302484 --------------------------------------------------------------------------------
00:00:10.302493 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00:00:10.302551 emR3Debug: rc=VINF_EM_TRIPLE_FAULT
00:00:11.308493 Changing the VM state from 'RUNNING' to 'GURU_MEDITATION'.
00:00:13.589521 Console::powerDown(): A request to power off the VM has been issued (mMachineState=Stopping, InUninit=0)
00:00:13.590174 Changing the VM state from 'GURU_MEDITATION' to 'POWERING_OFF'.
00:00:13.590183 ****************** Guest state at power off ******************
00:00:13.590187 Guest CPUM (VCPU 0) state:
00:00:13.590190 eax=00000a20 ebx=00007e00 ecx=00000000 edx=00000000 esi=00007c6a edi=000d8fa0
00:00:13.590193 eip=00007ebf esp=0008ffd8 ebp=00090000 iopl=0 nv up ei pl zr na po nc
00:00:13.590196 cs={0008 base=0000000000000000 limit=ffffffff flags=0000c09b} dr0=00000000 dr1=00000000
00:00:13.590200 ds={0008 base=0000000000000000 limit=ffffffff flags=0000c09b} dr2=00000000 dr3=00000000
00:00:13.590203 es={0010 base=0000000000000000 limit=ffffffff flags=0000c093} dr4=00000000 dr5=00000000
00:00:13.590205 fs={0010 base=0000000000000000 limit=ffffffff flags=0000c093} dr6=ffff0ff0 dr7=00000400
00:00:13.590208 gs={0010 base=0000000000000000 limit=ffffffff flags=0000c093} cr0=00000011 cr2=00000000
00:00:13.590210 ss={0010 base=0000000000000000 limit=ffffffff flags=0000c093} cr3=00000000 cr4=00000000
00:00:13.590212 gdtr=0000000000007d58:0017 idtr=0000000000000000:ffff eflags=00000206
00:00:13.590214 ldtr={0000 base=00000000 limit=0000ffff flags=00000082}
00:00:13.590215 tr ={0000 base=00000000 limit=0000ffff flags=0000008b}
00:00:13.590217 SysEnter={cs=0000 eip=00000000 esp=00000000}
00:00:13.590219 FCW=037f FSW=0000 FTW=0000 FOP=0000 MXCSR=00001f80 MXCSR_MASK=0000ffff
00:00:13.590221 FPUIP=00000000 CS=0000 Rsrvd1=0000 FPUDP=00000000 DS=0000 Rsvrd2=0000
00:00:13.590223 ST(0)=FPR0={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:13.590226 ST(1)=FPR1={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:13.590228 ST(2)=FPR2={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:13.590231 ST(3)=FPR3={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:13.590233 ST(4)=FPR4={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:13.590235 ST(5)=FPR5={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:13.590237 ST(6)=FPR6={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:13.590239 ST(7)=FPR7={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:13.590242 XMM0 =00000000'00000000'00000000'00000000 XMM1 =00000000'00000000'00000000'00000000
00:00:13.590245 XMM2 =00000000'00000000'00000000'00000000 XMM3 =00000000'00000000'00000000'00000000
00:00:13.590247 XMM4 =00000000'00000000'00000000'00000000 XMM5 =00000000'00000000'00000000'00000000
00:00:13.590250 XMM6 =00000000'00000000'00000000'00000000 XMM7 =00000000'00000000'00000000'00000000
00:00:13.590253 XMM8 =00000000'00000000'00000000'00000000 XMM9 =00000000'00000000'00000000'00000000
00:00:13.590255 XMM10=00000000'00000000'00000000'00000000 XMM11=00000000'00000000'00000000'00000000
00:00:13.590258 XMM12=00000000'00000000'00000000'00000000 XMM13=00000000'00000000'00000000'00000000
00:00:13.590261 XMM14=00000000'00000000'00000000'00000000 XMM15=00000000'00000000'00000000'00000000
00:00:13.590264 EFER =0000000000000000
00:00:13.590264 PAT =0007040600070406
00:00:13.590266 STAR =0000000000000000
00:00:13.590267 CSTAR =0000000000000000
00:00:13.590268 LSTAR =0000000000000000
00:00:13.590268 SFMASK =0000000000000000
00:00:13.590269 KERNELGSBASE =0000000000000000
00:00:13.590270 ***
00:00:13.590273 Guest paging mode: Protected (changed 6 times), A20 enabled (changed 2 times)
00:00:13.590275 Shadow paging mode: Nested
00:00:13.590276 Host paging mode: PAE+G
00:00:13.590277 ***
00:00:13.590278 Active Timers (pVM=053b0000)
00:00:13.590280 pTimerR3 offNext offPrev offSched Clock Time Expire HzHint State Description
00:00:13.590285 06d46c10 00005e60 00000000 00000000 Real 15799605 15796246 0 2-ACTIVE VGA Refresh Timer
00:00:13.590290 06d4ca70 ffffffa0 ffffa1a0 00000000 Real 15799605 15796266 0 2-ACTIVE EMT Yielder
00:00:13.590295 06d4ca10 00000000 00000060 00000000 Real 15799605 15796651 0 2-ACTIVE CPU Load Timer
00:00:13.590299 06d4aab0 00000000 00000000 00000000 Virt 2569247177 2572695571 0 2-ACTIVE Audio timer
00:00:13.590304 06d39c50 00000480 00000000 00000000 VrSy 2567639812 2568600425 18 2-ACTIVE i8254 Programmable Interval Timer
00:00:13.590309 06d3a0d0 00012390 fffffb80 00000000 VrSy 2567639812 2990000000 0 2-ACTIVE MC146818 RTC/CMOS - Second
00:00:13.590313 06d4c460 00000000 fffedc70 00000000 VrSy 2567639812 599932015941 0 2-ACTIVE ACPI PM Timer
00:00:13.590319 ***
00:00:13.590322 ***
00:00:13.590324 ************** End of Guest state at power off ***************

I've been stuck on this for hours now, can't get it right.

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 9:35 am
by Roman
Don't worry, if you're stuck, it happens. It seems like it doesn't crash immediately. Could you post the code for the second sector?

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 9:37 am
by StillTrying
Certainly:

Code: Select all

;In protected mode, kernel is ready to load

[bits 32]

org 0x7E00;

jmp kernel;

%include "protected_mode\termio.asm";
protected_mode_msg db "Kernel loaded.",0;

kernel:
	push cs;
	pop ds;
	call ClrScr32;
	mov ebx, protected_mode_msg;
	call Puts32;
	cli;
	hlt;
	jmp	$;

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 10:43 am
by Roman
Are you sure, that the problem is not in your 32-bit code, which you haven't posted (termio), and is in the setup code?

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 11:12 am
by StillTrying
When the jump into protected mode was within the 512 bytes loaded by the BIOS, the termio functions worked fine. It is only when I am trying to call the kernel from the second sector, the program hangs.

Here is termio.asm

Code: Select all

bits 32
 
%define		VIDMEM	0xB8000			; video memory
%define		COLS	80			; width and height of screen
%define		LINES	25
%define		CHAR_ATTRIB 10			; character attribute (White text on black background)
 
_CurX db 0					; current x/y location
_CurY db 0
 
;**************************************************;
;	Putch32 ()
;		- Prints a character to screen
;	BL => Character to print
;**************************************************;
 
Putch32:
 
	pusha				; save registers
	mov	edi, VIDMEM		; get pointer to video memory
	;-------------------------------;
	;   Get current position	;
	;-------------------------------;
 
	xor	eax, eax		; clear eax
 
	;--------------------------------
	; Remember: currentPos = x + y * COLS! x and y are in _CurX and _CurY.
	; Because there are two bytes per character, COLS=number of characters in a line.
	; We have to multiply this by 2 to get number of bytes per line. This is the screen width,
	; so multiply screen with * _CurY to get current line
	;--------------------------------
 
	mov	ecx, COLS*2		; Mode 7 has 2 bytes per char, so its COLS*2 bytes per line
	mov	al, byte [_CurY]	; get y pos
	mul	ecx			; multiply y*COLS
	push	eax			; save eax--the multiplication

	;--------------------------------
	; Now y * screen width is in eax. Now, just add _CurX. But, again remember that _CurX is relative
	; to the current character count, not byte count. Because there are two bytes per character, we
	; have to multiply _CurX by 2 first, then add it to our screen width * y.
	;--------------------------------
 
	mov	al, byte [_CurX]	; multiply _CurX by 2 because it is 2 bytes per char
	mov	cl, 2
	mul	cl
	pop	ecx			; pop y*COLS result
	add	eax, ecx

	;-------------------------------
	; Now eax contains the offset address to draw the character at, so just add it to the base address
	; of video memory (Stored in edi)
	;-------------------------------
 
	xor	ecx, ecx
	add	edi, eax		; add it to the base address

	;-------------------------------;
	;   Watch for new line          ;
	;-------------------------------;
 
	cmp	bl, 0x0A		; is it a newline character?
	je	.Row			; yep--go to next row
 
	;-------------------------------;
	;   Print a character           ;
	;-------------------------------;
 
	mov	dl, bl			; Get character
	mov	dh, CHAR_ATTRIB		; the character attribute
	mov	word [edi], dx		; write to video display
 
	;-------------------------------;
	;   Update next position        ;
	;-------------------------------;
 
	inc	byte [_CurX]		; go to next character
	cmp	[_CurX], BYTE COLS		; are we at the end of the line?
	je	.Row			; yep-go to next row
	jmp	.done			; nope, bail out
	;-------------------------------;
	;   Go to next row              ;
	;-------------------------------;
 
.Row:
	mov	byte [_CurX], 0		; go back to col 0
	inc	byte [_CurY]		; go to next row
 
	;-------------------------------;
	;   Restore registers & return  ;
	;-------------------------------;
 
.done:
	popa				; restore registers and return
	ret;

Puts32:
 
	;-------------------------------;
	;   Store registers             ;
	;-------------------------------;
 
	pusha				; save registers
	push	ebx			; copy the string address
	pop	edi
.loop:
 
	;-------------------------------;
	;   Get character               ;
	;-------------------------------;
 
	mov	bl, byte [edi]		; get next character
	cmp	bl, 0			; is it 0 (Null terminator)?
	je	.done			; yep-bail out

	;-------------------------------;
	;   Print the character         ;
	;-------------------------------;
 
	call	Putch32			; Nope-print it out
	;-------------------------------;
	;   Go to next character        ;
	;-------------------------------;
 
.Next:
	inc	edi			; go to next character
	jmp	.loop
 
.done:
	;-------------------------------;
	;   Update hardware cursor      ;
	;-------------------------------;
 
	; Its more efficiant to update the cursor after displaying
	; the complete string because direct VGA is slow
 
	mov	bh, byte [_CurY]	; get current position
	mov	bl, byte [_CurX]
	call	MovCur			; update cursor
 
	popa				; restore registers, and return
	ret

 
MovCur:
 
	pusha				; save registers (aren't you getting tired of this comment?)
 
	;-------------------------------;
	;   Get current position        ;
	;-------------------------------;
 
	; Here, _CurX and _CurY are relitave to the current position on screen, not in memory.
	; That is, we don't need to worry about the byte alignment we do when displaying characters,
	; so just follow the forumla: location = _CurX + _CurY * COLS
 
	xor	eax, eax
	mov	ecx, COLS
	mov	al, bh			; get y pos
	mul	ecx			; multiply y*COLS
	add	al, bl			; Now add x
	mov	ebx, eax
 
	;--------------------------------------;
	;   Set low byte index to VGA register ;
	;--------------------------------------;
 
	mov	al, 0x0f		; Cursor location low byte index
	mov	dx, 0x03D4		; Write it to the CRT index register
	out	dx, al
 
	mov	al, bl			; The current location is in EBX. BL contains the low byte, BH high byte
	mov	dx, 0x03D5		; Write it to the data register
	out	dx, al			; low byte
 
	;---------------------------------------;
	;   Set high byte index to VGA register ;
	;---------------------------------------;
 
	xor	eax, eax
 
	mov	al, 0x0e		; Cursor location high byte index
	mov	dx, 0x03D4		; Write to the CRT index register
	out	dx, al
 
	mov	al, bh			; the current location is in EBX. BL contains low byte, BH high byte
	mov	dx, 0x03D5		; Write it to the data register
	out	dx, al			; high byte
 
	popa
	ret

;**************************************************;
;	ClrScr32 ()
;		- Clears screen
;**************************************************;
 
bits 32
 
ClrScr32:
 
	pusha
	cld
	mov	edi, VIDMEM
	mov	cx, 2000
	mov	ah, CHAR_ATTRIB
	mov	al, ' '	
	rep	stosw
 
	mov	byte [_CurX], 0
	mov	byte [_CurY], 0
	popa
	ret

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 11:50 am
by jnc100
The virtualbox dump gives you valuable info - particularly the EIP at the time of the crash is 0x7ebf. By decompiling your kernel and seeing what is at address 0xbf (given that it is loaded at 0x7e00) you will find the culprit instruction. Also, you have DS being a code segment, when it should be a data segment. Finally, have you confirmed that your kernel is actually loaded as expected (e.g. by looking at the bytes at 0x7e00 onwards with a debugger)?

Regards,
John.

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 12:25 pm
by StillTrying
After some tinkering and re-arranging I've got it working. Very happy.

To jump I had to have base of 0x8 as the code descriptor table is 8 bytes long. Not fully understanding it, but it works.


EDIT -

@jnc

Sorry I didn't see your post. In the tutorial, the man said making cs == ds at the start ensures you are in the right data segment?


EDIT 2 -

@jnc

I too was looking at the vm dump, as the IP had fell short I knew it had something to do with the way I was jumping. I'm not exactly sure how the 0x8:kernel_offset makes it work, I'm still trying to crack this gdt thing.

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 2:03 pm
by Octocontrabass
StillTrying wrote:In the tutorial, the man said making cs == ds at the start ensures you are in the right data segment?
That only applies to real mode, not protected mode. (And even in real mode, most tutorials do that wrong. You shouldn't use the value the BIOS put into CS.)

Re: How to access data I had before switching to protected m

Posted: Sun May 17, 2015 2:34 pm
by Roman
Do you understand the difference between real and protected mode segmentation? In protected mode the segment registers select entries from the GDT. Each entry has its own base, size and properties. What actually you don't understand as you say?

Re: How to access data I had before switching to protected m

Posted: Mon May 18, 2015 5:55 am
by Combuster

Code: Select all

push cs ;in protected mode, code selectors are always read-only.
pop ds  ;now make all of memory read-only
In the tutorial, the man said making cs == ds at the start ensures you are in the right data segment?
That only goes for real mode code, where basically the segment offset is taken from the value instead of a GDT entry. And even there, if you try push cs; pop ds; in the bootsector, you load DS with whatever the BIOS chose to use for CS, which can be anything between 0x0000 and 0x07c0

Re: How to access data I had before switching to protected m

Posted: Mon May 18, 2015 8:02 am
by SpyderTL
Before you switched to 32-bit protected mode, you set up two GDT entries:

0x08 for code and 0x10 for data (I'm assuming)

If so, you always want CS to be set to 0x08 and all of the others (DS, ES, etc.) set to 0x10.