void * initarm(struct arm_boot_params *abp) { struct pv_addr kernel_l1pt; struct pv_addr dpcpu; int loop, i; u_int l1pagetable; vm_offset_t freemempos; vm_offset_t freemem_pt; vm_offset_t afterkern; vm_offset_t freemem_after; vm_offset_t lastaddr; uint32_t memsize, memstart; lastaddr = parse_boot_param(abp); arm_physmem_kernaddr = abp->abp_physaddr; set_cpufuncs(); pcpu_init(pcpup, 0, sizeof(struct pcpu)); PCPU_SET(curthread, &thread0); /* Do basic tuning, hz etc */ init_param1(); freemempos = 0xa0200000; /* Define a macro to simplify memory allocation */ #define valloc_pages(var, np) \ alloc_pages((var).pv_pa, (np)); \ (var).pv_va = (var).pv_pa + 0x20000000; #define alloc_pages(var, np) \ freemempos -= (np * PAGE_SIZE); \ (var) = freemempos; \ memset((char *)(var), 0, ((np) * PAGE_SIZE)); while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0) freemempos -= PAGE_SIZE; valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) { valloc_pages(kernel_pt_table[loop], L2_TABLE_SIZE / PAGE_SIZE); } else { kernel_pt_table[loop].pv_pa = freemempos + (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) * L2_TABLE_SIZE_REAL; kernel_pt_table[loop].pv_va = kernel_pt_table[loop].pv_pa + 0x20000000; } } freemem_pt = freemempos; freemempos = 0xa0100000; /* * Allocate a page for the system page mapped to V0x00000000 * This page will just contain the system vectors and can be * shared by all processes. */ valloc_pages(systempage, 1); /* Allocate dynamic per-cpu area. */ valloc_pages(dpcpu, DPCPU_SIZE / PAGE_SIZE); dpcpu_init((void *)dpcpu.pv_va, 0); /* Allocate stacks for all modes */ valloc_pages(irqstack, IRQ_STACK_SIZE); valloc_pages(abtstack, ABT_STACK_SIZE); valloc_pages(undstack, UND_STACK_SIZE); valloc_pages(kernelstack, KSTACK_PAGES); alloc_pages(minidataclean.pv_pa, 1); valloc_pages(msgbufpv, round_page(msgbufsize) / PAGE_SIZE); /* * Allocate memory for the l1 and l2 page tables. The scheme to avoid * wasting memory by allocating the l1pt on the first 16k memory was * taken from NetBSD rpc_machdep.c. NKPT should be greater than 12 for * this to work (which is supposed to be the case). */ /* * Now we start construction of the L1 page table * We start by mapping the L2 page tables into the L1. * This means that we can replace L1 mappings later on if necessary */ l1pagetable = kernel_l1pt.pv_va; /* Map the L2 pages tables in the L1 page table */ pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH & ~(0x00100000 - 1), &kernel_pt_table[KERNEL_PT_SYS]); pmap_link_l2pt(l1pagetable, IQ80321_IOPXS_VBASE, &kernel_pt_table[KERNEL_PT_IOPXS]); pmap_link_l2pt(l1pagetable, KERNBASE, &kernel_pt_table[KERNEL_PT_BEFOREKERN]); pmap_map_chunk(l1pagetable, KERNBASE, IQ80321_SDRAM_START, 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, IQ80321_SDRAM_START + 0x100000, 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); pmap_map_chunk(l1pagetable, KERNBASE + 0x200000, IQ80321_SDRAM_START + 0x200000, (((uint32_t)(lastaddr) - KERNBASE - 0x200000) + L1_S_SIZE) & ~(L1_S_SIZE - 1), VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); freemem_after = ((int)lastaddr + PAGE_SIZE) & ~(PAGE_SIZE - 1); afterkern = round_page(((vm_offset_t)lastaddr + L1_S_SIZE) & ~(L1_S_SIZE - 1)); for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) { pmap_link_l2pt(l1pagetable, afterkern + i * 0x00100000, &kernel_pt_table[KERNEL_PT_AFKERNEL + i]); } pmap_map_entry(l1pagetable, afterkern, minidataclean.pv_pa, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); /* Map the Mini-Data cache clean area. */ xscale_setup_minidata(l1pagetable, afterkern, minidataclean.pv_pa); /* Map the vector page. */ pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); arm_devmap_bootstrap(l1pagetable, ep80219_devmap); /* * Give the XScale global cache clean code an appropriately * sized chunk of unmapped VA space starting at 0xff000000 * (our device mappings end before this address). */ xscale_cache_clean_addr = 0xff000000U; cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); setttb(kernel_l1pt.pv_pa); cpu_tlb_flushID(); cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); /* * Pages were allocated during the secondary bootstrap for the * stacks for different CPU modes. * We must now set the r13 registers in the different CPU modes to * point to these stacks. * Since the ARM stacks use STMFD etc. we must set r13 to the top end * of the stack memory. */ set_stackptrs(0); /* * We must now clean the cache again.... * Cleaning may be done by reading new data to displace any * dirty data in the cache. This will have happened in setttb() * but since we are boot strapping the addresses used for the read * may have just been remapped and thus the cache could be out * of sync. A re-clean after the switch will cure this. * After booting there are no gross relocations of the kernel thus * this problem will not occur after initarm(). */ cpu_idcache_wbinv_all(); cpu_setup(""); /* * Fetch the SDRAM start/size from the i80321 SDRAM configration * registers. */ i80321_calibrate_delay(); i80321_sdram_bounds(obio_bs_tag, IQ80321_80321_VBASE + VERDE_MCU_BASE, &memstart, &memsize); physmem = memsize / PAGE_SIZE; cninit(); undefined_init(); init_proc0(kernelstack.pv_va); /* Enable MMU, I-cache, D-cache, write buffer. */ arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); vm_max_kernel_address = 0xd0000000; pmap_bootstrap(pmap_curmaxkvaddr, &kernel_l1pt); msgbufp = (void*)msgbufpv.pv_va; msgbufinit(msgbufp, msgbufsize); mutex_init(); /* * Add the physical ram we have available. * * Exclude the kernel (and all the things we allocated which immediately * follow the kernel) from the VM allocation pool but not from crash * dumps. virtual_avail is a global variable which tracks the kva we've * "allocated" while setting up pmaps. * * Prepare the list of physical memory available to the vm subsystem. */ arm_physmem_hardware_region(IQ80321_SDRAM_START, memsize); arm_physmem_exclude_region(abp->abp_physaddr, virtual_avail - KERNVIRTADDR, EXFLAG_NOALLOC); arm_physmem_init_kernel_globals(); init_param2(physmem); kdb_init(); return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - sizeof(struct pcb))); }
/* * u_int initarm(...) * * Initial entry point on startup. This gets called before main() is * entered. * It should be responsible for setting up everything that must be * in place when main is called. * This includes * Taking a copy of the boot configuration structure. * Initialising the physical console so characters can be printed. * Setting up page tables for the kernel * Relocating the kernel to the bottom of physical memory */ u_int initarm(void *arg) { extern vaddr_t xscale_cache_clean_addr; #ifdef DIAGNOSTIC extern vsize_t xscale_minidata_clean_size; #endif int loop; int loop1; u_int l1pagetable; paddr_t memstart; psize_t memsize; /* * Clear out the 7-segment display. Whee, the first visual * indication that we're running kernel code. */ iq80321_7seg(' ', ' '); /* Calibrate the delay loop. */ i80321_calibrate_delay(); i80321_hardclock_hook = iq80321_hardclock_hook; /* * Since we map the on-board devices VA==PA, and the kernel * is running VA==PA, it's possible for us to initialize * the console now. */ consinit(); #ifdef VERBOSE_INIT_ARM /* Talk to the user */ printf("\nNetBSD/evbarm (IQ80321) booting ...\n"); #endif /* * Heads up ... Setup the CPU / MMU / TLB functions */ if (set_cpufuncs()) panic("CPU not recognized!"); /* * We are currently running with the MMU enabled and the * entire address space mapped VA==PA, except for the * first 64M of RAM is also double-mapped at 0xc0000000. * There is an L1 page table at 0xa0004000. */ /* * Fetch the SDRAM start/size from the i80321 SDRAM configuration * registers. */ i80321_sdram_bounds(&obio_bs_tag, VERDE_PMMR_BASE + VERDE_MCU_BASE, &memstart, &memsize); #ifdef VERBOSE_INIT_ARM printf("initarm: Configuring system ...\n"); #endif /* Fake bootconfig structure for the benefit of pmap.c */ /* XXX must make the memory description h/w independent */ bootconfig.dramblocks = 1; bootconfig.dram[0].address = memstart; bootconfig.dram[0].pages = memsize / PAGE_SIZE; /* * Set up the variables that define the availablilty of * physical memory. For now, we're going to set * physical_freestart to 0xa0200000 (where the kernel * was loaded), and allocate the memory we need downwards. * If we get too close to the L1 table that we set up, we * will panic. We will update physical_freestart and * physical_freeend later to reflect what pmap_bootstrap() * wants to see. * * XXX pmap_bootstrap() needs an enema. */ physical_start = bootconfig.dram[0].address; physical_end = physical_start + (bootconfig.dram[0].pages * PAGE_SIZE); physical_freestart = 0xa0009000UL; physical_freeend = 0xa0200000UL; physmem = (physical_end - physical_start) / PAGE_SIZE; #ifdef VERBOSE_INIT_ARM /* Tell the user about the memory */ printf("physmemory: %d pages at 0x%08lx -> 0x%08lx\n", physmem, physical_start, physical_end - 1); #endif /* * Okay, the kernel starts 2MB in from the bottom of physical * memory. We are going to allocate our bootstrap pages downwards * from there. * * We need to allocate some fixed page tables to get the kernel * going. We allocate one page directory and a number of page * tables and store the physical addresses in the kernel_pt_table * array. * * The kernel page directory must be on a 16K boundary. The page * tables must be on 4K boundaries. What we do is allocate the * page directory on the first 16K boundary that we encounter, and * the page tables on 4K boundaries otherwise. Since we allocate * at least 3 L2 page tables, we are guaranteed to encounter at * least one 16K aligned region. */ #ifdef VERBOSE_INIT_ARM printf("Allocating page tables\n"); #endif free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE; #ifdef VERBOSE_INIT_ARM printf("freestart = 0x%08lx, free_pages = %d (0x%08x)\n", physical_freestart, free_pages, free_pages); #endif /* Define a macro to simplify memory allocation */ #define valloc_pages(var, np) \ alloc_pages((var).pv_pa, (np)); \ (var).pv_va = KERNEL_BASE + (var).pv_pa - physical_start; #define alloc_pages(var, np) \ physical_freeend -= ((np) * PAGE_SIZE); \ if (physical_freeend < physical_freestart) \ panic("initarm: out of memory"); \ (var) = physical_freeend; \ free_pages -= (np); \ memset((char *)(var), 0, ((np) * PAGE_SIZE)); loop1 = 0; kernel_l1pt.pv_pa = 0; kernel_l1pt.pv_va = 0; for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) { /* Are we 16KB aligned for an L1 ? */ if (((physical_freeend - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) == 0 && kernel_l1pt.pv_pa == 0) { valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); } else { valloc_pages(kernel_pt_table[loop1], L2_TABLE_SIZE / PAGE_SIZE); ++loop1; } } /* This should never be able to happen but better confirm that. */ if (!kernel_l1pt.pv_pa || (kernel_l1pt.pv_pa & (L1_TABLE_SIZE-1)) != 0) panic("initarm: Failed to align the kernel page directory"); /* * Allocate a page for the system page mapped to V0x00000000 * This page will just contain the system vectors and can be * shared by all processes. */ alloc_pages(systempage.pv_pa, 1); /* Allocate stacks for all modes */ valloc_pages(irqstack, IRQ_STACK_SIZE); valloc_pages(abtstack, ABT_STACK_SIZE); valloc_pages(undstack, UND_STACK_SIZE); valloc_pages(kernelstack, UPAGES); /* Allocate enough pages for cleaning the Mini-Data cache. */ KASSERT(xscale_minidata_clean_size <= PAGE_SIZE); valloc_pages(minidataclean, 1); #ifdef VERBOSE_INIT_ARM printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa, irqstack.pv_va); printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa, abtstack.pv_va); printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa, undstack.pv_va); printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa, kernelstack.pv_va); #endif /* * XXX Defer this to later so that we can reclaim the memory * XXX used by the RedBoot page tables. */ alloc_pages(msgbufphys, round_page(MSGBUFSIZE) / PAGE_SIZE); /* * Ok we have allocated physical pages for the primary kernel * page tables */ #ifdef VERBOSE_INIT_ARM printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa); #endif /* * Now we start construction of the L1 page table * We start by mapping the L2 page tables into the L1. * This means that we can replace L1 mappings later on if necessary */ l1pagetable = kernel_l1pt.pv_pa; /* Map the L2 pages tables in the L1 page table */ pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH & ~(0x00400000 - 1), &kernel_pt_table[KERNEL_PT_SYS]); for (loop = 0; loop < KERNEL_PT_KERNEL_NUM; loop++) pmap_link_l2pt(l1pagetable, KERNEL_BASE + loop * 0x00400000, &kernel_pt_table[KERNEL_PT_KERNEL + loop]); pmap_link_l2pt(l1pagetable, IQ80321_IOPXS_VBASE, &kernel_pt_table[KERNEL_PT_IOPXS]); for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; loop++) pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000, &kernel_pt_table[KERNEL_PT_VMDATA + loop]); /* update the top of the kernel VM */ pmap_curmaxkvaddr = KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000); #ifdef VERBOSE_INIT_ARM printf("Mapping kernel\n"); #endif /* Now we fill in the L2 pagetable for the kernel static code/data */ { extern char etext[], _end[]; size_t textsize = (uintptr_t) etext - KERNEL_TEXT_BASE; size_t totalsize = (uintptr_t) _end - KERNEL_TEXT_BASE; u_int logical; textsize = (textsize + PGOFSET) & ~PGOFSET; totalsize = (totalsize + PGOFSET) & ~PGOFSET; logical = 0x00200000; /* offset of kernel in RAM */ logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, physical_start + logical, textsize, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, physical_start + logical, totalsize - textsize, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); } #ifdef VERBOSE_INIT_ARM printf("Constructing L2 page tables\n"); #endif /* Map the stack pages */ pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa, IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa, ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa, UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa, UPAGES * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va, kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); } /* Map the Mini-Data cache clean area. */ xscale_setup_minidata(l1pagetable, minidataclean.pv_va, minidataclean.pv_pa); /* Map the vector page. */ pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); /* Map the statically mapped devices. */ pmap_devmap_bootstrap(l1pagetable, iq80321_devmap); /* * Give the XScale global cache clean code an appropriately * sized chunk of unmapped VA space starting at 0xff000000 * (our device mappings end before this address). */ xscale_cache_clean_addr = 0xff000000U; /* * Now we have the real page tables in place so we can switch to them. * Once this is done we will be running with the REAL kernel page * tables. */ /* * Update the physical_freestart/physical_freeend/free_pages * variables. */ { extern char _end[]; physical_freestart = physical_start + (((((uintptr_t) _end) + PGOFSET) & ~PGOFSET) - KERNEL_BASE); physical_freeend = physical_end; free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE; } /* Switch tables */ #ifdef VERBOSE_INIT_ARM printf("freestart = 0x%08lx, free_pages = %d (0x%x)\n", physical_freestart, free_pages, free_pages); printf("switching to new L1 page table @%#lx...", kernel_l1pt.pv_pa); #endif cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); setttb(kernel_l1pt.pv_pa); cpu_tlb_flushID(); cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); /* * Moved from cpu_startup() as data_abort_handler() references * this during uvm init */ proc0paddr = (struct user *)kernelstack.pv_va; lwp0.l_addr = proc0paddr; #ifdef VERBOSE_INIT_ARM printf("done!\n"); #endif #ifdef VERBOSE_INIT_ARM printf("bootstrap done.\n"); #endif arm32_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); /* * Pages were allocated during the secondary bootstrap for the * stacks for different CPU modes. * We must now set the r13 registers in the different CPU modes to * point to these stacks. * Since the ARM stacks use STMFD etc. we must set r13 to the top end * of the stack memory. */ #ifdef VERBOSE_INIT_ARM printf("init subsystems: stacks "); #endif set_stackptr(PSR_IRQ32_MODE, irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); set_stackptr(PSR_ABT32_MODE, abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); set_stackptr(PSR_UND32_MODE, undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); /* * Well we should set a data abort handler. * Once things get going this will change as we will need a proper * handler. * Until then we will use a handler that just panics but tells us * why. * Initialisation of the vectors will just panic on a data abort. * This just fills in a slightly better one. */ #ifdef VERBOSE_INIT_ARM printf("vectors "); #endif data_abort_handler_address = (u_int)data_abort_handler; prefetch_abort_handler_address = (u_int)prefetch_abort_handler; undefined_handler_address = (u_int)undefinedinstruction_bounce; /* Initialise the undefined instruction handlers */ #ifdef VERBOSE_INIT_ARM printf("undefined "); #endif undefined_init(); /* Load memory into UVM. */ #ifdef VERBOSE_INIT_ARM printf("page "); #endif uvm_setpagesize(); /* initialize PAGE_SIZE-dependent variables */ uvm_page_physload(atop(physical_freestart), atop(physical_freeend), atop(physical_freestart), atop(physical_freeend), VM_FREELIST_DEFAULT); /* Boot strap pmap telling it where the kernel page table is */ #ifdef VERBOSE_INIT_ARM printf("pmap "); #endif pmap_bootstrap(KERNEL_VM_BASE, KERNEL_VM_BASE + KERNEL_VM_SIZE); /* Setup the IRQ system */ #ifdef VERBOSE_INIT_ARM printf("irq "); #endif i80321_intr_init(); #ifdef VERBOSE_INIT_ARM printf("done.\n"); #endif #ifdef BOOTHOWTO boothowto = BOOTHOWTO; #endif #if NKSYMS || defined(DDB) || defined(LKM) /* Firmware doesn't load symbols. */ ksyms_init(0, NULL, NULL); #endif #ifdef DDB db_machine_init(); if (boothowto & RB_KDB) Debugger(); #endif /* We return the new stack pointer address */ return(kernelstack.pv_va + USPACE_SVC_STACK_TOP); }
/* * u_int initarm(...) * * Initial entry point on startup. This gets called before main() is * entered. * It should be responsible for setting up everything that must be * in place when main is called. * This includes * Taking a copy of the boot configuration structure. * Initialising the physical console so characters can be printed. * Setting up page tables for the kernel * Relocating the kernel to the bottom of physical memory */ u_int initarm(void *arg0, void *arg1, void *arg2) { extern vaddr_t xscale_cache_clean_addr; extern cpu_kcore_hdr_t cpu_kcore_hdr; int loop; int loop1; u_int l1pagetable; pv_addr_t kernel_l1pt; paddr_t memstart; psize_t memsize; extern u_int32_t esym; /* &_end if no symbols are loaded */ #ifdef DIAGNOSTIC extern vsize_t xscale_minidata_clean_size; /* used in KASSERT */ #endif /* setup a serial console for very early boot */ consinit(); /* * Heads up ... Setup the CPU / MMU / TLB functions */ if (set_cpufuncs()) panic("cpu not recognized!"); /* * Examine the boot args string for options we need to know about * now. */ /* XXX should really be done after setting up the console, but we * XXX need to parse the console selection flags right now. */ process_kernel_args((char *)0xa0200000 - MAX_BOOT_STRING - 1); /* Calibrate the delay loop. */ #if 1 i80321_calibrate_delay(); #endif /* Talk to the user */ printf("\nOpenBSD/armish booting ...\n"); /* * Reset the secondary PCI bus. RedBoot doesn't stop devices * on the PCI bus before handing us control, so we have to * do this. * * XXX This is arguably a bug in RedBoot, and doing this reset * XXX could be problematic in the future if we encounter an * XXX application where the PPB in the i80312 is used as a * XXX PPB. */ //#define VERBOSE_INIT_ARM /* * Fetch the SDRAM start/size from the i80312 SDRAM configuration * registers. */ i80321_sdram_bounds(&obio_bs_tag, VERDE_PMMR_BASE + VERDE_MCU_BASE, &memstart, &memsize); #define DEBUG #ifdef DEBUG printf("initarm: Configuring system ...\n"); #endif /* Fake bootconfig structure for the benefit of pmap.c */ /* XXX must make the memory description h/w independant */ bootconfig.dramblocks = 1; bootconfig.dram[0].address = memstart; bootconfig.dram[0].pages = memsize / PAGE_SIZE; /* * Set up the variables that define the availablilty of * physical memory. For now, we're going to set * physical_freestart to 0xa0200000 (where the kernel * was loaded), and allocate the memory we need downwards. * If we get too close to the page tables that RedBoot * set up, we will panic. We will update physical_freestart * and physical_freeend later to reflect what pmap_bootstrap() * wants to see. * * XXX pmap_bootstrap() needs an enema. */ physical_start = bootconfig.dram[0].address; physical_end = physical_start + (bootconfig.dram[0].pages * PAGE_SIZE); physical_freestart = 0xa0009000UL; physical_freeend = 0xa0200000UL; physmem = (physical_end - physical_start) / PAGE_SIZE; #ifdef DEBUG /* Tell the user about the memory */ printf("physmemory: %d pages at 0x%08lx -> 0x%08lx\n", physmem, physical_start, physical_end - 1); #endif /* * Okay, the kernel starts 2MB in from the bottom of physical * memory. We are going to allocate our bootstrap pages downwards * from there. * * We need to allocate some fixed page tables to get the kernel * going. We allocate one page directory and a number of page * tables and store the physical addresses in the kernel_pt_table * array. * * The kernel page directory must be on a 16K boundary. The page * tables must be on 4K boundaries. What we do is allocate the * page directory on the first 16K boundary that we encounter, and * the page tables on 4K boundaries otherwise. Since we allocate * at least 3 L2 page tables, we are guaranteed to encounter at * least one 16K aligned region. */ #ifdef VERBOSE_INIT_ARM printf("Allocating page tables\n"); #endif free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE; #ifdef VERBOSE_INIT_ARM printf("freestart = 0x%08lx, free_pages = %d (0x%08x)\n", physical_freestart, free_pages, free_pages); #endif /* Define a macro to simplify memory allocation */ #define valloc_pages(var, np) \ alloc_pages((var).pv_pa, (np)); \ (var).pv_va = KERNEL_BASE + (var).pv_pa - physical_start; #define alloc_pages(var, np) \ physical_freeend -= ((np) * PAGE_SIZE); \ if (physical_freeend < physical_freestart) \ panic("initarm: out of memory"); \ (var) = physical_freeend; \ free_pages -= (np); \ memset((char *)(var), 0, ((np) * PAGE_SIZE)); loop1 = 0; kernel_l1pt.pv_pa = 0; for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) { /* Are we 16KB aligned for an L1 ? */ if (((physical_freeend - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) == 0 && kernel_l1pt.pv_pa == 0) { valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); } else { valloc_pages(kernel_pt_table[loop1], L2_TABLE_SIZE / PAGE_SIZE); ++loop1; } } /* This should never be able to happen but better confirm that. */ if (!kernel_l1pt.pv_pa || (kernel_l1pt.pv_pa & (L1_TABLE_SIZE-1)) != 0) panic("initarm: Failed to align the kernel page directory"); /* * Allocate a page for the system page mapped to V0x00000000 * This page will just contain the system vectors and can be * shared by all processes. */ alloc_pages(systempage.pv_pa, 1); /* Allocate stacks for all modes */ valloc_pages(irqstack, IRQ_STACK_SIZE); valloc_pages(abtstack, ABT_STACK_SIZE); valloc_pages(undstack, UND_STACK_SIZE); valloc_pages(kernelstack, UPAGES); /* Allocate enough pages for cleaning the Mini-Data cache. */ KASSERT(xscale_minidata_clean_size <= PAGE_SIZE); valloc_pages(minidataclean, 1); #ifdef VERBOSE_INIT_ARM printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa, irqstack.pv_va); printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa, abtstack.pv_va); printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa, undstack.pv_va); printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa, kernelstack.pv_va); #endif /* * XXX Defer this to later so that we can reclaim the memory * XXX used by the RedBoot page tables. */ alloc_pages(msgbufphys, round_page(MSGBUFSIZE) / PAGE_SIZE); /* * Ok we have allocated physical pages for the primary kernel * page tables */ #ifdef VERBOSE_INIT_ARM printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa); #endif /* * Now we start construction of the L1 page table * We start by mapping the L2 page tables into the L1. * This means that we can replace L1 mappings later on if necessary */ l1pagetable = kernel_l1pt.pv_pa; #ifdef HIGH_VECT /* Map the L2 pages tables in the L1 page table */ pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH & ~(0x00400000 - 1), &kernel_pt_table[KERNEL_PT_SYS]); #else /* Map the L2 pages tables in the L1 page table */ pmap_link_l2pt(l1pagetable, 0x00000000, &kernel_pt_table[KERNEL_PT_SYS]); #endif for (loop = 0; loop < KERNEL_PT_KERNEL_NUM; loop++) pmap_link_l2pt(l1pagetable, KERNEL_BASE + loop * 0x00400000, &kernel_pt_table[KERNEL_PT_KERNEL + loop]); for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; loop++) pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000, &kernel_pt_table[KERNEL_PT_VMDATA + loop]); #if 0 pmap_link_l2pt(l1pagetable, IQ80321_IOPXS_VBASE, &kernel_pt_table[KERNEL_PT_IOPXS]); #endif /* update the top of the kernel VM */ pmap_curmaxkvaddr = KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000); #ifdef VERBOSE_INIT_ARM printf("Mapping kernel\n"); #endif /* Now we fill in the L2 pagetable for the kernel static code/data * and the symbol table. */ { extern char etext[]; #ifdef VERBOSE_INIT_ARM extern char _end[]; #endif size_t textsize = (u_int32_t) etext - KERNEL_TEXT_BASE; size_t totalsize = esym - KERNEL_TEXT_BASE; u_int logical; #ifdef VERBOSE_INIT_ARM printf("kernelsize text %x total %x end %xesym %x\n", textsize, totalsize, _end, esym); #endif textsize = round_page(textsize); totalsize = round_page(totalsize); logical = 0x00200000; /* offset of kernel in RAM */ /* Update dump information */ cpu_kcore_hdr.kernelbase = KERNEL_BASE; cpu_kcore_hdr.kerneloffs = logical; cpu_kcore_hdr.staticsize = totalsize; logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, physical_start + logical, textsize, PROT_READ | PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, physical_start + logical, totalsize - textsize, PROT_READ | PROT_WRITE, PTE_CACHE); } #ifdef VERBOSE_INIT_ARM printf("Constructing L2 page tables\n"); #endif /* Map the stack pages */ pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa, IRQ_STACK_SIZE * PAGE_SIZE, PROT_READ | PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa, ABT_STACK_SIZE * PAGE_SIZE, PROT_READ | PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa, UND_STACK_SIZE * PAGE_SIZE, PROT_READ | PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa, UPAGES * PAGE_SIZE, PROT_READ | PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, L1_TABLE_SIZE, PROT_READ | PROT_WRITE, PTE_PAGETABLE); for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va, kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE, PROT_READ | PROT_WRITE, PTE_PAGETABLE); } /* Map the Mini-Data cache clean area. */ xscale_setup_minidata(l1pagetable, minidataclean.pv_va, minidataclean.pv_pa); /* Map the vector page. */ #ifdef HIGH_VECT pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, PROT_READ | PROT_WRITE, PTE_CACHE); #else pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa, PROT_READ | PROT_WRITE, PTE_CACHE); #endif pmap_devmap_bootstrap(l1pagetable, iq80321_devmap); /* * Give the XScale global cache clean code an appropriately * sized chunk of unmapped VA space starting at 0xff000000 * (our device mappings end before this address). */ xscale_cache_clean_addr = 0xff000000U; /* * Now we have the real page tables in place so we can switch to them. * Once this is done we will be running with the REAL kernel page * tables. */ /* * Update the physical_freestart/physical_freeend/free_pages * variables. */ { physical_freestart = physical_start - KERNEL_BASE + round_page(esym); physical_freeend = physical_end; free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE; } #ifdef VERBOSE_INIT_ARM printf("physical_freestart %x end %x\n", physical_freestart, physical_freeend); #endif /* be a client to all domains */ cpu_domains(0x55555555); /* Switch tables */ #ifdef VERBOSE_INIT_ARM printf("freestart = 0x%08lx, free_pages = %d (0x%x)\n", physical_freestart, free_pages, free_pages); printf("switching to new L1 page table @%#lx...", kernel_l1pt.pv_pa); #endif cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); setttb(kernel_l1pt.pv_pa); cpu_tlb_flushID(); cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); /* * Moved from cpu_startup() as data_abort_handler() references * this during uvm init */ proc0paddr = (struct user *)kernelstack.pv_va; proc0.p_addr = proc0paddr; #ifdef VERBOSE_INIT_ARM printf("bootstrap done.\n"); #endif #ifdef HIGH_VECT arm32_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); #else arm32_vector_init(ARM_VECTORS_LOW, ARM_VEC_ALL); #endif /* * Pages were allocated during the secondary bootstrap for the * stacks for different CPU modes. * We must now set the r13 registers in the different CPU modes to * point to these stacks. * Since the ARM stacks use STMFD etc. we must set r13 to the top end * of the stack memory. */ #ifdef VERBOSE_INIT_ARM printf("init subsystems: stacks "); #endif set_stackptr(PSR_IRQ32_MODE, irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); set_stackptr(PSR_ABT32_MODE, abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); set_stackptr(PSR_UND32_MODE, undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); /* * Well we should set a data abort handler. * Once things get going this will change as we will need a proper * handler. * Until then we will use a handler that just panics but tells us * why. * Initialisation of the vectors will just panic on a data abort. * This just fills in a slightly better one. */ #ifdef VERBOSE_INIT_ARM printf("vectors "); #endif data_abort_handler_address = (u_int)data_abort_handler; prefetch_abort_handler_address = (u_int)prefetch_abort_handler; undefined_handler_address = (u_int)undefinedinstruction_bounce; /* Initialise the undefined instruction handlers */ #ifdef VERBOSE_INIT_ARM printf("undefined "); #endif undefined_init(); /* Load memory into UVM. */ #ifdef VERBOSE_INIT_ARM printf("page "); #endif uvm_setpagesize(); /* initialize PAGE_SIZE-dependent variables */ uvm_page_physload(atop(physical_freestart), atop(physical_freeend), atop(physical_freestart), atop(physical_freeend), 0); /* Boot strap pmap telling it where the kernel page table is */ #ifdef VERBOSE_INIT_ARM printf("pmap "); #endif pmap_bootstrap((pd_entry_t *)kernel_l1pt.pv_va, KERNEL_VM_BASE, KERNEL_VM_BASE + KERNEL_VM_SIZE); /* Update dump information */ cpu_kcore_hdr.pmap_kernel_l1 = (u_int32_t)pmap_kernel()->pm_l1; cpu_kcore_hdr.pmap_kernel_l2 = (u_int32_t)&(pmap_kernel()->pm_l2); /* Setup the IRQ system */ #ifdef VERBOSE_INIT_ARM printf("irq "); #endif i80321intc_intr_init(); #ifdef VERBOSE_INIT_ARM printf("done.\n"); #endif #ifdef DDB db_machine_init(); /* Firmware doesn't load symbols. */ ddb_init(); if (boothowto & RB_KDB) Debugger(); #endif /* We return the new stack pointer address */ return(kernelstack.pv_va + USPACE_SVC_STACK_TOP); }
int iq80321_attach(device_t dev) { struct i80321_softc *sc = device_get_softc(dev); int b0u, b0l, b1u, b1l; vm_paddr_t memstart = 0; vm_size_t memsize = 0; int busno; /* * Fill in the space tag for the i80321's own devices, * and hand-craft the space handle for it (the device * was mapped during early bootstrap). */ i80321_bs_init(&i80321_bs_tag, sc); sc->sc_st = &i80321_bs_tag; sc->sc_sh = IQ80321_80321_VBASE; sc->dev = dev; sc->sc_is_host = 1; /* * Slice off a subregion for the Memory Controller -- we need it * here in order read the memory size. */ if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_MCU_BASE, VERDE_MCU_SIZE, &sc->sc_mcu_sh)) panic("%s: unable to subregion MCU registers", device_get_name(dev)); if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_ATU_BASE, VERDE_ATU_SIZE, &sc->sc_atu_sh)) panic("%s: unable to subregion ATU registers", device_get_name(dev)); /* * We have mapped the PCI I/O windows in the early * bootstrap phase. */ sc->sc_iow_vaddr = IQ80321_IOW_VBASE; /* * Check the configuration of the ATU to see if another BIOS * has configured us. If a PC BIOS didn't configure us, then: * IQ80321: BAR0 00000000.0000000c BAR1 is 00000000.8000000c. * IQ31244: BAR0 00000000.00000004 BAR1 is 00000000.0000000c. * If a BIOS has configured us, at least one of those should be * different. This is pretty fragile, but it's not clear what * would work better. */ b0l = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0x0); b0u = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0x4); b1l = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0x8); b1u = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0xc); #ifdef VERBOSE_INIT_ARM printf("i80321: BAR0 = %08x.%08x BAR1 = %08x.%08x\n", b0l,b0u, b1l, b1u ); #endif #define PCI_MAPREG_MEM_ADDR_MASK 0xfffffff0 b0l &= PCI_MAPREG_MEM_ADDR_MASK; b0u &= PCI_MAPREG_MEM_ADDR_MASK; b1l &= PCI_MAPREG_MEM_ADDR_MASK; b1u &= PCI_MAPREG_MEM_ADDR_MASK; #ifdef VERBOSE_INIT_ARM printf("i80219: BAR0 = %08x.%08x BAR1 = %08x.%08x\n", b0l,b0u, b1l, b1u ); #endif if ((b0u != b1u) || (b0l != 0) || ((b1l & ~0x80000000U) != 0)) sc->sc_is_host = 0; else sc->sc_is_host = 1; /* FIXME: i force it's */ #ifdef CPU_XSCALE_80219 sc->sc_is_host = 1; #endif i80321_sdram_bounds(sc->sc_st, sc->sc_mcu_sh, &memstart, &memsize); /* * We set up the Inbound Windows as follows: * * 0 Access to i80321 PMMRs * * 1 Reserve space for private devices * * 2 RAM access * * 3 Unused. * * This chunk needs to be customized for each IOP321 application. */ #if 0 sc->sc_iwin[0].iwin_base_lo = VERDE_PMMR_BASE; sc->sc_iwin[0].iwin_base_hi = 0; sc->sc_iwin[0].iwin_xlate = VERDE_PMMR_BASE; sc->sc_iwin[0].iwin_size = VERDE_PMMR_SIZE; #endif if (sc->sc_is_host) { /* Map PCI:Local 1:1. */ sc->sc_iwin[1].iwin_base_lo = VERDE_OUT_XLATE_MEM_WIN0_BASE | PCI_MAPREG_MEM_PREFETCHABLE_MASK | PCI_MAPREG_MEM_TYPE_64BIT; sc->sc_iwin[1].iwin_base_hi = 0; } else { sc->sc_iwin[1].iwin_base_lo = 0; sc->sc_iwin[1].iwin_base_hi = 0; } sc->sc_iwin[1].iwin_xlate = VERDE_OUT_XLATE_MEM_WIN0_BASE; sc->sc_iwin[1].iwin_size = VERDE_OUT_XLATE_MEM_WIN_SIZE; if (sc->sc_is_host) { sc->sc_iwin[2].iwin_base_lo = memstart | PCI_MAPREG_MEM_PREFETCHABLE_MASK | PCI_MAPREG_MEM_TYPE_64BIT; sc->sc_iwin[2].iwin_base_hi = 0; } else { sc->sc_iwin[2].iwin_base_lo = 0; sc->sc_iwin[2].iwin_base_hi = 0; } sc->sc_iwin[2].iwin_xlate = memstart; sc->sc_iwin[2].iwin_size = memsize; if (sc->sc_is_host) { sc->sc_iwin[3].iwin_base_lo = 0 | PCI_MAPREG_MEM_PREFETCHABLE_MASK | PCI_MAPREG_MEM_TYPE_64BIT; } else { sc->sc_iwin[3].iwin_base_lo = 0; } sc->sc_iwin[3].iwin_base_hi = 0; sc->sc_iwin[3].iwin_xlate = 0; sc->sc_iwin[3].iwin_size = 0; #ifdef VERBOSE_INIT_ARM printf("i80321: Reserve space for private devices (Inbound Window 1) \n hi:0x%08x lo:0x%08x xlate:0x%08x size:0x%08x\n", sc->sc_iwin[1].iwin_base_hi, sc->sc_iwin[1].iwin_base_lo, sc->sc_iwin[1].iwin_xlate, sc->sc_iwin[1].iwin_size ); printf("i80321: RAM access (Inbound Window 2) \n hi:0x%08x lo:0x%08x xlate:0x%08x size:0x%08x\n", sc->sc_iwin[2].iwin_base_hi, sc->sc_iwin[2].iwin_base_lo, sc->sc_iwin[2].iwin_xlate, sc->sc_iwin[2].iwin_size ); #endif /* * We set up the Outbound Windows as follows: * * 0 Access to private PCI space. * * 1 Unused. */ #define PCI_MAPREG_MEM_ADDR(x) ((x) & 0xfffffff0) sc->sc_owin[0].owin_xlate_lo = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo); sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi; /* * Set the Secondary Outbound I/O window to map * to PCI address 0 for all 64K of the I/O space. */ sc->sc_ioout_xlate = 0; i80321_attach(sc); i80321_dr.dr_sysbase = sc->sc_iwin[2].iwin_xlate; i80321_dr.dr_busbase = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo); i80321_dr.dr_len = sc->sc_iwin[2].iwin_size; dma_range_init = 1; busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR); busno = PCIXSR_BUSNO(busno); if (busno == 0xff) busno = 0; sc->sc_irq_rman.rm_type = RMAN_ARRAY; sc->sc_irq_rman.rm_descr = "i80321 IRQs"; if (rman_init(&sc->sc_irq_rman) != 0 || rman_manage_region(&sc->sc_irq_rman, 0, 25) != 0) panic("i80321_attach: failed to set up IRQ rman"); device_add_child(dev, "obio", 0); device_add_child(dev, "itimer", 0); device_add_child(dev, "iopwdog", 0); #ifndef CPU_XSCALE_80219 device_add_child(dev, "iqseg", 0); #endif device_add_child(dev, "pcib", busno); device_add_child(dev, "i80321_dma", 0); device_add_child(dev, "i80321_dma", 1); #ifndef CPU_XSCALE_80219 device_add_child(dev, "i80321_aau", 0); #endif bus_generic_probe(dev); bus_generic_attach(dev); return (0); }
void hdlg_mainbus_attach(struct device *parent, struct device *self, void *aux) { struct i80321_softc *sc = (void *) self; pcireg_t b0u, b0l, b1u, b1l; paddr_t memstart; psize_t memsize; hdlg_mainbus_found = 1; /* * Fill in the space tag for the i80321's own devices, * and hand-craft the space handle for it (the device * was mapped during early bootstrap). */ i80321_bs_init(&i80321_bs_tag, sc); sc->sc_st = &i80321_bs_tag; sc->sc_sh = HDLG_80321_VBASE; /* * Slice off a subregion for the Memory Controller -- we need it * here in order read the memory size. */ if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_MCU_BASE, VERDE_MCU_SIZE, &sc->sc_mcu_sh)) panic("%s: unable to subregion MCU registers", device_xname(&sc->sc_dev)); if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_ATU_BASE, VERDE_ATU_SIZE, &sc->sc_atu_sh)) panic("%s: unable to subregion ATU registers", device_xname(&sc->sc_dev)); /* * We have mapped the PCI I/O windows in the early bootstrap phase. */ sc->sc_iow_vaddr = HDLG_IOW_VBASE; /* * Check the configuration of the ATU to see if another BIOS * has configured us. If a PC BIOS didn't configure us, then: * IQ80321: BAR0 00000000.0000000c BAR1 is 00000000.8000000c. * IQ31244: BAR0 00000000.00000004 BAR1 is 00000000.0000000c. * If a BIOS has configured us, at least one of those should be * different. This is pretty fragile, but it's not clear what * would work better. */ b0l = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCI_MAPREG_START+0x0); b0u = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCI_MAPREG_START+0x4); b1l = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCI_MAPREG_START+0x8); b1u = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCI_MAPREG_START+0xc); b0l &= PCI_MAPREG_MEM_ADDR_MASK; b0u &= PCI_MAPREG_MEM_ADDR_MASK; b1l &= PCI_MAPREG_MEM_ADDR_MASK; b1u &= PCI_MAPREG_MEM_ADDR_MASK; if ((b0u != b1u) || (b0l != 0) || ((b1l & ~0x80000000U) != 0)) sc->sc_is_host = 0; else sc->sc_is_host = 1; aprint_naive(": i80219 I/O Processor\n"); aprint_normal(": i80219 I/O Processor, acting as PCI %s\n", sc->sc_is_host ? "host" : "slave"); i80321_sdram_bounds(sc->sc_st, sc->sc_mcu_sh, &memstart, &memsize); /* * We set up the Inbound Windows as follows: * * 0 Access to i80219 PMMRs * * 1 Reserve space for private devices * * 2 RAM access * * 3 Unused. * * This chunk needs to be customized for each IOP321 application. */ #if 0 sc->sc_iwin[0].iwin_base_lo = VERDE_PMMR_BASE; sc->sc_iwin[0].iwin_base_hi = 0; sc->sc_iwin[0].iwin_xlate = VERDE_PMMR_BASE; sc->sc_iwin[0].iwin_size = VERDE_PMMR_SIZE; #endif if (sc->sc_is_host) { /* Map PCI:Local 1:1. */ sc->sc_iwin[1].iwin_base_lo = VERDE_OUT_XLATE_MEM_WIN0_BASE | PCI_MAPREG_MEM_PREFETCHABLE_MASK | PCI_MAPREG_MEM_TYPE_64BIT; sc->sc_iwin[1].iwin_base_hi = 0; } else { sc->sc_iwin[1].iwin_base_lo = 0; sc->sc_iwin[1].iwin_base_hi = 0; } sc->sc_iwin[1].iwin_xlate = VERDE_OUT_XLATE_MEM_WIN0_BASE; sc->sc_iwin[1].iwin_size = VERDE_OUT_XLATE_MEM_WIN_SIZE; if (sc->sc_is_host) { sc->sc_iwin[2].iwin_base_lo = memstart | PCI_MAPREG_MEM_PREFETCHABLE_MASK | PCI_MAPREG_MEM_TYPE_64BIT; sc->sc_iwin[2].iwin_base_hi = 0; } else { sc->sc_iwin[2].iwin_base_lo = 0; sc->sc_iwin[2].iwin_base_hi = 0; } sc->sc_iwin[2].iwin_xlate = memstart; sc->sc_iwin[2].iwin_size = memsize; if (sc->sc_is_host) { sc->sc_iwin[3].iwin_base_lo = 0 | PCI_MAPREG_MEM_PREFETCHABLE_MASK | PCI_MAPREG_MEM_TYPE_64BIT; } else { sc->sc_iwin[3].iwin_base_lo = 0; } sc->sc_iwin[3].iwin_base_hi = 0; sc->sc_iwin[3].iwin_xlate = 0; sc->sc_iwin[3].iwin_size = 0; /* * We set up the Outbound Windows as follows: * * 0 Access to private PCI space. * * 1 Unused. */ sc->sc_owin[0].owin_xlate_lo = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo); sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi; /* * Set the Secondary Outbound I/O window to map * to PCI address 0 for all 64K of the I/O space. */ sc->sc_ioout_xlate = 0; sc->sc_ioout_xlate_offset = 0x1000; /* * Initialize the interrupt part of our PCI chipset tag. */ hdlg_pci_init(&sc->sc_pci_chipset, sc); i80321_attach(sc); }
void * initarm(struct arm_boot_params *abp) { struct pv_addr kernel_l1pt; struct pv_addr dpcpu; int loop, i; u_int l1pagetable; vm_offset_t freemempos; vm_offset_t freemem_pt; vm_offset_t afterkern; vm_offset_t freemem_after; vm_offset_t lastaddr; uint32_t memsize, memstart; lastaddr = parse_boot_param(abp); set_cpufuncs(); pcpu_init(pcpup, 0, sizeof(struct pcpu)); PCPU_SET(curthread, &thread0); /* Do basic tuning, hz etc */ init_param1(); freemempos = 0xa0200000; /* Define a macro to simplify memory allocation */ #define valloc_pages(var, np) \ alloc_pages((var).pv_pa, (np)); \ (var).pv_va = (var).pv_pa + 0x20000000; #define alloc_pages(var, np) \ freemempos -= (np * PAGE_SIZE); \ (var) = freemempos; \ memset((char *)(var), 0, ((np) * PAGE_SIZE)); while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0) freemempos -= PAGE_SIZE; valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) { valloc_pages(kernel_pt_table[loop], L2_TABLE_SIZE / PAGE_SIZE); } else { kernel_pt_table[loop].pv_pa = freemempos + (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) * L2_TABLE_SIZE_REAL; kernel_pt_table[loop].pv_va = kernel_pt_table[loop].pv_pa + 0x20000000; } } freemem_pt = freemempos; freemempos = 0xa0100000; /* * Allocate a page for the system page mapped to V0x00000000 * This page will just contain the system vectors and can be * shared by all processes. */ valloc_pages(systempage, 1); /* Allocate dynamic per-cpu area. */ valloc_pages(dpcpu, DPCPU_SIZE / PAGE_SIZE); dpcpu_init((void *)dpcpu.pv_va, 0); /* Allocate stacks for all modes */ valloc_pages(irqstack, IRQ_STACK_SIZE); valloc_pages(abtstack, ABT_STACK_SIZE); valloc_pages(undstack, UND_STACK_SIZE); valloc_pages(kernelstack, KSTACK_PAGES); alloc_pages(minidataclean.pv_pa, 1); valloc_pages(msgbufpv, round_page(msgbufsize) / PAGE_SIZE); #ifdef ARM_USE_SMALL_ALLOC freemempos -= PAGE_SIZE; freemem_pt = trunc_page(freemem_pt); freemem_after = freemempos - ((freemem_pt - 0xa0100000) / PAGE_SIZE) * sizeof(struct arm_small_page); arm_add_smallalloc_pages((void *)(freemem_after + 0x20000000) , (void *)0xc0100000, freemem_pt - 0xa0100000, 1); freemem_after -= ((freemem_after - 0xa0001000) / PAGE_SIZE) * sizeof(struct arm_small_page); arm_add_smallalloc_pages((void *)(freemem_after + 0x20000000) , (void *)0xc0001000, trunc_page(freemem_after) - 0xa0001000, 0); freemempos = trunc_page(freemem_after); freemempos -= PAGE_SIZE; #endif /* * Allocate memory for the l1 and l2 page tables. The scheme to avoid * wasting memory by allocating the l1pt on the first 16k memory was * taken from NetBSD rpc_machdep.c. NKPT should be greater than 12 for * this to work (which is supposed to be the case). */ /* * Now we start construction of the L1 page table * We start by mapping the L2 page tables into the L1. * This means that we can replace L1 mappings later on if necessary */ l1pagetable = kernel_l1pt.pv_va; /* Map the L2 pages tables in the L1 page table */ pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH & ~(0x00100000 - 1), &kernel_pt_table[KERNEL_PT_SYS]); pmap_link_l2pt(l1pagetable, IQ80321_IOPXS_VBASE, &kernel_pt_table[KERNEL_PT_IOPXS]); pmap_link_l2pt(l1pagetable, KERNBASE, &kernel_pt_table[KERNEL_PT_BEFOREKERN]); pmap_map_chunk(l1pagetable, KERNBASE, SDRAM_START, 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, SDRAM_START + 0x100000, 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); pmap_map_chunk(l1pagetable, KERNBASE + 0x200000, SDRAM_START + 0x200000, (((uint32_t)(lastaddr) - KERNBASE - 0x200000) + L1_S_SIZE) & ~(L1_S_SIZE - 1), VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); freemem_after = ((int)lastaddr + PAGE_SIZE) & ~(PAGE_SIZE - 1); afterkern = round_page(((vm_offset_t)lastaddr + L1_S_SIZE) & ~(L1_S_SIZE - 1)); for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) { pmap_link_l2pt(l1pagetable, afterkern + i * 0x00100000, &kernel_pt_table[KERNEL_PT_AFKERNEL + i]); } pmap_map_entry(l1pagetable, afterkern, minidataclean.pv_pa, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); #ifdef ARM_USE_SMALL_ALLOC if ((freemem_after + 2 * PAGE_SIZE) <= afterkern) { arm_add_smallalloc_pages((void *)(freemem_after), (void*)(freemem_after + PAGE_SIZE), afterkern - (freemem_after + PAGE_SIZE), 0); } #endif /* Map the Mini-Data cache clean area. */ xscale_setup_minidata(l1pagetable, afterkern, minidataclean.pv_pa); /* Map the vector page. */ pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); pmap_devmap_bootstrap(l1pagetable, iq80321_devmap); /* * Give the XScale global cache clean code an appropriately * sized chunk of unmapped VA space starting at 0xff000000 * (our device mappings end before this address). */ xscale_cache_clean_addr = 0xff000000U; cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); setttb(kernel_l1pt.pv_pa); cpu_tlb_flushID(); cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); /* * Pages were allocated during the secondary bootstrap for the * stacks for different CPU modes. * We must now set the r13 registers in the different CPU modes to * point to these stacks. * Since the ARM stacks use STMFD etc. we must set r13 to the top end * of the stack memory. */ set_stackptr(PSR_IRQ32_MODE, irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); set_stackptr(PSR_ABT32_MODE, abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); set_stackptr(PSR_UND32_MODE, undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); /* * We must now clean the cache again.... * Cleaning may be done by reading new data to displace any * dirty data in the cache. This will have happened in setttb() * but since we are boot strapping the addresses used for the read * may have just been remapped and thus the cache could be out * of sync. A re-clean after the switch will cure this. * After booting there are no gross relocations of the kernel thus * this problem will not occur after initarm(). */ cpu_idcache_wbinv_all(); /* * Fetch the SDRAM start/size from the i80321 SDRAM configration * registers. */ i80321_calibrate_delay(); i80321_sdram_bounds(&obio_bs_tag, IQ80321_80321_VBASE + VERDE_MCU_BASE, &memstart, &memsize); physmem = memsize / PAGE_SIZE; cninit(); /* Set stack for exception handlers */ data_abort_handler_address = (u_int)data_abort_handler; prefetch_abort_handler_address = (u_int)prefetch_abort_handler; undefined_handler_address = (u_int)undefinedinstruction_bounce; undefined_init(); init_proc0(kernelstack.pv_va); /* Enable MMU, I-cache, D-cache, write buffer. */ arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); pmap_curmaxkvaddr = afterkern + PAGE_SIZE; /* * ARM_USE_SMALL_ALLOC uses dump_avail, so it must be filled before * calling pmap_bootstrap. */ dump_avail[0] = 0xa0000000; dump_avail[1] = 0xa0000000 + memsize; dump_avail[2] = 0; dump_avail[3] = 0; pmap_bootstrap(pmap_curmaxkvaddr, 0xd0000000, &kernel_l1pt); msgbufp = (void*)msgbufpv.pv_va; msgbufinit(msgbufp, msgbufsize); mutex_init(); i = 0; #ifdef ARM_USE_SMALL_ALLOC phys_avail[i++] = 0xa0000000; phys_avail[i++] = 0xa0001000; /* *XXX: Gross hack to get our * pages in the vm_page_array . */ #endif phys_avail[i++] = round_page(virtual_avail - KERNBASE + SDRAM_START); phys_avail[i++] = trunc_page(0xa0000000 + memsize - 1); phys_avail[i++] = 0; phys_avail[i] = 0; init_param2(physmem); kdb_init(); return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - sizeof(struct pcb))); }