Strange memory segment behavior

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.
Post Reply
LIC
Member
Member
Posts: 44
Joined: Mon Jun 04, 2018 8:10 am
Libera.chat IRC: lic

Strange memory segment behavior

Post by LIC »

Hello,
I am currently trying to develop a small OS with the help of a tutorial but I ran into something that looks strange and that I don't understand. This is related with memory segments.

This is how my Global Descriptor Table is setup:

Code: Select all

void init_gdt() {

	gdt_ptr.base = (u32)&gdt_entries;
	gdt_ptr.limit = sizeof(gdt_entry_t) * GDT_SIZE - 1;

	gdt_entries[0] = create_gdt_entry(0, 0, 0, 0); // 0x00

	gdt_entries[1] = create_gdt_entry(0, 0xffffffff, 0x98, 0xc0); // code segment 0x08
	gdt_entries[2] = create_gdt_entry(0, 0xffffffff, 0x92, 0xc0); // data segment 0x10
	gdt_entries[3] = create_gdt_entry(0x00, 0x00, 0x96, 0xc0);	// kernel stack 0x18

	gdt_entries[4] = create_gdt_entry(0x30000, 0x0, 0xf8, 0xc0); // user code segment 0x20 / 0x23
	gdt_entries[5] = create_gdt_entry(0x30000, 0x0, 0xf2, 0xc0); // user data segment 0x28 / 0x2B
	gdt_entries[6] = create_gdt_entry(0x00, 0x20, 0xf6, 0xc0); // user stack 0x30 / 0x33

	load_gdt((u32)&gdt_ptr);

	print_ok();
	print("New GDT loaded\n");

}

gdt_entry_t create_gdt_entry(const u32 base, const u32 limit, const u8 access, const u8 gran) {

	return (gdt_entry_t) {

		.base_low 		= (base & 0xffff),
		.base_middle 	= (base >> 16) & 0xff,
		.base_high 		= (base >> 24) & 0xff,

		.limit_low 		= limit & 0xffff,
		.granularity 	= (gran & 0xf0) | ((limit >> 16) & 0x0f),

		.access 		= access

	};

}

Code: Select all


[bits 32]
[GLOBAL load_gdt]

load_gdt:
	mov eax, [esp + 4] 	; get pointer passed by stack
	lgdt [eax]			; load the gdt pointer

	mov ax, 0x10		; offset in gdt for data segment
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax

	mov ax, 0x18		; ...
	mov ss, ax

	jmp 0x08:flush		; load code segment (0x08 is offset to code segment)

flush:
	ret
The user code and data segment (0x20 and 0x28) are supposed to start at memory address 0x30000 and end 4kiB further which is address 0x31000.
I am therefore not supposed to be able to access memory above 0x31000 in my user code, but here is my user code:

Code: Select all

void task() {

	char *vid = (char *)0x88000; // 0xb8000 - 0x30000
	*vid = 'f';

	while(1);

}
What I found strange and don't understand is that I don't get any error by executing this code and that it actually writes an 'f' in the top left corner of the screen. How is this possible since I am not supposed to be able to access memory above 0x31000?
I would be pleased if anyone had an answer.
Regards
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Strange memory segment behavior

Post by iansjack »

Are you sure that you are in user mode? Without seeing your full code (link to an online repository, please, don't post all code here) we can't see how you have entered user mode and be sure that CS and DS have the appropriate values.

You can, of course, test these things for yourself. Run under a debugger with a breakpoint at the start of your user function and check all the appropriate register and memory values.
LIC
Member
Member
Posts: 44
Joined: Mon Jun 04, 2018 8:10 am
Libera.chat IRC: lic

Re: Strange memory segment behavior

Post by LIC »

Thank you for your reply and sorry for posting all the code here.

Here is a link to a repository with all the code: https://github.com/leonard-limon/osdev/

I am quite sure that I am in user mode and that CS and DS have the correct values but I will indeed check theses things with a debugger.
MichaelPetch
Member
Member
Posts: 799
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Strange memory segment behavior

Post by MichaelPetch »

My best guess is that whatever environment you are running in is likely emulated and to speed things up they dropped the segment limit check. If you are using QEMU try using the -enable-kvm option and see what happens. The QEMU documentation says this:
The x86 segment limits and access rights are not tested at every memory access (yet). Hopefully, very few OSes seem to rely on that for normal use.
LIC
Member
Member
Posts: 44
Joined: Mon Jun 04, 2018 8:10 am
Libera.chat IRC: lic

[Solved] Re: Strange memory segment behavior

Post by LIC »

Ok, it looks that the emulator is what's causing this strange behavior.
Thanks for your reply
Post Reply