I got annoyed at using ROM as my stack (it's slow, requires bit of
an effort to get working if doable at all), only using registers
for ram init is also a bit of an effort.. So I took a look at
coreboot & how they do stuff, instantly encountering this apparently
old, but totally new for me concept of using Cache as ram.
In theory, this is as simple as it sounds, configure MTRR subsystem
and clear cache-disable & not-write through bits from cr0, then
clear cache region to use & set stack pointer to CAR base address.
In practise, this proved to be almost as simple, but I was bit too
eager to implement this, skipped parts of intel's manual regarding
Caching, and messed things up for quite a while..
The setup part was quite straightforward, there aren't _too_ many
resources, but old linuxboot docs, coreboot sourcecode + docs,
mtrr specs & overall intel system programming guide combined were
plenty enough to get this done. You might notice heavy *cough*
inspiration *cough*, aka copying of code parts from coreboot &
linuxboot.
However, exit from CAR mode wasn't easy at all.. Well in reality
it was, but I made a silly mistake, which only affected how my
disk reads worked.
Before I implemented CAR, disk read worked reliably, even though
admittedly slowly in ATA 28b pio mode. As soon as I added
Cache As Ram operations into my code, disk reads started suddenly
returning only 00 or FF bytes. Disk identification etc. still
worked correctly, as did all PCI operations, communication with
interrupt controller, etc...
This was super confusing, for the longest time I believed I had a bug
in my disk driver that is only triggered somehow with this changed
entrycode.
Then, I was reminded that oftentimes disk reads can make use of Cache,
which led me to doublecheck my CAR exit code... I had disabled
MTRR subsystem, cr3 was 0, but cr0 still had
cache-disable bit set as 0... CPU was using non-configured cache.
After changing cache-disable to 1 in cr0, everything worked just
fine again.
I wont be going too deeply in detail here, linuxboot & coreboot
docs explain this stuff way better than I do, however here's a short
walkthrough of how to enable cache-as-ram on intel i386&x86 machines.
As always, don't copy-paste my code & use it as is, it may break stuff.
%define CACHE_AS_RAM_BASE 0x08000000
%define CACHE_AS_RAM_SIZE 0x2000
%define MEMORY_TYPE_WRITEBACK 0x06
%define MTRR_PAIR_VALID 0x800
%define MTRR_PHYB_LO (CACHE_AS_RAM_BASE | \
MEMORY_TYPE_WRITEBACK)
%define MTRR_PHYB_REG0 0x200
%define MTRR_PHYB_HI 0x00
; mask
%define MTRR_PHYM_LO ((~((CACHE_AS_RAM_SIZE) - 1)) | \
MTRR_PAIR_VALID)
%define MTRR_PHYM_HI 0xF
%define MTRR_PHYM_REG0 0x201
%define MTRR_DEFTYPE_REG0 0x2FF
%define MTRR_ENABLE 0x800
; setup MTRR base
mov eax, MTRR_PHYB_LO ; mtrr phybase low
mov ecx, MTRR_PHYB_REG0 ; ia32 mtrr phybase reg0
xor edx, edx
wrmsr
; setup MTRR mask
mov eax, MTRR_PHYM_LO
mov ecx, MTRR_PHYM_REG0
mov edx, MTRR_PHYM_HI
wrmsr
; enable MTRR subsystem
mov ecx, MTRR_DEFTYPE_REG0
rdmsr
or eax, MTRR_ENABLE
wrmsr
; enter normal cache mode
mov eax, cr0
and eax, 0x9FFFFFFF
invd
mov cr0, eax
; establish tags for cache-as-ram region in cache
mov esi, CACHE_AS_RAM_BASE
mov ecx, (CACHE_AS_RAM_SIZE / 2)
rep lodsw
; clear cache memory region
mov edi, CACHE_AS_RAM_BASE
mov ecx, (CACHE_AS_RAM_SIZE / 2)
rep stosw
xor ax, ax
mov ss, ax
mov esp, (CACHE_AS_RAM_BASE + CACHE_AS_RAM_SIZE)
; Done, now cache is used as stack,.. hopefully.
; atleast it works on my machine!