Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"

This reverts commit 15b7df8ef1.
This commit is contained in:
souldbminersmwc
2025-11-09 16:14:52 -05:00
parent 22ec140738
commit 21a3f953d7
3804 changed files with 435 additions and 570162 deletions

View File

@@ -1,161 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Some macros taken from https://github.com/ARM-software/arm-trusted-firmware/blob/master/include/common/aarch64/asm_macros.S */
/*
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Declare the exception vector table, enforcing it is aligned on a
* 2KB boundary, as required by the ARMv8 architecture.
* Use zero bytes as the fill value to be stored in the padding bytes
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
.macro vector_base label, section_name=.vectors
.section \section_name, "ax"
.align 11, 0
\label:
.endm
/*
* Create an entry in the exception vector table, enforcing it is
* aligned on a 128-byte boundary, as required by the ARMv8 architecture.
* Use zero bytes as the fill value to be stored in the padding bytes
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
.macro vector_entry label, section_name=.vectors
.cfi_sections .debug_frame
.section \section_name, "ax"
.align 7, 0
.type \label, %function
.func \label
.cfi_startproc
\label:
.endm
/*
* This macro verifies that the given vector doesnt exceed the
* architectural limit of 32 instructions. This is meant to be placed
* immediately after the last instruction in the vector. It takes the
* vector entry as the parameter
*/
.macro check_vector_size since
.endfunc
.cfi_endproc
.if (. - \since) > (32 * 4)
.error "Vector exceeds 32 instructions"
.endif
.endm
/* Actual Vectors for KernelLdr. */
.global kernelldr_vectors
vector_base kernelldr_vectors
/* Current EL, SP0 */
.global unknown_exception
unknown_exception:
vector_entry synch_sp0
/* Just infinite loop. */
b unknown_exception
check_vector_size synch_sp0
vector_entry irq_sp0
b unknown_exception
check_vector_size irq_sp0
vector_entry fiq_sp0
b unknown_exception
check_vector_size fiq_sp0
vector_entry serror_sp0
b unknown_exception
check_vector_size serror_sp0
/* Current EL, SPx */
vector_entry synch_spx
b restore_tpidr_el1
check_vector_size synch_spx
vector_entry irq_spx
b unknown_exception
check_vector_size irq_spx
vector_entry fiq_spx
b unknown_exception
check_vector_size fiq_spx
vector_entry serror_spx
b unknown_exception
check_vector_size serror_spx
/* Lower EL, A64 */
vector_entry synch_a64
b unknown_exception
check_vector_size synch_a64
vector_entry irq_a64
b unknown_exception
check_vector_size irq_a64
vector_entry fiq_a64
b unknown_exception
check_vector_size fiq_a64
vector_entry serror_a64
b unknown_exception
check_vector_size serror_a64
/* Lower EL, A32 */
vector_entry synch_a32
b unknown_exception
check_vector_size synch_a32
vector_entry irq_a32
b unknown_exception
check_vector_size irq_a32
vector_entry fiq_a32
b unknown_exception
check_vector_size fiq_a32
vector_entry serror_a32
b unknown_exception
.endfunc
.cfi_endproc
/* To save space, insert in an unused vector segment. */
.global restore_tpidr_el1
.type restore_tpidr_el1, %function
restore_tpidr_el1:
mrs x0, tpidr_el1
/* Make sure that TPIDR_EL1 can be dereferenced. */
invalid_tpidr:
cbz x0, invalid_tpidr
/* Restore saved registers. */
ldp x19, x20, [x0], #0x10
ldp x21, x22, [x0], #0x10
ldp x23, x24, [x0], #0x10
ldp x25, x26, [x0], #0x10
ldp x27, x28, [x0], #0x10
ldp x29, x30, [x0], #0x10
ldp x1, xzr, [x0], #0x10
mov sp, x1
mov x0, #0x1
ret

View File

@@ -1,48 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
.section .text._ZN3ams4kern4init6loader23SaveRegistersToTpidrEl1EPv, "ax", %progbits
.global _ZN3ams4kern4init6loader23SaveRegistersToTpidrEl1EPv
_ZN3ams4kern4init6loader23SaveRegistersToTpidrEl1EPv:
/* Set TPIDR_EL1 to the input register. */
msr tpidr_el1, x0
/* Save registers to the region specified. */
mov x1, sp
stp x19, x20, [x0], #0x10
stp x21, x22, [x0], #0x10
stp x23, x24, [x0], #0x10
stp x25, x26, [x0], #0x10
stp x27, x28, [x0], #0x10
stp x29, x30, [x0], #0x10
stp x1, xzr, [x0], #0x10
mov x0, #0x0
ret
.section .text._ZN3ams4kern4init6loader22VerifyAndClearTpidrEl1EPv, "ax", %progbits
.global _ZN3ams4kern4init6loader22VerifyAndClearTpidrEl1EPv
_ZN3ams4kern4init6loader22VerifyAndClearTpidrEl1EPv:
/* Get system register area from thread-specific processor id */
mrs x1, tpidr_el1
/* We require here that the region registers are saved is same as input. */
cmp x0, x1
invalid_tpidr:
b.ne invalid_tpidr
/* Clear TPIDR_EL1. */
msr tpidr_el1, xzr
ret

View File

@@ -1,160 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
#define cpuactlr_el1 s3_1_c15_c2_0
#define cpuectlr_el1 s3_1_c15_c2_1
#define LOAD_IMMEDIATE_32(reg, val) \
mov reg, #(((val) >> 0x00) & 0xFFFF); \
movk reg, #(((val) >> 0x10) & 0xFFFF), lsl#16
.section .crt0.text.start, "ax", %progbits
.global _start
_start:
b _main
__metadata_begin:
.ascii "MLD0" /* Magic */
__metadata_target_firmware:
.word 0xCCCCCCCC /* Target Firmware. */
__metadata_reserved:
.word 0xCCCCCCCC /* Reserved. */
_main:
/* KernelLdr_Main(uintptr_t kernel_base_address, KernelMap *kernel_map, uintptr_t ini1_base_address); */
adr x18, _start
adr x16, __external_references
ldr x17, [x16, #0x8] /* bss end */
ldr x16, [x16, #0x0] /* bss start */
add x16, x16, x18
add x17, x17, x18
clear_bss:
cmp x16, x17
b.cs clear_bss_done
str xzr, [x16],#0x8
b clear_bss
clear_bss_done:
adr x17, __external_references
ldr x17, [x17, #0x10] /* stack top */
add sp, x17, x18
/* Stack is now set up, so save important state. */
sub sp, sp, #0x30
stp x0, x1, [sp, #0x00]
stp x2, x30, [sp, #0x10]
stp xzr, xzr, [sp, #0x20]
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
/* Get the target firmware from exosphere. */
LOAD_IMMEDIATE_32(w0, 0xC3000004)
mov w1, #65000
smc #1
cmp x0, #0
0:
b.ne 0b
/* Store the target firmware. */
adr x0, __metadata_target_firmware
str w1, [x0]
#endif
/* Apply relocations and call init array for KernelLdr. */
adr x0, _start
adr x1, __external_references
ldr x1, [x1, #0x18] /* .dynamic. */
add x1, x0, x1
/* branch to ams::kern::init::Elf::ApplyRelocations(uintptr_t, const ams::kern::init::Elf::Elf64::Dyn *); */
bl _ZN3ams4kern4init3Elf16ApplyRelocationsEmPKNS2_5Elf643DynE
/* branch to ams::kern::init::Elf::CallInitArrayFuncs(uintptr_t, uintptr_t) */
adr x2, _start
adr x1, __external_references
ldr x0, [x1, #0x20] /* init_array_start */
ldr x1, [x1, #0x28] /* init_array_end */
add x0, x0, x2
add x1, x1, x2
bl _ZN3ams4kern4init3Elf18CallInitArrayFuncsEmm
/* Setup system registers, for detection of errors during init later. */
msr tpidr_el1, xzr
msr cntv_cval_el0, xzr
adr x0, __external_references
adr x1, _start
ldr x0, [x0, #0x30]
add x0, x1, x0
msr vbar_el1, x0
isb
/* Call ams::kern::init::loader::Main(uintptr_t, ams::kern::init::KernelLayout *, uintptr_t) */
ldp x0, x1, [sp, #0x00]
ldr x2, [sp, #0x10]
bl _ZN3ams4kern4init6loader4MainEmPNS1_12KernelLayoutEm
str x0, [sp, #0x00]
/* Get ams::kern::init::loader::AllocateKernelInitStack(). */
bl _ZN3ams4kern4init6loader23AllocateKernelInitStackEv
str x0, [sp, #0x20]
/* Call ams::kern::init::loader::GetFinalState() */
bl _ZN3ams4kern4init6loader13GetFinalStateEv
/* X0 is now the saved state. */
/* We will return this to the kernel. */
/* Adjust return address to point to the relocated kernel. */
ldr x1, [sp, #0x18] /* Return address to Kernel */
ldr x2, [sp, #0x00] /* Relocated kernel base address diff. */
add x1, x2, x1
/* Translate the relocated address back to a physical address. */
and x4, x1, #0xFFF
sub x3, x1, x4
at s1e1r, x3
isb
mrs x3, par_el1
1:
tbnz w3, #0, 1b
and x3, x3, #0xFFFFFFFFF000
add x3, x3, x4
/* Return the difference between relocated and physical in x1. */
sub x1, x1, x3
/* Setup stack, and return to the kernel. */
ldr x2, [sp, #0x20]
mov sp, x2
br x3
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
.global _ZN3ams4kern17GetTargetFirmwareEv
.type _ZN3ams4kern17GetTargetFirmwareEv, %function
_ZN3ams4kern17GetTargetFirmwareEv:
adr x0, __metadata_target_firmware
ldr w0, [x0]
ret
#endif
.balign 8
__external_references:
.quad __bss_start__ - _start
.quad __bss_end__ - _start
.quad __stack_end - _start
.quad _DYNAMIC - _start
.quad __init_array_start - _start
.quad __init_array_end - _start
.quad __vectors_start__ - _start

View File

@@ -1,25 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere.hpp>
#include "../../../kern_init_loader_board_setup.hpp"
namespace ams::kern::init::loader {
void PerformBoardSpecificSetup() {
/* ... */
}
}

View File

@@ -1,295 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere.hpp>
#include "kern_init_loader_board_setup.hpp"
/* Necessary for calculating kernelldr size/base for initial identity mapping */
extern "C" {
extern const u8 __bin_start__[];
extern const u8 __bin_end__[];
}
namespace ams::kern::init::loader {
namespace {
constexpr uintptr_t KernelBaseAlignment = 0x200000;
constexpr uintptr_t KernelBaseRangeStart = 0xFFFFFF8000000000;
constexpr uintptr_t KernelBaseRangeEnd = 0xFFFFFFFFFFE00000;
constexpr uintptr_t KernelBaseRangeLast = KernelBaseRangeEnd - 1;
static_assert(util::IsAligned(KernelBaseRangeStart, KernelBaseAlignment));
static_assert(util::IsAligned(KernelBaseRangeEnd, KernelBaseAlignment));
static_assert(KernelBaseRangeStart <= KernelBaseRangeLast);
static_assert(InitialProcessBinarySizeMax <= KernelResourceSize);
constexpr size_t InitialPageTableRegionSizeMax = 2_MB;
static_assert(InitialPageTableRegionSizeMax < KernelPageTableHeapSize + KernelInitialPageHeapSize);
/* Global Allocator. */
constinit KInitialPageAllocator g_initial_page_allocator;
constinit KInitialPageAllocator::State g_final_page_allocator_state;
constinit InitialProcessBinaryLayoutWithSize g_initial_process_binary_meta;
constinit void *g_final_state[2];
void RelocateKernelPhysically(uintptr_t &base_address, KernelLayout *&layout, const uintptr_t &ini_base_address) {
/* Adjust layout to be correct. */
{
const ptrdiff_t layout_offset = reinterpret_cast<uintptr_t>(layout) - base_address;
layout->rx_offset += layout_offset;
layout->rx_end_offset += layout_offset;
layout->ro_offset += layout_offset;
layout->ro_end_offset += layout_offset;
layout->rw_offset += layout_offset;
layout->rw_end_offset += layout_offset;
layout->bss_offset += layout_offset;
layout->bss_end_offset += layout_offset;
layout->resource_offset += layout_offset;
layout->dynamic_offset += layout_offset;
layout->init_array_offset += layout_offset;
layout->init_array_end_offset += layout_offset;
layout->sysreg_offset += layout_offset;
}
/* Relocate the kernel if necessary. */
KPhysicalAddress correct_base = KSystemControl::Init::GetKernelPhysicalBaseAddress(base_address);
if (correct_base != base_address) {
const uintptr_t diff = GetInteger(correct_base) - base_address;
const size_t size = layout->rw_end_offset;
/* Check that the new kernel doesn't overlap with us. */
MESOSPHERE_INIT_ABORT_UNLESS((GetInteger(correct_base) >= reinterpret_cast<uintptr_t>(__bin_end__)) || (GetInteger(correct_base) + size <= reinterpret_cast<uintptr_t>(__bin_start__)));
/* Check that the new kernel doesn't overlap with the initial process binary. */
MESOSPHERE_INIT_ABORT_UNLESS((ini_base_address + InitialProcessBinarySizeMax <= GetInteger(correct_base)) || (GetInteger(correct_base) + size <= ini_base_address));
/* Conversion from KPhysicalAddress to void * is safe here, because MMU is not set up yet. */
std::memmove(reinterpret_cast<void *>(GetInteger(correct_base)), reinterpret_cast<void *>(base_address), size);
base_address += diff;
layout = reinterpret_cast<KernelLayout *>(reinterpret_cast<uintptr_t>(layout) + diff);
}
}
void SetupInitialIdentityMapping(KInitialPageTable &init_pt, uintptr_t base_address, uintptr_t kernel_size, uintptr_t page_table_region, size_t page_table_region_size, KInitialPageAllocator &allocator, KernelSystemRegisters *sysregs) {
/* Map in an RWX identity mapping for the kernel. */
constexpr PageTableEntry KernelRWXIdentityAttribute(PageTableEntry::Permission_KernelRWX, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
init_pt.Map(base_address, kernel_size, base_address, KernelRWXIdentityAttribute, allocator, 0);
/* Map in an RWX identity mapping for ourselves. */
constexpr PageTableEntry KernelLdrRWXIdentityAttribute(PageTableEntry::Permission_KernelRWX, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
const uintptr_t kernel_ldr_base = util::AlignDown(reinterpret_cast<uintptr_t>(__bin_start__), PageSize);
const uintptr_t kernel_ldr_size = util::AlignUp(reinterpret_cast<uintptr_t>(__bin_end__), PageSize) - kernel_ldr_base;
init_pt.Map(kernel_ldr_base, kernel_ldr_size, kernel_ldr_base, KernelLdrRWXIdentityAttribute, allocator, 0);
/* Map in the page table region as RW- for ourselves. */
constexpr PageTableEntry PageTableRegionRWAttribute(PageTableEntry::Permission_KernelRW, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
init_pt.Map(page_table_region, page_table_region_size, page_table_region, PageTableRegionRWAttribute, allocator, 0);
/* Place the L1 table addresses in the relevant system registers. */
cpu::SetTtbr0El1(init_pt.GetTtbr0L1TableAddress());
cpu::SetTtbr1El1(init_pt.GetTtbr1L1TableAddress());
/* Setup MAIR_EL1, TCR_EL1. */
/* TODO: Define these bits properly elsewhere, document exactly what each bit set is doing .*/
constexpr u64 MairValue = 0x0000000044FF0400ul;
constexpr u64 TcrValue = 0x00000011B5193519ul;
cpu::MemoryAccessIndirectionRegisterAccessor(MairValue).Store();
cpu::TranslationControlRegisterAccessor(TcrValue).Store();
/* Ensure that our configuration takes before proceeding. */
cpu::EnsureInstructionConsistency();
/* Perform board-specific setup. */
PerformBoardSpecificSetup();
/* Setup SCTLR_EL1. */
/* TODO: Define these bits properly elsewhere, document exactly what each bit set is doing .*/
constexpr u64 SctlrValue = 0x0000000034D5D92Dul;
cpu::SetSctlrEl1(SctlrValue);
cpu::InstructionMemoryBarrier();
/* Setup the system registers for other cores. */
/* NOTE: sctlr_el1 on other cores has the WXN bit set (0x80000); this will be set before KernelMain() on this core. */
sysregs->ttbr0_el1 = init_pt.GetTtbr0L1TableAddress();
sysregs->ttbr1_el1 = init_pt.GetTtbr1L1TableAddress();
sysregs->tcr_el1 = TcrValue;
sysregs->mair_el1 = MairValue;
sysregs->sctlr_el1 = SctlrValue | 0x80000;
}
KVirtualAddress GetRandomKernelBaseAddress(KInitialPageTable &page_table, KPhysicalAddress phys_base_address, size_t kernel_size) {
/* Define useful values for random generation. */
const uintptr_t kernel_offset = GetInteger(phys_base_address) % KernelBaseAlignment;
/* Repeatedly generate a random virtual address until we get one that's unmapped in the destination page table. */
while (true) {
const uintptr_t random_kaslr_slide = KSystemControl::Init::GenerateRandomRange(KernelBaseRangeStart / KernelBaseAlignment, KernelBaseRangeLast / KernelBaseAlignment);
const KVirtualAddress kernel_region_start = random_kaslr_slide * KernelBaseAlignment;
const KVirtualAddress kernel_region_end = kernel_region_start + util::AlignUp(kernel_offset + kernel_size, KernelBaseAlignment);
const size_t kernel_region_size = GetInteger(kernel_region_end) - GetInteger(kernel_region_start);
/* Make sure the region has not overflowed */
if (kernel_region_start >= kernel_region_end) {
continue;
}
/* Make sure that the region stays within our intended bounds. */
if (kernel_region_end > KernelBaseRangeEnd) {
continue;
}
/* Validate we can map the range we've selected. */
if (!page_table.IsFree(kernel_region_start, kernel_region_size)) {
continue;
}
/* Our range is valid! */
return kernel_region_start + kernel_offset;
}
}
}
uintptr_t Main(uintptr_t base_address, KernelLayout *layout, uintptr_t ini_base_address) {
/* Relocate the kernel to the correct physical base address. */
/* Base address and layout are passed by reference and modified. */
RelocateKernelPhysically(base_address, layout, ini_base_address);
/* Validate kernel layout. */
const uintptr_t rx_offset = layout->rx_offset;
const uintptr_t rx_end_offset = layout->rx_end_offset;
const uintptr_t ro_offset = layout->ro_offset;
const uintptr_t ro_end_offset = layout->ro_end_offset;
const uintptr_t rw_offset = layout->rw_offset;
/* UNUSED: const uintptr_t rw_end_offset = layout->rw_end_offset; */
const uintptr_t bss_end_offset = layout->bss_end_offset;
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(rx_offset, PageSize));
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(rx_end_offset, PageSize));
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(ro_offset, PageSize));
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(ro_end_offset, PageSize));
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(rw_offset, PageSize));
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(bss_end_offset, PageSize));
const uintptr_t bss_offset = layout->bss_offset;
const uintptr_t resource_offset = layout->resource_offset;
const uintptr_t dynamic_offset = layout->dynamic_offset;
const uintptr_t init_array_offset = layout->init_array_offset;
const uintptr_t init_array_end_offset = layout->init_array_end_offset;
const uintptr_t sysreg_offset = layout->sysreg_offset;
/* Determine the size of the resource region. */
const size_t resource_region_size = KMemoryLayout::GetResourceRegionSizeForInit(KSystemControl::Init::ShouldIncreaseThreadResourceLimit());
const uintptr_t resource_end_address = base_address + resource_offset + resource_region_size;
/* Setup the INI1 header in memory for the kernel. */
{
/* Get the kernel layout. */
KSystemControl::Init::GetInitialProcessBinaryLayout(std::addressof(g_initial_process_binary_meta.layout), base_address);
/* If there's no desired base address, use the ini in place. */
if (g_initial_process_binary_meta.layout.address == 0) {
g_initial_process_binary_meta.layout.address = ini_base_address;
}
/* Validate and potentially relocate the INI. */
const InitialProcessBinaryHeader *ini_header = reinterpret_cast<const InitialProcessBinaryHeader *>(ini_base_address);
size_t ini_size = 0;
if (ini_header->magic == InitialProcessBinaryMagic && (ini_size = ini_header->size) <= InitialProcessBinarySizeMax) {
/* INI is valid, relocate it if necessary. */
if (ini_base_address != g_initial_process_binary_meta.layout.address) {
std::memmove(reinterpret_cast<void *>(g_initial_process_binary_meta.layout.address), ini_header, ini_size);
}
} else {
/* INI is invalid. Make the destination header invalid. */
std::memset(reinterpret_cast<void *>(g_initial_process_binary_meta.layout.address), 0, sizeof(InitialProcessBinaryHeader));
}
/* Set the INI size in layout. */
g_initial_process_binary_meta.size = util::AlignUp(ini_size, PageSize);
}
/* We want to start allocating page tables at the end of the resource region. */
g_initial_page_allocator.Initialize(resource_end_address);
/* Make a new page table for TTBR1_EL1. */
KInitialPageTable init_pt(KernelBaseRangeStart, KernelBaseRangeLast, g_initial_page_allocator);
/* Setup initial identity mapping. TTBR1 table passed by reference. */
SetupInitialIdentityMapping(init_pt, base_address, bss_end_offset, resource_end_address, InitialPageTableRegionSizeMax, g_initial_page_allocator, reinterpret_cast<KernelSystemRegisters *>(base_address + sysreg_offset));
/* NOTE: On 19.0.0+, Nintendo calls an unknown function here on init_pt and g_initial_page_allocator. */
/* This is stubbed in prod KernelLdr. */
/* Generate a random slide for the kernel's base address. */
const KVirtualAddress virtual_base_address = GetRandomKernelBaseAddress(init_pt, base_address, bss_end_offset);
/* Map kernel .text as R-X. */
constexpr PageTableEntry KernelTextAttribute(PageTableEntry::Permission_KernelRX, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
init_pt.Map(virtual_base_address + rx_offset, rx_end_offset - rx_offset, base_address + rx_offset, KernelTextAttribute, g_initial_page_allocator, 0);
/* Map kernel .rodata and .rwdata as RW-. */
/* Note that we will later reprotect .rodata as R-- */
constexpr PageTableEntry KernelRoDataAttribute(PageTableEntry::Permission_KernelR, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
constexpr PageTableEntry KernelRwDataAttribute(PageTableEntry::Permission_KernelRW, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
init_pt.Map(virtual_base_address + ro_offset, ro_end_offset - ro_offset, base_address + ro_offset, KernelRwDataAttribute, g_initial_page_allocator, 0);
init_pt.Map(virtual_base_address + rw_offset, bss_end_offset - rw_offset, base_address + rw_offset, KernelRwDataAttribute, g_initial_page_allocator, 0);
/* Physically randomize the kernel region. */
/* NOTE: Nintendo does this only on 10.0.0+ */
init_pt.PhysicallyRandomize(virtual_base_address + rx_offset, bss_end_offset - rx_offset, true);
/* Apply relocations to the kernel. */
const Elf::Dyn *kernel_dynamic = reinterpret_cast<const Elf::Dyn *>(GetInteger(virtual_base_address) + dynamic_offset);
Elf::ApplyRelocations(GetInteger(virtual_base_address), kernel_dynamic);
/* Clear kernel .bss. */
/* NOTE: The kernel does this before applying relocations, but we do it after. */
/* This allows us to place our relocations in space overlapping with .bss...and thereby reclaim the memory that would otherwise be wasted. */
std::memset(GetVoidPointer(virtual_base_address + bss_offset), 0, bss_end_offset - bss_offset);
/* Call the kernel's init array functions. */
/* NOTE: The kernel does this after reprotecting .rodata, but we do it before. */
/* This allows our global constructors to edit .rodata, which is valuable for editing the SVC tables to support older firmwares' ABIs. */
Elf::CallInitArrayFuncs(GetInteger(virtual_base_address) + init_array_offset, GetInteger(virtual_base_address) + init_array_end_offset);
/* Reprotect .rodata as R-- */
init_pt.Reprotect(virtual_base_address + ro_offset, ro_end_offset - ro_offset, KernelRwDataAttribute, KernelRoDataAttribute);
/* Return the difference between the random virtual base and the physical base. */
return GetInteger(virtual_base_address) - base_address;
}
KPhysicalAddress AllocateKernelInitStack() {
return g_initial_page_allocator.Allocate(PageSize) + PageSize;
}
void **GetFinalState() {
/* Get final page allocator state. */
g_initial_page_allocator.GetFinalState(std::addressof(g_final_page_allocator_state));
/* Setup final kernel loader state. */
g_final_state[0] = std::addressof(g_final_page_allocator_state);
g_final_state[1] = std::addressof(g_initial_process_binary_meta);
return g_final_state;
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere.hpp>
namespace ams::kern::init::loader {
struct SavedRegisterState {
u64 x[(30 - 19) + 1];
u64 sp;
u64 xzr;
};
static_assert(sizeof(SavedRegisterState) == 0x70);
int SaveRegistersToTpidrEl1(void *tpidr_el1);
void VerifyAndClearTpidrEl1(void *tpidr_el1);
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere.hpp>
#include "kern_init_loader_asm.hpp"
#include "kern_init_loader_board_setup.hpp"
namespace ams::kern::init::loader {
void PerformDefaultAarch64SpecificSetup() {
SavedRegisterState saved_registers;
SaveRegistersToTpidrEl1(std::addressof(saved_registers));
ON_SCOPE_EXIT { VerifyAndClearTpidrEl1(std::addressof(saved_registers)); };
/* Main ID specific setup. */
cpu::MainIdRegisterAccessor midr_el1;
if (midr_el1.GetImplementer() == cpu::MainIdRegisterAccessor::Implementer::ArmLimited) {
/* ARM limited specific setup. */
const auto cpu_primary_part = midr_el1.GetPrimaryPartNumber();
const auto cpu_variant = midr_el1.GetVariant();
const auto cpu_revision = midr_el1.GetRevision();
if (cpu_primary_part == cpu::MainIdRegisterAccessor::PrimaryPartNumber::CortexA57) {
/* Cortex-A57 specific setup. */
/* Non-cacheable load forwarding enabled. */
u64 cpuactlr_value = 0x1000000;
/* Enable the processor to receive instruction cache and TLB maintenance */
/* operations broadcast from other processors in the cluster; */
/* set the L2 load/store data prefetch distance to 8 requests; */
/* set the L2 instruction fetch prefetch distance to 3 requests. */
u64 cpuectlr_value = 0x1B00000040;
/* Disable load-pass DMB on certain hardware variants. */
if (cpu_variant == 0 || (cpu_variant == 1 && cpu_revision <= 1)) {
cpuactlr_value |= 0x800000000000000;
}
/* Set actlr and ectlr. */
if (cpu::GetCpuActlrEl1() != cpuactlr_value) {
cpu::SetCpuActlrEl1(cpuactlr_value);
}
if (cpu::GetCpuEctlrEl1() != cpuectlr_value) {
cpu::SetCpuEctlrEl1(cpuectlr_value);
}
} else if (cpu_primary_part == cpu::MainIdRegisterAccessor::PrimaryPartNumber::CortexA53) {
/* Cortex-A53 specific setup. */
/* Set L1 data prefetch control to allow 5 outstanding prefetches; */
/* enable device split throttle; */
/* set the number of independent data prefetch streams to 2; */
/* disable transient and no-read-allocate hints for loads; */
/* set write streaming no-allocate threshold so the 128th consecutive streaming */
/* cache line does not allocate in the L1 or L2 cache. */
u64 cpuactlr_value = 0x90CA000;
/* Enable hardware management of data coherency with other cores in the cluster. */
u64 cpuectlr_value = 0x40;
/* If supported, enable data cache clean as data cache clean/invalidate. */
if (cpu_variant != 0 || (cpu_variant == 0 && cpu_revision > 2)) {
cpuactlr_value |= 0x100000000000;
}
/* Set actlr and ectlr. */
if (cpu::GetCpuActlrEl1() != cpuactlr_value) {
cpu::SetCpuActlrEl1(cpuactlr_value);
}
if (cpu::GetCpuEctlrEl1() != cpuectlr_value) {
cpu::SetCpuEctlrEl1(cpuectlr_value);
}
}
}
}
/* This is a default implementation, which should be overridden in a source file in board/ */
WEAK_SYMBOL void PerformBoardSpecificSetup() {
return PerformDefaultAarch64SpecificSetup();
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere.hpp>
namespace ams::kern::init::loader {
#if defined(ATMOSPHERE_ARCH_ARM64)
void PerformDefaultAarch64SpecificSetup();
#endif
void PerformBoardSpecificSetup();
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere.hpp>
namespace ams::kern {
/* This overrides the panic implementation from the kernel, to prevent linking debug print into kldr. */
NORETURN void PanicImpl(const char *file, int line, const char *format, ...) {
MESOSPHERE_UNUSED(file, line, format);
MESOSPHERE_INIT_ABORT();
}
NORETURN void PanicImpl() {
MESOSPHERE_INIT_ABORT();
}
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
/* Definitions for libc genericity. */
#define MESOSPHERE_LIBC_MEMCPY_GENERIC 1
#define MESOSPHERE_LIBC_MEMCMP_GENERIC 1
#define MESOSPHERE_LIBC_MEMMOVE_GENERIC 1
#define MESOSPHERE_LIBC_MEMSET_GENERIC 1
#define MESOSPHERE_LIBC_STRNCPY_GENERIC 1
#define MESOSPHERE_LIBC_STRNCMP_GENERIC 1

View File

@@ -1,26 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if defined(ATMOSPHERE_ARCH_ARM64)
#include "kern_libc_config.arch.arm64.h"
#else
#error "Unknown architecture for libc"
#endif

View File

@@ -1,673 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stddef.h>
#include <limits.h>
#include "kern_libc_config.h"
/* Note: copied from newlib */
#ifdef __cplusplus
extern "C" {
#endif
/*
FUNCTION
<<memmove>>---move possibly overlapping memory
INDEX
memmove
SYNOPSIS
#include <string.h>
void *memmove(void *<[dst]>, const void *<[src]>, size_t <[length]>);
DESCRIPTION
This function moves <[length]> characters from the block of
memory starting at <<*<[src]>>> to the memory starting at
<<*<[dst]>>>. <<memmove>> reproduces the characters correctly
at <<*<[dst]>>> even if the two areas overlap.
RETURNS
The function returns <[dst]> as passed.
PORTABILITY
<<memmove>> is ANSI C.
<<memmove>> requires no supporting OS subroutines.
QUICKREF
memmove ansi pure
*/
/* Nonzero if either X or Y is not aligned on a "long" boundary. */
#define UNALIGNED(X, Y) \
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
/* How many bytes are copied each iteration of the 4X unrolled loop. */
#define BIGBLOCKSIZE (sizeof (long) << 2)
/* How many bytes are copied each iteration of the word copy loop. */
#define LITTLEBLOCKSIZE (sizeof (long))
/* Threshhold for punting to the byte copier. */
#undef TOO_SMALL
#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
#if MESOSPHERE_LIBC_MEMMOVE_GENERIC
/*SUPPRESS 20*/
void *
//__inhibit_loop_to_libcall
__attribute__((weak))
memmove (void *dst_void,
const void *src_void,
size_t length)
{
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
char *dst = dst_void;
const char *src = src_void;
if (src < dst && dst < src + length)
{
/* Have to copy backwards */
src += length;
dst += length;
while (length--)
{
*--dst = *--src;
}
}
else
{
while (length--)
{
*dst++ = *src++;
}
}
return dst_void;
#else
char *dst = dst_void;
const char *src = src_void;
long *aligned_dst;
const long *aligned_src;
if (src < dst && dst < src + length)
{
/* Destructive overlap...have to copy backwards */
src += length;
dst += length;
while (length--)
{
*--dst = *--src;
}
}
else
{
/* Use optimizing algorithm for a non-destructive copy to closely
match memcpy. If the size is small or either SRC or DST is unaligned,
then punt into the byte copy loop. This should be rare. */
if (!TOO_SMALL(length) && !UNALIGNED (src, dst))
{
aligned_dst = (long*)dst;
aligned_src = (long*)src;
/* Copy 4X long words at a time if possible. */
while (length >= BIGBLOCKSIZE)
{
*aligned_dst++ = *aligned_src++;
*aligned_dst++ = *aligned_src++;
*aligned_dst++ = *aligned_src++;
*aligned_dst++ = *aligned_src++;
length -= BIGBLOCKSIZE;
}
/* Copy one long word at a time if possible. */
while (length >= LITTLEBLOCKSIZE)
{
*aligned_dst++ = *aligned_src++;
length -= LITTLEBLOCKSIZE;
}
/* Pick up any residual with a byte copier. */
dst = (char*)aligned_dst;
src = (char*)aligned_src;
}
while (length--)
{
*dst++ = *src++;
}
}
return dst_void;
#endif /* not PREFER_SIZE_OVER_SPEED */
}
#endif /* MESOSPHERE_LIBC_MEMMOVE_GENERIC */
/*
FUNCTION
<<memcpy>>---copy memory regions
SYNOPSIS
#include <string.h>
void* memcpy(void *restrict <[out]>, const void *restrict <[in]>,
size_t <[n]>);
DESCRIPTION
This function copies <[n]> bytes from the memory region
pointed to by <[in]> to the memory region pointed to by
<[out]>.
If the regions overlap, the behavior is undefined.
RETURNS
<<memcpy>> returns a pointer to the first byte of the <[out]>
region.
PORTABILITY
<<memcpy>> is ANSI C.
<<memcpy>> requires no supporting OS subroutines.
QUICKREF
memcpy ansi pure
*/
#if MESOSPHERE_LIBC_MEMCPY_GENERIC
void *
__attribute__((weak))
memcpy (void * dst0,
const void * __restrict src0,
size_t len0)
{
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
char *dst = (char *) dst0;
char *src = (char *) src0;
void *save = dst0;
while (len0--)
{
*dst++ = *src++;
}
return save;
#else
char *dst = dst0;
const char *src = src0;
long *aligned_dst;
const long *aligned_src;
/* If the size is small, or either SRC or DST is unaligned,
then punt into the byte copy loop. This should be rare. */
if (!TOO_SMALL(len0) && !UNALIGNED (src, dst))
{
aligned_dst = (long*)dst;
aligned_src = (long*)src;
/* Copy 4X long words at a time if possible. */
while (len0 >= BIGBLOCKSIZE)
{
*aligned_dst++ = *aligned_src++;
*aligned_dst++ = *aligned_src++;
*aligned_dst++ = *aligned_src++;
*aligned_dst++ = *aligned_src++;
len0 -= BIGBLOCKSIZE;
}
/* Copy one long word at a time if possible. */
while (len0 >= LITTLEBLOCKSIZE)
{
*aligned_dst++ = *aligned_src++;
len0 -= LITTLEBLOCKSIZE;
}
/* Pick up any residual with a byte copier. */
dst = (char*)aligned_dst;
src = (char*)aligned_src;
}
while (len0--)
*dst++ = *src++;
return dst0;
#endif /* not PREFER_SIZE_OVER_SPEED */
}
#endif /* MESOSPHERE_LIBC_MEMCPY_GENERIC */
/*
FUNCTION
<<memset>>---set an area of memory
INDEX
memset
SYNOPSIS
#include <string.h>
void *memset(void *<[dst]>, int <[c]>, size_t <[length]>);
DESCRIPTION
This function converts the argument <[c]> into an unsigned
char and fills the first <[length]> characters of the array
pointed to by <[dst]> to the value.
RETURNS
<<memset>> returns the value of <[dst]>.
PORTABILITY
<<memset>> is ANSI C.
<<memset>> requires no supporting OS subroutines.
QUICKREF
memset ansi pure
*/
#include <string.h>
#undef LBLOCKSIZE
#undef UNALIGNED
#undef TOO_SMALL
#define LBLOCKSIZE (sizeof(long))
#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1))
#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
#if MESOSPHERE_LIBC_MEMSET_GENERIC
void *
__attribute__((weak))
memset (void *m,
int c,
size_t n)
{
char *s = (char *) m;
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
unsigned int i;
unsigned long buffer;
unsigned long *aligned_addr;
unsigned int d = c & 0xff; /* To avoid sign extension, copy C to an
unsigned variable. */
while (UNALIGNED (s))
{
if (n--)
*s++ = (char) c;
else
return m;
}
if (!TOO_SMALL (n))
{
/* If we get this far, we know that n is large and s is word-aligned. */
aligned_addr = (unsigned long *) s;
/* Store D into each char sized location in BUFFER so that
we can set large blocks quickly. */
buffer = (d << 8) | d;
buffer |= (buffer << 16);
for (i = 32; i < LBLOCKSIZE * 8; i <<= 1)
buffer = (buffer << i) | buffer;
/* Unroll the loop. */
while (n >= LBLOCKSIZE*4)
{
*aligned_addr++ = buffer;
*aligned_addr++ = buffer;
*aligned_addr++ = buffer;
*aligned_addr++ = buffer;
n -= 4*LBLOCKSIZE;
}
while (n >= LBLOCKSIZE)
{
*aligned_addr++ = buffer;
n -= LBLOCKSIZE;
}
/* Pick up the remainder with a bytewise loop. */
s = (char*)aligned_addr;
}
#endif /* not PREFER_SIZE_OVER_SPEED */
while (n--)
*s++ = (char) c;
return m;
}
#endif /* MESOSPHERE_LIBC_MEMSET_GENERIC */
/*
FUNCTION
<<memcmp>>---compare two memory areas
INDEX
memcmp
SYNOPSIS
#include <string.h>
int memcmp(const void *<[s1]>, const void *<[s2]>, size_t <[n]>);
DESCRIPTION
This function compares not more than <[n]> characters of the
object pointed to by <[s1]> with the object pointed to by <[s2]>.
RETURNS
The function returns an integer greater than, equal to or
less than zero according to whether the object pointed to by
<[s1]> is greater than, equal to or less than the object
pointed to by <[s2]>.
PORTABILITY
<<memcmp>> is ANSI C.
<<memcmp>> requires no supporting OS subroutines.
QUICKREF
memcmp ansi pure
*/
#undef LBLOCKSIZE
#undef UNALIGNED
#undef TOO_SMALL
/* Nonzero if either X or Y is not aligned on a "long" boundary. */
#define UNALIGNED(X, Y) \
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
/* How many bytes are copied each iteration of the word copy loop. */
#define LBLOCKSIZE (sizeof (long))
/* Threshhold for punting to the byte copier. */
#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
#if MESOSPHERE_LIBC_MEMCMP_GENERIC
int
__attribute__((weak))
memcmp (const void *m1,
const void *m2,
size_t n)
{
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
unsigned char *s1 = (unsigned char *) m1;
unsigned char *s2 = (unsigned char *) m2;
while (n--)
{
if (*s1 != *s2)
{
return *s1 - *s2;
}
s1++;
s2++;
}
return 0;
#else
unsigned char *s1 = (unsigned char *) m1;
unsigned char *s2 = (unsigned char *) m2;
unsigned long *a1;
unsigned long *a2;
/* If the size is too small, or either pointer is unaligned,
then we punt to the byte compare loop. Hopefully this will
not turn up in inner loops. */
if (!TOO_SMALL(n) && !UNALIGNED(s1,s2))
{
/* Otherwise, load and compare the blocks of memory one
word at a time. */
a1 = (unsigned long*) s1;
a2 = (unsigned long*) s2;
while (n >= LBLOCKSIZE)
{
if (*a1 != *a2)
break;
a1++;
a2++;
n -= LBLOCKSIZE;
}
/* check m mod LBLOCKSIZE remaining characters */
s1 = (unsigned char*)a1;
s2 = (unsigned char*)a2;
}
while (n--)
{
if (*s1 != *s2)
return *s1 - *s2;
s1++;
s2++;
}
return 0;
#endif /* not PREFER_SIZE_OVER_SPEED */
}
#endif /* MESOSPHERE_LIBC_MEMCMP_GENERIC */
/*
FUNCTION
<<strncpy>>---counted copy string
INDEX
strncpy
SYNOPSIS
#include <string.h>
char *strncpy(char *restrict <[dst]>, const char *restrict <[src]>,
size_t <[length]>);
DESCRIPTION
<<strncpy>> copies not more than <[length]> characters from the
the string pointed to by <[src]> (including the terminating
null character) to the array pointed to by <[dst]>. If the
string pointed to by <[src]> is shorter than <[length]>
characters, null characters are appended to the destination
array until a total of <[length]> characters have been
written.
RETURNS
This function returns the initial value of <[dst]>.
PORTABILITY
<<strncpy>> is ANSI C.
<<strncpy>> requires no supporting OS subroutines.
QUICKREF
strncpy ansi pure
*/
#include <string.h>
#include <limits.h>
/*SUPPRESS 560*/
/*SUPPRESS 530*/
/* Nonzero if either X or Y is not aligned on a "long" boundary. */
#define UNALIGNED(X, Y) \
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
#if LONG_MAX == 2147483647L
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
#else
#if LONG_MAX == 9223372036854775807L
/* Nonzero if X (a long int) contains a NULL byte. */
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
#else
#error long int is not a 32bit or 64bit type.
#endif
#endif
#ifndef DETECTNULL
#error long int is not a 32bit or 64bit byte
#endif
#undef TOO_SMALL
#define TOO_SMALL(LEN) ((LEN) < sizeof (long))
#if MESOSPHERE_LIBC_STRNCMP_GENERIC
char *
strncpy (char *__restrict dst0,
const char *__restrict src0,
size_t count)
{
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
char *dscan;
const char *sscan;
dscan = dst0;
sscan = src0;
while (count > 0)
{
--count;
if ((*dscan++ = *sscan++) == '\0')
break;
}
while (count-- > 0)
*dscan++ = '\0';
return dst0;
#else
char *dst = dst0;
const char *src = src0;
long *aligned_dst;
const long *aligned_src;
/* If SRC and DEST is aligned and count large enough, then copy words. */
if (!UNALIGNED (src, dst) && !TOO_SMALL (count))
{
aligned_dst = (long*)dst;
aligned_src = (long*)src;
/* SRC and DEST are both "long int" aligned, try to do "long int"
sized copies. */
while (count >= sizeof (long int) && !DETECTNULL(*aligned_src))
{
count -= sizeof (long int);
*aligned_dst++ = *aligned_src++;
}
dst = (char*)aligned_dst;
src = (char*)aligned_src;
}
while (count > 0)
{
--count;
if ((*dst++ = *src++) == '\0')
break;
}
while (count-- > 0)
*dst++ = '\0';
return dst0;
#endif /* not PREFER_SIZE_OVER_SPEED */
}
#endif /* MESOSPHERE_LIBC_STRNCPY_GENERIC */
/*
FUNCTION
<<strncmp>>---character string compare
INDEX
strncmp
SYNOPSIS
#include <string.h>
int strncmp(const char *<[a]>, const char * <[b]>, size_t <[length]>);
DESCRIPTION
<<strncmp>> compares up to <[length]> characters
from the string at <[a]> to the string at <[b]>.
RETURNS
If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>,
<<strncmp>> returns a number greater than zero. If the two
strings are equivalent, <<strncmp>> returns zero. If <<*<[a]>>>
sorts lexicographically before <<*<[b]>>>, <<strncmp>> returns a
number less than zero.
PORTABILITY
<<strncmp>> is ANSI C.
<<strncmp>> requires no supporting OS subroutines.
QUICKREF
strncmp ansi pure
*/
#include <string.h>
#include <limits.h>
/* Nonzero if either X or Y is not aligned on a "long" boundary. */
#define UNALIGNED(X, Y) \
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
/* DETECTNULL returns nonzero if (long)X contains a NULL byte. */
#if LONG_MAX == 2147483647L
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
#else
#if LONG_MAX == 9223372036854775807L
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
#else
#error long int is not a 32bit or 64bit type.
#endif
#endif
#ifndef DETECTNULL
#error long int is not a 32bit or 64bit byte
#endif
#if MESOSPHERE_LIBC_STRNCMP_GENERIC
int
strncmp (const char *s1,
const char *s2,
size_t n)
{
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
if (n == 0)
return 0;
while (n-- != 0 && *s1 == *s2)
{
if (n == 0 || *s1 == '\0')
break;
s1++;
s2++;
}
return (*(unsigned char *) s1) - (*(unsigned char *) s2);
#else
unsigned long *a1;
unsigned long *a2;
if (n == 0)
return 0;
/* If s1 or s2 are unaligned, then compare bytes. */
if (!UNALIGNED (s1, s2))
{
/* If s1 and s2 are word-aligned, compare them a word at a time. */
a1 = (unsigned long*)s1;
a2 = (unsigned long*)s2;
while (n >= sizeof (long) && *a1 == *a2)
{
n -= sizeof (long);
/* If we've run out of bytes or hit a null, return zero
since we already know *a1 == *a2. */
if (n == 0 || DETECTNULL (*a1))
return 0;
a1++;
a2++;
}
/* A difference was detected in last few bytes of s1, so search bytewise */
s1 = (char*)a1;
s2 = (char*)a2;
}
while (n-- > 0 && *s1 == *s2)
{
/* If we've run out of bytes or hit a null, return zero
since we already know *s1 == *s2. */
if (n == 0 || *s1 == '\0')
return 0;
s1++;
s2++;
}
return (*(unsigned char *) s1) - (*(unsigned char *) s2);
#endif /* not PREFER_SIZE_OVER_SPEED */
}
#endif /* MESOSPHERE_LIBC_STRNCMP_GENERIC */
#ifdef __cplusplus
} /* extern "C" */
#endif