Fix switching to physical mode as part of calling into EFI runtime

services or PAL procedures. The new implementation is based on
specific functions that are known to be called in certain scenarios
only. This in particular fixes the PAL call to obtain information
about translation registers. In general, the new implementation does
not bank on virtual addresses being direct-mapped and will work when
the kernel uses PBVM.

When new scenarios need to be supported, new functions are added if
the existing functions cannot be changed to handle the new scenario.
If a single generic implementation is possible, it will become clear
in due time.

While here, change bootinfo to a pointer type in anticipation of
future development.
This commit is contained in:
Marcel Moolenaar 2011-03-21 18:20:53 +00:00
parent 1f0caefd53
commit 0355a8b24b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=219841
11 changed files with 305 additions and 273 deletions

View File

@ -95,6 +95,7 @@ ia64/ia64/mem.c optional mem
ia64/ia64/mp_machdep.c optional smp
ia64/ia64/nexus.c standard
ia64/ia64/pal.S standard
ia64/ia64/physical.S standard
ia64/ia64/pmap.c standard
ia64/ia64/ptrace_machdep.c standard
ia64/ia64/sal.c standard

View File

@ -32,13 +32,11 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <machine/bootinfo.h>
#include <machine/efi.h>
#include <machine/md_var.h>
#include <machine/sal.h>
#include <vm/vm.h>
#include <vm/pmap.h>
extern uint64_t ia64_call_efi_physical(uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t, uint64_t);
static struct efi_systbl *efi_systbl;
static struct efi_cfgtbl *efi_cfgtbl;
static struct efi_rt *efi_runtime;
@ -96,6 +94,7 @@ efi_boot_finish(void)
int
efi_boot_minimal(uint64_t systbl)
{
ia64_efi_f setvirt;
struct efi_md *md;
efi_status status;
@ -121,18 +120,16 @@ efi_boot_minimal(uint64_t systbl)
md = efi_md_first();
while (md != NULL) {
if (md->md_attr & EFI_MD_ATTR_RT) {
if (md->md_attr & EFI_MD_ATTR_WB)
md->md_virt =
(void *)IA64_PHYS_TO_RR7(md->md_phys);
else if (md->md_attr & EFI_MD_ATTR_UC)
md->md_virt = pmap_mapdev(md->md_phys,
md->md_pages * EFI_PAGE_SIZE);
md->md_virt = (md->md_attr & EFI_MD_ATTR_WB) ?
(void *)IA64_PHYS_TO_RR7(md->md_phys) :
(void *)IA64_PHYS_TO_RR6(md->md_phys);
}
md = efi_md_next(md);
}
status = ia64_call_efi_physical((uint64_t)efi_runtime->rt_setvirtual,
bootinfo.bi_memmap_size, bootinfo.bi_memdesc_size,
bootinfo.bi_memdesc_version, bootinfo.bi_memmap, 0);
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);
return ((status < 0) ? EFAULT : 0);
}
@ -165,9 +162,9 @@ struct efi_md *
efi_md_first(void)
{
if (bootinfo.bi_memmap == 0)
if (bootinfo->bi_memmap == 0)
return (NULL);
return ((struct efi_md *)IA64_PHYS_TO_RR7(bootinfo.bi_memmap));
return ((struct efi_md *)IA64_PHYS_TO_RR7(bootinfo->bi_memmap));
}
struct efi_md *
@ -175,8 +172,8 @@ efi_md_next(struct efi_md *md)
{
uint64_t plim;
plim = IA64_PHYS_TO_RR7(bootinfo.bi_memmap + bootinfo.bi_memmap_size);
md = (struct efi_md *)((uintptr_t)md + bootinfo.bi_memdesc_size);
plim = IA64_PHYS_TO_RR7(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

@ -116,7 +116,7 @@ SYSCTL_UINT(_hw_freq, OID_AUTO, itc, CTLFLAG_RD, &itc_freq, 0,
int cold = 1;
u_int64_t pa_bootinfo;
struct bootinfo bootinfo;
struct bootinfo *bootinfo;
struct pcpu pcpu0;
@ -684,11 +684,11 @@ ia64_init(void)
* 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));
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);
if (bootinfo->bi_magic != BOOTINFO_MAGIC || bootinfo->bi_version != 1) {
bzero(bootinfo, sizeof(*bootinfo));
bootinfo->bi_kernend = (vm_offset_t)round_page(_end);
}
/*
@ -708,20 +708,20 @@ ia64_init(void)
}
metadata_missing = 0;
if (bootinfo.bi_modulep)
preload_metadata = (caddr_t)bootinfo.bi_modulep;
if (bootinfo->bi_modulep)
preload_metadata = (caddr_t)bootinfo->bi_modulep;
else
metadata_missing = 1;
if (envmode == 0 && bootinfo.bi_envp)
kern_envp = (caddr_t)bootinfo.bi_envp;
if (envmode == 0 && bootinfo->bi_envp)
kern_envp = (caddr_t)bootinfo->bi_envp;
else
kern_envp = static_env;
/*
* Look at arguments passed to us and compute boothowto.
*/
boothowto = bootinfo.bi_boothowto;
boothowto = bootinfo->bi_boothowto;
if (boothowto & RB_VERBOSE)
bootverbose = 1;
@ -731,15 +731,15 @@ ia64_init(void)
*/
kernstart = trunc_page(kernel_text);
#ifdef DDB
ksym_start = bootinfo.bi_symtab;
ksym_end = bootinfo.bi_esymtab;
ksym_start = bootinfo->bi_symtab;
ksym_end = bootinfo->bi_esymtab;
kernend = (vm_offset_t)round_page(ksym_end);
#else
kernend = (vm_offset_t)round_page(_end);
#endif
/* But if the bootstrap tells us otherwise, believe it! */
if (bootinfo.bi_kernend)
kernend = round_page(bootinfo.bi_kernend);
if (bootinfo->bi_kernend)
kernend = round_page(bootinfo->bi_kernend);
/*
* Setup the PCPU data for the bootstrap processor. It is needed
@ -775,7 +775,7 @@ ia64_init(void)
* Wire things up so we can call the firmware.
*/
map_pal_code();
efi_boot_minimal(bootinfo.bi_systab);
efi_boot_minimal(bootinfo->bi_systab);
ia64_xiv_init();
ia64_sal_init();
calculate_frequencies();
@ -784,8 +784,8 @@ ia64_init(void)
printf("WARNING: loader(8) metadata is missing!\n");
/* Get FPSWA interface */
fpswa_iface = (bootinfo.bi_fpswa == 0) ? NULL :
(struct fpswa_iface *)IA64_PHYS_TO_RR7(bootinfo.bi_fpswa);
fpswa_iface = (bootinfo->bi_fpswa == 0) ? NULL :
(struct fpswa_iface *)IA64_PHYS_TO_RR7(bootinfo->bi_fpswa);
/* Init basic tunables, including hz */
init_param1();
@ -940,7 +940,7 @@ uint64_t
ia64_get_hcdp(void)
{
return (bootinfo.bi_hcdp);
return (bootinfo->bi_hcdp);
}
void

View File

@ -75,63 +75,8 @@ psrsave = loc4
;;
srlz.d
br.ret.sptk rp
END(ia64_call_pal_static)
#ifdef _KERNEL
/*
* struct ia64_pal_result ia64_call_pal_static_physical(u_int64_t proc,
* u_int64_t arg1, u_int64_t arg2, u_int64_t arg3)
*/
ENTRY(ia64_call_pal_static_physical, 4)
.regstk 4,5,0,0
palret = loc0
entry = loc1
rpsave = loc2
pfssave = loc3
psrsave = loc4
alloc pfssave=ar.pfs,4,5,0,0
;;
mov rpsave=rp
movl entry=@gprel(ia64_pal_entry)
1: mov palret=ip // for return address
;;
add entry=entry,gp
mov r28=in0 // procedure number
;;
ld8 entry=[entry] // read entry point
mov r29=in1 // copy arguments
mov r30=in2
mov r31=in3
;;
dep entry=0,entry,61,3 // physical address
dep palret=0,palret,61,3 // physical address
br.call.sptk.many rp=ia64_physical_mode
mov psrsave=ret0
;;
mov b6=entry
add palret=2f-1b,palret // calculate return address
;;
mov b0=palret
br.cond.sptk b6 // call into firmware
;;
2: mov r14=psrsave
;;
br.call.sptk.many rp=ia64_change_mode
;;
mov rp=rpsave
mov ar.pfs=pfssave
;;
br.ret.sptk rp
END(ia64_call_pal_static_physical)
#endif
/*
* struct ia64_pal_result ia64_call_pal_stacked(u_int64_t proc,
* u_int64_t arg1, u_int64_t arg2, u_int64_t arg3)
@ -172,52 +117,3 @@ psrsave = loc3
br.ret.sptk rp
END(ia64_call_pal_stacked)
#ifdef _KERNEL
/*
* struct ia64_pal_result ia64_call_pal_stacked_physical(u_int64_t proc,
* u_int64_t arg1, u_int64_t arg2, u_int64_t arg3)
*/
ENTRY(ia64_call_pal_stacked_physical, 4)
.regstk 4,4,4,0
entry = loc0
rpsave = loc1
pfssave = loc2
psrsave = loc3
alloc pfssave=ar.pfs,4,4,4,0
;;
mov rpsave=rp
movl entry=@gprel(ia64_pal_entry)
;;
add entry=entry,gp
mov r28=in0 // procedure number
mov out0=in0
;;
ld8 entry=[entry] // read entry point
mov out1=in1 // copy arguments
mov out2=in2
mov out3=in3
;;
dep entry=0,entry,61,3 // physical address
br.call.sptk.many rp=ia64_physical_mode
mov psrsave=ret0
;;
mov b6=entry
;;
br.call.sptk.many rp=b6 // call into firmware
;;
mov r14=psrsave
;;
br.call.sptk.many rp=ia64_change_mode
;;
mov rp=rpsave
mov ar.pfs=pfssave
;;
br.ret.sptk rp
END(ia64_call_pal_stacked_physical)
#endif

258
sys/ia64/ia64/physical.S Normal file
View File

@ -0,0 +1,258 @@
/*-
* 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 ``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 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>
.text
/*
* u_long ia64_efi_physical(ia64_efi_f, u_long, u_long, u_long, u_long)
*
* loc0 = ar.pfs
* loc1 = rp
* loc2 = psr
* loc3 = sp
* loc4 = bsp
* loc5 = gp
*/
ENTRY(ia64_efi_physical, 5)
.prologue
.regstk 5,6,4,0
.save ar.pfs,loc0
alloc loc0=ar.pfs,5,6,4,0
;;
.save rp,loc1
mov loc1=rp
;;
.body
mov loc2=psr // save psr
movl r16=IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | \
IA64_PSR_RT | IA64_PSR_DFL | IA64_PSR_DFH
;;
andcm r14=loc2,r16
movl r15=IA64_PSR_BN
;;
rsm psr.i
mov r17=ar.rsc
or r16=r14,r15 // new psr
;;
mov ar.rsc=0
or loc2=loc2,r15
;;
flushrs
mov loc3=sp // save sp
;;
mov loc4=ar.bsp // save ar.bsp
mov r18=ar.rnat
;;
tpa r19=loc4 // new bspstore
mov loc5=gp
;;
tpa r20=loc3 // new sp
ld8 r21=[in0],8
;;
1:
mov r14=ip
;;
ld8 r22=[in0]
add r15=2f-1b,r14
;;
tpa r14=r15
;;
rsm psr.ic
;;
srlz.i
;;
mov cr.iip=r14
mov cr.ifs=r0
mov cr.ipsr=r16
;;
rfi
2:
mov ar.bspstore=r19
mov sp=r20
;;
mov ar.rnat=r18
mov ar.rsc=r17
;;
mov b6=r21
mov gp=r22
mov out0=in1
mov out1=in2
mov out2=in3
mov out3=in4
;;
br.call.sptk.many rp=b6
mov gp=loc5
;;
rsm psr.i | psr.ic
mov r16=ar.rsc
;;
srlz.i
mov ar.rsc=0
;;
flushrs
;;
mov r17=ar.rnat
movl r18=3f
;;
mov cr.iip=r18
mov cr.ifs=r0
mov cr.ipsr=loc2
;;
rfi
3:
mov ar.bspstore=loc4
mov sp=loc3
;;
mov ar.rnat=r17
mov ar.rsc=r16
;;
mov rp=loc1
mov ar.pfs=loc0
;;
br.ret.sptk.many rp
END(ia64_efi_physical)
/*
* ia64_pal_ret ia64_pal_physical(ia64_fw_f, u_long, u_long, u_long, u_long)
*
* loc0 = ar.pfs
* loc1 = rp
* loc2 = psr
* loc3 = sp
* loc4 = bsp
* loc5 = gp
*/
ENTRY(ia64_pal_physical, 5)
.prologue
.regstk 5,6,4,0
.save ar.pfs,loc0
alloc loc0=ar.pfs,5,6,4,0
;;
.save rp,loc1
mov loc1=rp
;;
.body
mov loc2=psr // save psr
movl r16=IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | \
IA64_PSR_RT | IA64_PSR_DFL | IA64_PSR_DFH
;;
andcm r14=loc2,r16
movl r15=IA64_PSR_BN
;;
rsm psr.i
mov r17=ar.rsc
or r16=r14,r15 // new psr
;;
mov ar.rsc=0
or loc2=loc2,r15
;;
flushrs
mov loc3=sp // save sp
;;
mov loc4=ar.bsp // save ar.bsp
mov r18=ar.rnat
;;
mov loc5=gp
movl r14=kstack
;;
tpa r19=r14 // new bspstore
movl r15=kstack_top
;;
tpa r20=r15 // new sp
movl r21=ia64_pal_entry
;;
1:
mov r14=ip
ld8 r22=[r21]
;;
tpa r21=r22
add r15=2f-1b,r14
;;
tpa r14=r15
;;
rsm psr.ic
;;
srlz.i
;;
mov cr.iip=r14
mov cr.ifs=r0
mov cr.ipsr=r16
;;
rfi
2:
mov ar.bspstore=r19
add sp=-16,r20
;;
mov ar.rnat=r18
mov ar.rsc=r17
;;
mov b6=r21
mov out0=in0
mov out1=in1
mov out2=in2
mov out3=in3
// PAL static calls
mov r28=in0
mov r29=in1
mov r30=in2
mov r31=in3
br.call.sptk.many rp=b6
mov gp=loc5
;;
rsm psr.i | psr.ic
mov r16=ar.rsc
;;
srlz.i
mov ar.rsc=0
;;
flushrs
;;
mov r17=ar.rnat
movl r18=3f
;;
mov cr.iip=r18
mov cr.ifs=r0
mov cr.ipsr=loc2
;;
rfi
3:
mov ar.bspstore=loc4
mov sp=loc3
;;
mov ar.rnat=r17
mov ar.rsc=r16
;;
mov rp=loc1
mov ar.pfs=loc0
;;
br.ret.sptk.many rp
END(ia64_pal_physical)

View File

@ -2378,8 +2378,8 @@ print_trs(int type)
db_printf("V RID Virtual Page Physical Page PgSz ED AR PL D A MA P KEY\n");
for (i = 0; i <= maxtr; i++) {
bzero(&buf, sizeof(buf));
res = ia64_call_pal_stacked_physical
(PAL_VM_TR_READ, i, type, ia64_tpa((uint64_t) &buf));
res = ia64_pal_physical(PAL_VM_TR_READ, i, type,
ia64_tpa((uint64_t)&buf));
if (!(res.pal_result[0] & 1))
buf.pte &= ~PTE_AR_MASK;
if (!(res.pal_result[0] & 2))

View File

@ -58,131 +58,6 @@
.text
/*
* ia64_change_mode: change mode to/from physical mode
*
* Arguments:
* r14 psr for desired mode
*
* Modifies:
* r15-r19 scratch
* ar.bsp tranlated to new mode
*/
ENTRY_NOPROFILE(ia64_change_mode, 0)
rsm psr.i | psr.ic
mov r19=ar.rsc // save rsc while we change mode
tbit.nz p6,p7=r14,17 // physical or virtual ?
;;
mov ar.rsc=0 // turn off RSE
(p6) mov r15=7 // RR base for virtual addresses
(p7) mov r15=0 // RR base for physical addresses
;;
flushrs // no dirty registers please
srlz.i
;;
mov r16=ar.bsp
mov r17=rp
mov r18=ar.rnat
;;
dep r16=r15,r16,61,3 // new address of ar.bsp
dep r17=r15,r17,61,3 // new address of rp
dep sp=r15,sp,61,3 // new address of sp
;;
mov ar.bspstore=r16
mov rp=r17
;;
1: mov r16=ip
mov ar.rnat=r18
mov cr.ipsr=r14 // psr for new mode
;;
add r16=2f-1b,r16 // address to rfi to
;;
dep r16=r15,r16,61,3 // new mode address for rfi
;;
mov cr.iip=r16 // setup for rfi
mov cr.ifs=r0
;;
rfi
2: mov ar.rsc=r19 // restore ar.rsc
br.ret.sptk.few rp // now in new mode
END(ia64_change_mode)
/*
* ia64_physical_mode: change mode to physical mode
*
* Return:
* ret0 psr to restore
*
* Modifies:
* r15-r18 scratch
* ar.bsp tranlated to physical mode
* psr.i cleared
*/
ENTRY(ia64_physical_mode, 0)
mov r14=psr
mov ret0=psr
movl r15=(IA64_PSR_I|IA64_PSR_IT|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFL|IA64_PSR_DFH)
movl r16=IA64_PSR_BN
;;
andcm r14=r14,r15 // clear various xT bits
;;
or r14=r14,r16 // make sure BN=1
or ret0=ret0,r16 // make sure BN=1
br.cond.sptk.many ia64_change_mode
END(ia64_physical_mode)
/*
* ia64_call_efi_physical: call an EFI procedure in physical mode
*
* Arguments:
* in0 Address of EFI procedure descriptor
* in1-in5 Arguments to EFI procedure
*
* Return:
* ret0-ret3 return values from EFI
*
*/
ENTRY(ia64_call_efi_physical, 6)
.prologue
.regstk 6,4,5,0
.save ar.pfs,loc0
alloc loc0=ar.pfs,6,4,5,0
;;
.save rp,loc1
mov loc1=rp
;;
.body
br.call.sptk.many rp=ia64_physical_mode
;;
mov loc2=r8 // psr to restore mode
mov loc3=gp // save kernel gp
ld8 r14=[in0],8 // function address
;;
mov out0=in1
mov out1=in2
mov out2=in3
mov out3=in4
mov out4=in5
ld8 gp=[in0] // function gp value
;;
mov b6=r14
;;
br.call.sptk.many rp=b6 // call EFI procedure
mov gp=loc3 // restore kernel gp
;;
mov r14=loc2 // psr to restore mode
br.call.sptk.many rp=ia64_change_mode
;;
mov rp=loc1
mov ar.pfs=loc0
;;
br.ret.sptk.many rp
END(ia64_call_efi_physical)
/**************************************************************************/
ENTRY(fusufault, 0)
{ .mib
st8.rel [r15]=r0 // Clear onfault.

View File

@ -48,4 +48,4 @@ struct bootinfo {
uint64_t bi_modulep; /* preloaded modules */
};
extern struct bootinfo bootinfo;
extern struct bootinfo *bootinfo;

View File

@ -151,6 +151,12 @@ struct efi_systbl {
uint64_t st_cfgtbl;
};
#ifdef _KERNEL
typedef u_long (*ia64_efi_f)(u_long, u_long, u_long, u_long);
u_long ia64_efi_physical(ia64_efi_f, u_long, u_long, u_long, u_long);
void efi_boot_finish(void);
int efi_boot_minimal(uint64_t);
void *efi_get_table(struct uuid *);
@ -163,4 +169,6 @@ int efi_var_get(efi_char *, struct uuid *, uint32_t *, size_t *, void *);
int efi_var_nextname(size_t *, efi_char *, struct uuid *);
int efi_var_set(efi_char *, struct uuid *, uint32_t, size_t, void *);
#endif /* _KERNEL */
#endif /* _MACHINE_EFI_H_ */

View File

@ -111,16 +111,12 @@ struct ia64_pal_result {
uint64_t pal_result[3];
};
struct ia64_pal_result ia64_pal_physical(u_long, u_long, u_long, u_long);
struct ia64_pal_result ia64_call_pal_static(uint64_t proc, uint64_t arg1,
uint64_t arg2, uint64_t arg3);
struct ia64_pal_result ia64_call_pal_static_physical(uint64_t proc,
uint64_t arg1, uint64_t arg2, uint64_t arg3);
struct ia64_pal_result ia64_call_pal_stacked(uint64_t proc, uint64_t arg1,
uint64_t arg2, uint64_t arg3);
struct ia64_pal_result ia64_call_pal_stacked_physical(uint64_t proc,
uint64_t arg1, uint64_t arg2, uint64_t arg3);
#endif /* _MACHINE_PAL_H_ */

View File

@ -124,7 +124,8 @@
#define IA64_RR_BASE(n) (((uint64_t) (n)) << 61)
#define IA64_RR_MASK(x) ((x) & ((1L << 61) - 1))
#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