first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
// Taken from pexpert/pexpert/arm/boot.h and pexpert/pexpert/arm64/boot.h
// Modified for iBoot:
// - Fixed incosistent naming in boot-args struct
// - Added monitor_boot_args
/*
* Copyright (c) 2007-2009 Apple Inc. All rights reserved.
* Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
*/
/*
* @OSF_COPYRIGHT@
*/
#ifndef _PEXPERT_ARM_BOOT_H_
#define _PEXPERT_ARM_BOOT_H_
//#include <kern/kern_types.h>
#define BOOT_LINE_LENGTH 256
/*
* Video information..
*/
struct boot_video {
unsigned long v_baseAddr; /* Base address of video memory */
unsigned long v_display; /* Display Code (if Applicable */
unsigned long v_rowBytes; /* Number of bytes per pixel row */
unsigned long v_width; /* Width */
unsigned long v_height; /* Height */
unsigned long v_depth; /* Pixel Depth and other parameters */
};
#define kBootVideoDepthMask (0xFF)
#define kBootVideoDepthDepthShift (0)
#define kBootVideoDepthRotateShift (8)
#define kBootVideoDepthScaleShift (16)
typedef struct boot_video boot_video;
/* Boot argument structure - passed into Mach kernel at boot time.
*/
#define kBootArgsRevision 2
#define kBootArgsVersion1 1
#define kBootArgsVersion2 2
#define kBootFlagDarkBoot 1
#if defined(__LP64__)
typedef struct boot_args {
uint16_t revision; /* Revision of boot_args structure */
uint16_t version; /* Version of boot_args structure */
uint64_t virtBase; /* Virtual base of memory */
uint64_t physBase; /* Physical base of memory */
uint64_t memSize; /* Size of memory */
uint64_t topOfKernelData; /* Highest physical address used in kernel data area */
boot_video video; /* Video Information */
uint32_t machineType; /* Machine Type */
void *deviceTreeP; /* Base of flattened device tree */
uint32_t deviceTreeLength; /* Length of flattened tree */
char commandLine[BOOT_LINE_LENGTH]; /* Passed in command line */
uint64_t boot_flags; /* Misc boot flags*/
} boot_args;
#else
typedef struct boot_args {
uint16_t revision; /* Revision of boot_args structure */
uint16_t version; /* Version of boot_args structure */
uint32_t virtBase; /* Virtual base of memory */
uint32_t physBase; /* Physical base of memory */
uint32_t memSize; /* Size of memory */
uint32_t topOfKernelData; /* Highest physical address used in kernel data area */
boot_video video; /* Video Information */
uint32_t machineType; /* Machine Type */
void *deviceTreeP; /* Base of flattened device tree */
uint32_t deviceTreeLength; /* Length of flattened tree */
char commandLine[BOOT_LINE_LENGTH]; /* Passed in command line */
uint32_t boot_flags; /* Misc boot flags*/
} boot_args;
#endif
#define SOC_DEVICE_TYPE_BUFFER_SIZE 32
#define PC_TRACE_BUF_SIZE 1024
/*
* Monitor/hypervisor boot argument structure.
*/
#if defined(__LP64__)
typedef struct monitor_boot_args {
uint64_t version; /* structure version - this is version 2 */
uint64_t virtBase; /* virtual base of memory assigned to the monitor */
uint64_t physBase; /* physical address corresponding to the virtual base */
uint64_t memSize; /* size of memory assigned to the monitor */
uint64_t kernArgs; /* physical address of the kernel boot_args structure */
uint64_t kernEntry; /* kernel entrypoint */
uint64_t kernPhysBase; /* physical base of the kernel's address space */
uint64_t kernPhysSlide; /* offset from kernPhysBase to kernel load address */
uint64_t kernVirtSlide; /* virtual slide applied to kernel at load time */
} monitor_boot_args;
#else
typedef struct monitor_boot_args {
uint32_t version; /* structure version - this is version 2 */
uint32_t virtBase; /* virtual base of memory assigned to the monitor */
uint32_t physBase; /* physical address corresponding to the virtual base */
uint32_t memSize; /* size of memory assigned to the monitor */
uint32_t kernArgs; /* physical address of the kernel boot_args structure */
uint32_t kernEntry; /* kernel entrypoint */
uint32_t kernPhysBase; /* physical base of the kernel's address space */
uint32_t kernPhysSlide; /* offset from kernPhysBase to kernel load address */
uint32_t kernVirtSlide; /* virtual slide applied to kernel at load time */
} monitor_boot_args;
#endif
#endif /* _PEXPERT_ARM_BOOT_H_ */
+874
View File
@@ -0,0 +1,874 @@
/*
* Copyright (C) 2007-2014 Apple Inc. All rights reserved.
* Copyright (C) 1998-2006 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#if WITH_HW_GASGAUGE
#include <drivers/gasgauge.h>
#endif
#include <drivers/power.h>
#include <lib/devicetree.h>
#include <lib/env.h>
#include <lib/image.h>
#include <lib/macho.h>
#include <lib/net.h>
#include <lib/nvram.h>
#include <lib/paint.h>
#include <lib/random.h>
#include <lib/syscfg.h>
#if WITH_TICKET
#include <lib/ticket.h>
#endif
#include <platform.h>
#include <platform/memmap.h>
#include <sys.h>
#include <sys/hash.h>
#include <target.h>
#if WITH_CONSISTENT_DBG
#include <drivers/consistent_debug.h>
#endif
extern bool contains_boot_arg(const char *bootArgs, const char *arg, bool prefixmatch);
#include "boot.h"
#define kBootPResponceSize (0x12C)
static char gBootPResponse[kBootPResponceSize];
#define ROOT_DTPATH ""
#ifndef ETHERNET_DTPATH
#define ETHERNET_DTPATH "ethernet"
#endif
#ifndef MULTITOUCH_DTPATH
#define MULTITOUCH_DTPATH ""
#endif
#ifndef WIFI_DTPATH
#define WIFI_DTPATH "arm-io/sdio"
#endif
#ifndef PINTO_DTPATH
#define PINTO_DTPATH ""
#endif
#ifndef BT_DTPATH
#define BT_DTPATH "arm-io/uart3/bluetooth"
#endif
#ifndef BASEBAND_DTPATH
#define BASEBAND_DTPATH "baseband"
#endif
#ifndef CHARGER_DTPATH
#define CHARGER_DTPATH "charger"
#endif
#ifndef USBDEVICE_DTPATH
#define USBDEVICE_DTPATH "arm-io/usb-complex/usb-device"
#endif
int UpdateDeviceTree(const boot_args *boot_args)
{
DTNodePtr node, chosen;
uint32_t propSize, boot_partition;
char *propName;
void *propData;
const char *str;
int result, noenet = 0;
uint32_t ipaddr;
uint8_t ethaddr[6];
void *wifiaddr;
const char *dram_vendor_string;
const char *product_id;
#if WITH_SYSCFG
void *batteryId = NULL;
uint32_t batteryIdSize = 0;
#endif
#if WITH_SYSCFG
// Put the model number in the root node
if (FindNode(0, ROOT_DTPATH, &node)) {
propName = "model-number";
if (FindProperty(node, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('Mod#', propData, propSize);
}
}
// Put the regulatory model number in the root node
if (FindNode(0, ROOT_DTPATH, &node)) {
propName = "regulatory-model-number";
if (FindProperty(node, &propName, &propData, &propSize))
if (syscfgCopyDataForTag('RMd#', propData, propSize) == -1 && ((char *)propData)[0] == 0)
propName[0] = '~';
}
// Put the region info in the root node
if (FindNode(0, ROOT_DTPATH, &node)) {
propName = "region-info";
if (FindProperty(node, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('Regn', propData, propSize);
}
}
// Put the serial number in the root node
if (FindNode(0, ROOT_DTPATH, &node)) {
propName = "serial-number";
if (FindProperty(node, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('SrNm', propData, propSize);
}
}
// Put the mlb serial number in the root node
if (FindNode(0, ROOT_DTPATH, &node)) {
propName = "mlb-serial-number";
if (FindProperty(node, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('MLB#', propData, propSize);
}
}
// Put the config number in the root node
if (FindNode(0, ROOT_DTPATH, &node)) {
propName = "config-number";
if (FindProperty(node, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('CFG#', propData, propSize);
}
}
#endif
// Find the pram node
if (FindNode(0, "pram", &node)) {
// Fill in the memory range
propName = "reg";
if (FindProperty(node, &propName, &propData, &propSize)) {
((uintptr_t *)propData)[0] = platform_get_memory_region_base(kMemoryRegion_Panic);
((uintptr_t *)propData)[1] = platform_get_memory_region_size(kMemoryRegion_Panic);
}
}
// Find the vram node
if (FindNode(0, "vram", &node)) {
// Fill in the memory range
propName = "reg";
if (FindProperty(node, &propName, &propData, &propSize)) {
((uintptr_t *)propData)[0] = platform_get_memory_region_base(kMemoryRegion_Display);
((uintptr_t *)propData)[1] = platform_get_memory_region_size(kMemoryRegion_Display);
}
}
#if defined(SLEEP_TOKEN_BUFFER_BASE) && defined(SLEEP_TOKEN_BUFFER_SIZE)
// Find the stram (sleep-token ram) node
if (FindNode(0, "stram", &node)) {
// Fill in the memory range
propName = "reg";
if (FindProperty(node, &propName, &propData, &propSize)) {
((uintptr_t *)propData)[0] = platform_get_memory_region_base(kMemoryRegion_SleepToken);
((uintptr_t *)propData)[1] = platform_get_memory_region_size(kMemoryRegion_SleepToken);
}
}
#endif
// Find the arm-io node
if (FindNode(0, "arm-io", &node)) {
dt_set_prop_32(node, "chip-revision", platform_get_chip_revision());
dt_set_prop_32(node, "fuse-revision", platform_get_fuse_revision());
}
if (FindNode(0, "product", &node)) {
propName = "product-id";
if (FindProperty(node, &propName, &propData, &propSize)) {
product_id = platform_get_product_id();
memcpy(propData, product_id, propSize);
}
#if WITH_SYSCFG
propName = "device-color-legacy";
if (FindProperty(node, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('ClrC', propData, propSize);
}
propName = "primary-calibration-matrix";
if (FindProperty(node, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('DPCl', propData, propSize);
uint32_t *data_ptr = (uint32_t*)propData;
if (data_ptr[0] == 0x01000000) {
for(uint32_t i = 0; i < ((uint32_t)propSize / sizeof(uint32_t)); i ++) {
data_ptr[i] = swap32(data_ptr[i]);
}
}
}
#if WITH_PAINT
propName = "device-colors";
if (FindProperty(node, &propName, &propData, &propSize)) {
paint_color_map_get_DClr((syscfg_DClr_t *)propData, propSize, false);
}
propName = "device-color-policy";
if (FindProperty(node, &propName, &propData, &propSize)) {
if (propSize == sizeof(uint32_t)) {
*(uint32_t *)propData = paint_get_color_policy();
}
}
#endif
#endif
}
str = env_get("network-type");
if (str && strcmp(str, "ethernet")) noenet = 1;
// Find the chosen node.
if (!FindNode(0, "chosen", &chosen)) {
printf("UpdateDeviceTree: failed to find the /chosen node\n");
return -1;
}
#if WITH_NVRAM
// <rdar://problem/9529235> race condition possible between
// IODTNVRAM and IONVRAMController (restore loses boot-args)
nvram_update_devicetree(chosen, "nvram-proxy-data");
#endif
// Fill in the debug-enabled property
propName = "debug-enabled";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
if (security_allow_modes(kSecurityModeKDPEnabled)) {
((uint32_t *)propData)[0] = 1;
}
}
#if WITH_CONSISTENT_DBG
// Fill in the consistent-debug-root property
propName = "consistent-debug-root";
if(FindProperty(chosen, &propName, &propData, &propSize))
{
*(uint64_t*)propData = (uint64_t)(consistent_debug_get_registry());
}
#endif
// Fill in the development-cert property
propName = "development-cert";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
if (security_allow_modes(kSecurityModeDevCertAccess)) {
((uint32_t *)propData)[0] = 1;
}
}
// Fill in the production-cert property
propName = "production-cert";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
if (security_allow_modes(kSecurityModeProdCertAccess)) {
((uint32_t *)propData)[0] = 1;
}
}
// Fill in the gid-aes-key property
propName = "gid-aes-key";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
if (security_allow_modes(kSecurityModeGIDKeyAccess)) {
((uint32_t *)propData)[0] = 1;
}
}
// Fill in the uid-aes-key property
propName = "uid-aes-key";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
if (security_allow_modes(kSecurityModeUIDKeyAccess)) {
((uint32_t *)propData)[0] = 1;
}
}
// Fill in the secure-boot property
propName = "secure-boot";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
if (security_allow_modes(kSecurityStatusSecureBoot)) {
((uint32_t *)propData)[0] = 1;
}
}
// Fill in the certificate-production-status (raw production mode) property
propName = "certificate-production-status";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint32_t *)propData)[0] = platform_get_raw_production_mode();
}
// Fill in the certificate-security-mode (raw security mode) property
propName = "certificate-security-mode";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint32_t *)propData)[0] = platform_get_secure_mode();
}
// Fill in the effective-production-status-ap property
propName = "effective-production-status-ap";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint32_t *)propData)[0] = platform_get_current_production_mode();
}
// Fill in the effective-security-mode-ap property
// This is for legacy reasons. As far as the AP is concerned, its effective security mode
// doesn't change with demotion
// <rdar://problem/16434259> Get rid of effective-security-mode-ap device tree property
propName = "effective-security-mode-ap";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint32_t *)propData)[0] = platform_get_secure_mode();
}
#if WITH_IMAGE4
// Fill in the boot-nonce property
propName = "boot-nonce";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
uint64_t boot_nonce = platform_get_nonce();
memcpy(propData, &boot_nonce, propSize);
}
#endif
// Fill in the memory vendor info
propName = "dram-vendor";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
dram_vendor_string = platform_get_memory_manufacturer_string();
strlcpy(propData, dram_vendor_string, propSize);
}
#if WITH_SYSCFG
// Fill in the software-behavior property
propName = "software-behavior";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('SwBh', propData, propSize);
}
// Fill in the software-bundle-version property
propName = "software-bundle-version";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('SBVr', propData, propSize);
}
#endif
// Fill in the system-trusted property
propName = "system-trusted";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
if (security_allow_modes(kSecurityStatusSystemTrusted)) {
((uint32_t *)propData)[0] = 1;
}
}
// Fill in the board-id property
propName = "board-id";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint32_t *)propData)[0] = platform_get_board_id();
}
// Fill in the chip-id property
propName = "chip-id";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint32_t *)propData)[0] = platform_get_chip_id();
}
// Fill in the unique-chip-id property
propName = "unique-chip-id";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint64_t *)propData)[0] = platform_get_ecid_id();
}
// Fill in the die-id property
propName = "die-id";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint64_t *)propData)[0] = platform_get_die_id();
}
// Fill in the random-seed property
propName = "random-seed";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
random_get_bytes(propData, propSize);
}
// Fill in the firmware-version
propName = "firmware-version";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
strlcpy(propData, XBS_BUILD_TAG, propSize);
}
#if WITH_TICKET
// Fill in the root-ticket-hash property
propName = "root-ticket-hash";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
uint8_t hash[CCSHA1_OUTPUT_SIZE];
if (propSize >= sizeof(hash) && ticket_get_hash(hash, sizeof(hash))) {
memcpy(propData, hash, sizeof(hash));
}
}
#endif
#if WITH_IMAGE4
{
uint8_t boot_manifest_hash[HASH_OUTPUT_SIZE];
propName = "boot-manifest-hash";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
if (platform_get_boot_manifest_hash(boot_manifest_hash) == 0) {
// Fill in the boot-manifest-hash property
if (propSize >= sizeof(boot_manifest_hash)) {
memcpy(propData, boot_manifest_hash, sizeof(boot_manifest_hash));
} else {
panic("%s property is too small", propName);
}
}
else {
// Rename the boot-manifest-hash property to mark it invalid
propName[0] = '~';
}
}
}
// Fill in the mix-n-match-prevention-status property
propName = "mix-n-match-prevention-status";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint32_t *)propData)[0] = platform_get_mix_n_match_prevention_status();
}
#endif
// Fill in the display-rotation
propName = "display-rotation";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint32_t *)propData)[0] = ((boot_args->video.v_depth >> 8) & 0xFF) * 90;
}
// Fill in the display-rotation
propName = "display-scale";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
((uint32_t *)propData)[0] = ((boot_args->video.v_depth >> 16) & 0xFF) + 1;
}
// Fill in the bootp-response packet
propName = "bootp-response";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
*gBootPResponse = 2;
ipaddr = 0;
env_get_ipaddr("ipaddr", &ipaddr);
memcpy(gBootPResponse + 0x10, &ipaddr, 4);
if (env_get("gateway")) {
env_get_ipaddr("gateway", &ipaddr);
memcpy(gBootPResponse + 236, "\143\202\123\143", 4); //dhcp magic cookie
memcpy(gBootPResponse + 236 + 4, "\003\004", 1 + 1); //dhcp tag=3(gateway), len = 4
memcpy(gBootPResponse + 236 + 6, &ipaddr, 4); //dhcp gateway ip
}
memcpy(propData, gBootPResponse, kBootPResponceSize);
}
dt_set_prop_32(chosen, "security-domain", platform_get_security_domain());
dt_set_prop_32(chosen, "chip-epoch", platform_get_hardware_epoch());
// tell the kernel which partition to root off of, unless the user was explicit
if (!contains_boot_arg(boot_args->commandLine, "rd=", true)) {
propName = "root-matching";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
#if RELEASE_BUILD
boot_partition = 1;
#else
boot_partition = env_get_uint("boot-partition", 0) + 1;
#endif
boot_partition =
// default to the same logic as what is used for loading
// the kernelcache, even if the user loaded that over usb.
// The IOStorageFamily uses 1-indexed partitions
snprintf(propData, propSize,
"<dict><key>IOProviderClass</key><string>IOMedia</string><key>IOPropertyMatch</key><dict><key>Partition ID</key><integer>%u</integer></dict></dict>",
boot_partition);
}
}
#if defined(ASP_BASE) && defined(ASP_SIZE)
// Update ASP region info
if (FindNode(0, "arm-io/ans/iop-ans-nub", &node)) {
propName = "region-base";
if (FindProperty(node, &propName, &propData, &propSize)) {
((uintptr_t *) propData)[0] = platform_get_memory_region_base(kMemoryRegion_StorageProcessor);
}
propName = "region-size";
if (FindProperty(node, &propName, &propData, &propSize)) {
((uintptr_t *) propData)[0] = platform_get_memory_region_size(kMemoryRegion_StorageProcessor);
}
}
#endif
// Add the platform name to the root node
if (FindNode(0, ROOT_DTPATH, &node)) {
propName = "platform-name";
if (FindProperty(node, &propName, &propData, &propSize)) {
strlcpy(propData, PLATFORM_NAME_STRING, propSize);
}
}
// Populate consistent location in device tree with mac addresses for Gestalt
if (FindNode(0, "chosen", &node)) {
propName = "mac-address-ethernet0";
if (FindProperty(node, &propName, &propData, &propSize)) {
if (env_get("ethaddr")) {
env_get_ethaddr("ethaddr", propData);
} else {
int retlen = 0;
if (!target_get_property(TARGET_PROPERTY_ETH_MACADDR, propData, 6, &retlen)) {
propName[0] = '~';
}
}
}
propName = "mac-address-wifi0";
if (FindProperty(node, &propName, &propData, &propSize)) {
if (env_get("wifiaddr")) {
env_get_ethaddr("wifiaddr", propData);
} else {
int retlen = 0;
if (!target_get_property(TARGET_PROPERTY_WIFI_MACADDR, propData, 6, &retlen)) {
propName[0] = '~';
}
}
}
propName = "mac-address-bluetooth0";
if (FindProperty(node, &propName, &propData, &propSize)) {
if (env_get("btaddr")) {
env_get_ethaddr("btaddr", propData);
} else {
int retlen = 0;
if (!target_get_property(TARGET_PROPERTY_BT_MACADDR, propData, 6, &retlen)) {
propName[0] = '~';
}
}
}
}
// Set the ethernet address in "/"
memset(ethaddr, 0, sizeof(ethaddr));
if (env_get("ethaddr")) {
env_get_ethaddr("ethaddr", ethaddr);
} else {
int retlen = 0;
target_get_property(TARGET_PROPERTY_ETH_MACADDR, ethaddr, 6, &retlen);
}
if (FindNode(0, ROOT_DTPATH, &node)) {
propName = "local-mac-address";
if (FindProperty(node, &propName, &propData, &propSize)) {
memcpy(propData, ethaddr, 6);
}
}
// Set the ethernet address is ETHERNET_DTPATH
if (FindNode(0, ETHERNET_DTPATH, &node)) {
propName = "local-mac-address";
if (FindProperty(node, &propName, &propData, &propSize)) {
memcpy(propData, ethaddr, 6);
if (noenet) {
propName = "compatible";
if (FindProperty(node, &propName, &propData, &propSize)) {
strlcpy(propData, "xxx", propSize);
printf("Ethernet disabled\n");
}
}
}
}
// store enet mac-address into 'device-mac-address' in 'usb-device' node for tethering
else if (FindNode(0, USBDEVICE_DTPATH, &node)) {
propName = "device-mac-address";
if (FindProperty(node, &propName, &propData, &propSize)) {
memcpy(propData, ethaddr, 6);
}
}
// Set the wifi address/calibration in the wifi node (SDIO or HSIC)
if (FindNode(0, WIFI_DTPATH, &node)) {
DTNodePtr usb_node;
propName = "local-mac-address";
if (FindProperty(node, &propName, &wifiaddr, &propSize)) {
if (env_get("wifiaddr")) {
env_get_ethaddr("wifiaddr", wifiaddr);
} else {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_MACADDR, wifiaddr, 6, &retlen);
}
// store 'wifiaddr' into 'host-mac-address' in 'usb-device' node for tethering
if (FindNode(0, USBDEVICE_DTPATH, &usb_node)) {
propName = "host-mac-address";
if (FindProperty(usb_node, &propName, &propData, &propSize)) {
memcpy(propData, wifiaddr, 6);
}
}
}
propName = "tx-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_CALIBRATION_TX, propData, 1024, &retlen);
}
propName = "tx-calibration-2.4";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_CALIBRATION_TX_24, propData, propSize, &retlen);
}
propName = "tx-calibration-5.0";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_CALIBRATION_TX_50, propData, propSize, &retlen);
}
propName = "rx-calibration-2.4";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_CALIBRATION_RX_24, propData, propSize, &retlen);
}
propName = "rx-calibration-5.0";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_CALIBRATION_RX_50, propData, propSize, &retlen);
}
propName = "rx-calibration-temp";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_CALIBRATION_RX_TEMP, propData, propSize, &retlen);
}
propName = "freq-group-2g-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_CALIBRATION_FREQ_GROUP_2G, propData, propSize, &retlen);
}
propName = "wireless-board-snum";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_BOARD_SNUM, propData, propSize, &retlen);
}
propName = "wifi-calibration-msf";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_WIFI_WCAL, propData, propSize, &retlen);
}
}
if (FindNode(0, BT_DTPATH, &node)) {
// Set the bt address in the bluetooth node
propName = "local-mac-address";
if (FindProperty(node, &propName, &propData, &propSize)) {
if (env_get("btaddr")) {
env_get_ethaddr("btaddr", propData);
} else {
int retlen = 0;
target_get_property(TARGET_PROPERTY_BT_MACADDR, propData, 6, &retlen);
}
}
#if WITH_SYSCFG
// Update Bluetooth TX and RX calibration data. If calibration data is
// missing, don't publish these properties.
propName = "bluetooth-tx-calibration";
if (FindProperty(node, &propName, &propData, &propSize))
if (syscfgCopyDataForTag('BTTx', propData, propSize) == -1)
propName[0] = '~';
propName = "bluetooth-rx-calibration";
if (FindProperty(node, &propName, &propData, &propSize))
if (syscfgCopyDataForTag('BTRx', propData, propSize) == -1)
propName[0] = '~';
#endif
}
//Fill Pinto address
if (FindNode(0, PINTO_DTPATH, &node)) {
// Set the pinto address in the corresponding node
propName = "local-mac-address";
if (FindProperty(node, &propName, &propData, &propSize)) {
if (env_get("pintoaddr")) {
env_get_ethaddr("pintoaddr", propData);
} else {
int retlen = 0;
target_get_property(TARGET_PROPERTY_PINTO_MACADDR, propData, 6, &retlen);
}
}
}
// Fill in baseband properties as necessary (don't qualify this with presence of the
// radio driver since there may be work to do regardless)
if (FindNode(0, BASEBAND_DTPATH, &node)) {
#if WITH_SYSCFG
propName = "battery-id";
if (FindProperty(node, &propName, &propData, &propSize)) {
#if WITH_HW_GASGAUGE
if (gasgauge_get_battery_id(propData, propSize) == 0) {
batteryId = propData;
batteryIdSize = propSize;
}
else
#endif
{
syscfgCopyDataForTag('Batt', propData, propSize);
}
}
#endif
propName = "region-sku";
if (FindProperty(node, &propName, &propData, &propSize)) {
int retlen = 0;
target_get_property(TARGET_PROPERTY_BB_REGION_SKU, propData, propSize, &retlen);
}
}
// Put the battery-id, boot-voltage in the charger node
if (FindNode(0, CHARGER_DTPATH, &node)) {
#if WITH_SYSCFG
propName = "battery-id";
if (FindProperty(node, &propName, &propData, &propSize)) {
if ((batteryId != NULL) && (propSize == batteryIdSize)) {
memcpy(propData, batteryId, propSize);
}
#if WITH_HW_GASGAUGE
else if (gasgauge_get_battery_id(propData, propSize) != 0)
#endif
{
syscfgCopyDataForTag('Batt', propData, propSize);
}
}
#endif
#if WITH_HW_POWER
propName = "boot-voltage";
if (FindProperty(node, &propName, &propData, &propSize)) {
*(uint32_t *)propData = power_get_boot_battery_level();
}
propName = "boot-adapter-id";
if (FindProperty(node, &propName, &propData, &propSize)) {
power_get_usb_brick_id((uint32_t *)propData, propSize / sizeof(uint32_t));
}
#endif
}
#if WITH_HW_MERLOT
// Set the lcd panel info in the merlot node
if (FindNode(0, MERLOT_DTPATH, &node)) {
extern const uint32_t gMerlotPanelID, gMerlotInitRegisterCount;
extern const uint8_t *gMerlotInitRegisters;
propName = "lcd-panel-id";
if (FindProperty(node, &propName, &propData, &propSize)) {
*(uint32_t *)propData = gMerlotPanelID;
}
propName = "lcd-init-register-count";
if (FindProperty(node, &propName, &propData, &propSize)) {
*(uint32_t *)propData = gMerlotInitRegisterCount;
}
propName = "lcd-init-registers";
if ((gMerlotInitRegisters != 0) && FindProperty(node, &propName, &propData, &propSize)) {
memcpy(propData, gMerlotInitRegisters, gMerlotInitRegisterCount * 2);
}
}
#endif
#if WITH_SYSCFG
// Save the multi-touch calibration
if (FindNode(0, MULTITOUCH_DTPATH, &node)) {
propName = "multi-touch-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
syscfgCopyDataForTag('MtCl', propData, propSize);
}
}
uint32_t sysCfgData = 0;
// Obtain the syscfg entry that identifies when a rear camera is absent
result = syscfgCopyDataForTag('NoBC', (uint8_t *)(&sysCfgData), sizeof(sysCfgData));
// Set rear camera information
if (FindNode(0, "arm-io/isp", &node)) {
propName = "camera-rear";
if (FindProperty(node, &propName, &propData, &propSize)) {
// if bit 0 is 1, then delete rear camera entry
if (result == sizeof(sysCfgData) && (sysCfgData & 0x1))
propName[0] = '~';
}
}
// Also delete rear camera related properties in product/camera if rear camera is absent
if (FindNode(0, "product/camera", &node)) {
if (result == sizeof(sysCfgData) && (sysCfgData & 0x1)) {
propName = "flash";
if (FindProperty(node, &propName, &propData, &propSize))
propName[0] = '~';
propName = "rear-burst";
if (FindProperty(node, &propName, &propData, &propSize))
propName[0] = '~';
propName = "rear-slowmo";
if (FindProperty(node, &propName, &propData, &propSize))
propName[0] = '~';
propName = "rear-max-video-zoom";
if (FindProperty(node, &propName, &propData, &propSize))
propName[0] = '~';
propName = "rear-hdr";
if (FindProperty(node, &propName, &propData, &propSize))
propName[0] = '~';
propName = "panorama";
if (FindProperty(node, &propName, &propData, &propSize))
propName[0] = '~';
propName = "rear-auto-hdr";
if (FindProperty(node, &propName, &propData, &propSize))
propName[0] = '~';
}
}
#endif
// Let the platform and target make updates
result = platform_update_device_tree();
if (result < 0) return result;
// Find the iBoot node under the chosen direectory
// as that's where the boot specific stuff goes.
if (FindNode(0, "chosen/iBoot", &node)) {
// Fill in the boot performance information
extern const uint32_t gPowerOnTime;
extern const uint32_t gDebugPromptTime;
extern const uint32_t gLoadKernelTime;
const uint32_t populateRegistryTime = system_time();
propName = "start-time";
if (FindProperty(node, &propName, &propData, &propSize)) {
*(uint32_t *)propData = gPowerOnTime;
}
propName = "debug-wait-start";
if (FindProperty(node, &propName, &propData, &propSize)) {
*(uint32_t *)propData = gDebugPromptTime;
}
propName = "load-kernel-start";
if (FindProperty(node, &propName, &propData, &propSize)) {
*(uint32_t *)propData = gLoadKernelTime;
}
propName = "populate-registry-time";
if (FindProperty(node, &propName, &propData, &propSize)) {
*(uint32_t *)propData = populateRegistryTime;
}
}
return 0;
}
+793
View File
@@ -0,0 +1,793 @@
/*
* Copyright (C) 2007-2013 Apple Inc. All rights reserved.
* Copyright (C) 1998-2006 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <arch.h>
#include <debug.h>
#include <drivers/display.h>
#include <drivers/power.h>
#include <lib/profile.h>
#include <lib/cksum.h>
#include <lib/devicetree.h>
#include <lib/env.h>
#include <lib/image.h>
#include <lib/lzss.h>
#include <lib/macho.h>
#include <lib/random.h>
#include <lib/syscfg.h>
#include <platform.h>
#include <platform/memmap.h>
#include <sys.h>
#include <target.h>
#include "boot.h"
#include "macho_header.h"
#if __arm64__
#define L2_GRANULE (PAGE_SIZE * (PAGE_SIZE / 8))
#define L2_GRANULE_MASK (L2_GRANULE - 1)
#endif
#if !WITH_MONITOR
addr_t gKernelEntry; // Kernel entry point
#endif
/* From dt.c */
extern int UpdateDeviceTree(const boot_args *boot_args);
/* From lib/ramdisk/ramdisk.c */
extern addr_t gRAMDiskAddr;
extern size_t gRAMDiskSize;
struct compressed_kernel_header {
uint32_t signature;
uint32_t compress_type;
uint32_t adler32;
uint32_t uncompressed_size;
uint32_t compressed_size;
uint32_t reserved[11];
uint8_t platform_name[64];
uint8_t root_path[256];
uint8_t data[];
};
typedef struct compressed_kernel_header compressed_kernel_header;
static int loaded_kernelcache(addr_t secure_addr, size_t secure_size, addr_t *entry, addr_t *boot_args_out);
static int valid_kernelcache(addr_t addr, size_t size);
static size_t decompress_kernelcache(addr_t addr, size_t maxsize);
static addr_t load_kernelcache_object(addr_t addr, size_t size, addr_t *boot_args_out);
static int valid_monitor(addr_t addr, size_t size, addr_t *monitor_addr, size_t *monitor_size);
static void record_kernelcache_segments(addr_t addr, addr_t phys_base);
static void record_kernelcache_segment(addr_t segCmd, addr_t phys_base, addr_t *virt_base);
static bool record_memory_range(char *rangeName, addr_t start, size_t length);
static addr_t alloc_kernel_mem(size_t size);
static void init_kernel_mem_allocator(void);
static addr_t kern_to_phys(addr_t vmaddr, boot_args *boot_args);
static int load_and_set_device_tree(void);
int
load_kernelcache(addr_t addr, size_t len, uint32_t type, addr_t *entry, addr_t *boot_args_out)
{
addr_t secure_addr;
size_t secure_size;
if (len > DEFAULT_KERNEL_SIZE) {
printf("Kernelcache too large\n");
return -2;
}
secure_addr = DEFAULT_KERNEL_ADDRESS;
secure_size = DEFAULT_KERNEL_SIZE;
if (image_load_memory(addr, len, &secure_addr, &secure_size, &type, 1, NULL, 0)) {
printf("Kernelcache image not valid\n");
return -3;
}
return(loaded_kernelcache(secure_addr, secure_size, entry, boot_args_out));
}
#if WITH_FS
int
load_kernelcache_file(const char *path, uint32_t type, addr_t *entry, addr_t *boot_args_out)
{
addr_t secure_addr;
size_t secure_size;
/*
* We could stat the file here to perform a size check, but the load-from-disk
* case is less likely to have an accidentally-oversize kernelcache.
*/
secure_addr = DEFAULT_KERNEL_ADDRESS;
secure_size = DEFAULT_KERNEL_SIZE;
PROFILE_ENTER('ILF');
if (image_load_file(path, &secure_addr, &secure_size, &type, 1, NULL, 0)) {
printf("Kernelcache image not valid\n");
return -3;
}
PROFILE_EXIT('ILF');
return(loaded_kernelcache(secure_addr, secure_size, entry, boot_args_out));
}
#endif /* WITH_FS */
int load_kernelcache_image(struct image_info *image, uint32_t type, addr_t *entry, addr_t *boot_args_out)
{
addr_t secure_addr;
size_t secure_size;
secure_addr = DEFAULT_KERNEL_ADDRESS;
secure_size = DEFAULT_KERNEL_SIZE;
if (image_load(image, &type, 1, NULL, (void **)&secure_addr, &secure_size)) {
printf("Kernelcache image not valid\n");
return -3;
}
return(loaded_kernelcache(secure_addr, secure_size, entry, boot_args_out));
}
static int
loaded_kernelcache(addr_t secure_addr, size_t secure_size, addr_t *entry, addr_t *boot_args_out)
{
addr_t addr;
#if WITH_MONITOR
addr_t monitor_addr;
size_t monitor_size;
#endif
/* consolidate environment */
security_consolidate_environment();
/* Load and setup devicetree. This needs to happen here to retrieve information regarding
* monitor memory
*/
if (load_and_set_device_tree() != 0) {
printf("Failed to setup devicetree \n");
return -4;
}
#if WITH_MONITOR
/* Find total kernelcache file size from compressed header, and look for monitor at the end.
* If theres a monitor, load it now, then load kernelcache
*/
if (valid_monitor(secure_addr, secure_size, &monitor_addr, &monitor_size) != 0) {
load_monitor_image(monitor_addr, monitor_size);
}
#endif
if (!valid_kernelcache(secure_addr, secure_size))
return -4;
PROFILE_ENTER('DKc');
secure_size = decompress_kernelcache(secure_addr, DEFAULT_KERNEL_SIZE);
if (secure_size == 0)
return -5;
PROFILE_EXIT('DKc');
if (!macho_valid(secure_addr))
return -6;
security_protect_memory(0, 0, true);
PROFILE_ENTER('LKO');
addr = load_kernelcache_object(secure_addr, secure_size, boot_args_out);
PROFILE_EXIT('LKO');
if (addr == 0) {
/* Re-init security and clear devicetree, ramdisk */
security_init(true);
return -7;
}
*entry = addr;
return 0;
}
static int
valid_kernelcache(addr_t addr, size_t size)
{
compressed_kernel_header *kernel_header;
kernel_header = (compressed_kernel_header *)addr;
if (ntohl(kernel_header->signature) != 'comp')
return 0;
return 1;
}
static size_t
decompress_kernelcache(addr_t addr, size_t maxsize)
{
compressed_kernel_header *kernel_header;
size_t tmp_size, comp_size, uncomp_size;
uint8_t *uncomp_buffer, *comp_buffer = NULL;
uint32_t kernel_adler32;
size_t result = 0;
kernel_header = (compressed_kernel_header *)(addr);
if (ntohl(kernel_header->signature) != 'comp') {
dprintf(DEBUG_CRITICAL, "unknown kernelcache signature\n");
goto exit;
}
if (ntohl(kernel_header->compress_type) != 'lzss') {
dprintf(DEBUG_CRITICAL, "unknown kernelcache compression type\n");
goto exit;
}
dprintf(DEBUG_CRITICAL, "Loading kernel cache at %p\n", (void *)addr);
// For now, ignore platform name and root path
// Save the adler32 checksum for the kernel cache
kernel_adler32 = ntohl(kernel_header->adler32);
// Ensure that the uncompressed kernel cache is not too large
uncomp_size = ntohl(kernel_header->uncompressed_size);
if (uncomp_size > maxsize) {
dprintf(DEBUG_CRITICAL, "Uncompressed size too large: 0x%08lx, max 0x%08lx\n", uncomp_size, maxsize);
goto exit;
}
uncomp_buffer = (uint8_t *)addr;
// Allocate buffer for the compressed kernel cache
comp_size = ntohl(kernel_header->compressed_size);
comp_buffer = malloc(comp_size);
// Copy the compressed kernel cache to the new buffer
memcpy(comp_buffer, &kernel_header->data[0], comp_size);
tmp_size = decompress_lzss(uncomp_buffer, maxsize, comp_buffer, comp_size);
if (tmp_size != uncomp_size) {
dprintf(DEBUG_CRITICAL, "Size mismatch from lzss 0x%08lx, should be 0x%08lx\n", tmp_size, uncomp_size);
goto exit;
}
if (kernel_adler32 != adler32(uncomp_buffer, uncomp_size)) {
dprintf(DEBUG_CRITICAL, "Adler32 mismatch\n");
goto exit;
}
dprintf(DEBUG_CRITICAL, "Uncompressed kernel cache at %p\n", uncomp_buffer);
result = uncomp_size;
exit:
// Zero and free the buffer for the compressed kernel cache
if (comp_buffer != 0) {
memset(comp_buffer, 0, comp_size);
free(comp_buffer);
}
return result;
}
static int
valid_monitor(addr_t addr, size_t size, addr_t *monitor_addr, size_t *monitor_size)
{
compressed_kernel_header *kernel_header;
size_t kernel_size;
*monitor_addr = 0;
*monitor_size = 0;
kernel_header = (compressed_kernel_header *)addr;
if (ntohl(kernel_header->signature) != 'comp')
return 0;
kernel_size = ntohl(kernel_header->compressed_size) + sizeof(compressed_kernel_header);
if (size > kernel_size) {
if (!macho_valid(addr + kernel_size)) {
return 0;
}
*monitor_addr = addr + kernel_size;
*monitor_size = (size - kernel_size);
return 1;
}
return 0;
}
static int
load_and_set_device_tree(void)
{
/* Load device-tree here. We need to know size of certain memory regions at this point.
* Example: tz1 region to load monitor
*/
if (dt_load() != 0) {
dprintf(DEBUG_CRITICAL, "failed to load device tree\n");
return -1;
}
return 0;
}
/*
* tokenize the string based on whitespace and look for
* each token to have the specified value/prefix
*
* XXX In general, using this function is an admission
* that you haven't architected things correctly.
* boot-args should normally NOT BE USED for
* communication with anything other than the very
* early stages of the kernel startup process.
* For all other applications, use the DeviceTree.
*
* XXX This is also not terribly well implemented. The
* search can be phrased as a substring search for
* prefixmatch ? " <arg>" : " <arg> "
* removing much of the manual token scanning.
*/
bool
contains_boot_arg(const char *bootArgs,
const char *arg,
bool prefixmatch)
{
const char *pos = bootArgs;
size_t tokenlen;
size_t arglen = strlen(arg);
while (*pos) {
// skip leading whitespace
while (*pos && *pos == ' ') {
pos++;
}
if (*pos == '\0') {
// got to the end of the string, this arg isn't present
return false;
}
tokenlen = 0;
while (pos[tokenlen] != '\0' && pos[tokenlen] != ' ') {
tokenlen++;
}
// the current token may end at a space or the end of the buffer,
// so don't dereference past it
if (tokenlen >= arglen) {
if (prefixmatch && strncmp(pos, arg, arglen) == 0) {
return true;
} else if (strncmp(pos, arg, tokenlen) == 0) {
return true;
}
}
pos += tokenlen;
}
return false;
}
void update_display_info(boot_args *boot_args)
{
struct display_info info;
memset(&info, 0, sizeof(info));
display_get_info(&info);
boot_args->video.v_rowBytes = info.stride;
boot_args->video.v_width = info.width;
boot_args->video.v_height = info.height;
boot_args->video.v_depth = info.depth;
boot_args->video.v_baseAddr = (addr_t)info.framebuffer;
boot_args->video.v_display = 1;
}
static size_t
get_kaslr_random(const char *env_var)
{
size_t value;
#if DEBUG_BUILD
// Debug builds can also specify a specific slide for debug reasons
value = env_get_uint(env_var, (size_t)-1);
if (value != (size_t)-1) {
printf("got static value 0x%08lx for %s\n", value, env_var);
return value;
}
#endif
random_get_bytes((void *)&value, sizeof(value));
return value;
}
static void
get_kaslr_slides(uintptr_t kernel_phys_base, size_t kernel_size, size_t *physical_slide_out, size_t *virtual_slide_out)
{
bool kaslr_off = false;
size_t slide_phys = 0;
size_t slide_virt = 0;
#if !RELEASE_BUILD
// Non-release builds can disable ASLR for debug reasons
kaslr_off = env_get_bool("kaslr-off", false);
#endif
#if PAGE_SIZE != 16384
if (!kaslr_off) {
size_t random_value = get_kaslr_random("kaslr-slide") & 0xff;
if (random_value == 0)
random_value = 0x100;
slide_virt = 0x1000000 + (random_value << 21);
} else {
slide_virt = 0;
}
slide_phys = 0;
#else
#if DEFAULT_KERNEL_SIZE + L2_GRANULE > DEFAULT_LOAD_SIZE
#error "kernelcache loader needs extra space to do physical kernel slide"
#endif
const size_t slide_granule = (1 << 21);
const size_t slide_granule_mask = slide_granule - 1;
const size_t slide_virt_max = 0x100 * (2*1024*1024);
ASSERT((kernel_phys_base & L2_GRANULE_MASK) == 0);
if (!kaslr_off) {
// Slide the kernel virtually, keeping in the min and max range
// defined above
size_t random_value = get_kaslr_random("kaslr-slide");
slide_virt = (random_value & ~slide_granule_mask) % slide_virt_max;
if (slide_virt == 0) {
slide_virt = slide_virt_max;
}
// The virtual and physical addresses need to have the same offset
// within an L2 block (2MiB with 4k pages, 32MiB with 16k).
// By contract the kernel's virtual base address is aligned to an L2 block.
// We asserted above that the physical base address is aligned to an L2 block.
// Under those conditions, guaranteeing the alignment is trivial.
slide_phys = (slide_virt & L2_GRANULE_MASK);
} else {
slide_virt = 0;
slide_phys = 0;
}
#endif
dprintf(DEBUG_INFO, "KASLR virtual slide: 0x%08zx\n", slide_virt);
dprintf(DEBUG_INFO, "KASLR physical slide: 0x%08zx\n", slide_phys);
*physical_slide_out = slide_phys;
*virtual_slide_out = slide_virt;
}
static addr_t
load_kernelcache_object(addr_t addr, size_t size, addr_t *boot_args_out)
{
static boot_args boot_args;
const char *bootArgsStr;
addr_t kernel_region_phys;
size_t kernel_region_size;
addr_t kcache_base_kern;
addr_t entry_point_kern;
addr_t entry_point_phys;
addr_t kcache_end_kern;
addr_t ramdisk_kern;
addr_t ramdisk_phys;
addr_t boot_args_kern;
addr_t boot_args_phys;
addr_t devicetree_kern;
addr_t devicetree_phys;
size_t devicetree_size;
addr_t last_alloc_addr_kern;
addr_t last_alloc_addr_phys;
size_t slide_phys;
size_t slide_kern;
// Reset the kernel memory allocator in case this is our second time through
init_kernel_mem_allocator();
// Ditto with boot args
memset(&boot_args, 0, sizeof(boot_args));
boot_args.revision = kBootArgsRevision;
boot_args.version = kBootArgsVersion1 + platform_get_security_epoch();
// Get the region of memory that will be managed by the kernel.
// This is typically above the SEP region (if any) or
// at the base of memory if no SEP
kernel_region_phys = platform_get_memory_region_base(kMemoryRegion_Kernel);
kernel_region_size = platform_get_memory_region_size(kMemoryRegion_Kernel);
get_kaslr_slides(kernel_region_phys, size, &slide_phys, &slide_kern);
RELEASE_ASSERT(slide_phys + size < kernel_region_size);
boot_args.physBase = kernel_region_phys;
boot_args.memSize = kernel_region_size;
// Scan the kernelcache and record the location of segments in the
// /chosen/memory-map node in the devicetree.
record_kernelcache_segments(addr, kernel_region_phys + slide_phys);
// Load the kernelcache object
macho_load(addr, size, kernel_region_phys + slide_phys, &kcache_base_kern, &kcache_end_kern, &entry_point_kern, slide_kern);
boot_args.virtBase = kcache_base_kern - slide_phys;
// Record the space used by the kernelcache
alloc_kernel_mem(kcache_end_kern);
#if RELEASE_BUILD
// Force boot-args for RELEASE builds
bootArgsStr = (gRAMDiskAddr == 0) ? "" : "rd=md0 nand-enable-reformat=1 -progress";
#else
bootArgsStr = env_get("boot-args");
if (bootArgsStr == 0)
bootArgsStr = "";
#endif
if (target_is_tethered()) {
snprintf(boot_args.commandLine, BOOT_LINE_LENGTH, "%s force-usb-power=1 ", bootArgsStr);
} else {
snprintf(boot_args.commandLine, BOOT_LINE_LENGTH, "%s ", bootArgsStr);
}
if (gRAMDiskAddr != 0) {
uint32_t backlight_level;
if (target_get_property(TARGET_PROPERTY_RESTORE_BACKLIGHT_LEVEL, &backlight_level, sizeof(backlight_level), NULL)) {
snprintf(boot_args.commandLine, BOOT_LINE_LENGTH, "%s backlight-level=%d ", bootArgsStr, backlight_level);
}
}
bootArgsStr = boot_args.commandLine;
#if WITH_HW_POWER
boot_args.boot_flags |= (power_is_dark_boot()) ? kBootFlagDarkBoot : 0;
dprintf(DEBUG_INFO, "Passing dark boot state: %s\n", power_is_dark_boot() ? "dark" : "not dark");
#endif
update_display_info(&boot_args);
if (contains_boot_arg(bootArgsStr, "-s", false)
|| contains_boot_arg(bootArgsStr, "-v", false)) {
boot_args.video.v_display = 0;
}
if (contains_boot_arg(bootArgsStr, "debug=", true)) {
security_enable_kdp();
}
#if WITH_HW_USB
if (contains_boot_arg(bootArgsStr, "force-usb-power=1", false)) {
extern bool force_usb_power;
force_usb_power = true;
}
#endif
// If we have a ramdisk, allocate kernel memory for it and copy
// it from its load address to the kernel region
if (gRAMDiskAddr != 0) {
ramdisk_kern = alloc_kernel_mem(gRAMDiskSize);
ramdisk_phys = kern_to_phys(ramdisk_kern, &boot_args);
memcpy((void *)ramdisk_phys, (void *)gRAMDiskAddr, gRAMDiskSize);
record_memory_range("RAMDisk", ramdisk_phys, gRAMDiskSize);
}
// Allocate a kernel memory for the boot args. The boot args
// will get copied to this buffer at the end of this function.
boot_args_kern = alloc_kernel_mem(PAGE_SIZE);
boot_args_phys = kern_to_phys(boot_args_kern, &boot_args);
record_memory_range("BootArgs", boot_args_phys, PAGE_SIZE);
PROFILE_ENTER('UDT');
int ret = UpdateDeviceTree(&boot_args);
PROFILE_EXIT('UDT');
if (ret < 0){
dprintf(DEBUG_CRITICAL, "UpdateDeviceTree() failed with %d\n", ret);
return (addr_t)(NULL);
}
// We need to put the size of the device tree into the device tree, but
// doing so could change its size. So, start by recording dummy information
// and then calculate the final device tree size
record_memory_range("DeviceTree", (addr_t)-1, (size_t)-1);
devicetree_size = dt_get_size();
// Allocate kernel memory for the device tree
devicetree_kern = alloc_kernel_mem(devicetree_size);
devicetree_phys = kern_to_phys(devicetree_kern, &boot_args);
// overwrite the dummy entry made previously
record_memory_range("DeviceTree", devicetree_phys, devicetree_size);
dt_serialize(NULL, (void *)devicetree_phys, devicetree_size);
// After this point, the device tree must not be modified
dt_seal();
boot_args.deviceTreeP = (void *)devicetree_kern;
boot_args.deviceTreeLength = devicetree_size;
entry_point_phys = kern_to_phys(entry_point_kern, &boot_args);
last_alloc_addr_kern = (alloc_kernel_mem(0) + 0x3000) & (size_t)~0x3fff;
last_alloc_addr_phys = kern_to_phys(last_alloc_addr_kern, &boot_args);
boot_args.topOfKernelData = last_alloc_addr_phys;
dprintf(DEBUG_CRITICAL, "boot_args.commandLine = [%s]\n", boot_args.commandLine);
dprintf(DEBUG_INFO, "boot_args.physBase = [%p], boot_args.virtBase = [%p]\n", (void *)boot_args.physBase, (void *)boot_args.virtBase);
dprintf(DEBUG_INFO, "boot_args.deviceTreeLength = 0x%x, boot_args.deviceTreeP = %p, devicetree_phys = %p\n",
boot_args.deviceTreeLength, (void *)boot_args.deviceTreeP, (void *)devicetree_phys);
dprintf(DEBUG_INFO, "kernel entry point: %p, boot args: %p\n", (void *)entry_point_phys, (void *)boot_args_phys);
// copy our local boot arg buffer into the kernel memory region for boot args
memset((void *)boot_args_phys, 0, PAGE_SIZE);
memcpy((void *)boot_args_phys, &boot_args, sizeof(boot_args));
security_create_sleep_token(SLEEP_TOKEN_BUFFER_BASE + kSleepTokeniBootOffset);
#if !RELEASE_BUILD && WITH_CONSISTENT_DEBUG
// Astris needs to be able to find the kernel to do coredumps
dbg_record_header_t kernel_region_hdr;
kernel_region_hdr.record_id = kDbgIdXNUKernelRegion;
kernel_region_hdr.physaddr = kernel_region_phys + slide_phys;
kernel_region_hdr.length = kcache_end_kern - kcache_base_kern;
consistent_debug_register_header(kernel_region_hdr);
#endif
#if WITH_MONITOR
extern addr_t gMonitorArgs;
extern addr_t gMonitorEntry;
monitor_boot_args *mba;
/*
* Patch the monitor boot-args with the location of the
* now-constructed kernel boot-args.
* Ensure that we pass back the monitor entrypoint, not
* the kernel's.
*/
if (0 != gMonitorArgs) {
mba = (struct monitor_boot_args *)gMonitorArgs;
mba->kernArgs = boot_args_phys;
mba->kernEntry = entry_point_phys;
mba->kernPhysBase = kernel_region_phys;
mba->kernPhysSlide = slide_phys;
mba->kernVirtSlide = slide_kern;
dprintf(DEBUG_INFO, "monitor entry point: %p, boot args: %p\n", (void *)gMonitorEntry, (void *)gMonitorArgs);
*boot_args_out = gMonitorArgs;
return gMonitorEntry;
}
#else
gKernelEntry = entry_point_phys;
#endif
*boot_args_out = boot_args_phys;
return entry_point_phys;
}
// Private Functions
/*
* Scan the mach-o kernelcache and record the location
* of interesting segments in the chosen/memory-map node
* of the DeviceTree.
*/
static void
record_kernelcache_segments(addr_t addr, addr_t phys_base)
{
mach_header_t *mH;
addr_t cmdBase;
addr_t virt_base;
uint32_t index;
mH = (mach_header_t *)addr;
cmdBase = (addr_t)(mH + 1);
virt_base = 0;
for (index = 0; index < mH->ncmds; index++) {
#if defined(__LP64__)
if ((((struct load_command *)cmdBase)->cmd) == LC_SEGMENT_64)
#else
if ((((struct load_command *)cmdBase)->cmd) == LC_SEGMENT)
#endif
record_kernelcache_segment(cmdBase, phys_base, &virt_base);
cmdBase += (((struct load_command *)cmdBase)->cmdsize);
}
}
static void
record_kernelcache_segment(addr_t cmdBase, addr_t phys_base, addr_t *virt_base)
{
segment_command_t *segCmd;
char rangeName[kPropNameLength];
addr_t pmaddr;
addr_t vmaddr;
size_t vmsize;
segCmd = (segment_command_t *)cmdBase;
vmaddr = segCmd->vmaddr;
vmsize = segCmd->vmsize;
// if virt_base has not been set let vmaddr select a segment (1MB)
if (*virt_base == 0) {
*virt_base = vmaddr & (addr_t)~0xfffff;
}
pmaddr = phys_base + vmaddr - *virt_base;
if (strcmp(segCmd->segname, "__PAGEZERO")) {
// Add the Segment to the memory-map.
snprintf(rangeName, kPropNameLength, "Kernel-%s", segCmd->segname);
record_memory_range(rangeName, pmaddr, vmsize);
}
}
/* used in the chosen/memory-map node */
typedef struct MemoryMapFileInfo {
addr_t paddr;
size_t length;
} MemoryMapFileInfo;
static bool
record_memory_range(char *rangeName, addr_t start, size_t length)
{
dt_node_t *memory_map;
MemoryMapFileInfo prop_data;
/*
* Find the /chosen/memory-map node.
*/
if (!dt_find_node(0, "chosen/memory-map", &memory_map)) {
dprintf(DEBUG_INFO, "no /chosen/memory-map in DeviceTree\n");
return false;
}
prop_data.paddr = start;
prop_data.length = length;
dt_set_prop(memory_map, rangeName, &prop_data, sizeof(prop_data));
return true;
}
static addr_t last_kernel_addr;
static void
init_kernel_mem_allocator(void)
{
last_kernel_addr = 0;
}
static addr_t
alloc_kernel_mem(size_t size)
{
addr_t addr;
addr = last_kernel_addr;
last_kernel_addr += (size + PAGE_SIZE - 1) & ~(addr_t)(PAGE_SIZE - 1);
return addr;
}
/*
* Convert a kernel-virtual address to a physical address.
*/
static addr_t
kern_to_phys(addr_t vmaddr, boot_args *boot_args)
{
if (boot_args->virtBase == 0)
panic("kern_to_phys without setting kernel virtual base");
return(vmaddr - boot_args->virtBase + boot_args->physBase);
}
+544
View File
@@ -0,0 +1,544 @@
/*
* Copyright (C) 2007-2011 Apple Inc. All rights reserved.
* Copyright (C) 1998-2006 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
/*
* macho.c - Functions for decoding a Mach-o Kernel.
*
* Copyright (c) 1998-2006 Apple Computer, Inc.
*
* DRI: Josh de Cesare
*/
#include <debug.h>
#include <lib/macho.h>
#include <platform.h>
#include "macho_header.h"
static addr_t gRelocBase = (addr_t)NULL;
static addr_t gLinkeditBase = (addr_t)NULL;
static uint32_t gLinkeditOffset = 0;
static uint32_t gkalsr_debug = DEBUG_SPEW;
static bool ProcessSymbols(addr_t cmdBase, size_t slide);
static bool ProcessRelocations(addr_t cmdBase, size_t slide);
static segment_command_t *firstsegfromheader(mach_header_t *header);
static segment_command_t *nextsegfromheader(mach_header_t *header, segment_command_t *seg);
static section_t *firstsect(segment_command_t *sgp);
static section_t *nextsect(segment_command_t *sgp, section_t *sp);
static bool macho_load_segment(addr_t imageAddr,
size_t imageSize,
addr_t segmentAddr,
addr_t loadAddr,
addr_t *virtualBase,
addr_t *virtualEnd,
size_t slide);
/*
* Check whether something might be a Mach-O object.
*/
bool
macho_valid(addr_t addr)
{
return(((mach_header_t *)addr)->magic == MH_MAGIC);
}
bool
macho_slideable(addr_t addr)
{
mach_header_t *mH;
mH = (mach_header_t *)addr;
if (!macho_valid(addr))
return false;
return (mH->flags & MH_PIE) != 0;
}
/*
* Process a mach-o object.
*/
bool
macho_load(
addr_t imageAddr,
size_t imageSize,
addr_t loadAddr,
addr_t *virtualBase,
addr_t *virtualEnd,
addr_t *entryPoint,
size_t slide)
{
mach_header_t *mH;
uint32_t index;
addr_t cmdBase;
mH = (mach_header_t *)imageAddr;
cmdBase = (addr_t)(mH + 1);
*virtualBase = 0;
*virtualEnd = 0;
gRelocBase = (addr_t)NULL;
gLinkeditBase = (addr_t)NULL;
gLinkeditOffset = 0;
dprintf(DEBUG_INFO, "mach-o: loading %p->%p\n", (void *)imageAddr, (void *)loadAddr);
dprintf(DEBUG_INFO, " magic 0x%x\n", mH->magic);
dprintf(DEBUG_INFO, " cputype 0x%x\n", mH->cputype);
dprintf(DEBUG_INFO, " cpusubtype 0x%x\n", mH->cpusubtype);
dprintf(DEBUG_INFO, " filetype 0x%x\n", mH->filetype);
dprintf(DEBUG_INFO, " ncmds 0x%x\n", mH->ncmds);
dprintf(DEBUG_INFO, " sizeofcmds 0x%x\n", mH->sizeofcmds);
dprintf(DEBUG_INFO, " flags 0x%x\n", mH->flags);
for (index = 0; index < mH->ncmds; index++) {
switch(((struct load_command *)cmdBase)->cmd) {
#if defined(__arm__) || defined(__arm64__)
case LC_SEGMENT_ARM:
dprintf(gkalsr_debug, "cmd LC_SEGMENT_ARM:\n");
#else
# error no support for this architecture
#endif
if (!macho_load_segment(imageAddr, imageSize, cmdBase, loadAddr, virtualBase, virtualEnd, slide))
return false;
break;
case LC_UNIXTHREAD:
dprintf(gkalsr_debug, "cmd LC_UNIXTHREAD:\n");
// plus 8 for flavor and count fields
#if defined(__arm__) || defined(__arm64__)
*entryPoint = ((arm_thread_state_t *)(cmdBase + sizeof(struct thread_command) + 8))->pc;
#else
# error no support for this architecture
#endif
break;
case LC_SYMTAB:
dprintf(gkalsr_debug, "cmd LC_SYMTAB:\n");
if (slide == 0) {
break;
}
if (!ProcessSymbols(cmdBase, slide))
return false;
break;
case LC_DYSYMTAB:
dprintf(gkalsr_debug, "cmd LC_DYSYMTAB:\n");
if (slide == 0) {
break;
}
if (!ProcessRelocations(cmdBase, slide))
return false;
break;
}
cmdBase += ((struct load_command *)cmdBase)->cmdsize;
}
if (slide != 0) {
*entryPoint = *entryPoint + slide;
*virtualBase = *virtualBase + slide;
*virtualEnd = *virtualEnd + slide;
}
dprintf(gkalsr_debug, "macho_load: *entryPoint %p *virtualBase %p *virtualEnd %p\n",
(void *)*entryPoint, (void *)*virtualBase, (void *)*virtualEnd);
/*
* Clean everything we have just written out to memory.
*
* XXX this should really not be necessary...
*/
platform_cache_operation(CACHE_CLEAN, 0, 0);
return true;
}
/*
* Process a Mach-o LC_SEGMENT/LC_SEGMENT_64 command.
*/
static bool
macho_load_segment(
addr_t imageAddr,
size_t imageSize,
addr_t segmentAddr,
addr_t loadAddr,
addr_t *virtualBase,
addr_t *virtualEnd,
size_t slide)
{
segment_command_t *cmd;
addr_t segmentSourceAddress;
addr_t segmentDestinationAddress;
addr_t segmentVirtualEnd;
size_t segmentLoadSize;
size_t segmentFillSize;
cmd = (segment_command_t *)segmentAddr;
/*
* We assume that the first segment in the object
* is lowest in memory, and round it down to the
* nearest megabyte.
*/
if (0 == *virtualBase) {
#if defined(__LP64__)
*virtualBase = cmd->vmaddr & 0xfffffffffff00000ULL;
#else
*virtualBase = cmd->vmaddr & 0xfff00000UL;
#endif
} else {
/* sanity check the segment */
if (cmd->vmaddr < *virtualBase)
return false;
if ((cmd->vmaddr + cmd->vmsize) < *virtualBase)
return false;
/*
* XXX should add checks for the file*
* members and sizes
*/
}
/*
* Mostly ignore the __PAGEZERO segment.
*/
if (!strcmp(cmd->segname, "__PAGEZERO"))
return true;
/*
* Precalculate various things we are going to
* need to refer to as we copy and fill the segment.
*/
segmentSourceAddress = imageAddr + cmd->fileoff;
segmentDestinationAddress = loadAddr + (cmd->vmaddr - *virtualBase);
segmentLoadSize = __min(cmd->vmsize, cmd->filesize);
segmentFillSize = __min(cmd->vmsize, cmd->vmsize - cmd->filesize);
segmentVirtualEnd = cmd->vmaddr + cmd->vmsize;
dprintf(DEBUG_INFO,
" %-16.16s %p/%p/%p 0x%zx+0x%zx\n",
cmd->segname,
(void *)segmentDestinationAddress,
(void *)cmd->vmaddr,
(void *)cmd->vmaddr + slide,
segmentLoadSize,
segmentFillSize);
/*
* Copy the portion of the segment contained in
* the object to its location in the loaded area.
*/
if (segmentLoadSize) {
addr_t segmentEnd = segmentDestinationAddress + segmentLoadSize;
/* no integer overflow */
RELEASE_ASSERT(segmentEnd > segmentDestinationAddress);
/* don't overwrite the image we're loading from; assumes we always load
* to an address below the image we're loading from
*/
RELEASE_ASSERT((segmentEnd <= imageAddr) || (segmentEnd >= imageAddr + imageSize));
memcpy((void *)segmentDestinationAddress,
(void *)segmentSourceAddress,
segmentLoadSize);
}
/*
* Zero the remaining portion of the segment.
*/
if (segmentFillSize) {
addr_t fillEnd = segmentDestinationAddress + segmentLoadSize + segmentFillSize;
/* no integer overflow */
RELEASE_ASSERT(fillEnd > segmentDestinationAddress);
/* don't overwrite the image we're loading from; assumes we always load
* to an address below the image we're loading from
*/
RELEASE_ASSERT((fillEnd <= imageAddr) || (fillEnd >= imageAddr + imageSize));
memset((void *)(segmentDestinationAddress + segmentLoadSize),
0,
segmentFillSize);
}
/*
* Adjust the occupied length if we have extended it.
*/
if (segmentVirtualEnd > *virtualEnd)
*virtualEnd = segmentVirtualEnd;
if (slide != 0) {
// Remember reloc and linkedit base
if (gRelocBase == (addr_t)NULL) {
gRelocBase = (addr_t)segmentDestinationAddress;
dprintf(gkalsr_debug,"KASLR: gRelocBase = %p\n", (void *)gRelocBase);
}
if ((gLinkeditBase == (addr_t)NULL) && (!strcmp(cmd->segname, "__LINKEDIT"))) {
gLinkeditBase = (addr_t)segmentDestinationAddress;
gLinkeditOffset = (uint32_t)(cmd->fileoff);
dprintf(gkalsr_debug,"KASR: gLinkeditBase = %p gLinkeditOffset = 0x%x\n", (void *)gLinkeditBase, gLinkeditOffset);
}
if (strcmp(cmd->segname, "__TEXT") == 0) {
segment_command_t *seg;
section_t *sec;
mach_header_t *mh = (mach_header_t *)segmentDestinationAddress;
dprintf(gkalsr_debug, "Applying KASLR slide to _mh_execute_header contents:\n");
for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
dprintf(gkalsr_debug," segment %s: %p -> %p\n", seg->segname,
(void *)seg->vmaddr, (void *)(seg->vmaddr + slide));
seg->vmaddr += slide;
for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
dprintf(gkalsr_debug," -> section %s: %p -> %p\n", sec->sectname,
(void *)sec->addr, (void *)(sec->addr + slide));
sec->addr += slide;
}
}
}
}
/*
* Parse segment sections
*/
{
segment_command_t *seg;
section_t *sec;
addr_t sectionDestinationAddress;
seg = (segment_command_t *)segmentAddr;
for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
sectionDestinationAddress = loadAddr + (sec->addr - *virtualBase);
dprintf(gkalsr_debug," -> section %s: %p/%p 0x%llx\n",
sec->sectname, (void *)sectionDestinationAddress, (void *)sec->addr, (uint64_t)sec->size);
/* Slide pointers in __nl_symbol_ptr section */
if (((sec->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS)) {
void **nl_symbols_ptr;
dprintf(gkalsr_debug,"Slide S_NON_LAZY_SYMBOL_POINTERS \n");
for (nl_symbols_ptr = (void **)sectionDestinationAddress;
nl_symbols_ptr < (void **)(sectionDestinationAddress+sec->size);
nl_symbols_ptr++) {
if (nl_symbols_ptr == (void **)sectionDestinationAddress)
dprintf(gkalsr_debug," %p : %p -> %p\n",
nl_symbols_ptr, *nl_symbols_ptr, *nl_symbols_ptr + slide);
*nl_symbols_ptr = *nl_symbols_ptr + slide;
}
}
}
}
return true;
}
/*
* Return the first segment_command in the header.
*/
segment_command_t *
firstsegfromheader(mach_header_t *header)
{
uint32_t i = 0;
segment_command_t *sgp = (segment_command_t *) ((uintptr_t)header + sizeof(*header));
for (i = 0; i < header->ncmds; i++){
#if defined(__arm__) || defined(__arm64__)
if (sgp->cmd == LC_SEGMENT_ARM)
return sgp;
#else
# error no support for this architecture
#endif
sgp = (segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
}
return (segment_command_t *)NULL;
}
/*
* This routine operates against any kernel mach segment_command structure
* pointer and the provided kernel header, to obtain the sequentially next
* segment_command structure in that header.
*/
segment_command_t *
nextsegfromheader(mach_header_t *header,
segment_command_t *seg)
{
uint32_t i = 0;
segment_command_t *sgp = (segment_command_t *) ((uintptr_t)header + sizeof(*header));
/* Find the index of the passed-in segment */
for (i = 0; sgp != seg && i < header->ncmds; i++) {
sgp = (segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
}
/* Increment to the next load command */
i++;
sgp = (segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
/* Return the next segment command, if any */
for (; i < header->ncmds; i++) {
#if defined(__arm__) || defined(__arm64__)
if (sgp->cmd == LC_SEGMENT_ARM)
return sgp;
#else
# error no support for this architecture
#endif
sgp = (segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
}
return (segment_command_t *)NULL;
}
/*
* This routine can operate against any kernel segment_command structure to
* return the first kernel section immediately following that structure. If
* there are no sections associated with the segment_command structure, it
* returns NULL.
*/
section_t *
firstsect(segment_command_t *sgp)
{
if (!sgp || sgp->nsects == 0)
return (section_t *)NULL;
return (section_t *)(sgp + 1);
}
/*
* This routine can operate against any kernel segment_command structure and
* kernel section to return the next consecutive kernel section immediately
* following the kernel section provided. If there are no sections following
* the provided section, it returns NULL.
*/
section_t *
nextsect(segment_command_t *sgp, section_t *sp)
{
section_t *fsp = firstsect(sgp);
if (((uintptr_t)(sp - fsp) + 1) >= sgp->nsects)
return (section_t *)NULL;
return sp + 1;
}
bool
ProcessSymbols(addr_t cmdBase, size_t slide)
{
struct symtab_command *symtab;
#if defined(__LP64__)
struct nlist_64 *sym;
#else
struct nlist *sym;
#endif
uint32_t i;
uint32_t cnt = 0;
symtab = (struct symtab_command *)cmdBase;
dprintf(gkalsr_debug, "Symbols:\n");
dprintf(gkalsr_debug, "nsyms: %d, symoff: 0x%x\n", symtab->nsyms, symtab->symoff);
if (symtab->nsyms == 0) {
dprintf(gkalsr_debug, "No symbols to relocate\n");
return true;
}
#if defined(__LP64__)
sym = (struct nlist_64 *)(gLinkeditBase + symtab->symoff - gLinkeditOffset);
#else
sym = (struct nlist *)(gLinkeditBase + symtab->symoff - gLinkeditOffset);
#endif
for (i = 0; i < symtab->nsyms; i++) {
if (sym[i].n_type & N_STAB)
continue;
sym[i].n_value += slide;
cnt++;
}
dprintf(gkalsr_debug, "KASLR: Relocated %d symbols\n", cnt);
return true;
}
bool
ProcessRelocations(addr_t cmdBase, size_t slide)
{
struct dysymtab_command *dysymtab;
dysymtab = (struct dysymtab_command *)cmdBase;
dprintf(gkalsr_debug, "Symbols:\n");
dprintf(gkalsr_debug, "local: %6d @ 0x%x\n", dysymtab->nlocalsym, dysymtab->ilocalsym);
dprintf(gkalsr_debug, "external: %6d @ 0x%x\n", dysymtab->nextdefsym, dysymtab->iextdefsym);
dprintf(gkalsr_debug, "undefined: %6d @ 0x%x\n", dysymtab->nundefsym, dysymtab->iundefsym);
dprintf(gkalsr_debug, "indirect: %6d @ 0x%x\n", dysymtab->nindirectsyms, dysymtab->indirectsymoff);
dprintf(gkalsr_debug, "Relocation entries:\n");
dprintf(gkalsr_debug, "local: %6d @ 0x%x\n", dysymtab->nlocrel, dysymtab->locreloff);
dprintf(gkalsr_debug, "external: %6d @ 0x%x\n", dysymtab->nextrel, dysymtab->extreloff);
if (dysymtab->nlocrel != 0) {
struct relocation_info *relocStart;
struct relocation_info *relocEnd;
struct relocation_info *reloc;
if (gRelocBase == (addr_t)NULL) {
dprintf(gkalsr_debug, "KASLR: no writeable segment for relocations found\n");
return false;
}
if (gLinkeditBase == (addr_t)NULL) {
dprintf(gkalsr_debug, "KASLR: No __LINKEDIT segment found\n");
return false;
}
relocStart = (struct relocation_info *)(gLinkeditBase + dysymtab->locreloff - gLinkeditOffset);
relocEnd = &relocStart[dysymtab->nlocrel];
dprintf(gkalsr_debug, "KASLR: processing local relocations...\n");
dprintf(gkalsr_debug, "relocStart = %p, relocEnd = %p\n", relocStart, relocEnd);
for (reloc = relocStart; reloc < relocEnd; reloc++) {
if ((1 << reloc->r_length) != sizeof(void *)) {
/* 2 to the r_length should be the size of a pointer for all relocations */
dprintf(gkalsr_debug, "bad local relocation length (%d)\n", reloc->r_length);
return false;
}
if (reloc->r_type != ARM_RELOC_VANILLA) {
dprintf(gkalsr_debug, "unknown local relocation type (%d)\n", reloc->r_type);
return false;
}
if (reloc->r_pcrel != 0) {
dprintf(gkalsr_debug, "bad local relocation r_pcrel");
return false;
}
if (reloc->r_extern != 0) {
dprintf(gkalsr_debug, "extern relocation found with local relocations\n");
return false;
}
*((uintptr_t*)(gRelocBase + reloc->r_address)) += slide;
if (reloc == relocStart)
dprintf(gkalsr_debug, "r_address = 0x%x, gRelocBase + reloc->r_addres = %p\n",
reloc->r_address, (uintptr_t*)(gRelocBase + reloc->r_address));
}
dprintf(gkalsr_debug, "KASLR: %d local relocations processed\n", dysymtab->nlocrel);
}
return true;
}
+597
View File
@@ -0,0 +1,597 @@
/*
* Copyright (C) 2007-2011 Apple Inc. All rights reserved.
* Copyright (C) 1998-2006 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __MACHO_HEADER_H
#define __MACHO_HEADER_H
// Taken from osfmk/mach/vm_prot.h
typedef int vm_prot_t;
#define VM_PROT_NONE ((vm_prot_t) 0x00)
#define VM_PROT_READ ((vm_prot_t) 0x01) /* read permission */
#define VM_PROT_WRITE ((vm_prot_t) 0x02) /* write permission */
#define VM_PROT_EXECUTE ((vm_prot_t) 0x04) /* execute permission */
// Taken from osfmk/mach/arm/vm_types.h
typedef int integer_t;
// Taken from osfmk/mach/machine.h
typedef integer_t cpu_type_t;
typedef integer_t cpu_subtype_t;
#ifndef __LP64__
// Taken from mach-o/loader.h
/*
* The 32-bit mach header appears at the very beginning of the object file for
* 32-bit architectures.
*/
typedef struct mach_header {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
}mach_header_t;
/* Constant for the magic field of the mach_header (32-bit architectures) */
#define MH_MAGIC 0xfeedface /* the mach magic number */
#else
/*
* The 64-bit mach header appears at the very beginning of object files for
* 64-bit architectures.
*/
typedef struct mach_header_64 {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
} mach_header_t;
/* Constant for the magic field of the mach_header_64 (64-bit architectures) */
#define MH_MAGIC 0xfeedfacf /* the 64-bit mach magic number */
#endif
/* Constants for the flags field of the mach_header */
#define MH_PIE 0x200000 /* When this bit is set, the OS will
load the main executable at a
random address. Only used in
MH_EXECUTE filetypes. */
/*
* The load commands directly follow the mach_header. The total size of all
* of the commands is given by the sizeofcmds field in the mach_header. All
* load commands must have as their first two fields cmd and cmdsize. The cmd
* field is filled in with a constant for that command type. Each command type
* has a structure specifically for it. The cmdsize field is the size in bytes
* of the particular load command structure plus anything that follows it that
* is a part of the load command (i.e. section structures, strings, etc.). To
* advance to the next load command the cmdsize can be added to the offset or
* pointer of the current load command. The cmdsize for 32-bit architectures
* MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple
* of 8 bytes (these are forever the maximum alignment of any load commands).
* The padded bytes must be zero. All tables in the object file must also
* follow these rules so the file can be memory mapped. Otherwise the pointers
* to these tables will not work well or at all on some machines. With all
* padding zeroed like objects will compare byte for byte.
*/
struct load_command {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */
};
/* Constants for the cmd field of all load commands, the type */
#define LC_SEGMENT 0x1 /* segment of this file to be mapped */
#define LC_SYMTAB 0x2 /* link-edit stab symbol table info */
#define LC_THREAD 0x4 /* thread */
#define LC_UNIXTHREAD 0x5 /* unix thread (includes a stack) */
#define LC_DYSYMTAB 0xb /* dynamic link-edit symbol table info */
#define LC_SEGMENT_64 0x19 /* 64-bit segment of this file to be mapped */
#ifndef __LP64__
#define LC_SEGMENT_ARM LC_SEGMENT
#else
#define LC_SEGMENT_ARM LC_SEGMENT_64
#endif
#ifndef __LP64__
/*
* The segment load command indicates that a part of this file is to be
* mapped into the task's address space. The size of this segment in memory,
* vmsize, maybe equal to or larger than the amount to map from this file,
* filesize. The file is mapped starting at fileoff to the beginning of
* the segment in memory, vmaddr. The rest of the memory of the segment,
* if any, is allocated zero fill on demand. The segment's maximum virtual
* memory protection and initial virtual memory protection are specified
* by the maxprot and initprot fields. If the segment has sections then the
* section structures directly follow the segment command and their size is
* reflected in cmdsize.
*/
typedef struct segment_command { /* for 32-bit architectures */
uint32_t cmd; /* LC_SEGMENT */
uint32_t cmdsize; /* includes sizeof section structs */
char segname[16]; /* segment name */
uint32_t vmaddr; /* memory address of this segment */
uint32_t vmsize; /* memory size of this segment */
uint32_t fileoff; /* file offset of this segment */
uint32_t filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
} segment_command_t;
#else
/*
* The 64-bit segment load command indicates that a part of this file is to be
* mapped into a 64-bit task's address space. If the 64-bit segment has
* sections then section_64 structures directly follow the 64-bit segment
* command and their size is reflected in cmdsize.
*/
typedef struct segment_command_64 { /* for 64-bit architectures */
uint32_t cmd; /* LC_SEGMENT_64 */
uint32_t cmdsize; /* includes sizeof section_64 structs */
char segname[16]; /* segment name */
uint64_t vmaddr; /* memory address of this segment */
uint64_t vmsize; /* memory size of this segment */
uint64_t fileoff; /* file offset of this segment */
uint64_t filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
} segment_command_t;
#endif
#ifndef __LP64__
typedef struct section { /* for 32-bit architectures */
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
uint32_t addr; /* memory address of this section */
uint32_t size; /* size in bytes of this section */
uint32_t offset; /* file offset of this section */
uint32_t align; /* section alignment (power of 2) */
uint32_t reloff; /* file offset of relocation entries */
uint32_t nreloc; /* number of relocation entries */
uint32_t flags; /* flags (section type and attributes)*/
uint32_t reserved1; /* reserved (for offset or index) */
uint32_t reserved2; /* reserved (for count or sizeof) */
} section_t;
#else
typedef struct section_64 { /* for 64-bit architectures */
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
uint64_t addr; /* memory address of this section */
uint64_t size; /* size in bytes of this section */
uint32_t offset; /* file offset of this section */
uint32_t align; /* section alignment (power of 2) */
uint32_t reloff; /* file offset of relocation entries */
uint32_t nreloc; /* number of relocation entries */
uint32_t flags; /* flags (section type and attributes)*/
uint32_t reserved1; /* reserved (for offset or index) */
uint32_t reserved2; /* reserved (for count or sizeof) */
uint32_t reserved3; /* reserved */
} section_t;
#endif
/*
* The flags field of a section structure is separated into two parts a section
* type and section attributes. The section types are mutually exclusive (it
* can only have one type) but the section attributes are not (it may have more
* than one attribute).
*/
#define SECTION_TYPE 0x000000ff /* 256 section types */
#define SECTION_ATTRIBUTES 0xffffff00 /* 24 section attributes */
/* Constants for the type of a section */
#define S_REGULAR 0x0 /* regular section */
#define S_ZEROFILL 0x1 /* zero fill on demand section */
#define S_CSTRING_LITERALS 0x2 /* section with only literal C strings*/
#define S_4BYTE_LITERALS 0x3 /* section with only 4 byte literals */
#define S_8BYTE_LITERALS 0x4 /* section with only 8 byte literals */
#define S_LITERAL_POINTERS 0x5 /* section with only pointers to */
/* literals */
/*
* For the two types of symbol pointers sections and the symbol stubs section
* they have indirect symbol table entries. For each of the entries in the
* section the indirect symbol table entries, in corresponding order in the
* indirect symbol table, start at the index stored in the reserved1 field
* of the section structure. Since the indirect symbol table entries
* correspond to the entries in the section the number of indirect symbol table
* entries is inferred from the size of the section divided by the size of the
* entries in the section. For symbol pointers sections the size of the entries
* in the section is 4 bytes and for symbol stubs sections the byte size of the
* stubs is stored in the reserved2 field of the section structure.
*/
#define S_NON_LAZY_SYMBOL_POINTERS 0x6 /* section with only non-lazy
symbol pointers */
#define S_LAZY_SYMBOL_POINTERS 0x7 /* section with only lazy symbol
pointers */
#define S_SYMBOL_STUBS 0x8 /* section with only symbol
stubs, byte size of stub in
the reserved2 field */
#define S_MOD_INIT_FUNC_POINTERS 0x9 /* section with only function
pointers for initialization*/
#define S_MOD_TERM_FUNC_POINTERS 0xa /* section with only function
pointers for termination */
#define S_COALESCED 0xb /* section contains symbols that
are to be coalesced */
#define S_GB_ZEROFILL 0xc /* zero fill on demand section
(that can be larger than 4
gigabytes) */
#define S_INTERPOSING 0xd /* section with only pairs of
function pointers for
interposing */
#define S_16BYTE_LITERALS 0xe /* section with only 16 byte
literals */
#define S_DTRACE_DOF 0xf /* section contains
DTrace Object Format */
#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 /* section with only lazy
symbol pointers to lazy
loaded dylibs */
/*
* The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
* "stab" style symbol table information as described in the header files
* <nlist.h> and <stab.h>.
*/
struct symtab_command {
uint32_t cmd; /* LC_SYMTAB */
uint32_t cmdsize; /* sizeof(struct symtab_command) */
uint32_t symoff; /* symbol table offset */
uint32_t nsyms; /* number of symbol table entries */
uint32_t stroff; /* string table offset */
uint32_t strsize; /* string table size in bytes */
};
/*
* This is the second set of the symbolic information which is used to support
* the data structures for the dynamically link editor.
*
* The original set of symbolic information in the symtab_command which contains
* the symbol and string tables must also be present when this load command is
* present. When this load command is present the symbol table is organized
* into three groups of symbols:
* local symbols (static and debugging symbols) - grouped by module
* defined external symbols - grouped by module (sorted by name if not lib)
* undefined external symbols (sorted by name if MH_BINDATLOAD is not set,
* and in order the were seen by the static
* linker if MH_BINDATLOAD is set)
* In this load command there are offsets and counts to each of the three groups
* of symbols.
*
* This load command contains a the offsets and sizes of the following new
* symbolic information tables:
* table of contents
* module table
* reference symbol table
* indirect symbol table
* The first three tables above (the table of contents, module table and
* reference symbol table) are only present if the file is a dynamically linked
* shared library. For executable and object modules, which are files
* containing only one module, the information that would be in these three
* tables is determined as follows:
* table of contents - the defined external symbols are sorted by name
* module table - the file contains only one module so everything in the
* file is part of the module.
* reference symbol table - is the defined and undefined external symbols
*
* For dynamically linked shared library files this load command also contains
* offsets and sizes to the pool of relocation entries for all sections
* separated into two groups:
* external relocation entries
* local relocation entries
* For executable and object modules the relocation entries continue to hang
* off the section structures.
*/
struct dysymtab_command {
uint32_t cmd; /* LC_DYSYMTAB */
uint32_t cmdsize; /* sizeof(struct dysymtab_command) */
/*
* The symbols indicated by symoff and nsyms of the LC_SYMTAB load command
* are grouped into the following three groups:
* local symbols (further grouped by the module they are from)
* defined external symbols (further grouped by the module they are from)
* undefined symbols
*
* The local symbols are used only for debugging. The dynamic binding
* process may have to use them to indicate to the debugger the local
* symbols for a module that is being bound.
*
* The last two groups are used by the dynamic binding process to do the
* binding (indirectly through the module table and the reference symbol
* table when this is a dynamically linked shared library file).
*/
uint32_t ilocalsym; /* index to local symbols */
uint32_t nlocalsym; /* number of local symbols */
uint32_t iextdefsym;/* index to externally defined symbols */
uint32_t nextdefsym;/* number of externally defined symbols */
uint32_t iundefsym; /* index to undefined symbols */
uint32_t nundefsym; /* number of undefined symbols */
/*
* For the for the dynamic binding process to find which module a symbol
* is defined in the table of contents is used (analogous to the ranlib
* structure in an archive) which maps defined external symbols to modules
* they are defined in. This exists only in a dynamically linked shared
* library file. For executable and object modules the defined external
* symbols are sorted by name and is use as the table of contents.
*/
uint32_t tocoff; /* file offset to table of contents */
uint32_t ntoc; /* number of entries in table of contents */
/*
* To support dynamic binding of "modules" (whole object files) the symbol
* table must reflect the modules that the file was created from. This is
* done by having a module table that has indexes and counts into the merged
* tables for each module. The module structure that these two entries
* refer to is described below. This exists only in a dynamically linked
* shared library file. For executable and object modules the file only
* contains one module so everything in the file belongs to the module.
*/
uint32_t modtaboff; /* file offset to module table */
uint32_t nmodtab; /* number of module table entries */
/*
* To support dynamic module binding the module structure for each module
* indicates the external references (defined and undefined) each module
* makes. For each module there is an offset and a count into the
* reference symbol table for the symbols that the module references.
* This exists only in a dynamically linked shared library file. For
* executable and object modules the defined external symbols and the
* undefined external symbols indicates the external references.
*/
uint32_t extrefsymoff; /* offset to referenced symbol table */
uint32_t nextrefsyms; /* number of referenced symbol table entries */
/*
* The sections that contain "symbol pointers" and "routine stubs" have
* indexes and (implied counts based on the size of the section and fixed
* size of the entry) into the "indirect symbol" table for each pointer
* and stub. For every section of these two types the index into the
* indirect symbol table is stored in the section header in the field
* reserved1. An indirect symbol table entry is simply a 32bit index into
* the symbol table to the symbol that the pointer or stub is referring to.
* The indirect symbol table is ordered to match the entries in the section.
*/
uint32_t indirectsymoff; /* file offset to the indirect symbol table */
uint32_t nindirectsyms; /* number of indirect symbol table entries */
/*
* To support relocating an individual module in a library file quickly the
* external relocation entries for each module in the library need to be
* accessed efficiently. Since the relocation entries can't be accessed
* through the section headers for a library file they are separated into
* groups of local and external entries further grouped by module. In this
* case the presents of this load command who's extreloff, nextrel,
* locreloff and nlocrel fields are non-zero indicates that the relocation
* entries of non-merged sections are not referenced through the section
* structures (and the reloff and nreloc fields in the section headers are
* set to zero).
*
* Since the relocation entries are not accessed through the section headers
* this requires the r_address field to be something other than a section
* offset to identify the item to be relocated. In this case r_address is
* set to the offset from the vmaddr of the first LC_SEGMENT command.
* For MH_SPLIT_SEGS images r_address is set to the the offset from the
* vmaddr of the first read-write LC_SEGMENT command.
*
* The relocation entries are grouped by module and the module table
* entries have indexes and counts into them for the group of external
* relocation entries for that the module.
*
* For sections that are merged across modules there must not be any
* remaining external relocation entries for them (for merged sections
* remaining relocation entries must be local).
*/
uint32_t extreloff; /* offset to external relocation entries */
uint32_t nextrel; /* number of external relocation entries */
/*
* All the local relocation entries are grouped together (they are not
* grouped by their module since they are only used if the object is moved
* from it staticly link edited address).
*/
uint32_t locreloff; /* offset to local relocation entries */
uint32_t nlocrel; /* number of local relocation entries */
};
/*
* An indirect symbol table entry is simply a 32bit index into the symbol table
* to the symbol that the pointer or stub is refering to. Unless it is for a
* non-lazy symbol pointer section for a defined symbol which strip(1) as
* removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. If the
* symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that.
*/
#define INDIRECT_SYMBOL_LOCAL 0x80000000
#define INDIRECT_SYMBOL_ABS 0x40000000
/*
* Thread commands contain machine-specific data structures suitable for
* use in the thread state primitives. The machine specific data structures
* follow the struct thread_command as follows.
* Each flavor of machine specific data structure is preceded by an unsigned
* long constant for the flavor of that data structure, an uint32_t
* that is the count of longs of the size of the state data structure and then
* the state data structure follows. This triple may be repeated for many
* flavors. The constants for the flavors, counts and state data structure
* definitions are expected to be in the header file <machine/thread_status.h>.
* These machine specific data structures sizes must be multiples of
* 4 bytes The cmdsize reflects the total size of the thread_command
* and all of the sizes of the constants for the flavors, counts and state
* data structures.
*
* For executable objects that are unix processes there will be one
* thread_command (cmd == LC_UNIXTHREAD) created for it by the link-editor.
* This is the same as a LC_THREAD, except that a stack is automatically
* created (based on the shell's limit for the stack size). Command arguments
* and environment variables are copied onto that stack.
*/
struct thread_command {
uint32_t cmd; /* LC_THREAD or LC_UNIXTHREAD */
uint32_t cmdsize; /* total size of this command */
/* uint32_t flavor flavor of thread state */
/* uint32_t count count of longs in thread state */
/* struct XXX_thread_state state thread state for this flavor */
/* ... */
};
#ifdef __arm__
// Taken from osfmk/mach/arm/_types.h
typedef struct arm_thread_state
{
uint32_t r[13]; /* General purpose register r0-r12 */
uint32_t sp; /* Stack pointer r13 */
uint32_t lr; /* Link regisster r14 */
uint32_t pc; /* Program counter r15 */
uint32_t cpsr; /* Current program status register */
} arm_thread_state_t;
#else
#ifdef __arm64__
// Based from osfmk/mach/arm/_structs.h
typedef struct arm_thread_state64
{
uint64_t x[29]; /* General purpose registers x0-x28 */
uint64_t fp; /* Frame pointer x29 */
uint64_t lr; /* Link register x30 */
uint64_t sp; /* Stack pointer x31 */
uint64_t pc; /* Program counter */
uint32_t cpsr; /* Current program status register */
} arm_thread_state_t;
#endif
#endif
/*
* Format of a symbol table entry of a Mach-O file for 32-bit architectures.
* Modified from the BSD format. The modifications from the original format
* were changing n_other (an unused field) to n_sect and the addition of the
* N_SECT type. These modifications are required to support symbols in a larger
* number of sections not just the three sections (text, data and bss) in a BSD
* file.
*/
struct nlist {
union {
#ifndef __LP64__
char *n_name; /* for use when in-core */
#endif
int32_t n_strx; /* index into the string table */
} n_un;
uint8_t n_type; /* type flag, see below */
uint8_t n_sect; /* section number or NO_SECT */
int16_t n_desc; /* see <mach-o/stab.h> */
uint32_t n_value; /* value of this symbol (or stab offset) */
};
/*
* This is the symbol table entry structure for 64-bit architectures.
*/
struct nlist_64 {
union {
uint32_t n_strx; /* index into the string table */
} n_un;
uint8_t n_type; /* type flag, see below */
uint8_t n_sect; /* section number or NO_SECT */
uint16_t n_desc; /* see <mach-o/stab.h> */
uint64_t n_value; /* value of this symbol (or stab offset) */
};
/*
* Symbols with a index into the string table of zero (n_un.n_strx == 0) are
* defined to have a null, "", name. Therefore all string indexes to non null
* names must not have a zero string index. This is bit historical information
* that has never been well documented.
*/
/*
* The n_type field really contains four fields:
* unsigned char N_STAB:3,
* N_PEXT:1,
* N_TYPE:3,
* N_EXT:1;
* which are used via the following masks.
*/
#define N_STAB 0xe0 /* if any of these bits set, a symbolic debugging entry */
#define N_PEXT 0x10 /* private external symbol bit */
#define N_TYPE 0x0e /* mask for the type bits */
#define N_EXT 0x01 /* external symbol bit, set for external symbols */
/*
* Format of a relocation entry of a Mach-O file. Modified from the 4.3BSD
* format. The modifications from the original format were changing the value
* of the r_symbolnum field for "local" (r_extern == 0) relocation entries.
* This modification is required to support symbols in an arbitrary number of
* sections not just the three sections (text, data and bss) in a 4.3BSD file.
* Also the last 4 bits have had the r_type tag added to them.
*/
struct relocation_info {
int32_t r_address; /* offset in the section to what is being
relocated */
uint32_t r_symbolnum:24, /* symbol index if r_extern == 1 or section
ordinal if r_extern == 0 */
r_pcrel:1, /* was relocated pc relative already */
r_length:2, /* 0=byte, 1=word, 2=long, 3=quad */
r_extern:1, /* does not include value of sym referenced */
r_type:4; /* if not 0, machine specific relocation type */
};
enum reloc_type_arm
{
ARM_RELOC_VANILLA, /* generic relocation as discribed above */
ARM_RELOC_PAIR, /* the second relocation entry of a pair */
ARM_RELOC_SECTDIFF, /* a PAIR follows with subtract symbol value */
ARM_RELOC_LOCAL_SECTDIFF, /* like ARM_RELOC_SECTDIFF, but the symbol
referenced was local. */
ARM_RELOC_PB_LA_PTR,/* prebound lazy pointer */
ARM_RELOC_BR24, /* 24 bit branch displacement (to a word address) */
ARM_THUMB_RELOC_BR22, /* 22 bit branch displacement (to a half-word
address) */
ARM_THUMB_32BIT_BRANCH, /* obsolete - a thumb 32-bit branch instruction
possibly needing page-spanning branch workaround */
/*
* For these two r_type relocations they always have a pair following them
* and the r_length bits are used differently. The encoding of the
* r_length is as follows:
* low bit of r_length:
* 0 - :lower16: for movw instructions
* 1 - :upper16: for movt instructions
* high bit of r_length:
* 0 - arm instructions
* 1 - thumb instructions
* the other half of the relocated expression is in the following pair
* relocation entry in the the low 16 bits of r_address field.
*/
ARM_RELOC_HALF,
ARM_RELOC_HALF_SECTDIFF
};
#endif /* __MACHO_HEADER_H */
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2007-2013 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <arch.h>
#include <debug.h>
#include <lib/image.h>
#include <lib/macho.h>
#include <lib/env.h>
#include <platform.h>
#include <platform/memmap.h>
#if WITH_HW_MIU
#include <platform/soc/miu.h>
#endif
#include <sys.h>
#include <sys/menu.h>
#include "boot.h"
addr_t gMonitorEntry;
addr_t gMonitorArgs;
/*
* Only applicable if the platform memory map has allocations for
* a monitor.
*/
#if WITH_MONITOR
static int loaded_monitor(addr_t secure_addr, size_t secure_size);
/*
* This expects a known macho image of size 'size' is placed at address 'addr'.
* This is helper function to single monitor + kernel load image, where monitor macho
* is placed at the end of compressed kernelcache, and entire object is wrapped into
* img3/4 format.
*/
int
load_monitor_image(addr_t addr, size_t size)
{
if (size > platform_get_memory_region_size(kMemoryRegion_Monitor)) {
printf("monitor too large\n");
return -2;
}
return (loaded_monitor(addr, size));
}
static int
loaded_monitor(addr_t secure_addr, size_t secure_size)
{
monitor_boot_args *mba;
addr_t virtualBase;
addr_t virtualEnd;
addr_t monitor_base;
addr_t monitor_size;
if (!macho_valid(secure_addr))
return -6;
monitor_base = platform_get_memory_region_base(kMemoryRegion_Monitor);
monitor_size = platform_get_memory_region_size(kMemoryRegion_Monitor);
if (!macho_load(secure_addr, secure_size, monitor_base, &virtualBase, &virtualEnd, &gMonitorEntry, 0))
return -7;
dprintf(DEBUG_INFO, "monitor loaded at virt: %p, phys: %p, entry: %p\n",
(void *)virtualBase, (void *)monitor_base, (void *)gMonitorEntry);
gMonitorEntry -= virtualBase;
gMonitorEntry += monitor_base;
mba = (monitor_boot_args *)(monitor_base + monitor_size - sizeof(*mba));
mba->version = 2;
mba->virtBase = virtualBase;
mba->physBase = monitor_base;
mba->memSize = monitor_size;
gMonitorArgs = (addr_t)mba;
return 0;
}
#endif /* WITH_MONITOR */
+23
View File
@@ -0,0 +1,23 @@
# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
#
# This document is the property of Apple Computer, Inc.
# It is considered confidential and proprietary.
#
# This document may not be reproduced or transmitted in any form,
# in whole or in part, without the express written permission of
# Apple Computer, Inc.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += WITH_MACHO=1
MODULES += \
lib/cksum \
lib/devicetree \
lib/lzss
ALL_OBJS += \
$(LOCAL_DIR)/dt.o \
$(LOCAL_DIR)/kernelcache.o \
$(LOCAL_DIR)/macho.o \
$(LOCAL_DIR)/monitor.o