Hi,
tsdnz wrote:
Hi all, how does this look for inline syntax and setting up caching?
Code:
asm volatile (
// Enable SSE
// Set Operating System Support for FXSAVE and FXSTOR instructions (Bit 9)
// Set Operating System Support for Unmasked SIMD Floating-Point Exceptions (Bit 10)
"mov %%cr4, %%rax; " \
"bts $9, %%rax; " \
"bts $10, %%rax; " \
"mov %%rax, %%cr4; " \
OK, so far; but I wouldn't preserve the previous values in CR4 at all, and would reduce it down to the 2 instructions "mov $0x00000600,%%rax" and "mov %%rax, %%cr4".
Code:
// Enables MTRR's & Enables Fixed Range MTRR's, Bit 10, Bit 11, and WB—Writeback (0x6) Bits 0-7
"mov $0x000002FF, %%ecx; " \
"rdmsr; " \
"mov $0x00000C06, %%eax; " \
"wrmsr; " \
// Flush Cache
"wbinvd; " \
// Enable Cache
// Clear No Write Thru (Bit 29), Not used legacy olny.
// Clear Cache Disable (Bit 30)
"mov %%cr0, %%rax; " \
"btr $29, %%rax; " \
"btr $30, %%rax; " \
"mov %%rax, %%cr0; " \
This is mostly wrong. To change the MTTRs (which should be 100% unnecessary to begin with); you must:
- disable caches in CR0 and then flush them (wbinvd); on all CPUs (not just one)
- wait until all CPUs have done the previous step before continuing
- update the MTTRs on all CPUs, so that the MTRRs are identical on all CPUs
- wait until all CPUs have done the previous step before continuing
- enable caches in CR0
In addition; you can not assume that "default memory type = write-back" is correct. For most systems the firmware sets the default memory type to "uncached" and then uses the variable range MTTRs to change anything that shouldn't be uncached to "write-back" (or whatever else); and therefore for most systems "default memory type = write-back" is wrong (e.g. you will end up with things like memory mapped PCI devices using "write-back" and breaking because of it).
However; for some systems the firmware sets the default memory type to "write-back" and then uses the variable range MTTRs to change anything that shouldn't be write-back to "uncached" (or whatever else); and therefore for some systems "default memory type = write-back" is correct.
Essentially there are only 2 sane choices. Either you don't touch the MTTRs at all and assume the firmware did it's job properly; or you reprogram all variable range MTTRs and the default memory type at the same time. Reprogramming all variable range MTTRs correctly and efficiently (e.g. using the least number of variable range MTTRs so you've got the most free for things like video) is complicated.
Code:
// Enable Floating Point
// Set Monitor co-processor (Bit 1)
// Clear Emulation (Bit 2)
"mov %%cr0, %%rax; " \
"bts $1, %%rax; " \
"btr $2, %%rax; " \
"mov %%rax, %%cr0; " \
// Init Math Co-processor
"finit; " \
// Clobber used registers
"": : : "%rcx","%rax","cc","memory");
To be perfectly correct; you should tell the compiler that all floating point registers (and all MMX and 3DNow registers) are clobbered. This brings up another problem - what prevents the compiler from using FPU, MMX or 3DNow before this code is executed? There's only 2 ways to guarantee that doesn't happen. The first is to write the CPU initialisation code as pure assembly (not inline assembly) and use it as the kernel's entry point (where the pure assembly initialises the CPU before any C code is executed, and then passes control to the C code). The other way is to tell the compiler not to use FPU, MMX or 3DNow (but I'm not sure if that's possible to do for individual functions so you may end up never using FPU, MMX or 3DNow for anything anywhere in your entire kernel).
Note: I'd be willing to bet that you've already got some "pure assembly startup code" that (e.g.) sets up the stack.Cheers,
Brendan