Loading...
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
*
* Copyright (c) 2017 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/

#ifndef BuilderConfig_hpp
#define BuilderConfig_hpp

#include "Timer.h"
#include "Types.h"

#include <string>

namespace cache_builder
{

constexpr uint64_t operator"" _KB(uint64_t v)
{
    return (1ULL << 10) * v;
}

constexpr uint64_t operator"" _MB(uint64_t v)
{
    return (1ULL << 20) * v;
}

constexpr uint64_t operator"" _GB(uint64_t v)
{
    return (1ULL << 30) * v;
}

constexpr uint64_t operator"" _GB(long double v)
{
    return (1ULL << 30) * v;
}

struct BuilderOptions;

// Layout handles all the different kinds of cache we can build.  They are:
//  - regular contiguous:    The cache is one big file, eg, arm64 simulators
//  - regular discontiguous: The cache is one big file, eg, x86_64 simulators
//  - large contiguous:      The cache is one or more files, which each contain TEXT/DATA/LINKEDIT.  Eg, macOS/iOS/tvOS arm64
//  - large discontiguous:   The cache is one or more files, which each contain TEXT/DATA/LINKEDIT.  Eg, macOS x86_64
struct Layout
{
    Layout(const BuilderOptions& options);

    // Used only for x86_64*
    struct Discontiguous
    {
        // For the host OS, regions should be 1GB aligned
        // If this has a value, then we use it.  Otherwise we fall back to the sim fixed addresses
        std::optional<uint64_t> regionAlignment;

        // How much __TEXT in each subCache before we split to a new file
        CacheVMSize subCacheTextLimit;
    };

    // arm64* layout
    //
    //                                     ┌──────▶┌────────────────────────────┬──────┐
    //                                     │       │                            │      │
    // ┌────────────────────────────┬──────┘       │    __TEXT: Dylib 0 .. n    │      └──────▶┌────────────────────────────┐
    // │                            │              │                            │              │                            │
    // │     2GB __TEXT+__DATA      │              ├────────────────────────────┼──────┐       │ 110MB __TEXT: Dylib 0 .. k │
    // │                            │              │                            │      │       │                            │
    // ├────────────────────────────┼──────┐       │ __DATA_CONST: Dylib 0 .. n │      │       ├────────────────────────────┤
    // │                            │      │       │                            │      │       │                            │
    // │     2GB __TEXT+__DATA      │      │       ├────────────────────────────┤      │       │    Stubs: Dylib 0 .. k     │
    // │                            │      │       │                            │      │       │                            │
    // ├────────────────────────────┤      │       │       Padding: 32MB        │      │       ├────────────────────────────┤
    // │                            │      │       │                            │      │       │                            │
    // │            ...             │      │       ├────────────────────────────┤      │       │     110MB __TEXT: ...      │
    // │                            │      │       │                            │      │       │                            │
    // ├────────────────────────────┤      │       │    __DATA: Dylib 0 .. n    │      │       ├────────────────────────────┤
    // │                            │      │       │                            │      │       │                            │
    // │  __TEXT+__DATA+__LINKEDIT  │      │       ├────────────────────────────┤      │       │         Stubs: ...         │
    // │                            │      │       │                            │      │       │                            │
    // └────────────────────────────┘      │       │ __TPRO_CONST: Dylib 0 .. n │      └──────▶└────────────────────────────┘
    //                                     │       │                            │
    //                                     │       ├────────────────────────────┤
    //                                     │       │                            │
    //                                     │       │    __AUTH: Dylib 0 .. n    │
    //                                     │       │                            │
    //                                     │       ├────────────────────────────┤
    //                                     │       │                            │
    //                                     │       │ __AUTH_CONST: Dylib 0 .. n │
    //                                     │       │                            │
    //                                     │       ├────────────────────────────┤
    //                                     │       │                            │
    //                                     │       │       Padding: 32MB        │
    //                                     │       │                            │
    //                                     │       ├────────────────────────────┤
    //                                     │       │                            │
    //                                     │       │ __READ_ONLY: Dylib 0 .. n  │
    //                                     │       │                            │
    //                                     └──────▶└────────────────────────────┘
    struct Contiguous
    {
        // How many bytes of padding do we add between each Region
        CacheVMSize regionPadding;

        // How much __TEXT + DATA + ... (not LINKEDIT) in each subCache before we split to a new file
        CacheVMSize subCacheTextDataLimit;

        // How much __TEXT before we make a new stubs subCache
        CacheVMSize subCacheStubsLimit;

        // How much padding will we have in every "subCacheTextDataLimit" (2GB) region of memory
        CacheVMSize subCachePadding;
    };

    // Fields for all layouts
    CacheVMAddress          cacheBaseAddress;
    CacheVMSize             cacheSize;
    std::optional<uint64_t> cacheMaxSlide;
    std::optional<uint64_t> cacheFixedSlide;
    const bool              is64;
    const bool              hasAuthRegion;
    const bool              tproIsInData;
    const uint32_t          pageSize;
    const uint32_t          machHeaderAlignment = 4096;

    // Fields only used for discontiguous layouts, ie, x86_64
    std::optional<Discontiguous>    discontiguous;

    // Fields only used for contiguous layouts, ie, arm64*
    std::optional<Contiguous>       contiguous;
};

struct SlideInfo
{
    SlideInfo(const BuilderOptions& options, const Layout& layout);

    enum class SlideInfoFormat
    {
        v1,
        v2,
        v3,
        // v4 (deprecated.  arm64_32 uses v1 instead)
        v5,
    };

    std::optional<SlideInfoFormat>  slideInfoFormat;
    uint32_t                        slideInfoBytesPerDataPage;
    uint32_t                        slideInfoPageSize           = 4096; // 16384 for v5
    CacheVMAddress                  slideInfoValueAdd;
    uint64_t                        slideInfoDeltaMask          = 0;
};

struct CodeSign
{
    CodeSign(const BuilderOptions& options);

    enum class Mode
    {
        onlySHA256,
        onlySHA1,
        agile
    };

    const Mode      mode;
    const uint32_t  pageSize;
};

struct BuilderConfig
{
    BuilderConfig(const BuilderOptions& options);

    Logger      log;
    Timer       timer;
    Layout      layout;
    SlideInfo   slideInfo;
    CodeSign    codeSign;
};

} // namespace cache_builder

#endif /* BuilderConfig_hpp */