Page 1 of 1

Invlpg operand errors.

Posted: Tue Jan 10, 2012 11:19 pm
by TylerH
I can't get GCC (or, more correctly, GAS) to take my inline invlpg. When I cast the address (which I store as a uintptr_t) to a void* and try to dereference it, I get "‘void*’ is not a pointer-to-object type." When I cast to it anything else (char, short, int, long long), I get "operand size mismatch for `invlpg.'"

Is this a GCC/GAS bug, or am I doing something wrong?

Code: Select all

void page_table::map(uintptr_t virtual_address, uintptr_t physical_address, ptrdiff_t size, bool user, bool writable)
{
	for(ptrdiff_t i = 0;i + PGSIZE <= size;i += PGSIZE)
	{
		auto &pte = _page_table[PTX(virtual_address + i)];
		pte.set_page(physical_address + i);
		pte.set_present(true);
		pte.user(user);
		pte.writable(writable);
		
		asm volatile("invlpg %0" :: "m"(*((type*)virtual_address + i)));
	}
}
What should "type" be?

Re: Invlpg operand errors.

Posted: Wed Jan 11, 2012 4:47 pm
by TylerH
Wouldn't that result in the page containing virtual_address being flushed from the TLB, not the page it points to? There's a warning about that specific problem here: http://wiki.osdev.org/Inline_Assembly/E ... PGFLUSHTLB.

Re: Invlpg operand errors.

Posted: Thu Jan 12, 2012 3:50 pm
by TylerH
Even reinterpret_cast doesn't work for me. I get the same error as trying to C-style cast it to char*, "Assembler messages: Error: operand size mismatch for `invlpg.'"

I compiled the code above to assembly (with -masm=intel) and the code in question is output as: "invlpg BYTE PTR [eax]."

gcc -v

Code: Select all

$i686-elf-gcc -v
Using built-in specs.
COLLECT_GCC=i686-elf-gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/i686-elf/4.6.2/lto-wrapper
Target: i686-elf
Configured with: ../gcc-4.6.2/configure --prefix=/usr/local/ --target=i686-elf --enable-languages=c,c++ --with-newlib --enable-lto
Thread model: single
gcc version 4.6.2 (GCC)

Re: Invlpg operand errors.

Posted: Thu Jan 12, 2012 3:54 pm
by TylerH
It is a bug. I had been compiling with -masm=intel all the time, so I could use intel syntax in my inline assembly. I tried compiling without -masm=intel and it worked.

Re: Invlpg operand errors.

Posted: Sun Jan 15, 2012 3:16 am
by TylerH
A workaround that allows -masm=intel to be used is to require va to be put into a general purpose register (using "r") and then dereferencing that register.

Code: Select all

int main()
{
    uintptr_t va = 0;
    int i = 1;
    asm volatile("invlpg [%0]" :: "r"(va+i));
}