1/* $NetBSD: fixup.c,v 1.1 2026/01/09 22:54:27 jmcneill Exp $ */ 2 3/*- 4 * Copyright (c) 2026 Jared McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30#ifndef lint 31__RCSID("$NetBSD: fixup.c,v 1.1 2026/01/09 22:54:27 jmcneill Exp $"); 32#endif 33 34#include <sys/types.h> 35#include <sys/mman.h> 36#include <sys/sysctl.h> 37#include <machine/cpu.h> 38#include <errno.h> 39#include "debug.h" 40#include "rtld.h" 41 42static bool _rtld_fixup_init; 43static uint32_t _rtld_ppc_pvr; 44static int _rtld_ncpus; 45 46union instr { 47 u_int i_int; 48 struct { 49 u_int i_opcd:6; 50 u_int i_rs:5; 51 u_int i_ra:5; 52 u_int i_rb:5; 53 u_int i_xo:10; 54 u_int i_rc:1; 55 } i_x; 56}; 57 58#define OPC_integer_31 0x1f 59#define OPC31_DCBST 0x036 60#define OPC31_STWCX 0x096 61 62#define IBMESPRESSO_P(_pvr) (((_pvr) >> 16) == 0x7001) 63 64static inline uint32_t 65_rtld_ppc_mfpvr(void) 66{ 67 uint32_t pvr; 68 69 asm volatile ("mfpvr %0" : "=r"(pvr)); 70 71 return pvr; 72} 73 74int 75_rtld_map_segment_fixup(Elf_Phdr *phdr, caddr_t data_addr, size_t data_size, 76 int data_prot) 77{ 78 uint32_t *start, *where, *end; 79 union instr previ; 80 81 if (!_rtld_fixup_init) { 82 ssize_t i; 83 size_t j; 84 85 _rtld_ppc_pvr = _rtld_ppc_mfpvr(); 86 _rtld_fixup_init = true; 87 j = sizeof(_rtld_ncpus); 88 i = _rtld_sysctl("hw.ncpu", &_rtld_ncpus, &j); 89 if (i != CTLTYPE_INT) { 90 _rtld_ncpus = 1; 91 } 92 } 93 if (!IBMESPRESSO_P(_rtld_ppc_pvr) && _rtld_ncpus == 1) { 94 return 0; 95 } 96 if ((phdr->p_flags & PF_X) == 0) { 97 return 0; 98 } 99 100 start = (uint32_t *)data_addr; 101 end = start + data_size / sizeof(*where); 102 previ.i_int = 0; 103 104 dbg(("fixup (espresso) from %p to %p\n", start, end)); 105 106 if ((data_prot & PROT_WRITE) == 0 && 107 mprotect(start, data_size, data_prot | PROT_WRITE) == -1) { 108 _rtld_error("Cannot write-enable segment: %s", 109 xstrerror(errno)); 110 return -1; 111 } 112 113 for (where = start; where < end; where++) { 114 union instr i = *(union instr *)where; 115 116 if (i.i_x.i_opcd == OPC_integer_31 && 117 i.i_x.i_xo == OPC31_STWCX && 118 i.i_x.i_rc == 1) { 119 120 if (previ.i_x.i_opcd == OPC_integer_31 && 121 previ.i_x.i_xo == OPC31_DCBST && 122 previ.i_x.i_rs == 0 && 123 previ.i_x.i_ra == i.i_x.i_ra && 124 previ.i_x.i_rb == i.i_x.i_rb) { 125 dbg(("skip instruction at %p (not required)", 126 where)); 127 goto next_opcode; 128 } 129 130 dbg(("fixup instruction at %p: 0x%x", where, i.i_int)); 131 132 i.i_x.i_rc = 0; 133 134 *where = i.i_int; 135 __syncicache(where, 4); 136 } 137 138next_opcode: 139 previ = i; 140 } 141 142 if ((data_prot & PROT_WRITE) == 0 && 143 mprotect(start, data_size, data_prot) == -1) { 144 _rtld_error("Cannot write-protect segment: %s", 145 xstrerror(errno)); 146 return -1; 147 } 148 149 return 0; 150} 151