Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177412270
D61331.1794319753.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
23 KB
Referenced Files
None
Subscribers
None
D61331.1794319753.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 10, 2:09 PM (12 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41639345
Default Alt Text
D61331.1794319753.diff (23 KB)
Attached To
Mode
D61331: powerpc64: give processes a 47-bit address space by default
Attached
Detach File
Event Timeline