diff options
Diffstat (limited to 'sys/arch')
| -rw-r--r-- | sys/arch/sparc64/include/autoconf.h | 6 | ||||
| -rw-r--r-- | sys/arch/sparc64/include/bootinfo.h | 134 | ||||
| -rw-r--r-- | sys/arch/sparc64/include/cpu.h | 30 | ||||
| -rw-r--r-- | sys/arch/sparc64/include/loadfile_machdep.h | 73 | ||||
| -rw-r--r-- | sys/arch/sparc64/include/pmap.h | 8 | ||||
| -rw-r--r-- | sys/arch/sparc64/include/vmparam.h | 10 | ||||
| -rw-r--r-- | sys/arch/sparc64/sparc64/autoconf.c | 128 | ||||
| -rw-r--r-- | sys/arch/sparc64/sparc64/cpu.c | 65 | ||||
| -rw-r--r-- | sys/arch/sparc64/sparc64/db_interface.c | 9 | ||||
| -rw-r--r-- | sys/arch/sparc64/sparc64/genassym.cf | 7 | ||||
| -rw-r--r-- | sys/arch/sparc64/sparc64/locore.s | 673 | ||||
| -rw-r--r-- | sys/arch/sparc64/sparc64/machdep.c | 14 | ||||
| -rw-r--r-- | sys/arch/sparc64/sparc64/pmap.c | 705 |
13 files changed, 768 insertions, 1094 deletions
diff --git a/sys/arch/sparc64/include/autoconf.h b/sys/arch/sparc64/include/autoconf.h index da30063446d..dbcb1474a0f 100644 --- a/sys/arch/sparc64/include/autoconf.h +++ b/sys/arch/sparc64/include/autoconf.h @@ -1,4 +1,4 @@ -/* $NetBSD: autoconf.h,v 1.23 2005/12/11 12:19:10 christos Exp $ */ +/* $NetBSD: autoconf.h,v 1.24 2006/01/27 18:37:49 cdi Exp $ */ /*- * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. @@ -157,6 +157,8 @@ struct device *parsedisk __P((char *, int, int, dev_t *)); void mountroot_hook_establish __P((void (*) __P((struct device *)), struct device *)); -void bootstrap __P((int)); +/* Kernel initialization routine. */ +void bootstrap(void *, void *, void *, void *, void *); + struct device *getdevunit __P((const char *, int)); int romgetcursoraddr __P((int **, int **)); diff --git a/sys/arch/sparc64/include/bootinfo.h b/sys/arch/sparc64/include/bootinfo.h index 8147ddf2b11..bc63f4a704a 100644 --- a/sys/arch/sparc64/include/bootinfo.h +++ b/sys/arch/sparc64/include/bootinfo.h @@ -1,3 +1,135 @@ -/* $NetBSD: bootinfo.h,v 1.1 2002/07/20 11:52:21 mrg Exp $ */ +/* $NetBSD: bootinfo.h,v 1.2 2006/01/27 18:37:49 cdi Exp $ */ +/*- + * Copyright (c) 2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _BOOTINFO_H_ +#define _BOOTINFO_H_ + +#include <machine/param.h> #include <sparc/bootinfo.h> + +/* + * The bootloader v1.9 and higher makes a call into a kernel with the following + * arguments: + * + * %o0 OpenFirmware entry point, to keep Sun's updaters happy + * %o1 Address of boot information vector (see below) + * %o2 Length of the vector, in bytes + * %o3 OpenFirmware entry point, to mimic Sun bootloader behavior + * %o4 OpenFirmware entry point, to meet earlier NetBSD kernels + * expectations + * + * All parameters are of void* type except for vector length which is of + * integer type. + * + * The boot information vector format was dictated by earlier kernels and + * starting from ofwboot v1.9 has four entries: + * + * +-------------------------------------+ + * #0 | NetBSD boot magic number ('DDB2') | + * +-------------------------------------+ + * #1 | ksyms' table end address | + * +-------------------------------------+ + * #2 | ksyms' table start address | + * +-------------------------------------+ + * #3 | Pointer to a bootinfo binary object | + * +-------------------------------------+ + * + * Kernels written for pre-v1.8 ofwboot require first three cells to present + * in this particular order, those that rely on v1.9 and higher won't work if + * the last pointer is not in the table; therefore, the vector cannot be + * shorter than 4 * sizeof(u_int32_t) or 4 * sizeof(u_int64_t) for 32-bit and + * 64-bit boot loader, respectively. + * + * As of ofwboot v1.9, bootinfo binary object is placed right after the kernel + * data segment end, i.e. in the permanently locked 4MB page. There is no order + * for the data located in bootinfo binary object. The kernel however expects + * at least following parameters to exist in there: + * + * - Symbol information (size, start, end; see struct btinfo_symtab) + * - Kernel end address, calculated as true kernel end address plus size of + * space reserved for bootinfo binary object (struct btinfo_kernend) + * - Number of text segment pages (struct btinfo_count) + * - Number of data segment pages (struct btinfo_count) + * - Array of text pages VA/PA (struct btinfo_tlb) + * - Array of data pages VA/PA (struct btinfo_tlb) + * + * The last four data structures fully describe kernel mappings. ofwboot v1.9 + * and higher map the kernel with 4MB permanent pages and this is the only + * way to let kernel know how exactly it was mapped. + */ + +/* Boot magic number */ +#define SPARC_MACHINE_OPENFIRMWARE 0x44444230 + +#ifdef BOOTINFO_SIZE +#undef BOOTINFO_SIZE +#endif + +#define BOOTINFO_SIZE NBPG + +#define BTINFO_DTLB_SLOTS 100 +#define BTINFO_ITLB_SLOTS 101 +#define BTINFO_DTLB 102 +#define BTINFO_ITLB 103 +#define BTINFO_KERNEND 104 + +#define LOOKUP_BOOTINFO(btp, info) \ +do { \ + if ( ((btp) = lookup_bootinfo(info)) == NULL) { \ + panic("lookup_bootinfo: No " #info " found.\n"); \ + } \ +} while (0) + +struct tlb_entry { + uint64_t te_pa; + uint64_t te_va; +}; + +struct btinfo_count { + struct btinfo_common common; + int count; +}; + +struct btinfo_tlb { + struct btinfo_common common; + struct tlb_entry tlb[1]; +}; + +struct btinfo_kernend { + struct btinfo_common common; + uint64_t addr; +}; + +#endif /* _BOOTINFO_H_ */ diff --git a/sys/arch/sparc64/include/cpu.h b/sys/arch/sparc64/include/cpu.h index 7480a2e53e4..cf20c1ca140 100644 --- a/sys/arch/sparc64/include/cpu.h +++ b/sys/arch/sparc64/include/cpu.h @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.h,v 1.50 2005/12/24 20:07:37 perry Exp $ */ +/* $NetBSD: cpu.h,v 1.51 2006/01/27 18:37:49 cdi Exp $ */ /* * Copyright (c) 1992, 1993 @@ -109,11 +109,19 @@ struct cpu_info { /* Most important fields first */ struct lwp *ci_curlwp; - struct cpu_data ci_data; /* MI per-cpu data */ struct pcb *ci_cpcb; struct cpu_info *ci_next; struct lwp *ci_fplwp; + + void *ci_eintstack; + struct pcb *ci_idle_u; + + /* Spinning up the CPU */ + void (*ci_spinup) __P((void)); + void *ci_initstack; + paddr_t ci_paddr; + int ci_number; int ci_upaid; int ci_cpuid; @@ -123,11 +131,6 @@ struct cpu_info { */ struct cc_microtime_state ci_cc; - /* Spinning up the CPU */ - void (*ci_spinup) __P((void)); - void *ci_initstack; - paddr_t ci_paddr; - /* CPU PROM information. */ u_int ci_node; @@ -135,8 +138,7 @@ struct cpu_info { int ci_want_ast; int ci_want_resched; - void *ci_eintstack; - struct pcb *ci_idle_u; + struct cpu_data ci_data; /* MI per-cpu data */ }; #define CPUF_PRIMARY 1 @@ -191,7 +193,15 @@ extern struct cpu_info *cpus; void cpu_proc_fork(struct proc *, struct proc *); #if defined(MULTIPROCESSOR) -void cpu_mp_startup __P((void)); +extern vaddr_t cpu_spinup_trampoline; + +extern char *mp_tramp_code; +extern u_long mp_tramp_code_len; +extern u_long mp_tramp_tlb_slots; +extern u_long mp_tramp_func; +extern u_long mp_tramp_ci; + +void cpu_hatch __P((void)); void cpu_boot_secondary_processors __P((void)); #endif diff --git a/sys/arch/sparc64/include/loadfile_machdep.h b/sys/arch/sparc64/include/loadfile_machdep.h index 0b117662c3a..75bd4089f05 100644 --- a/sys/arch/sparc64/include/loadfile_machdep.h +++ b/sys/arch/sparc64/include/loadfile_machdep.h @@ -1,3 +1,72 @@ -/* $NetBSD: loadfile_machdep.h,v 1.1 2000/08/16 08:17:50 mrg Exp $ */ +/* $NetBSD: loadfile_machdep.h,v 1.2 2006/01/27 18:37:49 cdi Exp $ */ -#include <sparc/loadfile_machdep.h> +/*- + * Copyright (c) 2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOAD_KERNEL LOAD_ALL +#define COUNT_KERNEL COUNT_ALL + +#ifdef _STANDALONE +#define LOADADDR(a) ((long)(a)) +#define ALIGNENTRY(a) ((u_long)(a)) +#define READ(f, b, c) sparc64_read((f), (void *)LOADADDR(b), (c)) +#define BCOPY(s, d, c) sparc64_memcpy((void *)LOADADDR(d), \ + (void *)(s), (c)) +#define BZERO(d, c) sparc64_memset((void *)LOADADDR(d), 0, (c)) +#define WARN(a) (void)(printf a, \ + printf((errno ? ": %s\n" : "\n"), \ + strerror(errno))) +#define PROGRESS(a) (void) printf a +#define ALLOC(a) alloc(a) +#define DEALLOC(a, b) dealloc(a, b) +#define OKMAGIC(a) ((a) == OMAGIC) + +extern ssize_t sparc64_read(int, void *, size_t); +extern void* sparc64_memcpy(void *, const void *, size_t); +extern void* sparc64_memset(void *, int, size_t); + +#else +#define LOADADDR(a) (((u_long)(a)) + (u_long)offset) +#define ALIGNENTRY(a) ((u_long)(a)) +#define READ(f, b, c) read((f), (void *)LOADADDR(b), (c)) +#define BCOPY(s, d, c) memcpy((void *)LOADADDR(d), (void *)(s), (c)) +#define BZERO(d, c) memset((void *)LOADADDR(d), 0, (c)) +#define WARN(a) warn a +#define PROGRESS(a) /* nothing */ +#define ALLOC(a) malloc(a) +#define FREE(a, b) free(a) +#define OKMAGIC(a) ((a) == OMAGIC) +#endif diff --git a/sys/arch/sparc64/include/pmap.h b/sys/arch/sparc64/include/pmap.h index f19454f9078..dfd7933b92a 100644 --- a/sys/arch/sparc64/include/pmap.h +++ b/sys/arch/sparc64/include/pmap.h @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.h,v 1.34 2005/12/11 12:19:10 christos Exp $ */ +/* $NetBSD: pmap.h,v 1.35 2006/01/27 18:37:49 cdi Exp $ */ /*- * Copyright (C) 1995, 1996 Wolfgang Solfrank. @@ -173,7 +173,7 @@ int pmap_count_wired __P((struct pmap *)); void pmap_activate_pmap(struct pmap *); void pmap_update(struct pmap *); -void pmap_bootstrap __P((u_long kernelstart, u_long kernelend, u_int numctx)); +void pmap_bootstrap __P((u_long, u_long)); /* make sure all page mappings are modulo 16K to prevent d$ aliasing */ #define PMAP_PREFER(pa, va, sz, td) (*(va)+=(((*(va))^(pa))&(1<<(PGSHIFT)))) @@ -194,6 +194,10 @@ void pmap_kprotect(vaddr_t, vm_prot_t); int ctx_alloc __P((struct pmap *)); void ctx_free __P((struct pmap *)); +/* Installed physical memory, as discovered during bootstrap. */ +extern int phys_installed_size; +extern struct mem_region *phys_installed; + #endif /* _KERNEL */ #endif /* _LOCORE */ diff --git a/sys/arch/sparc64/include/vmparam.h b/sys/arch/sparc64/include/vmparam.h index 0d2a704c830..d800806a6bc 100644 --- a/sys/arch/sparc64/include/vmparam.h +++ b/sys/arch/sparc64/include/vmparam.h @@ -1,4 +1,4 @@ -/* $NetBSD: vmparam.h,v 1.28 2005/12/11 12:19:10 christos Exp $ */ +/* $NetBSD: vmparam.h,v 1.29 2006/01/27 18:37:49 cdi Exp $ */ /* * Copyright (c) 1992, 1993 @@ -56,6 +56,14 @@ #define PAGE_MASK (PAGE_SIZE - 1) /* + * The kernel itself is mapped by the boot loader with 4Mb locked VM pages, + * so let's keep 4Mb definitions here as well. + */ +#define PAGE_SHIFT_4M 22 +#define PAGE_SIZE_4M (1UL<<PAGE_SHIFT_4M) +#define PAGE_MASK_4M (PAGE_SIZE_4M-1) + +/* * USRSTACK is the top (end) of the user stack. */ #define USRSTACK32 0xffffe000L diff --git a/sys/arch/sparc64/sparc64/autoconf.c b/sys/arch/sparc64/sparc64/autoconf.c index 8dacc0ef2e9..30034f5b11d 100644 --- a/sys/arch/sparc64/sparc64/autoconf.c +++ b/sys/arch/sparc64/sparc64/autoconf.c @@ -1,4 +1,4 @@ -/* $NetBSD: autoconf.c,v 1.106 2005/12/24 20:07:37 perry Exp $ */ +/* $NetBSD: autoconf.c,v 1.107 2006/01/27 18:37:49 cdi Exp $ */ /* * Copyright (c) 1996 @@ -48,7 +48,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.106 2005/12/24 20:07:37 perry Exp $"); +__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.107 2006/01/27 18:37:49 cdi Exp $"); #include "opt_ddb.h" #include "opt_kgdb.h" @@ -81,6 +81,7 @@ __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.106 2005/12/24 20:07:37 perry Exp $") #include <machine/sparc64.h> #include <machine/cpu.h> #include <machine/pmap.h> +#include <machine/bootinfo.h> #include <sparc64/sparc64/timerreg.h> #include <dev/ata/atavar.h> @@ -119,6 +120,7 @@ struct evcnt intr_evcnts[] = { }; int printspl = 0; +void *bootinfo = 0; #ifdef KGDB extern int kgdb_debug_panic; @@ -140,6 +142,12 @@ int nbootpath; static void bootpath_build __P((void)); static void bootpath_print __P((struct bootpath *)); +/* + * Kernel 4MB mappings. + */ +struct tlb_entry *kernel_tlbs; +int kernel_tlb_slots; + /* Global interrupt mappings for all device types. Match against the OBP * 'device_type' property. */ @@ -229,40 +237,107 @@ get_ncpus() } /* + * lookup_bootinfo: + * Look up information in bootinfo of boot loader. + */ +void * +lookup_bootinfo(type) + int type; +{ + struct btinfo_common *bt; + char *help = bootinfo; + + /* Check for a bootinfo record first. */ + if (help == NULL) + return (NULL); + + do { + bt = (struct btinfo_common *)help; + if (bt->type == type) + return ((void *)help); + help += bt->next; + } while (bt->next != 0 && + (size_t)help < (size_t)bootinfo + BOOTINFO_SIZE); + + return (NULL); +} + +/* * locore.s code calls bootstrap() just before calling main(). * * What we try to do is as follows: + * - Initialize PROM and the console + * - Read in part of information provided by a bootloader and find out + * kernel load and end addresses + * - Initialize ksyms + * - Find out number of active CPUs + * - Finalize the bootstrap by calling pmap_bootstrap() * - * 1) We will try to re-allocate the old message buffer. - * - * 2) We will then get the list of the total and available - * physical memory and available virtual memory from the - * prom. - * - * 3) We will pass the list to pmap_bootstrap to manage them. - * - * We will try to run out of the prom until we get to cpu_init(). + * We will try to run out of the prom until we get out of pmap_bootstrap(). */ void -bootstrap(nctx) - int nctx; +bootstrap(void *o0, void *bootargs, void *bootsize, void *o3, void *ofw) { - extern int end; /* End of kernel */ -#if (NKSYMS || defined(DDB) || defined(LKM)) - extern void *ssym, *esym; -#endif -#if !defined(__arch64__) && defined(DDB) - /* Assembly glue for the PROM */ - extern void OF_sym2val32 __P((void *)); - extern void OF_val2sym32 __P((void *)); -#endif + void *bi; + long bmagic; + + struct btinfo_symtab *bi_sym; + struct btinfo_count *bi_count; + struct btinfo_kernend *bi_kend; + struct btinfo_tlb *bi_tlb; + + extern void *romtba; + extern void* get_romtba(void); + extern void OF_val2sym32(void *); + extern void OF_sym2val32(void *); + + /* Save OpenFrimware entry point */ + romp = ofw; + romtba = get_romtba(); prom_init(); /* Initialize the PROM console so printf will not panic */ (*cn_tab->cn_init)(cn_tab); + + printf("sparc64_init(%p, %p, %p, %p, %p)\n", o0, bootargs, bootsize, + o3, ofw); + + /* Extract bootinfo pointer */ + if ((long)bootsize >= (4 * sizeof(u_int64_t))) { + /* Loaded by 64-bit bootloader */ + bi = (void*)(u_long)(((u_int64_t*)bootargs)[3]); + bmagic = (long)(((u_int64_t*)bootargs)[0]); + } else if ((long)bootsize >= (4 * sizeof(u_int32_t))) { + /* Loaded by 32-bit bootloader */ + bi = (void*)(u_long)(((u_int32_t*)bootargs)[3]); + bmagic = (long)(((u_int32_t*)bootargs)[0]); + } else { + printf("Bad bootinfo size.\n" + "This kernel requires NetBSD boot loader.\n"); + panic("sparc64_init."); + } + + printf("sparc64_init: bmagic=%lx, bi=%p\n", bmagic, bi); + + /* Read in the information provided by NetBSD boot loader */ + if (SPARC_MACHINE_OPENFIRMWARE != bmagic) { + printf("No bootinfo information.\n" + "This kernel requires NetBSD boot loader.\n"); + panic("sparc64_init."); + } + + bootinfo = (void*)(u_long)((u_int64_t*)bi)[1]; + LOOKUP_BOOTINFO(bi_kend, BTINFO_KERNEND); + + if (bi_kend->addr == (vaddr_t)0) { + panic("Kernel end address is not found in bootinfo.\n"); + } + #if NKSYMS || defined(DDB) || defined(LKM) - ksyms_init((int)((caddr_t)esym - (caddr_t)ssym), ssym, esym); + LOOKUP_BOOTINFO(bi_sym, BTINFO_SYMTAB); + ksyms_init(bi_sym->nsym, (int *)(u_long)bi_sym->ssym, + (int *)(u_long)bi_sym->esym); #ifdef DDB #ifdef __arch64__ /* This can only be installed on an 64-bit system cause otherwise our stack is screwed */ @@ -273,8 +348,13 @@ bootstrap(nctx) #endif #endif + LOOKUP_BOOTINFO(bi_count, BTINFO_DTLB_SLOTS); + kernel_tlb_slots = bi_count->count; + LOOKUP_BOOTINFO(bi_tlb, BTINFO_DTLB); + kernel_tlbs = &bi_tlb->tlb[0]; + get_ncpus(); - pmap_bootstrap(KERNBASE, (u_long)&end, nctx); + pmap_bootstrap(KERNBASE, bi_kend->addr); } /* diff --git a/sys/arch/sparc64/sparc64/cpu.c b/sys/arch/sparc64/sparc64/cpu.c index a7b61bd4e77..fedc119c889 100644 --- a/sys/arch/sparc64/sparc64/cpu.c +++ b/sys/arch/sparc64/sparc64/cpu.c @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.c,v 1.43 2005/12/24 20:07:37 perry Exp $ */ +/* $NetBSD: cpu.c,v 1.44 2006/01/27 18:37:49 cdi Exp $ */ /* * Copyright (c) 1996 @@ -52,7 +52,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.43 2005/12/24 20:07:37 perry Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.44 2006/01/27 18:37:49 cdi Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -82,7 +82,6 @@ volatile cpuset_t cpus_active;/* set of active cpus */ struct cpu_bootargs *cpu_args; /* allocated very early in pmap_bootstrap. */ static struct cpu_info *alloc_cpuinfo(u_int); -void mp_main(void); /* The following are used externally (sysctl_hw). */ char machine[] = MACHINE; /* from <machine/param.h> */ @@ -338,55 +337,21 @@ cpu_attach(parent, dev, aux) } #if defined(MULTIPROCESSOR) +vaddr_t cpu_spinup_trampoline; + +u_long dump_rtf_info = 0; + /* * Start secondary processors in motion. */ -extern vaddr_t ktext; -extern paddr_t ktextp; -extern vaddr_t ektext; -extern vaddr_t kdata; -extern paddr_t kdatap; -extern vaddr_t ekdata; - -extern void cpu_mp_startup_end(void *); - void cpu_boot_secondary_processors() { - int pstate; + int i, pstate; struct cpu_info *ci; - int i; - vaddr_t mp_start; - int mp_start_size; sparc64_ipi_init(); - cpu_args->cb_ktext = ktext; - cpu_args->cb_ktextp = ktextp; - cpu_args->cb_ektext = ektext; - - cpu_args->cb_kdata = kdata; - cpu_args->cb_kdatap = kdatap; - cpu_args->cb_ekdata = ekdata; - - mp_start = ((vaddr_t)cpu_args + sizeof(*cpu_args)+ 0x0f) & ~0x0f; - mp_start_size = (vaddr_t)cpu_mp_startup_end - (vaddr_t)cpu_mp_startup; - memcpy((void *)mp_start, cpu_mp_startup, mp_start_size); - - mp_start_size = mp_start_size >> 3; - for (i = 0; i < mp_start_size; i++) - flush(mp_start + (i << 3)); - -#ifdef DEBUG - printf("cpu_args @ %p\n", cpu_args); - printf("ktext %lx, ktextp %lx, ektext %lx\n", - cpu_args->cb_ktext, cpu_args->cb_ktextp,cpu_args->cb_ektext); - printf("kdata %lx, kdatap %lx, ekdata %lx\n", - cpu_args->cb_kdata, cpu_args->cb_kdatap, cpu_args->cb_ekdata); - printf("mp_start %lx, mp_start_size 0x%x\n", - mp_start, mp_start_size); -#endif - printf("cpu0: booting secondary processors:\n"); for (ci = cpus; ci != NULL; ci = ci->ci_next) { @@ -408,7 +373,8 @@ cpu_boot_secondary_processors() pstate = getpstate(); setpstate(PSTATE_KERN); - prom_startcpu(ci->ci_node, (void *)mp_start, 0); + printf("mp_tramp: %p\n", (void*)cpu_spinup_trampoline); + prom_startcpu(ci->ci_node, (void *)cpu_spinup_trampoline, 0); for (i = 0; i < 2000; i++) { membar_sync(); @@ -429,10 +395,21 @@ cpu_boot_secondary_processors() } void -mp_main() +cpu_hatch() { + int i; + char *v = (char*)CPUINFO_VA; + + for (i = 0; i < 4*PAGE_SIZE; i += sizeof(long)) + flush(v + i); + dump_rtf_info = 1; + + printf("cpu%d fired up.\n", cpu_number()); CPUSET_ADD(cpus_active, cpu_number()); + for (i = 0; i < 5000000; i++) + ; + printf("cpu%d enters idle loop.\n", cpu_number()); membar_sync(); spl0(); } diff --git a/sys/arch/sparc64/sparc64/db_interface.c b/sys/arch/sparc64/sparc64/db_interface.c index 699c23d9756..cd0478a5b44 100644 --- a/sys/arch/sparc64/sparc64/db_interface.c +++ b/sys/arch/sparc64/sparc64/db_interface.c @@ -1,4 +1,4 @@ -/* $NetBSD: db_interface.c,v 1.83 2005/12/24 22:45:39 perry Exp $ */ +/* $NetBSD: db_interface.c,v 1.84 2006/01/27 18:37:49 cdi Exp $ */ /* * Copyright (c) 1996-2002 Eduardo Horvath. All rights reserved. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.83 2005/12/24 22:45:39 perry Exp $"); +__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.84 2006/01/27 18:37:49 cdi Exp $"); #include "opt_ddb.h" @@ -414,8 +414,7 @@ db_write_bytes(addr, size, data) register const char *data; { register char *dst; - extern vaddr_t ktext; - extern paddr_t ktextp; + extern paddr_t pmap_kextract(vaddr_t va); dst = (char *)addr; while (size-- > 0) { @@ -424,7 +423,7 @@ db_write_bytes(addr, size, data) else if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS) && (dst < (char *)VM_MIN_KERNEL_ADDRESS+0x400000)) /* Read Only mapping -- need to do a bypass access */ - stba((u_long)dst - ktext + ktextp, ASI_PHYS_CACHED, *data); + stba(pmap_kextract((vaddr_t)dst), ASI_PHYS_CACHED, *data); else subyte(dst, *data); dst++, data++; diff --git a/sys/arch/sparc64/sparc64/genassym.cf b/sys/arch/sparc64/sparc64/genassym.cf index a826308e974..4bc3ea6ab89 100644 --- a/sys/arch/sparc64/sparc64/genassym.cf +++ b/sys/arch/sparc64/sparc64/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.39 2005/12/11 12:19:14 christos Exp $ +# $NetBSD: genassym.cf,v 1.40 2006/01/27 18:37:49 cdi Exp $ # # Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -301,3 +301,8 @@ endif # TLB IPI handler arguments. define ITA_VADDR offsetof(struct ipi_tlb_args, ita_vaddr) define ITA_CTX offsetof(struct ipi_tlb_args, ita_ctx) + +# pte_t structure. +define TTE_VPN offsetof(pte_t, tag) +define TTE_DATA offsetof(pte_t, data) +define PTE_SIZE sizeof(pte_t) diff --git a/sys/arch/sparc64/sparc64/locore.s b/sys/arch/sparc64/sparc64/locore.s index 247dfc478c2..6c5fa4303a9 100644 --- a/sys/arch/sparc64/sparc64/locore.s +++ b/sys/arch/sparc64/sparc64/locore.s @@ -1,4 +1,4 @@ -/* $NetBSD: locore.s,v 1.208 2006/01/12 17:58:39 cdi Exp $ */ +/* $NetBSD: locore.s,v 1.209 2006/01/27 18:37:49 cdi Exp $ */ /* * Copyright (c) 1996-2002 Eduardo Horvath @@ -742,8 +742,8 @@ label: \ TA32 .globl start, _C_LABEL(kernel_text) - _C_LABEL(kernel_text) = start ! for kvm_mkdb(8) -start: + _C_LABEL(kernel_text) = kernel_start ! for kvm_mkdb(8) +kernel_start: /* Traps from TL=0 -- traps from user mode */ #ifdef __STDC__ #define TABLE(name) user_ ## name @@ -4217,6 +4217,63 @@ ENTRY(sparc64_ipi_flush_all) ba,a ret_from_intr_vector nop + +/* + * Secondary CPU bootstrap code. + */ + .text + .align 32 +1: rd %pc, %l0 + ldx [%l0 + (4f-1b)], %l1 + add %l0, (6f-1b), %l2 + clr %l3 +2: cmp %l3, %l1 + be %xcc, 3f + nop + ldx [%l2 + TTE_VPN], %l4 + ldx [%l2 + TTE_DATA], %l5 + wr %g0, ASI_DMMU, %asi + stxa %l4, [%g0 + TLB_TAG_ACCESS] %asi + stxa %l5, [%g0] ASI_DMMU_DATA_IN + wr %g0, ASI_IMMU, %asi + stxa %l4, [%g0 + TLB_TAG_ACCESS] %asi + stxa %l5, [%g0] ASI_IMMU_DATA_IN + membar #Sync + flush %l4 + add %l2, PTE_SIZE, %l2 + add %l3, 1, %l3 + ba %xcc, 2b + nop +3: ldx [%l0 + (5f-1b)], %l1 + ldx [%l0 + (7f-1b)], %g2 ! Load cpu_info address. + jmpl %l1, %g0 + nop + + .align 8 +4: .xword 0x0 +5: .xword 0x0 +7: .xword 0x0 +6: + +#define DATA(name) \ + .data ; \ + .align 8 ; \ + .globl name ; \ +name: + +DATA(mp_tramp_code) + .xword 1b +DATA(mp_tramp_code_len) + .xword 6b-1b +DATA(mp_tramp_tlb_slots) + .xword 4b-1b +DATA(mp_tramp_func) + .xword 5b-1b +DATA(mp_tramp_ci) + .xword 7b-1b + + .text + .align 32 #endif /* MULTIPROCESSOR */ /* @@ -5240,7 +5297,19 @@ ENTRY_NOPROFILE(print_itlb) #endif #endif +/* + * Kernel entry point. + * + * The contract between bootloader and kernel is: + * + * %o0 OpenFirmware entry point, to keep Sun's updaters happy + * %o1 Address of boot information vector (see bootinfo.h) + * %o2 Length of the vector, in bytes + * %o3 OpenFirmware entry point, to mimic Sun bootloader behavior + * %o4 OpenFirmware, to meet earlier NetBSD kernels expectations + */ .align 8 +start: dostart: wrpr %g0, 0, %tick ! XXXXXXX clear %tick register for now mov 1, %g1 @@ -5276,79 +5345,6 @@ dostart: wrpr %g0, 13, %pil wrpr %g0, PSTATE_INTR|PSTATE_PEF, %pstate wr %g0, FPRS_FEF, %fprs ! Turn on FPU -#if NKSYMS || defined(DDB) || defined(LKM) - /* - * First, check for DDB arguments. A pointer to an argument - * is passed in %o1 who's length is passed in %o2. Our - * bootloader passes in a magic number as the first argument, - * followed by esym as argument 2, so check that %o2 == 8, - * then extract esym and check the magic number. - * - * Oh, yeah, start of elf symtab is arg 3. - */ - cmp %o2, 8 - blt 1f ! Not enuff args - - /* - * First we'll see if we were loaded by a 64-bit bootloader - */ - btst 0x7, %o1 ! Check alignment - bne 0f - set 0x44444230, %l3 - - ldx [%o1], %l4 - cmp %l3, %l4 ! chk magic - bne %xcc, 0f - nop - - ldx [%o1+8], %l4 - sethi %hi(_C_LABEL(esym)), %l3 ! store _esym - STPTR %l4, [%l3 + %lo(_C_LABEL(esym))] - - cmp %o2, 12 - blt 1f - nop - - ldx [%o1+16], %l4 - sethi %hi(_C_LABEL(ssym)), %l3 ! store _esym - ba 1f - STPTR %l4, [%l3 + %lo(_C_LABEL(ssym))] -0: - /* - * Now we can try again with for a 32-bit bootloader - */ - cmp %o2, 8 - blt 1f ! Not enuff args - - set 0x44444230, %l3 - ld [%o1], %l4 - cmp %l3, %l4 ! chk magic - bne 1f - nop - - ld [%o1+4], %l4 - sethi %hi(_C_LABEL(esym)), %l3 ! store _esym - STPTR %l4, [%l3 + %lo(_C_LABEL(esym))] - - cmp %o2, 12 - blt 1f - nop - - ld [%o1+8], %l4 - sethi %hi(_C_LABEL(ssym)), %l3 ! store _esym - STPTR %l4, [%l3 + %lo(_C_LABEL(ssym))] -1: -#endif - /* - * Step 1: Save rom entry pointer and prom tba - */ - - set romp, %o5 - STPTR %o4, [%o5] ! It's initialized data, I hope - - rdpr %tba, %o4 - set romtba, %o5 - STPTR %o4, [%o5] /* * Step 2: Set up a v8-like stack if we need to @@ -5366,30 +5362,10 @@ dostart: add %sp, BIAS, %sp #endif 0: - /* - * Step 3: clear BSS. This may just be paranoia; the boot - * loader might already do it for us; but what the hell. - */ - set _C_LABEL(edata), %o0 ! memset(edata, 0, end - edata) - set _C_LABEL(end), %o2 - clr %o1 - call _C_LABEL(memset) - sub %o2, %o0, %o2 - /* - * Ready to run C code; finish bootstrap. - */ - set CTX_SECONDARY, %o1 ! Store -1 in the context register - mov -1, %o2 - stxa %o2, [%o1] ASI_DMMU - membar #Sync - ldxa [%o1] ASI_DMMU, %o0 ! then read it back - membar #Sync - stxa %g0, [%o1] ASI_DMMU - membar #Sync - clr %g4 ! Clear data segment pointer + call _C_LABEL(bootstrap) - inc %o0 ! and add 1 to discover maxctx + clr %g4 ! Clear data segment pointer /* * pmap_bootstrap should have allocated a stack for proc 0 and @@ -5426,325 +5402,6 @@ _C_LABEL(cpu_initialize): * %l7 = 4MB-1 * %o0-%o5 = tmp */ - -#ifdef NO_VCACHE - !! Turn off D$ in LSU - ldxa [%g0] ASI_LSU_CONTROL_REGISTER, %g1 - bclr MCCR_DCACHE_EN, %g1 - stxa %g1, [%g0] ASI_LSU_CONTROL_REGISTER - membar #Sync -#endif - - wrpr %g0, 0, %tl ! Make sure we're not in NUCLEUS mode - sethi %hi(KERNBASE), %l0 ! Find our xlation - sethi %hi(DATA_START), %l3 - - set _C_LABEL(ktextp), %l2 ! Find phys addr - ldx [%l2], %l2 ! The following gets ugly: We need to load the following mask - set _C_LABEL(kdatap), %l5 - ldx [%l5], %l5 - - set _C_LABEL(ektext), %l1 ! And the ends... - LDPTR [%l1], %l1 - set _C_LABEL(ekdata), %l4 - LDPTR [%l4], %l4 - - sethi %hi(0xe0000000), %o0 ! V=1|SZ=11|NFO=0|IE=0 - sllx %o0, 32, %o0 ! Shift it into place - - sethi %hi(0x400000), %l6 ! Create a 4MB mask - add %l6, -1, %l7 - - mov -1, %o1 ! Create a nice mask - sllx %o1, 41, %o1 ! Mask off high bits - or %o1, 0xfff, %o1 ! We can just load this in 12 (of 13) bits - - andn %l2, %o1, %l2 ! Mask the phys page number - andn %l5, %o1, %l5 ! Mask the phys page number - - or %l2, %o0, %l2 ! Now take care of the high bits - or %l5, %o0, %l5 ! Now take care of the high bits - - wrpr %g0, PSTATE_KERN, %pstate ! Disable interrupts - -#ifdef DEBUG - set _C_LABEL(pmapdebug), %o1 - ld [%o1], %o1 - sethi %hi(0x40000), %o2 - btst %o2, %o1 - bz 0f - - set 1f, %o0 ! Debug printf for TEXT page - srlx %l0, 32, %o1 - srl %l0, 0, %o2 - or %l2, TTE_L|TTE_CP|TTE_CV|TTE_P, %o4 ! And low bits: L=1|CP=1|CV=1|E=0|P=1|W=1(ugh)|G=0 - srlx %o4, 32, %o3 - call _C_LABEL(prom_printf) - srl %o4, 0, %o4 - - set 1f, %o0 ! Debug printf for DATA page - srlx %l3, 32, %o1 - srl %l3, 0, %o2 - or %l5, TTE_L|TTE_CP|TTE_CV|TTE_P|TTE_W, %o4 ! And low bits: L=1|CP=1|CV=1|E=0|P=1|W=1(ugh)|G=0 - srlx %o4, 32, %o3 - call _C_LABEL(prom_printf) - srl %o4, 0, %o4 - .data -1: - .asciz "Setting DTLB entry %08x %08x data %08x %08x\r\n" - _ALIGN - .text -0: -#endif - mov %l0, %o0 ! Demap all of kernel dmmu text segment - mov %l3, %o1 - set 0x2000, %o2 ! 8K page size - add %l1, %l7, %o5 ! Extend to 4MB boundary - andn %o5, %l7, %o5 -0: - stxa %o0, [%o0] ASI_DMMU_DEMAP ! Demap text segment - membar #Sync - cmp %o0, %o5 - bleu 0b - add %o0, %o2, %o0 - - add %l4, %l7, %o5 ! Extend to 4MB boundary - andn %o5, %l7, %o5 -0: - stxa %o1, [%o1] ASI_DMMU_DEMAP ! Demap data segment - membar #Sync - cmp %o1, %o5 - bleu 0b - add %o1, %o2, %o1 - - set (1<<14)-8, %o0 ! Clear out DCACHE -1: - stxa %g0, [%o0] ASI_DCACHE_TAG ! clear DCACHE line - membar #Sync - brnz,pt %o0, 1b - dec 8, %o0 - - /* - * First map data segment into the DMMU. - */ - set TLB_TAG_ACCESS, %o0 ! Now map it back in with a locked TTE - mov %l3, %o1 -#ifdef NO_VCACHE - ! And low bits: L=1|CP=1|CV=0(ugh)|E=0|P=1|W=1|G=0 - or %l5, TTE_L|TTE_CP|TTE_P|TTE_W, %o2 -#else - ! And low bits: L=1|CP=1|CV=1|E=0|P=1|W=1|G=0 - or %l5, TTE_L|TTE_CP|TTE_CV|TTE_P|TTE_W, %o2 -#endif - set 1f, %o5 -2: - stxa %o1, [%o0] ASI_DMMU ! Set VA for DSEG - membar #Sync ! We may need more membar #Sync in here - stxa %o2, [%g0] ASI_DMMU_DATA_IN ! Store TTE for DSEG - membar #Sync ! We may need more membar #Sync in here - flush %o5 ! Make IMMU see this too -1: - add %o1, %l6, %o1 ! increment VA - cmp %o1, %l4 ! Next 4MB mapping.... - blu,pt %xcc, 2b - add %o2, %l6, %o2 ! Increment tag - - /* - * Next map the text segment into the DMMU so we can get at RODATA. - */ - mov %l0, %o1 -#ifdef NO_VCACHE - ! And low bits: L=1|CP=1|CV=0(ugh)|E=0|P=1|W=0|G=0 - or %l2, TTE_L|TTE_CP|TTE_P, %o2 -#else - ! And low bits: L=1|CP=1|CV=1|E=0|P=1|W=0|G=0 - or %l2, TTE_L|TTE_CP|TTE_CV|TTE_P, %o2 -#endif -2: - stxa %o1, [%o0] ASI_DMMU ! Set VA for DSEG - membar #Sync ! We may need more membar #Sync in here - stxa %o2, [%g0] ASI_DMMU_DATA_IN ! Store TTE for DSEG - membar #Sync ! We may need more membar #Sync in here - flush %o5 ! Make IMMU see this too - add %o1, %l6, %o1 ! increment VA - cmp %o1, %l1 ! Next 4MB mapping.... - blu,pt %xcc, 2b - add %o2, %l6, %o2 ! Increment tag - -#ifdef DEBUG - set _C_LABEL(pmapdebug), %o1 - ld [%o1], %o1 - sethi %hi(0x40000), %o2 - btst %o2, %o1 - bz 0f - - set 1f, %o0 ! Debug printf - srlx %l0, 32, %o1 - srl %l0, 0, %o2 - or %l2, TTE_L|TTE_CP|TTE_CV|TTE_P, %o4 - srlx %o4, 32, %o3 - call _C_LABEL(prom_printf) - srl %o4, 0, %o4 - .data -1: - .asciz "Setting ITLB entry %08x %08x data %08x %08x\r\n" - _ALIGN - .text -0: -#endif - /* - * Finished the DMMU, now we need to do the IMMU which is more - * difficult because we're execting instructions through the IMMU - * while we're flushing it. We need to remap the entire kernel - * to a new context, flush the entire context 0 IMMU, map it back - * into context 0, switch to context 0, and flush context 1. - * - * Another interesting issue is that the flush instructions are - * translated through the DMMU, therefore we need to enter the - * mappings both in the IMMU and the DMMU so we can flush them - * correctly. - * - * Start by mapping in the kernel text as context==1 - */ - set TLB_TAG_ACCESS, %o0 - or %l0, 1, %o1 ! Context = 1 - or %l2, TTE_CP|TTE_P, %o2 ! And low bits: L=0|CP=1|CV=0|E=0|P=1|G=0 - set 1f, %o5 -2: - stxa %o1, [%o0] ASI_DMMU ! Make DMMU point to it - membar #Sync ! We may need more membar #Sync in here - stxa %o2, [%g0] ASI_DMMU_DATA_IN ! Store it - membar #Sync ! We may need more membar #Sync in here - stxa %o1, [%o0] ASI_IMMU ! Make IMMU point to it - membar #Sync ! We may need more membar #Sync in here - flush %o1-1 ! Make IMMU see this too - stxa %o2, [%g0] ASI_IMMU_DATA_IN ! Store it - membar #Sync ! We may need more membar #Sync in here - flush %o5 ! Make IMMU see this too -1: - add %o1, %l6, %o1 ! increment VA - cmp %o1, %l1 ! Next 4MB mapping.... - blu,pt %xcc, 2b - add %o2, %l6, %o2 ! Increment tag - - !! - !! Load 1 as primary context - !! - mov 1, %o0 - mov CTX_PRIMARY, %o1 - stxa %o0, [%o1] ASI_DMMU - wrpr %g0, 0, %tl ! Make SURE we're nucleus mode - membar #Sync ! This probably should be a flush, but it works - flush %o5 ! This should be KERNBASE - - !! - !! Demap entire context 0 kernel - !! - or %l0, DEMAP_PAGE_NUCLEUS, %o0 ! Context = Nucleus - add %l1, %l7, %o1 ! Demap all of kernel text seg - andn %o1, %l7, %o1 ! rounded up to 4MB. - set 0x2000, %o2 ! 8K page size -0: - stxa %o0, [%o0] ASI_IMMU_DEMAP ! Demap it - membar #Sync - flush %o5 ! Assume low bits are benign - cmp %o0, %o1 - bleu,pt %xcc, 0b ! Next page - add %o0, %o2, %o0 - - or %l3, DEMAP_PAGE_NUCLEUS, %o0 ! Context = Nucleus - add %l4, %l7, %o1 ! Demap all of kernel data seg - andn %o1, %l7, %o1 ! rounded up to 4MB. -0: - stxa %o0, [%o0] ASI_IMMU_DEMAP ! Demap it - membar #Sync - flush %o5 ! Assume low bits are benign - cmp %o0, %o1 - bleu,pt %xcc, 0b ! Next page - add %o0, %o2, %o0 - - !! - !! Now, map in the kernel text as context==0 - !! - set TLB_TAG_ACCESS, %o0 - mov %l0, %o1 ! Context = 0 -#ifdef NO_VCACHE - ! And low bits: L=1|CP=1|CV=0(ugh)|E=0|P=1|W=1|G=0 - or %l2, TTE_L|TTE_CP|TTE_P, %o2 -#else - ! And low bits: L=1|CP=1|CV=1|E=0|P=1|W=1|G=0 - or %l2, TTE_L|TTE_CP|TTE_CV|TTE_P, %o2 -#endif -2: - stxa %o1, [%o0] ASI_IMMU ! Make IMMU point to it - membar #Sync ! We may need more membar #Sync in here - stxa %o2, [%g0] ASI_IMMU_DATA_IN ! Store it - membar #Sync ! We may need more membar #Sync in here - flush %o5 ! Make IMMU see this too - add %o1, %l6, %o1 ! increment VA - cmp %o1, %l1 ! Next 4MB mapping.... - blu,pt %xcc, 2b - add %o2, %l6, %o2 ! Increment tag - - !! - !! Restore 0 as primary context - !! - mov CTX_PRIMARY, %o0 - stxa %g0, [%o0] ASI_DMMU - flush %o5 - - !! - !! Demap context 1 - !! -#ifdef SPITFIRE - mov 1, %o1 - mov CTX_SECONDARY, %o0 - stxa %o1, [%o0] ASI_DMMU - membar #Sync ! This probably should be a flush, but it works - flush %l0 - mov DEMAP_CTX_SECONDARY, %o4 - stxa %o4, [%o4] ASI_DMMU_DEMAP - membar #Sync - stxa %o4, [%o4] ASI_IMMU_DEMAP - membar #Sync - flush %l0 - stxa %g0, [%o0] ASI_DMMU - membar #Sync - flush %l0 -#else - mov 1, %o1 - wrpr %g0, 1, %tl ! Enter nucleus context - mov CTX_PRIMARY, %o0 - stxa %o1, [%o0] ASI_DMMU - membar #Sync ! This probably should be a flush, but it works - flush %l0 - mov DEMAP_CTX_PRIMARY, %o4 - stxa %o4, [%o4] ASI_DMMU_DEMAP - membar #Sync - stxa %o4, [%o4] ASI_IMMU_DEMAP - membar #Sync - flush %l0 - stxa %g0, [%o0] ASI_DMMU - membar #Sync - flush %l0 - wrpr %g0, 0, %tl ! Exit nucleus context -#endif -#ifdef DEBUG - set _C_LABEL(pmapdebug), %o1 - ld [%o1], %o1 - sethi %hi(0x40000), %o2 - btst %o2, %o1 - bz 0f - - set 1f, %o0 ! Debug printf - call _C_LABEL(prom_printf) - .data -1: - .asciz "Setting CPUINFO mappings...\r\n" - _ALIGN - .text -0: -#endif /* * Step 6: hunt through cpus list and find the one that @@ -5926,139 +5583,6 @@ ENTRY(cpu_mp_startup) flushw /* - * This code copied to preallocated 'claimed' memory 2-page block. - * cpu_args are at the beginning of that block - */ - rd %pc, %g2 ! cpu_args are at the beginning of this page - andn %g2, 0xfff, %g2 ! they should be smaller the half page - - /* map kernel text, data and cpuinfo_va, all locked*/ - sethi %hi(KERNBASE), %l0 ! Find our xlation - sethi %hi(DATA_START), %l3 - - ldx [%g2 + CBA_KTEXTP], %l2 - ldx [%g2 + CBA_KDATAP], %l5 - - LDPTR [%g2 + CBA_EKTEXT], %l1 - LDPTR [%g2 + CBA_EKDATA], %l4 - - sethi %hi(0xe0000000), %o0 ! V=1|SZ=11|NFO=0|IE=0 - sllx %o0, 32, %o0 ! Shift it into place - - sethi %hi(0x400000), %l6 ! Create a 4MB mask - add %l6, -1, %l7 - - mov -1, %o1 ! Create a nice mask - sllx %o1, 41, %o1 ! Mask off high bits - or %o1, 0xfff, %o1 ! We can just load this in 12 (of 13) bits - - andn %l2, %o1, %l2 ! Mask the phys page number - andn %l5, %o1, %l5 ! Mask the phys page number - - or %l2, %o0, %l2 ! Now take care of the high bits - or %l5, %o0, %l5 ! Now take care of the high bits - - /* - * XXX Demap kernel text/data from DTLB, probably not needed - */ - mov %l0, %o0 ! Demap all of kernel dmmu text segment - mov %l3, %o1 - set 0x2000, %o2 ! 8K page size - add %l1, %l7, %o5 ! Extend to 4MB boundary - andn %o5, %l7, %o5 -0: - stxa %o0, [%o0] ASI_DMMU_DEMAP ! Demap text segment - membar #Sync - cmp %o0, %o5 - bleu 0b - add %o0, %o2, %o0 - - add %l4, %l7, %o5 ! Extend to 4MB boundary - andn %o5, %l7, %o5 -0: - stxa %o1, [%o1] ASI_DMMU_DEMAP ! Demap data segment - membar #Sync - cmp %o1, %o5 - bleu 0b - add %o1, %o2, %o1 - - set (1<<14)-8, %o0 ! Clear out DCACHE -1: - stxa %g0, [%o0] ASI_DCACHE_TAG ! clear DCACHE line - membar #Sync - brnz,pt %o0, 1b - dec 8, %o0 - - /* - * Now map kernel text/data, first map data segment into the DMMU. - */ - set TLB_TAG_ACCESS, %o0 ! Now map it back in with a locked TTE - mov %l3, %o1 -#ifdef NO_VCACHE - ! And low bits: L=1|CP=1|CV=0(ugh)|E=0|P=1|W=1|G=0 - or %l5, TTE_L|TTE_CP|TTE_P|TTE_W, %o2 -#else - ! And low bits: L=1|CP=1|CV=1|E=0|P=1|W=1|G=0 - or %l5, TTE_L|TTE_CP|TTE_CV|TTE_P|TTE_W, %o2 -#endif - set 1f, %o5 -2: - stxa %o1, [%o0] ASI_DMMU ! Set VA for DSEG - membar #Sync ! We may need more membar #Sync in here - stxa %o2, [%g0] ASI_DMMU_DATA_IN ! Store TTE for DSEG - membar #Sync ! We may need more membar #Sync in here -1: - add %o1, %l6, %o1 ! increment VA - cmp %o1, %l4 ! Next 4MB mapping.... - blu,pt %xcc, 2b - add %o2, %l6, %o2 ! Increment tag - - /* - * Next map the text segment into the DMMU so we can get at RODATA. - */ - mov %l0, %o1 -#ifdef NO_VCACHE - ! And low bits: L=1|CP=1|CV=0(ugh)|E=0|P=1|W=0|G=0 - or %l2, TTE_L|TTE_CP|TTE_P, %o2 -#else - ! And low bits: L=1|CP=1|CV=1|E=0|P=1|W=0|G=0 - or %l2, TTE_L|TTE_CP|TTE_CV|TTE_P, %o2 -#endif -2: - stxa %o1, [%o0] ASI_DMMU ! Set VA for DSEG - membar #Sync ! We may need more membar #Sync in here - stxa %o2, [%g0] ASI_DMMU_DATA_IN ! Store TTE for DSEG - membar #Sync ! We may need more membar #Sync in here - flush %o5 ! Make IMMU see this too - add %o1, %l6, %o1 ! increment VA - cmp %o1, %l1 ! Next 4MB mapping.... - blu,pt %xcc, 2b - add %o2, %l6, %o2 ! Increment tag - - !! - !! Now, map in the kernel text as context==0 - !! - set TLB_TAG_ACCESS, %o0 - mov %l0, %o1 ! Context = 0 -#ifdef NO_VCACHE - ! And low bits: L=1|CP=1|CV=0(ugh)|E=0|P=1|W=1|G=0 - or %l2, TTE_L|TTE_CP|TTE_P, %o2 -#else - ! And low bits: L=1|CP=1|CV=1|E=0|P=1|W=1|G=0 - or %l2, TTE_L|TTE_CP|TTE_CV|TTE_P, %o2 -#endif -2: - stxa %o1, [%o0] ASI_IMMU ! Make IMMU point to it - membar #Sync ! We may need more membar #Sync in here - stxa %o2, [%g0] ASI_IMMU_DATA_IN ! Store it - membar #Sync ! We may need more membar #Sync in here - flush %o5 ! Make IMMU see this too - add %o1, %l6, %o1 ! increment VA - cmp %o1, %l1 ! Next 4MB mapping.... - blu,pt %xcc, 2b - add %o2, %l6, %o2 ! Increment tag - - /* * Get pointer to our cpu_info struct */ ldx [%g2 + CBA_CPUINFO], %l1 ! Load the interrupt stack's PA @@ -6088,6 +5612,16 @@ ENTRY(cpu_mp_startup) flush %o5 flush %l0 1: + !! + !! Map in cpu_info structure at CPUINFO_VA. + !! + set CPUINFO_VA, %l0 + stxa %l0, [%l5] ASI_DMMU ! Make DMMU point to it + membar #Sync + stxa %l2, [%g0] ASI_DMMU_DATA_IN ! Store it + membar #Sync + flush %o5 + flush %l0 !! !! Set 0 as primary context XXX @@ -6136,9 +5670,13 @@ ENTRY(cpu_mp_startup) jmpl %l0, %o7 mov %l1, %o0 wrpr %l1, 0, %tba ! Make sure the PROM didn't foul up. + + /* + * Switch to the kernel mode and run away. + */ wrpr %g0, WSTATE_KERN, %wstate - set _C_LABEL(mp_main), %l1 + set _C_LABEL(cpu_hatch), %l1 jmpl %l1, %o7 clr %g4 @@ -6146,12 +5684,14 @@ ENTRY(cpu_mp_startup) set _C_LABEL(sched_lock_idle), %l1 ! Acquire sched_lock jmpl %l1, %o7 nop + sethi %hi(_C_LABEL(sched_whichqs)), %l2 sethi %hi(CURLWP), %l7 set _C_LABEL(idle), %l1 jmpl %l1, %g0 - nop + clr %l4 +/* nop*/ NOTREACHED @@ -6159,6 +5699,29 @@ ENTRY(cpu_mp_startup) cpu_mp_startup_end: #endif + .align 8 +ENTRY(get_romtba) + retl + rdpr %tba, %o0 +/* + * int get_maxctx(void) + * + * Get number of available contexts. + * + */ + .align 8 +ENTRY(get_maxctx) + set CTX_SECONDARY, %o1 ! Store -1 in the context register + mov -1, %o2 + stxa %o2, [%o1] ASI_DMMU + membar #Sync + ldxa [%o1] ASI_DMMU, %o0 ! then read it back + membar #Sync + stxa %g0, [%o1] ASI_DMMU + membar #Sync + retl + inc %o0 + /* * openfirmware(cell* param); * @@ -7884,6 +7447,8 @@ Lsw_scan: cmp %l3, %o5 ! if (p == q) be,pn %icc, Lsw_panic_rq ! panic("switch rq"); EMPTY + +Lcpu_ok: LDPTR [%l3], %o0 ! tmp0 = p->p_forw; STPTR %o0, [%o5] ! q->ph_link = tmp0; STPTR %o5, [%o0 + PTRSZ] ! tmp0->p_back = q; @@ -7950,8 +7515,10 @@ cpu_loadproc: STPTR %l4, [%l7 + %lo(CURLWP)] ! restore old proc so we can save it cmp %l3, %l4 ! new lwp == curlwp? +#if !defined(MULTIPROCESSOR) be,a,pt %xcc, Lsw_sameproc ! yes, go return 0 clr %i0 +#endif mov 1, %i0 /* @@ -8010,6 +7577,7 @@ Lsw_load: _ALIGN .text #endif + /* set new cpcb */ STPTR %l3, [%l7 + %lo(CURLWP)] ! curlwp = p; STPTR %l1, [%l6 + %lo(CPCB)] ! cpcb = newpcb; @@ -8235,6 +7803,7 @@ swtchdelay: Debugger(); 2: #endif + ! wrpr %g0, 0, %cleanwin ! DEBUG clr %g4 ! This needs to point to the base of the data segment wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore default ASI diff --git a/sys/arch/sparc64/sparc64/machdep.c b/sys/arch/sparc64/sparc64/machdep.c index bd24c5995eb..43d43f9e9c1 100644 --- a/sys/arch/sparc64/sparc64/machdep.c +++ b/sys/arch/sparc64/sparc64/machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.183 2005/12/11 12:19:15 christos Exp $ */ +/* $NetBSD: machdep.c,v 1.184 2006/01/27 18:37:49 cdi Exp $ */ /*- * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. @@ -78,7 +78,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.183 2005/12/11 12:19:15 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.184 2006/01/27 18:37:49 cdi Exp $"); #include "opt_ddb.h" #include "opt_compat_netbsd.h" @@ -757,10 +757,9 @@ dumpsys() register int psize; daddr_t blkno; register int (*dump) __P((dev_t, daddr_t, caddr_t, size_t)); - int error = 0; + int j, error = 0; unsigned long todo; register struct mem_region *mp; - extern struct mem_region *mem; /* copy registers to memory */ snapshot(curpcb); @@ -803,10 +802,11 @@ dumpsys() blkno += pmap_dumpsize(); /* calculate total size of dump */ - for (todo = 0, mp = mem; mp->size; mp++) - todo += mp->size; + for (todo = 0, j = 0; j < phys_installed_size; j++) + todo += phys_installed[j].size; - for (mp = mem; mp->size; mp++) { + for (mp = &phys_installed[0], j = 0; j < phys_installed_size; + j++, mp = &phys_installed[j]) { unsigned i = 0, n; paddr_t maddr = mp->start; diff --git a/sys/arch/sparc64/sparc64/pmap.c b/sys/arch/sparc64/sparc64/pmap.c index dd11427fded..ddbe64e7b5a 100644 --- a/sys/arch/sparc64/sparc64/pmap.c +++ b/sys/arch/sparc64/sparc64/pmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.167 2006/01/12 18:04:09 cdi Exp $ */ +/* $NetBSD: pmap.c,v 1.168 2006/01/27 18:37:50 cdi Exp $ */ /* * * Copyright (C) 1996-1999 Eduardo Horvath. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.167 2006/01/12 18:04:09 cdi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.168 2006/01/27 18:37:50 cdi Exp $"); #undef NO_VCACHE /* Don't forget the locked TLB in dostart */ #define HWREF @@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.167 2006/01/12 18:04:09 cdi Exp $"); #include <machine/promlib.h> #include <machine/kcore.h> #include <machine/cpu.h> +#include <machine/bootinfo.h> #include "cache.h" @@ -159,16 +160,19 @@ paddr_t kdatap; vaddr_t ekdata; paddr_t ekdatap; +/* + * Kernel 4MB pages. + */ +extern struct tlb_entry *kernel_tlbs; +extern int kernel_tlb_slots; + static int npgs; static u_int nextavail; -static struct mem_region memlist[32]; /* Pick a random size here */ vaddr_t vmmap; /* one reserved MI vpage for /dev/mem */ -struct mem_region *mem, *avail, *orig; -int memsize; - -static int memh = 0, vmemh = 0; /* Handles to OBP devices */ +int phys_installed_size; /* Installed physical memory */ +struct mem_region *phys_installed; paddr_t avail_start, avail_end; /* These are used by ps & family */ @@ -405,6 +409,157 @@ static void pmap_alloc_bootargs(void) cpu_args->cb_initstack = v + 2*PAGE_SIZE; } +#if defined(MULTIPROCESSOR) +static void pmap_mp_init(void); + +static void +pmap_mp_init(void) +{ + pte_t *tp; + char *v; + int i; + + extern void cpu_mp_startup(void); + + if ( (v = OF_claim(NULL, PAGE_SIZE, PAGE_SIZE)) == NULL) { + panic("pmap_mp_init: Cannot claim a page."); + } + + bcopy(mp_tramp_code, v, mp_tramp_code_len); + *(u_long *)(v + mp_tramp_tlb_slots) = kernel_tlb_slots; + *(u_long *)(v + mp_tramp_func) = (u_long)cpu_mp_startup; + *(u_long *)(v + mp_tramp_ci) = (u_long)cpu_args; + tp = (pte_t *)(v + mp_tramp_code_len); + for (i = 0; i < kernel_tlb_slots; i++) { + tp[i].tag = kernel_tlbs[i].te_va; + tp[i].data = TSB_DATA(0, /* g */ + PGSZ_4M, /* sz */ + kernel_tlbs[i].te_pa, /* pa */ + 1, /* priv */ + 1, /* write */ + 1, /* cache */ + 1, /* aliased */ + 1, /* valid */ + 0 /* ie */); + tp[i].data |= TLB_L | TLB_CV; + printf("xtlb[%d]: Tag: %p Data: %p\n", + i, (void*)tp[i].tag, (void*)tp[i].data); + } + + for (i = 0; i < PAGE_SIZE; i += sizeof(long)) + flush(v + i); + + cpu_spinup_trampoline = (vaddr_t)v; +} +#else +#define pmap_mp_init() ((void)0) +#endif + +paddr_t pmap_kextract(vaddr_t va); + +paddr_t +pmap_kextract(vaddr_t va) +{ + int i; + paddr_t paddr = (paddr_t)-1; + + for (i = 0; i < kernel_tlb_slots; i++) { + if ((va & ~PAGE_MASK_4M) == kernel_tlbs[i].te_va) { + paddr = kernel_tlbs[i].te_pa + + (paddr_t)(va & PAGE_MASK_4M); + break; + } + } + + if (i == kernel_tlb_slots) { + panic("pmap_kextract: Address %p is not from kernel space.\n" + "Data segment is too small?\n", (void*)va); + } + + return (paddr); +} + +/* + * Bootstrap kernel allocator, allocates from unused space in 4MB kernel + * data segment meaning that + * + * - Access to allocated memory will never generate a trap + * - Allocated chunks are never reclaimed or freed + * - Allocation calls do not change PROM memlists + */ +static struct mem_region kdata_mem_pool; + +static void +kdata_alloc_init(vaddr_t va_start, vaddr_t va_end) +{ + vsize_t va_size = va_end - va_start; + + kdata_mem_pool.start = va_start; + kdata_mem_pool.size = va_size; + + BDPRINTF(PDB_BOOT, ("kdata_alloc_init(): %d bytes @%p.\n", va_size, + va_start)); +} + +static vaddr_t +kdata_alloc(vsize_t size, vsize_t align) +{ + vaddr_t va; + vsize_t asize; + + asize = roundup(kdata_mem_pool.start, align) - kdata_mem_pool.start; + + kdata_mem_pool.start += asize; + kdata_mem_pool.size -= asize; + + if (kdata_mem_pool.size < size) { + panic("kdata_alloc(): Data segment is too small.\n"); + } + + va = kdata_mem_pool.start; + kdata_mem_pool.start += size; + kdata_mem_pool.size -= size; + + BDPRINTF(PDB_BOOT, ("kdata_alloc(): Allocated %d@%p, %d free.\n", + size, (void*)va, kdata_mem_pool.size)); + + return (va); +} + +/* + * Unified routine for reading PROM properties. + */ +static void +pmap_read_memlist(const char *device, const char *property, void **ml, + int *ml_size, vaddr_t (* ml_alloc)(vsize_t, vsize_t)) +{ + void *va; + int size, handle; + + if ( (handle = prom_finddevice(device)) == 0) { + prom_printf("pmap_read_memlist(): No %s device found.\n", + device); + prom_halt(); + } + if ( (size = OF_getproplen(handle, property)) < 0) { + prom_printf("pmap_read_memlist(): %s/%s has no length.\n", + device, property); + prom_halt(); + } + if ( (va = (void*)(* ml_alloc)(size, sizeof(u_int64_t))) == NULL) { + prom_printf("pmap_read_memlist(): Cannot allocate memlist.\n"); + prom_halt(); + } + if (OF_getprop(handle, property, va, size) <= 0) { + prom_printf("pmap_read_memlist(): Cannot read %s/%s.\n", + device, property); + prom_halt(); + } + + *ml = va; + *ml_size = size; +} + /* * This is called during bootstrap, before the system is really initialized. * @@ -426,31 +581,53 @@ static void pmap_alloc_bootargs(void) */ void -pmap_bootstrap(kernelstart, kernelend, maxctx) +pmap_bootstrap(kernelstart, kernelend) u_long kernelstart, kernelend; - u_int maxctx; { - extern int data_start[], end[]; /* start of data segment */ + extern int etext, data_start[]; /* start of data segment */ extern int msgbufmapped; - struct mem_region *mp, *mp1; - int msgbufsiz; - int pcnt; + struct mem_region *mp, *mp1, *avail, *orig; + int i, j, pcnt, msgbufsiz; size_t s, sz; - int i, j; int64_t data; - vaddr_t va; + vaddr_t va, intstk; u_int64_t phys_msgbuf; - paddr_t newp, newkp; - vaddr_t newkv, firstaddr, intstk; - vsize_t kdsize, ktsize; + paddr_t newp; + + void *prom_memlist; + int prom_memlist_size; + + extern int get_maxctx(void); + + BDPRINTF(PDB_BOOT, ("Entered pmap_bootstrap.\n")); + + /* + * Calculate kernel size. + */ + ktext = kernelstart; + ktextp = pmap_kextract(ktext); + ektext = roundup((vaddr_t)&etext, PAGE_SIZE_4M); + ektextp = pmap_kextract(ektext); + + kdata = (vaddr_t)data_start; + kdatap = pmap_kextract(kdata); + ekdata = roundup(kernelend, PAGE_SIZE_4M); + ekdatap = roundup(pmap_kextract(kernelend), PAGE_SIZE_4M); + + BDPRINTF(PDB_BOOT, ("Virtual layout: text %lx-%lx, data %lx-%lx.\n", + ktext, ektext, kdata, ekdata)); + BDPRINTF(PDB_BOOT, ("Physical layout: text %lx-%lx, data %lx-%lx.\n", + ktextp, ektextp, kdatap, ekdatap)); + + /* Initialize bootstrap allocator. */ + kdata_alloc_init(kernelend + 1 * 1024 * 1024, ekdata); #ifdef DEBUG pmap_bootdebug(); #endif - BDPRINTF(PDB_BOOT, ("Entered pmap_bootstrap.\n")); - pmap_alloc_bootargs(); + pmap_mp_init(); /* * set machine page size @@ -460,32 +637,6 @@ pmap_bootstrap(kernelstart, kernelend, maxctx) uvm_setpagesize(); /* - * Find out how big the kernel's virtual address - * space is. The *$#@$ prom loses this info - */ - if ((vmemh = prom_finddevice("/virtual-memory")) == 0) { - prom_printf("no virtual-memory?"); - prom_halt(); - } - memset(memlist, 0, sizeof(memlist)); - if (OF_getprop(vmemh, "available", memlist, sizeof(memlist)) <= 0) { - prom_printf("no vmemory avail?"); - prom_halt(); - } - -#ifdef DEBUG - if (pmapdebug & PDB_BOOT) { - /* print out mem list */ - prom_printf("Available virtual memory:\n"); - for (mp = memlist; mp->size; mp++) { - prom_printf("memlist start %p size %lx\n", - (void *)(u_long)mp->start, - (u_long)mp->size); - } - prom_printf("End of available virtual memory\n"); - } -#endif - /* * Get hold or the message buffer. */ msgbufp = (struct kern_msgbuf *)(vaddr_t)MSGBUF_VA; @@ -512,191 +663,32 @@ pmap_bootstrap(kernelstart, kernelend, maxctx) initmsgbuf((caddr_t)msgbufp, msgbufsiz); /* - * Record kernel mapping -- we will map these with a permanent 4MB - * TLB entry when we initialize the CPU later. - */ - BDPRINTF(PDB_BOOT, ("translating kernelstart %p\n", - (void *)kernelstart)); - ktext = kernelstart; - ktextp = prom_vtop(kernelstart); - - kdata = (vaddr_t)data_start; - kdatap = prom_vtop(kdata); - ekdata = (vaddr_t)end; - - /* - * Find the real size of the kernel. Locate the smallest starting - * address > kernelstart. - */ - for (mp1 = mp = memlist; mp->size; mp++) { - /* - * Check whether this region is at the end of the kernel. - */ - if (mp->start >= ekdata && (mp1->start < ekdata || - mp1->start > mp->start)) - mp1 = mp; - } - if (mp1->start < kdata) - prom_printf("Kernel at end of vmem???\n"); - - BDPRINTF(PDB_BOOT1, - ("Kernel data is mapped at %lx, next free seg: %lx, %lx\n", - (long)kdata, (u_long)mp1->start, (u_long)mp1->size)); - - /* - * We save where we can start allocating memory. - */ - firstaddr = (ekdata + 07) & ~ 07; /* Longword align */ - - /* - * We reserve 100K to grow. - */ - ekdata += 100*KB; - - /* - * And set the end of the data segment to the end of what our - * bootloader allocated for us, if we still fit in there. - */ - if (ekdata < mp1->start) - ekdata = mp1->start; - -#define valloc(name, type, sz) do { \ - (name) = (type *)firstaddr; \ - firstaddr += (sz); \ - firstaddr = (firstaddr + 0xf) & ~0xf; \ -} while (0) - - /* - * Since we can't always give the loader the hint to align us on a 4MB - * boundary, we will need to do the alignment ourselves. First - * allocate a new 4MB aligned segment for the kernel, then map it - * in, copy the kernel over, swap mappings, then finally, free the - * old kernel. Then we can continue with this. - * - * We'll do the data segment up here since we know how big it is. - * We'll do the text segment after we've read in the PROM translations - * so we can figure out its size. - * - * The ctxbusy table takes about 64KB, the TSB up to 32KB, and the - * rest should be less than 1K, so 100KB extra should be plenty. - */ - kdsize = round_page(ekdata - kdata); - BDPRINTF(PDB_BOOT1, ("Kernel data size is %lx\n", (long)kdsize)); - - if ((kdatap & (4*MEG-1)) == 0) { - /* We were at a 4MB boundary -- claim the rest */ - psize_t szdiff = (4*MEG - kdsize) & (4*MEG - 1); - - BDPRINTF(PDB_BOOT1, ("Need to extend dseg by %lx\n", - (long)szdiff)); - if (szdiff) { - /* Claim the rest of the physical page. */ - newkp = kdatap + kdsize; - newkv = kdata + kdsize; - if (newkp != prom_claim_phys(newkp, szdiff)) { - prom_printf("pmap_bootstrap: could not claim " - "physical dseg extension " - "at %lx size %lx\n", - newkp, szdiff); - goto remap_data; - } - - /* And the rest of the virtual page. */ - if (prom_claim_virt(newkv, szdiff) != newkv) - prom_printf("pmap_bootstrap: could not claim " - "virtual dseg extension " - "at size %lx\n", newkv, szdiff); - - /* Make sure all 4MB are mapped */ - prom_map_phys(newkp, szdiff, newkv, -1); - } - } else { - psize_t sz1; -remap_data: - /* - * Either we're not at a 4MB boundary or we can't get the rest - * of the 4MB extension. We need to move the data segment. - * Leave 1MB of extra fiddle space in the calculations. - */ - - sz1 = (kdsize + 4*MEG - 1) & ~(4*MEG-1); - BDPRINTF(PDB_BOOT1, - ("Allocating new %lx kernel data at 4MB boundary\n", - (u_long)sz1)); - if ((newkp = prom_alloc_phys(sz1, 4*MEG)) == (paddr_t)-1 ) { - prom_printf("Cannot allocate new kernel\n"); - prom_halt(); - } - BDPRINTF(PDB_BOOT1, ("Allocating new va for buffer at %llx\n", - (u_int64_t)newkp)); - if ((newkv = (vaddr_t)prom_alloc_virt(sz1, 8)) == - (vaddr_t)-1) { - prom_printf("Cannot allocate new kernel va\n"); - prom_halt(); - } - BDPRINTF(PDB_BOOT1, ("Mapping in buffer %llx at %llx\n", - (u_int64_t)newkp, (u_int64_t)newkv)); - prom_map_phys(newkp, sz1, (vaddr_t)newkv, -1); - BDPRINTF(PDB_BOOT1, ("Copying %ld bytes kernel data...", - kdsize)); - memset((void*)newkv, 0, sz1); - memcpy((void*)newkv, (void*)kdata, kdsize); - BDPRINTF(PDB_BOOT1, ("done. Swapping maps..unmap new\n")); - prom_unmap_virt((vaddr_t)newkv, sz1); - BDPRINTF(PDB_BOOT, ("remap old ")); -#if 0 - /* - * calling the prom will probably require reading part of the - * data segment so we can't do this. */ - prom_unmap_virt((vaddr_t)kdatap, kdsize); -#endif - prom_map_phys(newkp, sz1, kdata, -1); - /* - * we will map in 4MB, more than we allocated, to allow - * further allocation - */ - BDPRINTF(PDB_BOOT1, ("free old\n")); - prom_free_phys(kdatap, kdsize); - kdatap = newkp; - BDPRINTF(PDB_BOOT1, - ("pmap_bootstrap: firstaddr is %lx virt (%lx phys)" - "avail for kernel\n", (u_long)firstaddr, - (u_long)prom_vtop(firstaddr))); - } - - /* * Find out how much RAM we have installed. */ BDPRINTF(PDB_BOOT, ("pmap_bootstrap: getting phys installed\n")); - if ((memh = prom_finddevice("/memory")) == 0) { - prom_printf("no memory?"); - prom_halt(); - } - memsize = OF_getproplen(memh, "reg") + 2 * sizeof(struct mem_region); - valloc(mem, struct mem_region, memsize); - memset(mem, 0, memsize); - if (OF_getprop(memh, "reg", mem, memsize) <= 0) { - prom_printf("no memory installed?"); - prom_halt(); - } - memsize /= sizeof(struct mem_region); + pmap_read_memlist("/memory", "reg", &prom_memlist, &prom_memlist_size, + kdata_alloc); + phys_installed = prom_memlist; + phys_installed_size = prom_memlist_size / sizeof(*phys_installed); #ifdef DEBUG if (pmapdebug & PDB_BOOT1) { /* print out mem list */ prom_printf("Installed physical memory:\n"); - for (mp = mem; mp->size; mp++) { + for (i = 0; i < phys_installed_size; i++) { prom_printf("memlist start %lx size %lx\n", - (u_long)mp->start, (u_long)mp->size); + (u_long)phys_installed[i].start, + (u_long)phys_installed[i].size); } } #endif - BDPRINTF(PDB_BOOT1, ("Calculating physmem:")); - for (mp = mem; mp->size; mp++) - physmem += btoc(mp->size); + BDPRINTF(PDB_BOOT1, ("Calculating physmem:")); + for (i = 0; i < phys_installed_size; i++) + physmem += btoc(phys_installed[i].size); BDPRINTF(PDB_BOOT1, (" result %x or %d pages\n", (int)physmem, (int)physmem)); + /* * Calculate approx TSB size. This probably needs tweaking. */ @@ -710,13 +702,11 @@ remap_data: /* * Save the prom translations */ - sz = OF_getproplen(vmemh, "translations"); - valloc(prom_map, struct prom_map, sz); - if (OF_getprop(vmemh, "translations", (void*)prom_map, sz) <= 0) { - prom_printf("no translations installed?"); - prom_halt(); - } - prom_map_size = sz / sizeof(struct prom_map); + pmap_read_memlist("/virtual-memory", "translations", &prom_memlist, + &prom_memlist_size, kdata_alloc); + prom_map = prom_memlist; + prom_map_size = prom_memlist_size / sizeof(struct prom_map); + #ifdef DEBUG if (pmapdebug & PDB_BOOT) { /* print out mem list */ @@ -730,111 +720,13 @@ remap_data: prom_printf("End of prom xlations\n"); } #endif - /* - * Hunt for the kernel text segment and figure out it size and - * alignment. - */ - for (i = 0; i < prom_map_size; i++) - if (prom_map[i].vstart == ktext) - break; - if (i == prom_map_size) - panic("No kernel text segment!"); - ktsize = prom_map[i].vsize; - ektext = ktext + ktsize; - - if (ktextp & (4*MEG-1)) { - /* Kernel text is not 4MB aligned -- need to fix that */ - BDPRINTF(PDB_BOOT1, - ("Allocating new %lx kernel text at 4MB boundary\n", - (u_long)ktsize)); - if ((newkp = prom_alloc_phys(ktsize, 4*MEG)) == 0 ) { - prom_printf("Cannot allocate new kernel text\n"); - prom_halt(); - } - BDPRINTF(PDB_BOOT1, ("Allocating new va for buffer at %llx\n", - (u_int64_t)newkp)); - if ((newkv = (vaddr_t)prom_alloc_virt(ktsize, 8)) == - (vaddr_t)-1) { - prom_printf("Cannot allocate new kernel text VA\n"); - prom_halt(); - } - BDPRINTF(PDB_BOOT1, ("Mapping in buffer %lx at %lx\n", - (u_long)newkp, (u_long)newkv)); - prom_map_phys(newkp, ktsize, (vaddr_t)newkv, -1); - BDPRINTF(PDB_BOOT1, ("Copying %ld bytes kernel text...", - ktsize)); - memcpy((void *)newkv, (void *)ktext, - ktsize); - BDPRINTF(PDB_BOOT1, ("done. Swapping maps..unmap new\n")); - prom_unmap_virt((vaddr_t)newkv, 4*MEG); - BDPRINTF(PDB_BOOT, ("remap old ")); -#if 0 - /* - * calling the prom will probably require reading part of the - * text segment so we can't do this. - */ - prom_unmap_virt((vaddr_t)ktextp, ktsize); -#endif - prom_map_phys(newkp, ktsize, ktext, -1); - /* - * we will map in 4MB, more than we allocated, to allow - * further allocation - */ - BDPRINTF(PDB_BOOT1, ("free old\n")); - prom_free_phys(ktextp, ktsize); - ktextp = newkp; - - BDPRINTF(PDB_BOOT1, - ("pmap_bootstrap: firstaddr is %lx virt (%lx phys)" - "avail for kernel\n", (u_long)firstaddr, - (u_long)prom_vtop(firstaddr))); - - /* - * Re-fetch translations -- they've certainly changed. - */ - if (OF_getprop(vmemh, "translations", (void*)prom_map, sz) <= - 0) { - prom_printf("no translations installed?"); - prom_halt(); - } -#ifdef DEBUG - if (pmapdebug & PDB_BOOT) { - /* print out mem list */ - prom_printf("New prom xlations:\n"); - for (i = 0; i < prom_map_size; i++) { - prom_printf("start %016lx size %016lx tte %016lx\n", - (u_long)prom_map[i].vstart, - (u_long)prom_map[i].vsize, - (u_long)prom_map[i].tte); - } - prom_printf("End of prom xlations\n"); - } -#endif - } - ektextp = ktextp + ktsize; /* * Here's a quick in-lined reverse bubble sort. It gets rid of * any translations inside the kernel data VA range. */ for(i = 0; i < prom_map_size; i++) { - if (prom_map[i].vstart >= kdata && - prom_map[i].vstart <= firstaddr) { - prom_map[i].vstart = 0; - prom_map[i].vsize = 0; - } - if (prom_map[i].vstart >= ktext && - prom_map[i].vstart <= ektext) { - prom_map[i].vstart = 0; - prom_map[i].vsize = 0; - } for(j = i; j < prom_map_size; j++) { - if (prom_map[j].vstart >= kdata && - prom_map[j].vstart <= firstaddr) - continue; /* this is inside the kernel */ - if (prom_map[j].vstart >= ktext && - prom_map[j].vstart <= ektext) - continue; /* this is inside the kernel */ if (prom_map[j].vstart > prom_map[i].vstart) { struct prom_map tmp; tmp = prom_map[i]; @@ -869,37 +761,27 @@ remap_data: * Now the kernel text segment is in its final location we can try to * find out how much memory really is free. */ - sz = OF_getproplen(memh, "available") + sizeof(struct mem_region); - valloc(orig, struct mem_region, sz); - memset(orig, 0, sz); - if (OF_getprop(memh, "available", orig, sz) <= 0) { - prom_printf("no available RAM?"); - prom_halt(); - } -#ifdef DEBUG - if (pmapdebug & PDB_BOOT1) { - /* print out mem list */ - prom_printf("Available physical memory:\n"); - for (mp = orig; mp->size; mp++) { - prom_printf("memlist start %lx size %lx\n", - (u_long)mp->start, (u_long)mp->size); - } - prom_printf("End of available physical memory\n"); - } -#endif - valloc(avail, struct mem_region, sz); - memset(avail, 0, sz); - for (pcnt = 0, mp = orig, mp1 = avail; (mp1->size = mp->size); - mp++, mp1++) { - mp1->start = mp->start; - pcnt++; + pmap_read_memlist("/memory", "available", &prom_memlist, + &prom_memlist_size, kdata_alloc); + orig = prom_memlist; + sz = prom_memlist_size; + pcnt = prom_memlist_size / sizeof(*orig); + + BDPRINTF(PDB_BOOT1, ("Available physical memory:\n")); + avail = (struct mem_region*)kdata_alloc(sz, sizeof(u_int64_t)); + for (i = 0; i < pcnt; i++) { + avail[i] = orig[i]; + BDPRINTF(PDB_BOOT1, ("memlist start %lx size %lx\n", + (u_long)orig[i].start, + (u_long)orig[i].size)); } + BDPRINTF(PDB_BOOT1, ("End of available physical memory\n")); /* * Allocate and initialize a context table */ - numctx = maxctx; - valloc(ctxbusy, paddr_t, CTXSIZE); + numctx = get_maxctx(); + ctxbusy = (paddr_t *)kdata_alloc(CTXSIZE, sizeof(u_int64_t)); memset(ctxbusy, 0, CTXSIZE); LIST_INIT(&pmap_ctxlist); @@ -908,61 +790,29 @@ remap_data: * * We will use the left over space to flesh out the kernel pmap. */ - BDPRINTF(PDB_BOOT1, ("firstaddr before TSB=%lx\n", - (u_long)firstaddr)); - firstaddr = ((firstaddr + TSBSIZE - 1) & ~(TSBSIZE - 1)); -#ifdef DEBUG - /* First, page align */ - i = (firstaddr + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); - if ((int)firstaddr < i) { - prom_printf("TSB alloc fixup failed\n"); - prom_printf("frobbed i, firstaddr before TSB=%x, %lx\n", - (int)i, (u_long)firstaddr); - panic("TSB alloc"); - prom_halt(); - } -#endif - BDPRINTF(PDB_BOOT, ("frobbed i, firstaddr before TSB=%x, %lx\n", - (int)i, (u_long)firstaddr)); - valloc(tsb_dmmu, pte_t, TSBSIZE); + tsb_dmmu = (pte_t *)kdata_alloc(TSBSIZE, TSBSIZE); memset(tsb_dmmu, 0, TSBSIZE); - valloc(tsb_immu, pte_t, TSBSIZE); + tsb_immu = (pte_t *)kdata_alloc(TSBSIZE, TSBSIZE); memset(tsb_immu, 0, TSBSIZE); - BDPRINTF(PDB_BOOT1, ("firstaddr after TSB=%lx\n", (u_long)firstaddr)); BDPRINTF(PDB_BOOT1, ("TSB allocated at %p/%p size %08x\n", tsb_dmmu, tsb_immu, TSBSIZE)); - /* - * Page align all regions. - * Non-page memory isn't very interesting to us. - * Also, sort the entries for ascending addresses. - * - * And convert from virtual to physical addresses. - */ - - BDPRINTF(PDB_BOOT, ("kernel virtual size %08lx - %08lx\n", - (u_long)kernelstart, (u_long)firstaddr)); - kdata = kdata & ~PGOFSET; - ekdata = firstaddr; - ekdata = (ekdata + PGOFSET) & ~PGOFSET; - BDPRINTF(PDB_BOOT1, ("kernel virtual size %08lx - %08lx\n", - (u_long)kernelstart, (u_long)kernelend)); - ekdatap = ekdata - kdata + kdatap; - /* Switch from vaddrs to paddrs */ - if(ekdatap > (kdatap + 4*MEG)) { - prom_printf("Kernel size exceeds 4MB\n"); - } - + BDPRINTF(PDB_BOOT, ("ktext %08lx[%08lx] - %08lx[%08lx] : " + "kdata %08lx[%08lx] - %08lx[%08lx]\n", + (u_long)ktext, (u_long)ktextp, + (u_long)ektext, (u_long)ektextp, + (u_long)kdata, (u_long)kdatap, + (u_long)ekdata, (u_long)ekdatap)); #ifdef DEBUG if (pmapdebug & PDB_BOOT1) { /* print out mem list */ prom_printf("Available %lx physical memory before cleanup:\n", (u_long)avail); - for (mp = avail; mp->size; mp++) { + for (i = 0; i < pcnt; i++) { prom_printf("memlist start %lx size %lx\n", - (u_long)mp->start, - (u_long)mp->size); + (u_long)avail[i].start, + (u_long)avail[i].size); } prom_printf("End of available physical memory before cleanup\n"); prom_printf("kernel physical text size %08lx - %08lx\n", @@ -996,34 +846,7 @@ remap_data: * memory lists. (NB: we may have already alloc'ed the entire space). */ npgs = 0; - for (mp = avail; mp->size; mp++) { - /* - * Check whether this region holds all of the kernel. - */ - s = mp->start + mp->size; - if (mp->start < kdatap && s > roundup(ekdatap, 4*MEG)) { - avail[pcnt].start = roundup(ekdatap, 4*MEG); - avail[pcnt++].size = s - kdatap; - mp->size = kdatap - mp->start; - } - /* - * Look whether this regions starts within the kernel. - */ - if (mp->start >= kdatap && - mp->start < roundup(ekdatap, 4*MEG)) { - s = ekdatap - mp->start; - if (mp->size > s) - mp->size -= s; - else - mp->size = 0; - mp->start = roundup(ekdatap, 4*MEG); - } - /* - * Now look whether this region ends within the kernel. - */ - s = mp->start + mp->size; - if (s > kdatap && s < roundup(ekdatap, 4*MEG)) - mp->size -= s - kdatap; + for (mp = avail, i = 0; i < pcnt; i++, mp = &avail[i]) { /* * Now page align the start of the region. */ @@ -1078,6 +901,9 @@ remap_data: * In future we should be able to specify both allocated * and free. */ + BDPRINTF(PDB_BOOT1, ("uvm_page_physload(%lx, %lx)\n", + (long)mp->start, + (long)(mp->start + mp->size))); uvm_page_physload( atop(mp->start), atop(mp->start+mp->size), @@ -1086,25 +912,13 @@ remap_data: VM_FREELIST_DEFAULT); } -#if 0 - /* finally, free up any space that valloc did not use */ - prom_unmap_virt((vaddr_t)ekdata, roundup(ekdata, 4*MEG) - ekdata); - if (ekdatap < roundup(kdatap, 4*MEG)) { - uvm_page_physload(atop(ekdatap), - atop(roundup(ekdatap, (4*MEG))), - atop(ekdatap), - atop(roundup(ekdatap, (4*MEG))), - VM_FREELIST_DEFAULT); - } -#endif - #ifdef DEBUG if (pmapdebug & PDB_BOOT) { /* print out mem list */ prom_printf("Available physical memory after cleanup:\n"); - for (mp = avail; mp->size; mp++) { + for (i = 0; i < pcnt; i++) { prom_printf("avail start %lx size %lx\n", - (long)mp->start, (long)mp->size); + (long)avail[i].start, (long)avail[i].size); } prom_printf("End of available physical memory after cleanup\n"); } @@ -1307,6 +1121,8 @@ remap_data: avail_end = mp->start+mp->size; BDPRINTF(PDB_BOOT1, ("Finished pmap_bootstrap()\n")); + BDPRINTF(PDB_BOOT, ("left kdata: %" PRId64 " @%" PRIx64 ".\n", + kdata_mem_pool.size, kdata_mem_pool.start)); } /* @@ -2227,12 +2043,12 @@ pmap_extract(pm, va, pap) if (pm == pmap_kernel() && va >= kdata && va < roundup(ekdata, 4*MEG)) { /* Need to deal w/locked TLB entry specially. */ - pa = (paddr_t)(kdatap - kdata + va); + pa = pmap_kextract(va); DPRINTF(PDB_EXTRACT, ("pmap_extract: va=%lx pa=%llx\n", (u_long)va, (unsigned long long)pa)); } else if (pm == pmap_kernel() && va >= ktext && va < ektext) { /* Need to deal w/locked TLB entry specially. */ - pa = (paddr_t)(ktextp - ktext + va); + pa = pmap_kextract(va); DPRINTF(PDB_EXTRACT, ("pmap_extract: va=%lx pa=%llx\n", (u_long)va, (unsigned long long)pa)); } else { @@ -2318,7 +2134,7 @@ pmap_dumpsize() int sz; sz = ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t)); - sz += memsize * sizeof(phys_ram_seg_t); + sz += phys_installed_size * sizeof(phys_ram_seg_t); return btodb(sz + DEV_BSIZE - 1); } @@ -2333,7 +2149,7 @@ pmap_dumpsize() * * kcore_seg_t MI header defined in <sys/kcore.h>) * cpu_kcore_hdr_t MD header defined in <machine/kcore.h>) - * phys_ram_seg_t[memsize] physical memory segments + * phys_ram_seg_t[phys_installed_size] physical memory segments */ int pmap_dumpmmu(dump, blkno) @@ -2391,7 +2207,7 @@ pmap_dumpmmu(dump, blkno) kcpu->kdatasz = (u_int64_t)ekdatap - kdatap; /* Now the memsegs */ - kcpu->nmemseg = memsize; + kcpu->nmemseg = phys_installed_size; kcpu->memsegoffset = memsegoffset = ALIGN(sizeof(cpu_kcore_hdr_t)); /* Now we need to point this at our kernel pmap. */ @@ -2401,9 +2217,9 @@ pmap_dumpmmu(dump, blkno) /* Note: we have assumed everything fits in buffer[] so far... */ bp = (int *)((long)kcpu + ALIGN(sizeof(cpu_kcore_hdr_t))); - for (i = 0; i < memsize; i++) { - memseg.start = mem[i].start; - memseg.size = mem[i].size; + for (i = 0; i < phys_installed_size; i++) { + memseg.start = phys_installed[i].start; + memseg.size = phys_installed[i].size; EXPEDITE(&memseg, sizeof(phys_ram_seg_t)); } @@ -2420,12 +2236,15 @@ int pmap_pa_exists(pa) paddr_t pa; { - struct mem_region *mp; + int i; /* Just go through physical memory list & see if we're there */ - for (mp = mem; mp->size && mp->start <= pa; mp++) - if (mp->start <= pa && mp->start + mp->size >= pa) + for (i = 0; i < phys_installed_size; i++) { + if ((phys_installed[i].start <= pa) && + (phys_installed[i].start + + phys_installed[i].size >= pa)) return 1; + } return 0; } |
