258 lines
No EOL
7.6 KiB
ArmAsm
258 lines
No EOL
7.6 KiB
ArmAsm
.section .text
|
|
|
|
.global vap_get_real
|
|
vap_get_real:
|
|
// switches the kernel from relying on openfirmware's virtual memory
|
|
// to its own BAT-mapped memory
|
|
// r3 = "translation table" (array of addresses of physical pages, starting at the virtual page with address 0)
|
|
// r4 = "translation table" size (in pages)
|
|
// r5 = vap_get_fake
|
|
// r6 = so_fake (pointer to the function to call after the kernel has been remapped (IN VIRTUAL MEMORY))
|
|
// r7 = amount of memory this system has (in bytes)
|
|
// all pointer arguments are physical addresses unless otherwise specified
|
|
|
|
// enter real mode
|
|
mfmsr 31
|
|
// MSR_IR (1 << 5) = 0
|
|
// MSR_DR (1 << 4) = 0
|
|
andi. 31, 31, ~((1 << 5) | (1 << 4))@l
|
|
mtsrr1 31
|
|
|
|
// because instructions will be fetched from physical addresses now, we need to load the
|
|
// physical address of vap_get_fake into srr0 and perform an rfi
|
|
mtsrr0 5
|
|
|
|
sync
|
|
isync
|
|
rfi
|
|
.global vap_get_fake
|
|
.extern VAP_KERN_BASE
|
|
vap_get_fake:
|
|
// we are now in actual real mode, the registers shouldn't have changed
|
|
// first things first, use the translation table to remap the kernel's memory
|
|
|
|
#define PAGE_WIDTH 12
|
|
#define PAGE_SIZE (1 << PAGE_WIDTH)
|
|
|
|
// some values for page copying, very much inspired by helenos's ppc32 port
|
|
li 31, PAGE_SIZE >> 2
|
|
li 30, 0
|
|
|
|
page_copy:
|
|
cmpwi 4, 0 // are we at 0 pages (done)?
|
|
beq page_copy_done // if so, jump to the end
|
|
|
|
mtctr 31 // set the counter to PAGE_SIZE >> 2
|
|
lwz 29, 0(3) // load the physical address of the page to copy
|
|
|
|
page_copy_loop:
|
|
lwz 28, 0(29) // load the word to copy
|
|
stw 28, 0(30) // store the word to the new page
|
|
|
|
// ensure everything's synced
|
|
dcbst 0, 30
|
|
sync
|
|
icbi 0, 30
|
|
sync
|
|
isync
|
|
|
|
addi 29, 29, 4 // increment the source pointer
|
|
addi 30, 30, 4 // increment the destination pointer
|
|
bdnz page_copy_loop // loop
|
|
// end of page_copy_loop
|
|
// increment the translation table pointer
|
|
addi 3, 3, 4
|
|
// decrement the number of pages left
|
|
subi 4, 4, 1
|
|
b page_copy // loop
|
|
|
|
page_copy_done:
|
|
|
|
// normally i'd write register names as their true values, but with the bat registers
|
|
// that'd just make things purely unreadable
|
|
#define ibat0u 528
|
|
#define ibat0l 529
|
|
#define ibat1u 530
|
|
#define ibat1l 531
|
|
#define ibat2u 532
|
|
#define ibat2l 533
|
|
#define ibat3u 534
|
|
#define ibat3l 535
|
|
#define dbat0u 536
|
|
#define dbat0l 537
|
|
#define dbat1u 538
|
|
#define dbat1l 539
|
|
#define dbat2u 540
|
|
#define dbat2l 541
|
|
#define dbat3u 542
|
|
#define dbat3l 543
|
|
|
|
// here we will give all of the bat registers an initial value of 0
|
|
li 30, 0
|
|
mtspr ibat0u, 30
|
|
mtspr ibat0l, 30
|
|
mtspr ibat1u, 30
|
|
mtspr ibat1l, 30
|
|
mtspr ibat2u, 30
|
|
mtspr ibat2l, 30
|
|
mtspr ibat3u, 30
|
|
mtspr ibat3l, 30
|
|
mtspr dbat0u, 30
|
|
mtspr dbat0l, 30
|
|
mtspr dbat1u, 30
|
|
mtspr dbat1l, 30
|
|
mtspr dbat2u, 30
|
|
mtspr dbat2l, 30
|
|
mtspr dbat3u, 30
|
|
mtspr dbat3l, 30
|
|
|
|
// here we define a macro for calculating the bat register values
|
|
// the bat registers are referred to as "upper" and "lower" registers
|
|
// the upper register contains the virtual address of the page, and the lower register contains
|
|
// the physical address of the page, as well as some other information
|
|
// if you want to learn more about this, i'd recommend reading this pdf:
|
|
// http://www.cs.cmu.edu/~412-s05/projects/9mac/PowerPC_Memory.pdf
|
|
// there are two notable things about this macro:
|
|
// 1. lower and upper are registers that the lower and upper bat registers should be set to
|
|
// their initial values do not matter
|
|
// 2. i kinda just stole this from helenos, i'm sorry ):
|
|
.macro BAT_COMPUTE base size mask lower upper kern_base
|
|
lis \upper, 0x0002
|
|
cmpw \size, \upper // check if we have less than 128kib remaining to map
|
|
blt finish_bat // if so, jump to the end
|
|
|
|
li \upper, 18
|
|
srw \mask, \size, \upper // calculate the mask (size >> 18)
|
|
|
|
// create the block length mask by duplicating the leading 1 14 times
|
|
// the block length mask indicates the length by number of bits set
|
|
li \upper, 14
|
|
mtctr \upper
|
|
li \upper, 1
|
|
0:
|
|
srw \lower, \mask, \upper
|
|
or \mask, \mask, \lower
|
|
bdnz 0b
|
|
// end of 0:
|
|
// & the mask with 0x07ff to assure that we map at most 256mib
|
|
andi. \mask, \mask, 0x07ff
|
|
|
|
// calculate the upper register
|
|
// the upper register contains:
|
|
// 1. the virtual address of the page
|
|
// 2. the block length mask
|
|
// 3. kernel access bit (1 << 2)
|
|
// 4. user access bit (1 << 1)
|
|
// we don't have a userspace yet! so we'll just set the kernel access bit to 1
|
|
// and the user access bit to 0
|
|
li \upper, 2
|
|
slw \mask, \mask, \upper
|
|
ori \upper, \upper, 0x0002
|
|
|
|
lis \upper, (\kern_base + \base)@l
|
|
or \upper, \upper, \mask
|
|
|
|
// calculate the lower register
|
|
// the lower register contains:
|
|
// 1. the physical address of the page
|
|
// 2. storage access controls
|
|
// 3. protection bits
|
|
lis \lower, \base
|
|
ori \lower, \lower, 0x0002
|
|
.endm
|
|
|
|
// now we are finally ready to set the bat registers!
|
|
// we will load into r29 either 256MiB or the remaining memory amount, whichever is smaller
|
|
lis 30, 268435456@h
|
|
ori 30, 30, 268435456@l
|
|
// reminder that r7 contains the amount of memory we have
|
|
cmpw 7, 30
|
|
blt bat0_memsmaller
|
|
|
|
// 256mib is smaller
|
|
mr 29, 30
|
|
b bat0_constsmaller
|
|
|
|
bat0_memsmaller:
|
|
mr 29, 7
|
|
bat0_constsmaller:
|
|
BAT_COMPUTE 0x0000 29 28 27 26 VAP_KERN_BASE
|
|
mtspr ibat0u, 26
|
|
mtspr ibat0l, 27
|
|
mtspr dbat0u, 26
|
|
mtspr dbat0l, 27
|
|
|
|
// now we will do the same thing for bat 1
|
|
sub 7, 7, 29 // decrement the amount of memory left
|
|
|
|
cmpw 7, 30
|
|
blt bat1_memsmaller
|
|
|
|
// 256mib is smaller
|
|
mr 29, 30
|
|
b bat1_constsmaller
|
|
|
|
bat1_memsmaller:
|
|
mr 29, 7
|
|
bat1_constsmaller:
|
|
BAT_COMPUTE 0x1000 29 28 27 26 VAP_KERN_BASE
|
|
mtspr ibat1u, 26
|
|
mtspr ibat1l, 27
|
|
mtspr dbat1u, 26
|
|
mtspr dbat1l, 27
|
|
|
|
// now we will do the same thing for bat 2
|
|
sub 7, 7, 29 // decrement the amount of memory left
|
|
|
|
cmpw 7, 30
|
|
blt bat2_memsmaller
|
|
|
|
// 256mib is smaller
|
|
mr 29, 30
|
|
b bat2_constsmaller
|
|
|
|
bat2_memsmaller:
|
|
mr 29, 7
|
|
bat2_constsmaller:
|
|
BAT_COMPUTE 0x2000 29 28 27 26 VAP_KERN_BASE
|
|
mtspr ibat2u, 26
|
|
mtspr ibat2l, 27
|
|
mtspr dbat2u, 26
|
|
mtspr dbat2l, 27
|
|
|
|
// now we will do the same thing for bat 3
|
|
sub 7, 7, 29 // decrement the amount of memory left
|
|
|
|
cmpw 7, 30
|
|
blt bat3_memsmaller
|
|
|
|
// 256mib is smaller
|
|
mr 29, 30
|
|
b bat3_constsmaller
|
|
|
|
bat3_memsmaller:
|
|
mr 29, 7
|
|
bat3_constsmaller:
|
|
BAT_COMPUTE 0x3000 29 28 27 26 VAP_KERN_BASE
|
|
mtspr ibat3u, 26
|
|
mtspr ibat3l, 27
|
|
mtspr dbat3u, 26
|
|
mtspr dbat3l, 27
|
|
|
|
finish_bat:
|
|
// theoretically, we should be done with the bat registers now
|
|
// we can now rfi to so_real (who's address should still be in r6)
|
|
// this function is in virtual memory, but this shouldn't matter as we have set up the bat registers
|
|
// to map said virtual memory to the same physical memory
|
|
mtsrr0 6
|
|
|
|
// we need to set the srr1 register to the value of the msr register
|
|
// but also re-enable MSR_IR and MSR_DR so that we can use the bat registers
|
|
mfmsr 31
|
|
ori 31, 31, ((1 << 5) | (1 << 4))@l
|
|
mtsrr1 31
|
|
|
|
// now we can rfi to so_real
|
|
sync
|
|
isync
|
|
rfi |