Some old changes, probably shouldn't get lost, even if this boot method

is not being used by the PPC anymore.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10299 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-11-30 17:37:56 +00:00
parent 058569262f
commit caa0ef0b4c
+375 -176
View File
@@ -3,64 +3,49 @@
** Distributed under the terms of the NewOS License.
*/
#include <boot/stage2.h>
#include <kernel/kernel.h>
#include <arch/cpu.h>
#include <libc/string.h>
#include "stage2_priv.h"
#define PAGE_SIZE 4096
static unsigned int primary_hash(unsigned int vsid, unsigned int vaddr);
static unsigned int secondary_hash(unsigned int primary_hash);
// BAT register defs
#define BATU_BEPI_MASK 0xfffe0000
#define BATU_LEN_256M 0x1ffc
#define BATU_VS 0x2
#define BATU_VP 0x1
#define BATL_BRPN_MASK 0xfffe0000
#define BATL_WIMG_MASK 0x78
#define BATL_WT 0x40
#define BATL_CI 0x20
#define BATL_MC 0x10
#define BATL_G 0x08
#define BATL_PP_MASK 0x3
#define BATL_PP_RO 0x1
#define BATL_PP_RW 0x2
struct pte {
// pte lower word
unsigned int v : 1;
unsigned int vsid : 24;
unsigned int hash : 1;
unsigned int api : 6;
// pte upper word
unsigned int ppn : 20;
unsigned int unused : 3;
unsigned int r : 1;
unsigned int c : 1;
unsigned int wimg : 4;
unsigned int unused1 : 1;
unsigned int pp : 2;
};
struct pteg {
struct pte pte[8];
};
static struct pteg *ptable = 0;
static struct ppc_pteg *ptable = 0;
static int ptable_size = 0;
static unsigned int ptable_hash_mask = 0;
static unsigned long total_ram_size = 0;
static void print_pte(struct ppc_pte *e);
static bool does_intersect(unsigned long base1, unsigned long len1, unsigned long base2, unsigned long len2)
{
unsigned long end1 = base1 + len1;
unsigned long end2 = base2 + len2;
if(base2 >= base1 && base2 <= end1)
return true; // base2 is inside first range
if(end2 >= base1 && end2 <= end1)
return true; // end of second range inside first range
if(base1 >= base2 && base1 <= end2)
return true; // base1 is inside second range
if(end1 >= base2 && end1 <= end2)
return true; // end of first range inside second range
return false;
}
static void find_phys_memory_map(kernel_args *ka)
{
int handle;
int i;
unsigned int i;
struct mem_region {
unsigned long pa;
int len;
} mem_regions[33];
int mem_regions_len = 0;
unsigned int mem_regions_len = 0;
// get the physical memory map of the system
handle = of_finddevice("/memory");
@@ -90,21 +75,80 @@ static void find_phys_memory_map(kernel_args *ka)
}
}
for(i=0; i<ka->num_phys_mem_ranges; i++) {
printf("phys map %d: pa 0x%x, len %d\n", i, ka->phys_mem_range[i].start, ka->phys_mem_range[i].size);
printf("phys map %d: pa 0x%lx, len 0x%lx\n", i, ka->phys_mem_range[i].start, ka->phys_mem_range[i].size);
}
}
static bool is_in_phys_mem(kernel_args *ka, unsigned long addr)
{
unsigned int i;
for(i = 0; i < ka->num_phys_mem_ranges; i++) {
if(does_intersect(ka->phys_mem_range[i].start, ka->phys_mem_range[i].size, addr, 0))
return true;
}
return false;
}
static void mark_used_phys_mem_range(kernel_args *ka, unsigned long base, unsigned long len)
{
unsigned int i;
unsigned long start;
base = ROUNDOWN(base, PAGE_SIZE);
len = ROUNDUP(len, PAGE_SIZE);
start = base;
while(start < base + len){
// cycle through the list of physical runs of used pages,
// seeing if start will intersect one of them
for(i = 0; i < ka->num_phys_alloc_ranges; i++) {
if(start == ka->phys_alloc_range[i].start + ka->phys_alloc_range[i].size) {
// it will extend it
ka->phys_alloc_range[i].size += PAGE_SIZE;
goto next_page;
}
if(start + PAGE_SIZE == ka->phys_alloc_range[i].start) {
// it will prepend it
ka->phys_alloc_range[i].start = start;
ka->phys_alloc_range[i].size += PAGE_SIZE;
goto next_page;
}
if(does_intersect(ka->phys_alloc_range[i].start, ka->phys_alloc_range[i].size, start, PAGE_SIZE)) {
// it's off in the middle of this range, skip it
goto next_page;
}
}
// didn't find it in one of the existing ranges, must need to start a new one
if(ka->num_phys_alloc_ranges >= MAX_PHYS_ALLOC_ADDR_RANGE) {
printf("mark_used_phys_mem_range: MAX_PHYS_ALLOC_ADDR_RANGE (%d) too small\n", MAX_PHYS_ALLOC_ADDR_RANGE);
for(;;);
}
// create a new allocated range
ka->phys_alloc_range[ka->num_phys_alloc_ranges].start = start;
ka->phys_alloc_range[ka->num_phys_alloc_ranges].size = PAGE_SIZE;
ka->num_phys_alloc_ranges++;
next_page:
start += PAGE_SIZE;
}
}
static void find_used_phys_memory_map(kernel_args *ka)
{
int handle;
int i;
unsigned int i;
struct translation_map {
unsigned long va;
int len;
unsigned long pa;
int mode;
} memmap[64];
int translation_map_len = 0;
unsigned int translation_map_len = 0;
ka->num_phys_alloc_ranges = 0;
// get the current translation map of the system,
// to find how much memory was mapped to load the stage1 and bootdir
@@ -115,29 +159,99 @@ static void find_used_phys_memory_map(kernel_args *ka)
translation_map_len = of_getprop(handle, "translations", memmap, sizeof(memmap));
translation_map_len /= sizeof(struct translation_map);
for(i=0; i<translation_map_len; i++) {
if(memmap[i].va == LOAD_ADDR) {
if(is_in_phys_mem(ka, memmap[i].va)) {
printf("package loaded at pa 0x%lx va 0x%lx, len 0x%x\n", memmap[i].pa, memmap[i].va, memmap[i].len);
// we found the translation that covers the loaded package. Save this.
printf("package loaded at pa 0x%x, len 0x%x\n", memmap[i].pa, memmap[i].len);
ka->phys_alloc_range[0].start = memmap[i].pa;
ka->phys_alloc_range[0].size = memmap[i].len;
ka->num_phys_alloc_ranges = 1;
mark_used_phys_mem_range(ka, memmap[i].pa, memmap[i].len);
}
}
for(i=0; i<ka->num_phys_alloc_ranges; i++) {
printf("phys alloc map %d: pa 0x%lx, len 0x%lx\n", i, ka->phys_alloc_range[i].start, ka->phys_alloc_range[i].size);
}
}
static void mark_used_virt_mem_range(kernel_args *ka, unsigned long base, unsigned long len)
{
unsigned int i;
unsigned long start;
base = ROUNDOWN(base, PAGE_SIZE);
len = ROUNDUP(len, PAGE_SIZE);
start = base;
while(start < base + len) {
// cycle through the list of virtual runs of used pages,
// seeing if start will intersect one of them
for(i = 0; i < ka->num_virt_alloc_ranges; i++) {
if(start == ka->virt_alloc_range[i].start + ka->virt_alloc_range[i].size) {
// it will extend it
ka->virt_alloc_range[i].size += PAGE_SIZE;
goto next_page;
}
if(start + PAGE_SIZE == ka->virt_alloc_range[i].start) {
// it will prepend it
ka->virt_alloc_range[i].start = start;
ka->virt_alloc_range[i].size += PAGE_SIZE;
goto next_page;
}
if(does_intersect(ka->virt_alloc_range[i].start, ka->virt_alloc_range[i].size, start, PAGE_SIZE)) {
// it's off in the middle of this range, skip it
goto next_page;
}
}
// didn't find it in one of the existing ranges, must need to start a new one
if(ka->num_virt_alloc_ranges >= MAX_VIRT_ALLOC_ADDR_RANGE) {
printf("mark_used_virt_mem_range: MAX_VIRT_ALLOC_ADDR_RANGE (%d) too small\n", MAX_VIRT_ALLOC_ADDR_RANGE);
for(;;);
}
// create a new allocated range
ka->virt_alloc_range[ka->num_virt_alloc_ranges].start = start;
ka->virt_alloc_range[ka->num_virt_alloc_ranges].size = PAGE_SIZE;
ka->num_virt_alloc_ranges++;
next_page:
start += PAGE_SIZE;
}
}
unsigned long mmu_allocate_page(kernel_args *ka)
{
unsigned long page;
if(ka->num_phys_alloc_ranges == 0) {
// no physical allocated ranges, start one
page = ka->phys_mem_range[0].start;
mark_used_phys_mem_range(ka, page, PAGE_SIZE);
return page;
}
// allocate from the first allocated physical range
page = ka->phys_alloc_range[0].start + ka->phys_alloc_range[0].size;
ka->phys_alloc_range[0].size += PAGE_SIZE;
// XXX check for validity better
return page;
}
static void tlbia()
{
unsigned long i;
asm volatile("sync");
for(i=0; i< 0x40000; i += 0x1000) {
asm volatile("tlbie %0" :: "r" (i));
asm volatile("eieio");
asm volatile("sync");
}
asm volatile("tlbsync");
asm volatile("sync");
}
#define CACHELINE 64
#define CACHELINE 32
void syncicache(void *address, int len)
{
@@ -167,162 +281,245 @@ int s2_mmu_init(kernel_args *ka)
{
unsigned int ibats[8];
unsigned int dbats[8];
unsigned long top_ram = 0;
int i;
getibats(ibats);
getdbats(dbats);
for(i=0; i<8; i++) {
ibats[0] = 0;
dbats[0] = 0;
}
// identity map the first 256Mb of RAM
ibats[0] = BATU_LEN_256M | BATU_VS;
dbats[0] = BATU_LEN_256M | BATU_VS;
ibats[1] = BATL_MC | BATL_PP_RW;
dbats[1] = BATL_MC | BATL_PP_RW;
// XXX remove
ibats[2] = 0x10000000 | BATU_LEN_256M | BATU_VS;
dbats[2] = 0x10000000 | BATU_LEN_256M | BATU_VS;
ibats[3] = 0x90000000 | BATL_CI | BATL_PP_RW;
dbats[3] = 0x90000000 | BATL_CI | BATL_PP_RW;
setibats(ibats);
setdbats(dbats);
tlbia();
s2_faults_init(ka);
// XXX remove
s2_change_framebuffer_addr(0x16008000);
printf("msr = 0x%x\n", getmsr());
// setmsr(getmsr() | 0x400);
printf("foo\n");
*(int *)0x30000000 = 5;
printf("here\n");
for(;;);
ka->num_virt_alloc_ranges = 0;
// figure out where physical memory is and what is being used
find_phys_memory_map(ka);
find_used_phys_memory_map(ka);
// allocate a page table
{
unsigned long top_ram = 0;
// find the largest address of physical memory, but with a max of 256 MB,
// so it'll be within our 256 MB BAT window
for(i=0; i<ka->num_phys_mem_ranges; i++) {
if(ka->phys_mem_range[i].start + ka->phys_mem_range[i].size > top_ram) {
if(ka->phys_mem_range[i].start + ka->phys_mem_range[i].size > 256*1024*1024) {
if(ka->phys_mem_range[i].start < 256*1024*1024) {
top_ram = 256*1024*1024;
break;
}
#if 0
// find the largest address of physical memory, but with a max of 256 MB,
// so it'll be within our 256 MB BAT window
for(i=0; i<ka->num_phys_mem_ranges; i++) {
if(ka->phys_mem_range[i].start + ka->phys_mem_range[i].size > top_ram) {
if(ka->phys_mem_range[i].start + ka->phys_mem_range[i].size > 256*1024*1024) {
if(ka->phys_mem_range[i].start < 256*1024*1024) {
top_ram = 256*1024*1024;
break;
}
top_ram = ka->phys_mem_range[i].start + ka->phys_mem_range[i].size;
}
top_ram = ka->phys_mem_range[i].start + ka->phys_mem_range[i].size;
}
printf("top of ram (but under 256Mb) is 0x%x\n", top_ram);
// figure the size of the new pagetable, as recommended by Motorola
if(total_ram_size <= 8*1024*1024) {
ptable_size = 64*1024;
ptable_hash_mask = 0x0;
} else if(total_ram_size <= 16*1024*1024) {
ptable_size = 128*1024;
ptable_hash_mask = 0x1;
} else if(total_ram_size <= 32*1024*1024) {
ptable_size = 256*1024;
ptable_hash_mask = 0x3;
} else if(total_ram_size <= 64*1024*1024) {
ptable_size = 512*1024;
ptable_hash_mask = 0x7;
} else if(total_ram_size <= 128*1024*1024) {
ptable_size = 1024*1024;
ptable_hash_mask = 0xf;
} else if(total_ram_size <= 256*1024*1024) {
ptable_size = 2*1024*1024;
ptable_hash_mask = 0x1f;
} else if(total_ram_size <= 512*1024*1024) {
ptable_size = 4*1024*1024;
ptable_hash_mask = 0x3f;
} else if(total_ram_size <= 1024*1024*1024) {
ptable_size = 8*1024*1024;
ptable_hash_mask = 0x7f;
} else if(total_ram_size <= 2*1024*1024*1024) {
ptable_size = 16*1024*1024;
ptable_hash_mask = 0xff;
} else {
ptable_size = 32*1024*1024;
ptable_hash_mask = 0x1ff;
}
ptable = (struct pteg *)(top_ram - ptable_size - 0x100000);
printf("ptable at pa 0x%x, size 0x%x\n", ptable, ptable_size);
printf("mask = 0x%x\n", ptable_hash_mask);
printf("sdr1 = 0x%x\n", getsdr1());
printf("msr = 0x%x\n", getmsr());
for(i=0; i<16; i++) {
printf("sr[%i] = 0x%x\n", i, getsr(i));
}
printf("memsetting pagetable and performing switch\n");
memset(ptable, 0, ptable_size);
mmu_map_page(0, 0x96008000, 0x96008000);
mmu_map_page(0, 0x96009000, 0x96009000);
mmu_map_page(0, 0x9600a000, 0x9600a000);
mmu_map_page(0, 0x0, 0x30000000);
printf("done, setting sdr1\n");
setsdr1(((unsigned int)ptable & 0xffff0000) | ptable_hash_mask);
tlbia();
printf("hello\n");
printf("sdr1 = 0x%x\n", getsdr1());
printf("%d\n", *(int *)0x30000000);
printf("%d\n", *(int *)0x96008000);
printf("hello2\n");
for(i=0; i<64; i++) {
*(char *)(0x96008000 + i) = i;
}
printf("foo\n");
}
printf("top of ram (but under 256MB) is 0x%x\n", top_ram);
#endif
// figure the size of the new pagetable, as recommended by Motorola
if(total_ram_size <= 8*1024*1024) {
ptable_size = 64*1024;
} else if(total_ram_size <= 16*1024*1024) {
ptable_size = 128*1024;
} else if(total_ram_size <= 32*1024*1024) {
ptable_size = 256*1024;
} else if(total_ram_size <= 64*1024*1024) {
ptable_size = 512*1024;
} else if(total_ram_size <= 128*1024*1024) {
ptable_size = 1024*1024;
} else if(total_ram_size <= 256*1024*1024) {
ptable_size = 2*1024*1024;
} else if(total_ram_size <= 512*1024*1024) {
ptable_size = 4*1024*1024;
} else if(total_ram_size <= 1024*1024*1024) {
ptable_size = 8*1024*1024;
} else if(total_ram_size <= 2*1024*1024*1024UL) {
ptable_size = 16*1024*1024;
} else {
ptable_size = 32*1024*1024;
}
// figure out where to put the page table
printf("allocating a page table using claim\n");
ptable_hash_mask = (ptable_size >> 6) - 1;
ptable = (struct ppc_pteg *)of_claim(0, ptable_size, ptable_size);
printf("ptable at pa 0x%x, size 0x%x\n", ptable, ptable_size);
printf("mask = 0x%x\n", ptable_hash_mask);
// mark it used
mark_used_phys_mem_range(ka, (unsigned long)ptable, ptable_size);
// save it's new location in the kernel args
ka->arch_args.page_table.start = (unsigned long)ptable;
ka->arch_args.page_table.size = ptable_size;
ka->arch_args.page_table_mask = ptable_hash_mask;
#if 0
{
struct ppc_pteg *old_ptable;
int j;
printf("sdr1 = 0x%x\n", getsdr1());
old_ptable = (struct ppc_pteg *)((unsigned int)getsdr1() & 0xffff0000);
printf("old_ptable %p\n", old_ptable);
for(i=0; i< (64*1024) >> 6 ; i++) {
for(j=0; j< 8; j++)
if(old_ptable[i].pte[j].v && old_ptable[i].pte[j].vsid == 0)
print_pte(&old_ptable[i].pte[j]);
}
}
#endif
unsigned int sp;
asm volatile("mr %0,1" : "=r"(sp));
printf("sp = 0x%x\n", sp);
/* set up the new BATs */
getibats(ibats);
getdbats(dbats);
for(i=0; i<8; i++) {
ibats[i] = 0;
dbats[i] = 0;
}
// identity map the first 256MB of RAM
dbats[0] = ibats[0] = BATU_LEN_256M | BATU_VS;
dbats[1] = ibats[1] = BATL_MC | BATL_PP_RW;
// map the framebuffer using a BAT to 256MB
{
unsigned int framebuffer_phys = ka->fb.mapping.start & ~((16*1024*1024) - 1);
dbats[2] = ibats[2] = 0x10000000 | BATU_LEN_16M | BATU_VS;
dbats[3] = ibats[3] = framebuffer_phys | BATL_CI | BATL_PP_RW;
printf("remapping framebuffer at pa 0x%x to va 0x%x using BAT\n",
ka->fb.mapping.start, 0x10000000 + ka->fb.mapping.start - framebuffer_phys);
s2_change_framebuffer_addr(ka, 0x10000000 + ka->fb.mapping.start - framebuffer_phys);
}
setibats(ibats);
setdbats(dbats);
tlbia();
printf("unsetting the old page table\n");
setsdr1(0);
tlbia();
printf("memsetting new pagetable\n");
memset(ptable, 0, ptable_size);
printf("done\n");
printf("setting up the 16 segment registers\n");
// set up the segment registers
for(i=0; i<16; i++) {
setsr(i * 0x10000000, i);
}
printf("done, setting sdr1\n");
setsdr1(((unsigned int)ptable & 0xffff0000) | (ptable_hash_mask >> 10));
tlbia();
printf("sdr1 = 0x%x\n", getsdr1());
#if 0
mmu_map_page(0x96008000, 0x96008000);
mmu_map_page(0x96009000, 0x96009000);
mmu_map_page(0x9600a000, 0x9600a000);
mmu_map_page(0x96008000, 0x30000000);
printf("testing...\n");
printf("hello\n");
printf("%d\n", *(int *)0x30000000);
printf("%d\n", *(int *)0x96008000);
*(int *)0x30000000 = 0x99;
printf("%d\n", *(int *)0x30000000);
printf("%d\n", *(int *)0x96008000);
printf("hello2\n");
#endif
printf("done\n");
return 0;
}
void mmu_map_page(unsigned int vsid, unsigned long pa, unsigned long va)
int s2_mmu_remap_pagetable(kernel_args *ka)
{
unsigned long i;
unsigned long new_ptable;
// find a new spot to allocate the page table
// XXX make better
new_ptable = ka->virt_alloc_range[0].start + ka->virt_alloc_range[0].size;
for(i = 0; i < ptable_size; i += PAGE_SIZE) {
mmu_map_page(ka, ka->arch_args.page_table.start + i, new_ptable + i, true);
}
ka->arch_args.page_table_virt.start = new_ptable;
ka->arch_args.page_table_virt.size = ka->arch_args.page_table.size;
}
int s2_mmu_remove_fb_bat_entries(kernel_args *ka)
{
unsigned int ibat[8];
unsigned int dbat[8];
// zero out the 2nd bat entry, used to map the framebuffer
getibats(ibat);
getdbats(dbat);
ibat[2] = ibat[3] = dbat[2] = dbat[3] = 0;
setibats(ibat);
setdbats(dbat);
return NO_ERROR;
}
static void print_pte(struct ppc_pte *e)
{
printf("entry %p: ", e);
printf("v %d ", e->v);
if(e->v) {
printf("vsid 0x%x ", e->vsid);
printf("hash %d ", e->hash);
printf("api 0x%x ", e->api);
printf("ppn 0x%x ", e->ppn);
printf("r %d ", e->r);
printf("c %d ", e->c);
printf("wimg 0x%x ", e->wimg);
printf("pp 0x%x ", e->pp);
}
printf("\n");
}
void mmu_map_page(kernel_args *ka, unsigned long pa, unsigned long va, bool cached)
{
unsigned int hash;
struct pteg *pteg;
struct ppc_pteg *pteg;
int i;
unsigned int vsid;
printf("mmu_map_page: vsid %d, pa 0x%x, va 0x%x\n", vsid, pa, va);
// mark it used if this is in the kernel area
if(va >= KERNEL_BASE) {
mark_used_virt_mem_range(ka, va, PAGE_SIZE);
}
// lookup the vsid based off the va
vsid = getsr(va) & 0xffffff;
// printf("mmu_map_page: vsid %d, pa 0x%x, va 0x%x\n", vsid, pa, va);
hash = primary_hash(vsid, va);
// printf("hash = 0x%x\n", hash);
hash = primary_hash(0, va);
printf("hash = 0x%x\n", hash);
pteg = &ptable[hash];
printf("pteg @ 0x%x\n", pteg);
// printf("pteg @ 0x%x\n", pteg);
// search for the first free slot for this pte
for(i=0; i<8; i++) {
printf("trying pteg[%i]\n", i);
// printf("trying pteg[%i]\n", i);
if(pteg->pte[i].v == 0) {
// upper word
pteg->pte[i].ppn = pa / PAGE_SIZE;
pteg->pte[i].unused = 0;
pteg->pte[i].r = 0;
pteg->pte[i].c = 0;
pteg->pte[i].wimg = 0x4;
pteg->pte[i].wimg = cached ? 0 : (1 << 3);
pteg->pte[i].unused1 = 0;
pteg->pte[i].pp = 0x2; // RW
asm volatile("eieio");
@@ -332,7 +529,9 @@ void mmu_map_page(unsigned int vsid, unsigned long pa, unsigned long va)
pteg->pte[i].api = (va >> 22) & 0x3f;
pteg->pte[i].v = 1;
tlbia();
printf("set pteg to 0x%x 0x%x\n", *((int *)&pteg->pte[i]), *(((int *)&pteg->pte[i])+1));
// printf("set pteg to ");
// print_pte(&pteg->pte[i]);
// printf("set pteg to 0x%x 0x%x\n", *((int *)&pteg->pte[i]), *(((int *)&pteg->pte[i])+1));
return;
}
}