diff options
| author | cdi <cdi@NetBSD.org> | 2006-01-27 18:37:49 +0000 |
|---|---|---|
| committer | cdi <cdi@NetBSD.org> | 2006-01-27 18:37:49 +0000 |
| commit | 4c2e4320bd13e4cbea1e7f2bb4e130202d00a523 (patch) | |
| tree | 221f0a253d99b181928545feb19a2b2493c85401 | |
| parent | 97aa1417ff2c6fb2f1ce0c64e018be5211e81769 (diff) | |
Alter sparc64 bootstrap, catch up to ofwboot v1.9:
- Accept bootinfo structure passed down from ofwboot v1.9
- Drop kernel re-mapping code
- Use permanent 4MB mappings provided by the loader instead
- Change kernel entry address to point directly at the code instead of pointing
at the trap table's first slot. This allows the bootloader to detect
those kernels which are aware of the new boot scheme
- Due to the changes in kernel mapping code, alter secondary CPU bootstrap
code to use trampoline just like FreeBSD does (some FreeBSD code is used
here as well)
| -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; } |
