Page MenuHomeFreeBSD

D61331.1794340800.diff
No OneTemporary

Authored By
Unknown
Size
23 KB
Referenced Files
None
Subscribers
None

D61331.1794340800.diff

diff --git a/share/man/man7/arch.7 b/share/man/man7/arch.7
--- a/share/man/man7/arch.7
+++ b/share/man/man7/arch.7
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 24, 2026
+.Dd November 9, 2026
.Dt ARCH 7
.Os
.Sh NAME
@@ -271,7 +271,7 @@
.It riscv64c Ta 4K, 2M, 1G
.El
.Ss User Address Space Layout
-.Bl -column -offset indent "riscv64 (Sv48)" "0x0001000000000000" "NNNU"
+.Bl -column -offset indent "powerpc64le (LA48)" "0x0001000000000000" "NNNU"
.It Sy Architecture Ta Sy Maximum Address Ta Sy Address Space Size
.It aarch64 Ta 0x0001000000000000 Ta 256TiB
.It aarch64c Ta 0x0001000000000000 Ta 256TiB
@@ -280,8 +280,10 @@
.It armv7 Ta 0xbfc00000 Ta 3GiB
.It i386 Ta 0xffc00000 Ta 4GiB
.It powerpc Ta 0xfffff000 Ta 4GiB
-.It powerpc64 Ta 0x000fffffc0000000 Ta 4PiB
-.It powerpc64le Ta 0x000fffffc0000000 Ta 4PiB
+.It powerpc64 (LA48) Ta 0x0000800000000000 Ta 128TiB
+.It powerpc64 (LA57) Ta 0x000fffffc0000000 Ta 4PiB
+.It powerpc64le (LA48) Ta 0x0000800000000000 Ta 128TiB
+.It powerpc64le (LA57) Ta 0x000fffffc0000000 Ta 4PiB
.It riscv64 (Sv39) Ta 0x0000004000000000 Ta 256GiB
.It riscv64c (Sv39) Ta 0x0000004000000000 Ta 256GiB
.It riscv64 (Sv48) Ta 0x0000800000000000 Ta 128TiB
@@ -303,7 +305,7 @@
supports 5-level paging.
In this mode, all processes get a 48-bit address space.
The
-.Sy vm.pmap.prefer_la48_uva
+.Sy vm.pmap.prefer_uva_la48
tunable determines whether processes running on a LA57 system are limited to
a 48-bit address space by default.
Some applications make use of unused upper bits in pointer values to store
@@ -316,6 +318,19 @@
.Xr proccontrol 1
can be used to configure the address space layout when executing a process.
.Pp
+On powerpc64 the radix MMU provides a 52-bit user address space, but for the
+same reason processes are limited to 47 bits (128TiB) by default, as they are
+on Linux.
+The
+.Sy vm.pmap.prefer_uva_la48
+tunable,
+.Xr elfctl 1
+and
+.Xr proccontrol 1
+work as on amd64, with
+.Dq la57
+requesting the full 52-bit address space.
+.Pp
The RISC-V specification permits 3-level (Sv39), 4-level (Sv48), and
5-level (Sv57) page tables.
Hardware is only required to implement Sv39; implementations which support
diff --git a/sys/powerpc/include/proc.h b/sys/powerpc/include/proc.h
--- a/sys/powerpc/include/proc.h
+++ b/sys/powerpc/include/proc.h
@@ -45,12 +45,12 @@
};
struct mdproc {
- /*
- * Avoid empty structs because they are undefined behavior.
- */
- long md_spare;
+ u_int md_flags; /* (c) md process flags P_MD */
};
+#define P_MD_LA48 0x00000001 /* Request LA48 after exec */
+#define P_MD_LA57 0x00000002 /* Request LA57 after exec */
+
#ifdef __powerpc64__
#define KINFO_PROC_SIZE 1088
#define KINFO_PROC32_SIZE 816
diff --git a/sys/powerpc/include/procctl.h b/sys/powerpc/include/procctl.h
--- a/sys/powerpc/include/procctl.h
+++ b/sys/powerpc/include/procctl.h
@@ -1,3 +1,23 @@
/*-
* This file is in the public domain.
*/
+
+#ifndef _MACHINE_PROCCTL_H_
+#define _MACHINE_PROCCTL_H_
+
+/*
+ * Same numbers as on amd64 so that proccontrol(1) works unchanged. la48
+ * means the default 47-bit (128 TiB) user address space, la57 the full
+ * range the MMU supports (52 bits with radix).
+ */
+#define PROC_LA_CTL (PROC_PROCCTL_MD_MIN + 2)
+#define PROC_LA_STATUS (PROC_PROCCTL_MD_MIN + 3)
+
+#define PROC_LA_CTL_LA48_ON_EXEC 1
+#define PROC_LA_CTL_LA57_ON_EXEC 2
+#define PROC_LA_CTL_DEFAULT_ON_EXEC 3
+
+#define PROC_LA_STATUS_LA48 0x01000000
+#define PROC_LA_STATUS_LA57 0x02000000
+
+#endif /* !_MACHINE_PROCCTL_H_ */
diff --git a/sys/powerpc/include/vmparam.h b/sys/powerpc/include/vmparam.h
--- a/sys/powerpc/include/vmparam.h
+++ b/sys/powerpc/include/vmparam.h
@@ -87,24 +87,44 @@
* kernel map should be able to start at 0xc008000000000000 -
* but at least the functional simulator doesn't like it
*
- * 0x0000000000000000 - 0x000fffffffffffff user map
+ * 0x0000000000000000 - 0x00007fffffffffff user map (default)
+ * 0x0000000000000000 - 0x000fffffffffffff user map (la57)
* 0xc000000000000000 - 0xc007ffffffffffff direct map
* 0xc008000000000000 - 0xc00fffffffffffff kernel map
*
*/
#define VM_MIN_ADDRESS 0x0000000000000000
-#define VM_MAXUSER_ADDRESS 0x000fffffc0000000
+/*
+ * Radix lets user space address 52 bits, but a process only gets the low
+ * 47 bits (128 TiB) by default, like on amd64 with LA57 and like Linux on
+ * ppc64le: lots of userland (SpiderMonkey, JavaScriptCore, QV4, ...) packs
+ * pointers into 47 or 48 bits and crashes once ASLR puts the heap above
+ * that. The full range is available per process through the la57 feature
+ * control note or PROC_LA_CTL, see elf64_machdep.c. The LA48/LA57 names
+ * come from that interface and amd64, they don't describe POWER paging modes.
+ */
+#define VM_MAXUSER_ADDRESS_LA48 0x0000800000000000
+#define VM_MAXUSER_ADDRESS_LA57 0x000fffffc0000000
+#define VM_MAXUSER_ADDRESS VM_MAXUSER_ADDRESS_LA57
#define VM_MAX_ADDRESS 0xc00fffffffffffff
#define VM_MIN_KERNEL_ADDRESS 0xc008000000000000
#define VM_MAX_KERNEL_ADDRESS 0xc00801ffffffffff
#define VM_MAX_SAFE_KERNEL_ADDRESS VM_MAX_KERNEL_ADDRESS
+
+#define SHAREDPAGE_LA48 (VM_MAXUSER_ADDRESS_LA48 - PAGE_SIZE)
+#define SHAREDPAGE_LA57 (VM_MAXUSER_ADDRESS_LA57 - PAGE_SIZE)
+#define SHAREDPAGE SHAREDPAGE_LA48
+#define USRSTACK_LA48 SHAREDPAGE_LA48
+#define USRSTACK_LA57 SHAREDPAGE_LA57
+#define PS_STRINGS_LA48 (USRSTACK_LA48 - sizeof(struct ps_strings))
+#define PS_STRINGS_LA57 (USRSTACK_LA57 - sizeof(struct ps_strings))
#else
#define VM_MIN_ADDRESS 0
#define VM_MAXUSER_ADDRESS VM_MAXUSER_ADDRESS32
#define VM_MAX_ADDRESS 0xffffffff
-#endif
#define SHAREDPAGE (VM_MAXUSER_ADDRESS - PAGE_SIZE)
+#endif
#define FREEBSD32_SHAREDPAGE (VM_MAXUSER_ADDRESS32 - PAGE_SIZE)
#define FREEBSD32_USRSTACK FREEBSD32_SHAREDPAGE
diff --git a/sys/powerpc/powerpc/elf64_machdep.c b/sys/powerpc/powerpc/elf64_machdep.c
--- a/sys/powerpc/powerpc/elf64_machdep.c
+++ b/sys/powerpc/powerpc/elf64_machdep.c
@@ -41,6 +41,7 @@
#include <sys/jail.h>
#include <sys/smp.h>
#include <sys/syscall.h>
+#include <sys/sysctl.h>
#include <sys/signalvar.h>
#include <sys/vnode.h>
#include <sys/linker.h>
@@ -61,7 +62,7 @@
static void exec_setregs_funcdesc(struct thread *td, struct image_params *imgp,
uintptr_t stack);
-struct sysentvec elf64_freebsd_sysvec_v1 = {
+struct sysentvec elf64_freebsd_sysvec_v1_la48 = {
.sv_size = SYS_MAXSYSCALL,
.sv_table = sysent,
.sv_fixup = __elfN(freebsd_fixup),
@@ -75,9 +76,9 @@
.sv_elf_core_prepare_notes = __elfN(prepare_notes),
.sv_minsigstksz = MINSIGSTKSZ,
.sv_minuser = VM_MIN_ADDRESS,
- .sv_maxuser = VM_MAXUSER_ADDRESS,
- .sv_usrstack = USRSTACK,
- .sv_psstrings = PS_STRINGS,
+ .sv_maxuser = VM_MAXUSER_ADDRESS_LA48,
+ .sv_usrstack = USRSTACK_LA48,
+ .sv_psstrings = PS_STRINGS_LA48,
.sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = __elfN(powerpc_copyout_auxargs),
@@ -90,7 +91,7 @@
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
- .sv_shared_page_base = SHAREDPAGE,
+ .sv_shared_page_base = SHAREDPAGE_LA48,
.sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
@@ -105,7 +106,95 @@
.sv_regset_end = SET_LIMIT(__elfN(regset)),
};
-struct sysentvec elf64_freebsd_sysvec_v2 = {
+struct sysentvec elf64_freebsd_sysvec_v1_la57 = {
+ .sv_size = SYS_MAXSYSCALL,
+ .sv_table = sysent,
+ .sv_fixup = __elfN(freebsd_fixup),
+ .sv_sendsig = sendsig,
+ .sv_sigcode = sigcode64,
+ .sv_szsigcode = &szsigcode64,
+ .sv_name = "FreeBSD ELF64",
+ .sv_coredump = __elfN(coredump),
+ .sv_elf_core_osabi = ELFOSABI_FREEBSD,
+ .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR,
+ .sv_elf_core_prepare_notes = __elfN(prepare_notes),
+ .sv_minsigstksz = MINSIGSTKSZ,
+ .sv_minuser = VM_MIN_ADDRESS,
+ .sv_maxuser = VM_MAXUSER_ADDRESS_LA57,
+ .sv_usrstack = USRSTACK_LA57,
+ .sv_psstrings = PS_STRINGS_LA57,
+ .sv_psstringssz = sizeof(struct ps_strings),
+ .sv_stackprot = VM_PROT_ALL,
+ .sv_copyout_auxargs = __elfN(powerpc_copyout_auxargs),
+ .sv_copyout_strings = exec_copyout_strings,
+ .sv_setregs = exec_setregs_funcdesc,
+ .sv_fixlimit = NULL,
+ .sv_maxssiz = NULL,
+ .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_SHP | SV_ASLR |
+ SV_TIMEKEEP | SV_RNG_SEED_VER | SV_SIGSYS,
+ .sv_set_syscall_retval = cpu_set_syscall_retval,
+ .sv_fetch_syscall_args = cpu_fetch_syscall_args,
+ .sv_syscallnames = syscallnames,
+ .sv_shared_page_base = SHAREDPAGE_LA57,
+ .sv_shared_page_len = PAGE_SIZE,
+ .sv_schedtail = NULL,
+ .sv_thread_detach = NULL,
+ .sv_trap = NULL,
+ .sv_hwcap = &cpu_features,
+ .sv_hwcap2 = &cpu_features2,
+ .sv_hwcap3 = NULL,
+ .sv_hwcap4 = NULL,
+ .sv_onexec_old = exec_onexec_old,
+ .sv_onexit = exit_onexit,
+ .sv_regset_begin = SET_BEGIN(__elfN(regset)),
+ .sv_regset_end = SET_LIMIT(__elfN(regset)),
+};
+
+struct sysentvec elf64_freebsd_sysvec_v2_la48 = {
+ .sv_size = SYS_MAXSYSCALL,
+ .sv_table = sysent,
+ .sv_fixup = __elfN(freebsd_fixup),
+ .sv_sendsig = sendsig,
+ .sv_sigcode = sigcode64, /* Fixed up in ppc64_init_sysvecs(). */
+ .sv_szsigcode = &szsigcode64,
+ .sv_name = "FreeBSD ELF64 V2",
+ .sv_coredump = __elfN(coredump),
+ .sv_elf_core_osabi = ELFOSABI_FREEBSD,
+ .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR,
+ .sv_elf_core_prepare_notes = __elfN(prepare_notes),
+ .sv_minsigstksz = MINSIGSTKSZ,
+ .sv_minuser = VM_MIN_ADDRESS,
+ .sv_maxuser = VM_MAXUSER_ADDRESS_LA48,
+ .sv_usrstack = USRSTACK_LA48,
+ .sv_psstrings = PS_STRINGS_LA48,
+ .sv_psstringssz = sizeof(struct ps_strings),
+ .sv_stackprot = VM_PROT_ALL,
+ .sv_copyout_auxargs = __elfN(powerpc_copyout_auxargs),
+ .sv_copyout_strings = exec_copyout_strings,
+ .sv_setregs = exec_setregs,
+ .sv_fixlimit = NULL,
+ .sv_maxssiz = NULL,
+ .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_SHP | SV_ASLR |
+ SV_TIMEKEEP | SV_RNG_SEED_VER | SV_SIGSYS,
+ .sv_set_syscall_retval = cpu_set_syscall_retval,
+ .sv_fetch_syscall_args = cpu_fetch_syscall_args,
+ .sv_syscallnames = syscallnames,
+ .sv_shared_page_base = SHAREDPAGE_LA48,
+ .sv_shared_page_len = PAGE_SIZE,
+ .sv_schedtail = NULL,
+ .sv_thread_detach = NULL,
+ .sv_trap = NULL,
+ .sv_hwcap = &cpu_features,
+ .sv_hwcap2 = &cpu_features2,
+ .sv_hwcap3 = NULL,
+ .sv_hwcap4 = NULL,
+ .sv_onexec_old = exec_onexec_old,
+ .sv_onexit = exit_onexit,
+ .sv_regset_begin = SET_BEGIN(__elfN(regset)),
+ .sv_regset_end = SET_LIMIT(__elfN(regset)),
+};
+
+struct sysentvec elf64_freebsd_sysvec_v2_la57 = {
.sv_size = SYS_MAXSYSCALL,
.sv_table = sysent,
.sv_fixup = __elfN(freebsd_fixup),
@@ -119,9 +208,9 @@
.sv_elf_core_prepare_notes = __elfN(prepare_notes),
.sv_minsigstksz = MINSIGSTKSZ,
.sv_minuser = VM_MIN_ADDRESS,
- .sv_maxuser = VM_MAXUSER_ADDRESS,
- .sv_usrstack = USRSTACK,
- .sv_psstrings = PS_STRINGS,
+ .sv_maxuser = VM_MAXUSER_ADDRESS_LA57,
+ .sv_usrstack = USRSTACK_LA57,
+ .sv_psstrings = PS_STRINGS_LA57,
.sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = __elfN(powerpc_copyout_auxargs),
@@ -134,7 +223,7 @@
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
- .sv_shared_page_base = SHAREDPAGE,
+ .sv_shared_page_base = SHAREDPAGE_LA57,
.sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
@@ -151,47 +240,82 @@
static bool ppc64_elfv1_header_match(const struct image_params *params,
const int32_t *, const uint32_t *);
+static bool ppc64_elfv1_la57_header_match(const struct image_params *params,
+ const int32_t *, const uint32_t *);
static bool ppc64_elfv2_header_match(const struct image_params *params,
const int32_t *, const uint32_t *);
+static bool ppc64_elfv2_la57_header_match(const struct image_params *params,
+ const int32_t *, const uint32_t *);
-static const Elf64_Brandinfo freebsd_brand_info_elfv1 = {
+static const Elf64_Brandinfo freebsd_brand_info_elfv1_la48 = {
.brand = ELFOSABI_FREEBSD,
.machine = EM_PPC64,
.compat_3_brand = "FreeBSD",
.interp_path = "/libexec/ld-elf.so.1",
- .sysvec = &elf64_freebsd_sysvec_v1,
+ .sysvec = &elf64_freebsd_sysvec_v1_la48,
.interp_newpath = NULL,
.brand_note = &elf64_freebsd_brandnote,
.flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
.header_supported = &ppc64_elfv1_header_match
};
-C_SYSINIT(elf64v1, SI_SUB_EXEC, SI_ORDER_ANY,
- (sysinit_cfunc_t) elf64_insert_brand_entry,
- &freebsd_brand_info_elfv1);
+static const Elf64_Brandinfo freebsd_brand_info_elfv1_la57 = {
+ .brand = ELFOSABI_FREEBSD,
+ .machine = EM_PPC64,
+ .compat_3_brand = "FreeBSD",
+ .interp_path = "/libexec/ld-elf.so.1",
+ .sysvec = &elf64_freebsd_sysvec_v1_la57,
+ .interp_newpath = NULL,
+ .brand_note = &elf64_freebsd_brandnote,
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
+ .header_supported = &ppc64_elfv1_la57_header_match
+};
-static const Elf64_Brandinfo freebsd_brand_info_elfv2 = {
+static const Elf64_Brandinfo freebsd_brand_info_elfv2_la48 = {
.brand = ELFOSABI_FREEBSD,
.machine = EM_PPC64,
.compat_3_brand = "FreeBSD",
.interp_path = "/libexec/ld-elf.so.1",
- .sysvec = &elf64_freebsd_sysvec_v2,
+ .sysvec = &elf64_freebsd_sysvec_v2_la48,
.interp_newpath = NULL,
.brand_note = &elf64_freebsd_brandnote,
.flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
.header_supported = &ppc64_elfv2_header_match
};
-C_SYSINIT(elf64v2, SI_SUB_EXEC, SI_ORDER_ANY,
- (sysinit_cfunc_t) elf64_insert_brand_entry,
- &freebsd_brand_info_elfv2);
+static const Elf64_Brandinfo freebsd_brand_info_elfv2_la57 = {
+ .brand = ELFOSABI_FREEBSD,
+ .machine = EM_PPC64,
+ .compat_3_brand = "FreeBSD",
+ .interp_path = "/libexec/ld-elf.so.1",
+ .sysvec = &elf64_freebsd_sysvec_v2_la57,
+ .interp_newpath = NULL,
+ .brand_note = &elf64_freebsd_brandnote,
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
+ .header_supported = &ppc64_elfv2_la57_header_match
+};
+
+static void
+ppc64_register_brand_entries(void *arg __unused)
+{
+ /*
+ * The la57 entries must go first so they can either claim the
+ * image or hand it to the la48 ones.
+ */
+ elf64_insert_brand_entry(&freebsd_brand_info_elfv2_la57);
+ elf64_insert_brand_entry(&freebsd_brand_info_elfv2_la48);
+ elf64_insert_brand_entry(&freebsd_brand_info_elfv1_la57);
+ elf64_insert_brand_entry(&freebsd_brand_info_elfv1_la48);
+}
+SYSINIT(elf64_brands, SI_SUB_EXEC, SI_ORDER_FIRST,
+ ppc64_register_brand_entries, NULL);
static const Elf64_Brandinfo freebsd_brand_oinfo = {
.brand = ELFOSABI_FREEBSD,
.machine = EM_PPC64,
.compat_3_brand = "FreeBSD",
.interp_path = "/usr/libexec/ld-elf.so.1",
- .sysvec = &elf64_freebsd_sysvec_v1,
+ .sysvec = &elf64_freebsd_sysvec_v1_la48,
.interp_newpath = NULL,
.brand_note = &elf64_freebsd_brandnote,
.flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
@@ -207,20 +331,27 @@
static void
ppc64_init_sysvecs(void *arg)
{
- exec_sysvec_init(&elf64_freebsd_sysvec_v2);
- exec_sysvec_init_secondary(&elf64_freebsd_sysvec_v2,
- &elf64_freebsd_sysvec_v1);
+ exec_sysvec_init(&elf64_freebsd_sysvec_v2_la48);
+ exec_sysvec_init_secondary(&elf64_freebsd_sysvec_v2_la48,
+ &elf64_freebsd_sysvec_v2_la57);
+ exec_sysvec_init_secondary(&elf64_freebsd_sysvec_v2_la48,
+ &elf64_freebsd_sysvec_v1_la48);
+ exec_sysvec_init_secondary(&elf64_freebsd_sysvec_v2_la48,
+ &elf64_freebsd_sysvec_v1_la57);
/*
- * Adjust elfv2 sigcode after elfv1 sysvec is initialized.
+ * Adjust elfv2 sigcode after the elfv1 sysvecs are initialized.
* exec_sysvec_init_secondary() assumes secondary sysvecs use
* identical signal code, and skips allocating a second copy.
* Since the ELFv2 trampoline is a strict subset of the ELFv1 code,
* we can work around this by adjusting the offset. This also
* avoids two copies of the trampoline code being allocated!
*/
- elf64_freebsd_sysvec_v2.sv_sigcode_offset +=
+ elf64_freebsd_sysvec_v2_la48.sv_sigcode_offset +=
(uintptr_t)sigcode64_elfv2 - (uintptr_t)&sigcode64;
- elf64_freebsd_sysvec_v2.sv_szsigcode = &szsigcode64_elfv2;
+ elf64_freebsd_sysvec_v2_la48.sv_szsigcode = &szsigcode64_elfv2;
+ elf64_freebsd_sysvec_v2_la57.sv_sigcode_offset +=
+ (uintptr_t)sigcode64_elfv2 - (uintptr_t)&sigcode64;
+ elf64_freebsd_sysvec_v2_la57.sv_szsigcode = &szsigcode64_elfv2;
}
SYSINIT(elf64_sysvec, SI_SUB_EXEC, SI_ORDER_ANY, ppc64_init_sysvecs, NULL);
@@ -244,6 +375,50 @@
return (abi == 2);
}
+/*
+ * Processes get a 47-bit address space by default, see vmparam.h. The full
+ * 52 bits are available through the la57 feature control note or
+ * PROC_LA_CTL; vm.pmap.prefer_uva_la48 flips the default like on amd64.
+ */
+static int prefer_uva_la48 = 1;
+SYSCTL_DECL(_vm_pmap);
+SYSCTL_INT(_vm_pmap, OID_AUTO, prefer_uva_la48, CTLFLAG_RDTUN,
+ &prefer_uva_la48, 0,
+ "Userspace maps are limited to LA48 unless otherwise configured");
+
+static bool
+ppc64_la57_img_compat(const struct image_params *imgp, const uint32_t *fctl0)
+{
+
+ if ((imgp->proc->p_md.md_flags & P_MD_LA57) != 0)
+ return (true);
+ if (fctl0 != NULL && (*fctl0 & NT_FREEBSD_FCTL_LA57) != 0)
+ return (true);
+ if (fctl0 == NULL || (*fctl0 & NT_FREEBSD_FCTL_LA48) != 0)
+ return (false);
+ if ((imgp->proc->p_md.md_flags & P_MD_LA48) != 0)
+ return (false);
+ return (!prefer_uva_la48);
+}
+
+static bool
+ppc64_elfv1_la57_header_match(const struct image_params *params,
+ const int32_t *osrel, const uint32_t *fctl0)
+{
+
+ return (ppc64_elfv1_header_match(params, osrel, fctl0) &&
+ ppc64_la57_img_compat(params, fctl0));
+}
+
+static bool
+ppc64_elfv2_la57_header_match(const struct image_params *params,
+ const int32_t *osrel, const uint32_t *fctl0)
+{
+
+ return (ppc64_elfv2_header_match(params, osrel, fctl0) &&
+ ppc64_la57_img_compat(params, fctl0));
+}
+
static void
exec_setregs_funcdesc(struct thread *td, struct image_params *imgp,
uintptr_t stack)
diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c
--- a/sys/powerpc/powerpc/exec_machdep.c
+++ b/sys/powerpc/powerpc/exec_machdep.c
@@ -128,7 +128,8 @@
static void cleanup_power_extras(struct thread *);
#ifdef __powerpc64__
-extern struct sysentvec elf64_freebsd_sysvec_v2;
+extern struct sysentvec elf64_freebsd_sysvec_v2_la48;
+extern struct sysentvec elf64_freebsd_sysvec_v2_la57;
#endif
#ifdef __powerpc64__
@@ -1192,7 +1193,8 @@
#endif
} else {
#ifdef __powerpc64__
- if (td->td_proc->p_sysent == &elf64_freebsd_sysvec_v2) {
+ if (td->td_proc->p_sysent == &elf64_freebsd_sysvec_v2_la48 ||
+ td->td_proc->p_sysent == &elf64_freebsd_sysvec_v2_la57) {
tf->srr0 = (register_t)entry;
/* ELFv2 ABI requires that the global entry point be in r12. */
tf->fixreg[12] = (register_t)entry;
diff --git a/sys/powerpc/powerpc/vm_machdep.c b/sys/powerpc/powerpc/vm_machdep.c
--- a/sys/powerpc/powerpc/vm_machdep.c
+++ b/sys/powerpc/powerpc/vm_machdep.c
@@ -79,9 +79,11 @@
#include <sys/vmmeter.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
+#include <sys/procctl.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <sys/unistd.h>
+#include <sys/wait.h>
#include <machine/cpu.h>
#include <machine/fpu.h>
@@ -128,6 +130,9 @@
/* Copy the pcb */
bcopy(td1->td_pcb, pcb, sizeof(struct pcb));
+ /* Inherit the machine-dependent process flags. */
+ bcopy(&td1->td_proc->p_md, &p2->p_md, sizeof(p2->p_md));
+
/*
* Create a fresh stack for the new process.
* Copy the trap frame for the return to user mode as if from a
@@ -214,12 +219,89 @@
return (true);
}
+#ifdef __powerpc64__
+static void
+cpu_procctl_la_ctl(struct proc *p, int val)
+{
+
+ switch (val) {
+ case PROC_LA_CTL_LA48_ON_EXEC:
+ p->p_md.md_flags |= P_MD_LA48;
+ p->p_md.md_flags &= ~P_MD_LA57;
+ break;
+ case PROC_LA_CTL_LA57_ON_EXEC:
+ p->p_md.md_flags &= ~P_MD_LA48;
+ p->p_md.md_flags |= P_MD_LA57;
+ break;
+ case PROC_LA_CTL_DEFAULT_ON_EXEC:
+ p->p_md.md_flags &= ~(P_MD_LA48 | P_MD_LA57);
+ break;
+ }
+}
+
+static void
+cpu_procctl_la_status(struct proc *p, int *val)
+{
+ int res;
+
+ if ((p->p_md.md_flags & P_MD_LA48) != 0)
+ res = PROC_LA_CTL_LA48_ON_EXEC;
+ else if ((p->p_md.md_flags & P_MD_LA57) != 0)
+ res = PROC_LA_CTL_LA57_ON_EXEC;
+ else
+ res = PROC_LA_CTL_DEFAULT_ON_EXEC;
+ if (p->p_sysent->sv_maxuser <= VM_MAXUSER_ADDRESS_LA48)
+ res |= PROC_LA_STATUS_LA48;
+ else
+ res |= PROC_LA_STATUS_LA57;
+ *val = res;
+}
+#endif
+
int
-cpu_procctl(struct thread *td __unused, int idtype __unused, id_t id __unused,
- int com __unused, void *data __unused)
+cpu_procctl(struct thread *td, int idtype, id_t id, int com, void *data)
{
+#ifdef __powerpc64__
+ struct proc *p;
+ int error, val;
+ switch (com) {
+ case PROC_LA_CTL:
+ case PROC_LA_STATUS:
+ if (idtype != P_PID) {
+ error = EINVAL;
+ break;
+ }
+ if (com == PROC_LA_CTL) {
+ error = copyin(data, &val, sizeof(val));
+ if (error != 0)
+ break;
+ if (val != PROC_LA_CTL_LA48_ON_EXEC &&
+ val != PROC_LA_CTL_LA57_ON_EXEC &&
+ val != PROC_LA_CTL_DEFAULT_ON_EXEC) {
+ error = EINVAL;
+ break;
+ }
+ }
+ error = pget(id, PGET_CANSEE | PGET_NOTWEXIT | PGET_NOTID, &p);
+ if (error != 0)
+ break;
+ if (com == PROC_LA_CTL)
+ cpu_procctl_la_ctl(p, val);
+ else
+ cpu_procctl_la_status(p, &val);
+ PROC_UNLOCK(p);
+ if (com == PROC_LA_STATUS)
+ error = copyout(&val, data, sizeof(val));
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+#else
return (EINVAL);
+#endif
}
void
diff --git a/usr.bin/elfctl/elfctl.1 b/usr.bin/elfctl/elfctl.1
--- a/usr.bin/elfctl/elfctl.1
+++ b/usr.bin/elfctl/elfctl.1
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 5, 2023
+.Dd November 9, 2026
.Dt ELFCTL 1
.Os
.Sh NAME
@@ -97,7 +97,7 @@
.Ed
.Sh NOTES
On amd64, on a machine with LA57 (5-level paging) mode supported and
-enabled, if both
+enabled, and on powerpc64, if both
.Va la57
and
.Va la48
@@ -109,6 +109,10 @@
.Va vm.pmap.prefer_uva_la48
sysctl MIB defines the default user address space size for binaries
which do not set either of these flags.
+On powerpc64,
+.Va la57
+gives the process the full 52-bit address space of the radix MMU instead
+of the default 47 bits.
.Sh SEE ALSO
.Xr mitigations 7
.Sh HISTORY
diff --git a/usr.bin/elfctl/elfctl.c b/usr.bin/elfctl/elfctl.c
--- a/usr.bin/elfctl/elfctl.c
+++ b/usr.bin/elfctl/elfctl.c
@@ -68,9 +68,10 @@
{ "nostackgap", NT_FREEBSD_FCTL_STKGAP_DISABLE, "Disable stack gap" },
{ "wxneeded", NT_FREEBSD_FCTL_WXNEEDED, "Requires W+X mappings" },
{ "la48", NT_FREEBSD_FCTL_LA48,
- "amd64: Limit user virtual addresses to 48 bits" },
+ "amd64, powerpc64: Limit user virtual addresses to 48 bits" },
{ "la57", NT_FREEBSD_FCTL_LA57,
- "amd64: Allow the use of 57-bit virtual addresses when available" },
+ "amd64, powerpc64: Allow the use of 57-bit (52-bit on powerpc64) "
+ "virtual addresses when available" },
};
static struct option long_opts[] = {
diff --git a/usr.bin/proccontrol/proccontrol.1 b/usr.bin/proccontrol/proccontrol.1
--- a/usr.bin/proccontrol/proccontrol.1
+++ b/usr.bin/proccontrol/proccontrol.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 14, 2024
+.Dd November 9, 2026
.Dt PROCCONTROL 1
.Os
.Sh NAME
@@ -77,8 +77,12 @@
.It Ar kpti
Controls the KPTI enable, AMD64 only.
.It Ar la48
-Control limiting usermode process address space to 48 bits of address,
-AMD64 only, on machines capable of 57-bit addressing.
+Control limiting usermode process address space to 48 bits of address.
+AMD64, on machines capable of 57-bit addressing, and powerpc64 only.
+.It Ar la57
+Control the use of the full address space the machine is capable of,
+57 bits on AMD64 and 52 bits on powerpc64.
+AMD64 and powerpc64 only.
.It Ar logsigexit
Controls the logging of exits due to a signal that would normally cause a core
dump.

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 10, 8:00 PM (9 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41639345
Default Alt Text
D61331.1794340800.diff (23 KB)

Event Timeline