.section .text // oh how much more powerpc assembly must i write. woe is me // BAT stuff is completely ripped from helenos .macro BAT_COMPUTE base size mask lower upper // less than 128 KB -> no BAT lis \upper, 0x0002 cmpw \size, \upper blt no_bat // mask = total >> 18 li \upper, 18 srw \mask, \size, \upper // create Block Length mask by replicating // the leading logical one 14 times li \upper, 14 mtctr \mask li \upper, 1 0: // mask = (mask >> 1) | mask srw \lower, \mask, \upper or \mask, \mask, \lower bdnz 0b // mask = mask & 0x07ff // (BAT can map up to 256 MB) andi. \mask, \mask, 0x07ff // mask = (mask << 2) | 0x0002 // (priviledged access only) li \upper, 2 slw \mask, \mask, \upper ori \mask, \mask, 0x0002 lis \upper, (0x8000 + \base) or \upper, \upper, \mask lis \lower, \base ori \lower, \lower, 0x0002 .endm .global get_real get_real: // r3 = address of the function to call once we're in real mode (physical address) // r4 = kernel base address (physical address) // r5 = kernel size // r6 = final address (physical address) // r7 translate table (physical address) // r8 = memory size (physical address) // r9 = pages to translate // get msr value mfmsr 31 // disable interrupts rlwinm 31,31,0,17,15 // set msr mtmsr 31 // move r3 into srr0 (so we can jump to it with the rfi instruction) mtsrr0 3 // set srr1 to the pending msr value we want for real mode mfmsr 31 lis 30, ~0@h // "interrupts, instruction relocation, and data relocation" ori 30, 30, ~((1<<15) | (1<<5) | (1<<4))@l and 31, 31, 30 mtsrr1 31 // WE'RE GETTING REAL sync isync rfi #define PAGE_WIDTH 12 #define PAGE_SIZE (1 << PAGE_WIDTH) .global get_fake get_fake: // we want parameters in the format of // memory_size, translate_table, pages_to_translate, kernel_fake_address, kernel_real_address // so lets move them into the right registers mr 31, 4 mr 3, 8 mr 4, 7 mr 5, 9 mr 6, 6 mr 7, 31 // r3 = memory size, r4 = translate table, r5 = pages to translate, r6 = where we jump after finishing li 31, PAGE_SIZE >> 2 // number of words to copy per page mr 30, 7 // 30 = beginning of kernel (physical address), we want to copy it to the beginning of the kernel (virtual address) page_copy: cmpwi 5, 0 // are pages = 0? beq page_copy_done mtctr 31 // load counter with number of words to copy lwz 29, 0(4) // 29 = address of this page as a physical address page_copy_loop: lwz 28, 0(29) // load word from physical address stw 28, 0(30) // store word to virtual address dcbst 0, 30 // sync sync icbi 0, 30 sync isync addi 29, 29, 4 // add 4 to physical address addi 30, 30, 4 // add 4 to virtual address bdnz page_copy_loop // move to next translate table entry addi 4, 4, 4 // most confusing assembly language award goes to... subi 5, 5, 1 b page_copy page_copy_done: // infinite loop for debugging debug_loop: b debug_loop // fill segment registers li 31, 0 li 29, 8 mtctr 29 li 30, 0 seg_fill_unpriv: mtsrin 30, 31 addi 30, 30, 1 addis 31, 31, 0x1000 bdnz seg_fill_unpriv li 29, 8 mtctr 29 lis 30, 0x4000 ori 30, 30, 8 seg_fill_priv: mtsrin 30, 31 addi 30, 30, 1 addis 31, 31, 0x1000 bdnz seg_fill_priv // invalidate bat registers li 31, 0 mtspr 528, 31 mtspr 529, 31 mtspr 530, 31 mtspr 531, 31 mtspr 532, 31 mtspr 533, 31 mtspr 534, 31 mtspr 535, 31 mtspr 536, 31 mtspr 537, 31 mtspr 538, 31 mtspr 539, 31 mtspr 540, 31 mtspr 541, 31 mtspr 542, 31 mtspr 543, 31 // set up page hash table lis 31, 65536@h ori 31, 31, 65536@l subi 29, 31, 1 sub 30, 3, 31 andc 31, 31, 29 mtsdr1 30 li 29, 2 srw 31, 31, 29 li 29, 0 pht_clear: stw 29, 0(30) dcbst 0, 30 sync isync addi 30, 30, 4 subi 31, 31, 4 cmpwi 31, 0 beq pht_clear_done bdnz pht_clear pht_clear_done: mr 31, 3 lis 30, 268435456@h ori 30, 30, 268435456@l // 256MiB // bat 0 cmpw 31, 30 blt bat0_31 mr 29, 30 b bat0_30 bat0_31: mr 29, 31 bat0_30: BAT_COMPUTE 0x0000 29 28 27 26 mtspr 528, 26 mtspr 529, 27 mtspr 536, 26 mtspr 537, 27 // BAT1 sub 31, 31, 29 cmpw 31, 30 blt bat1_r31 mr 29, 30 b bat1_r30 bat1_r31: mr 29, 31 bat1_r30: BAT_COMPUTE 0x1000 29 28 27 26 mtspr 530, 26 mtspr 531, 27 mtspr 538, 26 mtspr 539, 27 // BAT2 sub 31, 31, 29 cmpw 31, 30 blt bat2_r31 mr 29, 30 b bat2_r30 bat2_r31: mr 29, 31 bat2_r30: BAT_COMPUTE 0x2000 29 28 27 26 mtspr 532, 26 mtspr 533, 27 mtspr 540, 26 mtspr 541, 27 // BAT3 sub 31, 31, 29 cmpw 31, 30 blt bat3_r31 mr 29, 30 b bat3_r30 bat3_r31: mr 29, 31 bat3_r30: BAT_COMPUTE 0x3000 29 28 27 26 mtspr 534, 26 mtspr 535, 27 mtspr 542, 26 mtspr 543, 27 no_bat: // flush tlb li 31, 0 sync eieio tlbsync sync // jump to the final function! mtsrr0 6 li 1, 0 // stack pointer mfmsr 31 ori 31, 31, ((1<<5) | (1<<4))@l mtsrr1 31 sync isync rfi