diff --git a/libexosphere/arm.mk b/libexosphere/arm.mk index 7a653f53..5819d270 100644 --- a/libexosphere/arm.mk +++ b/libexosphere/arm.mk @@ -14,7 +14,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk #--------------------------------------------------------------------------------- DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE -SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions +SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -flto -fno-non-call-exceptions CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) @@ -125,7 +125,7 @@ $(OFILES) : $(GCH_FILES) $(OFILES_SRC) : $(HFILES_BIN) -libc.o: CFLAGS += -fno-builtin +libc.o: CFLAGS += -fno-builtin -fno-lto #--------------------------------------------------------------------------------- %_bin.h %.bin.o : %.bin diff --git a/libexosphere/arm64.mk b/libexosphere/arm64.mk index 35492a4c..1ad716a3 100644 --- a/libexosphere/arm64.mk +++ b/libexosphere/arm64.mk @@ -126,7 +126,7 @@ $(OFILES) : $(GCH_FILES) $(OFILES_SRC) : $(HFILES_BIN) -libc.o: CFLAGS += -fno-builtin +libc.o: CFLAGS += -fno-builtin -fno-lto #--------------------------------------------------------------------------------- %_bin.h %.bin.o : %.bin diff --git a/libexosphere/include/exosphere.hpp b/libexosphere/include/exosphere.hpp index e93e8b8f..d7403cbf 100644 --- a/libexosphere/include/exosphere.hpp +++ b/libexosphere/include/exosphere.hpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp b/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp index ac534fe1..547014f4 100644 --- a/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp +++ b/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp @@ -43,11 +43,13 @@ namespace ams::hw::arch::arm64 { } ALWAYS_INLINE void InvalidateTlb(uintptr_t address) { - __asm__ __volatile__("tlbi vae3is, %[address]" :: [address]"r"(address) : "memory"); + const uintptr_t page_index = address / 4_KB; + __asm__ __volatile__("tlbi vae3is, %[page_index]" :: [page_index]"r"(page_index) : "memory"); } ALWAYS_INLINE void InvalidateTlbLastLevel(uintptr_t address) { - __asm__ __volatile__("tlbi vale3is, %[address]" :: [address]"r"(address) : "memory"); + const uintptr_t page_index = address / 4_KB; + __asm__ __volatile__("tlbi vale3is, %[page_index]" :: [page_index]"r"(page_index) : "memory"); } void FlushDataCache(const void *ptr, size_t size); diff --git a/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp b/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp index 07fea9c4..d4d0c970 100644 --- a/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp +++ b/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp @@ -140,7 +140,7 @@ namespace ams::mmu::arch::arm64 { constexpr inline u64 MemoryRegionAttributeWidth = 8; - constexpr PageTableMappingAttribute AddMappingAttributeIndex(PageTableMappingAttribute attr, int index) { + constexpr ALWAYS_INLINE PageTableMappingAttribute AddMappingAttributeIndex(PageTableMappingAttribute attr, int index) { return static_cast(attr | (static_cast::type>(index) << 2)); } @@ -169,35 +169,35 @@ namespace ams::mmu::arch::arm64 { constexpr inline u64 EntryBlock = 0x1ul; constexpr inline u64 EntryPage = 0x3ul; - constexpr u64 MakeTableEntry(u64 address, PageTableTableAttribute attr) { + constexpr ALWAYS_INLINE u64 MakeTableEntry(u64 address, PageTableTableAttribute attr) { return address | static_cast(attr) | 0x3ul; } - constexpr u64 MakeL1BlockEntry(u64 address, PageTableMappingAttribute attr) { + constexpr ALWAYS_INLINE u64 MakeL1BlockEntry(u64 address, PageTableMappingAttribute attr) { return address | static_cast(attr) | static_cast(PageTableMappingAttribute_AccessFlagAccessed) | 0x1ul; } - constexpr u64 MakeL2BlockEntry(u64 address, PageTableMappingAttribute attr) { + constexpr ALWAYS_INLINE u64 MakeL2BlockEntry(u64 address, PageTableMappingAttribute attr) { return address | static_cast(attr) | static_cast(PageTableMappingAttribute_AccessFlagAccessed) | 0x1ul; } - constexpr u64 MakeL3BlockEntry(u64 address, PageTableMappingAttribute attr) { + constexpr ALWAYS_INLINE u64 MakeL3BlockEntry(u64 address, PageTableMappingAttribute attr) { return address | static_cast(attr) | static_cast(PageTableMappingAttribute_AccessFlagAccessed) | 0x3ul; } - constexpr uintptr_t GetL2Offset(uintptr_t address) { + constexpr ALWAYS_INLINE uintptr_t GetL2Offset(uintptr_t address) { return address & ((1ul << L2EntryShift) - 1); } - constexpr u64 GetL1EntryIndex(uintptr_t address) { + constexpr ALWAYS_INLINE u64 GetL1EntryIndex(uintptr_t address) { return ((address >> L1EntryShift) & TableEntryIndexMask); } - constexpr u64 GetL2EntryIndex(uintptr_t address) { + constexpr ALWAYS_INLINE u64 GetL2EntryIndex(uintptr_t address) { return ((address >> L2EntryShift) & TableEntryIndexMask); } - constexpr u64 GetL3EntryIndex(uintptr_t address) { + constexpr ALWAYS_INLINE u64 GetL3EntryIndex(uintptr_t address) { return ((address >> L3EntryShift) & TableEntryIndexMask); } @@ -218,15 +218,15 @@ namespace ams::mmu::arch::arm64 { SetTableEntryImpl(table, index, value); } - constexpr void SetL1TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) { + constexpr ALWAYS_INLINE void SetL1TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) { SetTableEntry(table, GetL1EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr)); } - constexpr void SetL2TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) { + constexpr ALWAYS_INLINE void SetL2TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) { SetTableEntry(table, GetL2EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr)); } - constexpr void SetL1BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { + constexpr ALWAYS_INLINE void SetL1BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { const u64 start = GetL1EntryIndex(virt_addr); const u64 count = (size >> L1EntryShift); @@ -235,7 +235,7 @@ namespace ams::mmu::arch::arm64 { } } - constexpr void SetL2BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { + constexpr ALWAYS_INLINE void SetL2BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { const u64 start = GetL2EntryIndex(virt_addr); const u64 count = (size >> L2EntryShift); @@ -244,7 +244,7 @@ namespace ams::mmu::arch::arm64 { } } - constexpr void SetL3BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { + constexpr ALWAYS_INLINE void SetL3BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { const u64 start = GetL3EntryIndex(virt_addr); const u64 count = (size >> L3EntryShift); @@ -253,7 +253,7 @@ namespace ams::mmu::arch::arm64 { } } - constexpr void InvalidateL1Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) { + constexpr ALWAYS_INLINE void InvalidateL1Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) { const u64 start = GetL1EntryIndex(virt_addr); const u64 count = (size >> L1EntryShift); const u64 end = start + count; @@ -263,7 +263,7 @@ namespace ams::mmu::arch::arm64 { } } - constexpr void InvalidateL2Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) { + constexpr ALWAYS_INLINE void InvalidateL2Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) { const u64 start = GetL2EntryIndex(virt_addr); const u64 count = (size >> L2EntryShift); const u64 end = start + count; @@ -273,7 +273,7 @@ namespace ams::mmu::arch::arm64 { } } - constexpr void InvalidateL3Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) { + constexpr ALWAYS_INLINE void InvalidateL3Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) { const u64 start = GetL3EntryIndex(virt_addr); const u64 count = (size >> L3EntryShift); const u64 end = start + count; diff --git a/libexosphere/include/exosphere/pmic.hpp b/libexosphere/include/exosphere/pmic.hpp index 1d01eb81..29122bce 100644 --- a/libexosphere/include/exosphere/pmic.hpp +++ b/libexosphere/include/exosphere/pmic.hpp @@ -30,6 +30,7 @@ namespace ams::pmic { void EnableVddCpu(Regulator regulator); void DisableVddCpu(Regulator regulator); void EnableSleep(); + void PowerOff(); bool IsAcOk(); } \ No newline at end of file diff --git a/libexosphere/include/exosphere/rtc.hpp b/libexosphere/include/exosphere/rtc.hpp new file mode 100644 index 00000000..bacf1b9f --- /dev/null +++ b/libexosphere/include/exosphere/rtc.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include + +namespace ams::rtc { + + void StopAlarm(); + +} diff --git a/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp b/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp index 38e6452b..c6ec12b3 100644 --- a/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp +++ b/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp @@ -287,4 +287,6 @@ namespace ams::secmon { constexpr inline const MemoryRegion MemoryRegionPhysicalIramWarmbootBin = MemoryRegion(UINT64_C(0x4003E000), 0x17F0); constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootConfig = MemoryRegion(UINT64_C(0x4003F800), 0x400); + constexpr inline const MemoryRegion MemoryRegionPhysicalIramRebootStub = MemoryRegion(UINT64_C(0x4003F000), 0x1000); + } diff --git a/libexosphere/include/exosphere/tegra/tegra_pmc.hpp b/libexosphere/include/exosphere/tegra/tegra_pmc.hpp index f64f500f..da1c6d05 100644 --- a/libexosphere/include/exosphere/tegra/tegra_pmc.hpp +++ b/libexosphere/include/exosphere/tegra/tegra_pmc.hpp @@ -44,6 +44,8 @@ #define APBDEV_PMC_CRYPTO_OP (0x0F4) #define APBDEV_PMC_SCRATCH31 (0x118) #define APBDEV_PMC_SCRATCH32 (0x11C) +#define APBDEV_PMC_SCRATCH33 (0x120) +#define APBDEV_PMC_SCRATCH40 (0x13C) #define APBDEV_PMC_WAKE2_MASK (0x160) #define APBDEV_PMC_WAKE2_LVL (0x164) #define APBDEV_PMC_WAKE2_STATUS (0x168) @@ -54,6 +56,8 @@ #define APBDEV_PMC_IO_DPD2_REQ (0x1C0) #define APBDEV_PMC_IO_DPD2_STATUS (0x1C4) #define APBDEV_PMC_SEL_DPD_TIM (0x1C8) +#define APBDEV_PMC_SCRATCH45 (0x234) +#define APBDEV_PMC_SCRATCH46 (0x238) #define APBDEV_PMC_TSC_MULT (0x2B4) #define APBDEV_PMC_WEAK_BIAS (0x2C8) #define APBDEV_PMC_GPU_RG_CNTRL (0x2D4) diff --git a/libexosphere/source/pmic/pmic_api.cpp b/libexosphere/source/pmic/pmic_api.cpp index 96847f89..bf1515d7 100644 --- a/libexosphere/source/pmic/pmic_api.cpp +++ b/libexosphere/source/pmic/pmic_api.cpp @@ -145,12 +145,17 @@ namespace ams::pmic { u8 cnfg = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1); /* Set SlpEn. */ - cnfg |= (1 << 2); + cnfg |= MAX77620_ONOFFCNFG1_SLPEN; /* Write the new cfg. */ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1, cnfg); } + void PowerOff() { + /* Write power-off to onoff cfg. */ + i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1, MAX77620_ONOFFCNFG1_PWR_OFF); + } + bool IsAcOk() { return (GetPmicOnOffStat() & (1 << 1)) != 0; } diff --git a/libexosphere/source/rtc/max77620-rtc.h b/libexosphere/source/rtc/max77620-rtc.h new file mode 100644 index 00000000..2d38487c --- /dev/null +++ b/libexosphere/source/rtc/max77620-rtc.h @@ -0,0 +1,60 @@ +/* + * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC + * + * Copyright (c) 2018 CTCaer + * + * 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 . + */ + +#ifndef _MFD_MAX77620_RTC_H_ +#define _MFD_MAX77620_RTC_H_ + +#define MAX77620_RTC_I2C_ADDR 0x68 + +#define MAX77620_RTC_NR_TIME_REGS 7 + +#define MAX77620_RTC_CONTROLM_REG 0x02 +#define MAX77620_RTC_CONTROL_REG 0x03 +#define MAX77620_RTC_BIN_FORMAT (1 << 0) +#define MAX77620_RTC_24H (1 << 1) + +#define MAX77620_RTC_UPDATE0_REG 0x04 +#define MAX77620_RTC_WRITE_UPDATE (1 << 0) +#define MAX77620_RTC_READ_UPDATE (1 << 4) + +#define MAX77620_RTC_SEC_REG 0x07 +#define MAX77620_RTC_MIN_REG 0x08 +#define MAX77620_RTC_HOUR_REG 0x09 +#define MAX77620_RTC_HOUR_PM_MASK (1 << 6) +#define MAX77620_RTC_WEEKDAY_REG 0x0A +#define MAX77620_RTC_MONTH_REG 0x0B +#define MAX77620_RTC_YEAR_REG 0x0C +#define MAX77620_RTC_DATE_REG 0x0D + +#define MAX77620_ALARM1_SEC_REG 0x0E +#define MAX77620_ALARM1_MIN_REG 0x0F +#define MAX77620_ALARM1_HOUR_REG 0x10 +#define MAX77620_ALARM1_WEEKDAY_REG 0x11 +#define MAX77620_ALARM1_MONTH_REG 0x12 +#define MAX77620_ALARM1_YEAR_REG 0x13 +#define MAX77620_ALARM1_DATE_REG 0x14 +#define MAX77620_ALARM2_SEC_REG 0x15 +#define MAX77620_ALARM2_MIN_REG 0x16 +#define MAX77620_ALARM2_HOUR_REG 0x17 +#define MAX77620_ALARM2_WEEKDAY_REG 0x18 +#define MAX77620_ALARM2_MONTH_REG 0x19 +#define MAX77620_ALARM2_YEAR_REG 0x1A +#define MAX77620_ALARM2_DATE_REG 0x1B +#define MAX77620_RTC_ALARM_EN_MASK (1 << 7) + +#endif /* _MFD_MAX77620_RTC_H_ */ diff --git a/libexosphere/source/rtc/rtc_api.cpp b/libexosphere/source/rtc/rtc_api.cpp new file mode 100644 index 00000000..dcf8480e --- /dev/null +++ b/libexosphere/source/rtc/rtc_api.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#include +#include "max77620-rtc.h" + +namespace ams::rtc { + + namespace { + + constexpr inline int I2cAddressMax77620Rtc = 0x68; + + /* TODO: Find datasheet, link to it instead. */ + /* NOTE: Tentatively, Max77620 "mostly" matches https://datasheets.maximintegrated.com/en/ds/MAX77863.pdf. */ + constexpr inline int Max77620RtcRegisterUpdate0 = 0x04; + + constexpr inline int Max77620RtcRegisterAlarmStart = 0x0E; + + constexpr inline int Max77620RtcRegisterAlarm1Sec = 0x0E; + constexpr inline int Max77620RtcRegisterAlarm1Min = 0x0F; + constexpr inline int Max77620RtcRegisterAlarm1Hour = 0x10; + constexpr inline int Max77620RtcRegisterAlarm1Weekday = 0x11; + constexpr inline int Max77620RtcRegisterAlarm1Month = 0x12; + constexpr inline int Max77620RtcRegisterAlarm1Year = 0x13; + constexpr inline int Max77620RtcRegisterAlarm1Date = 0x14; + constexpr inline int Max77620RtcRegisterAlarm2Sec = 0x15; + constexpr inline int Max77620RtcRegisterAlarm2Min = 0x16; + constexpr inline int Max77620RtcRegisterAlarm2Hour = 0x17; + constexpr inline int Max77620RtcRegisterAlarm2Weekday = 0x18; + constexpr inline int Max77620RtcRegisterAlarm2Month = 0x19; + constexpr inline int Max77620RtcRegisterAlarm2Year = 0x1A; + constexpr inline int Max77620RtcRegisterAlarm2Date = 0x1B; + + constexpr inline int Max77620RtcRegisterAlarmLast = 0x1B; + + } + + void StopAlarm() { + /* Begin update. */ + i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, Max77620RtcRegisterUpdate0, MAX77620_RTC_READ_UPDATE); + + /* Clear ALARM_EN for all alarm registers. */ + for (auto reg = Max77620RtcRegisterAlarmStart; reg <= Max77620RtcRegisterAlarmLast; ++reg) { + u8 val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Rtc, reg); + val &= ~MAX77620_RTC_ALARM_EN_MASK; + i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, reg, val); + } + + /* End update. */ + i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, Max77620RtcRegisterUpdate0, MAX77620_RTC_WRITE_UPDATE); + } + +}