head 1.3; access; symbols netbsd-11-0-RC5:1.3.2.2 netbsd-11-0-RC4:1.3.2.2 netbsd-11:1.3.0.2; locks; strict; comment @ * @; 1.3 date 2026.01.18.19.19.09; author jmcneill; state Exp; branches 1.3.2.1; next 1.2; commitid 9XEEFZiS9U4KnUqG; 1.2 date 2026.01.15.22.13.32; author jmcneill; state Exp; branches; next 1.1; commitid WHux7muLntZWrxqG; 1.1 date 2026.01.09.22.54.27; author jmcneill; state Exp; branches; next ; commitid ICRnSxv4iQ7NSLpG; 1.3.2.1 date 2026.01.18.19.19.09; author martin; state dead; branches; next 1.3.2.2; commitid YjRKys5AO3megMEG; 1.3.2.2 date 2026.05.06.17.18.04; author martin; state Exp; branches; next ; commitid YjRKys5AO3megMEG; desc @@ 1.3 log @powerpc: Improve espresso fixup The previous implementation naively patched all executable program segments and this had some unintended consequences (PR pkg/59928). Let's use the section header table to narrow the scope of the patching. @ text @/* $NetBSD: fixup.c,v 1.2 2026/01/15 22:13:32 jmcneill Exp $ */ /*- * Copyright (c) 2026 Jared McNeill * 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. */ #include #ifndef lint __RCSID("$NetBSD: fixup.c,v 1.2 2026/01/15 22:13:32 jmcneill Exp $"); #endif #include #include #include #include #include #include "debug.h" #include "rtld.h" static bool _rtld_fixup_init; static uint32_t _rtld_ppc_pvr; static int _rtld_ncpus; union instr { u_int i_int; struct { u_int i_opcd:6; u_int i_rs:5; u_int i_ra:5; u_int i_rb:5; u_int i_xo:10; u_int i_rc:1; } i_x; }; #define OPC_integer_31 0x1f #define OPC31_DCBST 0x036 #define OPC31_STWCX 0x096 #define IBMESPRESSO_P(_pvr) (((_pvr) >> 16) == 0x7001) static int _rtld_espresso_fixup_range(caddr_t data_addr, size_t data_size, int data_prot) { uint32_t *start, *end, *where; union instr previ; start = (uint32_t *)data_addr; end = start + data_size / sizeof(*where); previ.i_int = 0; if ((data_prot & PROT_WRITE) == 0 && mprotect(start, data_size, data_prot | PROT_WRITE) == -1) { _rtld_error("Cannot write-enable segment: %s", xstrerror(errno)); return -1; } for (where = start; where < end; where++) { union instr i = *(union instr *)where; if (i.i_x.i_opcd == OPC_integer_31 && i.i_x.i_xo == OPC31_STWCX && i.i_x.i_rc == 1) { if (previ.i_x.i_opcd == OPC_integer_31 && previ.i_x.i_xo == OPC31_DCBST && previ.i_x.i_rs == 0 && previ.i_x.i_ra == i.i_x.i_ra && previ.i_x.i_rb == i.i_x.i_rb) { dbg(("skip instruction at %p (not required)", where)); goto next_opcode; } dbg(("fixup instruction at %p: 0x%x", where, i.i_int)); i.i_x.i_rc = 0; *where = i.i_int; __syncicache(where, 4); } next_opcode: previ = i; } if ((data_prot & PROT_WRITE) == 0 && mprotect(start, data_size, data_prot) == -1) { _rtld_error("Cannot write-protect segment: %s", xstrerror(errno)); return -1; } return 0; } static int _rtld_espresso_fixup(const char *path, int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr, caddr_t data_addr, size_t data_size, int data_prot) { Elf_Shdr *shdr; size_t shdr_size; int i; if (_rtld_ncpus == 1 || ehdr->e_shnum == 0 || (phdr->p_flags & PF_X) == 0) { return 0; } shdr_size = (size_t)ehdr->e_shentsize * ehdr->e_shnum; shdr = mmap(NULL, shdr_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, ehdr->e_shoff); if (shdr == MAP_FAILED) { _rtld_error("%s: mmap of shdr failed: %s", path, xstrerror(errno)); return -1; } for (i = 0; i < ehdr->e_shnum; i++) { Elf_Addr start = shdr[i].sh_addr; Elf_Addr end = shdr[i].sh_addr + shdr[i].sh_size - 1; if (shdr[i].sh_type != SHT_PROGBITS) { continue; } if ((shdr[i].sh_flags & SHF_EXECINSTR) == 0) { continue; } if (start >= phdr->p_vaddr && end < phdr->p_vaddr + phdr->p_filesz) { dbg(("%s: fixup (espresso) from %p to %p", path, (void *)start, (void *)end)); if (_rtld_espresso_fixup_range( data_addr + (start - phdr->p_vaddr), shdr[i].sh_size, data_prot) != 0) { _rtld_error("%s: fixup failed", path); munmap(shdr, shdr_size); return -1; } } } munmap(shdr, shdr_size); return 0; } int _rtld_map_segment_fixup(const char *path, int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr, caddr_t data_addr, size_t data_size, int data_prot) { if (!_rtld_fixup_init) { ssize_t i; size_t j; j = sizeof(_rtld_ppc_pvr); i = _rtld_sysctl("machdep.pvr", &_rtld_ppc_pvr, &j); if (i != CTLTYPE_INT) { _rtld_ppc_pvr = 0; } j = sizeof(_rtld_ncpus); i = _rtld_sysctl("hw.ncpu", &_rtld_ncpus, &j); if (i != CTLTYPE_INT) { _rtld_ncpus = 1; } _rtld_fixup_init = true; } if (IBMESPRESSO_P(_rtld_ppc_pvr)) { return _rtld_espresso_fixup(path, fd, ehdr, phdr, data_addr, data_size, data_prot); } return 0; } @ 1.3.2.1 log @file fixup.c was added on branch netbsd-11 on 2026-05-06 17:18:04 +0000 @ text @d1 201 @ 1.3.2.2 log @Pull up following revision(s) (requested by jmcneill in ticket #254): libexec/ld.elf_so/map_object.c: revision 1.70 libexec/ld.elf_so/arch/powerpc/fixup.c: revision 1.1 libexec/ld.elf_so/arch/powerpc/fixup.c: revision 1.2 libexec/ld.elf_so/rtld.h: revision 1.152 libexec/ld.elf_so/arch/powerpc/Makefile.inc: revision 1.18 libexec/ld.elf_so/Makefile: revision 1.154 This change adds the userspace portion of the IBM Espresso SMP fixup to the netbsd-11 branch. This enables SMP-safeness of a netbsd-11 userland running under a -current kernel on Wii U systems. Useful for eg. bulk builds in chroots. @ text @a0 201 /* $NetBSD: fixup.c,v 1.3 2026/01/18 19:19:09 jmcneill Exp $ */ /*- * Copyright (c) 2026 Jared McNeill * 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. */ #include #ifndef lint __RCSID("$NetBSD: fixup.c,v 1.3 2026/01/18 19:19:09 jmcneill Exp $"); #endif #include #include #include #include #include #include "debug.h" #include "rtld.h" static bool _rtld_fixup_init; static uint32_t _rtld_ppc_pvr; static int _rtld_ncpus; union instr { u_int i_int; struct { u_int i_opcd:6; u_int i_rs:5; u_int i_ra:5; u_int i_rb:5; u_int i_xo:10; u_int i_rc:1; } i_x; }; #define OPC_integer_31 0x1f #define OPC31_DCBST 0x036 #define OPC31_STWCX 0x096 #define IBMESPRESSO_P(_pvr) (((_pvr) >> 16) == 0x7001) static int _rtld_espresso_fixup_range(caddr_t data_addr, size_t data_size, int data_prot) { uint32_t *start, *end, *where; union instr previ; start = (uint32_t *)data_addr; end = start + data_size / sizeof(*where); previ.i_int = 0; if ((data_prot & PROT_WRITE) == 0 && mprotect(start, data_size, data_prot | PROT_WRITE) == -1) { _rtld_error("Cannot write-enable segment: %s", xstrerror(errno)); return -1; } for (where = start; where < end; where++) { union instr i = *(union instr *)where; if (i.i_x.i_opcd == OPC_integer_31 && i.i_x.i_xo == OPC31_STWCX && i.i_x.i_rc == 1) { if (previ.i_x.i_opcd == OPC_integer_31 && previ.i_x.i_xo == OPC31_DCBST && previ.i_x.i_rs == 0 && previ.i_x.i_ra == i.i_x.i_ra && previ.i_x.i_rb == i.i_x.i_rb) { dbg(("skip instruction at %p (not required)", where)); goto next_opcode; } dbg(("fixup instruction at %p: 0x%x", where, i.i_int)); i.i_x.i_rc = 0; *where = i.i_int; __syncicache(where, 4); } next_opcode: previ = i; } if ((data_prot & PROT_WRITE) == 0 && mprotect(start, data_size, data_prot) == -1) { _rtld_error("Cannot write-protect segment: %s", xstrerror(errno)); return -1; } return 0; } static int _rtld_espresso_fixup(const char *path, int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr, caddr_t data_addr, size_t data_size, int data_prot) { Elf_Shdr *shdr; size_t shdr_size; int i; if (_rtld_ncpus == 1 || ehdr->e_shnum == 0 || (phdr->p_flags & PF_X) == 0) { return 0; } shdr_size = (size_t)ehdr->e_shentsize * ehdr->e_shnum; shdr = mmap(NULL, shdr_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, ehdr->e_shoff); if (shdr == MAP_FAILED) { _rtld_error("%s: mmap of shdr failed: %s", path, xstrerror(errno)); return -1; } for (i = 0; i < ehdr->e_shnum; i++) { Elf_Addr start = shdr[i].sh_addr; Elf_Addr end = shdr[i].sh_addr + shdr[i].sh_size - 1; if (shdr[i].sh_type != SHT_PROGBITS) { continue; } if ((shdr[i].sh_flags & SHF_EXECINSTR) == 0) { continue; } if (start >= phdr->p_vaddr && end < phdr->p_vaddr + phdr->p_filesz) { dbg(("%s: fixup (espresso) from %p to %p", path, (void *)start, (void *)end)); if (_rtld_espresso_fixup_range( data_addr + (start - phdr->p_vaddr), shdr[i].sh_size, data_prot) != 0) { _rtld_error("%s: fixup failed", path); munmap(shdr, shdr_size); return -1; } } } munmap(shdr, shdr_size); return 0; } int _rtld_map_segment_fixup(const char *path, int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr, caddr_t data_addr, size_t data_size, int data_prot) { if (!_rtld_fixup_init) { ssize_t i; size_t j; j = sizeof(_rtld_ppc_pvr); i = _rtld_sysctl("machdep.pvr", &_rtld_ppc_pvr, &j); if (i != CTLTYPE_INT) { _rtld_ppc_pvr = 0; } j = sizeof(_rtld_ncpus); i = _rtld_sysctl("hw.ncpu", &_rtld_ncpus, &j); if (i != CTLTYPE_INT) { _rtld_ncpus = 1; } _rtld_fixup_init = true; } if (IBMESPRESSO_P(_rtld_ppc_pvr)) { return _rtld_espresso_fixup(path, fd, ehdr, phdr, data_addr, data_size, data_prot); } return 0; } @ 1.2 log @Fix ld.elf_so on non-espresso SMP and ibm4xx The espresso test in ld.elf_so for espresso had two flaws: 1) It relied on emulation of the privileged mfpvr instruction for userspace, which doesn't exist on ibm4xx platforms. 2) An && should have been an ||, which incorrectly caused the workaround to be applied to all SMP systems. Fixes PR# port-powerpc/59917 @ text @d1 1 a1 1 /* $NetBSD: fixup.c,v 1.1 2026/01/09 22:54:27 jmcneill Exp $ */ d31 1 a31 1 __RCSID("$NetBSD: fixup.c,v 1.1 2026/01/09 22:54:27 jmcneill Exp $"); d64 2 a65 3 int _rtld_map_segment_fixup(Elf_Phdr *phdr, caddr_t data_addr, size_t data_size, int data_prot) d67 1 a67 1 uint32_t *start, *where, *end; a69 24 if (!_rtld_fixup_init) { ssize_t i; size_t j; j = sizeof(_rtld_ppc_pvr); i = _rtld_sysctl("machdep.pvr", &_rtld_ppc_pvr, &j); if (i != CTLTYPE_INT) { _rtld_ppc_pvr = 0; } j = sizeof(_rtld_ncpus); i = _rtld_sysctl("hw.ncpu", &_rtld_ncpus, &j); if (i != CTLTYPE_INT) { _rtld_ncpus = 1; } _rtld_fixup_init = true; } if (!IBMESPRESSO_P(_rtld_ppc_pvr) || _rtld_ncpus == 1) { return 0; } if ((phdr->p_flags & PF_X) == 0) { return 0; } a73 2 dbg(("fixup (espresso) from %p to %p\n", start, end)); d119 83 @ 1.1 log @Add support for the Nintendo Wii U. @ text @d1 1 a1 1 /* $NetBSD$ */ d31 1 a31 1 __RCSID("$NetBSD$"); a63 10 static inline uint32_t _rtld_ppc_mfpvr(void) { uint32_t pvr; asm volatile ("mfpvr %0" : "=r"(pvr)); return pvr; } d75 5 a79 2 _rtld_ppc_pvr = _rtld_ppc_mfpvr(); _rtld_fixup_init = true; d85 2 d88 1 a88 1 if (!IBMESPRESSO_P(_rtld_ppc_pvr) && _rtld_ncpus == 1) { @