11.1Sjmcneill/* $NetBSD: fixup.c,v 1.1 2026/01/09 22:54:27 jmcneill Exp $ */ 21.1Sjmcneill 31.1Sjmcneill/*- 41.1Sjmcneill * Copyright (c) 2026 Jared McNeill <jmcneill@invisible.ca> 51.1Sjmcneill * All rights reserved. 61.1Sjmcneill * 71.1Sjmcneill * Redistribution and use in source and binary forms, with or without 81.1Sjmcneill * modification, are permitted provided that the following conditions 91.1Sjmcneill * are met: 101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright 111.1Sjmcneill * notice, this list of conditions and the following disclaimer. 121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 131.1Sjmcneill * notice, this list of conditions and the following disclaimer in the 141.1Sjmcneill * documentation and/or other materials provided with the distribution. 151.1Sjmcneill * 161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171.1Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181.1Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191.1Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201.1Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211.1Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 221.1Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231.1Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241.1Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Sjmcneill * SUCH DAMAGE. 271.1Sjmcneill */ 281.1Sjmcneill 291.1Sjmcneill#include <sys/cdefs.h> 301.1Sjmcneill#ifndef lint 311.1Sjmcneill__RCSID("$NetBSD: fixup.c,v 1.1 2026/01/09 22:54:27 jmcneill Exp $"); 321.1Sjmcneill#endif 331.1Sjmcneill 341.1Sjmcneill#include <sys/types.h> 351.1Sjmcneill#include <sys/mman.h> 361.1Sjmcneill#include <sys/sysctl.h> 371.1Sjmcneill#include <machine/cpu.h> 381.1Sjmcneill#include <errno.h> 391.1Sjmcneill#include "debug.h" 401.1Sjmcneill#include "rtld.h" 411.1Sjmcneill 421.1Sjmcneillstatic bool _rtld_fixup_init; 431.1Sjmcneillstatic uint32_t _rtld_ppc_pvr; 441.1Sjmcneillstatic int _rtld_ncpus; 451.1Sjmcneill 461.1Sjmcneillunion instr { 471.1Sjmcneill u_int i_int; 481.1Sjmcneill struct { 491.1Sjmcneill u_int i_opcd:6; 501.1Sjmcneill u_int i_rs:5; 511.1Sjmcneill u_int i_ra:5; 521.1Sjmcneill u_int i_rb:5; 531.1Sjmcneill u_int i_xo:10; 541.1Sjmcneill u_int i_rc:1; 551.1Sjmcneill } i_x; 561.1Sjmcneill}; 571.1Sjmcneill 581.1Sjmcneill#define OPC_integer_31 0x1f 591.1Sjmcneill#define OPC31_DCBST 0x036 601.1Sjmcneill#define OPC31_STWCX 0x096 611.1Sjmcneill 621.1Sjmcneill#define IBMESPRESSO_P(_pvr) (((_pvr) >> 16) == 0x7001) 631.1Sjmcneill 641.1Sjmcneillstatic inline uint32_t 651.1Sjmcneill_rtld_ppc_mfpvr(void) 661.1Sjmcneill{ 671.1Sjmcneill uint32_t pvr; 681.1Sjmcneill 691.1Sjmcneill asm volatile ("mfpvr %0" : "=r"(pvr)); 701.1Sjmcneill 711.1Sjmcneill return pvr; 721.1Sjmcneill} 731.1Sjmcneill 741.1Sjmcneillint 751.1Sjmcneill_rtld_map_segment_fixup(Elf_Phdr *phdr, caddr_t data_addr, size_t data_size, 761.1Sjmcneill int data_prot) 771.1Sjmcneill{ 781.1Sjmcneill uint32_t *start, *where, *end; 791.1Sjmcneill union instr previ; 801.1Sjmcneill 811.1Sjmcneill if (!_rtld_fixup_init) { 821.1Sjmcneill ssize_t i; 831.1Sjmcneill size_t j; 841.1Sjmcneill 851.1Sjmcneill _rtld_ppc_pvr = _rtld_ppc_mfpvr(); 861.1Sjmcneill _rtld_fixup_init = true; 871.1Sjmcneill j = sizeof(_rtld_ncpus); 881.1Sjmcneill i = _rtld_sysctl("hw.ncpu", &_rtld_ncpus, &j); 891.1Sjmcneill if (i != CTLTYPE_INT) { 901.1Sjmcneill _rtld_ncpus = 1; 911.1Sjmcneill } 921.1Sjmcneill } 931.1Sjmcneill if (!IBMESPRESSO_P(_rtld_ppc_pvr) && _rtld_ncpus == 1) { 941.1Sjmcneill return 0; 951.1Sjmcneill } 961.1Sjmcneill if ((phdr->p_flags & PF_X) == 0) { 971.1Sjmcneill return 0; 981.1Sjmcneill } 991.1Sjmcneill 1001.1Sjmcneill start = (uint32_t *)data_addr; 1011.1Sjmcneill end = start + data_size / sizeof(*where); 1021.1Sjmcneill previ.i_int = 0; 1031.1Sjmcneill 1041.1Sjmcneill dbg(("fixup (espresso) from %p to %p\n", start, end)); 1051.1Sjmcneill 1061.1Sjmcneill if ((data_prot & PROT_WRITE) == 0 && 1071.1Sjmcneill mprotect(start, data_size, data_prot | PROT_WRITE) == -1) { 1081.1Sjmcneill _rtld_error("Cannot write-enable segment: %s", 1091.1Sjmcneill xstrerror(errno)); 1101.1Sjmcneill return -1; 1111.1Sjmcneill } 1121.1Sjmcneill 1131.1Sjmcneill for (where = start; where < end; where++) { 1141.1Sjmcneill union instr i = *(union instr *)where; 1151.1Sjmcneill 1161.1Sjmcneill if (i.i_x.i_opcd == OPC_integer_31 && 1171.1Sjmcneill i.i_x.i_xo == OPC31_STWCX && 1181.1Sjmcneill i.i_x.i_rc == 1) { 1191.1Sjmcneill 1201.1Sjmcneill if (previ.i_x.i_opcd == OPC_integer_31 && 1211.1Sjmcneill previ.i_x.i_xo == OPC31_DCBST && 1221.1Sjmcneill previ.i_x.i_rs == 0 && 1231.1Sjmcneill previ.i_x.i_ra == i.i_x.i_ra && 1241.1Sjmcneill previ.i_x.i_rb == i.i_x.i_rb) { 1251.1Sjmcneill dbg(("skip instruction at %p (not required)", 1261.1Sjmcneill where)); 1271.1Sjmcneill goto next_opcode; 1281.1Sjmcneill } 1291.1Sjmcneill 1301.1Sjmcneill dbg(("fixup instruction at %p: 0x%x", where, i.i_int)); 1311.1Sjmcneill 1321.1Sjmcneill i.i_x.i_rc = 0; 1331.1Sjmcneill 1341.1Sjmcneill *where = i.i_int; 1351.1Sjmcneill __syncicache(where, 4); 1361.1Sjmcneill } 1371.1Sjmcneill 1381.1Sjmcneillnext_opcode: 1391.1Sjmcneill previ = i; 1401.1Sjmcneill } 1411.1Sjmcneill 1421.1Sjmcneill if ((data_prot & PROT_WRITE) == 0 && 1431.1Sjmcneill mprotect(start, data_size, data_prot) == -1) { 1441.1Sjmcneill _rtld_error("Cannot write-protect segment: %s", 1451.1Sjmcneill xstrerror(errno)); 1461.1Sjmcneill return -1; 1471.1Sjmcneill } 1481.1Sjmcneill 1491.1Sjmcneill return 0; 1501.1Sjmcneill} 151