Stop linking against a direct-mapped virtual address and instead

use the PBVM. This eliminates the implied hardcoding of the
physical address at which the kernel needs to be loaded. Using the
PBVM makes it possible to load the kernel irrespective of the
physical memory organization and allows us to replicate kernel text
on NUMA machines.

While here, reduce the direct-mapped page size to the kernel's
page size so that we can support memory attributes better.
This commit is contained in:
Marcel Moolenaar 2011-04-30 20:49:00 +00:00
parent 627cecc5c9
commit 7df304f3e0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=221271
14 changed files with 533 additions and 314 deletions

View File

@ -92,6 +92,7 @@ ia64/ia64/locore.S standard no-obj
ia64/ia64/machdep.c standard
ia64/ia64/mca.c standard
ia64/ia64/mem.c optional mem
ia64/ia64/mp_locore.S optional smp
ia64/ia64/mp_machdep.c optional smp
ia64/ia64/nexus.c standard
ia64/ia64/pal.S standard

View File

@ -3,7 +3,7 @@ OUTPUT_FORMAT("elf64-ia64-freebsd", "elf64-ia64-freebsd", "elf64-ia64-freebsd")
OUTPUT_ARCH(ia64)
ENTRY(__start)
SEARCH_DIR(/usr/lib);
kernel_text = 0xe000000004000000;
kernel_text = 0x9ffc000000000000;
SECTIONS
{
/* Read-only sections, merged into text segment: */
@ -11,10 +11,10 @@ SECTIONS
.interp : { *(.interp) }
PROVIDE (btext = .);
.ivt : { *(.ivt) }
.text :
{
*(.text.ivt)
*(.ivt)
*(.ivt.text)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
@ -60,9 +60,11 @@ SECTIONS
page in the loader virtual memory. */
. = ALIGN(65536);
PROVIDE (bdata = .);
.data :
{
*(.data.kstack .data .data.* .gnu.linkonce.d.*)
*(.ivt.data)
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }

View File

@ -129,7 +129,7 @@ efi_boot_minimal(uint64_t systbl)
setvirt = (void *)IA64_PHYS_TO_RR7((u_long)efi_runtime->rt_setvirtual);
status = ia64_efi_physical(setvirt, bootinfo->bi_memmap_size,
bootinfo->bi_memdesc_size, bootinfo->bi_memdesc_version,
bootinfo->bi_memmap);
ia64_tpa(bootinfo->bi_memmap));
return ((status < 0) ? EFAULT : 0);
}
@ -164,7 +164,7 @@ efi_md_first(void)
if (bootinfo->bi_memmap == 0)
return (NULL);
return ((struct efi_md *)IA64_PHYS_TO_RR7(bootinfo->bi_memmap));
return ((struct efi_md *)bootinfo->bi_memmap);
}
struct efi_md *
@ -172,7 +172,7 @@ efi_md_next(struct efi_md *md)
{
uint64_t plim;
plim = IA64_PHYS_TO_RR7(bootinfo->bi_memmap + bootinfo->bi_memmap_size);
plim = bootinfo->bi_memmap + bootinfo->bi_memmap_size;
md = (struct efi_md *)((uintptr_t)md + bootinfo->bi_memdesc_size);
return ((md >= (struct efi_md *)plim) ? NULL : md);
}

View File

@ -48,9 +48,16 @@ __FBSDID("$FreeBSD$");
* ar.k4 = PCPU data
*/
.section .ivt.data, "aw"
.global pmap_ptc_g_sem
pmap_ptc_g_sem: data8 0
.global ia64_kptdir
ia64_kptdir: data8 0
#ifdef EXCEPTION_TRACING
.data
.global xtrace, xhead
xtrace: .space 1024*5*8
xhead: data8 xtrace
@ -101,7 +108,7 @@ xhead: data8 xtrace
#endif
.section .text.ivt, "ax"
.section .ivt.text, "ax"
/*
* exception_save: save interrupted state
@ -129,7 +136,7 @@ ENTRY_NOPROFILE(exception_save, 0)
;;
}
{ .mmi
cmp.le p14,p15=5,r31
cmp.le p14,p15=IA64_VM_MINKERN_REGION,r31
;;
(p15) mov r23=ar.k7 // kernel memory stack
(p14) mov r23=sp
@ -233,7 +240,7 @@ exception_save_restart:
{ .mmi
st8 [r30]=r19,16 // rnat
st8 [r31]=r0,16 // __spare
cmp.le p12,p13=5,r24
cmp.le p12,p13=IA64_VM_MINKERN_REGION,r24
;;
}
{ .mmi
@ -602,7 +609,7 @@ ENTRY_NOPROFILE(exception_restore, 0)
{ .mmi
ld8.fill r1=[r30],16 // gp
ld8 r27=[r31],16 // ndirty
cmp.le p14,p15=5,r28
cmp.le p14,p15=IA64_VM_MINKERN_REGION,r28
;;
}
{ .mmi
@ -915,7 +922,7 @@ IVT_ENTRY(Alternate_Instruction_TLB, 0x0c00)
extr.u r17=r16,61,3 // get region number
mov r19=PTE_PRESENT+PTE_ACCESSED+PTE_DIRTY+PTE_PL_KERN+PTE_AR_RWX
;;
cmp.eq p13,p0=4,r17 // RR4?
cmp.eq p13,p0=IA64_PBVM_RR,r17 // RR4?
(p13) br.cond.sptk.few 4f
;;
cmp.ge p13,p0=5,r17 // RR0-RR5?
@ -958,7 +965,7 @@ IVT_ENTRY(Alternate_Data_TLB, 0x1000)
extr.u r17=r16,61,3 // get region number
mov r19=PTE_PRESENT+PTE_ACCESSED+PTE_DIRTY+PTE_PL_KERN+PTE_AR_RWX
;;
cmp.eq p13,p0=4,r17 // RR4?
cmp.eq p13,p0=IA64_PBVM_RR,r17 // RR4?
(p13) br.cond.sptk.few 4f
;;
cmp.ge p13,p0=5,r17 // RR0-RR5?
@ -1007,21 +1014,22 @@ IVT_ENTRY(Data_Nested_TLB, 0x1400)
// double nested faults. Since all virtual addresses we encounter
// here are direct mapped region 7 addresses, we have no problem
// constructing physical addresses.
{ .mlx
rsm psr.dt
nop 0
movl r27=ia64_kptdir
;;
}
{ .mii
srlz.d
dep r27=0,r27,61,3
;;
ld8 r27=[r27]
extr.u r28=r30,3*PAGE_SHIFT-8, PAGE_SHIFT-3 // dir L0 index
}
{ .mii
ld8 r27=[r27] // dir L0 page
extr.u r26=r30,2*PAGE_SHIFT-5, PAGE_SHIFT-3 // dir L1 index
;;
}
{ .mmi
rsm psr.dt
;;
srlz.d
dep r27=0,r27,61,3
;;
}

View File

@ -77,13 +77,13 @@ ASSYM(ERESTART, ERESTART);
ASSYM(FRAME_SYSCALL, FRAME_SYSCALL);
ASSYM(IA64_ID_PAGE_SHIFT, IA64_ID_PAGE_SHIFT);
ASSYM(IA64_PBVM_BASE, IA64_PBVM_BASE);
ASSYM(IA64_PBVM_PAGE_SHIFT, IA64_PBVM_PAGE_SHIFT);
ASSYM(IA64_PBVM_PGTBL, IA64_PBVM_PGTBL);
ASSYM(IA64_PBVM_RR, IA64_PBVM_RR);
ASSYM(IA64_VM_MINKERN_REGION, IA64_VM_MINKERN_REGION);
ASSYM(KSTACK_PAGES, KSTACK_PAGES);
ASSYM(MC_PRESERVED, offsetof(mcontext_t, mc_preserved));

View File

@ -1,4 +1,5 @@
/*-
* Copyright (c) 2001-2011 Marcel Moolenaar
* Copyright (c) 1998 Doug Rabson
* All rights reserved.
*
@ -26,12 +27,10 @@
* $FreeBSD$
*/
#include <sys/syscall.h>
#include <machine/asm.h>
#include <machine/ia64_cpu.h>
#include <machine/intrcnt.h>
#include <machine/pte.h>
#include <machine/intrcnt.h>
#include <assym.s>
/*
@ -40,7 +39,7 @@
*/
#define FW_STACK_SIZE 3*PAGE_SIZE
.section .data.kstack, "aw"
.section .ivt.data, "aw"
.align PAGE_SIZE
.global kstack
kstack: .space FW_STACK_SIZE
@ -82,7 +81,7 @@ ENTRY_NOPROFILE(__start, 1)
}
{ .mlx
mov ar.bspstore=r16 // switch backing store
movl r16=pa_bootinfo
movl r16=bootinfo
;;
}
{ .mmi
@ -187,124 +186,6 @@ enter_userland:
}
END(fork_trampoline)
#ifdef SMP
/*
* AP wake-up entry point. The handoff state is similar as for the BSP,
* as described on page 3-9 of the IPF SAL Specification. The difference
* lies in the contents of register b0. For APs this register holds the
* return address into the SAL rendezvous routine.
*
* Note that we're responsible for clearing the IRR bit by reading cr.ivr
* and issuing the EOI to the local SAPIC.
*/
.align 32
ENTRY_NOPROFILE(os_boot_rendez,0)
mov r16=cr.ivr // clear IRR bit
;;
srlz.d
mov cr.eoi=r0 // ACK the wake-up
;;
srlz.d
rsm IA64_PSR_IC|IA64_PSR_I
;;
mov r16 = (5<<8)|(PAGE_SHIFT<<2)|1
movl r17 = 5<<61
;;
mov rr[r17] = r16
;;
srlz.d
mov r16 = (6<<8)|(IA64_ID_PAGE_SHIFT<<2)
movl r17 = 6<<61
;;
mov rr[r17] = r16
;;
srlz.d
mov r16 = (7<<8)|(IA64_ID_PAGE_SHIFT<<2)
movl r17 = 7<<61
;;
mov rr[r17] = r16
;;
srlz.d
mov r18 = 28<<2
movl r16 = PTE_PRESENT+PTE_MA_WB+PTE_ACCESSED+PTE_DIRTY+ \
PTE_PL_KERN+PTE_AR_RWX+PTE_ED
;;
mov cr.ifa = r17
mov cr.itir = r18
ptr.d r17, r18
ptr.i r17, r18
;;
srlz.i
;;
itr.d dtr[r0] = r16
mov r18 = IA64_DCR_DEFAULT
;;
itr.i itr[r0] = r16
mov cr.dcr = r18
;;
srlz.i
;;
1: mov r16 = ip
add r17 = 2f-1b, r17
movl r18 = (IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_DFH|IA64_PSR_DT|IA64_PSR_IC|IA64_PSR_IT|IA64_PSR_RT)
;;
add r17 = r17, r16
mov cr.ipsr = r18
mov cr.ifs = r0
;;
mov cr.iip = r17
;;
rfi
.align 32
2:
{ .mlx
mov ar.rsc = 0
movl r16 = ia64_vector_table // set up IVT early
;;
}
{ .mlx
mov cr.iva = r16
movl r16 = ap_stack
;;
}
{ .mmi
srlz.i
;;
ld8 r16 = [r16]
mov r18 = KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16
;;
}
{ .mlx
mov ar.bspstore = r16
movl gp = __gp
;;
}
{ .mmi
loadrs
;;
alloc r17 = ar.pfs, 0, 0, 0, 0
add sp = r18, r16
;;
}
{ .mib
mov ar.rsc = 3
nop 0
br.call.sptk.few rp = ia64_ap_startup
;;
}
/* NOT REACHED */
9:
{ .mib
nop 0
nop 0
br.sptk 9b
;;
}
END(os_boot_rendez)
#endif /* !SMP */
/*
* Create a default interrupt name table. The first entry (vector 0) is
* hardwaired to the clock interrupt.

View File

@ -115,7 +115,6 @@ SYSCTL_UINT(_hw_freq, OID_AUTO, itc, CTLFLAG_RD, &itc_freq, 0,
int cold = 1;
u_int64_t pa_bootinfo;
struct bootinfo *bootinfo;
struct pcpu pcpu0;
@ -128,8 +127,9 @@ extern u_int64_t epc_sigtramp[];
struct fpswa_iface *fpswa_iface;
u_int64_t ia64_pal_base;
u_int64_t ia64_port_base;
vm_size_t ia64_pal_size;
vm_paddr_t ia64_pal_base;
vm_offset_t ia64_port_base;
u_int64_t ia64_lapic_addr = PAL_PIB_DEFAULT_ADDR;
@ -548,15 +548,15 @@ map_vhpt(uintptr_t vhpt)
pte |= vhpt & PTE_PPN_MASK;
__asm __volatile("ptr.d %0,%1" :: "r"(vhpt),
"r"(IA64_ID_PAGE_SHIFT<<2));
"r"(pmap_vhpt_log2size << 2));
__asm __volatile("mov %0=psr" : "=r"(psr));
__asm __volatile("rsm psr.ic|psr.i");
ia64_srlz_i();
ia64_set_ifa(vhpt);
ia64_set_itir(IA64_ID_PAGE_SHIFT << 2);
ia64_set_itir(pmap_vhpt_log2size << 2);
ia64_srlz_d();
__asm __volatile("itr.d dtr[%0]=%1" :: "r"(2), "r"(pte));
__asm __volatile("itr.d dtr[%0]=%1" :: "r"(3), "r"(pte));
__asm __volatile("mov psr.l=%0" :: "r" (psr));
ia64_srlz_i();
}
@ -565,25 +565,36 @@ void
map_pal_code(void)
{
pt_entry_t pte;
vm_offset_t va;
vm_size_t sz;
uint64_t psr;
u_int shft;
if (ia64_pal_base == 0)
if (ia64_pal_size == 0)
return;
va = IA64_PHYS_TO_RR7(ia64_pal_base);
sz = ia64_pal_size;
shft = 0;
while (sz > 1) {
shft++;
sz >>= 1;
}
pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY |
PTE_PL_KERN | PTE_AR_RWX;
pte |= ia64_pal_base & PTE_PPN_MASK;
__asm __volatile("ptr.d %0,%1; ptr.i %0,%1" ::
"r"(IA64_PHYS_TO_RR7(ia64_pal_base)), "r"(IA64_ID_PAGE_SHIFT<<2));
__asm __volatile("ptr.d %0,%1; ptr.i %0,%1" :: "r"(va), "r"(shft<<2));
__asm __volatile("mov %0=psr" : "=r"(psr));
__asm __volatile("rsm psr.ic|psr.i");
ia64_srlz_i();
ia64_set_ifa(IA64_PHYS_TO_RR7(ia64_pal_base));
ia64_set_itir(IA64_ID_PAGE_SHIFT << 2);
ia64_set_ifa(va);
ia64_set_itir(shft << 2);
ia64_srlz_d();
__asm __volatile("itr.d dtr[%0]=%1" :: "r"(1), "r"(pte));
__asm __volatile("itr.d dtr[%0]=%1" :: "r"(4), "r"(pte));
ia64_srlz_d();
__asm __volatile("itr.i itr[%0]=%1" :: "r"(1), "r"(pte));
__asm __volatile("mov psr.l=%0" :: "r" (psr));
@ -598,7 +609,7 @@ map_gateway_page(void)
pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY |
PTE_PL_KERN | PTE_AR_X_RX;
pte |= (uint64_t)ia64_gateway_page & PTE_PPN_MASK;
pte |= ia64_tpa((uint64_t)ia64_gateway_page) & PTE_PPN_MASK;
__asm __volatile("ptr.d %0,%1; ptr.i %0,%1" ::
"r"(VM_MAXUSER_ADDRESS), "r"(PAGE_SHIFT << 2));
@ -609,9 +620,9 @@ map_gateway_page(void)
ia64_set_ifa(VM_MAXUSER_ADDRESS);
ia64_set_itir(PAGE_SHIFT << 2);
ia64_srlz_d();
__asm __volatile("itr.d dtr[%0]=%1" :: "r"(3), "r"(pte));
__asm __volatile("itr.d dtr[%0]=%1" :: "r"(5), "r"(pte));
ia64_srlz_d();
__asm __volatile("itr.i itr[%0]=%1" :: "r"(3), "r"(pte));
__asm __volatile("itr.i itr[%0]=%1" :: "r"(2), "r"(pte));
__asm __volatile("mov psr.l=%0" :: "r" (psr));
ia64_srlz_i();
@ -680,17 +691,6 @@ ia64_init(void)
* information provided by the boot program).
*/
/*
* pa_bootinfo is the physical address of the bootinfo block as
* passed to us by the loader and set in locore.s.
*/
bootinfo = (struct bootinfo *)(IA64_PHYS_TO_RR7(pa_bootinfo));
if (bootinfo->bi_magic != BOOTINFO_MAGIC || bootinfo->bi_version != 1) {
bzero(bootinfo, sizeof(*bootinfo));
bootinfo->bi_kernend = (vm_offset_t)round_page(_end);
}
/*
* Look for the I/O ports first - we need them for console
* probing.
@ -702,6 +702,7 @@ ia64_init(void)
md->md_pages * EFI_PAGE_SIZE);
break;
case EFI_MD_TYPE_PALCODE:
ia64_pal_size = md->md_pages * EFI_PAGE_SIZE;
ia64_pal_base = md->md_phys;
break;
}
@ -742,34 +743,14 @@ ia64_init(void)
kernend = round_page(bootinfo->bi_kernend);
/*
* Setup the PCPU data for the bootstrap processor. It is needed
* by printf(). Also, since printf() has critical sections, we
* need to initialize at least pc_curthread.
* Region 6 is direct mapped UC and region 7 is direct mapped
* WC. The details of this is controlled by the Alt {I,D}TLB
* handlers. Here we just make sure that they have the largest
* possible page size to minimise TLB usage.
*/
pcpup = &pcpu0;
ia64_set_k4((u_int64_t)pcpup);
pcpu_init(pcpup, 0, sizeof(pcpu0));
dpcpu_init((void *)kernend, 0);
kernend += DPCPU_SIZE;
PCPU_SET(curthread, &thread0);
/*
* Initialize the console before we print anything out.
*/
cninit();
/* OUTPUT NOW ALLOWED */
if (ia64_pal_base != 0) {
ia64_pal_base &= ~IA64_ID_PAGE_MASK;
/*
* We use a TR to map the first 256M of memory - this might
* cover the palcode too.
*/
if (ia64_pal_base == 0)
printf("PAL code mapped by the kernel's TR\n");
} else
printf("PAL code not found\n");
ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (PAGE_SHIFT << 2));
ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (PAGE_SHIFT << 2));
ia64_srlz_d();
/*
* Wire things up so we can call the firmware.
@ -780,6 +761,26 @@ ia64_init(void)
ia64_sal_init();
calculate_frequencies();
/*
* Setup the PCPU data for the bootstrap processor. It is needed
* by printf(). Also, since printf() has critical sections, we
* need to initialize at least pc_curthread.
*/
pcpup = &pcpu0;
ia64_set_k4((u_int64_t)pcpup);
pcpu_init(pcpup, 0, sizeof(pcpu0));
dpcpu_init((void *)kernend, 0);
PCPU_SET(md.lid, ia64_get_lid());
kernend += DPCPU_SIZE;
PCPU_SET(curthread, &thread0);
/*
* Initialize the console before we print anything out.
*/
cninit();
/* OUTPUT NOW ALLOWED */
if (metadata_missing)
printf("WARNING: loader(8) metadata is missing!\n");

275
sys/ia64/ia64/mp_locore.S Normal file
View File

@ -0,0 +1,275 @@
/*-
* Copyright (c) 2011 Marcel Moolenaar
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#include <machine/asm.h>
#include <machine/ia64_cpu.h>
#include <machine/pte.h>
#include <assym.s>
/*
* AP wake-up entry point. The handoff state is similar as for the BSP,
* as described on page 3-9 of the IPF SAL Specification. The difference
* lies in the contents of register b0. For APs this register holds the
* return address into the SAL rendezvous routine.
*
* Note that we're responsible for clearing the IRR bit by reading cr.ivr
* and issuing the EOI to the local SAPIC.
*/
.align 32
ENTRY_NOPROFILE(os_boot_rendez,0)
{ .mmi
st8 [gp] = gp // trace = 0x00
mov r8 = cr.ivr // clear IRR bit
add r2 = 8, gp
;;
}
{ .mmi
srlz.d
mov cr.eoi = r0 // ACK the wake-up
add r3 = 16, gp
;;
}
{ .mmi
srlz.d
rsm IA64_PSR_IC | IA64_PSR_I
mov r16 = (IA64_PBVM_RR << 8) | (IA64_PBVM_PAGE_SHIFT << 2)
;;
}
{ .mmi
srlz.d
st8 [gp] = r2 // trace = 0x08
dep.z r17 = IA64_PBVM_RR, 61, 3
;;
}
{ .mlx
mov rr[r17] = r16
movl r18 = IA64_PBVM_PGTBL
;;
}
{ .mmi
srlz.i
;;
st8 [gp] = r3 // trace = 0x10
nop 0
;;
}
{ .mmi
ld8 r16 = [r2], 16 // as_pgtbl_pte
ld8 r17 = [r3], 16 // as_pgtbl_itir
nop 0
;;
}
{ .mmi
mov cr.itir = r17
mov cr.ifa = r18
nop 0
;;
}
{ .mmi
srlz.d
ptr.d r18, r17
nop 0
;;
}
{ .mmi
srlz.d
st8 [gp] = r2 // trace = 0x18
mov r8 = r0
;;
}
{ .mmi
itr.d dtr[r8] = r16
;;
srlz.d
mov r9 = r0
;;
}
{ .mmi
ld8 r16 = [r2], 16 // as_text_va
st8 [gp] = r3 // trace = 0x20
add r8 = 1, r8
;;
}
{ .mmi
ld8 r17 = [r3], 16 // as_text_pte
ld8 r18 = [r2], 16 // as_text_itir
nop 0
;;
}
{ .mmi
mov cr.ifa = r16
mov cr.itir = r18
nop 0
;;
}
{ .mmi
srlz.d
ptr.d r16, r18
nop 0
;;
}
{ .mmi
srlz.d
st8 [gp] = r3 // trace = 0x30
nop 0
;;
}
{ .mmi
itr.d dtr[r8] = r17
;;
srlz.d
nop 0
}
{ .mmi
st8 [gp] = r2 // trace = 0x38
ptr.i r16, r18
add r8 = 1, r8
;;
}
{ .mmi
srlz.i
;;
itr.i itr[r9] = r17
nop 0
;;
}
{ .mmi
srlz.i
;;
ld8 r16 = [r3], 16 // as_data_va
add r9 = 1, r9
;;
}
{ .mmi
st8 [gp] = r3 // trace = 0x40
ld8 r17 = [r2], 16 // as_data_pte
nop 0
;;
}
{ .mmi
mov cr.ifa = r16
ld8 r18 = [r3], 16 // as_data_itir
nop 0
;;
}
{ .mmi
mov cr.itir = r18
;;
srlz.d
nop 0
;;
}
{ .mmi
ptr.d r16, r18
;;
srlz.d
mov r19 = IA64_DCR_DEFAULT
;;
}
{ .mmi
itr.d dtr[r8] = r17
;;
srlz.d
add r8 = 1, r8
;;
}
{ .mmi
st8 [gp] = r2 // trace = 0x48
;;
ld8 r16 = [r2], 16 // as_kstack
nop 0
}
{ .mmi
ld8 r17 = [r3], 16 // as_kstack_top
mov cr.dcr = r19
nop 0
;;
}
{ .mlx
srlz.i
movl r18 = IA64_PSR_BN | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_IC | \
IA64_PSR_RT | IA64_PSR_DFH
;;
}
{ .mlx
mov cr.ipsr = r18
movl r19 = ia64_vector_table // set up IVT early
;;
}
{ .mlx
mov cr.iva = r19
movl r18 = 1f
;;
}
{ .mmi
mov cr.iip = r18
mov cr.ifs = r0
nop 0
;;
}
{ .mmb
srlz.d
st8 [gp] = r2 // trace = 0x58
rfi
;;
}
.align 32
1:
{ .mlx
mov ar.bspstore = r16
movl gp = __gp
;;
}
{ .mmi
loadrs
add sp = -16, r17
nop 0
;;
}
{ .mmi
mov ar.rsc = 3
;;
alloc r18 = ar.pfs, 0, 0, 0, 0
;;
}
{ .mib
nop 0
nop 0
br.call.sptk.few rp = ia64_ap_startup
;;
}
/* NOT REACHED */
9:
{ .mib
nop 0
nop 0
br.sptk 9b
;;
}
END(os_boot_rendez)

View File

@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <sys/uuid.h>
#include <machine/atomic.h>
#include <machine/bootinfo.h>
#include <machine/cpu.h>
#include <machine/fpu.h>
#include <machine/intr.h>
@ -62,22 +63,18 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_extern.h>
#include <vm/vm_kern.h>
extern uint64_t bdata[];
MALLOC_DEFINE(M_SMP, "SMP", "SMP related allocations");
void ia64_ap_startup(void);
#define LID_SAPIC(x) ((u_int)((x) >> 16))
#define LID_SAPIC_ID(x) ((u_int)((x) >> 24) & 0xff)
#define LID_SAPIC_EID(x) ((u_int)((x) >> 16) & 0xff)
#define LID_SAPIC_SET(id,eid) (((id & 0xff) << 8 | (eid & 0xff)) << 16);
#define LID_SAPIC_MASK 0xffff0000UL
#define SAPIC_ID_GET_ID(x) ((u_int)((x) >> 8) & 0xff)
#define SAPIC_ID_GET_EID(x) ((u_int)(x) & 0xff)
#define SAPIC_ID_SET(id, eid) ((u_int)(((id) & 0xff) << 8) | ((eid) & 0xff))
/* Variables used by os_boot_rendez and ia64_ap_startup */
struct pcpu *ap_pcpu;
void *ap_stack;
volatile int ap_delay;
volatile int ap_awake;
volatile int ap_spin;
/* State used to wake and bootstrap APs. */
struct ia64_ap_state ia64_ap_state;
int ia64_ipi_ast;
int ia64_ipi_highfp;
@ -86,6 +83,21 @@ int ia64_ipi_preempt;
int ia64_ipi_rndzvs;
int ia64_ipi_stop;
static u_int
sz2shft(uint64_t sz)
{
uint64_t s;
u_int shft;
shft = 12; /* Start with 4K */
s = 1 << shft;
while (s < sz) {
shft++;
s <<= 1;
}
return (shft);
}
static u_int
ia64_ih_ast(struct thread *td, u_int xiv, struct trapframe *tf)
{
@ -180,16 +192,27 @@ ia64_ap_startup(void)
{
uint64_t vhpt;
pcpup = ap_pcpu;
ia64_ap_state.as_trace = 0x100;
ia64_set_rr(IA64_RR_BASE(5), (5 << 8) | (PAGE_SHIFT << 2) | 1);
ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (PAGE_SHIFT << 2));
ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (PAGE_SHIFT << 2));
ia64_srlz_d();
pcpup = ia64_ap_state.as_pcpu;
ia64_set_k4((intptr_t)pcpup);
ia64_ap_state.as_trace = 0x108;
vhpt = PCPU_GET(md.vhpt);
map_vhpt(vhpt);
ia64_set_pta(vhpt + (1 << 8) + (pmap_vhpt_log2size << 2) + 1);
ia64_srlz_i();
ap_awake = 1;
ap_delay = 0;
ia64_ap_state.as_trace = 0x110;
ia64_ap_state.as_awake = 1;
ia64_ap_state.as_delay = 0;
map_pal_code();
map_gateway_page();
@ -197,14 +220,14 @@ ia64_ap_startup(void)
ia64_set_fpsr(IA64_FPSR_DEFAULT);
/* Wait until it's time for us to be unleashed */
while (ap_spin)
while (ia64_ap_state.as_spin)
cpu_spinwait();
/* Initialize curthread. */
KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
PCPU_SET(curthread, PCPU_GET(idlethread));
atomic_add_int(&ap_awake, 1);
atomic_add_int(&ia64_ap_state.as_awake, 1);
while (!smp_started)
cpu_spinwait();
@ -253,18 +276,18 @@ cpu_mp_probe(void)
}
void
cpu_mp_add(u_int acpiid, u_int apicid, u_int apiceid)
cpu_mp_add(u_int acpi_id, u_int id, u_int eid)
{
struct pcpu *pc;
u_int64_t lid;
void *dpcpu;
u_int cpuid;
u_int cpuid, sapic_id;
lid = LID_SAPIC_SET(apicid, apiceid);
cpuid = ((ia64_get_lid() & LID_SAPIC_MASK) == lid) ? 0 : smp_cpus++;
sapic_id = SAPIC_ID_SET(id, eid);
cpuid = (IA64_LID_GET_SAPIC_ID(ia64_get_lid()) == sapic_id)
? 0 : smp_cpus++;
KASSERT((all_cpus & (1UL << cpuid)) == 0,
("%s: cpu%d already in CPU map", __func__, acpiid));
("%s: cpu%d already in CPU map", __func__, acpi_id));
if (cpuid != 0) {
pc = (struct pcpu *)malloc(sizeof(*pc), M_SMP, M_WAITOK);
@ -274,23 +297,26 @@ cpu_mp_add(u_int acpiid, u_int apicid, u_int apiceid)
} else
pc = pcpup;
pc->pc_acpi_id = acpiid;
pc->pc_md.lid = lid;
all_cpus |= (1UL << cpuid);
pc->pc_acpi_id = acpi_id;
pc->pc_md.lid = IA64_LID_SET_SAPIC_ID(sapic_id);
all_cpus |= (1UL << pc->pc_cpuid);
}
void
cpu_mp_announce()
{
struct pcpu *pc;
uint32_t sapic_id;
int i;
for (i = 0; i <= mp_maxid; i++) {
pc = pcpu_find(i);
if (pc != NULL) {
sapic_id = IA64_LID_GET_SAPIC_ID(pc->pc_md.lid);
printf("cpu%d: ACPI Id=%x, SAPIC Id=%x, SAPIC Eid=%x",
i, pc->pc_acpi_id, LID_SAPIC_ID(pc->pc_md.lid),
LID_SAPIC_EID(pc->pc_md.lid));
i, pc->pc_acpi_id, SAPIC_ID_GET_ID(sapic_id),
SAPIC_ID_GET_EID(sapic_id));
if (i == 0)
printf(" (BSP)\n");
else
@ -302,41 +328,76 @@ cpu_mp_announce()
void
cpu_mp_start()
{
struct ia64_sal_result result;
struct ia64_fdesc *fd;
struct pcpu *pc;
uintptr_t state;
u_char *stp;
ap_spin = 1;
state = ia64_tpa((uintptr_t)&ia64_ap_state);
fd = (struct ia64_fdesc *) os_boot_rendez;
result = ia64_sal_entry(SAL_SET_VECTORS, SAL_OS_BOOT_RENDEZ,
ia64_tpa(fd->func), state, 0, 0, 0, 0);
ia64_ap_state.as_pgtbl_pte = PTE_PRESENT | PTE_MA_WB |
PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RW |
(bootinfo->bi_pbvm_pgtbl & PTE_PPN_MASK);
ia64_ap_state.as_pgtbl_itir = sz2shft(bootinfo->bi_pbvm_pgtblsz) << 2;
ia64_ap_state.as_text_va = IA64_PBVM_BASE;
ia64_ap_state.as_text_pte = PTE_PRESENT | PTE_MA_WB |
PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RX |
(ia64_tpa(IA64_PBVM_BASE) & PTE_PPN_MASK);
ia64_ap_state.as_text_itir = bootinfo->bi_text_mapped << 2;
ia64_ap_state.as_data_va = (uintptr_t)bdata;
ia64_ap_state.as_data_pte = PTE_PRESENT | PTE_MA_WB |
PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RW |
(ia64_tpa((uintptr_t)bdata) & PTE_PPN_MASK);
ia64_ap_state.as_data_itir = bootinfo->bi_data_mapped << 2;
/* Keep 'em spinning until we unleash them... */
ia64_ap_state.as_spin = 1;
SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
pc->pc_md.current_pmap = kernel_pmap;
pc->pc_other_cpus = all_cpus & ~pc->pc_cpumask;
if (pc->pc_cpuid > 0) {
ap_pcpu = pc;
pc->pc_md.vhpt = pmap_alloc_vhpt();
if (pc->pc_md.vhpt == 0) {
printf("SMP: WARNING: unable to allocate VHPT"
" for cpu%d", pc->pc_cpuid);
continue;
}
ap_stack = malloc(KSTACK_PAGES * PAGE_SIZE, M_SMP,
M_WAITOK);
ap_delay = 2000;
ap_awake = 0;
if (bootverbose)
printf("SMP: waking up cpu%d\n", pc->pc_cpuid);
ipi_send(pc, ia64_ipi_wakeup);
do {
DELAY(1000);
} while (--ap_delay > 0);
pc->pc_md.awake = ap_awake;
if (!ap_awake)
printf("SMP: WARNING: cpu%d did not wake up\n",
pc->pc_cpuid);
} else
/* The BSP is obviously running already. */
if (pc->pc_cpuid == 0) {
pc->pc_md.awake = 1;
continue;
}
ia64_ap_state.as_pcpu = pc;
pc->pc_md.vhpt = pmap_alloc_vhpt();
if (pc->pc_md.vhpt == 0) {
printf("SMP: WARNING: unable to allocate VHPT"
" for cpu%d", pc->pc_cpuid);
continue;
}
stp = malloc(KSTACK_PAGES * PAGE_SIZE, M_SMP, M_WAITOK);
ia64_ap_state.as_kstack = stp;
ia64_ap_state.as_kstack_top = stp + KSTACK_PAGES * PAGE_SIZE;
ia64_ap_state.as_trace = 0;
ia64_ap_state.as_delay = 2000;
ia64_ap_state.as_awake = 0;
if (bootverbose)
printf("SMP: waking up cpu%d\n", pc->pc_cpuid);
/* Here she goes... */
ipi_send(pc, ia64_ipi_wakeup);
do {
DELAY(1000);
} while (--ia64_ap_state.as_delay > 0);
pc->pc_md.awake = ia64_ap_state.as_awake;
if (!ia64_ap_state.as_awake) {
printf("SMP: WARNING: cpu%d did not wake up (code "
"%#lx)\n", pc->pc_cpuid,
ia64_ap_state.as_trace - state);
}
}
}
@ -372,10 +433,10 @@ cpu_mp_unleash(void *dummy)
}
}
ap_awake = 1;
ap_spin = 0;
ia64_ap_state.as_awake = 1;
ia64_ap_state.as_spin = 0;
while (ap_awake != smp_cpus)
while (ia64_ap_state.as_awake != smp_cpus)
cpu_spinwait();
if (smp_cpus != cpus || cpus != mp_ncpus) {
@ -432,21 +493,19 @@ ipi_all_but_self(int ipi)
}
/*
* Send an IPI to the specified processor. The lid parameter holds the
* cr.lid (CR64) contents of the target processor. Only the id and eid
* fields are used here.
* Send an IPI to the specified processor.
*/
void
ipi_send(struct pcpu *cpu, int xiv)
{
u_int lid;
u_int sapic_id;
KASSERT(xiv != 0, ("ipi_send"));
lid = LID_SAPIC(cpu->pc_md.lid);
sapic_id = IA64_LID_GET_SAPIC_ID(cpu->pc_md.lid);
ia64_mf();
ia64_st8(&(ia64_pib->ib_ipi[lid][0]), xiv);
ia64_st8(&(ia64_pib->ib_ipi[sapic_id][0]), xiv);
ia64_mf_a();
CTR3(KTR_SMP, "ipi_send(%p, %d): cpuid=%d", cpu, xiv, PCPU_GET(cpuid));
}

View File

@ -159,7 +159,8 @@ vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
* Kernel virtual memory management.
*/
static int nkpt;
struct ia64_lpte ***ia64_kptdir;
extern struct ia64_lpte ***ia64_kptdir;
#define KPTE_DIR0_INDEX(va) \
(((va) >> (3*PAGE_SHIFT-8)) & ((1<<(PAGE_SHIFT-3))-1))
#define KPTE_DIR1_INDEX(va) \
@ -177,7 +178,7 @@ static uint64_t pmap_ptc_e_count2 = 2;
static uint64_t pmap_ptc_e_stride1 = 0x2000;
static uint64_t pmap_ptc_e_stride2 = 0x100000000;
volatile u_long pmap_ptc_g_sem;
extern volatile u_long pmap_ptc_g_sem;
/*
* Data for the RID allocator
@ -390,13 +391,18 @@ pmap_bootstrap()
;
count = i+2;
/*
* Determine a valid (mappable) VHPT size.
*/
TUNABLE_INT_FETCH("machdep.vhpt.log2size", &pmap_vhpt_log2size);
if (pmap_vhpt_log2size == 0)
pmap_vhpt_log2size = 20;
else if (pmap_vhpt_log2size < 15)
pmap_vhpt_log2size = 15;
else if (pmap_vhpt_log2size > 61)
pmap_vhpt_log2size = 61;
else if (pmap_vhpt_log2size < 16)
pmap_vhpt_log2size = 16;
else if (pmap_vhpt_log2size > 28)
pmap_vhpt_log2size = 28;
if (pmap_vhpt_log2size & 1)
pmap_vhpt_log2size--;
base = 0;
size = 1UL << pmap_vhpt_log2size;
@ -453,16 +459,6 @@ pmap_bootstrap()
/* Region 5 is mapped via the VHPT. */
ia64_set_rr(IA64_RR_BASE(5), (5 << 8) | (PAGE_SHIFT << 2) | 1);
/*
* Region 6 is direct mapped UC and region 7 is direct mapped
* WC. The details of this is controlled by the Alt {I,D}TLB
* handlers. Here we just make sure that they have the largest
* possible page size to minimise TLB usage.
*/
ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (IA64_ID_PAGE_SHIFT << 2));
ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (IA64_ID_PAGE_SHIFT << 2));
ia64_srlz_d();
/*
* Clear out any random TLB entries left over from booting.
*/
@ -1210,7 +1206,6 @@ vm_paddr_t
pmap_kextract(vm_offset_t va)
{
struct ia64_lpte *pte;
vm_offset_t gwpage;
KASSERT(va >= VM_MAXUSER_ADDRESS, ("Must be kernel VA"));
@ -1218,19 +1213,16 @@ pmap_kextract(vm_offset_t va)
if (va >= IA64_RR_BASE(6))
return (IA64_RR_MASK(va));
/* EPC gateway page? */
gwpage = (vm_offset_t)ia64_get_k5();
if (va >= gwpage && va < gwpage + PAGE_SIZE)
return (IA64_RR_MASK((vm_offset_t)ia64_gateway_page));
/* Bail out if the virtual address is beyond our limits. */
if (va >= kernel_vm_end)
return (0);
pte = pmap_find_kpte(va);
if (!pmap_present(pte))
return (0);
return (pmap_ppn(pte) | (va & PAGE_MASK));
if (va >= VM_MIN_KERNEL_ADDRESS) {
pte = pmap_find_kpte(va);
return (pmap_present(pte) ? pmap_ppn(pte)|(va&PAGE_MASK) : 0);
}
return (0);
}
/*

View File

@ -101,10 +101,6 @@ ia64_sal_init(void)
}
case 5: {
struct sal_ap_wakeup_descriptor *dp;
#ifdef SMP
struct ia64_sal_result result;
struct ia64_fdesc *fd;
#endif
dp = (struct sal_ap_wakeup_descriptor*)p;
if (dp->sale_mechanism != 0) {
@ -126,14 +122,6 @@ ia64_sal_init(void)
if (bootverbose)
printf("SAL: AP wake-up XIV: %#x\n",
ia64_ipi_wakeup);
#ifdef SMP
fd = (struct ia64_fdesc *) os_boot_rendez;
result = ia64_sal_entry(SAL_SET_VECTORS,
SAL_OS_BOOT_RENDEZ, ia64_tpa(fd->func),
ia64_tpa(fd->gp), 0, 0, 0, 0);
#endif
break;
}
}

View File

@ -30,6 +30,12 @@
#ifndef _MACHINE_IA64_CPU_H_
#define _MACHINE_IA64_CPU_H_
/*
* Local Interrupt ID.
*/
#define IA64_LID_GET_SAPIC_ID(x) ((u_int)((x) >> 16) & 0xffff)
#define IA64_LID_SET_SAPIC_ID(x) ((u_int)((x) & 0xffff) << 16)
/*
* Definition of DCR bits.
*/

View File

@ -16,6 +16,24 @@
struct pcpu;
struct ia64_ap_state {
uint64_t as_trace;
uint64_t as_pgtbl_pte;
uint64_t as_pgtbl_itir;
uint64_t as_text_va;
uint64_t as_text_pte;
uint64_t as_text_itir;
uint64_t as_data_va;
uint64_t as_data_pte;
uint64_t as_data_itir;
void *as_kstack;
void *as_kstack_top;
struct pcpu *as_pcpu;
volatile int as_delay;
volatile u_int as_awake;
volatile u_int as_spin;
};
extern int ia64_ipi_ast;
extern int ia64_ipi_highfp;
extern int ia64_ipi_nmi;

View File

@ -124,8 +124,8 @@
#define IA64_RR_BASE(n) (((uint64_t) (n)) << 61)
#define IA64_RR_MASK(x) ((x) & ((1L << 61) - 1))
#define IA64_PHYS_TO_RR6(x) ((x) | IA64_RR_BASE(6))
#define IA64_PHYS_TO_RR7(x) ((x) | IA64_RR_BASE(7))
#define IA64_PHYS_TO_RR6(x) ((x) | IA64_RR_BASE(6))
#define IA64_PHYS_TO_RR7(x) ((x) | IA64_RR_BASE(7))
/*
* The Itanium architecture defines that all implementations support at
@ -138,18 +138,6 @@
#define IA64_REGION_GAP_START 0x0004000000000000
#define IA64_REGION_GAP_EXTEND 0x1ffc000000000000
/*
* Page size of the identity mappings in region 7.
*/
#ifndef LOG2_ID_PAGE_SIZE
#define LOG2_ID_PAGE_SIZE 28 /* 256M */
#endif
#define IA64_ID_PAGE_SHIFT (LOG2_ID_PAGE_SIZE)
#define IA64_ID_PAGE_SIZE (1<<(LOG2_ID_PAGE_SIZE))
#define IA64_ID_PAGE_MASK (IA64_ID_PAGE_SIZE-1)
/*
* Parameters for Pre-Boot Virtual Memory (PBVM).
* The kernel, its modules and metadata are loaded in the PBVM by the loader.