vap/assembly/ppc32/get_real.S

270 lines
7.7 KiB
ArmAsm
Raw Normal View History

2023-03-13 15:31:06 -07:00
.section .text
2023-03-14 07:17:49 -07:00
.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
// disable interrupts
mfmsr 31
rlwinm 31, 31, 0, 17, 15
mtmsr 31
2023-03-14 07:17:49 -07:00
// enter real mode
mtsrr0 5
2023-03-13 15:31:06 -07:00
mfmsr 31
2023-03-14 07:17:49 -07:00
// MSR_IR (1 << 5) = 0
// MSR_DR (1 << 4) = 0
// MSR_EE (1 << 15) = 0
lis 30, ~0@h
ori 30, 30, ~((1 << 15) | (1 << 5) | (1 << 4))@l
and 31, 31, 30
2023-03-13 15:31:06 -07:00
mtsrr1 31
// now we can rfi to so_real
2023-03-13 15:31:06 -07:00
sync
isync
rfi
2023-03-14 07:17:49 -07:00
.global vap_get_fake
.extern VAP_KERN_BASE
.extern VAP_KERN_END
2023-03-14 07:17:49 -07:00
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
2023-03-13 15:31:06 -07:00
2023-03-14 07:17:49 -07:00
#define PAGE_WIDTH 12
#define PAGE_SIZE (1 << PAGE_WIDTH)
2023-03-13 15:31:06 -07:00
2023-03-14 07:17:49 -07:00
// some values for page copying, very much inspired by helenos's ppc32 port
li 31, PAGE_SIZE >> 2
li 30, 0
2023-03-13 15:31:06 -07:00
page_copy:
2023-03-14 07:17:49 -07:00
cmpwi 4, 0 // are we at 0 pages (done)?
beq page_copy_done // if so, jump to the end
2023-03-13 15:31:06 -07:00
2023-03-14 07:17:49 -07:00
mtctr 31 // set the counter to PAGE_SIZE >> 2
lwz 29, 0(3) // load the physical address of the page to copy
2023-03-13 15:31:06 -07:00
page_copy_loop:
2023-03-14 07:17:49 -07:00
lwz 28, 0(29) // load the word to copy
stw 28, 0(30) // store the word to the new page
2023-03-13 15:31:06 -07:00
2023-03-14 07:17:49 -07:00
// ensure everything's synced
dcbst 0, 30
2023-03-13 15:31:06 -07:00
sync
icbi 0, 30
sync
isync
2023-03-14 07:17:49 -07:00
addi 29, 29, 4 // increment the source pointer
addi 30, 30, 4 // increment the destination pointer
bdnz page_copy_loop // loop
2023-03-14 07:17:49 -07:00
// 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
2023-03-13 15:31:06 -07:00
page_copy_done:
2023-03-14 07:17:49 -07:00
// 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
2023-03-13 15:31:06 -07:00
li 30, 0
2023-03-14 07:17:49 -07:00
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
2023-03-14 07:17:49 -07:00
// 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 \mask, \mask, 0x0002
2023-03-14 07:17:49 -07:00
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
2023-03-13 15:31:06 -07:00
2023-03-14 07:17:49 -07:00
// 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
2023-03-14 07:17:49 -07:00
// 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
2023-03-13 15:31:06 -07:00
// set stack pointer
lis 1, (VAP_KERN_END + 0x1000)@h
ori 1, 1, (VAP_KERN_END + 0x1000)@l
2023-03-14 07:17:49 -07:00
// now we can rfi to so_real
sync
isync
rfi