at91_machdep.c revision 163521
152284Sobrien/*-
252284Sobrien * Copyright (c) 1994-1998 Mark Brinicombe.
352284Sobrien * Copyright (c) 1994 Brini.
452284Sobrien * All rights reserved.
552284Sobrien *
652284Sobrien * This code is derived from software written for Brini by Mark Brinicombe
752284Sobrien *
852284Sobrien * Redistribution and use in source and binary forms, with or without
952284Sobrien * modification, are permitted provided that the following conditions
1052284Sobrien * are met:
1152284Sobrien * 1. Redistributions of source code must retain the above copyright
1252284Sobrien *    notice, this list of conditions and the following disclaimer.
1352284Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1452284Sobrien *    notice, this list of conditions and the following disclaimer in the
1552284Sobrien *    documentation and/or other materials provided with the distribution.
1652284Sobrien * 3. All advertising materials mentioning features or use of this software
1752284Sobrien *    must display the following acknowledgement:
1852284Sobrien *      This product includes software developed by Brini.
1952284Sobrien * 4. The name of the company nor the name of the author may be used to
2052284Sobrien *    endorse or promote products derived from this software without specific
2152284Sobrien *    prior written permission.
2252284Sobrien *
2352284Sobrien * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
2452284Sobrien * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2552284Sobrien * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2652284Sobrien * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2752284Sobrien * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2852284Sobrien * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2952284Sobrien * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3052284Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3152284Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3252284Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3352284Sobrien * SUCH DAMAGE.
3452284Sobrien *
3552284Sobrien * RiscBSD kernel project
3652284Sobrien *
3752284Sobrien * machdep.c
3852284Sobrien *
3952284Sobrien * Machine dependant functions for kernel setup
4052284Sobrien *
4152284Sobrien * This file needs a lot of work.
4252284Sobrien *
4352284Sobrien * Created      : 17/09/94
4452284Sobrien */
4552284Sobrien
4652284Sobrien#include "opt_msgbuf.h"
4752284Sobrien#include "opt_ddb.h"
4852284Sobrien#include "opt_at91.h"
4952284Sobrien
5052284Sobrien#include <sys/cdefs.h>
5152284Sobrien__FBSDID("$FreeBSD: head/sys/arm/at91/kb920x_machdep.c 163521 2006-10-20 07:03:57Z imp $");
5252284Sobrien
5352284Sobrien#define _ARM32_BUS_DMA_PRIVATE
5452284Sobrien#include <sys/param.h>
5552284Sobrien#include <sys/systm.h>
5652284Sobrien#include <sys/sysproto.h>
5752284Sobrien#include <sys/signalvar.h>
5852284Sobrien#include <sys/imgact.h>
5952284Sobrien#include <sys/kernel.h>
6052284Sobrien#include <sys/ktr.h>
6152284Sobrien#include <sys/linker.h>
6252284Sobrien#include <sys/lock.h>
6352284Sobrien#include <sys/malloc.h>
6452284Sobrien#include <sys/mutex.h>
6552284Sobrien#include <sys/pcpu.h>
6652284Sobrien#include <sys/proc.h>
6752284Sobrien#include <sys/ptrace.h>
6852284Sobrien#include <sys/cons.h>
6952284Sobrien#include <sys/bio.h>
7052284Sobrien#include <sys/bus.h>
7152284Sobrien#include <sys/buf.h>
7252284Sobrien#include <sys/exec.h>
7352284Sobrien#include <sys/kdb.h>
7452284Sobrien#include <sys/msgbuf.h>
7552284Sobrien#include <machine/reg.h>
7652284Sobrien#include <machine/cpu.h>
7752284Sobrien
7852284Sobrien#include <vm/vm.h>
7952284Sobrien#include <vm/pmap.h>
8052284Sobrien#include <vm/vm.h>
8152284Sobrien#include <vm/vm_object.h>
8252284Sobrien#include <vm/vm_page.h>
8352284Sobrien#include <vm/vm_pager.h>
8452284Sobrien#include <vm/vm_map.h>
8552284Sobrien#include <vm/vnode_pager.h>
8652284Sobrien#include <machine/pmap.h>
8752284Sobrien#include <machine/vmparam.h>
8852284Sobrien#include <machine/pcb.h>
8952284Sobrien#include <machine/undefined.h>
9052284Sobrien#include <machine/machdep.h>
9152284Sobrien#include <machine/metadata.h>
9252284Sobrien#include <machine/armreg.h>
9352284Sobrien#include <machine/bus.h>
9452284Sobrien#include <sys/reboot.h>
9552284Sobrien
9652284Sobrien#include <arm/at91/at91rm92reg.h>
9752284Sobrien#include <arm/at91/at91_piovar.h>
9852284Sobrien#include <arm/at91/at91_pio_rm9200.h>
9952284Sobrien
10052284Sobrien#define KERNEL_PT_SYS		0	/* Page table for mapping proc0 zero page */
10152284Sobrien#define KERNEL_PT_KERN		1
10252284Sobrien#define KERNEL_PT_KERN_NUM	22
10352284Sobrien#define KERNEL_PT_AFKERNEL	KERNEL_PT_KERN + KERNEL_PT_KERN_NUM	/* L2 table for mapping after kernel */
10452284Sobrien#define	KERNEL_PT_AFKERNEL_NUM	5
10552284Sobrien
10652284Sobrien/* this should be evenly divisable by PAGE_SIZE / L2_TABLE_SIZE_REAL (or 4) */
10752284Sobrien#define NUM_KERNEL_PTS		(KERNEL_PT_AFKERNEL + KERNEL_PT_AFKERNEL_NUM)
10852284Sobrien
10952284Sobrien/* Define various stack sizes in pages */
11052284Sobrien#define IRQ_STACK_SIZE	1
11152284Sobrien#define ABT_STACK_SIZE	1
11252284Sobrien#define UND_STACK_SIZE	1
11352284Sobrien
11452284Sobrienextern u_int data_abort_handler_address;
11552284Sobrienextern u_int prefetch_abort_handler_address;
11652284Sobrienextern u_int undefined_handler_address;
11752284Sobrien
11852284Sobrienstruct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
11952284Sobrien
12052284Sobrienextern void *_end;
12152284Sobrien
12252284Sobrienextern int *end;
12352284Sobrien
12452284Sobrienstruct pcpu __pcpu;
12552284Sobrienstruct pcpu *pcpup = &__pcpu;
12652284Sobrien
12752284Sobrien/* Physical and virtual addresses for some global pages */
12852284Sobrien
12952284Sobrienvm_paddr_t phys_avail[10];
13052284Sobrienvm_paddr_t dump_avail[4];
13152284Sobrienvm_offset_t physical_pages;
13252284Sobrienvm_offset_t clean_sva, clean_eva;
13352284Sobrien
13452284Sobrienstruct pv_addr systempage;
13552284Sobrienstruct pv_addr msgbufpv;
13652284Sobrienstruct pv_addr irqstack;
13752284Sobrienstruct pv_addr undstack;
13852284Sobrienstruct pv_addr abtstack;
13952284Sobrienstruct pv_addr kernelstack;
14052284Sobrienstruct pv_addr minidataclean;
14152284Sobrien
14252284Sobrienstatic struct trapframe proc0_tf;
14352284Sobrien
14452284Sobrien/* Static device mappings. */
14552284Sobrienstatic const struct pmap_devmap kb920x_devmap[] = {
14652284Sobrien	/*
14752284Sobrien	 * Map the on-board devices VA == PA so that we can access them
14852284Sobrien	 * with the MMU on or off.
14952284Sobrien	 */
15052284Sobrien	{
15152284Sobrien		/*
15252284Sobrien		 * This at least maps the interrupt controller, the UART
15352284Sobrien		 * and the timer. Other devices should use newbus to
15452284Sobrien		 * map their memory anyway.
15552284Sobrien		 */
15652284Sobrien		0xdff00000,
15752284Sobrien		0xfff00000,
15852284Sobrien		0x100000,
15952284Sobrien		VM_PROT_READ|VM_PROT_WRITE,
16052284Sobrien		PTE_NOCACHE,
16152284Sobrien	},
16252284Sobrien	/*
16352284Sobrien	 * We can't just map the OHCI registers VA == PA, because
16452284Sobrien	 * AT91RM92_OHCI_BASE belongs to the userland address space.
16552284Sobrien	 * We could just choose a different virtual address, but a better
16652284Sobrien	 * solution would probably be to just use pmap_mapdev() to allocate
16752284Sobrien	 * KVA, as we don't need the OHCI controller before the vm
16852284Sobrien	 * initialization is done. However, the AT91 resource allocation
16952284Sobrien	 * system doesn't know how to use pmap_mapdev() yet.
17052284Sobrien	 */
17152284Sobrien#if 0
17252284Sobrien	{
17352284Sobrien		/*
17452284Sobrien		 * Add the ohci controller, and anything else that might be
17552284Sobrien		 * on this chip select for a VA/PA mapping.
17652284Sobrien		 */
17752284Sobrien		AT91RM92_OHCI_BASE,
17852284Sobrien		AT91RM92_OHCI_BASE,
17952284Sobrien		AT91RM92_OHCI_SIZE,
18052284Sobrien		VM_PROT_READ|VM_PROT_WRITE,
18152284Sobrien		PTE_NOCACHE,
18252284Sobrien	},
18352284Sobrien#endif
18452284Sobrien	{
18552284Sobrien		0,
18652284Sobrien		0,
18752284Sobrien		0,
18852284Sobrien		0,
18952284Sobrien		0,
19052284Sobrien	}
19152284Sobrien};
19252284Sobrien
19352284Sobrien#define SDRAM_START 0xa0000000
19452284Sobrien
19552284Sobrien#ifdef DDB
19652284Sobrienextern vm_offset_t ksym_start, ksym_end;
19752284Sobrien#endif
19852284Sobrien
19952284Sobrienstatic long
20052284Sobrienramsize(void)
20152284Sobrien{
20252284Sobrien	uint32_t *SDRAMC = (uint32_t *)(AT91RM92_BASE + AT91RM92_SDRAMC_BASE);
20352284Sobrien	uint32_t cr, mr;
20452284Sobrien	int banks, rows, cols, bw;
20552284Sobrien
20652284Sobrien	cr = SDRAMC[AT91RM92_SDRAMC_CR / 4];
20752284Sobrien	mr = SDRAMC[AT91RM92_SDRAMC_MR / 4];
20852284Sobrien	bw = (mr & AT91RM92_SDRAMC_MR_DBW_16) ? 1 : 2;
20952284Sobrien	banks = (cr & AT91RM92_SDRAMC_CR_NB_4) ? 2 : 1;
21052284Sobrien	rows = ((cr & AT91RM92_SDRAMC_CR_NR_MASK) >> 2) + 11;
21152284Sobrien	cols = (cr & AT91RM92_SDRAMC_CR_NC_MASK) + 8;
21252284Sobrien	return (1 << (cols + rows + banks + bw));
21352284Sobrien}
21452284Sobrien
21552284Sobrienstatic long
21652284Sobrienboard_init(void)
21752284Sobrien{
21852284Sobrien	/*
21952284Sobrien	 * Since the USART supprots RS-485 multidrop mode, it allows the
22052284Sobrien	 * TX pins to float.  However, for RS-232 operations, we don't want
22152284Sobrien	 * these pins to float.  Instead, they should be pulled up to avoid
22252284Sobrien	 * mismatches.  Linux does something similar when it configures the
22352284Sobrien	 * TX lines.  This implies that we also allow the RX lines to float
22452284Sobrien	 * rather than be in the state they are left in by the boot loader.
22552284Sobrien	 * Since they are input pins, I think that this is the right thing
22652284Sobrien	 * to do.
22752284Sobrien	 */
22852284Sobrien
22952284Sobrien	/* PIOA's A periph: Turn USART 0 and 2's TX/RX pins */
23052284Sobrien	at91_pio_use_periph_a(AT91RM92_PIOA_BASE,
23152284Sobrien	    AT91C_PA18_RXD0 | AT91C_PA22_RXD2, 0);
23252284Sobrien	at91_pio_use_periph_a(AT91RM92_PIOA_BASE,
23352284Sobrien	    AT91C_PA17_TXD0 | AT91C_PA23_TXD2, 1);
23452284Sobrien	/* PIOA's B periph: Turn USART 3's TX/RX pins */
23552284Sobrien	at91_pio_use_periph_b(AT91RM92_PIOA_BASE, AT91C_PA6_RXD3, 0);
23652284Sobrien	at91_pio_use_periph_b(AT91RM92_PIOA_BASE, AT91C_PA5_TXD3, 1);
23752284Sobrien#ifdef AT91_TSC
23852284Sobrien	/* We're using TC0's A1 and A2 input */
23952284Sobrien	at91_pio_use_periph_b(AT91RM92_PIOA_BASE,
24052284Sobrien	    AT91C_PA19_TIOA1 | AT91C_PA21_TIOA2, 0);
24152284Sobrien#endif
24252284Sobrien	/* PIOB's A periph: Turn USART 1's TX/RX pins */
24352284Sobrien	at91_pio_use_periph_a(AT91RM92_PIOB_BASE, AT91C_PB21_RXD1, 0);
24452284Sobrien	at91_pio_use_periph_a(AT91RM92_PIOB_BASE, AT91C_PB20_TXD1, 1);
24552284Sobrien
24652284Sobrien	/* Pin assignment */
24752284Sobrien#ifdef AT91_TSC
24852284Sobrien	/* Assert PA24 low -- talk to rubidium */
24952284Sobrien	at91_pio_use_gpio(AT91RM92_PIOA_BASE, AT91C_PIO_PA24);
25052284Sobrien	at91_pio_gpio_output(AT91RM92_PIOA_BASE, AT91C_PIO_PA24, 0);
25152284Sobrien	at91_pio_gpio_clear(AT91RM92_PIOA_BASE, AT91C_PIO_PA24);
25252284Sobrien	at91_pio_use_gpio(AT91RM92_PIOB_BASE,
25352284Sobrien	    AT91C_PIO_PB16 | AT91C_PIO_PB17 | AT91C_PIO_PB18 | AT91C_PIO_PB19);
25452284Sobrien#endif
25552284Sobrien
25652284Sobrien	return (ramsize());
25752284Sobrien}
25852284Sobrien
25952284Sobrienvoid *
26052284Sobrieninitarm(void *arg, void *arg2)
26152284Sobrien{
26252284Sobrien	struct pv_addr  kernel_l1pt;
26352284Sobrien	int loop;
26452284Sobrien	u_int l1pagetable;
26552284Sobrien	vm_offset_t freemempos;
26652284Sobrien	vm_offset_t afterkern;
26752284Sobrien	int i;
26852284Sobrien	uint32_t fake_preload[35];
26952284Sobrien	uint32_t memsize;
27052284Sobrien	vm_offset_t lastaddr;
27152284Sobrien#ifdef DDB
27252284Sobrien	vm_offset_t zstart = 0, zend = 0;
27352284Sobrien#endif
27452284Sobrien
27552284Sobrien	i = 0;
27652284Sobrien
27752284Sobrien	set_cpufuncs();
27852284Sobrien
27952284Sobrien	fake_preload[i++] = MODINFO_NAME;
28052284Sobrien	fake_preload[i++] = strlen("elf kernel") + 1;
28152284Sobrien	strcpy((char*)&fake_preload[i++], "elf kernel");
28252284Sobrien	i += 2;
28352284Sobrien	fake_preload[i++] = MODINFO_TYPE;
28452284Sobrien	fake_preload[i++] = strlen("elf kernel") + 1;
28552284Sobrien	strcpy((char*)&fake_preload[i++], "elf kernel");
28652284Sobrien	i += 2;
28752284Sobrien	fake_preload[i++] = MODINFO_ADDR;
28852284Sobrien	fake_preload[i++] = sizeof(vm_offset_t);
28952284Sobrien	fake_preload[i++] = KERNBASE;
29052284Sobrien	fake_preload[i++] = MODINFO_SIZE;
29152284Sobrien	fake_preload[i++] = sizeof(uint32_t);
29252284Sobrien	fake_preload[i++] = (uint32_t)&end - KERNBASE;
29352284Sobrien#ifdef DDB
29452284Sobrien	if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) {
29552284Sobrien		fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM;
29652284Sobrien		fake_preload[i++] = sizeof(vm_offset_t);
29752284Sobrien		fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 4);
29852284Sobrien		fake_preload[i++] = MODINFO_METADATA|MODINFOMD_ESYM;
29952284Sobrien		fake_preload[i++] = sizeof(vm_offset_t);
30052284Sobrien		fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 8);
30152284Sobrien		lastaddr = *(uint32_t *)(KERNVIRTADDR + 8);
30252284Sobrien		zend = lastaddr;
30352284Sobrien		zstart = *(uint32_t *)(KERNVIRTADDR + 4);
30452284Sobrien		ksym_start = zstart;
30552284Sobrien		ksym_end = zend;
30652284Sobrien	} else
30752284Sobrien#endif
30852284Sobrien		lastaddr = (vm_offset_t)&end;
30952284Sobrien
31052284Sobrien	fake_preload[i++] = 0;
31152284Sobrien	fake_preload[i] = 0;
31252284Sobrien	preload_metadata = (void *)fake_preload;
31352284Sobrien
31452284Sobrien
31552284Sobrien	pcpu_init(pcpup, 0, sizeof(struct pcpu));
31652284Sobrien	PCPU_SET(curthread, &thread0);
31752284Sobrien
31852284Sobrien#define KERNEL_TEXT_BASE (KERNBASE)
31952284Sobrien	freemempos = (lastaddr + PAGE_MASK) & ~PAGE_MASK;
32052284Sobrien	/* Define a macro to simplify memory allocation */
32152284Sobrien#define valloc_pages(var, np)                   \
32252284Sobrien	alloc_pages((var).pv_va, (np));         \
32352284Sobrien	(var).pv_pa = (var).pv_va + (KERNPHYSADDR - KERNVIRTADDR);
32452284Sobrien
32552284Sobrien#define alloc_pages(var, np)			\
32652284Sobrien	(var) = freemempos;		\
32752284Sobrien	freemempos += (np * PAGE_SIZE);		\
32852284Sobrien	memset((char *)(var), 0, ((np) * PAGE_SIZE));
32952284Sobrien
33052284Sobrien	while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0)
33152284Sobrien		freemempos += PAGE_SIZE;
33252284Sobrien	valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
33352284Sobrien	for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
33452284Sobrien		if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
33552284Sobrien			valloc_pages(kernel_pt_table[loop],
33652284Sobrien			    L2_TABLE_SIZE / PAGE_SIZE);
33752284Sobrien		} else {
33852284Sobrien			kernel_pt_table[loop].pv_va = freemempos -
33952284Sobrien			    (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) *
34052284Sobrien			    L2_TABLE_SIZE_REAL;
34152284Sobrien			kernel_pt_table[loop].pv_pa =
34252284Sobrien			    kernel_pt_table[loop].pv_va - KERNVIRTADDR +
34352284Sobrien			    KERNPHYSADDR;
34452284Sobrien		}
34552284Sobrien		i++;
34652284Sobrien	}
34752284Sobrien	/*
34852284Sobrien	 * Allocate a page for the system page mapped to V0x00000000
34952284Sobrien	 * This page will just contain the system vectors and can be
35052284Sobrien	 * shared by all processes.
35152284Sobrien	 */
35252284Sobrien	valloc_pages(systempage, 1);
35352284Sobrien
35452284Sobrien	/* Allocate stacks for all modes */
35552284Sobrien	valloc_pages(irqstack, IRQ_STACK_SIZE);
35652284Sobrien	valloc_pages(abtstack, ABT_STACK_SIZE);
35752284Sobrien	valloc_pages(undstack, UND_STACK_SIZE);
35852284Sobrien	valloc_pages(kernelstack, KSTACK_PAGES);
35952284Sobrien	alloc_pages(minidataclean.pv_pa, 1);
36052284Sobrien	valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE);
36152284Sobrien	/*
36252284Sobrien	 * Now we start construction of the L1 page table
36352284Sobrien	 * We start by mapping the L2 page tables into the L1.
36452284Sobrien	 * This means that we can replace L1 mappings later on if necessary
36552284Sobrien	 */
36652284Sobrien	l1pagetable = kernel_l1pt.pv_va;
36752284Sobrien
36852284Sobrien	/* Map the L2 pages tables in the L1 page table */
36952284Sobrien	pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH,
37052284Sobrien	    &kernel_pt_table[KERNEL_PT_SYS]);
37152284Sobrien	for (i = 0; i < KERNEL_PT_KERN_NUM; i++)
37252284Sobrien		pmap_link_l2pt(l1pagetable, KERNBASE + i * 0x100000,
37352284Sobrien		    &kernel_pt_table[KERNEL_PT_KERN + i]);
37452284Sobrien	pmap_map_chunk(l1pagetable, KERNBASE, KERNPHYSADDR,
37552284Sobrien	   (((uint32_t)(lastaddr) - KERNBASE) + PAGE_SIZE) & ~(PAGE_SIZE - 1),
37652284Sobrien	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
37752284Sobrien	afterkern = round_page((lastaddr + L1_S_SIZE) & ~(L1_S_SIZE
37852284Sobrien	    - 1));
37952284Sobrien	for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) {
38052284Sobrien		pmap_link_l2pt(l1pagetable, afterkern + i * 0x00100000,
38152284Sobrien		    &kernel_pt_table[KERNEL_PT_AFKERNEL + i]);
38252284Sobrien	}
38352284Sobrien	pmap_map_entry(l1pagetable, afterkern, minidataclean.pv_pa,
38452284Sobrien	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
38552284Sobrien
38652284Sobrien
38752284Sobrien	/* Map the vector page. */
38852284Sobrien	pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
38952284Sobrien	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
39052284Sobrien	/* Map the stack pages */
39152284Sobrien	pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa,
39252284Sobrien	    IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
39352284Sobrien	pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa,
39452284Sobrien	    ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
39552284Sobrien	pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa,
39652284Sobrien	    UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
39752284Sobrien	pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa,
39852284Sobrien	    KSTACK_PAGES * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
39952284Sobrien
40052284Sobrien	pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
40152284Sobrien	    L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
40252284Sobrien	pmap_map_chunk(l1pagetable, msgbufpv.pv_va, msgbufpv.pv_pa,
40352284Sobrien	    MSGBUF_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
40452284Sobrien
40552284Sobrien
40652284Sobrien	for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
40752284Sobrien		pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va,
40852284Sobrien		    kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE,
40952284Sobrien		    VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
41052284Sobrien	}
41152284Sobrien
41252284Sobrien	pmap_devmap_bootstrap(l1pagetable, kb920x_devmap);
41352284Sobrien	cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT);
41452284Sobrien	setttb(kernel_l1pt.pv_pa);
41552284Sobrien	cpu_tlb_flushID();
41652284Sobrien	cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2));
41752284Sobrien	cninit();
41852284Sobrien	memsize = board_init();
41952284Sobrien	physmem = memsize / PAGE_SIZE;
42052284Sobrien
42152284Sobrien	/*
42252284Sobrien	 * Pages were allocated during the secondary bootstrap for the
42352284Sobrien	 * stacks for different CPU modes.
42452284Sobrien	 * We must now set the r13 registers in the different CPU modes to
42552284Sobrien	 * point to these stacks.
42652284Sobrien	 * Since the ARM stacks use STMFD etc. we must set r13 to the top end
42752284Sobrien	 * of the stack memory.
42852284Sobrien	 */
42952284Sobrien
43052284Sobrien	cpu_control(CPU_CONTROL_MMU_ENABLE, CPU_CONTROL_MMU_ENABLE);
43152284Sobrien	set_stackptr(PSR_IRQ32_MODE,
43252284Sobrien	    irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
43352284Sobrien	set_stackptr(PSR_ABT32_MODE,
43452284Sobrien	    abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
43552284Sobrien	set_stackptr(PSR_UND32_MODE,
43652284Sobrien	    undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);
43752284Sobrien
43852284Sobrien
43952284Sobrien
44052284Sobrien	/*
44152284Sobrien	 * We must now clean the cache again....
44252284Sobrien	 * Cleaning may be done by reading new data to displace any
44352284Sobrien	 * dirty data in the cache. This will have happened in setttb()
44452284Sobrien	 * but since we are boot strapping the addresses used for the read
44552284Sobrien	 * may have just been remapped and thus the cache could be out
44652284Sobrien	 * of sync. A re-clean after the switch will cure this.
44752284Sobrien	 * After booting there are no gross reloations of the kernel thus
44852284Sobrien	 * this problem will not occur after initarm().
44952284Sobrien	 */
45052284Sobrien	cpu_idcache_wbinv_all();
45152284Sobrien
45252284Sobrien	/* Set stack for exception handlers */
45352284Sobrien
45452284Sobrien	data_abort_handler_address = (u_int)data_abort_handler;
45552284Sobrien	prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
45652284Sobrien	undefined_handler_address = (u_int)undefinedinstruction_bounce;
45752284Sobrien	undefined_init();
45852284Sobrien
45952284Sobrien	proc_linkup(&proc0, &ksegrp0, &thread0);
46052284Sobrien	thread0.td_kstack = kernelstack.pv_va;
46152284Sobrien	thread0.td_pcb = (struct pcb *)
46252284Sobrien		(thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
46352284Sobrien	thread0.td_pcb->pcb_flags = 0;
46452284Sobrien	thread0.td_frame = &proc0_tf;
46552284Sobrien	pcpup->pc_curpcb = thread0.td_pcb;
46652284Sobrien
46752284Sobrien	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
46852284Sobrien
46952284Sobrien	pmap_curmaxkvaddr = afterkern + 0x100000 * (KERNEL_PT_KERN_NUM - 1);
47052284Sobrien	/*
47152284Sobrien	 * ARM_USE_SMALL_ALLOC uses dump_avail, so it must be filled before
47252284Sobrien	 * calling pmap_bootstrap.
47352284Sobrien	 */
47452284Sobrien	dump_avail[0] = KERNPHYSADDR;
47552284Sobrien	dump_avail[1] = KERNPHYSADDR + memsize;
47652284Sobrien	dump_avail[2] = 0;
47752284Sobrien	dump_avail[3] = 0;
47852284Sobrien
47952284Sobrien	pmap_bootstrap(freemempos,
48052284Sobrien	    KERNVIRTADDR + 3 * memsize,
48152284Sobrien	    &kernel_l1pt);
48252284Sobrien	msgbufp = (void*)msgbufpv.pv_va;
48352284Sobrien	msgbufinit(msgbufp, MSGBUF_SIZE);
48452284Sobrien	mutex_init();
48552284Sobrien
48652284Sobrien	i = 0;
48752284Sobrien
48852284Sobrien	phys_avail[0] = virtual_avail - KERNVIRTADDR + KERNPHYSADDR;
48952284Sobrien	phys_avail[1] = KERNPHYSADDR + memsize;
49052284Sobrien	phys_avail[2] = 0;
49152284Sobrien	phys_avail[3] = 0;
49252284Sobrien	/* Do basic tuning, hz etc */
49352284Sobrien	init_param1();
49452284Sobrien	init_param2(physmem);
49552284Sobrien	avail_end = KERNPHYSADDR + memsize - 1;
49652284Sobrien	kdb_init();
49752284Sobrien	return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
49852284Sobrien	    sizeof(struct pcb)));
49952284Sobrien}
50052284Sobrien