Compare commits

...

128 Commits

Author SHA1 Message Date
Kostas Missos
20040ae70f Bump version to v4.5 2018-12-02 11:12:19 +02:00
Kostas Missos
22e179d1cf Add 6.2.0 support to tools
- Print TSEC info
- Dump pkg1/2
2018-12-02 11:11:07 +02:00
Kostas Missos
1b075c91bd Name hardcoded TSEC regs 2018-12-01 20:49:31 +02:00
Kostas Missos
1ac7f61f49 Add 6.2.0 exosphere support
And refactor it to its own file.
2018-12-01 20:46:59 +02:00
Kostas Missos
4b3599b2d8 6.2.0 support
Co-Authored-By: nwert <nwert@users.noreply.github.com>
Co-Authored-By: Balázs Triszka <balika011@gmail.com>
2018-11-30 23:20:15 +02:00
Kostas Missos
ceabbb0be0 Refactor hos.c 2018-11-28 21:26:16 +02:00
Kostas Missos
471c1e514c Major refactoring of main.c 2018-11-27 11:45:43 +02:00
Kostas Missos
267a04c4ac Fix HDCP + some bugfixes
Thanks @hexkyz for taking the time to recheck for the missing 6.x changes
2018-11-20 21:32:54 +02:00
Kostas Missos
4eb5b5f91b Name more hardcoded regs/vals 2018-11-10 14:11:42 +02:00
Kostas Missos
cfef8b4f72 Update libminerva to v1.1 2018-11-10 13:30:17 +02:00
Kostas Missos
683ca6af1d Merge pull request #142 from StevenMattera/master
Ignore hidden and dot files when using wildcards.
2018-11-11 01:03:19 +02:00
Steven Mattera
14cdcc1497 Ignore hidden files when using wildcards. 2018-11-08 19:09:14 -05:00
Kostas Missos
ec1bb508b3 Fix minerva build
This is still for testing it out.
The real usage will come later.
2018-11-05 10:54:31 +02:00
Kostas Missos
cae9044c17 Minerva our DRAM trainer
Supports up to 1600MHz and periodic training.

For more check here: https://github.com/CTCaer/minerva_tc
2018-11-04 03:15:32 +02:00
Kostas Missos
5674dad1e9 Merge pull request #125 from Huntereb/master
Add "Silent" auto full power off option
2018-09-30 20:34:13 +03:00
Hunter
288b5c08db Add "Silent" auto full power off option 2018-09-30 13:24:30 -04:00
Kostas Missos
fac8db4238 Bump version to v4.2 2018-09-24 23:51:36 +03:00
Kostas Missos
04ac8ebd43 Allow verification cancel. Backup still remains. 2018-09-24 23:51:04 +03:00
Kostas Missos
1392e6eaf4 Add use of wildcard "*" for loading kips from a folder 2018-09-24 23:47:35 +03:00
Kostas Missos
381d5c9236 Allow toggling of auto power off from HOS waking 2018-09-24 23:45:06 +03:00
Kostas Missos
2f43b20124 Bugfixes / formating 2018-09-24 23:22:19 +03:00
Kostas Missos
c99ea77daf Bump version to v4.1 2018-09-19 17:58:26 +03:00
Kostas Missos
4ad7aedbaf -.-
Nintendo, I Am Disappoint
2018-09-19 17:57:02 +03:00
Kostas Missos
267bcd352f [PATCH] Port FS patches to 6.0.0
Co-Authored-By: Rajko Stojadinovic <admin@rajko.info>
2018-09-19 00:57:19 +03:00
Kostas Missos
db88eb31f2 Add svc/dbg &Atmosphère fs.mitm patches for 6.0.0 2018-09-19 00:55:26 +03:00
Kostas Missos
efc3fc34de Add cancel backup if VOL DOWN + UP are held
- Long press of both buttons cancels the backup process now
- Fixed an issue with partial backup when the resume was happening on the last part
2018-09-19 00:50:23 +03:00
Kostas Missos
89fb29e35e Add support for payloads with broken hw inits 2018-09-19 00:46:32 +03:00
Kostas Missos
b54cbbfc3c Fix version check for the update chainloader 2018-09-19 00:36:40 +03:00
Kostas Missos
fc0f75495e Add auto full power off if woke up from HOS.
Useful for modchips/dongles.
It shows a brief breathing style of hekate logo before powering off completely.
2018-09-19 00:34:05 +03:00
Kostas Missos
4e9b3d8157 Add proper BCT copy for dev units
Co-Authored-By: Rajko Stojadinovic <admin@rajko.info>
2018-09-19 00:28:13 +03:00
Kostas Missos
7aeac2c379 Add 4/5.X and 6.X hw config changes
Thanks to @balika011 for notice on 2.x vs 5.x changes.

(Some 2.x vs 5.x changes were added with the `fdd94ff` commit)
2018-09-19 00:11:18 +03:00
Kostas Missos
b9e348fc17 Add warnings on missing bootloader libraries 2018-09-19 00:04:58 +03:00
Kostas Missos
67a470921a Add PWM backlight support + options
- No eye blasting backlight
- Option to choose the prefered brightness
- Smooths transitions
2018-09-19 00:01:42 +03:00
Kostas Missos
780736591e Improvements to ini/payload handling
- Allow no hekate_ipl.ini and create it at 1st hekate boot
- Show Payloads/More configs options when no boot entry in main .ini
- Fix black screen on empty ini/payload folders
- Fix some stack corruption with freeing ini lists (wip)
2018-09-18 23:47:37 +03:00
Kostas Missos
fdd94ffd2b General bugfixes + hardcoded name replacement 2018-09-18 23:38:54 +03:00
Kostas Missos
59e711c91d Merge remote-tracking branch 'origin/dev' 2018-09-18 03:18:26 +03:00
Pika
4e43bd9a39 Add 6.0.0 support (#95)
Add partial 6.0.0 support
2018-09-18 03:08:05 +03:00
Kostas Missos
5aecd0d778 Merge pull request #107 from balika011/dev
Add ipatch and bootrom dumping
2018-09-10 15:50:38 +03:00
balika011
532dd6ddee Add ipatch and bootrom dumping 2018-09-10 01:12:28 +02:00
Kostas Missos
58b289bee2 Fix build pf sample module by adding missing files 2018-08-25 22:59:54 +03:00
Kostas Missos
6da09b3b93 Bump version to v4.0 2018-08-23 05:06:10 +03:00
Kostas Missos
7803bbcd83 Add payload launching. Supports all CFW bins, Linux, Tools. 2018-08-23 05:05:31 +03:00
Kostas Missos
382f727be3 Fix all the bugs
- Mem leaks
- Stack corruption
- Div by 0
- Double frees
2018-08-23 04:37:02 +03:00
Kostas Missos
6a554eec6c Update Readme + Fix Auto Update 2018-08-23 04:27:49 +03:00
Kostas Missos
0540128709 Faster backups
- Add file pre-allocations to greatly reduce overhead of FatFS.
This was missing before, because it takes 1.5KB payload size.

Speed bumps (no verify) are between 7 to 30% for exFAT and ~50% for FAT32, depending on the workload.
2018-08-22 03:42:25 +03:00
Kostas Missos
da5a1a9641 Fix a critical bug with exFAT FatFs + a list bug
Nintendo you hear? Fix your driver already.
(for us never caused any problem, because we always sync fs dir changes to medium.)
2018-08-22 03:38:25 +03:00
Kostas Missos
c5a6ad823e Add payload/libtools launching prerequisites 2018-08-21 04:45:19 +03:00
Kostas Missos
463383abca AutoRCM disabler support for all AutoRCM versions 2018-08-21 04:43:00 +03:00
Kostas Missos
13a07663ee Add autolaunch updated bootloader (mostly for modchips) 2018-08-21 04:41:16 +03:00
Kostas Missos
5328f89ffe Add support for split inis in 'bootloader/ini'
- A new option was added to Launch.
- These can be configured for autoboot
2018-08-21 04:37:40 +03:00
Kostas Missos
7e876388b4 Bugfixes
- Fixed partial dumping filename/bar position
- Add return for menu function handler
- More files to bootloader folder
2018-08-21 04:26:14 +03:00
Kostas Missos
bf816c5107 Move everything to 'bootloader' folder to reduce clutter
+ Make everything all lowercase
2018-08-21 04:21:09 +03:00
Kostas Missos
1d623eacf9 Our 1st module. LP0 configuration. 2018-08-21 04:14:31 +03:00
Kostas Missos
3d6216a6f3 Deploy ianos. Our elf/module loader. 2018-08-21 04:12:03 +03:00
Kostas Missos
5fd9daa364 Add display_end fix for all fw + easter egg
The easter egg is sth that was forgotten in booting via hekate's hwinit.
2018-08-14 02:30:44 +03:00
Kostas Missos
6b8887b5d8 Move display_end before secmon + add boolean supp.
Currently bpmp loses access to the relevant registers when secmon or exosphere is launched.

This change provides support for all firmwares and properly sanitizes the display.
2018-08-13 12:12:53 +03:00
Kostas Missos
e5abdd938e Refactor ALL the things + enable LTO 2018-08-13 11:58:24 +03:00
Kostas Missos
2666b440ef Merge pull request #66 from m4xw/feature/elf_loader
Implement basic elfloader/module support
2018-08-08 00:25:40 +03:00
M4xw
8b0915cb01 Implement elfloader/module support 2018-08-07 22:41:05 +02:00
Kostas Missos
71c4e2c155 Merge pull request #63 from misson20000/misson20000-patch-1
Update README.md to document `atmosphere` option in hekate.ini
2018-08-06 10:15:41 +03:00
misson20000
6baeb8b4ff Update README.md to document atmosphere option in hekate.ini 2018-08-05 22:08:17 -07:00
Kostas Missos
355ebb6acf Whitespaces, fixes 2018-08-05 14:40:32 +03:00
Kostas Missos
c9379d97a3 Merge pull request #62 from rajkosto/pull_improvenogc
Better nogc patch, no longer causes 10s hang on bootup and wakeup
2018-08-05 13:50:08 +03:00
Rajko Stojadinovic
c2da65e498 Better nogc patch, no longer causes 10s hang on bootup and wakeup 2018-08-05 06:27:18 +02:00
Kostas Missos
e9d1256df8 Merge pull request #51 from rajkosto/kip1patching
Add KIP1 patching support (with 2 FS patches included)
2018-07-29 23:09:25 +03:00
Rajko Stojadinovic
977ef6f150 Add KIP1 patching support (with 2 FS patches included) 2018-07-29 22:03:12 +02:00
Kostas Missos
d33f60e924 Add unique id to backup folder
+ Choose to boot into HOS if no SD card or .ini

*The unique id for the backup folder is eMMC's serial number.
2018-07-22 15:24:09 +03:00
Kostas Missos
39653f7678 Bugfixes + Unfattening + Remove white on boot 2018-07-22 15:18:30 +03:00
Kostas Missos
bc67798f43 More unfattening (like always) 2018-07-10 16:59:03 +03:00
tesnos
9401897f93 Allow dumping TSEC keys to sd card (#44)
* Allow dumping tsec keys to sd card
2018-07-10 10:19:06 +03:00
Kostas Missos
1988e3f19d Bump version to v3.2
Forgot to commit that ^^
2018-07-09 23:22:11 +03:00
Kostas Missos
7af531de77 Add sleep mode support for 3.X.X. ^^ 2018-07-09 23:01:40 +03:00
Kostas Missos
a77783b922 Add dumping of decrypted package2 2018-07-09 22:16:42 +03:00
Kostas Missos
33457ad8f8 As always remove more uneeded stuff 2018-07-09 22:13:56 +03:00
Kostas Missos
828b616468 Add status bar (battery info)
This gets updated in menus and backup/restore options and it's still visible to other options
2018-07-09 16:06:17 +03:00
Kostas Missos
2f120d1cbb Change partial backup msg + some fixes 2018-07-09 16:02:47 +03:00
Kostas Missos
a5f2bb9d57 Support custom backcolor when logo is smaller
When the bootlogo is smaller than 720x1280, the background color will be set to match the color of bmp's 1st pixel.

This ends the limit of having to use a background color of 0x1B1B1B.
2018-07-09 15:55:09 +03:00
Kostas Missos
60905c3829 Don't run hos keygen twice + Fix memory leaks 2018-07-07 18:36:18 +03:00
Kostas Missos
19e9292128 More unfattening 2018-07-07 18:34:33 +03:00
Kostas Missos
6d556bf213 Remove null term from "" as suggested
Additionally rename the archive bits again ( :) ) to have a little better syntax.
2018-07-06 16:11:51 +03:00
Jason Tomsic
f91546a1e5 Unset archive bit on all files except official Nintendo directory (#35)
* allow for all files to unset archive bit, except Nintendo dir
* don't recalculate path length with every file
* use strlen instead of a loop
* negating the if statement to reduce conditional context
* move an operation to the beginning of the loop so we don't have to have it twice
* combining some lines and removing a var for efficiency
2018-07-06 16:02:00 +03:00
Kostas Missos
eecdca3f03 Bump version to v3.1 2018-07-05 02:03:01 +03:00
Kostas Missos
a14f554657 Make the sleeps faster
Based on tests they are not faster, even though the raw sleeps have less instuctions.

But having them call get_tmr breaks important logic.
Make both raw to avoid any future problems.
2018-07-05 02:02:17 +03:00
Kostas Missos
879fc643d9 Add important fuse info (like burnt eFuses) 2018-07-05 01:51:36 +03:00
Kostas Missos
5e8eb1c57a Implement ms timer and fix all timers
This will fix everything that uses a timer (or sleep).

Without this any function like eMMC/SD read/write/verify, TSEC/SE, etc can break when the time reaches the max value of the u32 microsecond timer (71minutes).

This fixes every possible breakage, including backup and restore (read/write/verify errors) that takes a lot of time.

The new max before a timer reset is now 48 days (the old one was 71 minutes)
2018-07-04 18:39:26 +03:00
Kostas Missos
ebb9ca5bf5 Fix partial+single backup/restore verification
and archive bit for switch folder.
2018-07-04 18:28:03 +03:00
Kostas Missos
d16477ed20 Merge pull request #26 from TheDgtl/4_x_x_patch_fix
Fix Atmosphere's kernel patches for 4.x
2018-07-03 01:45:34 +03:00
Kostas Missos
d4731bb540 Split remove archive bit in two
1. Only switch folder and its subfolders/files
2. Everything in sd card
2018-07-02 17:12:15 +03:00
Drakia
605e95e025 Fix issue with Atmosphere 4.x kernel patches 2018-07-01 17:42:27 -07:00
Kostas Missos
3e35d99a3b Bump version to v3.0 2018-07-01 20:47:54 +03:00
Kostas Missos
57399e4df1 Add restore options 2018-07-01 20:46:22 +03:00
Kostas Missos
6df5fdc9c3 Add auto boot 2018-07-01 20:45:52 +03:00
Kostas Missos
94bd9a24d3 Add global configuration and saving mechanism 2018-07-01 20:45:25 +03:00
Kostas Missos
a442737a59 Update ini parsing to the new version 2018-07-01 20:29:30 +03:00
Kostas Missos
df8e6ea57d Add hekate new style .ini template 2018-07-01 20:26:26 +03:00
Kostas Missos
f22616894c Update README and README_BOOTLOGO 2018-07-01 20:21:25 +03:00
Kostas Missos
7b97015df6 Fix low battery shutdown tool 2
(forgot the driver changes)
2018-07-01 17:01:10 +03:00
Kostas Missos
9672650d1a Fix low battery shutdown tool
The real reason for the "battery de-sync" is a misconfig of MAX77620 low battery monitor.

So there's no real battery battery de-sync.

Thanks @natinusala and @perillamint for finding this
2018-07-01 16:58:59 +03:00
Kostas Missos
42d743d9d5 Fix build 2018-07-01 05:06:13 +03:00
Kostas Missos
ffeb8c60df Preliminary Exosphère support 2018-07-01 05:03:17 +03:00
Kostas Missos
d9dba2b182 Fix timing issues with battery desync fix 2018-07-01 04:58:37 +03:00
Kostas Missos
e5a34c3818 Small unfattening 2018-07-01 04:56:58 +03:00
Kostas Missos
0c5c827d0b Add battery/charge info + bugfixes 2018-06-28 04:05:19 +03:00
Kostas Missos
3908493cf5 Fix the accents lost in commits 2018-06-28 00:40:43 +03:00
Kostas Missos
6561a3e738 Preparation for adding config + restore options 2018-06-28 00:36:18 +03:00
Kostas Missos
66b6c5cdf0 Add 16px font support back 2018-06-28 00:21:05 +03:00
Kostas Missos
3175dbc1c9 Prepare about for 16px font 2018-06-26 19:09:26 +03:00
Kostas Missos
37a15ca8ff Make Backup verifying faster by using SE's SHA256 2018-06-26 19:07:34 +03:00
Kostas Missos
3f18713f53 Add seconds timer + bugfixes 2018-06-26 19:00:46 +03:00
Kostas Missos
c215b1c74c Disable verification for now & add memcmp32sparse
When the commit with the configuration will be a available, these 3 options will exist:

- Disable verification
- Sparse verification (Fast)
- Full (Slow)

Sparse will take approx 8 minutes for rawnand.bin and Full will take 4.5 hours.
2018-06-24 23:02:35 +03:00
Kostas Missos
60f4000e9d Fix build 2018-06-24 22:42:46 +03:00
Kostas Missos
52506def30 Add Battery Charger & Fuel Gauge dirvers
* Add Fuel gauge configuration fix
* Add Battery de-sync fix
* Fuel gauge registers dumping
* Add help and battery status in menu
2018-06-24 22:38:32 +03:00
Kostas Missos
6961769a86 Name more hardcoded values 2018-06-24 22:31:24 +03:00
Kostas Missos
df30512fd9 [Info] Add current bus maximum rate and refactor a bit 2018-06-23 07:18:53 +03:00
Kostas Missos
532a9f9949 [Tools] dump_emmc_verify() :/
With a working verify functions, the speed is 10.5 times slower.
(A 2.5 seconds operation takes now 28 minutes)

TODO: Find a faster way!
2018-06-23 07:12:30 +03:00
Kostas Missos
bee8004b74 [GFX] Add position saving and muting 2018-06-23 07:07:53 +03:00
Kostas Missos
f3149e0be3 FatFS and general file operations fixes
* Make FatFS thread safe via malloc and remove alloca.
* Fix memory leak from emmc gpt parsing
* Always unmount SD card in menu and when launching
* Use folders for Backup/Dump/Restore operations
* Add error report for some important f_opens
* Don't let partial dumping if backup chosen is not GPP or USER.
2018-06-23 07:04:41 +03:00
Kostas Missos
e8ee994ad0 [SDMMC] Raise power limit & fix sd power cycle
*Change sd_switch to accept other functions
*Allow for faster speeds by raising the power limit via switch cmd
*Fix the power cycle of sd cards.
2018-06-23 06:45:29 +03:00
Kostas Missos
901f2bb5bd Replace hardcoded values 2018-06-23 06:37:58 +03:00
Kostas Missos
481a3945e8 [FatFS] Update to 0.13b_rev2 2018-06-23 06:30:57 +03:00
Kostas Missos
e5c1e18f1f Add bootlogo resources 2018-06-21 11:31:05 +03:00
Kostas Missos
171e5ba30f Compile time configurable menu logo 2018-06-19 17:10:59 +03:00
Kostas Missos
426551b9b7 Minor changes to font + refactoring 2018-06-19 16:54:58 +03:00
Kostas Missos
d2291a78e2 Switch Framebuffer to ARGB by default 2018-06-19 16:53:41 +03:00
Kostas Missos
95878d1ad1 Hekate bootlogo and CTCaer logo 2018-06-18 09:04:45 +03:00
Kostas Missos
e76c2b4cb6 General additions, fixes and bugfixes 2018-06-18 09:04:13 +03:00
Kostas Missos
9d50a13ef0 Update GNU copyright for big changes
Additionally change the readme
2018-06-18 09:00:53 +03:00
Kostas Missos
36bd3bbed1 Merge pull request #7 from nwert/master
Merge upstream
2018-06-15 23:42:21 +03:00
194 changed files with 30802 additions and 7820 deletions

4
.gitignore vendored
View File

@@ -1,4 +1,4 @@
.vs
.vscode
build_ipl/*
/ipl.bin
build/*
output/*

View File

@@ -4,12 +4,21 @@ endif
include $(DEVKITARM)/base_rules
TARGET := ipl
BUILD := build_ipl
SOURCEDIR := ipl
OBJS = $(addprefix $(BUILD)/, \
TARGET := hekate
BLVERSION_MAJOR := 4
BLVERSION_MINOR := 5
BUILD := build
OUTPUT := output
SOURCEDIR = bootloader
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
start.o \
main.o \
fe_emmc_tools.o \
fe_info.o \
fe_tools.o \
config.o \
btn.o \
clock.o \
cluster.o \
@@ -17,16 +26,18 @@ OBJS = $(addprefix $(BUILD)/, \
gpio.o \
heap.o \
hos.o \
hos_config.o \
secmon_exo.o \
i2c.o \
kfuse.o \
lz.o \
bq24193.o \
max7762x.o \
max17050.o \
mc.o \
nx_emmc.o \
sdmmc.o \
sdmmc_driver.o \
sdram.o \
sdram_lp0.o \
tui.o \
util.o \
di.o \
@@ -37,32 +48,54 @@ OBJS = $(addprefix $(BUILD)/, \
se.o \
tsec.o \
uart.o \
hw_init.o \
dirlist.o \
ini.o \
ianos.o \
smmu.o \
)
OBJS += $(addprefix $(BUILD)/$(TARGET)/, \
lz.o blz.o \
diskio.o ff.o ffunicode.o ffsystem.o \
elfload.o elfreloc_arm.o \
)
OBJS += $(addprefix $(BUILD)/, diskio.o ff.o ffunicode.o)
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall
CUSTOMDEFINES := -DBLVERSIONMJ=$(BLVERSION_MAJOR) -DBLVERSIONMN=$(BLVERSION_MINOR)
CUSTOMDEFINES += -DMENU_LOGO_ENABLE #-DDEBUG
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES)
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections
.PHONY: all clean
MODULEDIRS := $(wildcard modules/*)
.PHONY: all clean $(MODULEDIRS)
all: $(TARGET).bin
@echo -n "Payload size is "
@wc -c < $(OUTPUT)/$(TARGET).bin
@echo "Max size is 126296 Bytes."
clean:
@rm -rf $(OBJS)
@rm -rf $(BUILD)
@rm -rf $(TARGET).bin
@rm -rf $(OUTPUT)
$(TARGET).bin: $(BUILD)/$(TARGET).elf
$(OBJCOPY) -S -O binary $< $@
$(MODULEDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)
$(BUILD)/$(TARGET).elf: $(OBJS)
$(CC) $(LDFLAGS) -T ipl/link.ld $^ -o $@
$(TARGET).bin: $(BUILD)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
$(OBJCOPY) -S -O binary $< $(OUTPUT)/$@
@printf ICTC$(BLVERSION_MAJOR)$(BLVERSION_MINOR) >> $(OUTPUT)/$@
$(BUILD)/%.o: $(SOURCEDIR)/%.c
$(BUILD)/$(TARGET)/$(TARGET).elf: $(OBJS)
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
$(BUILD)/$(TARGET)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD)/%.o: $(SOURCEDIR)/%.S
$(BUILD)/$(TARGET)/%.o: %.S
@mkdir -p "$(BUILD)"
@mkdir -p "$(BUILD)/$(TARGET)"
@mkdir -p "$(OUTPUT)"
$(CC) $(CFLAGS) -c $< -o $@

View File

@@ -1,36 +1,80 @@
# hekate
# hekate - CTCaer mod
![Image of Hekate](https://upload.wikimedia.org/wikipedia/commons/f/fc/H%C3%A9cate_-_Mallarm%C3%A9.png)
Nintendo Switch bootloader, firmware patcher, and more.
![Image of Hekate](https://i.imgur.com/O3REoy5.png)
## ipl config
Custom Nintendo Switch bootloader, firmware patcher, and more.
The ipl can be configured via 'hekate_ipl.ini' (if it is present on the SD card). Each ini section represents a boot entry, except for the special section 'config' that controls the global configuration.
### Possible key/value combinations:
## Bootloader folders and files
| Folder/File | Description |
| -------------------- | --------------------------------------------------------------------- |
| bootloader | Main folder. |
| \|__ bootlogo.bmp | It is used when custom is on and no logopath found. Can be skipped. |
| \|__ hekate_ipl.ini | Main bootloader configuration and boot entries. |
| \|__ update.bin | If newer, it is loaded at boot. For modchips. Can be skipped. |
| bootloader/ini/ | For individual inis. 'More configs...' menu. Autoboot is supported. |
| bootloader/sys/ | For system modules. |
| \|__ libsys_lp0.bso | LP0 (sleep mode) module. Important! |
| bootloader/payloads/ | For payloads. 'Payloads...' menu. Autoboot only supported by including them into an ini. All CFW bootloaders, tools, Linux payloads are supported. |
| bootloader/libtools/ | Future reserved |
## Bootloader configuration
The bootloader can be configured via 'bootloader/hekate_ipl.ini' (if it is present on the SD card). Each ini section represents a boot entry, except for the special section 'config' that controls the global configuration.
There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Caption, "**#**": Comment, "*newline*": .ini cosmetic newline.
### Configuration keys/values when boot entry is **config**:
| Config option | Description |
| ------------------ | ---------------------------------------------------------- |
| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. |
| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. |
| customlogo=0 | 0: Use default hekate bootlogo, 1: Use bootlogo.bmp. |
| verification=2 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and not 100% reliable), 2: Full (sha256 based, slow and 100% reliable). |
| autohosoff=1 | 0: Disable, 1: If woke up from HOS via an RTC alarm, shows logo, then powers off completely, 2: No logo, immediately powers off.|
| backlight=100 | Screen backlight level. 0-255. |
### Possible boot entry key/value combinations:
| Config option | Description |
| ------------------ | ---------------------------------------------------------- |
| logopath={SD path} | If global customlogo is 1 and logopath empty, bootlogo.bmp will be used. If logopath exists, it will load the specified bitmap. |
| warmboot={SD path} | Replaces the warmboot binary |
| secmon={SD path} | Replaces the security monitor binary |
| kernel={SD path} | Replaces the kernel binary |
| kip1={SD path} | Replaces/Adds kernel initial process. Multiple can be set. |
| fullsvcperm=1 | Disables SVC verification |
| kip1={SD folder}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. |
| kip1patch=patchname| Enables a kip1 patch. Specify with multiple lines and/or as CSV. Implemented patches right now are nosigchk,nogc |
| fullsvcperm=1 | Disables SVC verification (full services permission) |
| debugmode=1 | Enables Debug mode |
| atmosphere=1 | Enables Atmosphère patching |
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
You can find a template [Here](./res/hekate_ipl_template.ini)
If the main .ini is not found, it is created on the first hekate boot.
```
hekate (C) 2018 naehrwert, st4rk.
hekate (C) 2018 naehrwert, st4rk
CTCaer mod (C) 2018 CTCaer.
Thanks to: derrek, nedwill, plutoo, shuffle2, smea, thexyz, yellows8.
Greetings to: fincs, hexkyz, SciresM, Shiny Quagsire, WinterMute.
Open source and free packages used:
- FatFs R0.13a, Copyright (C) 2017, ChaN
- bcl-1.2.0, Copyright (C) 2003-2006, Marcus Geelnard
- bcl-1.2.0, Copyright (C) 2003-2006, Marcus Geelnard
- Atmosphère (SE sha256, prc id kernel patches), Copyright (C) 2018, Atmosphère-NX
- elfload, Copyright (C) 2014 Owen Shepherd, Copyright (C) 2018 M4xw
___
.-' `'.
@@ -49,4 +93,4 @@ Open source and free packages used:
, _.-'.'\ \ / / ( ( / /
`--'` ) ) .-'.' '.'. | (
(/` ( (` ) ) '-; [switchbrew]
```
```

16
README_BOOTLOGO.md Normal file
View File

@@ -0,0 +1,16 @@
# hekate - Bootlogo
The bootlogo can be any size with a maximum of 720 x 1280.
When it's smaller than 720 x 1280, it is automatically centered and the background takes the color of the first pixel.
When saving a landscape bootlogo, it should be rotated 90 degrees counterclockwise.
Lastly, the supported format is 32-bit (ARGB) BMP. Classic 24-bit (RGB) BMPs are not supported for performance reasons.
## How to configure
If the custom logo option is enabled, it will try to load /bootlogo.bmp. If this is not found, the default hekate's logo will be used.
If a boot entry specifies a custom logo path, this is one will be loaded. Again if this is not found, bootlogo.bmp will be loaded and if that fails, hekate's built-in will be used.

706
bootloader/config/config.c Normal file
View File

@@ -0,0 +1,706 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdlib.h>
#include "../utils/btn.h"
#include "config.h"
#include "../libs/fatfs/ff.h"
#include "ini.h"
#include "../utils/list.h"
#include "../gfx/tui.h"
#include "../utils/util.h"
#include "../gfx/gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
extern hekate_config h_cfg;
extern int sd_mount();
extern int sd_unmount();
void set_default_configuration()
{
h_cfg.autoboot = 0;
h_cfg.autoboot_list = 0;
h_cfg.bootwait = 3;
h_cfg.customlogo = 0;
h_cfg.verification = 2;
h_cfg.se_keygen_done = 0;
h_cfg.sbar_time_keeping = 0;
h_cfg.backlight = 100;
h_cfg.autohosoff = 1;
h_cfg.errors = 0;
}
int create_config_entry()
{
if (!sd_mount())
return 1;
char lbuf[16];
FIL fp;
bool mainIniFound = false;
LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
mainIniFound = true;
else
{
u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ);
if (res == FR_NO_FILE || res == FR_NO_PATH)
{
f_mkdir("bootloader");
f_mkdir("bootloader/ini");
f_mkdir("bootloader/payloads");
f_mkdir("bootloader/sys");
}
else
{
if (!res)
f_close(&fp);
return 1;
}
}
if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
return 1;
// Add config entry.
f_puts("[config]\nautoboot=", &fp);
itoa(h_cfg.autoboot, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nautoboot_list=", &fp);
itoa(h_cfg.autoboot_list, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nbootwait=", &fp);
itoa(h_cfg.bootwait, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\ncustomlogo=", &fp);
itoa(h_cfg.customlogo, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nverification=", &fp);
itoa(h_cfg.verification, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nbacklight=", &fp);
itoa(h_cfg.backlight, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nautohosoff=", &fp);
itoa(h_cfg.autohosoff, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\n", &fp);
if (mainIniFound)
{
// Re-construct existing entries.
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
if (!strcmp(ini_sec->name, "config"))
continue;
switch (ini_sec->type)
{
case INI_CHOICE: // Re-construct Boot entry [ ].
f_puts("[", &fp);
f_puts(ini_sec->name, &fp);
f_puts("]\n", &fp);
// Re-construct boot entry's config.
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
f_puts(kv->key, &fp);
f_puts("=", &fp);
f_puts(kv->val, &fp);
f_puts("\n", &fp);
}
break;
case INI_CAPTION: // Re-construct caption entry { }.
f_puts("{", &fp);
f_puts(ini_sec->name, &fp);
f_puts("}\n", &fp);
break;
case INI_NEWLINE: // Re-construct cosmetic newline \n.
f_puts("\n", &fp);
break;
case INI_COMMENT: // Re-construct comment entry #.
f_puts("#", &fp);
f_puts(ini_sec->name, &fp);
f_puts("\n", &fp);
break;
}
}
}
f_close(&fp);
sd_unmount();
if (mainIniFound)
ini_free(&ini_sections);
return 0;
}
void _config_autoboot_list()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
u32 *temp_autoboot = NULL;
LIST_INIT(ini_sections);
u8 max_entries = 30;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
char *boot_text = (char *)malloc(512 * max_entries);
for (u32 j = 0; j < max_entries; j++)
boot_values[j] = j;
if (sd_mount())
{
if (ini_parse(&ini_sections, "bootloader/ini", true))
{
// Build configuration menu.
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
u32 i = 2;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
// Skip other ini entries for autoboot.
if (ini_sec->type == INI_CHOICE)
{
if (!strcmp(ini_sec->name, "config"))
continue;
if (strlen(ini_sec->name) > 510)
ments[i].caption = ini_sec->name;
else
{
if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list)
boot_text[(i - 1) * 512] = ' ';
else
boot_text[(i - 1) * 512] = '*';
memcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1);
boot_text[strlen(ini_sec->name) + (i - 1) * 512 + 1] = 0;
ments[i].caption = &boot_text[(i - 1) * 512];
}
ments[i].type = ini_sec->type;
ments[i].data = &boot_values[i - 1];
i++;
if ((i - 1) > max_entries)
break;
}
}
memset(&ments[i], 0, sizeof(ment_t));
menu_t menu = {ments, "Select a list entry to auto boot", 0, 0};
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_autoboot != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.autoboot = *(u32 *)temp_autoboot;
h_cfg.autoboot_list = 1;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
}
else
goto out2;
}
else
{
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists in SD Card!.");
goto out;
}
}
out:;
btn_wait();
out2:;
free(ments);
free(boot_values);
free(boot_text);
ini_free(&ini_sections);
sd_unmount();
if (temp_autoboot == NULL)
return;
}
void config_autoboot()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
u32 *temp_autoboot = NULL;
LIST_INIT(ini_sections);
u8 max_entries = 30;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5));
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
char *boot_text = (char *)malloc(512 * max_entries);
for (u32 j = 0; j < max_entries; j++)
boot_values[j] = j;
if (sd_mount())
{
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
{
// Build configuration menu.
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
ments[2].type = MENT_DATA;
if (!h_cfg.autoboot)
ments[2].caption = "*Disable";
else
ments[2].caption = " Disable";
ments[2].data = &boot_values[0];
ments[3].type = MENT_HANDLER;
if (h_cfg.autoboot_list)
ments[3].caption = "*More configs...";
else
ments[3].caption = " More configs...";
ments[3].handler = _config_autoboot_list;
ments[3].data = NULL;
ments[4].type = MENT_CHGLINE;
u32 i = 5;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
// Skip other ini entries for autoboot.
if (ini_sec->type == INI_CHOICE)
{
if (!strcmp(ini_sec->name, "config"))
continue;
if (strlen(ini_sec->name) > 510)
ments[i].caption = ini_sec->name;
else
{
if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list)
boot_text[(i - 4) * 512] = ' ';
else
boot_text[(i - 4) * 512] = '*';
memcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1);
boot_text[strlen(ini_sec->name) + (i - 4) * 512 + 1] = 0;
ments[i].caption = &boot_text[(i - 4) * 512];
}
ments[i].type = ini_sec->type;
ments[i].data = &boot_values[i - 4];
i++;
if ((i - 4) > max_entries)
break;
}
}
if (i < 6 && !h_cfg.autoboot_list)
{
ments[i].type = MENT_CAPTION;
ments[i].caption = "No main configurations found...";
ments[i].color = 0xFFFFDD00;
i++;
}
memset(&ments[i], 0, sizeof(ment_t));
menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0};
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_autoboot != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.autoboot = *(u32 *)temp_autoboot;
h_cfg.autoboot_list = 0;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
}
else
goto out2;
}
else
{
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists in SD Card!.");
goto out;
}
}
out:;
btn_wait();
out2:;
free(ments);
free(boot_values);
free(boot_text);
ini_free(&ini_sections);
sd_unmount();
if (temp_autoboot == NULL)
return;
}
void config_bootdelay()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
u32 delay_entries = 6;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3));
u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries);
char *delay_text = (char *)malloc(32 * delay_entries);
for (u32 j = 0; j < delay_entries; j++)
delay_values[j] = j;
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
ments[2].type = MENT_DATA;
if (h_cfg.bootwait)
ments[2].caption = " 0 seconds (Bootlogo disabled)";
else
ments[2].caption = "*0 seconds (Bootlogo disabled)";
ments[2].data = &delay_values[0];
u32 i = 0;
for (i = 1; i < delay_entries; i++)
{
if (h_cfg.bootwait != i)
delay_text[i * 32] = ' ';
else
delay_text[i * 32] = '*';
delay_text[i * 32 + 1] = i + '0';
memcpy(delay_text + i * 32 + 2, " seconds", 9);
ments[i + 2].type = MENT_DATA;
ments[i + 2].caption = delay_text + i * 32;
ments[i + 2].data = &delay_values[i];
}
memset(&ments[i + 2], 0, sizeof(ment_t));
menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0};
u32 *temp_bootwait = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_bootwait != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.bootwait = *(u32 *)temp_bootwait;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
}
free(ments);
free(delay_values);
free(delay_text);
if (temp_bootwait == NULL)
return;
btn_wait();
}
void config_customlogo()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
for (u32 j = 0; j < 2; j++)
{
cb_values[j] = j;
ments[j + 2].type = MENT_DATA;
ments[j + 2].data = &cb_values[j];
}
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
if (h_cfg.customlogo)
{
ments[2].caption = " Disable";
ments[3].caption = "*Enable";
}
else
{
ments[2].caption = "*Disable";
ments[3].caption = " Enable";
}
memset(&ments[4], 0, sizeof(ment_t));
menu_t menu = {ments, "Custom bootlogo", 0, 0};
u32 *temp_customlogo = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_customlogo != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.customlogo = *(u32 *)temp_customlogo;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
}
free(ments);
free(cb_values);
if (temp_customlogo == NULL)
return;
btn_wait();
}
void config_verification()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3);
char *vr_text = (char *)malloc(64 * 3);
for (u32 j = 0; j < 3; j++)
{
vr_values[j] = j;
ments[j + 2].type = MENT_DATA;
ments[j + 2].data = &vr_values[j];
}
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
memcpy(vr_text, " Disable (Fastest)", 19);
memcpy(vr_text + 64, " Sparse (Fast - Not reliable)", 32);
memcpy(vr_text + 128, " Full (Slow - 100% reliable)", 32);
for (u32 i = 0; i < 3; i++)
{
if (h_cfg.verification != i)
{
vr_text[64 * i] = ' ';
ments[2 + i].caption = vr_text + (i * 64);
}
else
{
vr_text[64 * i] = '*';
ments[2 + i].caption = vr_text + (i * 64);
}
}
memset(&ments[5], 0, sizeof(ment_t));
menu_t menu = {ments, "Backup & Restore verification", 0, 0};
u32 *temp_verification = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_verification != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.verification = *(u32 *)temp_verification;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
}
free(ments);
free(vr_values);
free(vr_text);
if (temp_verification == NULL)
return;
btn_wait();
}
void config_backlight()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
u32 bri_entries = 11;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3));
u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries);
char *bri_text = (char *)malloc(8 * bri_entries);
for (u32 j = 1; j < bri_entries; j++)
bri_values[j] = j * 10;
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
u32 i = 0;
for (i = 1; i < bri_entries; i++)
{
if ((h_cfg.backlight / 20) != i)
bri_text[i * 32] = ' ';
else
bri_text[i * 32] = '*';
if (i < 10)
{
bri_text[i * 32 + 1] = i + '0';
memcpy(bri_text + i * 32 + 2, "0%", 3);
}
else
memcpy(bri_text + i * 32 + 1, "100%", 5);
ments[i + 1].type = MENT_DATA;
ments[i + 1].caption = bri_text + i * 32;
ments[i + 1].data = &bri_values[i];
}
memset(&ments[i + 1], 0, sizeof(ment_t));
menu_t menu = {ments, "Backlight brightness", 0, 0};
u32 *temp_backlight = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_backlight != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
//Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
}
free(ments);
free(bri_values);
free(bri_text);
if (temp_backlight == NULL)
return;
btn_wait();
}
void config_auto_hos_poweroff()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
for (u32 j = 0; j < 3; j++)
{
hp_values[j] = j;
ments[j + 2].type = MENT_DATA;
ments[j + 2].data = &hp_values[j];
}
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
if (h_cfg.autohosoff == 1)
{
ments[2].caption = " Disable";
ments[3].caption = "*Enable";
ments[4].caption = " Enable (No logo)";
}
else if (h_cfg.autohosoff >= 2)
{
ments[2].caption = " Disable";
ments[3].caption = " Enable";
ments[4].caption = "*Enable (No logo)";
}
else
{
ments[2].caption = "*Disable";
ments[3].caption = " Enable";
ments[4].caption = " Enable (No logo)";
}
memset(&ments[5], 0, sizeof(ment_t));
menu_t menu = {ments, "Power off if woke up from HOS", 0, 0};
u32 *temp_autohosoff = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_autohosoff != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
}
free(ments);
free(hp_values);
if (temp_autohosoff == NULL)
return;
btn_wait();
}

View File

@@ -0,0 +1,52 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include "../utils/types.h"
typedef struct _hekate_config
{
// Non-volatile config.
u32 autoboot;
u32 autoboot_list;
u32 bootwait;
u32 customlogo;
u32 verification;
u32 backlight;
u32 autohosoff;
u32 errors;
// Global temporary config.
int se_keygen_done;
u32 sbar_time_keeping;
} hekate_config;
typedef enum
{
ERR_LIBSYS_LP0 = (1 << 0),
} hsysmodule_t;
void set_default_configuration();
int create_config_entry();
void config_autoboot();
void config_bootdelay();
void config_customlogo();
void config_verification();
void config_backlight();
void config_auto_hos_poweroff();
#endif /* _CONFIG_H_ */

260
bootloader/config/ini.c Normal file
View File

@@ -0,0 +1,260 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "ini.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../utils/dirlist.h"
static char *_strdup(char *str)
{
char *res = (char *)malloc(strlen(str) + 1);
strcpy(res, str);
return res;
}
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
{
u32 lblen;
u32 pathlen = strlen(ini_path);
u32 k = 0;
char lbuf[512];
char *filelist = NULL;
FIL fp;
ini_sec_t *csec = NULL;
char *filename = (char *)malloc(256);
memcpy(filename, ini_path, pathlen + 1);
if (is_dir)
{
filelist = dirlist(filename, "*.ini", false);
if (!filelist)
{
free(filename);
return 0;
}
memcpy(filename + pathlen, "/", 2);
pathlen++;
}
do
{
if (is_dir)
{
if (filelist[k * 256])
{
memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1);
k++;
}
else
break;
}
if (f_open(&fp, filename, FA_READ) != FR_OK)
{
free(filelist);
free(filename);
return 0;
}
do
{
// Fetch one line.
lbuf[0] = 0;
f_gets(lbuf, 512, &fp);
lblen = strlen(lbuf);
// Remove trailing newline.
if (lbuf[lblen - 1] == '\n')
lbuf[lblen - 1] = 0;
if (lblen > 2 && lbuf[0] == '[') // Create new section.
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != ']'; i++)
;
lbuf[i] = 0;
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = _strdup(&lbuf[1]);
csec->type = INI_CHOICE;
list_init(&csec->kvs);
}
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '}'; i++)
;
lbuf[i] = 0;
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = _strdup(&lbuf[1]);
csec->type = INI_CAPTION;
csec->color = 0xFF0AB9E6;
}
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n'; i++)
;
lbuf[i] = 0;
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = _strdup(&lbuf[1]);
csec->type = INI_COMMENT;
}
else if (lblen < 2)
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = NULL;
csec->type = INI_NEWLINE;
}
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
{
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '='; i++)
;
lbuf[i] = 0;
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
kv->key = _strdup(&lbuf[0]);
kv->val = _strdup(&lbuf[i + 1]);
list_append(&csec->kvs, &kv->link);
}
} while (!f_eof(&fp));
f_close(&fp);
if (csec)
list_append(dst, &csec->link);
} while (is_dir);
free(filename);
free(filelist);
return 1;
}
void ini_free(link_t *dst)
{
if (!dst->prev || !dst->next)
return;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, dst, link)
{
if (ini_sec->type == INI_CHOICE)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
free(kv->key);
free(kv->val);
//free(kv);
}
}
free(ini_sec->name);
//free(ini_sec);
}
list_init(dst);
}
ini_sec_t *ini_clone_section(ini_sec_t *cfg)
{
if (cfg == NULL)
return NULL;
ini_sec_t *csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
list_init(&csec->kvs);
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
ini_kv_t *kvcfg = (ini_kv_t *)malloc(sizeof(ini_kv_t));
kvcfg->key = _strdup(kv->key);
kvcfg->val = _strdup(kv->val);
list_append(&csec->kvs, &kvcfg->link);
}
return csec;
}
void ini_free_section(ini_sec_t *cfg)
{
if (cfg == NULL)
return;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
free(kv->key);
free(kv->val);
//free(kv);
}
//free(cfg);
cfg = NULL;
}
char *ini_check_payload_section(ini_sec_t *cfg)
{
char *path = NULL;
if (cfg == NULL)
return NULL;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
if (!strcmp("payload", kv->key))
{
if (!path)
path = _strdup(kv->val);
}
}
if (path)
return path;
else
return NULL;
}

53
bootloader/config/ini.h Normal file
View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _INI_H_
#define _INI_H_
#include "../utils/types.h"
#include "../utils/list.h"
#define INI_CHOICE 3
#define INI_CAPTION 5
#define INI_CHGLINE 6
#define INI_NEWLINE 0xFE
#define INI_COMMENT 0xFF
typedef struct _ini_kv_t
{
char *key;
char *val;
link_t link;
} ini_kv_t;
typedef struct _ini_sec_t
{
char *name;
link_t kvs;
link_t link;
u32 type;
u32 color;
} ini_sec_t;
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
void ini_free(link_t *dst);
ini_sec_t *ini_clone_section(ini_sec_t *cfg);
void ini_free_section(ini_sec_t *cfg);
char *ini_check_payload_section(ini_sec_t *cfg);
#endif

View File

@@ -0,0 +1,884 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 Rajko Stojadinovic
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdlib.h>
#include "fe_emmc_tools.h"
#include "../config/config.h"
#include "../gfx/gfx.h"
#include "../gfx/tui.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/util.h"
extern sdmmc_t sd_sdmmc;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
extern hekate_config h_cfg;
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern bool sd_mount();
extern void sd_unmount();
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
{
FIL fp;
u32 btn = 0;
u32 prevPct = 200;
int res = 0;
u8 hashEm[0x20];
u8 hashSd[0x20];
if (f_open(&fp, outFilename, FA_READ) == FR_OK)
{
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
u32 numSectorsPerIter = 0;
if (totalSectorsVer > 0x200000)
numSectorsPerIter = 8192; //4MB Cache
else
numSectorsPerIter = 512; //256KB Cache
u8 *bufEm = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u8 *bufSd = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
u32 num = 0;
while (totalSectorsVer > 0)
{
num = MIN(totalSectorsVer, numSectorsPerIter);
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
num, lba_curr);
free(bufEm);
free(bufSd);
f_close(&fp);
return 1;
}
if (f_read(&fp, bufSd, num << 9, NULL))
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
free(bufEm);
free(bufSd);
f_close(&fp);
return 1;
}
switch (h_cfg.verification)
{
case 1:
res = memcmp32sparse((u32 *)bufEm, (u32 *)bufSd, num << 9);
break;
case 2:
default:
se_calc_sha256(&hashEm, bufEm, num << 9);
se_calc_sha256(&hashSd, bufSd, num << 9);
res = memcmp(hashEm, hashSd, 0x10);
break;
}
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nSD card and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
free(bufEm);
free(bufSd);
f_close(&fp);
return 1;
}
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
prevPct = pct;
}
lba_curr += num;
totalSectorsVer -= num;
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
{
gfx_con.fntsz = 16;
WPRINTF("\n\nThe verification was cancelled!");
EPRINTF("\nPress any key...\n");
msleep(1500);
free(bufEm);
free(bufSd);
f_close(&fp);
return 0;
}
}
free(bufEm);
free(bufSd);
f_close(&fp);
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
return 0;
}
else
{
gfx_con.fntsz = 16;
EPRINTF("\nFile not found or could not be loaded.\n\nVerification failed..\n");
return 1;
}
}
int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
{
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
static const u32 SECTORS_TO_MIB_COEFF = 11;
u32 multipartSplitSize = (1u << 31);
u32 totalSectors = part->lba_end - part->lba_start + 1;
u32 currPartIdx = 0;
u32 numSplitParts = 0;
u32 maxSplitParts = 0;
u32 btn = 0;
bool isSmallSdCard = false;
bool partialDumpInProgress = false;
int res = 0;
char *outFilename = sd_path;
u32 sdPathLen = strlen(sd_path);
FIL partialIdxFp;
char partialIdxFilename[12];
memcpy(partialIdxFilename, "partial.idx", 12);
gfx_con.fntsz = 8;
gfx_printf(&gfx_con, "\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF,
totalSectors >> SECTORS_TO_MIB_COEFF);
// 1GB parts for sd cards 8GB and less.
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
multipartSplitSize = (1u << 30);
// Maximum parts fitting the free space available.
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / 512);
// Check if the USER partition or the RAW eMMC fits the sd card free space.
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
{
isSmallSdCard = true;
gfx_printf(&gfx_con, "%k\nSD card free space is smaller than total backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC);
if (!maxSplitParts)
{
gfx_con.fntsz = 16;
EPRINTF("Not enough free space for Partial Backup.");
return 0;
}
}
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
{
gfx_printf(&gfx_con, "%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
partialDumpInProgress = true;
// Force partial dumping, even if the card is larger.
isSmallSdCard = true;
f_read(&partialIdxFp, &currPartIdx, 4, NULL);
f_close(&partialIdxFp);
if (!maxSplitParts)
{
gfx_con.fntsz = 16;
EPRINTF("Not enough free space for Partial Backup.");
return 0;
}
// Increase maxSplitParts to accommodate previously backed up parts.
maxSplitParts += currPartIdx;
}
else if (isSmallSdCard)
gfx_printf(&gfx_con, "%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) | isSmallSdCard)
{
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
outFilename[sdPathLen++] = '.';
if (!partialDumpInProgress)
{
outFilename[sdPathLen] = '0';
if (numSplitParts >= 10)
{
outFilename[sdPathLen + 1] = '0';
outFilename[sdPathLen + 2] = 0;
}
else
outFilename[sdPathLen + 1] = 0;
}
// Continue from where we left, if Partial Backup in progress.
else
{
if (numSplitParts >= 10 && currPartIdx < 10)
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
}
}
FIL fp;
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
if (!f_open(&fp, outFilename, FA_READ))
{
f_close(&fp);
gfx_con.fntsz = 16;
WPRINTF("An existing backup has been detected!");
WPRINTF("Press POWER to Continue.\nPress VOL to go to the menu.\n");
msleep(500);
if (!(btn_wait() & BTN_POWER))
return 0;
gfx_con.fntsz = 8;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, gfx_con.savedy, 48);
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
return 0;
}
u32 numSectorsPerIter = 0;
if (totalSectors > 0x200000)
numSectorsPerIter = 8192;
else
numSectorsPerIter = 512;
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u32 lba_curr = part->lba_start;
u32 lbaStartPart = part->lba_start;
u32 bytesWritten = 0;
u32 prevPct = 200;
int retryCount = 0;
// Continue from where we left, if Partial Backup in progress.
if (partialDumpInProgress)
{
lba_curr += currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
lbaStartPart = lba_curr; // Update the start LBA for verification.
}
u64 totalSize = (u64)((u64)totalSectors << 9);
if (!isSmallSdCard && sd_fs.fs_type == FS_EXFAT)
f_lseek(&fp, totalSize);
else
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
f_lseek(&fp, 0);
u32 num = 0;
u32 pct = 0;
while (totalSectors > 0)
{
if (numSplitParts != 0 && bytesWritten >= multipartSplitSize)
{
f_close(&fp);
memset(&fp, 0, sizeof(fp));
currPartIdx++;
if (h_cfg.verification)
{
// Verify part.
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
{
EPRINTF("\nPress any key and try again...\n");
free(buf);
return 0;
}
}
if (numSplitParts >= 10 && currPartIdx < 10)
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
// Always create partial.idx before next part, in case a fatal error occurs.
if (isSmallSdCard)
{
// Create partial backup index file.
if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
{
f_write(&partialIdxFp, &currPartIdx, 4, NULL);
f_close(&partialIdxFp);
}
else
{
gfx_con.fntsz = 16;
EPRINTF("\nError creating partial.idx file.\n");
free(buf);
return 0;
}
// More parts to backup that do not currently fit the sd card free space or fatal error.
if (currPartIdx >= maxSplitParts)
{
gfx_puts(&gfx_con, "\n\n1. Press any key to unmount SD Card.\n\
2. Remove SD Card and move files to free space.\n\
Don\'t move the partial.idx file!\n\
3. Re-insert SD Card.\n\
4. Select the SAME option again to continue.\n");
gfx_con.fntsz = 16;
free(buf);
return 1;
}
}
// Create next part.
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
lbaStartPart = lba_curr;
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
free(buf);
return 0;
}
bytesWritten = 0;
totalSize = (u64)((u64)totalSectors << 9);
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
f_lseek(&fp, 0);
}
retryCount = 0;
num = MIN(totalSectors, numSectorsPerIter);
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
{
EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...",
num, lba_curr, ++retryCount);
msleep(150);
if (retryCount >= 3)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n",
num, lba_curr);
EPRINTF("\nPress any key and try again...\n");
free(buf);
f_close(&fp);
f_unlink(outFilename);
return 0;
}
}
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res);
EPRINTF("\nPress any key and try again...\n");
free(buf);
f_close(&fp);
f_unlink(outFilename);
return 0;
}
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
prevPct = pct;
}
lba_curr += num;
totalSectors -= num;
bytesWritten += num * NX_EMMC_BLOCKSIZE;
// Force a flush after a lot of data if not splitting.
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
{
f_sync(&fp);
bytesWritten = 0;
}
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
{
gfx_con.fntsz = 16;
WPRINTF("\n\nThe backup was cancelled!");
EPRINTF("\nPress any key...\n");
msleep(1500);
free(buf);
f_close(&fp);
f_unlink(outFilename);
return 0;
}
}
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Backup operation ended successfully.
free(buf);
f_close(&fp);
if (h_cfg.verification)
{
// Verify last part or single file backup.
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
{
EPRINTF("\nPress any key and try again...\n");
return 0;
}
else
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
}
gfx_con.fntsz = 16;
// Remove partial backup index file if no fatal errors occurred.
if (isSmallSdCard)
{
f_unlink(partialIdxFilename);
gfx_printf(&gfx_con, "%k\n\nYou can now join the files\nand get the complete eMMC RAW GPP backup.", 0xFFCCCCCC);
}
gfx_puts(&gfx_con, "\n\n");
return 1;
}
typedef enum
{
PART_BOOT = (1 << 0),
PART_SYSTEM = (1 << 1),
PART_USER = (1 << 2),
PART_RAW = (1 << 3),
PART_GP_ALL = (1 << 7)
} emmcPartType_t;
static void _dump_emmc_selected(emmcPartType_t dumpType)
{
int res = 0;
u32 timer = 0;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
tui_sbar(&gfx_con, true);
gfx_con_setpos(&gfx_con, 0, 0);
if (!sd_mount())
goto out;
gfx_puts(&gfx_con, "Checking for available free space...\n\n");
// Get SD Card free space for Partial Backup.
f_getfree("", &sd_fs.free_clst, NULL);
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out;
}
int i = 0;
char sdPath[80];
// Create Restore folders, if they do not exist.
emmcsn_path_impl(sdPath, "/restore", "", &storage);
emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage);
timer = get_tmr_s();
if (dumpType & PART_BOOT)
{
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
emmc_part_t bootPart;
memset(&bootPart, 0, sizeof(bootPart));
bootPart.lba_start = 0;
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
for (i = 0; i < 2; i++)
{
memcpy(bootPart.name, "BOOT", 5);
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, i + 1);
emmcsn_path_impl(sdPath, "", bootPart.name, &storage);
res = _dump_emmc_part(sdPath, &storage, &bootPart);
}
}
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW))
{
sdmmc_storage_set_mmc_partition(&storage, 0);
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER))
{
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER"))
continue;
if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER"))
continue;
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/partitions", part->name, &storage);
res = _dump_emmc_part(sdPath, &storage, part);
// If a part failed, don't continue.
if (!res)
break;
}
nx_emmc_gpt_free(&gpt);
}
if (dumpType & PART_RAW)
{
// Get GP partition size dynamically.
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
emmc_part_t rawPart;
memset(&rawPart, 0, sizeof(rawPart));
rawPart.lba_start = 0;
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
strcpy(rawPart.name, "rawnand.bin");
{
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "", rawPart.name, &storage);
res = _dump_emmc_part(sdPath, &storage, &rawPart);
}
}
}
gfx_putc(&gfx_con, '\n');
timer = get_tmr_s() - timer;
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
sdmmc_storage_end(&storage);
if (res && h_cfg.verification)
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
else if (res)
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
out:
sd_unmount();
btn_wait();
}
void dump_emmc_system() { _dump_emmc_selected(PART_SYSTEM); }
void dump_emmc_user() { _dump_emmc_selected(PART_USER); }
void dump_emmc_boot() { _dump_emmc_selected(PART_BOOT); }
void dump_emmc_rawnand() { _dump_emmc_selected(PART_RAW); }
int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
{
static const u32 SECTORS_TO_MIB_COEFF = 11;
u32 totalSectors = part->lba_end - part->lba_start + 1;
u32 lbaStartPart = part->lba_start;
int res = 0;
char *outFilename = sd_path;
gfx_con.fntsz = 8;
FIL fp;
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
res = f_open(&fp, outFilename, FA_READ);
if (res)
{
WPRINTFARGS("Error (%d) while opening backup. Continuing...\n", res);
gfx_con.fntsz = 16;
return 0;
}
//TODO: Should we keep this check?
else if (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)
{
gfx_con.fntsz = 16;
EPRINTF("Size of the SD Card backup does not match,\neMMC's selected part size.\n");
f_close(&fp);
return 0;
}
else
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n", ((u32)((u64)f_size(&fp) >> (u64)9)) >> SECTORS_TO_MIB_COEFF);
u32 numSectorsPerIter = 0;
if (totalSectors > 0x200000)
numSectorsPerIter = 8192; //4MB Cache
else
numSectorsPerIter = 512; //256KB Cache
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u32 lba_curr = part->lba_start;
u32 bytesWritten = 0;
u32 prevPct = 200;
int retryCount = 0;
u32 num = 0;
u32 pct = 0;
while (totalSectors > 0)
{
retryCount = 0;
num = MIN(totalSectors, numSectorsPerIter);
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFatal error (%d) when reading from SD Card", res);
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again now...\n");
free(buf);
f_close(&fp);
return 0;
}
while (!sdmmc_storage_write(storage, lba_curr, num, buf))
{
EPRINTFARGS("Error writing %d blocks @ LBA %08X\nto eMMC (try %d), retrying...",
num, lba_curr, ++retryCount);
msleep(150);
if (retryCount >= 3)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to write %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n",
num, lba_curr);
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n");
free(buf);
f_close(&fp);
return 0;
}
}
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
prevPct = pct;
}
lba_curr += num;
totalSectors -= num;
bytesWritten += num * NX_EMMC_BLOCKSIZE;
}
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Restore operation ended successfully.
free(buf);
f_close(&fp);
if (h_cfg.verification)
{
// Verify restored data.
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
{
EPRINTF("\nPress any key and try again...\n");
return 0;
}
else
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
}
gfx_con.fntsz = 16;
gfx_puts(&gfx_con, "\n\n");
return 1;
}
static void _restore_emmc_selected(emmcPartType_t restoreType)
{
int res = 0;
u32 timer = 0;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
tui_sbar(&gfx_con, true);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%kThis is a dangerous operation\nand may render your device inoperative!\n\n", 0xFFFFDD00);
gfx_printf(&gfx_con, "Are you really sure?\n\n%k", 0xFFCCCCCC);
if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))
{
gfx_puts(&gfx_con, "The mode you selected will only restore\nthe ");
if (restoreType & PART_BOOT)
gfx_puts(&gfx_con, "boot ");
gfx_puts(&gfx_con, "partitions that it can find.\n");
gfx_puts(&gfx_con, "If it is not found, it will be skipped\nand continue with the next.\n\n");
}
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
u8 value = 10;
while (value > 0)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
msleep(1000);
value--;
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_puts(&gfx_con, "Press POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
u32 btn = btn_wait();
if (!(btn & BTN_POWER))
goto out;
if (!sd_mount())
goto out;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out;
}
int i = 0;
char sdPath[80];
timer = get_tmr_s();
if (restoreType & PART_BOOT)
{
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
emmc_part_t bootPart;
memset(&bootPart, 0, sizeof(bootPart));
bootPart.lba_start = 0;
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
for (i = 0; i < 2; i++)
{
memcpy(bootPart.name, "BOOT", 4);
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, i + 1);
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage);
res = _restore_emmc_part(sdPath, &storage, &bootPart);
}
}
if (restoreType & PART_GP_ALL)
{
sdmmc_storage_set_mmc_partition(&storage, 0);
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
res = _restore_emmc_part(sdPath, &storage, part);
}
nx_emmc_gpt_free(&gpt);
}
if (restoreType & PART_RAW)
{
// Get GP partition size dynamically.
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
emmc_part_t rawPart;
memset(&rawPart, 0, sizeof(rawPart));
rawPart.lba_start = 0;
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
strcpy(rawPart.name, "rawnand.bin");
{
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
res = _restore_emmc_part(sdPath, &storage, &rawPart);
}
}
gfx_putc(&gfx_con, '\n');
timer = get_tmr_s() - timer;
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
sdmmc_storage_end(&storage);
if (res && h_cfg.verification)
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
else if (res)
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
out:
sd_unmount();
btn_wait();
}
void restore_emmc_boot() { _restore_emmc_selected(PART_BOOT); }
void restore_emmc_rawnand() { _restore_emmc_selected(PART_RAW); }
void restore_emmc_gpp_parts() { _restore_emmc_selected(PART_GP_ALL); }

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2018 Rajko Stojadinovic
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _FE_EMMC_TOOLS_H_
#define _FE_EMMC_TOOLS_H_
void dump_emmc_system();
void dump_emmc_user();
void dump_emmc_boot();
void dump_emmc_rawnand();
void restore_emmc_boot();
void restore_emmc_rawnand();
void restore_emmc_gpp_parts();
#endif

View File

@@ -0,0 +1,706 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* 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 "fe_info.h"
#include "../gfx/gfx.h"
#include "../hos/hos.h"
#include "../hos/pkg1.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../power/bq24193.h"
#include "../power/max17050.h"
#include "../sec/tsec.h"
#include "../soc/fuse.h"
#include "../soc/i2c.h"
#include "../soc/kfuse.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../storage/mmc.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/util.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
extern bool sd_mount();
extern void sd_unmount();
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
void print_fuseinfo()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
u32 burntFuses = 0;
for (u32 i = 0; i < 32; i++)
{
if ((fuse_read_odm(7) >> i) & 1)
burntFuses++;
}
gfx_printf(&gfx_con, "\nSKU: %X - ", FUSE(FUSE_SKU_INFO));
switch (fuse_read_odm(4) & 3)
{
case 0:
gfx_printf(&gfx_con, "Retail\n");
break;
case 3:
gfx_printf(&gfx_con, "Dev\n");
break;
}
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
gfx_printf(&gfx_con, "Burnt fuses: %d\n", burntFuses);
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
gfx_puts(&gfx_con, "Press POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
emmcsn_path_impl(path, "/dumps", "fuses.bin", NULL);
if (!sd_save_to_file((u8 *)0x7000F900, 0x2FC, path))
gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
}
btn_wait();
}
}
void print_kfuseinfo()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%kKFuse contents:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
u32 buf[KFUSE_NUM_WORDS];
if (!kfuse_read(buf))
EPRINTF("CRC fail.");
else
gfx_hexdump(&gfx_con, 0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
if (!sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path))
gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
}
btn_wait();
}
}
void print_mmc_info()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
static const u32 SECTORS_TO_MIB_COEFF = 11;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out;
}
else
{
u16 card_type;
u32 speed = 0;
gfx_printf(&gfx_con, "%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
switch (storage.csd.mmca_vsn)
{
case 0: /* MMC v1.0 - v1.2 */
case 1: /* MMC v1.4 */
gfx_printf(&gfx_con,
" Vendor ID: %03X\n"
" Model: %c%c%c%c%c%c%c\n"
" HW rev: %X\n"
" FW rev: %X\n"
" S/N: %03X\n"
" Month/Year: %02d/%04d\n\n",
storage.cid.manfid,
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
storage.cid.prod_name[6], storage.cid.hwrev, storage.cid.fwrev,
storage.cid.serial, storage.cid.month, storage.cid.year);
break;
case 2: /* MMC v2.0 - v2.2 */
case 3: /* MMC v3.1 - v3.3 */
case 4: /* MMC v4 */
gfx_printf(&gfx_con,
" Vendor ID: %X\n"
" Card/BGA: %X\n"
" OEM ID: %02X\n"
" Model: %c%c%c%c%c%c\n"
" Prd Rev: %X\n"
" S/N: %04X\n"
" Month/Year: %02d/%04d\n\n",
storage.cid.manfid, storage.cid.card_bga, storage.cid.oemid,
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
storage.cid.prv, storage.cid.serial, storage.cid.month, storage.cid.year);
break;
default:
EPRINTFARGS("eMMC has unknown MMCA version %d", storage.csd.mmca_vsn);
break;
}
if (storage.csd.structure == 0)
EPRINTF("Unknown CSD structure.");
else
{
gfx_printf(&gfx_con, "%kExtended CSD V1.%d:%k\n",
0xFF00DDFF, storage.ext_csd.ext_struct, 0xFFCCCCCC);
card_type = storage.ext_csd.card_type;
u8 card_type_support[96];
u8 pos_type = 0;
card_type_support[0] = 0;
if (card_type & EXT_CSD_CARD_TYPE_HS_26)
{
memcpy(card_type_support, "HS26", 4);
speed = (26 << 16) | 26;
pos_type += 4;
}
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
{
memcpy(card_type_support + pos_type, ", HS52", 6);
speed = (52 << 16) | 52;
pos_type += 6;
}
if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
{
memcpy(card_type_support + pos_type, ", DDR52_1.8V", 12);
speed = (52 << 16) | 104;
pos_type += 12;
}
if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
{
memcpy(card_type_support + pos_type, ", HS200_1.8V", 12);
speed = (200 << 16) | 200;
pos_type += 12;
}
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
{
memcpy(card_type_support + pos_type, ", HS400_1.8V", 12);
speed = (200 << 16) | 400;
pos_type += 12;
}
card_type_support[pos_type] = 0;
gfx_printf(&gfx_con,
" Spec Version: %02X\n"
" Extended Rev: 1.%d\n"
" Dev Version: %d\n"
" Cmd Classes: %02X\n"
" Capacity: %s\n"
" Max Rate: %d MB/s (%d MHz)\n"
" Current Rate: %d MB/s\n"
" Type Support: ",
storage.csd.mmca_vsn, storage.ext_csd.rev, storage.ext_csd.dev_version, storage.csd.cmdclass,
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF,
storage.csd.busspeed);
gfx_con.fntsz = 8;
gfx_printf(&gfx_con, "%s", card_type_support);
gfx_con.fntsz = 16;
gfx_printf(&gfx_con, "\n\n", card_type_support);
u32 boot_size = storage.ext_csd.boot_mult << 17;
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
gfx_printf(&gfx_con, "%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf(&gfx_con, " 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
boot_size / 1024, boot_size / 1024 / 512);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, " 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
boot_size / 1024, boot_size / 1024 / 512);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, " 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
rpmb_size / 1024, rpmb_size / 1024 / 512);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, " 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC,
storage.sec_cnt >> SECTORS_TO_MIB_COEFF, storage.sec_cnt);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, "%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, 0);
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
int gpp_idx = 0;
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
gfx_printf(&gfx_con, " %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X)\n LBA Range: %08X-%08X\n",
gpp_idx++, 0xFFAEFD14, part->name, 0xFFCCCCCC, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);
gfx_put_small_sep(&gfx_con);
}
nx_emmc_gpt_free(&gpt);
}
}
out:
sdmmc_storage_end(&storage);
btn_wait();
}
void print_sdcard_info()
{
static const u32 SECTORS_TO_MIB_COEFF = 11;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
if (sd_mount())
{
u32 capacity;
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf(&gfx_con,
" Vendor ID: %02x\n"
" OEM ID: %c%c\n"
" Model: %c%c%c%c%c\n"
" HW rev: %X\n"
" FW rev: %X\n"
" S/N: %08x\n"
" Month/Year: %02d/%04d\n\n",
sd_storage.cid.manfid, (sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF,
sd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2],
sd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4],
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
sd_storage.cid.month, sd_storage.cid.year);
gfx_printf(&gfx_con, "%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC);
capacity = sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits);
gfx_printf(&gfx_con,
" Cmd Classes: %02X\n"
" Capacity: %d MiB\n"
" Bus Width: %d\n"
" Current Rate: %d MB/s (%d MHz)\n"
" Speed Class: %d\n"
" UHS Grade: U%d\n"
" Video Class: V%d\n"
" App perf class: A%d\n"
" Write Protect: %d\n\n",
sd_storage.csd.cmdclass, capacity,
sd_storage.ssr.bus_width, sd_storage.csd.busspeed, sd_storage.csd.busspeed * 2,
sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class,
sd_storage.ssr.app_class, sd_storage.csd.write_protect);
gfx_puts(&gfx_con, "Acquiring FAT volume info...\n\n");
f_getfree("", &sd_fs.free_clst, NULL);
gfx_printf(&gfx_con, "%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
0xFF00DDFF, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFCCCCCC,
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
sd_unmount();
}
btn_wait();
}
void print_tsec_key()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
u32 retries = 0;
u32 key_ver_max = 3;
tsec_ctxt_t tsec_ctxt;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
// Read package1.
u8 *pkg1 = (u8 *)malloc(0x40000);
sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
sdmmc_storage_end(&storage);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
if (!pkg1_id)
{
EPRINTFARGS("Unknown package1 version for reading\nTSEC firmware (= '%s').",
(char *)pkg1 + 0x10);
goto out_wait;
}
u8 keys[0x10 * 3];
tsec_ctxt.size = 0xF00;
tsec_ctxt.fw = (u8 *)pkg1 + pkg1_id->tsec_off;
tsec_ctxt.pkg1 = pkg1;
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
{
tsec_ctxt.size = 0x2900;
u8 *tsec_paged = (u8 *)page_alloc(3);
memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size);
tsec_ctxt.fw = tsec_paged;
key_ver_max = 1;
}
for (u32 i = 1; i <= key_ver_max; i++)
{
tsec_ctxt.key_ver = i;
int res = 0;
while (tsec_query(keys + ((i - 1) * 0x10), pkg1_id->kb, &tsec_ctxt) < 0)
{
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
memset(keys + ((i - 1) * 0x10), 0x00, 0x10);
else
memset(keys, 0x00, 0x30);
retries++;
if (retries > 3)
{
res = -1;
break;
}
}
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
{
gfx_printf(&gfx_con, "%kTSEC key %d: %k", 0xFF00DDFF, i, 0xFFCCCCCC);
if (res >= 0)
{
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[((i - 1) * 0x10) + j]);
}
else
EPRINTFARGS("ERROR %X", res);
gfx_putc(&gfx_con, '\n');
}
else
{
gfx_printf(&gfx_con, "%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
if (res >= 0)
{
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[j]);
gfx_putc(&gfx_con, '\n');
gfx_printf(&gfx_con, "%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[0x10 + j]);
}
else
EPRINTFARGS("ERROR %X", res);
gfx_putc(&gfx_con, '\n');
}
}
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL);
if (!sd_save_to_file(keys, 0x10 * 3, path))
gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
}
}
else
goto out;
out_wait:
btn_wait();
out:
free(pkg1);
}
void print_fuel_gauge_info()
{
int value = 0;
gfx_printf(&gfx_con, "%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
max17050_get_property(MAX17050_Age, &value);
gfx_printf(&gfx_con, "Age: %3d%\n", value);
max17050_get_property(MAX17050_RepSOC, &value);
gfx_printf(&gfx_con, "Capacity now: %3d%\n", value >> 8);
max17050_get_property(MAX17050_RepCap, &value);
gfx_printf(&gfx_con, "Capacity now: %4d mAh\n", value);
max17050_get_property(MAX17050_FullCAP, &value);
gfx_printf(&gfx_con, "Capacity full: %4d mAh\n", value);
max17050_get_property(MAX17050_DesignCap, &value);
gfx_printf(&gfx_con, "Capacity (design): %4d mAh\n", value);
max17050_get_property(MAX17050_Current, &value);
if (value >= 0)
gfx_printf(&gfx_con, "Current now: %d mA\n", value / 1000);
else
gfx_printf(&gfx_con, "Current now: -%d mA\n", ~value / 1000);
max17050_get_property(MAX17050_AvgCurrent, &value);
if (value >= 0)
gfx_printf(&gfx_con, "Current average: %d mA\n", value / 1000);
else
gfx_printf(&gfx_con, "Current average: -%d mA\n", ~value / 1000);
max17050_get_property(MAX17050_VCELL, &value);
gfx_printf(&gfx_con, "Voltage now: %4d mV\n", value);
max17050_get_property(MAX17050_OCVInternal, &value);
gfx_printf(&gfx_con, "Voltage open-circuit: %4d mV\n", value);
max17050_get_property(MAX17050_MinVolt, &value);
gfx_printf(&gfx_con, "Min voltage reached: %4d mV\n", value);
max17050_get_property(MAX17050_MaxVolt, &value);
gfx_printf(&gfx_con, "Max voltage reached: %4d mV\n", value);
max17050_get_property(MAX17050_V_empty, &value);
gfx_printf(&gfx_con, "Empty voltage (design): %4d mV\n", value);
max17050_get_property(MAX17050_TEMP, &value);
if (value >= 0)
gfx_printf(&gfx_con, "Battery temperature: %d.%d oC\n", value / 10, value % 10);
else
gfx_printf(&gfx_con, "Battery temperature: -%d.%d oC\n", ~value / 10, (~value) % 10);
}
void print_battery_charger_info()
{
int value = 0;
gfx_printf(&gfx_con, "%k\n\nBattery Charger IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
bq24193_get_property(BQ24193_InputVoltageLimit, &value);
gfx_printf(&gfx_con, "Input voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_InputCurrentLimit, &value);
gfx_printf(&gfx_con, "Input current limit: %4d mA\n", value);
bq24193_get_property(BQ24193_SystemMinimumVoltage, &value);
gfx_printf(&gfx_con, "Min voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);
gfx_printf(&gfx_con, "Fast charge current limit: %4d mA\n", value);
bq24193_get_property(BQ24193_ChargeVoltageLimit, &value);
gfx_printf(&gfx_con, "Charge voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_ChargeStatus, &value);
gfx_printf(&gfx_con, "Charge status: ");
switch (value)
{
case 0:
gfx_printf(&gfx_con, "Not charging\n");
break;
case 1:
gfx_printf(&gfx_con, "Pre-charging\n");
break;
case 2:
gfx_printf(&gfx_con, "Fast charging\n");
break;
case 3:
gfx_printf(&gfx_con, "Charge terminated\n");
break;
default:
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
break;
}
bq24193_get_property(BQ24193_TempStatus, &value);
gfx_printf(&gfx_con, "Temperature status: ");
switch (value)
{
case 0:
gfx_printf(&gfx_con, "Normal\n");
break;
case 2:
gfx_printf(&gfx_con, "Warm\n");
break;
case 3:
gfx_printf(&gfx_con, "Cool\n");
break;
case 5:
gfx_printf(&gfx_con, "Cold\n");
break;
case 6:
gfx_printf(&gfx_con, "Hot\n");
break;
default:
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
break;
}
}
void print_battery_info()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
print_fuel_gauge_info();
print_battery_charger_info();
u8 *buf = (u8 *)malloc(0x100 * 2);
gfx_printf(&gfx_con, "%k\n\nBattery Fuel Gauge Registers:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
for (int i = 0; i < 0x200; i += 2)
{
i2c_recv_buf_small(buf + i, 2, I2C_1, 0x36, i >> 1);
usleep(2500);
}
gfx_hexdump(&gfx_con, 0, (u8 *)buf, 0x200);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
emmcsn_path_impl(path, "/dumps", "fuel_gauge.bin", NULL);
if (sd_save_to_file((u8 *)buf, 0x200, path))
EPRINTF("\nError creating fuel.bin file.");
else
gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
}
btn_wait();
}
free(buf);
}
void _ipatch_process(u32 offset, u32 value)
{
gfx_printf(&gfx_con, "%8x %8x", BOOTROM_BASE + offset, value);
u8 lo = value & 0xff;
switch (value >> 8)
{
case 0xdf:
gfx_printf(&gfx_con, " svc #0x%02x", lo);
break;
case 0x20:
gfx_printf(&gfx_con, " movs r0, #0x%02x", lo);
break;
}
gfx_puts(&gfx_con, "\n");
}
void bootrom_ipatches_info()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
static const u32 BOOTROM_SIZE = 0x18000;
u32 res = fuse_read_ipatch(_ipatch_process);
if (res != 0)
EPRINTFARGS("Failed to read ipatches. Error: %d", res);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
u32 iram_evp_thunks[0x200];
u32 iram_evp_thunks_len = sizeof(iram_evp_thunks);
res = fuse_read_evp_thunk(iram_evp_thunks, &iram_evp_thunks_len);
if (res == 0)
{
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
if (!sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path))
gfx_puts(&gfx_con, "\nevp_thunks.bin saved!\n");
}
else
EPRINTFARGS("Failed to read evp_thunks. Error: %d", res);
u32 words[0x100];
read_raw_ipatch_fuses(words);
emmcsn_path_impl(path, "/dumps", "ipatches.bin", NULL);
if (!sd_save_to_file((u8 *)words, sizeof(words), path))
gfx_puts(&gfx_con, "\nipatches.bin saved!\n");
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts(&gfx_con, "\nbootrom_patched.bin saved!\n");
u8 ipatch_backup[13];
memcpy(ipatch_backup, (void *) IPATCH_BASE, 13);
memset((void*)IPATCH_BASE, 0, 13);
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts(&gfx_con, "\nbootrom_unpatched.bin saved!\n");
memcpy((void*)IPATCH_BASE, ipatch_backup, 13);
sd_unmount();
}
btn_wait();
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* 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/>.
*/
#ifndef _FE_INFO_H_
#define _FE_INFO_H_
void print_fuseinfo();
void print_kfuseinfo();
void print_mmc_info();
void print_sdcard_info();
void print_tsec_key();
void print_fuel_gauge_info();
void print_battery_charger_info();
void print_battery_info();
void bootrom_ipatches_info();
#endif

View File

@@ -0,0 +1,599 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 Reisyukaku
*
* 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 <stdlib.h>
#include "fe_tools.h"
#include "../config/config.h"
#include "../gfx/gfx.h"
#include "../gfx/tui.h"
#include "../hos/hos.h"
#include "../hos/pkg1.h"
#include "../hos/pkg2.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../power/max7762x.h"
#include "../sec/se.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/util.h"
extern hekate_config h_cfg;
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern sdmmc_storage_t sd_storage;
extern bool sd_mount();
extern void sd_unmount();
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
void dump_packages12()
{
if (!sd_mount())
return;
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
u8 *warmboot = (u8 *)calloc(1, 0x40000);
u8 *secmon = (u8 *)calloc(1, 0x40000);
u8 *loader = (u8 *)calloc(1, 0x40000);
u8 *pkg2 = NULL;
u8 kb = 0;
tsec_ctxt_t tsec_ctxt;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out_free;
}
sdmmc_storage_set_mmc_partition(&storage, 1);
// Read package1.
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
if (!pkg1_id)
{
gfx_con.fntsz = 8;
EPRINTFARGS("Unknown package1 version for reading\nTSEC firmware (= '%s').", (char *)pkg1 + 0x10);
goto out_free;
}
kb = pkg1_id->kb;
if (!h_cfg.se_keygen_done || kb >= KB_FIRMWARE_VERSION_620)
{
tsec_ctxt.key_ver = 1;
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
tsec_ctxt.pkg1 = (void *)pkg1;
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
// Read keyblob.
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
// Decrypt.
keygen(keyblob, kb, &tsec_ctxt);
h_cfg.se_keygen_done = 1;
free(keyblob);
}
if (kb <= KB_FIRMWARE_VERSION_600)
pkg1_decrypt(pkg1_id, pkg1);
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
// Display info.
gfx_printf(&gfx_con, "%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
gfx_printf(&gfx_con, "%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
gfx_printf(&gfx_con, "%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
gfx_printf(&gfx_con, "%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
gfx_printf(&gfx_con, "%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
char path[64];
// Dump package1.1.
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
if (sd_save_to_file(pkg1, 0x40000, path))
goto out_free;
gfx_puts(&gfx_con, "\nFull package1 dumped to pkg1_decr.bin\n");
// Dump nxbootloader.
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
if (sd_save_to_file(loader, hdr->ldr_size, path))
goto out_free;
gfx_puts(&gfx_con, "NX Bootloader dumped to nxloader.bin\n");
// Dump secmon.
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
if (sd_save_to_file(secmon, hdr->sm_size, path))
goto out_free;
gfx_puts(&gfx_con, "Secure Monitor dumped to secmon.bin\n");
// Dump warmboot.
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
if (sd_save_to_file(warmboot, hdr->wb_size, path))
goto out_free;
gfx_puts(&gfx_con, "Warmboot dumped to warmboot.bin\n\n\n");
// Dump package2.1.
sdmmc_storage_set_mmc_partition(&storage, 0);
// Parse eMMC GPT.
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
// Find package2 partition.
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
if (!pkg2_part)
goto out;
// Read in package2 header and get package2 real size.
u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp);
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
free(tmp);
// Read in package2.
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
pkg2 = malloc(pkg2_size_aligned);
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE,
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2);
// Display info.
u32 kernel_crc32 = crc32c(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
gfx_printf(&gfx_con, "\n%kKernel CRC32C: %k0x%08X\n\n", 0xFFC7EA46, 0xFFCCCCCC, kernel_crc32);
gfx_printf(&gfx_con, "%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
gfx_printf(&gfx_con, "%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]);
// Dump pkg2.1.
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage);
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
goto out;
gfx_puts(&gfx_con, "\nFull package2 dumped to pkg2_decr.bin\n");
// Dump kernel.
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
goto out;
gfx_puts(&gfx_con, "Kernel dumped to kernel.bin\n");
// Dump INI1.
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage);
if (sd_save_to_file(pkg2_hdr->data + pkg2_hdr->sec_size[PKG2_SEC_KERNEL],
pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
goto out;
gfx_puts(&gfx_con, "INI1 kip1 package dumped to ini1.bin\n");
gfx_puts(&gfx_con, "\nDone. Press any key...\n");
out:
nx_emmc_gpt_free(&gpt);
out_free:
free(pkg1);
free(secmon);
free(warmboot);
free(loader);
free(pkg2);
sdmmc_storage_end(&storage);
sd_unmount();
if (kb >= KB_FIRMWARE_VERSION_620)
se_aes_key_clear(8);
btn_wait();
}
void _toggle_autorcm(bool enable)
{
sdmmc_storage_t storage;
sdmmc_t sdmmc;
u8 randomXor = 0;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out;
}
u8 *tempbuf = (u8 *)malloc(0x200);
sdmmc_storage_set_mmc_partition(&storage, 1);
int i, sect = 0;
for (i = 0; i < 4; i++)
{
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
sdmmc_storage_read(&storage, sect, 1, tempbuf);
if (enable)
{
do
{
randomXor = get_tmr_us() & 0xFF; // Bricmii style of bricking.
} while (!randomXor); // Avoid the lottery.
tempbuf[0x10] ^= randomXor;
}
else
tempbuf[0x10] = 0xF7;
sdmmc_storage_write(&storage, sect, 1, tempbuf);
}
free(tempbuf);
sdmmc_storage_end(&storage);
if (enable)
gfx_printf(&gfx_con, "%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
else
gfx_printf(&gfx_con, "%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
gfx_printf(&gfx_con, "\n\nPress any key...\n");
out:
btn_wait();
}
void _enable_autorcm() { _toggle_autorcm(true); }
void _disable_autorcm() { _toggle_autorcm(false); }
void menu_autorcm()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
// Do a simple check on the main BCT.
sdmmc_storage_t storage;
sdmmc_t sdmmc;
bool disabled = true;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
btn_wait();
return;
}
u8 *tempbuf = (u8 *)malloc(0x200);
sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
if (tempbuf[0x10] != 0xF7)
disabled = false;
free(tempbuf);
sdmmc_storage_end(&storage);
// Create AutoRCM menu.
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
ments[2].type = MENT_CAPTION;
ments[3].type = MENT_CHGLINE;
if (disabled)
{
ments[2].caption = "Status: Disabled!";
ments[2].color = 0xFF96FF00;
ments[4].caption = "Enable AutoRCM";
ments[4].handler = _enable_autorcm;
}
else
{
ments[2].caption = "Status: Enabled!";
ments[2].color = 0xFFFFBA00;
ments[4].caption = "Disable AutoRCM";
ments[4].handler = _disable_autorcm;
}
ments[4].type = MENT_HDLR_RE;
memset(&ments[5], 0, sizeof(ment_t));
menu_t menu = {ments, "This corrupts your BOOT0!", 0, 0};
tui_do_menu(&gfx_con, &menu);
}
int _fix_attributes(char *path, u32 *total, u32 is_root, u32 check_first_run)
{
FRESULT res;
DIR dir;
u32 dirLength = 0;
static FILINFO fno;
if (check_first_run)
{
// Read file attributes.
res = f_stat(path, &fno);
if (res != FR_OK)
return res;
// Check if archive bit is set.
if (fno.fattrib & AM_ARC)
{
*(u32 *)total = *(u32 *)total + 1;
f_chmod(path, 0, AM_ARC);
}
}
// Open directory.
res = f_opendir(&dir, path);
if (res != FR_OK)
return res;
dirLength = strlen(path);
for (;;)
{
// Clear file or folder path.
path[dirLength] = 0;
// Read a directory item.
res = f_readdir(&dir, &fno);
// Break on error or end of dir.
if (res != FR_OK || fno.fname[0] == 0)
break;
// Skip official Nintendo dir.
if (is_root && !strcmp(fno.fname, "Nintendo"))
continue;
// Set new directory or file.
memcpy(&path[dirLength], "/", 1);
memcpy(&path[dirLength + 1], fno.fname, strlen(fno.fname) + 1);
// Check if archive bit is set.
if (fno.fattrib & AM_ARC)
{
*(u32 *)total = *(u32 *)total + 1;
f_chmod(path, 0, AM_ARC);
}
// Is it a directory?
if (fno.fattrib & AM_DIR)
{
// Enter the directory.
res = _fix_attributes(path, total, 0, 0);
if (res != FR_OK)
break;
}
}
f_closedir(&dir);
return res;
}
void _fix_sd_attr(u32 type)
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
char path[256];
char label[14];
u32 total = 0;
if (sd_mount())
{
switch (type)
{
case 0:
memcpy(path, "/", 2);
memcpy(label, "SD Card", 8);
break;
case 1:
default:
memcpy(path, "/switch", 8);
memcpy(label, "switch folder", 14);
break;
}
gfx_printf(&gfx_con, "Traversing all %s files!\nThis may take some time, please wait...\n\n", label);
_fix_attributes(path, &total, !type, type);
gfx_printf(&gfx_con, "%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
sd_unmount();
}
btn_wait();
}
void fix_sd_all_attr() { _fix_sd_attr(0); }
void fix_sd_switch_attr() { _fix_sd_attr(1); }
void fix_battery_desync()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
max77620_low_battery_monitor_config();
gfx_puts(&gfx_con, "\nDone!\n");
btn_wait();
}
/* void fix_fuel_gauge_configuration()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
int battVoltage, avgCurrent;
max17050_get_property(MAX17050_VCELL, &battVoltage);
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
// Check if still charging. If not, check if battery is >= 95% (4.1V).
if (avgCurrent < 0 && battVoltage > 4100)
{
if ((avgCurrent / 1000) < -10)
EPRINTF("You need to be connected to a wall adapter,\nto apply this fix!");
else
{
gfx_printf(&gfx_con, "%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00);
gfx_printf(&gfx_con, "Additionally this will power off your console.\n%k", 0xFFCCCCCC);
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
max17050_fix_configuration();
msleep(1000);
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
u16 value = 0;
gfx_printf(&gfx_con, "%kThe console will power off in 45 seconds.\n%k", 0xFFFFDD00, 0xFFCCCCCC);
while (value < 46)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%2ds elapsed", value);
msleep(1000);
value++;
}
msleep(2000);
power_off();
}
return;
}
}
else
EPRINTF("You need a fully charged battery\nand connected to a wall adapter,\nto apply this fix!");
msleep(500);
btn_wait();
} */
/*void reset_pmic_fuel_gauge_charger_config()
{
int avgCurrent;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%k\nThis will wipe your battery stats completely!\n"
"%kAnd it may not power on without physically\nremoving and re-inserting the battery.\n%k"
"\nAre you really sure?%k\n", 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC);
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
u8 value = 30;
while (value > 0)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
msleep(1000);
value--;
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
//Check if still connected.
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
if ((avgCurrent / 1000) < -10)
EPRINTF("You need to be connected to a wall adapter\nor PC to apply this fix!");
else
{
// Apply fix.
bq24193_fake_battery_removal();
gfx_printf(&gfx_con, "Done! \n"
"%k1. Remove the USB cable\n"
"2. Press POWER for 15s.\n"
"3. Reconnect the USB to power-on!%k\n", 0xFFFFDD00, 0xFFCCCCCC);
}
msleep(500);
btn_wait();
}
}*/
/*
//#include "../modules/hekate_libsys_minerva/mtc.h"
//mtc_config_t mtc_cfg;
void minerva()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
u32 curr_ram_idx = 0;
if (!sd_mount())
return;
gfx_printf(&gfx_con, "-- Minerva Training Cell --\n\n");
// Set table to ram.
mtc_cfg.mtc_table = NULL;
mtc_cfg.sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
gfx_printf(&gfx_con, "\nStarting training process..\n\n");
// Get current frequency
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
{
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg.mtc_table[curr_ram_idx].clk_src_emc)
break;
}
mtc_cfg.rate_from = mtc_cfg.mtc_table[curr_ram_idx].rate_khz;
mtc_cfg.rate_to = 800000;
mtc_cfg.train_mode = OP_TRAIN_SWITCH;
gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.mtc_table[curr_ram_idx].rate_khz, 800000);
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
// Thefollowing frequency needs periodic training every 100ms.
//msleep(200);
//mtc_cfg.rate_to = 1600000;
//gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
//ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
//mtc_cfg.train_mode = OP_PERIODIC_TRAIN;
sd_unmount();
gfx_printf(&gfx_con, "Finished!");
btn_wait();
}
*/

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _FE_TOOLS_H_
#define _FE_TOOLS_H_
void dump_packages12();
void fix_sd_all_attr();
void fix_sd_switch_attr();
void fix_battery_desync();
void menu_autorcm();
#endif

261
bootloader/gfx/di.c Normal file
View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "di.h"
#include "../soc/t210.h"
#include "../utils/util.h"
#include "../soc/i2c.h"
#include "../soc/pmc.h"
#include "../power/max77620.h"
#include "../soc/gpio.h"
#include "../soc/pinmux.h"
#include "../soc/clock.h"
#include "di.inl"
static u32 _display_ver = 0;
static void _display_dsi_wait(u32 timeout, u32 off, u32 mask)
{
u32 end = get_tmr_us() + timeout;
while (get_tmr_us() < end && DSI(off) & mask)
;
usleep(5);
}
void display_init()
{
// Power on.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO0_CFG, 0xD0); // Configure to 1.2V.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, 0x09);
// Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL) = 0xA;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA;
// DPD idle.
PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000;
PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000;
// Config pins.
PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE;
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); // Backlight +-5V.
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V.
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable.
usleep(10000);
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
usleep(10000);
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); // Backlight PWM, Enable, Reset.
gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE);
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable.
// Config display interface and display.
MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
usleep(10000);
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); // Backlight Reset enable.
usleep(60000);
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
DSI(_DSIREG(DSI_WR_DATA)) = 0x406; // MIPI_DCS_GET_DISPLAY_ID
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
_display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA);
usleep(5000);
_display_ver = DSI(_DSIREG(DSI_RD_DATA));
if (_display_ver == 0x10)
exec_cfg((u32 *)DSI_BASE, _display_config_4, 43);
DSI(_DSIREG(DSI_WR_DATA)) = 0x1105; // MIPI_DCS_EXIT_SLEEP_MODE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
usleep(180000);
DSI(_DSIREG(DSI_WR_DATA)) = 0x2905; // MIPI_DCS_SET_DISPLAY_ON
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
usleep(20000);
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
usleep(10000);
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
usleep(10000);
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
}
void display_backlight_pwm_init()
{
clock_enable_pwm();
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31); // Enable PWM
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source.
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
}
void display_backlight(bool enable)
{
gpio_write(GPIO_PORT_V, GPIO_PIN_0, enable ? GPIO_HIGH : GPIO_LOW); // Backlight PWM GPIO.
}
void display_backlight_brightness(u32 brightness, u32 step_delay)
{
u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR) >> 16) & 0xFF;
if (brightness == old_value)
return;
if (brightness > 255)
brightness = 255;
if (old_value < brightness)
{
for (u32 i = old_value; i < brightness + 1; i++)
{
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31) | (i << 16); // Enable PWM
usleep(step_delay);
}
}
else
{
for (u32 i = old_value; i > brightness; i--)
{
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31) | (i << 16); // Enable PWM
usleep(step_delay);
}
}
if (!brightness)
PWM(PWM_CONTROLLER_PWM_CSR) = 0;
}
void display_end()
{
display_backlight_brightness(0, 1000);
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 1;
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17);
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
usleep(10000);
if (_display_ver == 0x10)
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
DSI(_DSIREG(DSI_WR_DATA)) = 0x1005; // MIPI_DCS_ENTER_SLEEP_MODE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
usleep(50000);
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
usleep(10000);
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
usleep(10000);
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
usleep(10000);
// Disable clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000;
DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1;
}
void display_color_screen(u32 color)
{
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_one_color, 8);
// Configure display to show single color.
DISPLAY_A(_DIREG(DC_WIN_AD_WIN_OPTIONS)) = 0;
DISPLAY_A(_DIREG(DC_WIN_BD_WIN_OPTIONS)) = 0;
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color;
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ;
usleep(35000);
display_backlight(true);
}
u32 *display_init_framebuffer()
{
// Sanitize framebuffer area.
memset((u32 *)0xC0000000, 0, 0x3C0000);
// This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768).
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
usleep(35000);
return (u32 *)0xC0000000;
}

54
ipl/di.h → bootloader/gfx/di.h Executable file → Normal file
View File

@@ -1,23 +1,24 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _DI_H_
#define _DI_H_
#include "types.h"
#include "../utils/types.h"
/*! Display registers. */
#define _DIREG(reg) ((reg) * 4)
@@ -79,6 +80,8 @@
#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
#define DC_COM_DSC_TOP_CTL 0x33E
#define DC_DISP_DISP_WIN_OPTIONS 0x402
#define HDMI_ENABLE (1 << 30)
#define DSI_ENABLE (1 << 29)
@@ -158,6 +161,8 @@
#define DE_CONTROL_ACTIVE_BLANK (4 << 2)
#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480
#define DC_DISP_SD_BL_PARAMETERS 0x4D7
#define DC_DISP_SD_BL_CONTROL 0x4DC
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4
#define DC_WIN_CSC_YOF 0x611
@@ -172,10 +177,11 @@
#define DC_WIN_BD_WIN_OPTIONS 0xD80
#define DC_WIN_CD_WIN_OPTIONS 0xF80
//The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER).
// The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER).
#define DC_WIN_WIN_OPTIONS 0x700
#define H_DIRECTION (1 << 0)
#define V_DIRECTION (1 << 2)
#define SCAN_COLUMN (1 << 4)
#define COLOR_EXPAND (1 << 6)
#define CSC_ENABLE (1 << 18)
#define WIN_ENABLE (1 << 30)
@@ -223,9 +229,11 @@
#define V_DDA_INC(x) (((x) & 0xffff) << 16)
#define DC_WIN_LINE_STRIDE 0x70A
#define LINE_STRIDE(x) (x)
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
#define DC_WIN_DV_CONTROL 0x70E
//The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
#define DC_WINBUF_START_ADDR 0x800
#define DC_WINBUF_ADDR_H_OFFSET 0x806
#define DC_WINBUF_ADDR_V_OFFSET 0x808
@@ -334,17 +342,25 @@
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
#define DSI_PAD_CONTROL_4 0x52
#define DSI_INIT_SEQ_DATA_15 0x5F
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
/*! Display backlight related PWM registers. */
#define PWM_CONTROLLER_PWM_CSR 0x00
void display_init();
void display_backlight_pwm_init();
void display_end();
/*! Show one single color on the display. */
void display_color_screen(u32 color);
/*! Switches screen backlight ON/OFF. */
void display_backlight(u8 enable);
void display_backlight(bool enable);
void display_backlight_brightness(u32 brightness, u32 step_delay);
/*! Init display in full 1280x720 resolution (32bpp, line stride 768, framebuffer size = 1280*768*4 bytes). */
/*! Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */
u32 *display_init_framebuffer();
#endif

56
ipl/di.inl → bootloader/gfx/di.inl Executable file → Normal file
View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* 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,
@@ -127,7 +128,7 @@ static const cfg_op_t _display_config_2[94] = {
};
//DSI Init config.
static const cfg_op_t _display_config_3[60] = {
static const cfg_op_t _display_config_3[61] = {
{DSI_WR_DATA, 0},
{DSI_INT_ENABLE, 0},
{DSI_INT_STATUS, 0},
@@ -136,6 +137,7 @@ static const cfg_op_t _display_config_3[60] = {
{DSI_INIT_SEQ_DATA_1, 0},
{DSI_INIT_SEQ_DATA_2, 0},
{DSI_INIT_SEQ_DATA_3, 0},
{DSI_INIT_SEQ_DATA_15, 0},
{DSI_DCS_CMDS, 0},
{DSI_PKT_SEQ_0_LO, 0},
{DSI_PKT_SEQ_1_LO, 0},
@@ -285,12 +287,12 @@ static const cfg_op_t _display_config_7[10] = {
//MIPI CAL config.
static const cfg_op_t _display_config_8[6] = {
{0x18, 0},
{2, 0xF3F10000},
{0x16, 1},
{0x18, 0},
{0x18, 0x10010},
{0x17, 0x300}
{0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
{0x02, 0xF3F10000}, // MIPI_CAL_CIL_MIPI_CAL_STATUS
{0x16, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG0
{0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
{0x18, 0x10010}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
{0x17, 0x300} // MIPI_CAL_MIPI_BIAS_PAD_CFG1
};
//DSI config.
@@ -303,22 +305,22 @@ static const cfg_op_t _display_config_9[4] = {
//MIPI CAL config.
static const cfg_op_t _display_config_10[16] = {
{0xE, 0x200200},
{0xF, 0x200200},
{0x19, 0x200002},
{0x1A, 0x200002},
{5, 0},
{6, 0},
{7, 0},
{8, 0},
{9, 0},
{0xA, 0},
{0x10, 0},
{0x11, 0},
{0x1A, 0},
{0x1C, 0},
{0x1D, 0},
{0, 0x2A000001}
{0x0E, 0x200200}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG
{0x0F, 0x200200}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG
{0x19, 0x200002}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2
{0x1A, 0x200002}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2
{0x05, 0}, // MIPI_CAL_CILA_MIPI_CAL_CONFIG
{0x06, 0}, // MIPI_CAL_CILB_MIPI_CAL_CONFIG
{0x07, 0}, // MIPI_CAL_CILC_MIPI_CAL_CONFIG
{0x08, 0}, // MIPI_CAL_CILD_MIPI_CAL_CONFIG
{0x09, 0}, // MIPI_CAL_CILE_MIPI_CAL_CONFIG
{0x0A, 0}, // MIPI_CAL_CILF_MIPI_CAL_CONFIG
{0x10, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG
{0x11, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG
{0x1A, 0}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2
{0x1C, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2
{0x1D, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG_2
{0, 0x2A000001} // MIPI_CAL_DSIA_MIPI_CAL_CONFIG
};
//Display A config.
@@ -473,10 +475,10 @@ static const cfg_op_t _display_config_13[16] = {
{DSI_PAD_CONTROL_1, 0},
{DSI_PHY_TIMING_0, 0x6070601},
{DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30109},
{DSI_PHY_TIMING_2, 0x30118},
{DSI_BTA_TIMING, 0x190A14},
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) },
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0},
{DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
{DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
@@ -534,7 +536,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_R8G8B8A8}, //T_A8B8G8R8
{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8
{DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_POSITION, 0}, //(0,0)
@@ -543,7 +545,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = {
{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes.
{DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)},
{DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels.
{DC_WIN_LINE_STRIDE, 0x6000C00}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
{DC_WIN_BUFFER_CONTROL, 0},
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
{DC_WINBUF_START_ADDR, 0xC0000000}, //Framebuffer address.

524
bootloader/gfx/gfx.c Normal file
View File

@@ -0,0 +1,524 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <string.h>
#include "gfx.h"
static const u8 _gfx_font[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )
0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)
0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (")
0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, // Char 035 (#)
0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, // Char 036 ($)
0x00, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, // Char 037 (%)
0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, // Char 038 (&)
0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, // Char 039 (')
0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, // Char 040 (()
0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, // Char 041 ())
0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // Char 042 (*)
0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // Char 043 (+)
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 044 (,)
0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // Char 045 (-)
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // Char 046 (.)
0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, // Char 047 (/)
0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, // Char 048 (0)
0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, // Char 049 (1)
0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, // Char 050 (2)
0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, // Char 051 (3)
0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, // Char 052 (4)
0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, // Char 053 (5)
0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, // Char 054 (6)
0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, // Char 055 (7)
0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // Char 056 (8)
0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, // Char 057 (9)
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, // Char 058 (:)
0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 059 (;)
0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, // Char 060 (<)
0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // Char 061 (=)
0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, // Char 062 (>)
0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // Char 063 (?)
0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, // Char 064 (@)
0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 065 (A)
0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 066 (B)
0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, // Char 067 (C)
0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, // Char 068 (D)
0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, // Char 069 (E)
0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, // Char 070 (F)
0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, // Char 071 (G)
0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 072 (H)
0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 073 (I)
0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, // Char 074 (J)
0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, // Char 075 (K)
0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, // Char 076 (L)
0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, // Char 077 (M)
0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, // Char 078 (N)
0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 079 (O)
0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, // Char 080 (P)
0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, // Char 081 (Q)
0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, // Char 082 (R)
0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, // Char 083 (S)
0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // Char 084 (T)
0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 085 (U)
0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 086 (V)
0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, // Char 087 (W)
0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // Char 088 (X)
0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // Char 089 (Y)
0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, // Char 090 (Z)
0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, // Char 091 ([)
0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, // Char 092 (\)
0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, // Char 093 (])
0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, // Char 094 (^)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // Char 095 (_)
0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // Char 096 (`)
0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, // Char 097 (a)
0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 098 (b)
0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, // Char 099 (c)
0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // Char 100 (d)
0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, // Char 101 (e)
0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, // Char 102 (f)
0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, // Char 103 (g)
0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, // Char 104 (h)
0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, // Char 105 (i)
0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, // Char 106 (j)
0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, // Char 107 (k)
0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 108 (l)
0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // Char 109 (m)
0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, // Char 110 (n)
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 111 (o)
0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, // Char 112 (p)
0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, // Char 113 (q)
0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, // Char 114 (r)
0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, // Char 115 (s)
0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, // Char 116 (t)
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // Char 117 (u)
0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 118 (v)
0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, // Char 119 (w)
0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // Char 120 (x)
0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, // Char 121 (y)
0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, // Char 122 (z)
0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, 0x18, // Char 123 ({)
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // Char 124 (|)
0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, 0x0C, // Char 125 (})
0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~)
};
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride)
{
ctxt->fb = fb;
ctxt->width = width;
ctxt->height = height;
ctxt->stride = stride;
}
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color)
{
memset(ctxt->fb, color, 0x3C0000);
}
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color)
{
for (u32 i = 0; i < ctxt->height * ctxt->stride; i++)
ctxt->fb[i] = color;
}
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height)
{
memset(ctxt->fb + pos_x * ctxt->stride, color, height * 4 * ctxt->stride);
}
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt)
{
con->gfx_ctxt = ctxt;
con->fntsz = 16;
con->x = 0;
con->y = 0;
con->savedx = 0;
con->savedy = 0;
con->fgcol = 0xFFCCCCCC;
con->fillbg = 0;
con->bgcol = 0xFF1B1B1B;
con->mute = 0;
}
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol)
{
con->fgcol = fgcol;
con->fillbg = fillbg;
con->bgcol = bgcol;
}
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y)
{
*x = con->x;
*y = con->y;
}
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y)
{
con->x = x;
con->y = y;
}
void gfx_putc(gfx_con_t *con, char c)
{
// Duplicate code for performance reasons.
switch (con->fntsz)
{
case 16:
if (c >= 32 && c <= 126)
{
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride;
for (u32 i = 0; i < 16; i+=2)
{
u8 v = *cbuf++;
for (u32 k = 0; k < 2; k++)
{
for (u32 j = 0; j < 8; j++)
{
if (v & 1)
{
*fb = con->fgcol;
fb++;
*fb = con->fgcol;
}
else if (con->fillbg)
{
*fb = con->bgcol;
fb++;
*fb = con->bgcol;
}
else
fb++;
v >>= 1;
fb++;
}
fb += con->gfx_ctxt->stride - 16;
v = *cbuf;
}
}
con->x += 16;
}
else if (c == '\n')
{
con->x = 0;
con->y +=16;
if (con->y > con->gfx_ctxt->height - 16)
con->y = 0;
}
break;
case 8:
default:
if (c >= 32 && c <= 126)
{
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride;
for (u32 i = 0; i < 8; i++)
{
u8 v = *cbuf++;
for (u32 j = 0; j < 8; j++)
{
if (v & 1)
*fb = con->fgcol;
else if (con->fillbg)
*fb = con->bgcol;
v >>= 1;
fb++;
}
fb += con->gfx_ctxt->stride - 8;
}
con->x += 8;
}
else if (c == '\n')
{
con->x = 0;
con->y += 8;
if (con->y > con->gfx_ctxt->height - 8)
con->y = 0;
}
break;
}
}
void gfx_puts(gfx_con_t *con, const char *s)
{
if (!s || con->mute)
return;
for (; *s; s++)
gfx_putc(con, *s);
}
static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt)
{
char buf[65];
static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz";
char *p;
int c = fcnt;
if (base > 36)
return;
p = buf + 64;
*p = 0;
do
{
c--;
*--p = digits[v % base];
v /= base;
} while (v);
if (fill != 0)
{
while (c > 0)
{
*--p = fill;
c--;
}
}
gfx_puts(con, p);
}
void gfx_put_small_sep(gfx_con_t *con)
{
u8 prevFontSize = con->fntsz;
con->fntsz = 8;
gfx_putc(con, '\n');
con->fntsz = prevFontSize;
}
void gfx_put_big_sep(gfx_con_t *con)
{
u8 prevFontSize = con->fntsz;
con->fntsz = 16;
gfx_putc(con, '\n');
con->fntsz = prevFontSize;
}
void gfx_printf(gfx_con_t *con, const char *fmt, ...)
{
if (con->mute)
return;
va_list ap;
int fill, fcnt;
va_start(ap, fmt);
while(*fmt)
{
if(*fmt == '%')
{
fmt++;
fill = 0;
fcnt = 0;
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')
{
fcnt = *fmt;
fmt++;
if (*fmt >= '0' && *fmt <= '9')
{
fill = fcnt;
fcnt = *fmt - '0';
fmt++;
}
else
{
fill = ' ';
fcnt -= '0';
}
}
switch(*fmt)
{
case 'c':
gfx_putc(con, va_arg(ap, u32));
break;
case 's':
gfx_puts(con, va_arg(ap, char *));
break;
case 'd':
_gfx_putn(con, va_arg(ap, u32), 10, fill, fcnt);
break;
case 'p':
case 'P':
case 'x':
case 'X':
_gfx_putn(con, va_arg(ap, u32), 16, fill, fcnt);
break;
case 'k':
con->fgcol = va_arg(ap, u32);
break;
case 'K':
con->bgcol = va_arg(ap, u32);
con->fillbg = 1;
break;
case '%':
gfx_putc(con, '%');
break;
case '\0':
goto out;
default:
gfx_putc(con, '%');
gfx_putc(con, *fmt);
break;
}
}
else
gfx_putc(con, *fmt);
fmt++;
}
out:
va_end(ap);
}
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len)
{
if (con->mute)
return;
u8 prevFontSize = con->fntsz;
con->fntsz = 8;
for(u32 i = 0; i < len; i++)
{
if(i % 0x10 == 0)
{
if(i != 0)
{
gfx_puts(con, "| ");
for(u32 j = 0; j < 0x10; j++)
{
u8 c = buf[i - 0x10 + j];
if(c >= 32 && c <= 126)
gfx_putc(con, c);
else
gfx_putc(con, '.');
}
gfx_putc(con, '\n');
}
gfx_printf(con, "%08x: ", base + i);
}
gfx_printf(con, "%02x ", buf[i]);
if (i == len - 1)
{
int ln = len % 0x10 != 0;
u32 k = 0x10 - 1;
if (ln)
{
k = (len & 0xF) - 1;
for (u32 j = 0; j < 0x10 - k; j++)
gfx_puts(con, " ");
}
gfx_puts(con, "| ");
for(u32 j = 0; j < (ln ? k : k + 1); j++)
{
u8 c = buf[i - k + j];
if(c >= 32 && c <= 126)
gfx_putc(con, c);
else
gfx_putc(con, '.');
}
gfx_putc(con, '\n');
}
}
gfx_putc(con, '\n');
con->fntsz = prevFontSize;
}
static int abs(int x)
{
if (x < 0)
return -x;
return x;
}
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color)
{
ctxt->fb[x + y * ctxt->stride] = color;
}
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
{
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = (dx > dy ? dx : -dy) / 2, e2;
while (1)
{
gfx_set_pixel(ctxt, x0, y0, color);
if (x0 == x1 && y0 == y1)
break;
e2 = err;
if (e2 >-dx)
{
err -= dy;
x0 += sx;
}
if (e2 < dy)
{
err += dx;
y0 += sy;
}
}
}
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 pos = 0;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
{
memset(&ctxt->fb[x + y*ctxt->stride], buf[pos], 4);
pos++;
}
}
}
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 pos = 0;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
{
ctxt->fb[x + y*ctxt->stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);
pos+=3;
}
}
}
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 *ptr = (u32 *)buf;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
for (u32 x = pos_x; x < (pos_x + size_x); x++)
ctxt->fb[x + y * ctxt->stride] = *ptr++;
}
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
ctxt->fb[x + y * ctxt->stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];
}
}

46
bootloader/gfx/gfx.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (C) 2018 M4xw
*
* 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/>.
*/
#ifndef _GFX_H_
#define _GFX_H_
#include "../../common/common_gfx.h"
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride);
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color);
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height);
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color);
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt);
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol);
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y);
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y);
void gfx_putc(gfx_con_t *con, char c);
void gfx_puts(gfx_con_t *con, const char *s);
void gfx_printf(gfx_con_t *con, const char *fmt, ...);
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len);
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color);
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color);
void gfx_put_small_sep(gfx_con_t *con);
void gfx_put_big_sep(gfx_con_t *con);
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
#endif

931
bootloader/gfx/logos.h Normal file
View File

@@ -0,0 +1,931 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _HEKATE_LOGOS_H_
#define _HEKATE_LOGOS_H_
#ifdef MENU_LOGO_ENABLE
// 119 x 57 @24bpp RGB RAW positioned at 577 x 1199
#define SZ_MENU_LOGO 20349
#define SZ_MENU_LOGO_BLZ 7592
static unsigned char Kc_MENU_LOGO_blz[SZ_MENU_LOGO_BLZ] = {
0x01, 0x10, 0x80, 0x2D, 0xF0, 0x99, 0x30, 0x84, 0xB0, 0x1C, 0x6C, 0x60, 0x51, 0xF0, 0x59, 0x31,
0x03, 0x30, 0xF7, 0x0F, 0xF0, 0x0F, 0xF0, 0x42, 0xF0, 0xFE, 0xF4, 0x15, 0x6C, 0xCF, 0x30, 0xCC,
0x20, 0x1D, 0x7F, 0x1F, 0x52, 0x6D, 0xD8, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0xC9, 0xF0, 0xBE, 0xF2, 0x2A, 0x00, 0x75, 0x1F,
0x5D, 0x10, 0x36, 0x7F, 0x84, 0x10, 0x7E, 0x00, 0x85, 0x0B, 0x72, 0x00, 0x6C, 0x00, 0x54, 0x40,
0x1A, 0x42, 0x8F, 0xBF, 0x21, 0xCF, 0x1F, 0x33, 0x00, 0x03, 0x20, 0x0F, 0xF0, 0x09, 0x90, 0x03,
0x30, 0x00, 0x00, 0xFE, 0x33, 0x20, 0x9E, 0x01, 0x2D, 0x19, 0xF0, 0x10, 0x20, 0x49, 0x02, 0x30,
0x60, 0xD3, 0x08, 0x81, 0x23, 0x19, 0x1B, 0x2B, 0x19, 0x1B, 0x33, 0x01, 0x18, 0x1B, 0x38, 0x18,
0x2B, 0x05, 0x1B, 0x36, 0x18, 0x10, 0xF6, 0x00, 0xDC, 0x1E, 0x20, 0xE1, 0x30, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFB, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xD8, 0xF0,
0x3A, 0xFE, 0xAE, 0x00, 0x43, 0x2B, 0xFF, 0x2F, 0x19, 0x1B, 0x4A, 0x15, 0x1C, 0x6A, 0x11, 0x00,
0x1D, 0x8A, 0x0E, 0x1E, 0xAD, 0x09, 0x1E, 0xB7, 0x00, 0x81, 0x00, 0x07, 0x1E, 0xA6, 0x0A, 0x1E,
0x87, 0x0F, 0x01, 0x1E, 0x60, 0x13, 0x1D, 0x3E, 0x17, 0xEC, 0x51, 0x51, 0x40, 0xC0, 0xB3, 0x01,
0x1C, 0x6D, 0x12, 0x1D, 0x96, 0x09, 0x80, 0x0F, 0xF0, 0xC1, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00,
0x97, 0x0C, 0x94, 0x15, 0x80, 0x10, 0x27, 0x1E, 0x37, 0x17, 0x54, 0xA9, 0x1E, 0x8F, 0x1D, 0x1C,
0x37, 0x28, 0x17, 0x1C, 0x57, 0x13, 0x1C, 0x73, 0x11, 0x1D, 0x00, 0xA8, 0x09, 0xB3, 0x08, 0x1E,
0xB5, 0x08, 0x1E, 0xB1, 0x01, 0x09, 0x1E, 0x9F, 0x0C, 0x1E, 0x74, 0x10, 0x1D, 0x00, 0x53, 0x13,
0x1C, 0x31, 0x18, 0xD0, 0x02, 0x35, 0xF4, 0x0F, 0xF0, 0xE0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xDA, 0xF0, 0x35, 0xFD, 0xFF, 0x62, 0x04, 0xA6, 0x18, 0x7D,
0x10, 0x1D, 0xC6, 0x06, 0x1E, 0x03, 0xF4, 0x01, 0x2A, 0xF0, 0x20, 0xF1, 0x01, 0x20, 0xC1, 0x04,
0x07, 0x1E, 0xEC, 0x01, 0x2A, 0x1A, 0x08, 0x0D, 0xD8, 0x49, 0x40, 0x64, 0xC7, 0x52, 0x0F, 0xF0,
0x0F, 0xF0, 0x30, 0xF0, 0x1B, 0x00, 0x59, 0x13, 0xEC, 0x27, 0x9F, 0x17, 0x57, 0x30, 0x18, 0x1B,
0x51, 0x15, 0x1C, 0x98, 0x01, 0x0B, 0x1D, 0xBA, 0x03, 0xFB, 0xD8, 0xF0, 0x00, 0x20, 0xE5, 0x14,
0x03, 0x1F, 0xA4, 0x0B, 0x1E, 0x4B, 0x16, 0x1C, 0x00, 0xAE, 0x03, 0x1D, 0x65, 0x81, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFD, 0x0F, 0xF0, 0x0F, 0xF0, 0xDF, 0xF0, 0xE7,
0xF9, 0x2D, 0x18, 0x1B, 0x4E, 0x0F, 0x15, 0x1C, 0xA8, 0x09, 0x1E, 0xF7, 0x23, 0x14, 0x30, 0xF0,
0xC0, 0x0E, 0xA4, 0x99, 0x0C, 0x1E, 0x35, 0x93, 0x18, 0x62, 0x11, 0x47, 0x61, 0xE3, 0x0A, 0x4E,
0x50, 0x0F, 0xF0, 0x36, 0xF0, 0x62, 0xF1, 0x5F, 0x13, 0x1C, 0x1F, 0x36, 0x07, 0x19, 0xB5, 0x15,
0x1A, 0x07, 0x1B, 0x69, 0x11, 0x1C, 0x0D, 0xD0, 0xC1, 0x42, 0xD5, 0xF0, 0x9A, 0xA5, 0x6D, 0x11,
0x1D, 0x26, 0x0E, 0xDE, 0x00, 0x9C, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xE7, 0xF0, 0xA4, 0xF7, 0xE6, 0x11, 0x09, 0x19, 0xBE, 0x08,
0x36, 0xA0, 0x9F, 0x2A, 0xF0, 0xE7, 0xAC, 0x0B, 0x1F, 0x2D, 0x19, 0x48, 0x10, 0x3A, 0x43, 0x17,
0x1C, 0xC3, 0x36, 0xB3, 0x0F, 0xF0, 0x2D, 0xF0, 0xD3, 0x95, 0xE2, 0x02, 0xF8, 0x11, 0x1D, 0x5B,
0x12, 0x31, 0x18, 0x1C, 0x72, 0x11, 0x04, 0x2C, 0xA1, 0x0C, 0xC0, 0xC0, 0xC0, 0xF4, 0x01, 0x20,
0x6C, 0x11, 0x07, 0xFA, 0x18, 0x1C, 0x62, 0xC1, 0x36, 0xF0, 0x0F, 0xF0, 0x23, 0xF0, 0x45, 0xF0,
0x35, 0xF1, 0xFD, 0x0F, 0xF0, 0x13, 0xF1, 0x11, 0xF1, 0x99, 0x03, 0xE5, 0x25, 0x3C, 0x00, 0x1E,
0xC0, 0xCF, 0x7F, 0x06, 0x1E, 0x99, 0x0B, 0x1E, 0x81, 0x0F, 0x1E, 0x00, 0x38, 0x04, 0xA1, 0x0B,
0x1E, 0xDA, 0x56, 0x27, 0x60, 0x90, 0x7C, 0x61, 0x10, 0x1D, 0x23, 0xCE, 0x21, 0xC3, 0x06, 0xA8,
0x27, 0x50, 0x1B, 0x30, 0xD8, 0xA7, 0x0A, 0x1E, 0xAA, 0x09, 0x1E, 0xE5, 0x03, 0x00, 0x20, 0xBE,
0x95, 0xB1, 0x09, 0x1F, 0x03, 0x00, 0xA4, 0x03, 0x30, 0xA2, 0x0A, 0x1E, 0x00, 0x00, 0x47, 0x04,
0x95, 0x0D, 0x1E, 0x36, 0x0C, 0x18, 0x1B, 0x16, 0xCF, 0x23, 0x5F, 0x13, 0x1D, 0xD7, 0x08, 0x33,
0x19, 0xC1, 0xA2, 0x2B, 0x02, 0x8D, 0x0E, 0x1E, 0x7E, 0x10, 0x07, 0x1E, 0x8C, 0x0E, 0x1E, 0xB8,
0x08, 0x1E, 0xED, 0x00, 0x81, 0x23, 0x3E, 0x9D, 0x45, 0x16, 0xCC, 0xF6, 0x1B, 0x3C, 0x90, 0x36,
0x60, 0xD3, 0x65, 0xF1, 0x2A, 0xF0, 0x33, 0xC0, 0xB1, 0xC9, 0x29, 0xF1, 0x96, 0x99, 0x15, 0x9C,
0x34, 0x75, 0xFF, 0xB9, 0x21, 0x2C, 0x19, 0x1B, 0x77, 0xD5, 0x0F, 0x77, 0x87, 0x64, 0x0E, 0xE1,
0x89, 0x0D, 0x1E, 0x14, 0x07, 0x1E, 0x81, 0x20, 0x1E, 0x66, 0x1F, 0xA8, 0x5C, 0x14, 0xAA, 0x0A,
0x1E, 0xFE, 0x5D, 0x80, 0xDA, 0x9D, 0x22, 0xA1, 0x21, 0x1A, 0xC3, 0x3F, 0x27, 0xA0, 0x25, 0x19,
0x1B, 0x41, 0x0C, 0x17, 0x1C, 0xCD, 0x54, 0x80, 0x86, 0x01, 0xF9, 0x00, 0x3E, 0x07, 0x1E, 0x78,
0x03, 0x20, 0x20, 0x9C, 0x3F, 0xDB, 0x19, 0x36, 0x49, 0x40, 0x17, 0x1C, 0x1D, 0xAD, 0x0A, 0xDB,
0xA0, 0xDB, 0x04, 0x69, 0x16, 0x06, 0x00, 0x1D, 0x64, 0xEE, 0x0E, 0xE5, 0x1E, 0xFB, 0x0A, 0x1B,
0x61, 0x13, 0x1D, 0xD2, 0x07, 0xDE, 0xB0, 0x7B, 0x03, 0x24, 0x1A, 0x1C, 0x19, 0x93, 0xE9, 0x77,
0x01, 0xC3, 0x36, 0x00, 0xC8, 0x31, 0x30, 0x00, 0x36, 0xC0, 0x33, 0xF0, 0x1B, 0x40, 0x82, 0x22,
0xA6, 0x02, 0xFF, 0x00, 0x00, 0x33, 0x90, 0xD3, 0x32, 0x2C, 0xF1, 0xB9, 0x6A, 0xB5, 0x32, 0x03,
0x00, 0x4D, 0x01, 0xFF, 0xA0, 0x02, 0x32, 0x01, 0xF9, 0x00, 0x04, 0x12, 0xC1, 0x25, 0x48, 0x16,
0x1C, 0x1F, 0xBC, 0x08, 0x8C, 0xA1, 0x97, 0x0D, 0x1E, 0x16, 0x54, 0xC0, 0x84, 0x27, 0x3F, 0x17,
0x1C, 0xC5, 0x06, 0x1F, 0x62, 0x91, 0x7B, 0x41, 0x0F, 0x1D, 0x1C, 0x0C, 0x20, 0x18, 0x27, 0x80,
0x17, 0xBC, 0x21, 0xA8, 0x3D, 0x62, 0xE1, 0x42, 0x16, 0xBE, 0x15, 0x17, 0x06, 0x50, 0x19, 0x52,
0x83, 0x81, 0x2A, 0xDB, 0x10, 0x6D, 0x12, 0x07, 0x75, 0x01, 0x1F, 0x54, 0x1D, 0x14, 0x1C, 0x11,
0x1C, 0x5F, 0x41, 0x29, 0x41, 0xD6, 0x2B, 0x66, 0x70, 0x13, 0x1D, 0xED, 0x43, 0x72, 0x20, 0xE0,
0x03, 0x1F, 0x08, 0x43, 0xFF, 0x03, 0x13, 0x52, 0xB2, 0x38, 0x7D, 0x01, 0x30, 0x30, 0x30, 0x1E,
0xE7, 0x09, 0x72, 0x00, 0x59, 0x59, 0x59, 0xA4, 0x01, 0x45, 0x45, 0x23, 0x45, 0x28, 0x0B, 0x39,
0x00, 0x69, 0x00, 0x36, 0x90, 0x7B, 0xF9, 0xA9, 0x02, 0x5C, 0x01, 0xFE, 0xF4, 0x02, 0x00, 0x00,
0x1E, 0x0F, 0xF5, 0x0A, 0x73, 0x05, 0x44, 0x01, 0xA3, 0x02, 0x1A, 0xC7, 0xFF, 0xC5, 0x3A, 0x00,
0x00, 0xBC, 0x0A, 0x44, 0x01, 0xE7, 0x00, 0x3A, 0x05, 0xE7, 0x00, 0xD0, 0x0E, 0xFF, 0x46, 0x46,
0x46, 0x9A, 0x02, 0xD2, 0x00, 0x1B, 0x00, 0x28, 0x19, 0x38, 0x1B, 0x67, 0x12, 0x1D, 0xEF, 0x02,
0xF3, 0xA6, 0x3B, 0x40, 0x18, 0x1C, 0x12, 0x51, 0x3F, 0x65, 0x61, 0xB2, 0x38, 0x19, 0x1B, 0x38,
0x85, 0x0F, 0x57, 0xA0, 0xAC, 0x09, 0x1E, 0x19, 0x1C, 0x04, 0x19, 0x2B, 0x2A, 0x90, 0x9D, 0x22,
0x3E, 0x62, 0xE1, 0x43, 0x16, 0x8F, 0x11, 0x97, 0x56, 0x14, 0xB4, 0x66, 0x86, 0x5D, 0x3E, 0x04,
0x9D, 0x0B, 0xF3, 0xA6, 0xA5, 0x4F, 0x0A, 0x1E, 0x3D, 0x6B, 0x1A, 0x9D, 0x65, 0xA8, 0x23, 0x35,
0x18, 0x34, 0x1C, 0xBD, 0x08, 0x1F, 0x13, 0x92, 0x61, 0x13, 0xFA, 0x12, 0x90, 0x19, 0x5B, 0x2E,
0x26, 0x04, 0x47, 0x04, 0x52, 0x52, 0x52, 0xA3, 0x0E, 0xA3, 0xA3, 0x85, 0x08, 0xA7, 0x01, 0x36,
0x00, 0x39, 0x00, 0x65, 0x01, 0x1B, 0x03, 0xFC, 0x55, 0x55, 0x55, 0x48, 0x00, 0x65, 0x01, 0x4C,
0xF3, 0x89, 0x01, 0x28, 0x78, 0x28, 0x28, 0xA3, 0x02, 0x18, 0x0F, 0x49, 0x05, 0xD2, 0x06, 0x20,
0x01, 0xD7, 0x0D, 0xFC, 0x45, 0x0C, 0x7D, 0x01, 0x30, 0x00, 0xB2, 0x02, 0xCA, 0x12, 0x84, 0x86,
0x62, 0x01, 0x69, 0x7F, 0x69, 0x69, 0x87, 0x09, 0xB9, 0x0A, 0x35, 0x35, 0x35, 0x6D, 0x0C, 0x6D,
0x6D, 0xBC, 0xBC, 0xBC, 0xCF, 0x03, 0x06, 0x0F, 0x4D, 0x01, 0xE0, 0x54, 0x54, 0x54, 0xC1, 0x02,
0xEF, 0x1D, 0x19, 0x1B, 0x8D, 0x18, 0x0E, 0xB1, 0x90, 0x21, 0x9A, 0x0C, 0x1E, 0x14, 0x2D, 0x00,
0x82, 0xEF, 0xFD, 0x11, 0x2D, 0x50, 0x15, 0x1C, 0xEF, 0x02, 0x27, 0x7F, 0x83, 0xC3, 0x08, 0x20,
0x6F, 0x00, 0x17, 0xE8, 0x35, 0x62, 0xF1, 0x62, 0xF1, 0xE8, 0xEF, 0xFD, 0x8A, 0x2C, 0x3E, 0x17,
0x1C, 0xC4, 0x35, 0x81, 0xF1, 0x0E, 0xC3, 0x57, 0x14, 0x9E, 0x3A, 0xAB, 0xF3, 0x46, 0x12, 0x92,
0x0D, 0x1D, 0x1C, 0x61, 0x95, 0x92, 0x0E, 0xD6, 0x0B, 0x1A, 0x1A, 0xC4, 0x02, 0x28, 0x49, 0x28,
0xB2, 0x08, 0xBC, 0x01, 0x55, 0x0B, 0x5F, 0x07, 0x9A, 0x9A, 0x9A, 0x1E, 0x03, 0x00, 0x75, 0x75,
0x75, 0xCC, 0x09, 0x5D, 0x00, 0xD4, 0xD4, 0x31, 0xD4, 0xEF, 0xEF, 0xEF, 0x84, 0x84, 0x84, 0x3B,
0x04, 0x80, 0x88, 0x05, 0x24, 0x63, 0x8A, 0x39, 0xE5, 0x02, 0xD4, 0x0D, 0xA1, 0xA1, 0xA1, 0x1F,
0xF2, 0xF2, 0xF2, 0xCA, 0xCA, 0xCA, 0xA6, 0x05, 0x00, 0x00, 0xC0, 0x78, 0x78, 0x78, 0x98, 0x98,
0x98, 0xE0, 0x0A, 0x70, 0x02, 0xC0, 0x37, 0x05, 0x3B, 0x01, 0x23, 0x04, 0x62, 0x31, 0x57, 0x09,
0xC3, 0x03, 0x68, 0x01, 0x87, 0x09, 0xFF, 0x4C, 0x4C, 0x4C, 0x97, 0x97, 0x97, 0x88, 0x02, 0x4F,
0x08, 0xC0, 0x87, 0x87, 0x87, 0x20, 0x01, 0xCC, 0x03, 0x2C, 0x01, 0xEA, 0x00, 0xA4, 0x01, 0xF8,
0x3B, 0x17, 0x1C, 0xB4, 0x81, 0x8F, 0xE6, 0x0D, 0x74, 0x11, 0x30, 0x1D, 0x16, 0x11, 0x3D, 0x84,
0xF0, 0x3A, 0x05, 0x19, 0x1C, 0x88, 0x1C, 0x0F, 0x1D, 0xAD, 0x0A, 0x1E, 0xA9, 0x0B, 0x7E, 0x10,
0x80, 0x82, 0x10, 0x1D, 0xE0, 0x01, 0x16, 0x03, 0x30, 0x62, 0xF1, 0x62, 0xF1, 0xE8, 0x25, 0xFB,
0xA5, 0x23, 0x5A, 0x13, 0x1C, 0xDF, 0xA5, 0x83, 0xD7, 0x43, 0x04, 0x1F, 0x38, 0x17, 0x25, 0x2B,
0x43, 0xF2, 0x62, 0x21, 0x4F, 0x70, 0x15, 0x1C, 0xA1, 0x0C, 0x1E, 0xAE, 0x0A, 0x1E, 0x00, 0xA8,
0x0B, 0x1E, 0xA5, 0x0B, 0x1E, 0x61, 0x14, 0x00, 0x08, 0x11, 0x22, 0x23, 0x23, 0x33, 0x33, 0x33,
0xCA, 0x05, 0x81, 0xBC, 0x01, 0x7C, 0x08, 0x29, 0x07, 0x72, 0x30, 0x95, 0x01, 0xDE, 0x36, 0x50,
0x07, 0x99, 0x7F, 0x99, 0x99, 0xFA, 0xFA, 0xFA, 0x34, 0x0B, 0x09, 0x00, 0xE8, 0x32, 0xE0, 0x2C,
0x37, 0x29, 0x04, 0x79, 0x05, 0xB6, 0xB6, 0xB6, 0x12, 0x0F, 0x76, 0x47, 0x76, 0x76, 0xA0, 0x02,
0x3D, 0x38, 0xA6, 0x32, 0x6F, 0x09, 0xDF, 0x02, 0x8A, 0x39, 0xFC, 0x35, 0x01, 0x46, 0x00, 0x21,
0x30, 0x2C, 0x2C, 0x2C, 0x62, 0x01, 0x43, 0x08, 0xC7, 0xA9, 0xA9, 0xA9, 0x73, 0x02, 0x70, 0x70,
0x70, 0x0C, 0x00, 0x88, 0x23, 0x01, 0xD3, 0x0E, 0xE1, 0x00, 0xE7, 0x00, 0x31, 0x02, 0x5B, 0x38,
0xC9, 0x57, 0x80, 0xBF, 0xF2, 0x02, 0x5A, 0x0F, 0x1C, 0x1C, 0x4E, 0xC8, 0xF4, 0xE5, 0x38, 0x44,
0x17, 0xF4, 0x81, 0x10, 0x24, 0xD3, 0x28, 0x1E, 0x2D, 0x70, 0x62, 0xF1, 0x62, 0xF1, 0xC7, 0xF2,
0xF5, 0x72, 0x1F, 0x71, 0x11, 0x1D, 0xF2, 0xC0, 0x89, 0xC2, 0x06, 0x21, 0x1F, 0x32, 0x5B, 0x28,
0x62, 0xF1, 0x47, 0x1A, 0xD7, 0x27, 0x23, 0x1C, 0x2B, 0xBC, 0x27, 0xCE, 0x07, 0x35, 0x0A, 0xFF,
0x06, 0x1C, 0x1C, 0x91, 0x08, 0x63, 0x4E, 0x63, 0x63, 0xF4, 0xF4, 0xF4, 0x9B, 0x01, 0x2B, 0x0B,
0x83, 0x01, 0xE0, 0x29, 0x94, 0x4B, 0x30, 0x0B, 0x04, 0xB0, 0xB0, 0xB0, 0x04, 0x0B, 0xAC, 0x05,
0xC7, 0x65, 0x01, 0x1E, 0x30, 0x29, 0x04, 0x33, 0x00, 0x96, 0x96, 0x96, 0xF6, 0x0F, 0xF6, 0xF6,
0x61, 0x61, 0x61, 0xC4, 0x02, 0x36, 0x60, 0x33, 0x60, 0xE0, 0x6E, 0x01, 0xA4, 0xA4, 0xA4, 0xF7,
0xF7, 0xF7, 0x38, 0x01, 0x81, 0x1B, 0x00, 0xBA, 0x39, 0x97, 0x02, 0x2B, 0x08, 0x00, 0x00, 0xB2,
0x02, 0x9C, 0x06, 0x4F, 0x02, 0xFF, 0xDE, 0x06, 0x5C, 0x61, 0xF6, 0x66, 0x49, 0x15, 0x47, 0xAA,
0xE2, 0x03, 0x27, 0x14, 0x0D, 0xB8, 0x55, 0x87, 0xF0, 0x1E, 0x30, 0x81, 0x80, 0x19, 0x1C, 0x5C,
0xB0, 0x9F, 0x62, 0xF1, 0x62, 0xF1, 0x43, 0xE5, 0x27, 0x1A, 0x7B, 0x0F, 0x1E, 0xF9, 0x27, 0x62,
0x81, 0xAC, 0x0A, 0x1E, 0x2A, 0x91, 0xA5, 0xE1, 0xF0, 0x03, 0x30, 0xE1, 0x00, 0x00, 0x3B, 0x11,
0x18, 0x62, 0x51, 0xB2, 0xB2, 0xB2, 0xCC, 0x0B, 0xCC, 0xCC, 0xC6, 0x09, 0x6F, 0x00, 0x0C, 0x30,
0xEF, 0xCD, 0x9E, 0x01, 0xB6, 0x01, 0xFC, 0xE7, 0xE7, 0xE7, 0xCD, 0x05, 0x2C, 0x04, 0xB0, 0x31,
0x0B, 0x04, 0x53, 0x78, 0x53, 0x53, 0x29, 0x04, 0x8A, 0x8A, 0x8A, 0x5A, 0x9F, 0x23, 0x61, 0xC4,
0x60, 0x3F, 0xE2, 0x02, 0xD8, 0xD8, 0xD8, 0xB9, 0xB9, 0xB9, 0x03, 0x35, 0x04, 0x29, 0x01, 0x55,
0x02, 0x62, 0x01, 0x03, 0x00, 0x62, 0x01, 0xDE, 0x06, 0x3E, 0x01, 0xFF, 0xEB, 0x6E, 0x62, 0xC1,
0x4B, 0x62, 0xB1, 0xDB, 0x05, 0x1F, 0x2E, 0x0B, 0x19, 0x1E, 0x10, 0x62, 0xF1, 0x81, 0xF0, 0x60,
0xF0, 0x62, 0xF1, 0x62, 0xF1, 0x62, 0xF1, 0xFE, 0xC7, 0xF2, 0xA2, 0x0C, 0x62, 0xE1, 0xA2, 0xF3,
0x23, 0x31, 0x32, 0x8A, 0x2F, 0x79, 0x2F, 0x2F, 0xAF, 0xAF, 0xAF, 0x72, 0x0F, 0x0E, 0x0E, 0x20,
0x0E, 0x75, 0x60, 0xE9, 0xCD, 0x86, 0x01, 0x4B, 0x4B, 0x4B, 0xD9, 0x0E, 0xD9, 0xD9, 0x91, 0x05,
0x62, 0x01, 0x50, 0x31, 0xFF, 0x03, 0x9B, 0x9B, 0x3C, 0x9B, 0xD6, 0xD6, 0xD6, 0x72, 0x0F, 0xBD,
0x39, 0x29, 0xC1, 0x73, 0x32, 0xF0, 0x02, 0x01, 0x54, 0x0C, 0xE5, 0xE5, 0xE5, 0x44, 0x44, 0x44,
0x03, 0x62, 0x31, 0x31, 0x31, 0x31, 0xAB, 0xAB, 0xAB, 0x43, 0x05, 0x81, 0x15, 0x0C, 0x03, 0x00,
0x15, 0x3C, 0x62, 0xF1, 0xD6, 0x0B, 0xE1, 0x62, 0x81, 0x8B, 0x0E, 0xDF, 0x2F, 0x62, 0x01, 0x62,
0xF1, 0x0F, 0xF0, 0x63, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0x62, 0xF1, 0xFE, 0x90, 0x1C, 0x1C, 0x8A,
0x62, 0xB1, 0xA4, 0x62, 0x51, 0x62, 0xF1, 0x9C, 0xF0, 0xE9, 0x49, 0x6E, 0x98, 0x01, 0x5A, 0x00,
0x71, 0x01, 0x65, 0x01, 0xBB, 0x32, 0x2C, 0xC7, 0xD2, 0x39, 0xFF, 0x40, 0x40, 0x40, 0xD3, 0xD3,
0xD3, 0xF6, 0x06, 0x12, 0x40, 0x12, 0x12, 0x62, 0x01, 0x12, 0x00, 0x97, 0x05, 0xD5, 0xD5, 0xD5,
0x1C, 0x94, 0x94, 0x94, 0x7E, 0x3C, 0x0F, 0x00, 0x8E, 0xC5, 0x00, 0x00, 0x34, 0x08, 0xF8, 0x0F,
0x00, 0x64, 0x64, 0x64, 0xED, 0x03, 0x6B, 0x6B, 0x6B, 0x11, 0x77, 0x31, 0x2D, 0x2D, 0x2D, 0xAA,
0xAA, 0xAA, 0x50, 0x01, 0x81, 0x3B, 0x3B, 0x3B, 0xEF, 0x27, 0x2B, 0xE0, 0x88, 0x28, 0x4A, 0x15,
0x38, 0x1C, 0xE0, 0x62, 0xB1, 0xD5, 0x0F, 0x86, 0xF4, 0x1B, 0x0F, 0xF0, 0x63, 0xF0, 0xDC, 0x62,
0xF1, 0x62, 0xF1, 0x62, 0xF1, 0xC1, 0x15, 0x1C, 0x89, 0x0E, 0x0D, 0xA5, 0x8F, 0xA3, 0x0B, 0x1E,
0x26, 0x1A, 0x9F, 0xD6, 0x0F, 0xF0, 0x90, 0xF0, 0xE0, 0x00, 0x00, 0x8F, 0x01, 0x17, 0x3A, 0x62,
0x04, 0xB8, 0x02, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7A, 0x01, 0x4A, 0x01, 0xA9, 0x02,
0x49, 0x49, 0x49, 0xF6, 0x06, 0xC5, 0x0D, 0xC7, 0x2C, 0x34, 0xC3, 0x09, 0x44, 0x01, 0xA3, 0x02,
0x66, 0x0F, 0x32, 0x32, 0x32, 0x1F, 0x38, 0x38, 0x38, 0x06, 0x60, 0x03, 0x30, 0x00, 0x00, 0xEF,
0x0A, 0xAD, 0x0D, 0xF8, 0xD0, 0x02, 0x56, 0x56, 0x56, 0xDB, 0xDB, 0xDB, 0x84, 0x0C, 0x81, 0x12,
0x00, 0x62, 0x61, 0x2C, 0x01, 0x62, 0x41, 0x62, 0xF1, 0xE5, 0x28, 0x47, 0x15, 0x3F, 0x1C, 0xD8,
0xF9, 0x76, 0xBB, 0x1B, 0x33, 0x20, 0x00, 0x24, 0x60, 0x5E, 0xF5, 0xEC, 0x84, 0x80, 0x3B, 0xE1,
0x62, 0xF1, 0x62, 0xF1, 0x62, 0xF1, 0xF9, 0x16, 0x80, 0x0F, 0x3F, 0x1D, 0xFD, 0x62, 0x81, 0xA6,
0xB1, 0x1C, 0x62, 0xE1, 0x01, 0xE5, 0x1F, 0x12, 0xF4, 0x51, 0x36, 0x59, 0x87, 0x03, 0x03, 0xFC,
0x09, 0xCC, 0x0C, 0x87, 0x0C, 0x13, 0x0B, 0x5D, 0x7F, 0x5D, 0x5D, 0x66, 0x66, 0x66, 0x00, 0x00,
0x00, 0x00, 0x68, 0x60, 0x68, 0x68, 0x6C, 0x6C, 0x6C, 0x64, 0x0B, 0x39, 0x0F, 0xAC, 0x02, 0xE0,
0x62, 0x31, 0xC7, 0x02, 0x72, 0x72, 0x72, 0xEE, 0xEE, 0xEE, 0x03, 0xE1, 0x06, 0xC2, 0xC2, 0xC2,
0x00, 0x00, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0xF1, 0xC4, 0xC4, 0xC4, 0xC6, 0xC6, 0xC6, 0x51,
0x0C, 0xF3, 0x40, 0xF3, 0xF3, 0xFC, 0x03, 0xE1, 0x33, 0x62, 0xD1, 0x62, 0xF1, 0xBA, 0x20, 0x69,
0x00, 0xFC, 0xCC, 0x57, 0x80, 0xEB, 0x03, 0x20, 0x4F, 0x08, 0x2F, 0x84, 0x81, 0xF0, 0xE2, 0x09,
0x10, 0x21, 0x84, 0x50, 0x1F, 0x1A, 0x1B, 0x1D, 0x5A, 0x90, 0x85, 0x62, 0xF1, 0x62, 0xF1, 0x94,
0xC5, 0x70, 0x22, 0x74, 0x10, 0x1D, 0xF5, 0x0F, 0x43, 0x82, 0xB8, 0x08, 0x1E, 0x2F, 0x18, 0x1C,
0x89, 0x8D, 0x81, 0x63, 0xFC, 0x71, 0x21, 0x54, 0x46, 0xFA, 0x6E, 0x5F, 0x11, 0x14, 0x07, 0x3C,
0x3C, 0x3F, 0x3C, 0x6B, 0x01, 0xA5, 0x0C, 0xDA, 0xDA, 0xDA, 0x77, 0x01, 0x00, 0x00, 0xC6, 0x03,
0x30, 0x22, 0x3E, 0xC0, 0x0C, 0x5B, 0x08, 0xEF, 0x0D, 0xC7, 0x32, 0x46, 0x08, 0x5E, 0x05, 0xFF,
0xE4, 0x06, 0xB1, 0xB1, 0xB1, 0xA5, 0xA5, 0xA5, 0xA6, 0x01, 0xA6, 0xA6, 0x00, 0x00, 0x09, 0x90,
0x03, 0x30, 0x00, 0x00, 0x12, 0x00, 0xE3, 0x0A, 0xFC, 0x95, 0x95, 0x95, 0xCC, 0x03, 0xC0, 0x69,
0x62, 0xF1, 0x2D, 0xF0, 0x3C, 0x78, 0x18, 0x1C, 0xC3, 0x07, 0x57, 0x70, 0x9B, 0x07, 0x6A, 0x12,
0x30, 0x1D, 0x9F, 0x3F, 0x1B, 0x20, 0xFA, 0x64, 0x25, 0x3D, 0x18, 0x87, 0x00, 0x9A, 0x81, 0x10,
0x41, 0x16, 0x1C, 0x2D, 0x18, 0x1B, 0x23, 0x01, 0x59, 0x60, 0x62, 0xF1, 0x62, 0xF1, 0x2C, 0xF4,
0xA8, 0x23, 0x67, 0x11, 0x1D, 0x1F, 0xEE, 0x20, 0x87, 0xCD, 0x05, 0x1F, 0x3A, 0x18, 0x1C, 0x02,
0xDE, 0x10, 0xAD, 0xF0, 0xAD, 0x07, 0x1A, 0xAB, 0x00, 0x61, 0x15, 0x4E, 0x15, 0x37, 0x1C, 0xD2,
0x00, 0x38, 0x18, 0x1C, 0x27, 0x19, 0xE9, 0x14, 0x82, 0x50, 0x04, 0x2D, 0x2E, 0x2E, 0x12, 0x00,
0x6C, 0x00, 0xF9, 0xF9, 0x31, 0xF9, 0xD5, 0x0C, 0x18, 0x00, 0x64, 0x0B, 0x09, 0x00, 0x03, 0x00,
0x58, 0x58, 0x3E, 0x58, 0xBD, 0x09, 0x5B, 0x5B, 0x5B, 0x6E, 0x6E, 0x6E, 0x02, 0xDD, 0xDD, 0xDD,
0xBA, 0x09, 0xC7, 0x32, 0x2E, 0x08, 0x7F, 0x7F, 0x38, 0x7F, 0xDC, 0xDC, 0xDC, 0x07, 0x0E, 0x1E,
0x1E, 0x1E, 0x10, 0x1B, 0x00, 0x00, 0x00, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0xDE, 0x06, 0xFF,
0x03, 0x15, 0x00, 0xFF, 0x8E, 0x35, 0x62, 0x11, 0x62, 0xF1, 0x50, 0xFA, 0x83, 0x17, 0x1B, 0xDD,
0xC4, 0xAF, 0x0B, 0xDF, 0x18, 0x84, 0x20, 0x1A, 0xD7, 0xED, 0x24, 0x1A, 0x1B, 0x4B, 0x0A, 0x15,
0x1C, 0xC4, 0x07, 0x1E, 0xEA, 0x87, 0x20, 0xF0, 0x40, 0x02, 0x1F, 0xB3, 0x09, 0x1E, 0x2C, 0x1A,
0x1B, 0x00, 0x15, 0x62, 0x81, 0x62, 0xF1, 0x62, 0xF1, 0x62, 0xF1, 0x4A, 0x16, 0x1C, 0x1E, 0xD5,
0xF4, 0x82, 0xE8, 0x02, 0x20, 0x48, 0xFD, 0x07, 0x7D, 0x0D, 0xC2, 0x7B, 0xF3, 0xB0, 0x27, 0x79,
0x0F, 0x1D, 0xE0, 0x04, 0x1F, 0x03, 0xE8, 0x02, 0x1F, 0x54, 0x06, 0xB4, 0x09, 0x85, 0x0E, 0x1C,
0x18, 0x1E, 0x1E, 0x1D, 0x29, 0x2A, 0x2A, 0x5B, 0x5C, 0x00, 0x5C, 0x98, 0x01, 0x31, 0x0B, 0x8B,
0x05, 0x24, 0x00, 0xD5, 0x0C, 0xAF, 0x38, 0x00, 0x00, 0xFE, 0x65, 0x01, 0x50, 0x01, 0x6B, 0x04,
0x7B, 0x0C, 0xC3, 0x09, 0x62, 0x31, 0x0F, 0x00, 0x3A, 0x08, 0xFF, 0x71, 0x71, 0x71, 0xE4, 0x09,
0x59, 0x59, 0x59, 0x62, 0x01, 0x88, 0x1A, 0x04, 0x00, 0x00, 0x09, 0x90, 0x20, 0x91, 0xC7, 0xF2,
0x62, 0xF1, 0xC7, 0xF2, 0xB6, 0x07, 0xFF, 0x7A, 0x10, 0x1D, 0xFE, 0x79, 0x88, 0xB4, 0x08, 0x1E,
0x10, 0x27, 0x19, 0x26, 0xBD, 0x75, 0x5C, 0x2F, 0x19, 0x1B, 0x72, 0x0C, 0x11, 0x1D, 0xF7, 0xAD,
0x74, 0x21, 0xBE, 0x08, 0x1F, 0x08, 0x1E, 0x1B, 0x4F, 0x58, 0x62, 0xF1, 0x62, 0xF1, 0x35, 0xF1,
0xE0, 0x27, 0x30, 0x7C, 0x19, 0x1C, 0xB7, 0x08, 0x2A, 0xA0, 0x69, 0x06, 0x20, 0x1A, 0x30, 0x09,
0x20, 0xEE, 0xBB, 0x1E, 0x8C, 0x1A, 0x1C, 0xB2, 0x09, 0x7E, 0xA3, 0x8B, 0x7F, 0x0E, 0x1B, 0x20,
0x23, 0x22, 0x3F, 0x41, 0x00, 0x41, 0xC1, 0xC1, 0xC1, 0xE4, 0xE4, 0xE4, 0x92, 0x01, 0x80, 0x0F,
0x0F, 0x0F, 0x50, 0x07, 0x33, 0x00, 0x03, 0x30, 0x53, 0x31, 0xDC, 0x35, 0xF8, 0x3F, 0x3F, 0x3F,
0xD2, 0xD2, 0xD2, 0x92, 0x92, 0x00, 0x92, 0x62, 0x31, 0x67, 0x05, 0x62, 0x62, 0x62, 0x8E, 0x02,
0x8A, 0x09, 0xC6, 0x60, 0x3C, 0x0C, 0xC0, 0xA7, 0xFD, 0x62, 0x71, 0x62, 0xF1, 0xE9, 0xF1, 0x07,
0x22, 0x50, 0x7F, 0x15, 0x1D, 0x4A, 0x04, 0xBC, 0x94, 0x64, 0x12, 0x1D, 0x1D, 0x0C, 0x8D, 0xBC,
0x19, 0xD8, 0x26, 0x40, 0x16, 0x1C, 0xAD, 0x08, 0x05, 0x38, 0xA1, 0x95, 0x0C, 0x1E, 0x16, 0x2A,
0x90, 0x62, 0xF1, 0x62, 0xF1, 0xE1, 0x4B, 0xF9, 0x1C, 0x1B, 0x26, 0xCA, 0x02, 0x0F, 0x1D, 0xFC,
0x11, 0xDE, 0x80, 0xC8, 0x06, 0x1F, 0x3A, 0x17, 0x1B, 0x1E, 0x01, 0x1A, 0x1B, 0x19, 0x00, 0xBC,
0x2B, 0x19, 0x1B, 0x5C, 0x08, 0x13, 0x1C, 0xD6, 0x19, 0x82, 0xF2, 0x01, 0x1F, 0x46, 0x08, 0x14,
0x62, 0x11, 0x5B, 0x5D, 0x5D, 0x03, 0x03, 0x7A, 0x7A, 0x22, 0x7A, 0x89, 0x01, 0x00, 0x00, 0x0F,
0x00, 0x4C, 0xFB, 0x53, 0x04, 0xB5, 0x05, 0xD1, 0x7E, 0xD1, 0xD1, 0x91, 0x05, 0x05, 0x0A, 0x3B,
0x01, 0xCA, 0x02, 0x43, 0x43, 0x3C, 0x43, 0xD4, 0xD4, 0xD4, 0x9C, 0x9C, 0x9C, 0x38, 0x34, 0x80,
0x36, 0xC0, 0x37, 0xFB, 0x62, 0xC1, 0x62, 0xF1, 0x86, 0xF7, 0x2D, 0x19, 0x1B, 0x1F, 0x9A, 0x0C,
0x84, 0xA0, 0xD2, 0x05, 0x1F, 0x58, 0x14, 0x04, 0x1D, 0x28, 0x03, 0x10, 0x84, 0x00, 0x79, 0x05,
0xC5, 0x11, 0x3D, 0x17, 0x3C, 0x1B, 0x7B, 0x0F, 0x1D, 0xEA, 0x5F, 0x81, 0xF2, 0x02, 0x20, 0x20,
0x55, 0x15, 0x1C, 0x18, 0x2A, 0x90, 0x62, 0xF1, 0x62, 0xF1, 0xE0, 0x97, 0xF2, 0x2E, 0x28, 0x42,
0x16, 0x1C, 0xD4, 0x05, 0x24, 0xA0, 0x83, 0xA5, 0x0B, 0x1E, 0x39, 0x18, 0xAE, 0x16, 0x20, 0xF1,
0x08, 0xA0, 0x1A, 0x1B, 0x25, 0x1A, 0x1B, 0x2E, 0x19, 0x1C, 0x00, 0x4C, 0x15, 0x1C, 0xA6, 0xA3,
0xB2, 0xBD, 0x07, 0x1E, 0x10, 0x2D, 0x16, 0x1A, 0x23, 0x28, 0x27, 0x79, 0x7A, 0x00, 0x7A, 0x62,
0x01, 0x1E, 0x00, 0x15, 0x00, 0x1D, 0x37, 0xA8, 0xF9, 0xC1, 0x02, 0x5E, 0x7E, 0x5E, 0x5E, 0xED,
0xED, 0xED, 0x8F, 0x8F, 0x8F, 0x00, 0x62, 0x01, 0xDB, 0x09, 0x36, 0x00, 0x44, 0x04, 0x38, 0x04,
0x8B, 0x02, 0x46, 0x46, 0x3F, 0x46, 0x7E, 0x69, 0xA8, 0xF9, 0xBB, 0x32, 0xF6, 0x36, 0x62, 0x71,
0x62, 0xF1, 0x81, 0xF0, 0xFE, 0x51, 0x20, 0x4D, 0x15, 0x1C, 0xD9, 0x05, 0xCD, 0xA2, 0xF2, 0x01,
0xC1, 0x84, 0x0E, 0x1E, 0x8A, 0x00, 0x53, 0x15, 0x1C, 0x58, 0x08, 0x14, 0x1C, 0x78, 0x00, 0x9A,
0x0B, 0x1E, 0xE6, 0x02, 0x04, 0x84, 0xA0, 0xBB, 0x05, 0x23, 0x1A, 0x6E, 0xF7, 0x1B, 0xC7, 0xF2,
0x62, 0xF1, 0xD3, 0xDE, 0xF0, 0x29, 0x1A, 0x1B, 0x7E, 0x10, 0x1D, 0x24, 0x90, 0x81, 0xFE, 0x00,
0x20, 0xB5, 0x08, 0x1E, 0x6F, 0x10, 0x00, 0x1D, 0x57, 0x14, 0x1C, 0x52, 0x15, 0x1C, 0x90, 0x03,
0x80, 0x7D, 0x0F, 0x1D, 0xB6, 0x09, 0x5C, 0xD1, 0x69, 0x10, 0x20, 0x1C, 0x11, 0x1A, 0x19, 0x24,
0x26, 0x26, 0x6D, 0x00, 0x6E, 0x6E, 0xE6, 0xE6, 0xE6, 0x89, 0x04, 0x63, 0x00, 0x24, 0x00, 0xE0,
0x3C, 0x60, 0x88, 0x68, 0x89, 0x01, 0x39, 0x39, 0x39, 0x53, 0x04, 0xA3, 0x02, 0xC7, 0x87, 0x87,
0x87, 0x62, 0x91, 0x50, 0x50, 0x50, 0xEB, 0x08, 0xEB, 0xEB, 0x26, 0x01, 0x18, 0x60, 0x7B, 0x99,
0x5B, 0x35, 0x3E, 0x01, 0x7B, 0x3F, 0xFC, 0x93, 0x36, 0x62, 0x91, 0x62, 0xF1, 0x35, 0xF4, 0x23,
0x1B, 0x1B, 0x6C, 0x0F, 0x12, 0x1D, 0xF6, 0x18, 0xB0, 0xFC, 0x00, 0x20, 0xE4, 0x08, 0x03, 0x1F,
0xD7, 0x04, 0x1F, 0xDA, 0x04, 0x1F, 0x00, 0xED, 0x84, 0xE0, 0xD8, 0x05, 0x1F, 0x80, 0x01, 0xEE,
0x44, 0xC7, 0xF2, 0xE2, 0xD9, 0x05, 0x62, 0xE1, 0x44, 0x62, 0xB1, 0xDE, 0xF0, 0x32, 0x18, 0x1C,
0x1B, 0xA5, 0x0A, 0x65, 0xD1, 0xF4, 0xAE, 0x23, 0xD6, 0x04, 0x1F, 0x14, 0xDC, 0x04, 0x1F, 0xF8,
0x01, 0xC6, 0xD0, 0xA1, 0x0B, 0x20, 0x1E, 0x21, 0x4A, 0x07, 0x1A, 0x19, 0x1B, 0x00, 0xE2, 0x05,
0xEA, 0x64, 0xEA, 0xEA, 0x9E, 0x01, 0x26, 0x26, 0x26, 0x23, 0x04, 0x00, 0x00, 0xC4, 0xEE, 0x62,
0x3C, 0x00, 0x44, 0x01, 0x2C, 0x04, 0x83, 0x83, 0x83, 0x9E, 0x01, 0x8F, 0xF4, 0xF4, 0xF4, 0x61,
0x0E, 0xCA, 0x02, 0x12, 0x33, 0x2D, 0x00, 0x38, 0x01, 0xF8, 0x89, 0x89, 0x89, 0xFE, 0xFE, 0xFE,
0x97, 0x02, 0x29, 0x01, 0xC0, 0xA0, 0x05, 0x1E, 0x00, 0xD5, 0x63, 0x44, 0x01, 0x12, 0x00, 0x41,
0x01, 0x81, 0x81, 0x3F, 0x81, 0x7C, 0x7C, 0x7C, 0x5E, 0x02, 0x62, 0xA1, 0x62, 0xF1, 0x65, 0xF1,
0xF0, 0x84, 0x20, 0x4D, 0x04, 0x77, 0x10, 0x1D, 0xEE, 0x02, 0x1F, 0x03, 0x0F, 0xF0, 0x6F, 0xF0,
0xDB, 0x04, 0x1F, 0x49, 0x17, 0x1C, 0x03, 0x16, 0x5F, 0x31, 0x62, 0xF1, 0x7F, 0x22, 0x3F, 0x17,
0x1C, 0xCF, 0x0E, 0x06, 0x1F, 0x33, 0x60, 0xEE, 0x02, 0x20, 0x43, 0x16, 0x04, 0x62, 0x81, 0xD4,
0xF0, 0x2C, 0x21, 0x36, 0x18, 0x1C, 0xA9, 0x09, 0x07, 0x1E, 0x00, 0x00, 0x0F, 0xF0, 0xD2, 0xF0,
0xA8, 0x0B, 0x1E, 0x28, 0x0E, 0x19, 0x1B, 0x18, 0x39, 0x23, 0x8A, 0x0E, 0x89, 0x01, 0x91, 0x91,
0x38, 0x91, 0xFF, 0xFF, 0xFF, 0x68, 0x01, 0x36, 0x36, 0x36, 0x10, 0x06, 0x00, 0x3F, 0x00, 0x24,
0x24, 0x24, 0x3C, 0x00, 0x37, 0x37, 0x23, 0x37, 0x57, 0x57, 0x57, 0x47, 0x01, 0xE5, 0xE5, 0xE5,
0x10, 0x90, 0x90, 0x90, 0xCE, 0xCE, 0xCE, 0x7A, 0x01, 0x4B, 0x00, 0xC0, 0x85, 0x65, 0x8B, 0x0B,
0x65, 0x01, 0x9F, 0x9F, 0x9F, 0xFB, 0xFB, 0x07, 0xFB, 0x99, 0x99, 0x99, 0x45, 0x45, 0x45, 0xA9,
0x02, 0x80, 0x6D, 0x0B, 0xEE, 0x02, 0x76, 0x02, 0x0B, 0x01, 0x51, 0x51, 0x51, 0xA1, 0x0F, 0xA1,
0xA1, 0xE7, 0xE7, 0xE7, 0x6D, 0x6D, 0x6D, 0x00, 0x19, 0x0E, 0x74, 0x01, 0x32, 0x01, 0x2A, 0x2A,
0x2A, 0x47, 0x01, 0xC5, 0x47, 0xC5, 0xC5, 0xFF, 0x03, 0xF9, 0x03, 0x62, 0xA1, 0x65, 0xF1, 0xEC,
0x21, 0x22, 0x7C, 0x1A, 0x1B, 0x5D, 0x13, 0x1C, 0xC7, 0x07, 0x1F, 0x00, 0xFD, 0x84, 0x50, 0x81,
0xF0, 0xF8, 0x01, 0x20, 0xAB, 0x0A, 0x06, 0x1E, 0x3C, 0x17, 0x92, 0x04, 0x5F, 0x51, 0xAA, 0xF4,
0x36, 0x20, 0x33, 0x78, 0x18, 0x1C, 0xC9, 0x06, 0x3C, 0x00, 0x22, 0x39, 0x20, 0x21, 0x50, 0xEC,
0x02, 0x21, 0x3B, 0x17, 0x1C, 0x1A, 0x71, 0x64, 0x80, 0xD4, 0xF0, 0xE1, 0x10, 0xA3, 0x12, 0x30,
0x18, 0x1B, 0x87, 0x0F, 0x07, 0x1E, 0xE1, 0x04, 0x1F, 0x0F, 0x60, 0x03, 0x30, 0x00, 0x00, 0x03,
0x00, 0xF0, 0xFF, 0x00, 0x21, 0xFF, 0x00, 0x20, 0xE3, 0x03, 0x00, 0x1F, 0x05, 0x01, 0x27, 0x1A,
0x1C, 0x17, 0x37, 0x22, 0x1A, 0x42, 0xA4, 0x51, 0x31, 0x31, 0x31, 0x23, 0x0D, 0xFC, 0xFC, 0xFC,
0x11, 0xCC, 0xCC, 0xCC, 0x8A, 0x8A, 0x8A, 0x76, 0x76, 0x00, 0x76, 0x78, 0x78, 0x78, 0x85, 0x85,
0x85, 0xB5, 0x00, 0xB5, 0xB5, 0x56, 0x01, 0xD6, 0xD6, 0xD6, 0x9D, 0x0B, 0x2B, 0x44, 0x2B, 0x2B,
0x53, 0x01, 0xD0, 0xD0, 0xD0, 0x2C, 0x2C, 0x04, 0x2C, 0x15, 0x15, 0x15, 0x48, 0x60, 0x2D, 0x00,
0x36, 0x00, 0x93, 0x70, 0x93, 0x93, 0xEC, 0xEC, 0xEC, 0x6B, 0x01, 0x9D, 0x9D, 0x20, 0x9D, 0x2F,
0x01, 0x74, 0x74, 0x74, 0x7E, 0x7E, 0x7E, 0x02, 0xA7, 0xA7, 0xA7, 0xE0, 0xE0, 0xE0, 0xE3, 0xE3,
0x00, 0xE3, 0x65, 0x65, 0x65, 0x12, 0x12, 0x12, 0x00, 0x00, 0x80, 0x62, 0x31, 0x32, 0x01, 0xAF,
0xAF, 0xAF, 0xD7, 0xD7, 0xD7, 0x03, 0x2E, 0x2E, 0x2E, 0xC9, 0x13, 0x5F, 0xF1, 0x48, 0xF0, 0x84,
0x20, 0x2E, 0x78, 0x1A, 0x1B, 0x6D, 0x11, 0x1D, 0xA9, 0x0A, 0x1E, 0x00, 0xCF, 0x07, 0x1F, 0xEA,
0x02, 0x84, 0x10, 0xEF, 0x01, 0x20, 0x20, 0xDD, 0x04, 0x1F, 0xC3, 0x08, 0x1F, 0x9A, 0x00, 0x0C,
0x1E, 0x59, 0x14, 0x1D, 0x9B, 0x01, 0x18, 0x36, 0xE0, 0xA0, 0xA1, 0xF1, 0x24, 0x1B, 0x1B, 0x7F,
0x0F, 0x1D, 0xB7, 0x01, 0x08, 0x1E, 0xAC, 0x0A, 0x1E, 0xAE, 0x0A, 0x1E, 0x00, 0x94, 0x0D, 0x1E,
0x2B, 0x1A, 0x1C, 0xE7, 0xD3, 0x02, 0xF4, 0xC0, 0x68, 0x21, 0xBA, 0x0E, 0x3E, 0x17, 0x1B, 0x89,
0x0D, 0x1E, 0x03, 0xB7, 0x09, 0x1E, 0xDB, 0x05, 0x1F, 0xF0, 0x01, 0x00, 0x20, 0xEF, 0x02, 0x20,
0xE9, 0x03, 0x20, 0xD7, 0x00, 0x05, 0x1F, 0xB4, 0x09, 0x1E, 0x85, 0x0F, 0x1E, 0x00, 0x3C, 0x18,
0x1B, 0x16, 0x99, 0xE3, 0x86, 0x31, 0x27, 0x27, 0x30, 0x27, 0x6F, 0x6F, 0x6F, 0xC0, 0xC0, 0xC0,
0xE1, 0x00, 0xE1, 0xE1, 0x3C, 0x00, 0x00, 0x00, 0xDE, 0xDE, 0xDE, 0xB8, 0x0C, 0xB8, 0xB8, 0x7B,
0x7B, 0x7B, 0x33, 0x33, 0x33, 0x00, 0x5F, 0x31, 0x5F, 0x5F, 0x5F, 0x85, 0x0B, 0x29, 0x29, 0x29,
0x11, 0x2D, 0x00, 0x26, 0xC1, 0x29, 0x01, 0x6D, 0x0B, 0xA3, 0xA3, 0xA3, 0xD8, 0x0F, 0xD8, 0xD8,
0xE2, 0xE2, 0xE2, 0x00, 0x00, 0xDF, 0xDF, 0x20, 0xDF, 0xC8, 0xC8, 0xC8, 0x8D, 0x8D, 0x8D, 0x3D,
0x00, 0x3D, 0x3D, 0x5F, 0x31, 0x38, 0x61, 0x20, 0x01, 0x63, 0x63, 0x63, 0x1C, 0x77, 0x77, 0x77,
0x25, 0x25, 0x25, 0x4A, 0x11, 0x46, 0xF0, 0xC0, 0x84, 0xF0, 0x81, 0x30, 0x1A, 0x1B, 0x18, 0x78,
0x20, 0x35, 0x18, 0x23, 0x1B, 0x4F, 0x15, 0x1D, 0x81, 0x00, 0x52, 0x14, 0x1D, 0x10, 0x41, 0x17,
0x1C, 0x28, 0x1A, 0x1B, 0x11, 0x5C, 0x21, 0x80, 0x0F, 0xF0, 0x25, 0xF0, 0x30, 0x1C, 0x1A, 0x1B,
0x17, 0xA7, 0x01, 0x11, 0x11, 0xC7, 0x23, 0x11, 0x0F, 0x1D, 0x1B, 0x1E, 0x01, 0x10, 0x4A, 0xF0,
0xDE, 0xF0, 0xE1, 0x18, 0x10, 0xAD, 0x00, 0x16, 0xEB, 0x0B, 0x1B, 0x1B, 0x40, 0x17, 0x0B, 0x1C,
0x53, 0x13, 0x1D, 0x53, 0x14, 0x1D, 0x4C, 0x00, 0x15, 0x1D, 0x3A, 0x18, 0x1B, 0x4D, 0x00, 0x0F,
0x5C, 0x01, 0xA0, 0x03, 0x20, 0xD8, 0xF0, 0xE8, 0x38, 0x15, 0x00, 0x18, 0x00, 0x42, 0x42, 0x42,
0x1F, 0x53, 0x53, 0x53, 0x4E, 0x4E, 0x4E, 0x3E, 0x3E, 0x00, 0x3E, 0x18, 0x00, 0x9A, 0x0B, 0x1E,
0x00, 0x0C, 0x00, 0x48, 0x00, 0x47, 0x01, 0x0A, 0x7E, 0x0A, 0x0A, 0x12, 0x30, 0x65, 0xC1, 0x33,
0x00, 0x18, 0x00, 0x1D, 0x01, 0x34, 0x7C, 0x34, 0x34, 0x4D, 0x4D, 0x4D, 0x54, 0x54, 0x54, 0x00,
0x48, 0x48, 0x48, 0x22, 0x22, 0x22, 0x11, 0x11, 0x00, 0x11, 0x1D, 0x01, 0xCA, 0x05, 0x29, 0x91,
0x20, 0x20, 0x20, 0xFF, 0x00, 0x8E, 0x0D, 0x0D, 0x0D, 0x76, 0x08, 0x07, 0x70, 0x42, 0xF0, 0x48,
0xF0, 0x4E, 0x50, 0xF8, 0x16, 0x87, 0x50, 0x12, 0x84, 0x20, 0x16, 0x1C, 0x36, 0xC0, 0x2F, 0xF0,
0xCA, 0x39, 0xF0, 0x00, 0x00, 0x4B, 0x50, 0x23, 0x61, 0x42, 0xF0, 0x78, 0xF0, 0x18, 0x50, 0x18,
0x7F, 0x09, 0x00, 0x1B, 0x1B, 0x12, 0x00, 0x00, 0x1C, 0x1B, 0x13, 0x11, 0x1C, 0x1B, 0x14, 0x1C,
0x1B, 0x18, 0xCF, 0x20, 0x19, 0x40, 0x05, 0x50, 0x39, 0xF0, 0x03, 0x00, 0x39, 0x30, 0x3F, 0x60,
0x3C, 0xC0, 0x50, 0xC1, 0x2D, 0xF0, 0xFF, 0x3B, 0x07, 0x0F, 0x00, 0x17, 0x17, 0x17, 0x03, 0x00,
0x08, 0x0A, 0x0B, 0x0A, 0xE3, 0x18, 0x18, 0x18, 0x15, 0x30, 0x15, 0xF0, 0x05, 0x71, 0x0F, 0xF0,
0x33, 0xF0, 0xF8, 0x81, 0xF0, 0x81, 0xF0, 0x0F, 0xF0, 0x21, 0xF0, 0x36, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x27, 0xF0, 0xFF, 0x09, 0x80, 0x47, 0x06, 0x03, 0x30, 0x00, 0x00, 0x35, 0xC0, 0x27, 0xF0,
0x3F, 0xF0, 0x3C, 0xF0, 0xFF, 0x30, 0xF0, 0xB3, 0xF1, 0xFA, 0xF2, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x7A, 0xF1, 0x5B, 0xF8, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0,
0x0F, 0xF0, 0x1A, 0xF7, 0x5B, 0xF8, 0x5C, 0xFD, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x1D, 0xF7, 0xFF, 0x79, 0xFB, 0x6D,
0x9B, 0x62, 0x01, 0x00, 0x00, 0xC1, 0x02, 0x03, 0x30, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x09, 0x90, 0xFF,
0x03, 0x30, 0x00, 0x00, 0x8B, 0x3B, 0xFB, 0x3D, 0x62, 0x01, 0x81, 0x0C, 0x6A, 0x6A, 0x3F, 0x6A,
0x42, 0x0F, 0x03, 0x30, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFE, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x88, 0x0B,
0xFF, 0x03, 0x0C, 0x4F, 0x4F, 0x4F, 0x6D, 0x0B, 0x8F, 0x0A, 0x05, 0x0A, 0xC6, 0x0F, 0xF1, 0xA8,
0xA8, 0xA8, 0x03, 0x30, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xF8, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0xFF, 0x9C,
0x9C, 0x9C, 0xA9, 0xA9, 0xA9, 0xCE, 0x0D, 0x09, 0x00, 0xC0, 0x62, 0x01, 0xB2, 0x08, 0x6B, 0x0A,
0xF4, 0x0B, 0x03, 0x30, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0xFF, 0x00, 0x00, 0x03,
0x00, 0x0C, 0x0C, 0x0C, 0xBE, 0x08, 0xF1, 0x08, 0x86, 0xC4, 0xE3, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0C,
0xC0, 0xEA, 0xF6, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF,
0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0,
0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x36, 0xF0,
0xFD, 0xC2, 0xFF, 0x76, 0xC2, 0x24, 0xF0, 0x1B, 0xF0, 0x12, 0xF0, 0xAE, 0xF0, 0x24, 0xF0, 0x66,
0xF0, 0x66, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x21, 0xF0, 0x9B, 0xF1, 0x1B, 0xF0,
0x02, 0xF1, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x39, 0xF0, 0xD4, 0x67, 0x7B, 0x30, 0x15,
0x90, 0x7F, 0x62, 0x39, 0xC0, 0xFF, 0x30, 0xF0, 0xB2, 0x6B, 0x7D, 0x61, 0x90, 0xF0, 0x27, 0xF0,
0x27, 0xF0, 0xB8, 0x6E, 0x1E, 0xF0, 0xFF, 0x65, 0xF4, 0x0F, 0xF0, 0x0F, 0xF0, 0x18, 0xF0, 0x1B,
0xF0, 0x12, 0xF0, 0xA2, 0x90, 0x1E, 0xF0, 0xFF, 0x5D, 0x90, 0x02, 0xF1, 0xDB, 0xF0, 0xF7, 0x32,
0x00, 0x00, 0x21, 0x03, 0xEE, 0x32, 0x78, 0x00, 0xFF, 0x51, 0x30, 0xB7, 0x03, 0x40, 0x05, 0xF3,
0x03, 0xF2, 0x01, 0x76, 0x02, 0x39, 0x00, 0xD6, 0x32, 0xFF, 0x45, 0x90, 0x42, 0xCF, 0x18, 0x00,
0x35, 0x01, 0x9F, 0x00, 0x60, 0x90, 0x2C, 0x01, 0x27, 0x00, 0xFF, 0x90, 0x00, 0xCF, 0x30, 0x97,
0xFB, 0x82, 0x62, 0x00, 0x06, 0xE7, 0x00, 0x0F, 0xF0, 0x1E, 0xF0, 0xFF, 0x84, 0x3C, 0x4F, 0xCB,
0x65, 0xF1, 0x56, 0xF1, 0xDE, 0x36, 0xD6, 0x02, 0xC8, 0x0A, 0xA7, 0x01, 0xFF, 0x03, 0x30, 0x08,
0x61, 0x8A, 0x39, 0x83, 0x01, 0xD9, 0x02, 0x4F, 0x02, 0x14, 0xC1, 0x38, 0xC1, 0xFF, 0xD2, 0xC3,
0x72, 0x60, 0x8D, 0x60, 0x7E, 0x60, 0x2D, 0x00, 0x81, 0x00, 0x1A, 0x04, 0x4D, 0x04, 0xFF, 0x30,
0x00, 0x81, 0x06, 0xDD, 0x04, 0x74, 0x01, 0x0B, 0x04, 0xF6, 0x00, 0x2A, 0x03, 0x6F, 0x03, 0xFF,
0xCC, 0x03, 0xF0, 0x00, 0xA8, 0x03, 0x7D, 0x01, 0xC4, 0x02, 0x45, 0x60, 0x06, 0xCC, 0xD4, 0x01,
0xFF, 0xD8, 0x00, 0xC1, 0x02, 0x15, 0x03, 0x62, 0x91, 0x4D, 0x01, 0x6A, 0x02, 0x3D, 0x35, 0x0C,
0x00, 0xFF, 0x2A, 0xF3, 0x22, 0x6E, 0x76, 0x02, 0x4E, 0x03, 0x6A, 0x05, 0x66, 0x30, 0x03, 0xC3,
0x6F, 0x99, 0xFF, 0xC5, 0x01, 0x01, 0x32, 0xE2, 0xC2, 0x62, 0xF1, 0x62, 0xF1, 0x1B, 0x33, 0xD1,
0x01, 0x33, 0x00, 0xFF, 0xD9, 0x02, 0x03, 0x30, 0x03, 0x30, 0x62, 0x31, 0x7B, 0x0C, 0x2E, 0x02,
0x28, 0x02, 0x62, 0x01, 0xFF, 0x5F, 0x9A, 0x33, 0x30, 0xB1, 0x00, 0x9C, 0x00, 0x12, 0x00, 0x2A,
0x00, 0x45, 0x00, 0xED, 0x30, 0xFF, 0x08, 0x31, 0x12, 0x00, 0xBA, 0x00, 0x48, 0x00, 0x39, 0x00,
0xD8, 0x60, 0x3C, 0x00, 0x33, 0x00, 0xFF, 0x09, 0x00, 0x61, 0x02, 0x59, 0x01, 0x09, 0x00, 0x6C,
0x00, 0x70, 0x05, 0x54, 0x00, 0x7E, 0x00, 0xFF, 0xB9, 0x04, 0x1D, 0x01, 0x81, 0x00, 0x09, 0x00,
0x49, 0x02, 0x3C, 0x00, 0x20, 0x04, 0x7B, 0x30, 0xFF, 0x12, 0x00, 0x08, 0x01, 0x5A, 0x39, 0x7B,
0x30, 0xB1, 0x00, 0x0B, 0x01, 0x23, 0x01, 0xF7, 0x05, 0xFF, 0x6E, 0x04, 0x2C, 0xC4, 0xA1, 0x01,
0x37, 0x02, 0x57, 0x00, 0x7E, 0x06, 0x5D, 0x60, 0x1E, 0x00, 0xFF, 0xF9, 0x00, 0x45, 0x00, 0x4A,
0x3A, 0x6F, 0x36, 0xC7, 0x02, 0x22, 0x3B, 0x30, 0x00, 0x09, 0x33, 0xFF, 0x5D, 0x00, 0x4E, 0x00,
0xB6, 0x01, 0x36, 0x39, 0x4B, 0x00, 0xA6, 0x02, 0xB4, 0x03, 0x3C, 0x00, 0xFF, 0x38, 0x01, 0x0C,
0x00, 0x17, 0x01, 0xB4, 0x06, 0x3C, 0x00, 0xEA, 0x03, 0x1E, 0x30, 0xC0, 0xF9, 0xFF, 0x4C, 0xC8,
0x08, 0x01, 0x19, 0x02, 0x36, 0x06, 0x02, 0x01, 0x84, 0x00, 0xF9, 0x03, 0x50, 0x01, 0xFF, 0xDE,
0x00, 0x35, 0x31, 0x37, 0x05, 0x18, 0x00, 0xF6, 0x66, 0x9C, 0x60, 0x32, 0x07, 0xA6, 0x05, 0xFF,
0x1B, 0x00, 0x09, 0x03, 0x62, 0x07, 0xB7, 0x03, 0x12, 0x00, 0x55, 0x02, 0xCF, 0x00, 0x90, 0x00,
0xFF, 0x12, 0x00, 0x68, 0x01, 0x81, 0x00, 0xCD, 0x02, 0x70, 0x70, 0x70, 0x4E, 0x00, 0x8F, 0x36,
0x00, 0x0F, 0x00, 0x50, 0x50, 0x50, 0x74, 0x01, 0xAE, 0x00, 0x38, 0x01, 0xE3, 0xC8, 0x01, 0x6E,
0x04, 0xED, 0x00, 0x3F, 0x00, 0x27, 0x00, 0x5F, 0x01, 0x38, 0x01, 0xB1, 0x7F, 0xB1, 0xB1, 0xA8,
0x00, 0xEA, 0x03, 0x48, 0x00, 0x8C, 0x01, 0x12, 0x00, 0x8D, 0x30, 0xFC, 0x31, 0x02, 0x40, 0x05,
0x6E, 0x04, 0x21, 0x06, 0xF2, 0x01, 0xB9, 0x04, 0x64, 0x02, 0x43, 0x02, 0xFF, 0x75, 0x00, 0xAA,
0xAA, 0xAA, 0x5C, 0x01, 0x62, 0x61, 0xBF, 0x31, 0x03, 0x00, 0xF1, 0xA2, 0x03, 0x21, 0x00, 0x40,
0x02, 0x9F, 0x00, 0xD4, 0x01, 0xC5, 0x01, 0x5B, 0x02, 0x18, 0x00, 0xFF, 0x72, 0x06, 0xF9, 0x00,
0x22, 0x02, 0x21, 0x00, 0x40, 0x32, 0x0D, 0x02, 0x86, 0x01, 0x58, 0x02, 0xFF, 0xA7, 0x07, 0xDB,
0x00, 0x06, 0x00, 0x60, 0x00, 0xB3, 0x01, 0xF0, 0x03, 0x21, 0x00, 0x1B, 0x00, 0xFF, 0xF4, 0x02,
0xBD, 0xBD, 0xBD, 0x16, 0x02, 0xAA, 0x34, 0xC0, 0x00, 0x39, 0x00, 0xF1, 0xA4, 0x01, 0x23, 0x01,
0x97, 0x02, 0x00, 0x00, 0x0F, 0x60, 0xE1, 0x30, 0x44, 0x3A, 0xE7, 0x96, 0xFF, 0x9C, 0x00, 0xAE,
0x00, 0x3D, 0x05, 0x03, 0x03, 0x95, 0x04, 0x7C, 0x7C, 0x7C, 0x1F, 0x92, 0x01, 0x8D, 0x00, 0xCA,
0x02, 0x12, 0x00, 0x5D, 0x00, 0x62, 0x31, 0x91, 0x95, 0xA3, 0x02, 0xFF, 0xCE, 0x01, 0x3C, 0x00,
0xCF, 0x00, 0x21, 0x03, 0xAF, 0xAF, 0xAF, 0x68, 0x01, 0x8F, 0xA5, 0x00, 0xF8, 0x01, 0x6D, 0x6D,
0x6D, 0x3F, 0x00, 0x37, 0x02, 0x7B, 0x00, 0xE3, 0x51, 0x00, 0x51, 0x03, 0x1E, 0x06, 0xA4, 0x01,
0xB7, 0x00, 0x1D, 0x01, 0xBE, 0x02, 0x66, 0x7F, 0x66, 0x66, 0x66, 0x00, 0xEF, 0x01, 0x5D, 0x00,
0xD2, 0x00, 0xC7, 0x02, 0x09, 0x00, 0xFC, 0x62, 0x01, 0xC3, 0x00, 0xE2, 0x02, 0x5B, 0x05, 0x05,
0x01, 0x1B, 0x00, 0xBB, 0x02, 0x0F, 0x00, 0xFF, 0x5A, 0x00, 0x08, 0x01, 0x90, 0x00, 0xD5, 0x00,
0xE9, 0x01, 0x52, 0x02, 0x30, 0x03, 0x1B, 0x00, 0xFF, 0x7C, 0x02, 0x6B, 0x01, 0x30, 0x03, 0x00,
0x03, 0xBA, 0xBA, 0xBA, 0x5D, 0x00, 0x8F, 0x62, 0x91, 0x9F, 0x03, 0xB2, 0x02, 0x0F, 0x00, 0x5A,
0x00, 0x30, 0x00, 0xA2, 0x00, 0x7B, 0x30, 0xFF, 0x8A, 0x8A, 0x8A, 0xEA, 0x00, 0x51, 0x03, 0xD7,
0x01, 0x68, 0x01, 0x0F, 0x00, 0xF8, 0x73, 0x02, 0x38, 0x01, 0x9F, 0x00, 0x8F, 0x01, 0x6F, 0x03,
0x7E, 0x00, 0x72, 0x00, 0x5D, 0x03, 0xFF, 0x00, 0x00, 0xFC, 0x03, 0x7E, 0x03, 0x17, 0x04, 0xDE,
0x00, 0xC9, 0x00, 0x26, 0x01, 0x55, 0x7F, 0x55, 0x55, 0x15, 0x00, 0x8E, 0x05, 0x06, 0x00, 0xE9,
0x01, 0x3C, 0x00, 0xDB, 0x00, 0xFC, 0xEA, 0x03, 0xB4, 0x00, 0x0C, 0x00, 0x3D, 0x38, 0x90, 0x00,
0x5C, 0x01, 0xC7, 0x38, 0x91, 0x95, 0xFF, 0x3A, 0x02, 0xC3, 0x03, 0x62, 0x01, 0xBE, 0x02, 0xB4,
0xB4, 0xB4, 0x7B, 0x00, 0x8F, 0x0E, 0x01, 0xCA, 0x02, 0xFE, 0x04, 0x12, 0x00, 0xF0, 0x00, 0x62,
0x01, 0x62, 0xF1, 0xBA, 0x00, 0xFF, 0x8F, 0x01, 0x09, 0x09, 0x09, 0x5D, 0x00, 0x27, 0x00, 0x02,
0x04, 0x77, 0x01, 0xF1, 0xA0, 0x35, 0x69, 0x00, 0x60, 0x00, 0x83, 0x01, 0x38, 0x01, 0x0F, 0x00,
0x52, 0x52, 0x3F, 0x52, 0x75, 0x03, 0x69, 0x00, 0xBC, 0x01, 0x28, 0x05, 0x6A, 0x02, 0x12, 0x00,
0xE0, 0x01, 0xFE, 0xC0, 0x00, 0x66, 0x00, 0x30, 0x00, 0x27, 0x00, 0xDE, 0x00, 0xBA, 0x00, 0x8F,
0x01, 0x7D, 0x7F, 0x7D, 0x7D, 0x4D, 0x01, 0xD7, 0x01, 0xC7, 0x32, 0x62, 0x01, 0x41, 0x04, 0x99,
0x00, 0xFC, 0xE4, 0x03, 0x72, 0x00, 0x52, 0x02, 0x9E, 0x01, 0x94, 0x02, 0x9C, 0x00, 0x33, 0x00,
0x03, 0x7F, 0x03, 0x03, 0xFF, 0x03, 0x63, 0x00, 0x2A, 0x00, 0x62, 0xC1, 0xB1, 0x03, 0xC3, 0x30,
0xFC, 0x2C, 0x04, 0x12, 0x00, 0x62, 0x01, 0x63, 0x00, 0xA7, 0xA7, 0xA7, 0xB6, 0x04, 0x8F, 0x77,
0x01, 0xAD, 0x04, 0x9A, 0x9A, 0x9A, 0xFD, 0x05, 0x62, 0x01, 0xAD, 0x63, 0xAD, 0xAD, 0xD1, 0x01,
0xA8, 0x00, 0xA4, 0x04, 0x0D, 0x35, 0x02, 0x01, 0x53, 0x7C, 0x53, 0x53, 0xBD, 0x03, 0x60, 0x00,
0xF3, 0x00, 0xC7, 0x32, 0xDE, 0x00, 0x47, 0x01, 0xFC, 0x62, 0x31, 0xA6, 0xA6, 0xA6, 0xD3, 0x35,
0x04, 0x02, 0xA4, 0xA4, 0x31, 0xA4, 0xE0, 0x01, 0x45, 0x00, 0x3F, 0x36, 0x54, 0x00, 0xC6, 0x00,
0x51, 0x00, 0xA6, 0x02, 0xFE, 0xA8, 0x36, 0xC7, 0x62, 0xCF, 0x00, 0x62, 0x31, 0x72, 0x03, 0x0C,
0x00, 0xB1, 0x00, 0x8C, 0x01, 0xFF, 0xFF, 0x00, 0x19, 0x02, 0x53, 0x01, 0x5D, 0x00, 0x62, 0xF1,
0x2A, 0x03, 0x4D, 0x01, 0xED, 0x00, 0xFF, 0x4B, 0x4B, 0x4B, 0xCC, 0x00, 0x32, 0x04, 0x84, 0x00,
0xC7, 0x02, 0xCB, 0x01, 0xF8, 0x3C, 0x00, 0xC1, 0x02, 0x12, 0x00, 0x15, 0x00, 0x27, 0x00, 0x45,
0x45, 0x45, 0x1F, 0x04, 0x02, 0xE0, 0x04, 0x62, 0x01, 0x1E, 0x00, 0x48, 0x00, 0x1E, 0x00, 0xCF,
0x03, 0xED, 0x00, 0xFF, 0xCB, 0x01, 0x3E, 0x3E, 0x3E, 0x02, 0x01, 0xC6, 0x00, 0x31, 0x02, 0x09,
0x00, 0xF1, 0x62, 0x61, 0x84, 0x00, 0x81, 0x81, 0x81, 0xA1, 0x01, 0x54, 0x54, 0x23, 0x54, 0x3C,
0x00, 0xCB, 0x01, 0x00, 0x00, 0xD9, 0x02, 0x08, 0x01, 0x7A, 0x04, 0x5D, 0x00, 0xFE, 0x25, 0x02,
0xC8, 0x01, 0x20, 0x01, 0x2D, 0x03, 0x78, 0x00, 0x56, 0x01, 0x93, 0x30, 0x87, 0x00, 0xFF, 0x5E,
0x02, 0x62, 0x01, 0x7B, 0x00, 0xAE, 0x00, 0x5D, 0x5D, 0x5D, 0xFE, 0x01, 0x8F, 0xCF, 0x00, 0x1A,
0x01, 0x38, 0x01, 0x00, 0x00, 0x45, 0x30, 0xDB, 0x03, 0xF9, 0x00, 0x03, 0x03, 0xFF, 0xE2, 0x02,
0xD1, 0x01, 0x20, 0x01, 0x39, 0x30, 0x7D, 0x01, 0x84, 0x84, 0x84, 0x1F, 0x40, 0x02, 0x6F, 0x6F,
0x6F, 0x29, 0x01, 0x30, 0x00, 0x0D, 0x02, 0xE3, 0x01, 0xF1, 0x09, 0x00, 0x68, 0x01, 0x72, 0x00,
0x4E, 0x00, 0x62, 0x01, 0xB1, 0x03, 0x72, 0x72, 0x3F, 0x72, 0xE1, 0x03, 0xA6, 0x02, 0x2A, 0x03,
0xA5, 0x00, 0x5C, 0x31, 0x02, 0x01, 0x00, 0x00, 0xFE, 0x5B, 0x5B, 0x5B, 0x2A, 0x00, 0x51, 0x00,
0x62, 0x61, 0x81, 0x00, 0x62, 0x31, 0xF8, 0xD7, 0x01, 0xA2, 0xA2, 0xA2, 0xD7, 0x31, 0x21, 0x00,
0x48, 0x00, 0xE4, 0x00, 0xF1, 0xF7, 0x02, 0x5D, 0x00, 0x41, 0x41, 0x41, 0x72, 0x00, 0x09, 0x66,
0xA2, 0x00, 0xE3, 0x89, 0x89, 0x89, 0x44, 0x44, 0x44, 0x87, 0x00, 0x3F, 0x03, 0xC0, 0x49, 0x02,
0x62, 0x01, 0x12, 0x00, 0xB7, 0x03, 0x46, 0x02, 0x1E, 0x1E, 0x1E, 0x1F, 0x5F, 0x5F, 0x5F, 0x94,
0x94, 0x94, 0x29, 0x29, 0x00, 0x29, 0x48, 0x00, 0x27, 0x00, 0x92, 0x92, 0x92, 0x48, 0x00, 0x72,
0x00, 0xC6, 0x97, 0x97, 0x97, 0xE7, 0x30, 0x66, 0x03, 0x20, 0x01, 0x86, 0x01, 0x24, 0x00, 0xF8,
0x30, 0x00, 0x36, 0x36, 0x36, 0xC3, 0x00, 0x09, 0x00, 0x80, 0x80, 0x31, 0x80, 0xB5, 0x02, 0xE1,
0x00, 0x0A, 0x02, 0x82, 0x82, 0x82, 0xED, 0x00, 0x8E, 0x4E, 0x03, 0x45, 0x00, 0x3F, 0x3F, 0x3F,
0x35, 0x01, 0x00, 0x00, 0x45, 0x00, 0xE3, 0x87, 0x00, 0xCF, 0x00, 0x4D, 0x01, 0x96, 0x00, 0x94,
0x02, 0xA1, 0xA1, 0xA1, 0x1F, 0x57, 0x00, 0x63, 0x00, 0x62, 0x61, 0x61, 0x02, 0x42, 0x00, 0x93,
0x00, 0x9D, 0x02, 0xE7, 0x00, 0xFF, 0x9C, 0x9C, 0x9C, 0xB5, 0x02, 0x49, 0x49, 0x49, 0x39, 0x00,
0x88, 0x75, 0x00, 0x57, 0x00, 0x56, 0x01, 0x73, 0x02, 0x45, 0x00, 0x03, 0x03, 0x62, 0x01, 0x84,
0x00, 0xFF, 0x6E, 0x01, 0xD0, 0x02, 0x98, 0x01, 0x6C, 0x6C, 0x6C, 0x96, 0x96, 0x07, 0x96, 0x21,
0x00, 0x9F, 0x00, 0xCE, 0x01, 0x97, 0x02, 0x0A, 0x0A, 0x0A, 0x1E, 0x43, 0x43, 0x43, 0x9C, 0x00,
0xCA, 0x02, 0x21, 0x00, 0x79, 0x02, 0xAA, 0x01, 0xF8, 0x3C, 0x00, 0x1F, 0x02, 0x15, 0x03, 0x47,
0x01, 0x65, 0x61, 0x69, 0x33, 0xAE, 0x00, 0x4E, 0x03, 0xFF, 0x73, 0x32, 0x62, 0x61, 0xDA, 0x01,
0x3C, 0x00, 0x2A, 0x00, 0x12, 0x00, 0xA5, 0xA5, 0x3F, 0xA5, 0x27, 0x00, 0x1B, 0x00, 0x7E, 0x00,
0x8A, 0x00, 0x2C, 0x2C, 0x2C, 0x1E, 0x62, 0x01, 0x88, 0x88, 0x88, 0x62, 0x01, 0xB1, 0x00, 0x20,
0x31, 0x6E, 0x01, 0xF1, 0x2B, 0x02, 0x3F, 0x00, 0xD2, 0x00, 0x72, 0x00, 0x47, 0x47, 0x47, 0x2A,
0x00, 0x8F, 0x28, 0x02, 0x48, 0x00, 0x63, 0x63, 0x63, 0x7F, 0x7F, 0x7F, 0x03, 0x7B, 0x30, 0x8E,
0x8E, 0x8E, 0x78, 0x00, 0x71, 0x71, 0x71, 0x11, 0xA5, 0x00, 0xBC, 0x01, 0x0B, 0x0B, 0x0B, 0xFF,
0x00, 0x93, 0x93, 0x23, 0x93, 0x8B, 0x8B, 0x8B, 0x69, 0x69, 0x69, 0xC3, 0x03, 0x80, 0x06, 0x00,
0x3B, 0x01, 0xB9, 0x01, 0x8D, 0x8D, 0x8D, 0x51, 0x00, 0xA0, 0x02, 0xC7, 0x36, 0x00, 0x1B, 0x00,
0x05, 0x01, 0xD1, 0x01, 0x58, 0x58, 0x58, 0x87, 0x0F, 0x87, 0x87, 0x0C, 0x03, 0x8D, 0x00, 0x68,
0x01, 0x8D, 0x00, 0x45, 0x30, 0x54, 0x00, 0xFC, 0x12, 0x00, 0x4D, 0x4D, 0x4D, 0x27, 0x00, 0x3F,
0x00, 0x57, 0x00, 0xC1, 0x71, 0xC1, 0xC1, 0xB6, 0x01, 0x30, 0x00, 0x00, 0x00, 0x90, 0x30, 0x53,
0x01, 0x90, 0x7C, 0x90, 0x90, 0x93, 0x00, 0xB6, 0x01, 0x56, 0x56, 0x56, 0xF2, 0x01, 0x8C, 0x60,
0x00, 0xB4, 0x00, 0x4E, 0x00, 0x98, 0x98, 0x98, 0x1D, 0x01, 0x85, 0x47, 0x85, 0x85, 0xCC, 0x00,
0x0C, 0x0C, 0x0C, 0x75, 0x75, 0x04, 0x75, 0x91, 0x91, 0x91, 0x1B, 0x00, 0x57, 0x57, 0x57, 0x10,
0x9F, 0x9F, 0x9F, 0x34, 0x34, 0x34, 0x46, 0x46, 0x00, 0x46, 0x9B, 0x9B, 0x9B, 0xA8, 0x00, 0xBA,
0x00, 0xB8, 0xB8, 0x30, 0xB8, 0x62, 0x62, 0x62, 0x07, 0x07, 0x07, 0x29, 0x01, 0x80, 0x99, 0x99,
0x99, 0x86, 0x86, 0x86, 0x36, 0x00, 0x78, 0x00, 0xC0, 0x79, 0x79, 0x79, 0x9D, 0x9D, 0x9D, 0x68,
0x68, 0x00, 0x68, 0x83, 0x83, 0x83, 0x5C, 0x5C, 0x5C, 0x13, 0x32, 0x80, 0x0C, 0x90, 0x35, 0xF4,
0x30, 0x30, 0x30, 0x8F, 0x8F, 0x8F, 0x03, 0x14, 0x01, 0x36, 0x00, 0xAC, 0xAC, 0xAC, 0x95, 0x95,
0x95, 0x03, 0x6B, 0x6B, 0x6B, 0xA0, 0xA0, 0xA0, 0x5C, 0x01, 0x46, 0x02, 0xC0, 0x15, 0x00, 0x8C,
0x8C, 0x8C, 0xE1, 0x00, 0x71, 0x01, 0x3C, 0x63, 0x22, 0x71, 0x22, 0x22, 0x48, 0x00, 0x26, 0x26,
0x26, 0x60, 0x00, 0xF6, 0x03, 0xC4, 0x54, 0x00, 0x35, 0x01, 0x18, 0x00, 0x60, 0x00, 0x35, 0x35,
0x35, 0x41, 0x31, 0x8F, 0x2D, 0x2D, 0x2D, 0x6A, 0x6A, 0x6A, 0x7E, 0x7E, 0x00, 0x7E, 0x12, 0x00,
0xCC, 0x33, 0x8D, 0x00, 0x32, 0x32, 0x32, 0x02, 0x01, 0x8E, 0x6E, 0x6E, 0x6E, 0x4F, 0x4F, 0x4F,
0x12, 0x00, 0x36, 0x00, 0xC0, 0x02, 0x31, 0x51, 0x60, 0x37, 0x37, 0x37, 0x2F, 0x01, 0x45, 0x30,
0x38, 0x63, 0x38, 0x38, 0x6F, 0x00, 0x24, 0x00, 0x24, 0x24, 0x24, 0x5A, 0x0C, 0x5A, 0x5A, 0x78,
0x78, 0x78, 0x67, 0x67, 0x67, 0x00, 0x2E, 0x2E, 0x2E, 0x08, 0x01, 0x3E, 0x01, 0x06, 0x00, 0x7A,
0x7A, 0x38, 0x7A, 0x5E, 0x5E, 0x5E, 0x4C, 0x4C, 0x4C, 0x78, 0x03, 0x80, 0x1E, 0x00, 0x78, 0x60,
0x96, 0x00, 0xFB, 0x01, 0x57, 0x00, 0x45, 0x00, 0x15, 0x00, 0x40, 0x7F, 0x40, 0x40, 0x5D, 0x00,
0xB4, 0x00, 0x28, 0x28, 0x28, 0x4B, 0x03, 0x8C, 0x36, 0x00, 0x84, 0x00, 0x2B, 0x2B, 0x2B, 0xC3,
0x00, 0x33, 0x33, 0x23, 0x33, 0x3C, 0x3C, 0x3C, 0x1B, 0x00, 0x99, 0x00, 0x42, 0x42, 0x30, 0x42,
0x2F, 0x2F, 0x2F, 0x30, 0x00, 0x4E, 0x4E, 0x4E, 0x10, 0x7B, 0x7B, 0x7B, 0x1B, 0x00, 0x48, 0x48,
0x48, 0x1E, 0x00, 0x88, 0x1E, 0x33, 0x4A, 0x4A, 0x4A, 0x77, 0x77, 0x77, 0x3F, 0x00, 0x81, 0xEA,
0x00, 0x4E, 0x00, 0x59, 0x59, 0x59, 0x76, 0x76, 0x76, 0x03, 0x65, 0x65, 0x65, 0x31, 0x31, 0x31,
0x3C, 0x00, 0x0C, 0xC0, 0xC0, 0x53, 0xF1, 0x21, 0x21, 0x21, 0x1B, 0x00, 0x1F, 0x1F, 0x1F, 0x11,
0x3D, 0x3D, 0x3D, 0xA3, 0xA3, 0xA3, 0x73, 0x73, 0x00, 0x73, 0x74, 0x74, 0x74, 0x61, 0x61, 0x61,
0x20, 0x00, 0x20, 0x20, 0x21, 0x00, 0x23, 0x23, 0x23, 0x39, 0x39, 0x04, 0x39, 0x25, 0x25, 0x25,
0x09, 0x00, 0x89, 0x91, 0x09, 0x00, 0x5A, 0x00, 0xF0, 0x09, 0x00, 0x21, 0x00, 0x09, 0x00, 0x27,
0x30, 0x60, 0x00, 0x27, 0x00, 0x00, 0x00, 0x12, 0x30, 0xFF, 0x99, 0x30, 0x23, 0x91, 0x3C, 0x00,
0xCC, 0x33, 0x0E, 0x0E, 0x0E, 0x12, 0x00, 0x8F, 0x02, 0xC1, 0x15, 0x30, 0x7B, 0x00, 0x45, 0x30,
0x09, 0x00, 0x27, 0x00, 0x8D, 0xC0, 0x39, 0x00, 0xFF, 0x4E, 0x30, 0x33, 0x00, 0x14, 0x31, 0x57,
0x00, 0x30, 0x00, 0x78, 0xC0, 0xAE, 0x60, 0x2A, 0x00, 0xFF, 0x0F, 0x0F, 0x0F, 0x5A, 0x00, 0x39,
0x30, 0x03, 0x00, 0x06, 0x00, 0x13, 0x78, 0x13, 0x13, 0x1E, 0x00, 0x3C, 0x30, 0x06, 0x00, 0x1B,
0x00, 0x7B, 0x00, 0x5D, 0x30, 0xFC, 0xB4, 0x00, 0x09, 0x00, 0x18, 0x30, 0x1E, 0x03, 0x06, 0x00,
0x09, 0x30, 0xB3, 0x01, 0x03, 0x00, 0xFF, 0x09, 0x00, 0x12, 0x00, 0x48, 0x00, 0x12, 0x12, 0x12,
0x1D, 0x1D, 0x07, 0x1D, 0x00, 0x00, 0x39, 0x00, 0x3C, 0x00, 0x0F, 0xF0, 0x36, 0xF0, 0x10, 0x10,
0x3E, 0x10, 0x17, 0x17, 0x17, 0x3A, 0x3A, 0x3A, 0xAE, 0x00, 0xAE, 0xAE, 0x3B, 0x3B, 0x3B, 0x0F,
0x00, 0x14, 0x14, 0x20, 0x14, 0x16, 0x16, 0x16, 0x09, 0x00, 0x39, 0x00, 0x11, 0x11, 0x30, 0x11,
0x36, 0x00, 0xB2, 0xF2, 0x3C, 0xF0, 0x90, 0xF0, 0x90, 0xF0, 0x36, 0x30, 0x7B, 0x90, 0xFE, 0x0F,
0xF0, 0x2A, 0xF0, 0x0F, 0xF0, 0x57, 0xF0, 0x0F, 0xF0, 0x18, 0xF0, 0x27, 0x00, 0x21, 0x00, 0xFF,
0x45, 0xF0, 0x12, 0xF0, 0x60, 0x60, 0x0C, 0xC0, 0x30, 0x60, 0x18, 0x18, 0x18, 0x1F, 0x2A, 0x00,
0x03, 0x30, 0x0F, 0xF0, 0x24, 0xF0, 0x00, 0x00, 0x1A, 0x1A, 0x1A, 0x1F, 0x27, 0x27, 0x27, 0x60,
0x60, 0x60, 0x2A, 0x2A, 0x00, 0x2A, 0x15, 0x15, 0x15, 0x5C, 0x01, 0x00, 0x00, 0x0F, 0xF0, 0x0F,
0xF0, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0,
0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0xFF, 0x18, 0xF0, 0x0D, 0x0D, 0x0D, 0x19, 0x19, 0x19, 0x1C, 0x01, 0x1C, 0x1C,
0x06, 0x60, 0x03, 0x30, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1C, 0xFF, 0xFF, 0xA8, 0x1D, 0x00, 0x00,
0x0E, 0x00, 0x00, 0x00, 0xD5, 0x31, 0x00, 0x00
};
#endif //MENU_LOGO_ENABLE
// 68 x 192 @8bpp Grayscale RAW.
#define X_BOOTLOGO 68
#define Y_BOOTLOGO 192
#define SZ_BOOTLOGO 13056
#define SZ_BOOTLOGO_BLZ 6704
static u8 BOOTLOGO_BLZ[SZ_BOOTLOGO_BLZ] = {
0x0F, 0xF0, 0x80, 0x1B, 0x1B, 0x77, 0xF0, 0x6A, 0x08, 0x41, 0x80, 0x0F, 0x4D, 0x21, 0x40, 0x29,
0xF0, 0xFC, 0x34, 0xED, 0x34, 0x10, 0x23, 0x26, 0x27, 0x23, 0x76, 0x30, 0x0F, 0xF0, 0xC3, 0xC9,
0xF0, 0x3F, 0x7F, 0xC6, 0x53, 0x80, 0x2E, 0x33, 0xDB, 0x2D, 0xBA, 0x20, 0x8F, 0x1C, 0xE7, 0x76,
0x23, 0xF8, 0x0E, 0x40, 0xF0, 0x54, 0x9C, 0x1E, 0x21, 0x3A, 0x1F, 0xBD, 0x71, 0x20, 0x2F, 0x3D,
0xDB, 0x35, 0xFE, 0x00, 0x82, 0x19, 0xB1, 0x9E, 0x83, 0x5D, 0x22, 0x85, 0x1C, 0x93, 0xB1, 0x44,
0x3F, 0xD2, 0x29, 0x63, 0x26, 0x39, 0x88, 0x33, 0x45, 0xDA, 0x38, 0x08, 0x9E, 0x50, 0x32, 0x56,
0x78, 0x75, 0x27, 0x1D, 0x1D, 0x99, 0xE6, 0xE8, 0xC3, 0x28, 0x33, 0xD0, 0x2B, 0x21, 0xC9, 0xB0,
0x49, 0xB9, 0x1C, 0x60, 0x30, 0x4F, 0xA1, 0x6D, 0x3A, 0x36, 0x37, 0x36, 0x00, 0x34, 0x2B, 0x79,
0x3C, 0x51, 0xF1, 0x2E, 0x3C, 0xD2, 0x32, 0x0C, 0x26, 0x19, 0xC6, 0x9F, 0x70, 0x95, 0x21, 0x8D,
0xBB, 0xBC, 0xBA, 0x0E, 0xBB, 0xBB, 0xBA, 0xBC, 0xBB, 0xF4, 0x10, 0x4E, 0xF1, 0xC9, 0x10, 0xE0,
0xD2, 0x36, 0xC9, 0x90, 0x11, 0x1E, 0x19, 0xA0, 0x1C, 0x27, 0x3F, 0x1C, 0x52, 0x54, 0x51, 0x51,
0x50, 0x51, 0x4D, 0x3A, 0x00, 0x24, 0xE0, 0x87, 0x38, 0x60, 0xC9, 0x10, 0x0D, 0xB1, 0x34, 0x59,
0xDA, 0xB1, 0x13, 0xDE, 0x93, 0x25, 0x28, 0x27, 0x88, 0x2D, 0xEB, 0x9A, 0x6A, 0x46, 0x1F, 0xC9,
0x70, 0xB9, 0x81, 0xF4, 0x71, 0x4C, 0x29, 0x02, 0x30, 0x2A, 0x1F, 0x73, 0x02, 0x7C, 0x22, 0xC7,
0x90, 0xD4, 0xB0, 0x24, 0xD4, 0x37, 0x25, 0x85, 0xB0, 0x27, 0x6B, 0xA4, 0xA3, 0x08, 0x0C, 0x47,
0x91, 0xAC, 0xBB, 0x2C, 0x27, 0x72, 0x01, 0x54, 0x22, 0x6F, 0x60, 0xF7, 0xBC, 0x6C, 0x14, 0x25,
0x7D, 0x88, 0x48, 0x5C, 0xDA, 0x3B, 0x7D, 0xA8, 0x84, 0x08, 0x48, 0xAB, 0x8A, 0x6A, 0x0C, 0xA7,
0x32, 0x2B, 0x56, 0xA8, 0x2B, 0x02, 0x20, 0x2C, 0xF2, 0xC0, 0x6C, 0x14, 0x34, 0x14, 0x05, 0x99,
0x09, 0xB5, 0x30, 0x7C, 0x8C, 0x45, 0x0F, 0x50, 0xA5, 0x30, 0x27, 0x42, 0x91, 0xAD, 0x1B, 0x1E,
0xFE, 0xC0, 0xB0, 0x04, 0x6C, 0x04, 0x2C, 0x79, 0x22, 0x95, 0x21, 0x0A, 0x65, 0x1A, 0xE9, 0x22,
0xB7, 0x8A, 0x69, 0x33, 0x45, 0xA4, 0x2E, 0x24, 0xF5, 0x27, 0x80, 0x1C, 0x1F, 0x23, 0x24, 0x25,
0x26, 0x51, 0x11, 0x26, 0x40, 0x25, 0x4C, 0x01, 0x99, 0x07, 0x25, 0x25, 0x2C, 0x3A, 0x4A, 0x06,
0xD3, 0xC4, 0x33, 0x60, 0x45, 0x48, 0x79, 0x2C, 0xA4, 0x23, 0xED, 0x5F, 0x75, 0x76, 0x89, 0x37,
0x46, 0xA4, 0x32, 0x2B, 0x47, 0xAA, 0x00, 0x42, 0x1E, 0x1D, 0x20, 0x29, 0x2F, 0x0A, 0x10, 0x38,
0x40, 0x01, 0x10, 0x37, 0x01, 0x00, 0x36, 0x37, 0x37, 0x37, 0x3B, 0x05, 0x47, 0x50, 0xD2, 0xFC,
0x1F, 0xB5, 0xB3, 0x1C, 0xFA, 0xB3, 0xA5, 0x58, 0x8C, 0x64, 0xA7, 0x4C, 0x5B, 0x9F, 0x89, 0x2B,
0x00, 0x1D, 0x1D, 0x24, 0x2F, 0xD1, 0x01, 0x10, 0xD2, 0x01, 0x10, 0xA0, 0xD2, 0xD3, 0xD3, 0xD3,
0xD4, 0xD4, 0xD4, 0xD2, 0x00, 0xD2, 0xD4, 0xD4, 0xED, 0x34, 0xE0, 0x72, 0x20, 0xF5, 0x27, 0xA0,
0x6E, 0x5B, 0x71, 0x50, 0x56, 0x90, 0xB6, 0xBA, 0xBA, 0xB0, 0x03, 0x86, 0x36, 0x25, 0x0B, 0x21,
0x2B, 0x38, 0x3F, 0x02, 0x10, 0x84, 0x42, 0x02, 0x10, 0x40, 0x00, 0x00, 0x41, 0x41, 0x41, 0x43,
0x0A, 0x46, 0x45, 0x3B, 0x2D, 0x20, 0xBD, 0xCC, 0x68, 0xD8, 0x30, 0x60, 0x41, 0x4F, 0x54, 0x4F,
0x43, 0x33, 0x24, 0x16, 0x04, 0x80, 0x1E, 0x24, 0x2C, 0x2F, 0x30, 0x31, 0x0A, 0x00, 0x32, 0x40,
0x32, 0x31, 0x31, 0x30, 0x31, 0x32, 0x31, 0x30, 0x00, 0x30, 0x31, 0x31, 0x32, 0x2F, 0x2B, 0xD4,
0x75, 0xBD, 0x5C, 0xC0, 0x61, 0xA9, 0x7F, 0x00, 0x9C, 0x05, 0x29, 0x24, 0x1F, 0x1D, 0xC1, 0x29,
0x87, 0x20, 0x22, 0x21, 0x22, 0x26, 0x15, 0x0B, 0x22, 0x21, 0x20, 0x20, 0x21, 0x20, 0x21, 0x20,
0x4F, 0x1E, 0x1F, 0x1E, 0x20, 0x1E, 0x1D, 0x85, 0x90, 0x39, 0xB8, 0x1D, 0x23, 0x2B, 0x30, 0x0C,
0x2E, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2D, 0x2F, 0x00, 0x2C, 0x35, 0x26, 0x1C, 0x1D, 0x1E, 0x24,
0x29, 0x2C, 0x02, 0x31, 0x31, 0x2D, 0x28, 0x25, 0x1E, 0x1E, 0x4D, 0x53, 0x80, 0x09, 0xF5, 0x41,
0xA0, 0xA4, 0xA6, 0xA5, 0xA6, 0xA7, 0x39, 0x18, 0x83, 0xA7, 0xA5, 0xA2, 0x25, 0xAF, 0x28, 0x29,
0x32, 0x3A, 0x10, 0x7D, 0xA0, 0xAB, 0xA0, 0x6E, 0x35, 0x2A, 0x21, 0x00, 0x9D, 0xFB, 0x1B, 0xCD,
0x5D, 0x1C, 0x96, 0x6F, 0x72, 0x76, 0x7E, 0x0D, 0xA5, 0x8D, 0x74, 0x72, 0x73, 0x7A, 0x9D, 0x8C,
0x00, 0x2B, 0x1F, 0x10, 0x2B, 0x3A, 0x8B, 0xDD, 0xC1, 0xA3, 0x02, 0x82, 0xAD, 0xC2, 0xE4, 0x6C,
0x2D, 0x22, 0x1D, 0x00, 0xC4, 0x32, 0x35, 0xFC, 0x9D, 0x8A, 0x1D, 0x24, 0x2E, 0x36, 0x42, 0x07,
0x74, 0x8F, 0x41, 0x35, 0x33, 0x35, 0x40, 0x51, 0x00, 0x9E, 0x30, 0x1D, 0x1B, 0x1F, 0x29, 0x3A,
0x98, 0x00, 0xDC, 0x59, 0x43, 0x3F, 0x3F, 0x43, 0x49, 0x77, 0x00, 0xD2, 0x6C, 0x06, 0x29, 0x5D,
0xF6, 0x2D, 0x13, 0x25, 0x88, 0x1D, 0x1E, 0x3C, 0x23, 0x37, 0x8A, 0x68, 0x2B, 0x12, 0x27, 0x3F,
0x8A, 0x10, 0x61, 0x1F, 0x1C, 0x24, 0x34, 0x64, 0xDC, 0x58, 0x00, 0x3B, 0x2F, 0x2C, 0x2A, 0x30,
0x38, 0x45, 0x69, 0x00, 0xDB, 0x33, 0x24, 0xBC, 0x79, 0xBD, 0x9C, 0xE1, 0xDA, 0x21, 0x36, 0x38,
0x84, 0x62, 0x09, 0x19, 0x1C, 0x28, 0x43, 0x98, 0x59, 0x02, 0x20, 0x1E, 0x2A, 0x3B, 0xB7, 0x8C,
0x3A, 0x29, 0x00, 0x21, 0x1E, 0x1F, 0x21, 0x28, 0x37, 0x45, 0xB6, 0x00, 0x88, 0x2C, 0x20, 0xC2,
0xF5, 0x21, 0x7D, 0x28, 0x31, 0x50, 0xA5, 0x42, 0xE8, 0x54, 0xB0, 0x7B, 0x37, 0x33, 0x37, 0x4D,
0x8D, 0x00, 0xA4, 0x30, 0x1E, 0x1E, 0x2F, 0x3F, 0xD2, 0x3F, 0x00, 0x2E, 0x1F, 0x86, 0x36, 0x3B,
0x7F, 0xAA, 0x30, 0x8E, 0x56, 0x84, 0x58, 0x76, 0xD9, 0x41, 0x05, 0xC6, 0x38, 0x61, 0xA1, 0xBB,
0xAB, 0x07, 0xAB, 0xB5, 0x92, 0x47, 0x24, 0x41, 0x20, 0x3A, 0x27, 0x20, 0x1D, 0x2A, 0x30, 0x36,
0x44, 0xD2, 0x33, 0x3A, 0x95, 0x1A, 0x42, 0xA1, 0x76, 0x85, 0xC0, 0xFD, 0x0B, 0x34, 0x44, 0x4A,
0x48, 0x47, 0x07, 0x45, 0x38, 0x15, 0x03, 0x20, 0x30, 0x41, 0x10, 0xCD, 0x43, 0x32, 0x64, 0x42,
0xD2, 0xBD, 0x00, 0x84, 0x60, 0x7D, 0x30, 0x35, 0x1C, 0xAD, 0x3B, 0x7B, 0xC8, 0xFC, 0x25, 0x25,
0x25, 0x25, 0xA2, 0x16, 0xC9, 0x20, 0x37, 0x8D, 0x3B, 0xB0, 0xBD, 0x00, 0x41, 0x20, 0x1C, 0xE5,
0xF6, 0x3D, 0x14, 0x61, 0xD2, 0x3A, 0x08, 0x29, 0x7B, 0x28, 0x60, 0x02, 0x1E, 0xE4, 0x0B, 0x40,
0xD2, 0x7A, 0x5F, 0x1F, 0x4A, 0x32, 0x41, 0xD2, 0x38, 0x25, 0x46, 0x50, 0xD9, 0x81, 0x2D, 0x23,
0xE0, 0x0C, 0xD8, 0x44, 0x80, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x01, 0x93, 0x24, 0x71, 0x08, 0x09,
0x70, 0x20, 0x35, 0x00, 0x36, 0x7E, 0x85, 0xAC, 0x1C, 0x3D, 0xA4, 0x95, 0x51, 0x87, 0x4D, 0x4A,
0xAB, 0x96, 0x95, 0x0E, 0xB2, 0x92, 0x90, 0xAB, 0x7A, 0x28, 0x1B, 0x1F, 0x00, 0x31, 0x41, 0xD3,
0x39, 0x2A, 0xA3, 0x01, 0x06, 0x00, 0x24, 0x60, 0x36, 0x45, 0xD4, 0x3B, 0x29, 0x1F, 0x86, 0x01,
0x1E, 0x40, 0x1F, 0x1D, 0x1C, 0x8D, 0xD9, 0xF6, 0xB7, 0x2F, 0x7C, 0x8D, 0x18, 0x4E, 0x5A, 0xA8,
0x4D, 0x47, 0x5B, 0x97, 0x2B, 0x00, 0x1C, 0x20, 0x31, 0x45, 0xD3, 0x42, 0x35, 0x2B, 0x00, 0x0D,
0x21, 0x30, 0x3F, 0x4E, 0xD4, 0x44, 0x35, 0x2B, 0x01, 0x2B, 0x2C, 0x2C, 0x2B, 0x27, 0x79, 0x01,
0x1C, 0x7B, 0x54, 0xA0, 0x89, 0x3D, 0x7D, 0xC8, 0x8B, 0x69, 0x34, 0x47, 0xA4, 0x37, 0x03, 0x2B,
0x41, 0x8F, 0x56, 0x1F, 0x1F, 0x31, 0x43, 0x00, 0xDD, 0x83, 0x7E, 0x00, 0x00, 0x06, 0x00, 0x7D,
0x81, 0x89, 0x18, 0xDD, 0x84, 0x7D, 0x7A, 0x79, 0x7A, 0x79, 0x7A, 0x00, 0x77, 0x73, 0x24, 0x1E,
0xB7, 0x36, 0x25, 0x6B, 0x17, 0x57, 0x56, 0x35, 0xF0, 0x35, 0x7C, 0x79, 0x32, 0x40, 0x98, 0x5A,
0x27, 0x00, 0x3C, 0x8A, 0x62, 0x21, 0x1F, 0x2B, 0x3D, 0xAE, 0x00, 0xAE, 0x01, 0x10, 0xAB, 0xAB,
0xAB, 0xAB, 0xAD, 0xB0, 0x02, 0xB2, 0xAF, 0x00, 0x00, 0xAC, 0xAB, 0xAB, 0xA9, 0xA6, 0x04, 0x25,
0x1F, 0x7D, 0x98, 0xD1, 0x29, 0x77, 0x9C, 0x2C, 0x52, 0xB0, 0x1C, 0x6F, 0x3C, 0x70, 0x9D, 0x44,
0x56, 0xAB, 0x40, 0x00, 0x1E, 0x1E, 0x24, 0x31, 0x39, 0x3F, 0x09, 0x10, 0x06, 0x10, 0xC0, 0x40,
0x41, 0x43, 0x41, 0x3D, 0x3C, 0x3C, 0x3C, 0x00, 0x3C, 0x3B, 0x36, 0x2E, 0x24, 0x1E, 0x49, 0xA9,
0x29, 0x47, 0xC0, 0x41, 0x8D, 0x65, 0x9C, 0x33, 0x43, 0x95, 0xBB, 0xB7, 0x01, 0x7A, 0x2B, 0x62,
0x0E, 0x22, 0x28, 0x2C, 0x2B, 0x29, 0x04, 0x01, 0x00, 0x07, 0x00, 0x2B, 0x2E, 0x2E, 0x2C, 0x2D,
0xC2, 0x00, 0x83, 0x2B, 0x2B, 0x28, 0x24, 0x1F, 0x1C, 0xE9, 0xC2, 0x49, 0x50, 0xC0, 0xA5, 0x52,
0x32, 0x2F, 0x25, 0x2E, 0x41, 0x4B, 0x44, 0x01, 0x30, 0x40, 0x10, 0xD4, 0x08, 0x08, 0x10, 0x20,
0x05, 0x10, 0x1F, 0x47, 0x09, 0xAE, 0x1F, 0x20, 0x1E, 0x1E, 0x1E, 0x20, 0x1E, 0xFC, 0x55, 0x80,
0x1A, 0x41, 0x10, 0x09, 0x35, 0x3B, 0xC4, 0x83, 0x04, 0x28, 0x28, 0x26, 0x1E, 0xD9, 0x64, 0x1A,
0x28, 0xB3, 0x3D, 0xF4, 0x69, 0x0B, 0xAE, 0xC1, 0x1E, 0x26, 0x3D, 0x32, 0x51, 0x66, 0x63, 0x3F,
0x27, 0x20, 0x24, 0x26, 0x80, 0x25, 0x28, 0x05, 0x10, 0x01, 0x00, 0x2C, 0x2A, 0x29, 0xDA, 0x2E,
0x8C, 0xD5, 0x0E, 0x27, 0x22, 0x1E, 0xA1, 0xC6, 0x28, 0xC3, 0x92, 0x98, 0x14, 0xD1, 0x5F, 0xA5,
0xAC, 0xA5, 0xA5, 0xB0, 0x95, 0x3B, 0x00, 0x7D, 0x08, 0x21, 0x2B, 0x37, 0x3C, 0x40, 0x3F, 0x09,
0x00, 0x81, 0x3F, 0x41, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3F, 0x00, 0x40, 0x40, 0x3F, 0x40, 0x3E,
0x38, 0x31, 0x26, 0x00, 0x1E, 0xC2, 0x4D, 0xD9, 0x41, 0x7D, 0xC8, 0x26, 0x49, 0xAB, 0x73, 0x0E,
0x4A, 0x47, 0x49, 0x51, 0x87, 0x9C, 0x0E, 0x09, 0x25, 0x40, 0x36, 0x00, 0x00, 0x07, 0x60, 0xF4,
0x00, 0x00, 0x00, 0x00, 0xF5, 0xF5, 0x36, 0xF5, 0x34, 0x84, 0x22, 0x35, 0x29, 0xA7, 0xF7, 0x33,
0x7C, 0x8C, 0x32, 0x39, 0x27, 0x26, 0x27, 0x35, 0x4B, 0x9F, 0x4B, 0x00, 0x1E, 0x1D, 0x26, 0x30,
0x40, 0x4A, 0x5F, 0x0E, 0x50, 0x40, 0x02, 0x20, 0x52, 0x0E, 0x4C, 0x2E, 0x4D, 0x45, 0x39, 0x27,
0x41, 0x70, 0x87, 0x22, 0x59, 0x0A, 0x39, 0x7D, 0xA8, 0x1A, 0x20, 0x36, 0x8A, 0x0A, 0x68, 0x27,
0x1C, 0x6F, 0x0C, 0x7D, 0x08, 0x1F, 0x1C, 0x20, 0x18, 0x29, 0x32, 0x35, 0x39, 0x38, 0x6B, 0x0C,
0xAD, 0x1F, 0x39, 0x60, 0x39, 0x39, 0xA4, 0x1F, 0x38, 0x38, 0x33, 0x2A, 0x24, 0x04, 0x1E, 0xE9,
0x82, 0xD5, 0xF5, 0x34, 0x7E, 0x81, 0x2A, 0x35, 0x02, 0x86, 0x27, 0x42, 0x9D, 0x4D, 0x20, 0x6B,
0x02, 0x20, 0x21, 0x20, 0x22, 0x21, 0x69, 0x1C, 0x23, 0xAA, 0x1F, 0x21, 0x23, 0x31, 0x01, 0x94,
0x21, 0x23, 0x21, 0x1E, 0x1E, 0x1B, 0x05, 0xC9, 0x7D, 0xB8, 0xC0, 0x2D, 0x51, 0xAA, 0x68, 0x33,
0x2F, 0x33, 0x40, 0x00, 0x85, 0x9E, 0x2E, 0x09, 0x90, 0x78, 0xF0, 0x1A, 0x69, 0xEB, 0x99, 0x7A,
0xD8, 0x38, 0x6A, 0xA6, 0xAB, 0xA6, 0xA6, 0xAF, 0x98, 0x00, 0x47, 0x24, 0x00, 0x00, 0x60, 0xF1,
0x81, 0xF4, 0x85, 0x10, 0x29, 0xC1, 0x25, 0x7C, 0x37, 0x47, 0x60, 0x73, 0x71, 0x53, 0x39, 0x25,
0x00, 0x09, 0x80, 0x34, 0xDC, 0x51, 0xE1, 0x68, 0x40, 0xEF, 0x78, 0x27, 0x2E, 0x31, 0x1F, 0x2E,
0x29, 0x72, 0xC3, 0x81, 0x70, 0xE9, 0xD2, 0x71, 0x23, 0x3E, 0x98, 0x22, 0x7C, 0x23, 0x23, 0x23,
0x22, 0x25, 0x25, 0x24, 0x24, 0x00, 0x23, 0x23, 0x20, 0x1B, 0x1A, 0x0C, 0x30, 0xB9, 0x01, 0x0E,
0x70, 0xE0, 0x1A, 0x34, 0x66, 0xC9, 0xE0, 0x1C, 0x38, 0x42, 0x63, 0x67, 0x66, 0x16, 0x67, 0x68,
0x67, 0x66, 0x68, 0x68, 0x68, 0x65, 0x00, 0x5E, 0xC5, 0xE4, 0x19, 0x35, 0xA0, 0x0D, 0x61, 0x41,
0x10, 0xD2, 0x42, 0xB0, 0x11, 0xFA, 0x36, 0xAE, 0x1F, 0x97, 0x01, 0xA8, 0x1F, 0xA9, 0x1F, 0xAD,
0xFA, 0xC9, 0xF0, 0xC5, 0x04, 0xFE, 0x41, 0x80, 0x79, 0x0C, 0x40, 0x46, 0x46, 0x46, 0x97, 0x11,
0x46, 0x43, 0x46, 0x41, 0x33, 0x80, 0xA4, 0x1A, 0xCD, 0x04, 0x1C, 0x1D, 0x28, 0x5D, 0x41, 0xE9,
0xF2, 0xC2, 0x92, 0x22, 0x9B, 0x01, 0x25, 0x00, 0x00, 0x26, 0x57, 0x26, 0x4C, 0x3E, 0x1C, 0x29,
0x80, 0x24, 0x21, 0x20, 0x1B, 0x0A, 0x09, 0x5C, 0x89, 0x5C, 0x0D, 0x71, 0xCF, 0xA9, 0x23, 0xBD,
0x33, 0x1F, 0x25, 0x2F, 0x33, 0x1E, 0xBD, 0x95, 0x23, 0x2B, 0x90, 0x63, 0xC6, 0x01, 0x84, 0x61,
0xF2, 0x51, 0x11, 0x36, 0x82, 0x19, 0x28, 0x07, 0x32, 0x85, 0x60, 0x17, 0x25, 0x23, 0x21, 0x21,
0x24, 0x34, 0x85, 0x5E, 0x00, 0x20, 0x59, 0x40, 0x1A, 0x92, 0x1B, 0x29, 0x33, 0xA7, 0x77, 0x0A,
0x27, 0x2F, 0x30, 0x19, 0xD1, 0x99, 0x22, 0x2D, 0x23, 0xE7, 0x13, 0xAA, 0x6F, 0xEA, 0x59, 0x71,
0x9E, 0x88, 0x6A, 0x67, 0x67, 0x68, 0x00, 0x6A, 0x71, 0xAB, 0x56, 0xC7, 0x90, 0x1E, 0x2A, 0x3A,
0x10, 0x41, 0x00, 0x82, 0x91, 0xF6, 0x56, 0x49, 0x29, 0x18, 0x30, 0x74, 0x4F, 0x90, 0xAA, 0x3F,
0xB1, 0xAD, 0xA7, 0x13, 0x0E, 0xA8, 0xA5, 0x74, 0x2D, 0x08, 0x1D, 0xBF, 0x81, 0x20, 0x2B, 0x3C,
0xAB, 0x79, 0x2A, 0x02, 0x1E, 0x37, 0xDA, 0x8D, 0x49, 0xD1, 0x39, 0x0C, 0x11, 0x9F, 0x10, 0x3E,
0x56, 0x3E, 0x92, 0x77, 0x4B, 0x46, 0x46, 0x45, 0x45, 0x3E, 0x00, 0x2E, 0x21, 0xE0, 0x10, 0xA2,
0x7C, 0x3D, 0x41, 0x00, 0xD9, 0x39, 0xEC, 0xC1, 0xEC, 0x19, 0x06, 0x69, 0x5B, 0x86, 0x39, 0x25,
0x34, 0x51, 0x3F, 0x29, 0x07, 0x26, 0x24, 0x24, 0x25, 0x23, 0xDB, 0xB1, 0x1F, 0x2B, 0x20, 0x39,
0xAB, 0x7A, 0x2B, 0x1F, 0x28, 0x61, 0xF9, 0x93, 0xDA, 0x60, 0x95, 0x21, 0xAA, 0x9B, 0x22, 0x23,
0x21, 0x25, 0x27, 0x25, 0x03, 0x07, 0x03, 0x86, 0xB0, 0x28, 0x36, 0xA9, 0x77, 0x28, 0x1E, 0x03,
0x1B, 0x1C, 0x33, 0x82, 0x19, 0xC9, 0x80, 0x1A, 0xA5, 0xB2, 0x2D, 0x54, 0x45, 0x78, 0x89, 0x88,
0x6C, 0x2E, 0x22, 0x86, 0xA0, 0x80, 0x1C, 0x24, 0x2D, 0x56, 0x41, 0x22, 0x07, 0x00, 0x6E, 0x4B,
0xC0, 0x9D, 0x8A, 0x2D, 0x13, 0xE4, 0xA0, 0xFD, 0x0B, 0x7B, 0xB0, 0xA5, 0x32, 0x0F, 0xA0, 0xCF,
0xB9, 0x0C, 0x26, 0x22, 0xEF, 0x26, 0x75, 0xA0, 0x55, 0x1E, 0x51, 0xD1, 0xBA, 0x0C, 0xF9, 0xA5,
0x22, 0x3F, 0x4B, 0x6B, 0xA3, 0x29, 0xFF, 0xC7, 0x1F, 0x41, 0x30, 0x47, 0x21, 0xD1, 0xA9, 0x7F,
0x2E, 0x50, 0xA5, 0x02, 0x32, 0xA5, 0x02, 0x30, 0x5F, 0xA5, 0x02, 0x1D, 0x4C, 0xE0, 0x1A, 0x9A,
0x64, 0x69, 0xCB, 0x41, 0xB0, 0x37, 0x75, 0x89, 0x67, 0x40, 0x12, 0x24, 0x3E, 0x8B, 0x62, 0x21,
0x04, 0x99, 0x67, 0x7C, 0xE0, 0x1E, 0x52, 0x19, 0x6D, 0x37, 0x28, 0xFA, 0xB0, 0x33, 0x57, 0x75,
0x8F, 0x2D, 0x1F, 0xA5, 0x32, 0x33, 0x66, 0x40, 0xF0, 0xD1, 0xA9, 0xF0, 0xDC, 0x81, 0x24, 0x9A,
0x8A, 0x2A, 0x44, 0xA4, 0x89, 0x46, 0x06, 0x37, 0x39, 0x58, 0xA5, 0x02, 0xC7, 0x00, 0x39, 0xF7,
0x41, 0xF0, 0xF9, 0x33, 0xF8, 0xD1, 0xB6, 0xA5, 0x12, 0xBA, 0xAC, 0x7D, 0x34, 0x21, 0x03, 0x30,
0x83, 0x3A, 0xF0, 0xE5, 0xF6, 0x0D, 0x71, 0x7C, 0x44, 0x31, 0x40, 0x4B, 0x50, 0x0F, 0x4D, 0x42,
0x30, 0x32, 0x3C, 0x1B, 0x3B, 0xF0, 0xC1, 0xCB, 0x35, 0x68, 0x47, 0xDA, 0x39, 0x27, 0x21, 0xD6,
0x21, 0x28, 0x32, 0x10, 0x33, 0x31, 0x28, 0x20, 0x57, 0x87, 0xFE, 0x8A, 0x0A, 0x1B, 0x19, 0x38,
0xB5, 0x93, 0xDA, 0x7D, 0x38, 0x11, 0x9A, 0x2C, 0x46, 0x7A, 0x88, 0x0D, 0x88, 0x6D, 0x2E, 0x21,
0x1C, 0xDD, 0x29, 0x26, 0x22, 0x20, 0x44, 0x05, 0x1C, 0x9E, 0x88, 0x27, 0x2D, 0x2D, 0x29, 0x68,
0x09, 0x85, 0xA1, 0x76, 0x48, 0xC9, 0x00, 0x9C, 0xB5, 0x21, 0x30, 0x7C, 0xAF, 0x0D, 0x95, 0x8E,
0x8E, 0x9A, 0xAF, 0x56, 0xD1, 0x09, 0x26, 0x40, 0x32, 0x40, 0x41, 0x38, 0x28, 0x1F, 0x62, 0x28,
0x34, 0x08, 0xC0, 0x4A, 0x0E, 0x1E, 0x28, 0x38, 0x86, 0x85, 0x81, 0x2B, 0x01, 0x80, 0x44, 0x1C,
0xB5, 0x53, 0x0E, 0x61, 0x32, 0x3C, 0x57, 0xAB, 0x56, 0x1D, 0x3E, 0x3E, 0x3E, 0x4B, 0x6C, 0xA3,
0x2A, 0xB5, 0x03, 0x80, 0x4B, 0x81, 0x14, 0x24, 0x84, 0x09, 0x29, 0x30, 0x33, 0x2E, 0x0A, 0x27,
0x46, 0x04, 0x20, 0x31, 0x52, 0x2E, 0x00, 0x3B, 0xD1, 0x49, 0xA2, 0x1C, 0x1A, 0x91, 0x45, 0x9E,
0xBA, 0x32, 0x84, 0x7C, 0x33, 0x0C, 0x22, 0x23, 0x24, 0x2F, 0x48, 0x98, 0x56, 0x1E, 0x00, 0x21,
0x39, 0x81, 0x24, 0xF0, 0x03, 0x29, 0x3A, 0xA0, 0xB6, 0x0C, 0xB4, 0x5D, 0xC5, 0x01, 0x21, 0x3B,
0x65, 0x2E, 0x00, 0x48, 0x44, 0x55, 0x8E, 0x85, 0x20, 0xD1, 0xA4, 0x20, 0x38, 0x8A, 0x67, 0x25,
0x07, 0xBA, 0x00, 0x24, 0x3F, 0x8B, 0x62, 0x20, 0x21, 0x3F, 0x01, 0xF5, 0x27, 0x85, 0x00, 0x2F,
0x4F, 0x8E, 0x09, 0x85, 0x2A, 0x1E, 0x13, 0x19, 0x22, 0x3E, 0x6F, 0x6E, 0x24, 0x1C, 0x61, 0xB2,
0x8B, 0xA4, 0xD0, 0x1F, 0x33, 0x75, 0x8E, 0x2E, 0x1E, 0x1D, 0x1E, 0x00, 0x2B, 0x47, 0xAB, 0x41,
0x1E, 0xD9, 0x31, 0x4F, 0x2A, 0x20, 0x1C, 0x20, 0x35, 0x5F, 0x41, 0x00, 0x8C, 0x30, 0x20, 0x10,
0x1B, 0x22, 0x41, 0x40, 0xB5, 0xC3, 0x0E, 0x71, 0x8E, 0x25, 0x44, 0xA5, 0x3C, 0x89, 0x45, 0x37,
0x39, 0x59, 0x9E, 0x8A, 0x2B, 0x00, 0x1B, 0x23, 0x41, 0x10, 0x10, 0x4E, 0x41, 0x00, 0x37, 0x85,
0x10, 0xA8, 0x8E, 0x32, 0x20, 0xD2, 0x16, 0xB6, 0x20, 0x39, 0xC8, 0xA5, 0x22, 0x5D, 0x83, 0xF8,
0x55, 0x8E, 0xB1, 0xBC, 0xBC, 0xAD, 0x7E, 0x36, 0x00, 0xD5, 0x05, 0x85, 0x30, 0x29, 0x85, 0x50,
0x32, 0x1F, 0x1B, 0x23, 0x0B, 0x3A, 0x25, 0x50, 0x95, 0x81, 0x45, 0xBD, 0x1A, 0xC0, 0x20, 0x23,
0x2F, 0x2D, 0x40, 0x4B, 0x4E, 0x4C, 0x41, 0x30, 0x23, 0x1C, 0x00, 0x10, 0x40, 0x50, 0x2B, 0x48,
0x02, 0x65, 0x41, 0x20, 0x8E, 0x16, 0xA2, 0x23, 0xE9, 0xB1, 0xA7, 0xDC, 0x7D, 0x48, 0xC0, 0x96,
0x24, 0x27, 0x29, 0x27, 0x0D, 0x25, 0x1F, 0x1D, 0x19, 0x16, 0xB5, 0x43, 0x1F, 0x39, 0x66, 0x18,
0x41, 0x00, 0x90, 0x33, 0x1F, 0xA2, 0x63, 0x1A, 0xA1, 0x86, 0xE9, 0x62, 0xD1, 0xF3, 0x47, 0x22,
0x24, 0x25, 0x1F, 0x1E, 0x22, 0x2C, 0x01, 0x31, 0x2C, 0x26, 0x5A, 0x1A, 0xC9, 0x20, 0x53, 0x30,
0x22, 0x18, 0x27, 0x3F, 0x6B, 0xBA, 0x08, 0x93, 0x39, 0x26, 0x21, 0x08, 0x28, 0x46, 0x73, 0xC9,
0xA0, 0x1C, 0xD5, 0x05, 0x99, 0x0E, 0xB7, 0x54, 0xE8, 0x49, 0x28, 0x34, 0x78, 0x89, 0x6D, 0x34,
0x46, 0x8F, 0x01, 0xB0, 0xAB, 0x86, 0x29, 0x1D, 0x1B, 0xB5, 0x33, 0x69, 0x40, 0x49, 0x3C, 0x41,
0x55, 0x76, 0x11, 0x0A, 0x9E, 0x52, 0x20, 0x3F, 0x3C, 0x43, 0x5B, 0x7D, 0x85, 0x40, 0x1C, 0xD9,
0x81, 0xA0, 0x29, 0x2E, 0x83, 0x22, 0x3B, 0xA5, 0x9C, 0x8F, 0xA0, 0x02, 0x9A, 0x93, 0x87, 0x5A,
0x66, 0xA1, 0x86, 0x24, 0x00, 0x81, 0x44, 0xC4, 0xC1, 0x07, 0x00, 0x14, 0x1A, 0xD5, 0xC2, 0xBF,
0x19, 0xBE, 0xBF, 0xC3, 0xC5, 0x2E, 0x00, 0x50, 0x41, 0x60, 0x1A, 0x50, 0xD1, 0x79, 0x72, 0x43,
0x2D, 0x6C, 0x99, 0x47, 0x43, 0x54, 0x03, 0x9E, 0xA1, 0x3E, 0x30, 0x3D, 0x5C, 0xAA, 0x2C, 0x00,
0x1D, 0x02, 0x6F, 0x41, 0xF0, 0xFF, 0x4E, 0x22, 0xD1, 0xD9, 0xA5, 0x83, 0x8A, 0x75, 0x69, 0x2E,
0x28, 0x3C, 0x74, 0x8A, 0x2D, 0x1E, 0x00, 0x2A, 0x48, 0xA3, 0x41, 0x00, 0x3E, 0xD9, 0x11, 0xFF,
0x3D, 0xF0, 0xA8, 0x4C, 0x2A, 0x59, 0xAA, 0x39, 0x45, 0x8D, 0x23, 0x39, 0x8A, 0x14, 0x63, 0x24,
0x20, 0x32, 0x6C, 0x87, 0x27, 0x1A, 0x00, 0x24, 0x43, 0xA5, 0x2F, 0x51, 0x01, 0x61, 0xE9, 0xF2,
0xFF, 0x50, 0x3E, 0x21, 0xD5, 0xB5, 0x3D, 0x84, 0x22, 0x3A, 0x89, 0x66, 0x28, 0x07, 0x26, 0x34,
0x6D, 0x89, 0x2E, 0x21, 0x2B, 0x48, 0x00, 0xA5, 0x31, 0xE1, 0x0A, 0x4A, 0x96, 0xA0, 0x00, 0x00,
0xA2, 0x44, 0xA3, 0xA1, 0x01, 0x10, 0xA2, 0xA2, 0xA2, 0xA2, 0xA3, 0x04, 0xA2, 0xA2, 0xA0, 0x9A,
0x8B, 0x37, 0xAD, 0x9B, 0x35, 0x0C, 0xC0, 0x29, 0x9B, 0x61, 0xD5, 0x04, 0x8C, 0x84, 0x66, 0x64,
0x6D, 0x06, 0x8A, 0x9A, 0x68, 0x63, 0x68, 0x72, 0xAB, 0x2E, 0x00, 0x1B, 0x1F, 0x29, 0x08, 0x53,
0x55, 0x50, 0x4E, 0x4D, 0x04, 0x4C, 0x01, 0x10, 0x00, 0x00, 0x4D, 0x4D, 0x4D, 0x4C, 0x4D, 0x06,
0x4A, 0x43, 0x37, 0x29, 0x20, 0x69, 0xCB, 0x31, 0x80, 0x31, 0x60, 0x6C, 0x8C, 0x8A, 0x8A, 0x8C,
0x90, 0x8F, 0x8B, 0x00, 0x8A, 0x8B, 0x8D, 0x89, 0xF6, 0x0F, 0x27, 0x3A, 0x4A, 0x10, 0x4F, 0x47,
0x38, 0x2E, 0x01, 0x10, 0x9D, 0x01, 0x28, 0x29, 0x30, 0x29, 0x28, 0x2A, 0x29, 0x2A, 0x29, 0x27,
0x23, 0x00, 0x1F, 0xA1, 0xB6, 0x3A, 0x09, 0x95, 0x25, 0x32, 0x39, 0x3A, 0x0A, 0x3B, 0x39, 0x3C,
0x3D, 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x31, 0x21, 0xA1, 0x06, 0x4D, 0x41, 0x00, 0x38, 0x26, 0x1D,
0x14, 0x1D, 0x02, 0x00, 0xB4, 0x04, 0x1C, 0x1C, 0x1D, 0x1E, 0x1D, 0x06, 0x1C, 0x1D, 0xB6, 0x01,
0xF5, 0xC7, 0x81, 0xA4, 0x4C, 0x03, 0x01, 0x10, 0x22, 0x7C, 0x40, 0x03, 0x20, 0x75, 0x01, 0x3A,
0x89, 0x1D, 0x44, 0x1F, 0x50, 0x18, 0xF0, 0xD5, 0x95, 0x51, 0x0D, 0x91, 0x85, 0xD0, 0x3F, 0x6D,
0x71, 0x13, 0x2A, 0xF8, 0x95, 0xA7, 0xA8, 0x00, 0x54, 0x20, 0x01, 0x9D, 0x51, 0x71, 0x21, 0xF0,
0xA9, 0x5F, 0x4E, 0xC0, 0x1C, 0x7F, 0xAD, 0xBE, 0xB5, 0x33, 0x19, 0x94, 0x50, 0x1C, 0xA0, 0xD9,
0x11, 0x6F, 0x78, 0x4F, 0xBB, 0xD1, 0xF7, 0xB1, 0xB7, 0x04, 0x3E, 0x74, 0x97, 0x1A, 0x1E, 0x30,
0x85, 0x40, 0x5B, 0x6F, 0x38, 0x2A, 0x2B, 0x03, 0x30, 0x2A, 0x2B, 0x29, 0x2A, 0x08, 0x2A, 0x2A,
0x28, 0x29, 0x24, 0x20, 0x1C, 0x71, 0x93, 0x80, 0xE5, 0xF6, 0x7D, 0x8A, 0x21, 0x3F, 0x73, 0x5A,
0x4F, 0x4F, 0x50, 0x07, 0x4F, 0x01, 0x00, 0x4E, 0x4F, 0x4F, 0x4E, 0x50, 0x50, 0x02, 0x4F, 0x4D,
0x46, 0x38, 0x28, 0x20, 0x51, 0x41, 0x1C, 0x40, 0x71, 0x73, 0x1C, 0x3E, 0x31, 0x0B, 0x04, 0x20,
0x1D, 0xAB, 0x57, 0x24, 0x4D, 0x68, 0x5E, 0xFF, 0x3D, 0xF0, 0x3A, 0x24, 0x1B, 0x55, 0x9E, 0x3B,
0x45, 0xD9, 0xA1, 0x7C, 0x6C, 0x2B, 0x20, 0x7D, 0x23, 0x30, 0x53, 0x21, 0x49, 0x09, 0x21, 0x11,
0x0E, 0x40, 0xF0, 0xA5, 0x12, 0xE8, 0x71, 0x1F, 0x34, 0x3D, 0x21, 0x3F, 0x7F, 0x41, 0xDE, 0x1E,
0xAB, 0x9E, 0x40, 0x24, 0x1C, 0x07, 0x1E, 0x27, 0x3B, 0x85, 0xAF, 0x6E, 0x95, 0x01, 0x24, 0x2E,
0xC0, 0xFF, 0x21, 0xFB, 0x47, 0x89, 0x2D, 0x85, 0x80, 0x01, 0x10, 0x19, 0xFB, 0x53, 0xBA, 0x4E,
0x8E, 0xB4, 0x6F, 0x30, 0x33, 0x57, 0xA5, 0x00, 0xA0, 0x50, 0x2F, 0x21, 0x85, 0x40, 0x03, 0x30,
0x03, 0x30, 0x00, 0x00, 0xF0, 0x63, 0x0F, 0xDF, 0x3D, 0x25, 0xD9, 0x91, 0xDC, 0x3B, 0x28, 0x11,
0x2C, 0x84, 0x1D, 0x24, 0x30, 0x45, 0x65, 0xA7, 0xA1, 0x01, 0x8B, 0xB1, 0x78, 0x3E, 0x2A, 0x78,
0x07, 0x22, 0x89, 0x2D, 0xA0, 0x7D, 0x6E, 0x05, 0x30, 0x66, 0x01, 0x00, 0x65, 0x66, 0x66, 0x14,
0x66, 0x63, 0x59, 0x46, 0x30, 0x1F, 0x1C, 0xD9, 0xA1, 0x80, 0xED, 0x5F, 0x19, 0xCB, 0x4D, 0x4A,
0x76, 0xB6, 0xBB, 0x88, 0x05, 0x43, 0x5B, 0x23, 0xCD, 0x3D, 0x64, 0x44, 0x3A, 0x39, 0x06, 0x00,
0x86, 0x00, 0x00, 0x39, 0x38, 0x3A, 0x39, 0x38, 0x38, 0x38, 0x01, 0x32, 0x2B, 0x22, 0xC8, 0x20,
0x19, 0x6D, 0x77, 0x1C, 0xE5, 0x95, 0xA8, 0x27, 0x3B, 0x88, 0xB2, 0x8F, 0x79, 0xAC, 0x9F, 0x00,
0x41, 0x1A, 0x16, 0x23, 0xD0, 0x2C, 0x52, 0x2F, 0x20, 0x20, 0x0A, 0x1F, 0x1F, 0x20, 0x22, 0x21,
0x0C, 0x06, 0x1F, 0x21, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x36, 0x01, 0x5D, 0x96, 0x95, 0xB1, 0x20,
0x70, 0x2F, 0x55, 0xA5, 0xA0, 0x5D, 0x3F, 0x3F, 0x51, 0x00, 0x8F, 0xB6, 0x6F, 0x2B, 0x1E, 0x58,
0x5D, 0x2B, 0x31, 0xD5, 0xA0, 0xB7, 0x22, 0xD6, 0x24, 0x19, 0x6D, 0xE7, 0x1E, 0x2A, 0x72, 0xB0,
0x0B, 0x77, 0x3E, 0x2B, 0x23, 0x24, 0x30, 0x47, 0x6F, 0x00, 0xAB, 0x9B, 0x24, 0xD0, 0x0C, 0x04,
0x1C, 0x4D, 0xE3, 0x08, 0x14, 0x9C, 0xD8, 0x21, 0x23, 0x20, 0x1E, 0x61, 0x92, 0x46, 0xDC, 0x39,
0x10, 0x27, 0x95, 0x95, 0x6F, 0x4D, 0x32, 0x9F, 0x1A, 0x1F, 0x2A, 0x22, 0x3B, 0x4A, 0x86, 0x26,
0x8D, 0x09, 0xA5, 0x12, 0x46, 0xEB, 0x80, 0xB0, 0x1C, 0x1E, 0x26, 0x2E, 0x36, 0x3A, 0x48, 0x29,
0x00, 0x1E, 0xC1, 0xB8, 0x4E, 0x46, 0x07, 0x30, 0x27, 0x26, 0x2E, 0x36, 0x1D, 0x4E, 0x23, 0x2B,
0x2B, 0x20, 0x50, 0x06, 0x4F, 0xBF, 0xC0, 0x10, 0xB9, 0x38, 0x10, 0x30, 0x1A, 0x19, 0x1C, 0x1E,
0x23, 0x04, 0x2A, 0xED, 0x03, 0x87, 0xC3, 0xF7, 0x36, 0xD1, 0x89, 0x34, 0x42, 0x41, 0xB0, 0x04,
0x08, 0x01, 0x71, 0x57, 0x15, 0x27, 0x37, 0x47, 0x48, 0x0F, 0x3E, 0x2B, 0x20, 0x11, 0x3E, 0x10,
0x26, 0x2F, 0x3A, 0x49, 0x0C, 0x69, 0xAC, 0x1B, 0x17, 0x43, 0xD8, 0x70, 0x0D, 0x31, 0xAC, 0x9F,
0x29, 0x74, 0x2D, 0xB1, 0x0B, 0x2E, 0x2E, 0x4D, 0x35, 0x2C, 0x18, 0x2A, 0x2B, 0x32, 0x28, 0xE0,
0x12, 0x1E, 0x20, 0x24, 0x2B, 0x36, 0x45, 0x02, 0x55, 0xA1, 0xD2, 0x3F, 0x30, 0x49, 0x27, 0xD1,
0xF9, 0x1B, 0x48, 0xF0, 0x5F, 0x78, 0xA4, 0xA5, 0xA6, 0xA4, 0xA4, 0xA5, 0x01, 0xA5, 0xA6, 0xA6,
0xA5, 0xA2, 0x19, 0x00, 0x1D, 0xB8, 0x00, 0xA0, 0x1C, 0x1C, 0x11, 0x05, 0x28, 0x32, 0x3D, 0x4E,
0x7B, 0x04, 0xC9, 0x10, 0x52, 0xFF, 0x42, 0x3D, 0x84, 0xB5, 0x53, 0x19, 0x49, 0x45, 0xB2, 0x28,
0x54, 0x6F, 0x72, 0x72, 0x72, 0x72, 0x73, 0x00, 0x79, 0x82, 0x9B, 0xBB, 0x8B, 0x99, 0x58, 0x21,
0x26, 0x20, 0x2F, 0x38, 0x4A, 0x68, 0xAD, 0xE1, 0x5C, 0x52, 0xDD, 0x40, 0xB1, 0x63, 0xD8, 0x0A,
0x1B, 0x19, 0x69, 0x9B, 0xF9, 0x97, 0x29, 0x64, 0x31, 0x71, 0x07, 0x38, 0x44, 0x62, 0xA5, 0xAD,
0x6E, 0x02, 0x37, 0x20, 0x69, 0x19, 0x1F, 0x24, 0x2B, 0x35, 0x42, 0x04, 0x54, 0x96, 0xD2, 0xA8,
0x52, 0xF8, 0xB4, 0x7D, 0x5E, 0x08, 0x4B, 0x37, 0x27, 0x20, 0xD0, 0x6C, 0x21, 0xD1, 0x29, 0xDE,
0x01, 0xD0, 0x19, 0x17, 0x6A, 0x23, 0x09, 0x28, 0x39, 0x78, 0xB6, 0x8F, 0x06, 0x45, 0x2F, 0x82,
0x10, 0x1E, 0x24, 0x30, 0x3C, 0x4C, 0x04, 0x79, 0xC0, 0xF4, 0x12, 0xD7, 0x25, 0x85, 0x00, 0x6A,
0x49, 0x35, 0x1C, 0x2B, 0x22, 0x20, 0xA9, 0x9F, 0x48, 0xE9, 0xE2, 0x20, 0x2C, 0x28, 0x4D, 0x9F,
0xAC, 0x67, 0x38, 0x25, 0x1E, 0x08, 0x2A, 0x80, 0x37, 0x50, 0xAB, 0x6C, 0x52, 0xF1, 0xCD, 0x9B,
0x0D, 0x01, 0x88, 0xE3, 0x4F, 0x2F, 0x1F, 0x80, 0x28, 0x19, 0xF6, 0xBE, 0x62, 0x26, 0x70, 0x37,
0x76, 0xB6, 0x8E, 0x41, 0x2E, 0x22, 0xB9, 0x40, 0x80, 0x51, 0x10, 0x51, 0xD3, 0x94, 0x6A, 0x63,
0x74, 0xA4, 0x02, 0x41, 0x00, 0x48, 0x55, 0x20, 0x09, 0xD5, 0xF0, 0x9F, 0x2C, 0x4E, 0xA1, 0x1D,
0xA7, 0x63, 0x3D, 0x2C, 0x25, 0x22, 0x21, 0x21, 0x00, 0x37, 0x03, 0x21, 0x3A, 0x64, 0xCF, 0x20,
0xD6, 0xAC, 0x7A, 0x11, 0x63, 0x4E, 0x40, 0x3F, 0x5A, 0xA3, 0x41, 0x20, 0xEB, 0x8F, 0xC0, 0x61,
0x22, 0x05, 0x09, 0x27, 0x19, 0x81, 0x2B, 0x6F, 0xB6, 0xA5, 0x0B, 0x7D, 0x72, 0x6A, 0x68, 0x68,
0x67, 0x68, 0x65, 0x00, 0x5D, 0x22, 0xB5, 0x23, 0x98, 0x25, 0xB5, 0x7D, 0x59, 0x42, 0x0C, 0x36,
0x37, 0x53, 0xA2, 0x85, 0x00, 0x45, 0xBA, 0x33, 0xA1, 0xA6, 0xD0, 0xE9, 0x92, 0x1E, 0x2F, 0x82,
0xAA, 0xAB, 0xA8, 0xA7, 0x01, 0xA7, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA2, 0x24, 0x00, 0x74, 0x04,
0x5D, 0xD1, 0x50, 0xDA, 0xA8, 0x60, 0x4D, 0x63, 0x05, 0x41, 0x00, 0xE1, 0x22, 0x02, 0xB8, 0xB2,
0x2D, 0x23, 0xA4, 0x86, 0x27, 0x39, 0x3D, 0x4A, 0x4A, 0x47, 0x46, 0x45, 0x46, 0x46, 0x46, 0x00,
0x46, 0x42, 0x35, 0x23, 0x79, 0x0C, 0x44, 0x65, 0x99, 0x10, 0xD5, 0xD1, 0x40, 0xF8, 0xD2, 0xAC,
0xA5, 0xFF, 0xFF, 0x02, 0xE2, 0x9A, 0x71, 0x21, 0x5F, 0x59, 0x8A, 0x98, 0x30, 0x25, 0x02, 0x10,
0x26, 0x5E, 0x24, 0x26, 0x25, 0x24, 0xB1, 0x12, 0x21, 0x2D, 0x3F, 0x10, 0x53, 0x65, 0x74, 0xB5,
0x69, 0x0F, 0x3B, 0x64, 0x5A, 0x39, 0x30, 0x29, 0x21, 0x3B, 0x44, 0x1B, 0x95, 0xF1, 0x89, 0xC5,
0xD0, 0x30, 0x25, 0x74, 0x2D, 0x39, 0x48, 0x59, 0x6C, 0x8F, 0xC5, 0xF1, 0x00, 0x44, 0x40, 0xF8,
0xCB, 0x83, 0x49, 0x39, 0x2B, 0xB3, 0x83, 0x81, 0x21, 0x33, 0xBD, 0x3C, 0xC7, 0xF0, 0x5E, 0x91,
0x29, 0x32, 0x40, 0x1C, 0x4F, 0x61, 0x72, 0xA4, 0xD6, 0x66, 0x12, 0x63, 0x22, 0xC3, 0x60, 0x74,
0x2E, 0x2C, 0x03, 0x35, 0xFC, 0x8C, 0x45, 0x42, 0x80, 0xB4, 0x84, 0x26, 0x7C, 0x2B, 0x37, 0x43,
0x55, 0x67, 0x82, 0xB5, 0xE3, 0x00, 0x69, 0x53, 0x3C, 0xF8, 0x70, 0x21, 0x3D, 0x44, 0x69, 0x9B,
0x64, 0x7D, 0x28, 0x94, 0xF5, 0x21, 0x27, 0x2F, 0x3B, 0x49, 0x5B, 0x6E, 0x8E, 0x00, 0xCD, 0xF2,
0x1B, 0x22, 0x46, 0x85, 0x50, 0x2D, 0x13, 0xF9, 0xE3, 0x30, 0xD4, 0xF4, 0x88, 0x62, 0x20, 0x22,
0x2A, 0x33, 0x40, 0x50, 0x62, 0x01, 0x74, 0xAC, 0xD5, 0x0D, 0x21, 0xC9, 0x80, 0x95, 0xC1, 0x25,
0x37, 0x25, 0x78, 0x29, 0x28, 0x29, 0x28, 0x27, 0x00, 0x13, 0x1F, 0x21, 0x20, 0x21, 0x20, 0x1D,
0xD7, 0x5B, 0x1E, 0x1E, 0x25, 0x2D, 0x08, 0x37, 0x45, 0x57, 0x6C, 0x86, 0xB5, 0xE7, 0x45, 0x00,
0x82, 0x22, 0x45, 0x9D, 0x24, 0xCB, 0x51, 0x82, 0x88, 0x76, 0x0C, 0x86, 0x47, 0x82, 0x23, 0x94,
0x06, 0x2F, 0x6C, 0x2E, 0x25, 0x2F, 0x82, 0x84, 0x1E, 0x21, 0x2A, 0x38, 0x4F, 0x6B, 0x7F, 0xCE,
0x00, 0x3F, 0x25, 0x9B, 0xA1, 0x16, 0x0D, 0x72, 0x3D, 0x24, 0x56, 0xAF, 0x93, 0x1E, 0x76, 0x6B,
0x6B, 0x6A, 0x69, 0x60, 0x24, 0x01, 0x0E, 0x80, 0x43, 0xF6, 0x87, 0x3B, 0x28, 0x1E, 0x1D, 0x97,
0x40, 0x80, 0xC5, 0x10, 0x39, 0x55, 0x9E, 0xF1, 0xB5, 0x93, 0x22, 0x59, 0xFA, 0xA1, 0x1F, 0x32,
0x84, 0x80, 0x42, 0x34, 0xC9, 0x10, 0x25, 0x40, 0xB4, 0x06, 0x38, 0x1C, 0x05, 0xA8, 0x42, 0x2B,
0x21, 0x3E, 0x56, 0x85, 0x22, 0x2B, 0x3E, 0x5A, 0xC2, 0x41, 0x20, 0xF1, 0x7B, 0x59, 0x6A, 0xE0,
0x76, 0x8D, 0x8A, 0x68, 0x2A, 0x39, 0x02, 0x20, 0x1E, 0x1C, 0x11, 0x2D, 0x03, 0x3C, 0x69, 0x0F,
0x00, 0xCD, 0x46, 0x2E, 0xC8, 0x3F, 0x89, 0x1E, 0x25, 0x32, 0x49, 0x7F, 0x4A, 0x21, 0x49, 0x29,
0x20, 0xA5, 0xC2, 0x81, 0xA4, 0x1F, 0x30, 0x6B, 0x88, 0x2D, 0x1E, 0x03, 0xBD, 0x5D, 0x3A, 0xD8,
0x14, 0xFF, 0xE0, 0x5C, 0x30, 0x23, 0x05, 0x1D, 0x47, 0x02, 0x28, 0x3A, 0x55, 0xB9, 0x82, 0x20,
0xF1, 0x42, 0x40, 0x25, 0xF9, 0xA3, 0x3B, 0x25, 0xCB, 0x28, 0x45, 0x9A, 0x14, 0x83, 0x43, 0x2F,
0x2E, 0x2F, 0x2D, 0x26, 0x1D, 0x02, 0x80, 0x33, 0x59, 0x90, 0x20, 0xE9, 0x6E, 0x34, 0x26, 0x1F,
0x04, 0x22, 0x2F, 0x44, 0x70, 0xDB, 0x82, 0x20, 0xCB, 0x65, 0x20, 0x35, 0x21, 0x85, 0xB0, 0x28,
0x62, 0xB2, 0x27, 0x47, 0x9A, 0x14, 0xBC, 0xA6, 0xA5, 0xA4, 0xA4, 0xA3, 0xA0, 0x24, 0x00, 0xCC,
0x00, 0x42, 0x68, 0xB4, 0x09, 0x20, 0x82, 0x3D, 0x34, 0x11, 0x3A, 0x51, 0x9A, 0x37, 0x20, 0xF8,
0xA9, 0x57, 0x3A, 0x08, 0x27, 0x1E, 0xA5, 0x82, 0x15, 0xBA, 0xEF, 0x2B, 0x75, 0xA2, 0x55, 0x1C,
0x47, 0x43, 0x43, 0x42, 0x3E, 0x32, 0x22, 0xCE, 0x01, 0x80, 0x2C, 0x45, 0x67, 0x9B, 0x57, 0x11,
0xFF, 0xAB, 0x59, 0x10, 0x72, 0xCC, 0x7F, 0x20, 0xDC, 0x78, 0x4C, 0x34, 0xAE, 0x40, 0x84, 0xE9,
0xF2, 0xDB, 0x3B, 0x1F, 0x36, 0x8B, 0x6C, 0x30, 0x26, 0x03, 0x26, 0x24, 0x24, 0x24, 0x22, 0x17,
0x10, 0x22, 0x2B, 0x20, 0x3F, 0x5F, 0x8F, 0xEA, 0x03, 0x10, 0xD4, 0xE9, 0x3C, 0x10, 0x90, 0xF9,
0xBB, 0x5D, 0x41, 0x2E, 0xC7, 0x9A, 0x19, 0x22, 0x20, 0xE9, 0x12, 0x85, 0x10, 0x76, 0x9D, 0x79,
0x6F, 0xEF, 0x8C, 0x77, 0x03, 0x3B, 0x67, 0x59, 0x83, 0xDD, 0x4B, 0x51, 0xE3, 0x86, 0x50, 0x37,
0x08, 0x29, 0xF4, 0x4D, 0x1C, 0x6E, 0x33, 0x22, 0x19, 0x06, 0x25, 0x4B, 0xB2, 0x67, 0xEA, 0x2E,
0x51, 0x98, 0x47, 0x31, 0x2F, 0x2F, 0x30, 0x00, 0x2D, 0x26, 0x28, 0x3A, 0x1F, 0x27, 0x37, 0x52,
0x74, 0x04, 0xCD, 0x06, 0x31, 0xC4, 0x66, 0x45, 0xEA, 0x06, 0xFD, 0xC2, 0x19, 0x26, 0xE2, 0x71,
0xB3, 0x2C, 0x6E, 0xA3, 0xB6, 0xA6, 0xA6, 0xA4, 0x01, 0xA6, 0xA4, 0xA1, 0xAE, 0x02, 0x5D, 0x09,
0x20, 0x21, 0x28, 0x18, 0x35, 0x50, 0x70, 0xB5, 0xC1, 0x10, 0xEA, 0x83, 0x51, 0x10, 0x34, 0x26,
0xC0, 0x0C, 0x57, 0x03, 0x79, 0x8B, 0xF5, 0x37, 0x61, 0x53, 0x1A, 0x7C, 0xC1, 0x01, 0x1D, 0x28,
0x55, 0x73, 0x77, 0x74, 0x71, 0x01, 0x71, 0x73, 0x71, 0x65, 0x24, 0x1B, 0x1C, 0x1F, 0x00, 0x26,
0x2C, 0x30, 0x33, 0x35, 0x39, 0x47, 0x5E, 0x00, 0x7B, 0x9C, 0x42, 0x20, 0x69, 0x41, 0x36, 0x24,
0x00, 0x2F, 0x44, 0x27, 0x68, 0x10, 0x49, 0x99, 0x6D, 0xC7, 0x1F, 0x26, 0x32, 0x34, 0x0E, 0x33,
0x3C, 0x04, 0x32, 0xB1, 0x01, 0x1E, 0x29, 0x39, 0x86, 0x0A, 0x8E, 0x90, 0x90, 0x90, 0x94, 0x9A,
0xA3, 0xA4, 0x00, 0xAD, 0xC4, 0x04, 0xFF, 0xEA, 0x98, 0x92, 0x8F, 0x91, 0x02, 0x8F, 0x8A, 0x80,
0x2B, 0x1F, 0xCE, 0x00, 0xE9, 0xF2, 0x3A, 0x84, 0xE0, 0x25, 0x27, 0x2A, 0x28, 0x25, 0x62, 0x0B,
0xB1, 0x07, 0x51, 0x60, 0x41, 0xF0, 0xFF, 0xC6, 0x21, 0x97, 0x20, 0x15, 0x5A, 0xE5, 0x56, 0xCC,
0x7A, 0x2B, 0x7D, 0x45, 0x79, 0x89, 0x87, 0x6E, 0x2C, 0x75, 0x0C, 0x21, 0x40, 0x39, 0x63, 0x01,
0x10, 0x3D, 0xF0, 0x44, 0x28, 0x69, 0xBB, 0x28, 0x4C, 0x35, 0xC9, 0x31, 0x7B, 0xB1, 0x94, 0x8E,
0x8E, 0x9A, 0x01, 0xB0, 0x56, 0xA8, 0x01, 0x39, 0x62, 0x01, 0x10, 0x39, 0xF4, 0x45, 0x64, 0x27,
0x1B, 0xA1, 0x76, 0x46, 0xDB, 0x59, 0x1A, 0x2B, 0x93, 0x28, 0x64, 0x57, 0xAB, 0x56, 0x40, 0x3D,
0x3F, 0x4B, 0x6C, 0x00, 0xA3, 0x2A, 0x1D, 0x20, 0x30, 0x4E, 0xC1, 0x05, 0x10, 0x80, 0xC5, 0xC5,
0xC5, 0xC5, 0xC4, 0xC5, 0xC6, 0x00, 0x00, 0x80, 0xC5, 0xC6, 0xC5, 0xC4, 0xC4, 0xC2, 0xB9, 0x39,
0x00, 0x0D, 0x91, 0x4D, 0x15, 0x50, 0x85, 0x56, 0x1A, 0x83, 0x7C, 0x33, 0x24, 0x0F, 0x25, 0x24,
0x2F, 0x48, 0x98, 0x56, 0x1E, 0x1E, 0x00, 0x29, 0x38, 0x4B, 0x59, 0x5B, 0x59, 0x01, 0x00, 0x03,
0x00, 0xC0, 0x5A, 0x5B, 0x59, 0x5A, 0x5A, 0x5B, 0x5B, 0x5B, 0x00, 0x5C, 0x5D, 0x53, 0x41, 0x2D,
0x1F, 0x1B, 0x1A, 0x00, 0x91, 0xB5, 0x6A, 0xA8, 0x37, 0x8A, 0x66, 0x24, 0x33, 0x00, 0x24, 0x43,
0x40, 0x8C, 0x62, 0x4B, 0x00, 0x30, 0x3D, 0x41, 0x3F, 0x08, 0x39, 0x33, 0x30, 0x30, 0x31, 0x32,
0x31, 0x32, 0x00, 0x30, 0x32, 0x30, 0x32, 0x32, 0x31, 0x38, 0x40, 0x00, 0x48, 0x46, 0x38, 0x29,
0x1F, 0x99, 0x80, 0x51, 0x51, 0x8E, 0x86, 0xE0, 0x74, 0x8F, 0x2E, 0x1E, 0x1D, 0x1E, 0x2B, 0x47,
0x00, 0xAB, 0x41, 0x20, 0x1F, 0x29, 0x3A, 0x87, 0x87, 0x00, 0x81, 0x2F, 0x24, 0xE1, 0x07, 0x24,
0x26, 0x27, 0x26, 0x08, 0x22, 0x8C, 0x02, 0x21, 0x2E, 0x41, 0xB7, 0xB8, 0xB3, 0x02, 0x32, 0x22,
0x9B, 0x50, 0x0D, 0x31, 0x29, 0x8E, 0x20, 0x18, 0x52, 0x1D, 0x6C, 0x2B, 0x45, 0xA5, 0x89, 0x45,
0x37, 0x3B, 0x59, 0x00, 0x9E, 0x8A, 0x2B, 0x1B, 0x8E, 0x00, 0x10, 0x00, 0x3B, 0x26, 0x30, 0x05,
0x02, 0x2B, 0x36, 0x39, 0x35, 0x28, 0x1F, 0x2E, 0x12, 0x81, 0x59, 0x2E, 0x00, 0x3F, 0x24, 0x5D,
0x86, 0x45, 0x51, 0x51, 0x81, 0x81, 0xD2, 0x55, 0x8D, 0xB0, 0xBC, 0xBC, 0xAC, 0x7D, 0xE5, 0x06,
0x80, 0x22, 0xC1, 0x28, 0x48, 0x28, 0x1B, 0x1E, 0x28, 0x3F, 0x02, 0xC0, 0xDE, 0xDD, 0x70, 0x27,
0x85, 0x00, 0x3B, 0x68, 0x20, 0x2E, 0x00, 0x49, 0x58, 0x19, 0x1A, 0x84, 0x43, 0xD9, 0x21, 0x42,
0xBA, 0x9D, 0x05, 0xF5, 0x4B, 0x4F, 0x4D, 0x42, 0x31, 0x24, 0x4A, 0x09, 0x3E, 0x40, 0x20, 0x11,
0x4D, 0x28, 0x1C, 0x1E, 0x31, 0x53, 0x41, 0x00, 0x81, 0x87, 0x2E, 0x51, 0x01, 0x3E, 0x6E, 0xB6,
0x10, 0x50, 0x10, 0x1A, 0x64, 0x71, 0x43, 0x48, 0xB5, 0x13, 0x81, 0xA4, 0xE9, 0x06, 0x24, 0x25,
0x45, 0x17, 0x9D, 0x1F, 0x1E, 0x1D, 0x23, 0x3F, 0x10, 0x20, 0x2A, 0x1C, 0x20, 0x20, 0x36, 0x61,
0x41, 0x00, 0x8F, 0x30, 0x1F, 0x1B, 0x08, 0x21, 0x82, 0x21, 0x4F, 0x2B, 0x1C, 0x1A, 0xD5, 0xF5,
0x1B, 0x42, 0x1D, 0x62, 0x5D, 0x41, 0x9B, 0x01, 0x19, 0x1E, 0x27, 0x5D, 0x09, 0x4F, 0x1E, 0x21,
0x41, 0x10, 0x30, 0x19, 0x06, 0xC9, 0x20, 0x34, 0x70, 0xC6, 0x01, 0x3F, 0x72, 0x30, 0xA5, 0x82,
0xC5, 0x04, 0x28, 0xCE, 0x40, 0x4B, 0x39, 0xDD, 0x2E, 0x41, 0x8B, 0x69, 0x34, 0x2F, 0x2F, 0x2F,
0x00, 0x34, 0x41, 0x8F, 0x5F, 0x20, 0x98, 0x30, 0x4E, 0x29, 0x20, 0x1B, 0x20, 0xD5, 0x35, 0x33,
0x1F, 0x1B, 0x23, 0x2E, 0x20, 0x84, 0x50, 0x2A, 0x1D, 0x72, 0x6D, 0xA7, 0xFE, 0x27, 0x90, 0xA8,
0xB2, 0x1C, 0xAC, 0xA5, 0xA5, 0xA5, 0xA5, 0xA7, 0xA7, 0xAB, 0x00, 0x3D, 0x1F, 0x22, 0x54, 0x40,
0xAC, 0x03, 0x67, 0x91, 0x45, 0x21, 0x58, 0x2E, 0x50, 0x41, 0xB0, 0xC7, 0x84, 0x1E, 0x2E, 0x63,
0x7C, 0xA0, 0x07, 0x8F, 0x75, 0x73, 0x73, 0x73, 0x72, 0x70, 0x3E, 0x00, 0x27, 0x1B, 0x23, 0x40,
0x6F, 0x10, 0x20, 0x09, 0x05, 0x65, 0x60, 0xC5, 0x14, 0x31, 0x1E, 0xB6, 0x10, 0x41, 0x20, 0x19,
0x1B, 0x95, 0x91, 0x99, 0xF9, 0x03, 0xEA, 0x72, 0x22, 0x2F, 0x43, 0x7C, 0x61, 0x37, 0x03, 0x32,
0x33, 0x33, 0x31, 0x2D, 0x24, 0x1E, 0xC9, 0x40, 0x80, 0x57, 0x34, 0x25, 0x2B, 0x41, 0x6D, 0x41,
0x00, 0x94, 0x40, 0x3D, 0x28, 0x27, 0x2E, 0x49, 0x73, 0x85, 0x20, 0x64, 0x71, 0xC0, 0x29, 0x27,
0xCC, 0x60, 0xA0, 0x25, 0x29, 0x2D, 0x28, 0x20, 0x1E, 0x07, 0x1E, 0x1F, 0x1E, 0x16, 0x04, 0x85,
0x00, 0x71, 0x10, 0x00, 0x6D, 0x58, 0x53, 0x44, 0x4A, 0x5D, 0x7A, 0x4A, 0x00, 0xA0, 0x58, 0x20,
0x48, 0x45, 0x4B, 0x63, 0x7C, 0x85, 0x20, 0x38, 0x58, 0x95, 0x31, 0xE0, 0x29, 0x83, 0x64, 0x70,
0x53, 0x23, 0x78, 0x03, 0x28, 0x12, 0x16, 0x21, 0x56, 0x40, 0x70, 0x10, 0x00, 0x07, 0x00, 0xE1,
0xE3, 0xE3, 0xF8, 0x0C, 0xFF, 0xFF, 0xEB, 0xE3, 0xCC, 0x15, 0xE3, 0x41, 0x10, 0x2A, 0x50, 0x65,
0x51, 0x0D, 0x11, 0x71, 0x03, 0x29, 0xB4, 0x1E, 0x2C, 0x4E, 0x81, 0x0F, 0x26, 0x2D, 0x5D, 0x96,
0x8E, 0x3B, 0x1F, 0x1B, 0x00, 0x22, 0x40, 0x6F, 0x01, 0x10, 0x3D, 0xF0, 0x4F, 0x29, 0x54, 0x30,
0x98, 0x1A, 0x85, 0x20, 0xDA, 0x95, 0x11, 0x19, 0x82, 0x70, 0x1E, 0x26, 0x2A, 0x4B, 0xAE, 0x78,
0x2F, 0x4C, 0xAF, 0x84, 0x88, 0x00, 0xA3, 0x28, 0x1C, 0x21, 0x3E, 0x6A, 0x01, 0x10, 0x3D, 0xF0,
0xC0, 0x4B, 0x1C, 0x51, 0x1C, 0x98, 0x00, 0xB5, 0x93, 0x1A, 0xFA, 0x23, 0x30, 0x5A, 0x7D, 0x85,
0x38, 0x37, 0x7C, 0x8D, 0x49, 0x4E, 0x00, 0x98, 0x54, 0x1E, 0x1F, 0x36, 0xD5, 0x55, 0x4D, 0xF5,
0x19, 0x60, 0xA5, 0x62, 0xD9, 0x11, 0x58, 0xA7, 0x20, 0x36, 0x89, 0x68, 0x2F, 0x07, 0x3F, 0x9F,
0x5F, 0x2F, 0x40, 0x8B, 0x62, 0x20, 0x00, 0x20, 0x2B, 0x43, 0x5D, 0x6B, 0x04, 0x00, 0xDA, 0x35,
0xD0, 0x15, 0xE0, 0x86, 0x06, 0x71, 0x6E, 0xD5, 0x05, 0xC5, 0x84, 0x33, 0x48, 0xDC, 0x19, 0xF9,
0x53, 0x1A, 0xB2, 0x54, 0x7C, 0x79, 0x3C, 0x56, 0xB0, 0x05, 0x37, 0x2B, 0x43, 0x97, 0x4D, 0x21,
0x1C, 0x21, 0x00, 0x2A, 0x36, 0x3C, 0x09, 0x30, 0x41, 0x3F, 0xD2, 0x75, 0x3A, 0x48, 0x31, 0x85,
0xB0, 0x95, 0x01, 0x00, 0x97, 0x1C, 0x1E, 0x2B, 0x50, 0x0E, 0xAB, 0x8E, 0xA1, 0x8A, 0x31, 0x43,
0x86, 0xA4, 0x00, 0x2E, 0x1D, 0xE7, 0x04, 0x27, 0x29, 0x2D, 0x02, 0x03, 0x10, 0x2A, 0x64, 0x00,
0x00, 0x2A, 0x28, 0x10, 0x12, 0x28, 0x28, 0x22, 0x9D, 0x42, 0x89, 0xE9, 0x72, 0x1C, 0x86, 0xA6,
0x23, 0x36, 0x55, 0x86, 0x7D, 0x05, 0x37, 0x2D, 0x5B, 0x97, 0x47, 0x6D, 0x01, 0x21, 0x29, 0x20,
0x35, 0x3A, 0x3C, 0x3D, 0x3A, 0x3B, 0x3C, 0x3D, 0x00, 0x3C, 0x3B, 0x03, 0x10, 0x3C, 0x3C, 0x3C,
0x3C, 0x3B, 0x04, 0x3B, 0x37, 0x2E, 0x4D, 0x95, 0x34, 0x45, 0xC5, 0x04, 0x0E, 0x31, 0xC8, 0x43,
0x50, 0x1E, 0x22, 0x2E, 0x33, 0x2E, 0x24, 0x22, 0x01, 0x2E, 0x31, 0x27, 0x1E, 0x1B, 0x20, 0x2B,
0x40, 0x00, 0xB7, 0xBB, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0xBE, 0xBE, 0xBE, 0x1C, 0xBD, 0xBA,
0xB3, 0x31, 0x22, 0xC9, 0x80, 0x41, 0x10, 0x1C, 0x60, 0x1C, 0xFA, 0xB5, 0x1F, 0x21, 0x1E, 0x10,
0x15, 0xAE, 0x13, 0x34, 0x62, 0x57, 0x01, 0x10, 0x3D, 0xF0, 0x3E, 0x25, 0x1B, 0x1C, 0x51, 0x81,
0x86, 0x39, 0x29, 0x95, 0xB1, 0x21, 0x2B, 0x35, 0x36, 0x36, 0x04, 0x36, 0x35, 0x34, 0x31, 0x29,
0x20, 0x6A, 0x02, 0x65, 0x40, 0x01, 0x10, 0x3D, 0xF0, 0x48, 0x27, 0x09, 0x44, 0x1D, 0x52, 0x1E,
0xB2, 0x2B, 0x73, 0x88, 0xBA, 0xBB, 0xBA, 0xBC, 0xBA, 0xBA, 0xBC, 0x00, 0xA1, 0x24, 0x1B, 0x22,
0x38, 0x5F, 0x01, 0x10, 0x29, 0xF3, 0xC0, 0x43, 0x0C, 0x20, 0xD9, 0x71, 0x27, 0x3D, 0xA1, 0x1D,
0x29, 0x3D, 0x16, 0x4B, 0x51, 0x51, 0x51, 0x53, 0x5A, 0x7B, 0x92, 0x00, 0x2B, 0x1B, 0x20, 0x30,
0x49, 0x96, 0x9E, 0xA2, 0x00, 0xA2, 0xA2, 0xA2, 0xA2, 0xA5, 0xA5, 0xEA, 0xFF, 0x00, 0xFF, 0xBE,
0xA4, 0xA3, 0xA2, 0xA2, 0xA1, 0xA3, 0x00, 0xA0, 0x9A, 0x8A, 0x37, 0x24, 0xF9, 0x72, 0x35, 0x46,
0x20, 0xDB, 0x3B, 0x29, 0x1B, 0x1C, 0xF8, 0x80, 0x1D, 0x1F, 0x20, 0x22, 0x27, 0x27, 0x27, 0x28,
0x2A, 0x34, 0x4A, 0x00, 0x97, 0x4A, 0x1E, 0x1E, 0x24, 0x31, 0x40, 0x49, 0x00, 0x0B, 0x00, 0x4D,
0x51, 0x63, 0x7C, 0x41, 0x00, 0xA2, 0x60, 0x21, 0x50, 0x4C, 0x4D, 0x4D, 0x4D, 0x4C, 0x43, 0x37,
0x00, 0x28, 0x82, 0x70, 0x21, 0x33, 0x46, 0xA5, 0x02, 0x7D, 0xC1, 0xE9, 0x42, 0xE2, 0x3E, 0x8A,
0x62, 0x1F, 0x1B, 0x1D, 0x21, 0x26, 0x00, 0x27, 0x28, 0x29, 0x29, 0x2A, 0x2F, 0x45, 0x6E, 0x00,
0x41, 0x00, 0x96, 0x40, 0x2D, 0x2A, 0x29, 0x2A, 0x29, 0x01, 0x28, 0x20, 0x04, 0x1D, 0x41, 0xB0,
0x27, 0x1F, 0x14, 0x3D, 0x81, 0x24, 0x6A, 0x26, 0x29, 0x27, 0x29, 0x2B, 0x33, 0x4A, 0xA5, 0x00,
0x4D, 0x1E, 0x16, 0x24, 0x1E, 0x1E, 0x1C, 0x1E, 0x23, 0x04, 0x3A, 0x69, 0x41, 0x10, 0x35, 0x20,
0x1D, 0x1D, 0x1D, 0x04, 0x1D, 0x1D, 0xF1, 0x10, 0x2D, 0x83, 0xC9, 0xE0, 0x1D, 0x24, 0x60, 0x1C,
0x86, 0x87, 0x87, 0x88, 0x89, 0x98, 0xAF, 0x8A, 0x00, 0x2E, 0xF4, 0x73, 0x20, 0x3A, 0xC9, 0x40,
0x1C, 0x5F, 0xE3, 0x22, 0x52, 0x41, 0x10, 0x27, 0x2D, 0xA0, 0x1E, 0x24, 0x4E, 0x67, 0x6A, 0x05,
0x6A, 0x6B, 0x6D, 0x6F, 0x59, 0x34, 0x22, 0xD1, 0x83, 0x80, 0x39, 0x85, 0x20, 0x32, 0x20, 0x18,
0x60, 0x1D, 0xA2, 0x3B, 0x28, 0x32, 0x0B, 0xA3, 0x1C, 0x20, 0x27, 0x2D, 0x2F, 0x2E, 0x2E, 0x01,
0x31, 0x2E, 0x28, 0x21, 0x42, 0x83, 0x21, 0x3A, 0x41, 0x10, 0x90, 0x91, 0x33, 0x20, 0xA7, 0x83,
0x19, 0x85, 0x40, 0x41, 0x60, 0x19, 0x82, 0xE8, 0x20, 0x1F, 0x20, 0x1E, 0x1F, 0x21, 0x1F, 0x1C,
0x00, 0x45, 0x93, 0x20, 0x38, 0x66, 0x85, 0x00, 0x90, 0x33, 0x26, 0x62, 0x91, 0xD9, 0x80, 0x95,
0x01, 0x3A, 0x85, 0x20, 0x1C, 0x81, 0x41, 0x20, 0x27, 0x2B, 0x32, 0x56, 0x35, 0x1D, 0x1D, 0x24,
0x49, 0x4A, 0x00, 0x28, 0x20, 0x1B, 0x1D, 0x12, 0x23, 0x26, 0x26, 0x26, 0x08, 0x26, 0x27, 0x2A,
0x3F, 0x6C, 0xE2, 0xFF, 0xFF, 0x00, 0x94, 0x3E, 0x28, 0x25, 0x26, 0x27, 0x27, 0x26, 0x00, 0x24,
0x21, 0x1E, 0xE8, 0x10, 0x1C, 0xD9, 0x71, 0x1D, 0x22, 0x1C, 0x68, 0x3A, 0x32, 0x1E, 0x2D, 0x61,
0xB1, 0xA8, 0x51, 0x1E, 0x01, 0x1D, 0x2B, 0x77, 0xAF, 0xA3, 0x3D, 0x20, 0x1B, 0x00, 0x1D, 0x22,
0x2E, 0x3A, 0x41, 0x45, 0x45, 0x45, 0x00, 0x46, 0x48, 0x5C, 0x79, 0xE3, 0xFF, 0xFF, 0xA1, 0x00,
0x5A, 0x49, 0x45, 0x44, 0x45, 0x45, 0x43, 0x3E, 0x00, 0x33, 0x26, 0x20, 0x1B, 0x1C, 0x0D, 0x61,
0xC9, 0x00, 0x41, 0x80, 0xE0, 0x1C, 0x26, 0x4D, 0xB1, 0x71, 0x3D, 0x27, 0x1C, 0x00, 0x1D, 0x26,
0x39, 0x4E, 0x81, 0x9B, 0x27, 0x1B, 0x00, 0x1F, 0x2E, 0x47, 0xDE, 0xE0, 0xE2, 0xE2, 0x07, 0x10,
0x80, 0xE3, 0xF7, 0xFF, 0xFF, 0xEA, 0xE3, 0xE2, 0xE2, 0x00, 0xE2, 0xE3, 0xE2, 0xE1, 0xE0, 0xDD,
0x34, 0x21, 0x00, 0x41, 0x90, 0xDA, 0x41, 0x90, 0x20, 0x2F, 0x7E, 0x8B, 0x38, 0x05, 0x25, 0x1E,
0x49, 0x12, 0x32, 0x4B, 0x9D, 0x3D, 0x1D, 0x04, 0x1F, 0x37, 0x5D, 0x03, 0x30, 0x85, 0xF0, 0x1E,
0x72, 0x35, 0x85, 0x00, 0xB8, 0x28, 0xC9, 0x70, 0x22, 0x37, 0x8B, 0x68, 0x27, 0xDE, 0x31, 0x82,
0x26, 0x3F, 0x8A, 0x61, 0x21, 0x21, 0x3B, 0x66, 0x00, 0x01, 0x10, 0x3D, 0xF0, 0x47, 0x28, 0x92,
0x61, 0xC9, 0x00, 0xDA, 0x3B, 0x33, 0x27, 0x1C, 0xF3, 0x61, 0x21, 0x38, 0x8B, 0x71, 0x25, 0x04,
0x76, 0x30, 0x24, 0x3C, 0x91, 0x62, 0x21, 0x1F, 0x35, 0x01, 0x5B, 0x07, 0x70, 0x03, 0x30, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0x41, 0x0E, 0x25, 0xD9, 0x60, 0x21, 0x34, 0x47, 0xDB, 0x39, 0x27, 0x02,
0xA6, 0x71, 0x1F, 0x31, 0x65, 0xA4, 0x32, 0x20, 0x55, 0x11, 0x81, 0x20, 0x2E, 0x55, 0xAA, 0x34,
0x1E, 0x1E, 0x2C, 0x00, 0x42, 0x5C, 0x6A, 0x01, 0x00, 0x71, 0x6F, 0x03, 0x10, 0x70, 0x48, 0x00,
0x00, 0x70, 0x70, 0x6F, 0x6F, 0x6D, 0x63, 0x4C, 0x01, 0x32, 0xAC, 0x20, 0x1C, 0x41, 0x30, 0x48,
0xDB, 0x3A, 0x26, 0x0A, 0x32, 0x50, 0xFD, 0x10, 0x42, 0x92, 0x9D, 0x52, 0x33, 0x2F, 0x03, 0x2F,
0x32, 0x3A, 0x6C, 0xAB, 0x72, 0x29, 0x1D, 0x00, 0x1B, 0x21, 0x2B, 0x36, 0x3D, 0x40, 0x3F, 0x05,
0x40, 0x80, 0x41, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x3F, 0x39, 0x02, 0x30, 0x24, 0x40, 0x70,
0x21, 0x35, 0x47, 0xDC, 0x3A, 0x04, 0x29, 0x65, 0x80, 0x20, 0x2D, 0x46, 0x81, 0xB0, 0xB0, 0x02,
0xA4, 0xA5, 0xA6, 0xB6, 0xA6, 0x6B, 0x32, 0x20, 0x00, 0x1B, 0x1B, 0x1D, 0x20, 0x20, 0x21, 0x22,
0x0B, 0x10, 0x80, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x23, 0x22, 0x00, 0x21, 0x23, 0x23, 0x21,
0x22, 0x21, 0x1E, 0x1E, 0x00, 0x25, 0x70, 0x20, 0x32, 0x45, 0xDA, 0x37, 0x27, 0x62, 0x30, 0x81,
0x8A, 0x30, 0x1F, 0x2B, 0x3C, 0x4A, 0x59, 0x71, 0x71, 0x01, 0x70, 0x4B, 0x3E, 0x2E, 0x21, 0x0A,
0x90, 0x1A, 0x04, 0x40, 0xA0, 0x6E, 0xF0, 0x21, 0x2E, 0x3B, 0xDC, 0x32, 0x24, 0x1B, 0x40, 0x81,
0x1A, 0x0C, 0x20, 0x1E, 0x23, 0x27, 0x2D, 0x32, 0x30, 0x02, 0x2E, 0x28, 0x24, 0x1E, 0x55, 0xC0,
0x19, 0x7A, 0x20, 0x19, 0x50, 0x45, 0xA0, 0x1C, 0x37, 0x00, 0x1E, 0x27, 0x2D, 0x30, 0x29, 0x05,
0x1F, 0x12, 0xC0, 0x73, 0x00, 0x1E, 0x1F, 0x2C, 0x80, 0x22, 0xF0, 0x53, 0xB0, 0xE6, 0x1F, 0x24,
0x24, 0x21, 0x1D, 0x1C, 0xF0, 0x1C, 0x1B, 0x80, 0xA0, 0x19, 0x02, 0x20, 0x1D, 0xF0, 0x0A, 0x60,
0x1C, 0x1C, 0x1C, 0x1D, 0x0E, 0x1C, 0x0A, 0xA0, 0x1B, 0x03, 0x30, 0x00, 0x00, 0x1B, 0x1B, 0x1B,
0x1A, 0xFF, 0xFF, 0xFF, 0x30, 0x1A, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xD0, 0x18, 0x00, 0x00
};
#endif

225
bootloader/gfx/tui.c Normal file
View File

@@ -0,0 +1,225 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#include "tui.h"
#include "../utils/btn.h"
#include "../config/config.h"
#include "../power/max17050.h"
#include "../utils/util.h"
#include "../config/config.h"
#include "di.h"
#ifdef MENU_LOGO_ENABLE
extern u8 *Kc_MENU_LOGO;
#define X_MENU_LOGO 119
#define Y_MENU_LOGO 57
#define X_POS_MENU_LOGO 577
#define Y_POS_MENU_LOGO 1179
#endif //MENU_LOGO_ENABLE
extern hekate_config h_cfg;
void tui_sbar(gfx_con_t *con, bool force_update)
{
u32 cx, cy;
u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping;
if (!force_update)
if (timePassed < 5)
return;
u8 prevFontSize = con->fntsz;
con->fntsz = 16;
h_cfg.sbar_time_keeping = get_tmr_s();
u32 battPercent = 0;
int battVoltCurr = 0;
gfx_con_getpos(con, &cx, &cy);
gfx_con_setpos(con, 0, 1260);
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
gfx_clear_partial_grey(con->gfx_ctxt, 0x30, 1256, 24);
gfx_printf(con, "%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
max17050_get_property(MAX17050_AvgCurrent, &battVoltCurr);
if (battVoltCurr >= 0)
gfx_printf(con, " %k+%d mA%k%K\n",
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
else
gfx_printf(con, " %k-%d mA%k%K\n",
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
con->fntsz = prevFontSize;
gfx_con_setpos(con, cx, cy);
}
void tui_pbar(gfx_con_t *con, int x, int y, u32 val, u32 fgcol, u32 bgcol)
{
u32 cx, cy;
if (val > 200)
val = 200;
gfx_con_getpos(con, &cx, &cy);
gfx_con_setpos(con, x, y);
gfx_printf(con, "%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
x += 7 * con->fntsz;
for (int i = 0; i < (con->fntsz >> 3) * 6; i++)
{
gfx_line(con->gfx_ctxt, x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
gfx_line(con->gfx_ctxt, x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
}
gfx_con_setpos(con, cx, cy);
// Update status bar.
tui_sbar(con, false);
}
void *tui_do_menu(gfx_con_t *con, menu_t *menu)
{
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
tui_sbar(con, true);
#ifdef MENU_LOGO_ENABLE
gfx_set_rect_rgb(con->gfx_ctxt, Kc_MENU_LOGO,
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
while (true)
{
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_con_setpos(con, menu->x, menu->y);
gfx_printf(con, "[%s]\n\n", menu->caption);
// Skip caption or seperator lines selection.
while (menu->ents[idx].type == MENT_CAPTION ||
menu->ents[idx].type == MENT_CHGLINE)
{
if (prev_idx <= idx || (!idx && prev_idx == cnt - 1))
{
idx++;
if (idx > (cnt - 1))
{
idx = 0;
prev_idx = 0;
}
}
else
{
idx--;
if (idx < 0)
{
idx = cnt - 1;
prev_idx = cnt;
}
}
}
prev_idx = idx;
// Draw the menu.
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
{
if (cnt == idx)
gfx_con_setcol(con, 0xFF1B1B1B, 1, 0xFFCCCCCC);
else
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
if (menu->ents[cnt].type == MENT_CAPTION)
gfx_printf(con, "%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
else if (menu->ents[cnt].type != MENT_CHGLINE)
gfx_printf(con, " %s", menu->ents[cnt].caption);
if(menu->ents[cnt].type == MENT_MENU)
gfx_printf(con, "%k...", 0xFF0099EE);
gfx_printf(con, " \n");
}
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_putc(con, '\n');
// Print help and battery status.
gfx_con_setpos(con, 0, 1127);
if (h_cfg.errors)
{
gfx_printf(con, "%k Warning: %k", 0xFF800000, 0xFF555555);
if (h_cfg.errors & ERR_LIBSYS_LP0)
gfx_printf(con, "Sleep mode library is missing!\n");
}
gfx_con_setpos(con, 0, 1191);
gfx_printf(con, "%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
display_backlight_brightness(h_cfg.backlight, 1000);
// Wait for user command.
u32 btn = btn_wait();
if (btn & BTN_VOL_DOWN && idx < (cnt - 1))
idx++;
else if (btn & BTN_VOL_DOWN && idx == (cnt - 1))
{
idx = 0;
prev_idx = -1;
}
if (btn & BTN_VOL_UP && idx > 0)
idx--;
else if (btn & BTN_VOL_UP && idx == 0)
{
idx = cnt - 1;
prev_idx = cnt;
}
if (btn & BTN_POWER)
{
ment_t *ent = &menu->ents[idx];
switch (ent->type)
{
case MENT_HANDLER:
ent->handler(ent->data);
break;
case MENT_MENU:
return tui_do_menu(con, ent->menu);
break;
case MENT_DATA:
return ent->data;
break;
case MENT_BACK:
return NULL;
break;
case MENT_HDLR_RE:
ent->handler(ent->data);
return NULL;
default:
break;
}
con->fntsz = 16;
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
#ifdef MENU_LOGO_ENABLE
gfx_set_rect_rgb(con->gfx_ctxt, Kc_MENU_LOGO,
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
}
tui_sbar(con, false);
}
return NULL;
}

7
ipl/tui.h → bootloader/gfx/tui.h Executable file → Normal file
View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* 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,
@@ -17,16 +18,17 @@
#ifndef _TUI_H_
#define _TUI_H_
#include "types.h"
#include "../utils/types.h"
#include "gfx.h"
#define MENT_END 0
#define MENT_HANDLER 1
#define MENT_MENU 2
#define MENT_CHOICE 3
#define MENT_DATA 3
#define MENT_BACK 4
#define MENT_CAPTION 5
#define MENT_CHGLINE 6
#define MENT_HDLR_RE 7
typedef struct _ment_t
{
@@ -57,6 +59,7 @@ typedef struct _menu_t
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
#define MDEF_CHGLINE() {MENT_CHGLINE}
void tui_sbar(gfx_con_t *con, bool force_update);
void tui_pbar(gfx_con_t *con, int x, int y, u32 val, u32 fgcol, u32 bgcol);
void *tui_do_menu(gfx_con_t *con, menu_t *menu);

601
bootloader/hos/hos.c Normal file
View File

@@ -0,0 +1,601 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018 Ced2911
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* 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 "hos.h"
#include "hos_config.h"
#include "secmon_exo.h"
#include "../config/config.h"
#include "../gfx/di.h"
#include "../mem/heap.h"
#include "../mem/mc.h"
#include "../sec/se.h"
#include "../sec/se_t210.h"
#include "../sec/tsec.h"
#include "../soc/cluster.h"
#include "../soc/fuse.h"
#include "../soc/pmc.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/util.h"
#include "../gfx/gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern hekate_config h_cfg;
extern void sd_unmount();
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...)
static const u8 keyblob_keyseeds[][0x10] = {
{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, //1.0.0
{ 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, //3.0.0
{ 0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B }, //3.0.1
{ 0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE }, //4.0.0
{ 0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80 }, //5.0.0
{ 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 } //6.0.0
};
static const u8 cmac_keyseed[0x10] =
{ 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 };
static const u8 master_keyseed_retail[0x10] =
{ 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C };
static const u8 console_keyseed[0x10] =
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
static const u8 key8_keyseed[] =
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
static const u8 master_keyseed_4xx_5xx_610[0x10] =
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
static const u8 master_keyseed_620[0x10] =
{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };
static const u8 console_keyseed_4xx_5xx[0x10] =
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
static void _se_lock(bool lock_se)
{
if (lock_se)
{
for (u32 i = 0; i < 16; i++)
se_key_acc_ctrl(i, 0x15);
for (u32 i = 0; i < 2; i++)
se_rsa_acc_ctrl(i, 1);
SE(0x4) = 0; // Make this reg secure only.
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = 0; // Make all key access regs secure only.
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = 0; // Make all RSA access regs secure only.
SE(SE_SECURITY_0) &= 0xFFFFFFFB; // Make access lock regs secure only.
}
memset((void *)IPATCH_BASE, 0, 13);
SB(SB_CSR) = 0x10; // Protected IROM enable.
// This is useful for documenting the bits in the SE config registers, so we can keep it around.
/*gfx_printf(&gfx_con, "SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0));
gfx_printf(&gfx_con, "SE(0x4) = %08X\n", SE(0x4));
gfx_printf(&gfx_con, "SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET));
gfx_printf(&gfx_con, "SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET));
for(u32 i = 0; i < 16; i++)
gfx_printf(&gfx_con, "%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
gfx_putc(&gfx_con, '\n');
for(u32 i = 0; i < 2; i++)
gfx_printf(&gfx_con, "%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
gfx_putc(&gfx_con, '\n');
gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
}
void _pmc_scratch_lock(u32 kb)
{
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
PMC(APBDEV_PMC_SEC_DISABLE) = 0x7FFFF3;
PMC(APBDEV_PMC_SEC_DISABLE2) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE3) = 0xFFAFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE4) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE6) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE7) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE8) = 0xFFAAFFFF;
break;
case KB_FIRMWARE_VERSION_400:
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF;
PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF;
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE6) |= 0xF3FFC00F;
PMC(APBDEV_PMC_SEC_DISABLE7) |= 0x3FFFFF;
PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF;
break;
}
}
void _sysctr0_reset()
{
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
SYSCTR0(SYSCTR0_CNTCR) = 0;
SYSCTR0(SYSCTR0_COUNTERID0) = 0;
SYSCTR0(SYSCTR0_COUNTERID1) = 0;
SYSCTR0(SYSCTR0_COUNTERID2) = 0;
SYSCTR0(SYSCTR0_COUNTERID3) = 0;
SYSCTR0(SYSCTR0_COUNTERID4) = 0;
SYSCTR0(SYSCTR0_COUNTERID5) = 0;
SYSCTR0(SYSCTR0_COUNTERID6) = 0;
SYSCTR0(SYSCTR0_COUNTERID7) = 0;
SYSCTR0(SYSCTR0_COUNTERID8) = 0;
SYSCTR0(SYSCTR0_COUNTERID9) = 0;
SYSCTR0(SYSCTR0_COUNTERID10) = 0;
SYSCTR0(SYSCTR0_COUNTERID11) = 0;
}
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
{
u8 tmp[0x20];
u32 retries = 0;
tsec_ctxt->size = 0xF00;
if (kb > KB_FIRMWARE_VERSION_MAX)
return 0;
// Get TSEC key.
if (kb >= KB_FIRMWARE_VERSION_620)
{
tsec_ctxt->size = 0x2900;
u8 *tsec_paged = (u8 *)page_alloc(3);
memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);
tsec_ctxt->fw = tsec_paged;
}
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
{
memset(tmp, 0x00, 0x20);
retries++;
if (retries > 3)
return 0;
}
if (kb >= KB_FIRMWARE_VERSION_620)
{
// Set TSEC key.
se_aes_key_set(12, tmp, 0x10);
// Set TSEC root key.
se_aes_key_set(13, tmp + 0x10, 0x10);
// Package2 key.
se_aes_key_set(8, tmp + 0x10, 0x10);
se_aes_unwrap_key(8, 8, master_keyseed_620);
se_aes_unwrap_key(8, 8, master_keyseed_retail);
se_aes_unwrap_key(8, 8, key8_keyseed);
}
else
{
se_key_acc_ctrl(13, 0x15);
se_key_acc_ctrl(14, 0x15);
// Set TSEC key.
se_aes_key_set(13, tmp, 0x10);
// Derive keyblob keys from TSEC+SBK.
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]);
se_aes_unwrap_key(15, 14, tmp);
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]);
se_aes_unwrap_key(13, 14, tmp);
// Clear SBK.
se_aes_key_clear(14);
//TODO: verify keyblob CMAC.
//se_aes_unwrap_key(11, 13, cmac_keyseed);
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
//if (!memcmp(keyblob, tmp, 0x10))
// return 0;
se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed);
se_aes_unwrap_key(11, 13, cmac_keyseed);
// Decrypt keyblob and set keyslots.
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); // Package1 key.
se_aes_key_set(12, keyblob + 0x20, 0x10);
se_aes_key_set(13, keyblob + 0x20, 0x10);
se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail);
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
se_aes_unwrap_key(13, 15, console_keyseed);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_400:
se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
}
// Package2 key.
se_key_acc_ctrl(8, 0x15);
se_aes_unwrap_key(8, 12, key8_keyseed);
}
return 1;
}
static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
{
int res = 0;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
// Read package1.
ctxt->pkg1 = (void *)malloc(0x40000);
sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
if (!ctxt->pkg1_id)
{
gfx_printf(&gfx_con, "%kUnknown package1,\nVersion (= '%s').%k\n", 0xFFFF0000, (char *)ctxt->pkg1 + 0x10, 0xFFCCCCCC);
goto out;
}
gfx_printf(&gfx_con, "Identified package1 ('%s'),\nKeyblob version %d\n\n", (char *)(ctxt->pkg1 + 0x10), ctxt->pkg1_id->kb);
// Read the correct keyblob.
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob);
res = 1;
out:;
sdmmc_storage_end(&storage);
return res;
}
static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
{
u8 *bctBuf = NULL;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
return NULL;
sdmmc_storage_set_mmc_partition(&storage, 0);
// Parse eMMC GPT.
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
DPRINTF("Parsed GPT\n");
// Find package2 partition.
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
if (!pkg2_part)
goto out;
// Read in package2 header and get package2 real size.
//TODO: implement memalign for DMA buffers.
static const u32 BCT_SIZE = 0x4000;
bctBuf = (u8 *)malloc(BCT_SIZE);
nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE, 1, bctBuf);
u32 *hdr = (u32 *)(bctBuf + 0x100);
u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3];
DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size);
// Read in Boot Config.
memset(bctBuf, 0, BCT_SIZE);
nx_emmc_part_read(&storage, pkg2_part, 0, BCT_SIZE / NX_EMMC_BLOCKSIZE, bctBuf);
// Read in package2.
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
DPRINTF("pkg2 size aligned is %08X\n", pkg2_size_aligned);
ctxt->pkg2 = malloc(pkg2_size_aligned);
ctxt->pkg2_size = pkg2_size;
nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE,
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, ctxt->pkg2);
out:;
nx_emmc_gpt_free(&gpt);
sdmmc_storage_end(&storage);
return bctBuf;
}
static void _free_launch_components(launch_ctxt_t *ctxt)
{
free(ctxt->keyblob);
free(ctxt->pkg1);
free(ctxt->pkg2);
free(ctxt->warmboot);
free(ctxt->secmon);
free(ctxt->kernel);
free(ctxt->kip1_patches);
}
int hos_launch(ini_sec_t *cfg)
{
launch_ctxt_t ctxt;
tsec_ctxt_t tsec_ctxt;
memset(&ctxt, 0, sizeof(launch_ctxt_t));
list_init(&ctxt.kip1_list);
if (!gfx_con.mute)
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
// Try to parse config if present.
if (cfg && !_parse_boot_config(&ctxt, cfg))
return 0;
gfx_printf(&gfx_con, "Initializing...\n\n");
// Read package1 and the correct keyblob.
if (!_read_emmc_pkg1(&ctxt))
return 0;
gfx_printf(&gfx_con, "Loaded package1 and keyblob\n");
// Generate keys.
if (!h_cfg.se_keygen_done || ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
{
tsec_ctxt.key_ver = 1;
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
tsec_ctxt.pkg1 = ctxt.pkg1;
tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base;
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt))
return 0;
DPRINTF("Generated keys\n");
h_cfg.se_keygen_done = 1;
}
// Decrypt and unpack package1 if we require parts of it.
if (!ctxt.warmboot || !ctxt.secmon)
{
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
gfx_printf(&gfx_con, "Decrypted and unpacked package1\n");
}
// Replace 'warmboot.bin' if requested.
if (ctxt.warmboot)
memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size);
// Set warmboot address in PMC if required.
if (ctxt.pkg1_id->set_warmboot)
PMC(APBDEV_PMC_SCRATCH1) = ctxt.pkg1_id->warmboot_base;
// Replace 'SecureMonitor' if requested.
if (ctxt.secmon)
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
else
{
// Else we patch it to allow for an unsigned package2 and patched kernel.
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
gfx_printf(&gfx_con, "%kPatching Security Monitor%k\n", 0xFFFFBA00, 0xFFCCCCCC);
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
}
gfx_printf(&gfx_con, "Loaded warmboot.bin and secmon\n");
// Read package2.
u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt);
if (!bootConfigBuf)
return 0;
gfx_printf(&gfx_con, "Read package2\n");
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
LIST_INIT(kip1_info);
pkg2_parse_kips(&kip1_info, pkg2_hdr);
gfx_printf(&gfx_con, "Parsed ini1\n");
// Use the kernel included in package2 in case we didn't load one already.
if (!ctxt.kernel)
{
ctxt.kernel = pkg2_hdr->data;
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
if (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere)
{
u32 kernel_crc32 = crc32c(ctxt.kernel, ctxt.kernel_size);
ctxt.pkg2_kernel_id = pkg2_identify(kernel_crc32);
// In case a kernel patch option is set; allows to disable SVC verification or/and enable debug mode.
kernel_patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset;
if (kernel_patchset != NULL)
{
gfx_printf(&gfx_con, "%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC);
u32 *temp;
for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)
{
if ((ctxt.svcperm && kernel_patchset[i].id == SVC_VERIFY_DS)
|| (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN && !(ctxt.atmosphere && ctxt.secmon))
|| (ctxt.atmosphere && kernel_patchset[i].id == ATM_GEN_PATCH))
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
else if (ctxt.atmosphere && kernel_patchset[i].id == ATM_ARR_PATCH)
{
temp = (u32 *)kernel_patchset[i].ptr;
for (u32 j = 0; j < kernel_patchset[i].val; j++)
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off + (j << 2)) = temp[j];
}
}
}
}
}
// Merge extra KIP1s into loaded ones.
gfx_printf(&gfx_con, "%kPatching kernel initial processes%k\n", 0xFFFFBA00, 0xFFCCCCCC);
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
// Patch kip1s in memory if needed.
const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches);
if (unappliedPatch != NULL)
{
gfx_printf(&gfx_con, "%kREQUESTED PATCH '%s' NOT APPLIED!%k\n", 0xFFFF0000, unappliedPatch, 0xFFCCCCCC);
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
while(1) {} // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
}
// Rebuild and encrypt package2.
pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info);
gfx_printf(&gfx_con, "Rebuilt and loaded package2\n");
// Unmount SD card.
sd_unmount();
gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
// Clear pkg1/pkg2 keys.
se_aes_key_clear(8);
se_aes_key_clear(11);
// Finalize per firmware keys.
int bootStateDramPkg2 = 0;
int bootStatePkg2Continue = 0;
switch (ctxt.pkg1_id->kb)
{
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_300)
PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0xE3; // Warmboot 3.0.0 PA address id.
else if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_301)
PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0x104; // Warmboot 3.0.1/.2 PA address id.
se_key_acc_ctrl(12, 0xFF);
se_key_acc_ctrl(13, 0xFF);
bootStateDramPkg2 = 2;
bootStatePkg2Continue = 3;
break;
case KB_FIRMWARE_VERSION_400:
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
se_key_acc_ctrl(12, 0xFF);
se_key_acc_ctrl(15, 0xFF);
case KB_FIRMWARE_VERSION_620:
bootStateDramPkg2 = 2;
bootStatePkg2Continue = 4;
break;
}
// Clear BCT area for retail units and copy it over if dev unit.
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_500)
{
memset((void *)0x4003D000, 0, 0x3000);
if ((fuse_read_odm(4) & 3) == 3)
memcpy((void *)0x4003D000, bootConfigBuf, 0x1000);
}
else
{
memset((void *)0x4003F000, 0, 0x1000);
if ((fuse_read_odm(4) & 3) == 3)
memcpy((void *)0x4003F800, bootConfigBuf, 0x800);
}
free(bootConfigBuf);
// Config Exosphère if booting full Atmosphère.
if (ctxt.atmosphere && ctxt.secmon)
config_exosphere(ctxt.pkg1_id->id, ctxt.pkg1_id->kb, ctxt.debugmode);
// Finalize MC carveout.
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
mc_config_carveout();
// Lock SE before starting 'SecureMonitor' if < 6.2.0, otherwise lock bootrom and ipatches.
_se_lock(ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600);
// Reset sysctr0 counters.
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
_sysctr0_reset();
// Free allocated memory.
ini_free_section(cfg);
_free_launch_components(&ctxt);
// < 4.0.0 pkg1.1 locks PMC scratches.
//_pmc_scratch_lock(ctxt.pkg1_id->kb);
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
vu32 *mb_in = (vu32 *)0x40002EF8;
// Non-zero: Secmon ready.
vu32 *mb_out = (vu32 *)0x40002EFC;
// Start from DRAM ready signal.
*mb_in = bootStateDramPkg2;
*mb_out = 0;
// Disable display. This must be executed before secmon to provide support for all fw versions.
display_end();
// Wait for secmon to get ready.
if (smmu_is_used())
smmu_exit();
else
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
while (!*mb_out)
usleep(1); // This only works when in IRAM or with a trained DRAM.
// Signal pkg2 ready and continue boot.
*mb_in = bootStatePkg2Continue;
// Halt ourselves in waitevent state and resume if there's JTAG activity.
while (1)
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = 0x50000000;
return 0;
}

70
bootloader/hos/hos.h Normal file
View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _HOS_H_
#define _HOS_H_
#include "pkg1.h"
#include "pkg2.h"
#include "../utils/types.h"
#include "../config/ini.h"
#include "../sec/tsec.h"
#define KB_FIRMWARE_VERSION_100_200 0
#define KB_FIRMWARE_VERSION_300 1
#define KB_FIRMWARE_VERSION_301 2
#define KB_FIRMWARE_VERSION_400 3
#define KB_FIRMWARE_VERSION_500 4
#define KB_FIRMWARE_VERSION_600 5
#define KB_FIRMWARE_VERSION_620 6
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_620
typedef struct _launch_ctxt_t
{
void *keyblob;
void *pkg1;
const pkg1_id_t *pkg1_id;
const pkg2_kernel_id_t *pkg2_kernel_id;
void *warmboot;
u32 warmboot_size;
void *secmon;
u32 secmon_size;
void *pkg2;
u32 pkg2_size;
void *kernel;
u32 kernel_size;
link_t kip1_list;
char* kip1_patches;
bool svcperm;
bool debugmode;
bool atmosphere;
} launch_ctxt_t;
typedef struct _merge_kip_t
{
void *kip1;
link_t link;
} merge_kip_t;
int hos_launch(ini_sec_t *cfg);
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt);
#endif

221
bootloader/hos/hos_config.c Normal file
View File

@@ -0,0 +1,221 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "hos.h"
#include "hos_config.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../utils/dirlist.h"
#include "../gfx/gfx.h"
extern gfx_con_t gfx_con;
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...)
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->warmboot_size = f_size(&fp);
ctxt->warmboot = malloc(ctxt->warmboot_size);
f_read(&fp, ctxt->warmboot, ctxt->warmboot_size, NULL);
f_close(&fp);
return 1;
}
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->secmon_size = f_size(&fp);
ctxt->secmon = malloc(ctxt->secmon_size);
f_read(&fp, ctxt->secmon, ctxt->secmon_size, NULL);
f_close(&fp);
return 1;
}
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->kernel_size = f_size(&fp);
ctxt->kernel = malloc(ctxt->kernel_size);
f_read(&fp, ctxt->kernel, ctxt->kernel_size, NULL);
f_close(&fp);
return 1;
}
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (!memcmp(value + strlen(value) - 1, "*", 1))
{
char *dir = (char *)malloc(256);
memcpy(dir, value, strlen(value) + 1);
u32 dirlen = 0;
dir[strlen(dir) - 2] = 0;
char *filelist = dirlist(dir, "*.kip*", false);
memcpy(dir + strlen(dir), "/", 2);
dirlen = strlen(dir);
u32 i = 0;
if (filelist)
{
while (true)
{
if (!filelist[i * 256])
break;
memcpy(dir + dirlen, &filelist[i * 256], strlen(&filelist[i * 256]) + 1);
if (f_open(&fp, dir, FA_READ))
{
free(dir);
free(filelist);
return 0;
}
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = malloc(f_size(&fp));
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
f_close(&fp);
list_append(&ctxt->kip1_list, &mkip1->link);
i++;
}
}
free(dir);
free(filelist);
}
else
{
if (f_open(&fp, value, FA_READ))
return 0;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = malloc(f_size(&fp));
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
f_close(&fp);
list_append(&ctxt->kip1_list, &mkip1->link);
}
return 1;
}
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Disabled SVC verification\n");
ctxt->svcperm = true;
}
return 1;
}
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled Debug mode\n");
ctxt->debugmode = true;
}
return 1;
}
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled atmosphere patching\n");
ctxt->atmosphere = true;
}
return 1;
}
static int _config_kip1patch(launch_ctxt_t *ctxt, const char *value)
{
if (value == NULL)
return 0;
int valueLen = strlen(value);
if (!valueLen)
return 0;
if (ctxt->kip1_patches == NULL)
{
ctxt->kip1_patches = malloc(valueLen + 1);
memcpy(ctxt->kip1_patches, value, valueLen);
ctxt->kip1_patches[valueLen] = 0;
}
else
{
char *oldAlloc = ctxt->kip1_patches;
int oldSize = strlen(oldAlloc);
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
free(oldAlloc);
oldAlloc = NULL;
ctxt->kip1_patches[oldSize++] = ',';
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
ctxt->kip1_patches[oldSize + valueLen] = 0;
}
return 1;
}
typedef struct _cfg_handler_t
{
const char *key;
int (*handler)(launch_ctxt_t *ctxt, const char *value);
} cfg_handler_t;
static const cfg_handler_t _config_handlers[] = {
{ "warmboot", _config_warmboot },
{ "secmon", _config_secmon },
{ "kernel", _config_kernel },
{ "kip1", _config_kip1 },
{ "kip1patch", _config_kip1patch },
{ "fullsvcperm", _config_svcperm },
{ "debugmode", _config_debugmode },
{ "atmosphere", _config_atmosphere },
{ NULL, NULL },
};
int _parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
for(u32 i = 0; _config_handlers[i].key; i++)
{
if (!strcmp(_config_handlers[i].key, kv->key))
if (!_config_handlers[i].handler(ctxt, kv->val))
return 0;
}
}
return 1;
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _HOS_CONFIG_H_
#define _HOS_CONFIG_H_
#include "hos.h"
int _parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg);
#endif

143
bootloader/hos/pkg1.c Normal file
View File

@@ -0,0 +1,143 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* 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 "pkg1.h"
#include "../utils/aarch64_util.h"
#include "../sec/se.h"
#define SM_100_ADR 0x4002B020
PATCHSET_DEF(_secmon_1_patchset,
// Patch the relocator to be able to run from SM_100_ADR.
{ 0x1E0, _ADRP(0, 0x7C013000 - _PAGEOFF(SM_100_ADR)) },
//Patch package2 decryption and signature/hash checks.
{ 0x9F0 + 0xADC, _NOP() }, //Header signature.
{ 0x9F0 + 0xB8C, _NOP() }, //Version.
{ 0x9F0 + 0xBB0, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_2_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xAC8 + 0xAAC, _NOP() }, //Header signature.
{ 0xAC8 + 0xB3C, _NOP() }, //Version.
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_3_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xAC8 + 0xA30, _NOP() }, //Header signature.
{ 0xAC8 + 0xAB4, _NOP() }, //package2 structure.
{ 0xAC8 + 0xAC0, _NOP() }, //Version.
{ 0xAC8 + 0xADC, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_4_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0x2300 + 0x5D80, _NOP() }, //package2 structure.
{ 0x2300 + 0x5D8C, _NOP() }, //Version.
{ 0x2300 + 0x5EFC, _NOP() }, //Header signature.
{ 0xAC8 + 0xA2C, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_5_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xDA8 + 0x9D8, _NOP() }, //package2 structure.
{ 0xDA8 + 0x9E4, _NOP() }, //Version.
{ 0xDA8 + 0xC9C, _NOP() }, //Header signature.
{ 0xDA8 + 0x1038, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_6_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
{ 0xDC8 + 0x82C, _NOP() }, //Version.
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_620_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
{ 0xDC8 + 0x610, _NOP() }, //Version.
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
);
/*
* package1.1 header: <wb, ldr, sm>
* package1.1 layout:
* 1.0: {sm, ldr, wb} { 2, 1, 0 }
* 2.0: {wb, ldr, sm} { 0, 1, 2 }
* 3.0: {wb, ldr, sm} { 0, 1, 2 }
* 3.1: {wb, ldr, sm} { 0, 1, 2 }
* 4.0: {ldr, sm, wb} { 1, 2, 0 }
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
*/
static const pkg1_id_t _pkg1_ids[] = {
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset }, //1.0.0 (Patched relocator)
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset }, //6.0.0 - 6.1.0
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset }, //6.2.0
{ NULL } //End.
};
const pkg1_id_t *pkg1_identify(u8 *pkg1)
{
for (u32 i = 0; _pkg1_ids[i].id; i++)
if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12))
return &_pkg1_ids[i];
return NULL;
}
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1)
{
// Decrypt package1.
u8 *pkg11 = pkg1 + id->pkg11_off;
u32 pkg11_size = *(u32 *)pkg11;
se_aes_crypt_ctr(11, pkg11 + 0x20, pkg11_size, pkg11 + 0x20, pkg11_size, pkg11 + 0x10);
}
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1)
{
pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20);
u32 sec_size[3] = { hdr->wb_size, hdr->ldr_size, hdr->sm_size };
//u32 sec_off[3] = { hdr->wb_off, hdr->ldr_off, hdr->sm_off };
u8 *pdata = (u8 *)hdr + sizeof(pk11_hdr_t);
for (u32 i = 0; i < 3; i++)
{
if (id->sec_map[i] == 0 && warmboot_dst)
memcpy(warmboot_dst, pdata, sec_size[id->sec_map[i]]);
else if (id->sec_map[i] == 1 && ldr_dst)
memcpy(ldr_dst, pdata, sec_size[id->sec_map[i]]);
else if (id->sec_map[i] == 2 && secmon_dst)
memcpy(secmon_dst, pdata, sec_size[id->sec_map[i]]);
pdata += sec_size[id->sec_map[i]];
}
}

63
bootloader/hos/pkg1.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _PKG1_H_
#define _PKG1_H_
#include "../utils/types.h"
typedef struct _patch_t
{
u32 off;
u32 val;
} patch_t;
#define PATCHSET_DEF(name, ...) \
patch_t name[] = { \
__VA_ARGS__, \
{ 0xFFFFFFFF, 0xFFFFFFFF } \
}
typedef struct _pkg1_id_t
{
const char *id;
u32 kb;
u32 tsec_off;
u32 pkg11_off;
u32 sec_map[3];
u32 secmon_base;
u32 warmboot_base;
bool set_warmboot;
patch_t *secmon_patchset;
} pkg1_id_t;
typedef struct _pk11_hdr_t
{
u32 magic;
u32 wb_size;
u32 wb_off;
u32 pad;
u32 ldr_size;
u32 ldr_off;
u32 sm_size;
u32 sm_off;
} pk11_hdr_t;
const pkg1_id_t *pkg1_identify(u8 *pkg1);
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1);
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1);
#endif

902
bootloader/hos/pkg2.c Normal file
View File

@@ -0,0 +1,902 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 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 "pkg2.h"
#include "../utils/aarch64_util.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../libs/compr/blz.h"
#include "../gfx/gfx.h"
extern gfx_con_t gfx_con;
/*#include "util.h"
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DEBUG_PRINTING*/
#define DPRINTF(...)
//TODO: Replace hardcoded AArch64 instructions with instruction macros.
//TODO: Reduce hardcoded values without searching kernel for patterns?
// The process ID send/receive kernel patches were taken from Atmosphère's kernel patches.
// They should only be used when running Atmosphère.
#define FREE_CODE_OFF_1ST_100 0x4797C
#define FREE_CODE_OFF_1ST_200 0x6486C
#define FREE_CODE_OFF_1ST_300 0x494A4
#define FREE_CODE_OFF_1ST_302 0x494BC
#define FREE_CODE_OFF_1ST_400 0x52890
#define FREE_CODE_OFF_1ST_500 0x5C020
#define FREE_CODE_OFF_1ST_600 0x5EE00
#define ID_SND_OFF_100 0x23CC0
#define ID_SND_OFF_200 0x3F134
#define ID_SND_OFF_300 0x26080
#define ID_SND_OFF_302 0x26080
#define ID_SND_OFF_400 0x2AF64
#define ID_SND_OFF_500 0x2AD34
#define ID_SND_OFF_600 0x2BB8C
#define ID_RCV_OFF_100 0x219F0
#define ID_RCV_OFF_200 0x3D1A8
#define ID_RCV_OFF_300 0x240F0
#define ID_RCV_OFF_302 0x240F0
#define ID_RCV_OFF_400 0x28F6C
#define ID_RCV_OFF_500 0x28DAC
#define ID_RCV_OFF_600 0x29B6C
static u32 PRC_ID_SND_100[] =
{
0xA9BF2FEA, 0x2A0E03EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9412948, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_100 (FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100) + 4)
static u32 PRC_ID_RCV_100[] =
{
0xA9BF2FEA, 0x2A1C03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,
0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9412968, 0xA8C12FEA
};
static u32 PRC_ID_SND_200[] =
{
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9413148, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_200 (FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200) + 4)
static u32 PRC_ID_RCV_200[] =
{
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9413168, 0xA8C12FEA
};
static u32 PRC_ID_SND_300[] =
{
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_300 (FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300) + 4)
static u32 PRC_ID_RCV_300[] =
{
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415568, 0xA8C12FEA
};
static u32 PRC_ID_SND_302[] =
{
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_302 (FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302) + 4)
static u32 PRC_ID_RCV_302[] =
{
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415568, 0xA8C12FEA
};
static u32 PRC_ID_SND_400[] =
{
0x2A1703EA, 0xD37EF54A, 0xF86A6B8A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9,
0xEB09015F, 0x54000060, 0xF94053EA, 0xF9415948, 0xF94053EA
};
#define FREE_CODE_OFF_2ND_400 (FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400) + 4)
static u32 PRC_ID_RCV_400[] =
{
0xF9403BED, 0x2A0E03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,
0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415B28, 0xD503201F
};
static u32 PRC_ID_SND_500[] =
{
0x2A1703EA, 0xD37EF54A, 0xF86A6B6A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9,
0xEB09015F, 0x54000060, 0xF94043EA, 0xF9415948, 0xF94043EA
};
#define FREE_CODE_OFF_2ND_500 (FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500) + 4)
static u32 PRC_ID_RCV_500[] =
{
0xF9403BED, 0x2A1503EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,
0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415B08, 0xF9406FEA
};
static u32 PRC_ID_SND_600[] =
{
0xA9BF2FEA, 0xF94037EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0,
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
};
#define FREE_CODE_OFF_2ND_600 (FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600) + 4)
static u32 PRC_ID_RCV_600[] =
{
0xA9BF2FEA, 0xF94043EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0,
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
};
// Include kernel patches here, so we can utilize pkg1 id
KERNEL_PATCHSET_DEF(_kernel_1_patchset,
{ SVC_VERIFY_DS, 0x3764C, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x44074, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_100, _B(ID_SND_OFF_100, FREE_CODE_OFF_1ST_100), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_100, sizeof(PRC_ID_SND_100) >> 2, PRC_ID_SND_100}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), ID_SND_OFF_100 + 4), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_100, _B(ID_RCV_OFF_100, FREE_CODE_OFF_2ND_100), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_100, sizeof(PRC_ID_RCV_100) >> 2, PRC_ID_RCV_100}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), ID_RCV_OFF_100 + 4), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_2_patchset,
{ SVC_VERIFY_DS, 0x54834, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x6086C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_200, _B(ID_SND_OFF_200, FREE_CODE_OFF_1ST_200), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_200, sizeof(PRC_ID_SND_200) >> 2, PRC_ID_SND_200}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), ID_SND_OFF_200 + 4), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_200, _B(ID_RCV_OFF_200, FREE_CODE_OFF_2ND_200), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_200, sizeof(PRC_ID_RCV_200) >> 2, PRC_ID_RCV_200}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), ID_RCV_OFF_200 + 4), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_3_patchset,
{ SVC_VERIFY_DS, 0x3BD24, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x483FC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_300, _B(ID_SND_OFF_300, FREE_CODE_OFF_1ST_300), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_300, sizeof(PRC_ID_SND_300) >> 2, PRC_ID_SND_300}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), ID_SND_OFF_300 + 4), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_300, _B(ID_RCV_OFF_300, FREE_CODE_OFF_2ND_300), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_300, sizeof(PRC_ID_RCV_300) >> 2, PRC_ID_RCV_300}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_300 + 4), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_302_patchset,
{ SVC_VERIFY_DS, 0x3BD24, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x48414, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_302, _B(ID_SND_OFF_302, FREE_CODE_OFF_1ST_302), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_302, sizeof(PRC_ID_SND_302) >> 2, PRC_ID_SND_302}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), ID_SND_OFF_302 + 4), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_302, _B(ID_RCV_OFF_302, FREE_CODE_OFF_2ND_302), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_302, sizeof(PRC_ID_RCV_302) >> 2, PRC_ID_RCV_302}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), ID_RCV_OFF_302 + 4), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_4_patchset,
{ SVC_VERIFY_DS, 0x41EB4, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x4EBFC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_400, _B(ID_SND_OFF_400, FREE_CODE_OFF_1ST_400), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_400, sizeof(PRC_ID_SND_400) >> 2, PRC_ID_SND_400}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), // Branch back and skip 2 instructions.
_B(FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), ID_SND_OFF_400 + 8), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_400, _B(ID_RCV_OFF_400, FREE_CODE_OFF_2ND_400), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_400, sizeof(PRC_ID_RCV_400) >> 2, PRC_ID_RCV_400}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), ID_RCV_OFF_400 + 4), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_5_patchset,
{ SVC_VERIFY_DS, 0x45E6C, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x5513C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_500, _B(ID_SND_OFF_500, FREE_CODE_OFF_1ST_500), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_500, sizeof(PRC_ID_SND_500) >> 2, PRC_ID_SND_500}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), // Branch back and skip 2 instructions.
_B(FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), ID_SND_OFF_500 + 8), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_500, _B(ID_RCV_OFF_500, FREE_CODE_OFF_2ND_500), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_500, sizeof(PRC_ID_RCV_500) >> 2, PRC_ID_RCV_500}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), // Branch back and skip 2 instructions.
_B(FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), ID_RCV_OFF_500 + 8), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_6_patchset,
{ SVC_VERIFY_DS, 0x47EA0, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x57548, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_600, _B(ID_SND_OFF_600, FREE_CODE_OFF_1ST_600), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_600, sizeof(PRC_ID_SND_600) >> 2, PRC_ID_SND_600}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), ID_SND_OFF_600 + 0x10), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_600, _B(ID_RCV_OFF_600, FREE_CODE_OFF_2ND_600), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_600, sizeof(PRC_ID_RCV_600) >> 2, PRC_ID_RCV_600}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), ID_RCV_OFF_600 + 0x10), NULL}
);
static const pkg2_kernel_id_t _pkg2_kernel_ids[] =
{
{ 0x427f2647, _kernel_1_patchset }, //1.0.0
{ 0xae19cf1b, _kernel_2_patchset }, //2.0.0 - 2.3.0
{ 0x73c9e274, _kernel_3_patchset }, //3.0.0 - 3.0.1
{ 0xe0e8cdc4, _kernel_302_patchset }, //3.0.2
{ 0x485d0157, _kernel_4_patchset }, //4.0.0 - 4.1.0
{ 0xf3c363f2, _kernel_5_patchset }, //5.0.0 - 5.1.0
{ 0x64ce1a44, _kernel_6_patchset }, //6.0.0 - 6.2.0
{ 0, 0 } //End.
};
enum kip_offset_section
{
KIP_TEXT = 0,
KIP_RODATA = 1,
KIP_DATA = 2,
KIP_BSS = 3,
KIP_UNKSEC1 = 4,
KIP_UNKSEC2 = 5
};
#define KIP_PATCH_SECTION_SHIFT (29)
#define KIP_PATCH_SECTION_MASK (7 << KIP_PATCH_SECTION_SHIFT)
#define KIP_PATCH_OFFSET_MASK (~KIP_PATCH_SECTION_MASK)
#define GET_KIP_PATCH_SECTION(x) ((x >> KIP_PATCH_SECTION_SHIFT) & 7)
#define GET_KIP_PATCH_OFFSET(x) (x & KIP_PATCH_OFFSET_MASK)
#define KPS(x) ((u32)(x) << KIP_PATCH_SECTION_SHIFT)
static kip1_patch_t _fs_nosigchk_100[] =
{
{ KPS(KIP_TEXT) | 0x194A0, 4, "\xBA\x09\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x3A79C, 4, "\xE0\x06\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_100[] =
{
{ "nosigchk", _fs_nosigchk_100 },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_200[] =
{
{ KPS(KIP_TEXT) | 0x15DF4, 4, "\xBC\x0A\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x3F720, 4, "\x00\x06\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_200[] =
{
{ "nosigchk", _fs_nosigchk_200 },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_210[] =
{
{ KPS(KIP_TEXT) | 0x15F64, 4, "\xDF\x0A\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x3FAF8, 4, "\x00\x06\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_210[] =
{
{ "nosigchk", _fs_nosigchk_210 },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_300[] =
{
{ KPS(KIP_TEXT) | 0x18E24, 4, "\x52\x0C\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x49EC8, 4, "\x40\x04\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_300[] =
{
{ "nosigchk", _fs_nosigchk_300 },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_30x[] =
{
{ KPS(KIP_TEXT) | 0x18E90, 4, "\x52\x0C\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x49F34, 4, "\xE0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_30x[] =
{
{ "nosigchk", _fs_nosigchk_30x },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_4xx[] =
{
{ KPS(KIP_TEXT) | 0x1C4FC, 4, "\x3C\x2F\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x57934, 4, "\xE0\x02\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_40x[] =
{
{ KPS(KIP_TEXT) | 0xA3458, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" },
{ KPS(KIP_TEXT) | 0xAAB44, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_40x[] =
{
{ "nosigchk", _fs_nosigchk_4xx },
{ "nogc", _fs_nogc_40x },
{ NULL, NULL }
};
static kip1_patch_t _fs_nogc_410[] =
{
{ KPS(KIP_TEXT) | 0xA34BC, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" },
{ KPS(KIP_TEXT) | 0xAABA8, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_410[] =
{
{ "nosigchk", _fs_nosigchk_4xx },
{ "nogc", _fs_nogc_410 },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_50x[] =
{
{ KPS(KIP_TEXT) | 0x22DDC, 4, "\x7D\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x7D490, 4, "\x40\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_50x[] =
{
{ KPS(KIP_TEXT) | 0xCF3C4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ KPS(KIP_TEXT) | 0xD73A0, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_50x[] =
{
{ "nosigchk", _fs_nosigchk_50x },
{ "nogc", _fs_nogc_50x },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_510[] =
{
{ KPS(KIP_TEXT) | 0x22E0C, 4, "\x85\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x7D860, 4, "\x40\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_510[] =
{
{ KPS(KIP_TEXT) | 0xCF794, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ KPS(KIP_TEXT) | 0xD7770, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_510[] =
{
{ "nosigchk", _fs_nosigchk_510 },
{ "nogc", _fs_nogc_510 },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_600[] =
{
{ KPS(KIP_TEXT) | 0x712A8, 4, "\x8E\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0xEB08C, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_600_exfat[] =
{
{ KPS(KIP_TEXT) | 0x7C9A8, 4, "\x8E\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0xF678C, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_600[] =
{
{ KPS(KIP_TEXT) | 0x12CC20, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x1538F4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_600_exfat[] =
{
{ KPS(KIP_TEXT) | 0x138320, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x15EFF4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_600[] =
{
{ "nosigchk", _fs_nosigchk_600 },
{ "nogc", _fs_nogc_600 },
{ NULL, NULL }
};
static kip1_patchset_t _fs_patches_600_exfat[] =
{
{ "nosigchk", _fs_nosigchk_600_exfat },
{ "nogc", _fs_nogc_600_exfat },
{ NULL, NULL }
};
static kip1_id_t _kip_ids[] =
{
{ "FS", "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe\x68\xdc\xb2\x0b\x41\x09\x5b\xb4", _fs_patches_100 }, // FS 1.0.0
{ "FS", "\xfc\x3e\x80\x99\x1d\xca\x17\x96\x4a\x12\x1f\x04\xb6\x1b\x17\x5e", _fs_patches_100 }, // FS 1.0.0 exfat
{ "FS", "\xcd\x7b\xbe\x18\xd6\x13\x0b\x28\xf6\x2f\x19\xfa\x79\x45\x53\x5b", _fs_patches_200 }, // FS 2.0.0
{ "FS", "\xe7\x66\x92\xdf\xaa\x04\x20\xe9\xfd\xd6\x8e\x43\x63\x16\x18\x18", _fs_patches_200 }, // FS 2.0.0 exfat
{ "FS", "\x0d\x70\x05\x62\x7b\x07\x76\x7c\x0b\x96\x3f\x9a\xff\xdd\xe5\x66", _fs_patches_210 }, // FS 2.1.0
{ "FS", "\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8\x30\x51\xc6\x64\xe6\x45\x2d\x32", _fs_patches_210 }, // FS 2.1.0 exfat
{ "FS", "\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b\x23\xda\xb5\xb4\xdb\xba\xef\xe7", _fs_patches_300 }, // FS 3.0.0
{ "FS", "\x98\x1c\x57\xe7\xf0\x2f\x70\xf7\xbc\xde\x75\x31\x81\xd9\x01\xa6", _fs_patches_300 }, // FS 3.0.0 exfat
{ "FS", "\x57\x39\x7c\x06\x3f\x10\xb6\x31\x3f\x4d\x83\x76\x53\xcc\xc3\x71", _fs_patches_30x }, // FS 3.0.1
{ "FS", "\x07\x30\x99\xd7\xc6\xad\x7d\x89\x83\xbc\x7a\xdd\x93\x2b\xe3\xd1", _fs_patches_30x }, // FS 3.0.1 exfat
{ "FS", "\x06\xe9\x07\x19\x59\x5a\x01\x0c\x62\x46\xff\x70\x94\x6f\x10\xfb", _fs_patches_40x }, // FS 4.0.1
{ "FS", "\x54\x9b\x0f\x8d\x6f\x72\xc4\xe9\xf3\xfd\x1f\x19\xea\xce\x4a\x5a", _fs_patches_40x }, // FS 4.0.1 exfat
{ "FS", "\x80\x96\xaf\x7c\x6a\x35\xaa\x82\x71\xf3\x91\x69\x95\x41\x3b\x0b", _fs_patches_410 }, // FS 4.1.0
{ "FS", "\x02\xd5\xab\xaa\xfd\x20\xc8\xb0\x63\x3a\xa0\xdb\xae\xe0\x37\x7e", _fs_patches_410 }, // FS 4.1.0 exfat
{ "FS", "\xa6\xf2\x7a\xd9\xac\x7c\x73\xad\x41\x9b\x63\xb2\x3e\x78\x5a\x0c", _fs_patches_50x }, // FS 5.0.0
{ "FS", "\xce\x3e\xcb\xa2\xf2\xf0\x62\xf5\x75\xf8\xf3\x60\x84\x2b\x32\xb4", _fs_patches_50x }, // FS 5.0.0 exfat
{ "FS", "\x76\xf8\x74\x02\xc9\x38\x7c\x0f\x0a\x2f\xab\x1b\x45\xce\xbb\x93", _fs_patches_510 }, // FS 5.1.0
{ "FS", "\x10\xb2\xd8\x16\x05\x48\x85\x99\xdf\x22\x42\xcb\x6b\xac\x2d\xf1", _fs_patches_510 }, // FS 5.1.0 exfat
{ "FS", "\x1b\x82\xcb\x22\x18\x67\xcb\x52\xc4\x4a\x86\x9e\xa9\x1a\x1a\xdd", _fs_patches_600 }, // FS 6.0.0-4.0
{ "FS", "\x96\x6a\xdd\x3d\x20\xb6\x27\x13\x2c\x5a\x8d\xa4\x9a\xc9\xd8\xdd", _fs_patches_600_exfat }, // FS 6.0.0-4.0 exfat
{ "FS", "\x3a\x57\x4d\x43\x61\x86\x19\x1d\x17\x88\xeb\x2c\x0f\x07\x6b\x11", _fs_patches_600 }, // FS 6.0.0-5.0
{ "FS", "\x33\x05\x53\xf6\xb5\xfb\x55\xc4\xc2\xd7\xb7\x36\x24\x02\x76\xb3", _fs_patches_600_exfat } // FS 6.0.0-5.0 exfat
};
const pkg2_kernel_id_t *pkg2_identify(u32 id)
{
for (u32 i = 0; _pkg2_kernel_ids[i].crc32c_id; i++)
if (id == _pkg2_kernel_ids[i].crc32c_id)
return &_pkg2_kernel_ids[i];
return NULL;
}
static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
{
u32 size = sizeof(pkg2_kip1_t);
for (u32 j = 0; j < KIP1_NUM_SECTIONS; j++)
size += kip1->sections[j].size_comp;
return size;
}
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2)
{
u8 *ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL];
pkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr;
ptr += sizeof(pkg2_ini1_t);
for (u32 i = 0; i < ini1->num_procs; i++)
{
pkg2_kip1_t *kip1 = (pkg2_kip1_t *)ptr;
pkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t));
ki->kip1 = kip1;
ki->size = _pkg2_calc_kip1_size(kip1);
list_append(info, &ki->link);
ptr += ki->size;
DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size);
}
}
int pkg2_has_kip(link_t *info, u64 tid)
{
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
if(ki->kip1->tid == tid)
return 1;
return 0;
}
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1)
{
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
if (ki->kip1->tid == tid)
{
ki->kip1 = kip1;
ki->size = _pkg2_calc_kip1_size(kip1);
DPRINTF("replaced kip (new size %08X)\n", ki->size);
return;
}
}
void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1)
{
pkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t));
ki->kip1 = kip1;
ki->size = _pkg2_calc_kip1_size(kip1);
DPRINTF("added kip (size %08X)\n", ki->size);
list_append(info, &ki->link);
}
void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1)
{
if (pkg2_has_kip(info, kip1->tid))
pkg2_replace_kip(info, kip1->tid, kip1);
else
pkg2_add_kip(info, kip1);
}
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
{
u32 compClearMask = ~sectsToDecomp;
if ((ki->kip1->flags & compClearMask) == ki->kip1->flags)
return 0; // Already decompressed, nothing to do.
pkg2_kip1_t hdr;
memcpy(&hdr, ki->kip1, sizeof(hdr));
unsigned int newKipSize = sizeof(hdr);
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
{
u32 sectCompBit = 1u << sectIdx;
// For compressed, cant get actual decompressed size without doing it, so use safe "output size".
if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit))
newKipSize += hdr.sections[sectIdx].size_decomp;
else
newKipSize += hdr.sections[sectIdx].size_comp;
}
pkg2_kip1_t* newKip = malloc(newKipSize);
unsigned char* dstDataPtr = newKip->data;
const unsigned char* srcDataPtr = ki->kip1->data;
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
{
u32 sectCompBit = 1u << sectIdx;
// Easy copy path for uncompressed or ones we dont want to uncompress.
if (sectIdx >= 3 || !(sectsToDecomp & sectCompBit) || !(hdr.flags & sectCompBit))
{
unsigned int dataSize = hdr.sections[sectIdx].size_comp;
if (dataSize == 0)
continue;
memcpy(dstDataPtr, srcDataPtr, dataSize);
srcDataPtr += dataSize;
dstDataPtr += dataSize;
continue;
}
unsigned int compSize = hdr.sections[sectIdx].size_comp;
unsigned int outputSize = hdr.sections[sectIdx].size_decomp;
gfx_printf(&gfx_con, "Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize);
if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0)
{
gfx_printf(&gfx_con, "%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC);
free(newKip);
return 1;
}
else
{
DPRINTF("Done! Decompressed size is %d!\n", outputSize);
}
hdr.sections[sectIdx].size_comp = outputSize;
srcDataPtr += compSize;
dstDataPtr += outputSize;
}
hdr.flags &= compClearMask;
memcpy(newKip, &hdr, sizeof(hdr));
newKipSize = dstDataPtr-(unsigned char*)(newKip);
free(ki->kip1);
ki->kip1 = newKip;
ki->size = newKipSize;
return 0;
}
const char* pkg2_patch_kips(link_t *info, char* patchNames)
{
if (patchNames == NULL || patchNames[0] == 0)
return NULL;
static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32)*8;
char* patches[MAX_NUM_PATCHES_REQUESTED];
u32 numPatches=1;
patches[0] = patchNames;
{
for (char* p = patchNames; *p != 0; p++)
{
if (*p == ',')
{
*p = 0;
patches[numPatches++] = p+1;
if (numPatches >= MAX_NUM_PATCHES_REQUESTED)
return "too_many_patches";
}
else if (*p >= 'A' && *p <= 'Z')
*p += 0x20;
}
}
u32 patchesApplied = 0; // Bitset over patches.
for (u32 i=0; i<numPatches; i++)
{
// Eliminate leading spaces.
for (const char* p=patches[i]; *p!=0; p++)
{
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
patches[i]++;
else
break;
}
int valueLen = strlen(patches[i]);
if (valueLen == 0)
continue;
// Eliminate trailing spaces.
for (int chIdx=valueLen-1; chIdx>=0; chIdx--)
{
const char* p = patches[i] + chIdx;
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
valueLen = chIdx;
else
break;
}
patches[i][valueLen] = 0;
DPRINTF("Requested patch: '%s'\n", patches[i]);
}
u32 shaBuf[32/sizeof(u32)];
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
{
shaBuf[0] = 0; // sha256 for this kip not yet calculated.
for (u32 currKipIdx=0; currKipIdx<(sizeof(_kip_ids)/sizeof(_kip_ids[0])); currKipIdx++)
{
if (strncmp((const char*)ki->kip1->name, _kip_ids[currKipIdx].name, sizeof(ki->kip1->name)) != 0)
continue;
u32 bitsAffected = 0;
kip1_patchset_t* currPatchset = _kip_ids[currKipIdx].patchset;
while (currPatchset != NULL && currPatchset->name != NULL)
{
for (u32 i=0; i<numPatches; i++)
{
if (strcmp(currPatchset->name, patches[i]) != 0)
{
bitsAffected = i + 1;
break;
}
}
currPatchset++;
}
// Dont bother even hashing this KIP if we dont have any patches enabled for it.
if (bitsAffected == 0)
continue;
if (shaBuf[0] == 0)
{
if (!se_calc_sha256(shaBuf, ki->kip1, ki->size))
memset(shaBuf, 0, sizeof(shaBuf));
}
if (memcmp(shaBuf, _kip_ids[currKipIdx].hash, sizeof(_kip_ids[0].hash)) != 0)
continue;
// Find out which sections are affected by the enabled patches, to know which to decompress.
bitsAffected = 0;
currPatchset = _kip_ids[currKipIdx].patchset;
while (currPatchset != NULL && currPatchset->name != NULL)
{
if (currPatchset->patches != NULL)
{
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
{
if (strcmp(currPatchset->name, patches[currEnabIdx]))
continue;
for (const kip1_patch_t* currPatch=currPatchset->patches; currPatch != NULL && currPatch->length != 0; currPatch++)
bitsAffected |= 1u << GET_KIP_PATCH_SECTION(currPatch->offset);
}
}
currPatchset++;
}
// Got patches to apply to this kip, have to decompress it.
#ifdef DEBUG_PRINTING
u32 preDecompTime = get_tmr_us();
#endif
if (pkg2_decompress_kip(ki, bitsAffected))
return (const char*)ki->kip1->name; // Failed to decompress.
#ifdef DEBUG_PRINTING
u32 postDecompTime = get_tmr_us();
if (!se_calc_sha256(shaBuf, ki->kip1, ki->size))
memset(shaBuf, 0, sizeof(shaBuf));
DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime)/1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0]));
#endif
currPatchset = _kip_ids[currKipIdx].patchset;
while (currPatchset != NULL && currPatchset->name != NULL)
{
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
{
if (strcmp(currPatchset->name, patches[currEnabIdx]))
continue;
u32 appliedMask = 1u << currEnabIdx;
if (currPatchset->patches == NULL)
{
gfx_printf(&gfx_con, "Patch '%s' not necessary for %s KIP1\n", currPatchset->name, (const char*)ki->kip1->name);
patchesApplied |= appliedMask;
break;
}
unsigned char* kipSectData = ki->kip1->data;
for (u32 currSectIdx=0; currSectIdx<KIP1_NUM_SECTIONS; currSectIdx++)
{
if (bitsAffected & (1u << currSectIdx))
{
gfx_printf(&gfx_con, "Applying patch '%s' on %s KIP1 sect %d\n", currPatchset->name, (const char*)ki->kip1->name, currSectIdx);
for (const kip1_patch_t* currPatch=currPatchset->patches;currPatch != NULL && currPatch->length != 0; currPatch++)
{
if (GET_KIP_PATCH_SECTION(currPatch->offset) != currSectIdx)
continue;
u32 currOffset = GET_KIP_PATCH_OFFSET(currPatch->offset);
if (memcmp(&kipSectData[currOffset], currPatch->srcData, currPatch->length) != 0)
{
gfx_printf(&gfx_con, "%kDATA MISMATCH FOR PATCH AT OFFSET 0x%x!!!%k\n", 0xFFFF0000, currOffset, 0xFFCCCCCC);
return currPatchset->name; // MUST stop here as kip is likely corrupt.
}
else
{
DPRINTF("Patching %d bytes at offset 0x%x\n", currPatch->length, currOffset);
memcpy(&kipSectData[currOffset], currPatch->dstData, currPatch->length);
}
}
}
kipSectData += ki->kip1->sections[currSectIdx].size_comp;
}
patchesApplied |= appliedMask;
break;
}
currPatchset++;
}
}
}
for (u32 i=0; i<numPatches; i++)
{
if ((patchesApplied & (1u << i)) == 0)
return patches[i];
}
return NULL;
}
pkg2_hdr_t *pkg2_decrypt(void *data)
{
u8 *pdata = (u8 *)data;
// Skip signature.
pdata += 0x100;
pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdata;
// Skip header.
pdata += sizeof(pkg2_hdr_t);
// Decrypt header.
se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
//gfx_hexdump(&gfx_con, (u32)hdr, hdr, 0x100);
if (hdr->magic != PKG2_MAGIC)
return NULL;
for (u32 i = 0; i < 4; i++)
{
DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]);
if (!hdr->sec_size[i])
continue;
se_aes_crypt_ctr(8, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]);
//gfx_hexdump(&gfx_con, (u32)pdata, pdata, 0x100);
pdata += hdr->sec_size[i];
}
return hdr;
}
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info)
{
u8 *pdst = (u8 *)dst;
// Signature.
memset(pdst, 0, 0x100);
pdst += 0x100;
// Header.
pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdst;
memset(hdr, 0, sizeof(pkg2_hdr_t));
pdst += sizeof(pkg2_hdr_t);
hdr->magic = PKG2_MAGIC;
hdr->base = 0x10000000;
DPRINTF("kernel @ %08X (%08X)\n", (u32)kernel, kernel_size);
// Kernel.
memcpy(pdst, kernel, kernel_size);
hdr->sec_size[PKG2_SEC_KERNEL] = kernel_size;
hdr->sec_off[PKG2_SEC_KERNEL] = 0x10000000;
se_aes_crypt_ctr(8, pdst, kernel_size, pdst, kernel_size, &hdr->sec_ctr[PKG2_SEC_KERNEL * 0x10]);
pdst += kernel_size;
DPRINTF("kernel encrypted\n");
// INI1.
u32 ini1_size = sizeof(pkg2_ini1_t);
pkg2_ini1_t *ini1 = (pkg2_ini1_t *)pdst;
memset(ini1, 0, sizeof(pkg2_ini1_t));
ini1->magic = INI1_MAGIC;
pdst += sizeof(pkg2_ini1_t);
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, kips_info, link)
{
DPRINTF("adding kip1 '%s' @ %08X (%08X)\n", ki->kip1->name, (u32)ki->kip1, ki->size);
memcpy(pdst, ki->kip1, ki->size);
pdst += ki->size;
ini1_size += ki->size;
ini1->num_procs++;
}
ini1->size = ini1_size;
hdr->sec_size[PKG2_SEC_INI1] = ini1_size;
hdr->sec_off[PKG2_SEC_INI1] = 0x14080000;
se_aes_crypt_ctr(8, ini1, ini1_size, ini1, ini1_size, &hdr->sec_ctr[PKG2_SEC_INI1 * 0x10]);
DPRINTF("INI1 encrypted\n");
//Encrypt header.
*(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size;
se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
memset(hdr->ctr, 0 , 0x10);
*(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size;
}

148
bootloader/hos/pkg2.h Normal file
View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _PKG2_H_
#define _PKG2_H_
#include "../utils/types.h"
#include "../utils/list.h"
#define PKG2_MAGIC 0x31324B50
#define PKG2_SEC_BASE 0x80000000
#define PKG2_SEC_KERNEL 0
#define PKG2_SEC_INI1 1
#define INI1_MAGIC 0x31494E49
typedef struct _kernel_patch_t
{
u32 id;
u32 off;
u32 val;
u32 *ptr;
} kernel_patch_t;
#define KERNEL_PATCHSET_DEF(name, ...) \
kernel_patch_t name[] = { \
__VA_ARGS__, \
{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, (u32 *)0xFFFFFFFF} \
}
enum
{
// Generic instruction patches
SVC_VERIFY_DS = 0x10, // 0x0-0xF are RESERVED.
DEBUG_MODE_EN,
ATM_GEN_PATCH,
// >4 bytes patches. Value is a pointer of a u32 array.
ATM_ARR_PATCH,
};
typedef struct _pkg2_hdr_t
{
u8 ctr[0x10];
u8 sec_ctr[0x40];
u32 magic;
u32 base;
u32 pad0;
u16 version;
u16 pad1;
u32 sec_size[4];
u32 sec_off[4];
u8 sec_sha256[0x80];
u8 data[];
} pkg2_hdr_t;
typedef struct _pkg2_ini1_t
{
u32 magic;
u32 size;
u32 num_procs;
u32 pad;
} pkg2_ini1_t;
typedef struct _pkg2_kip1_sec_t
{
u32 offset;
u32 size_decomp;
u32 size_comp;
u32 attrib;
} pkg2_kip1_sec_t;
#define KIP1_NUM_SECTIONS 6
typedef struct _pkg2_kip1_t
{
u32 magic;
u8 name[12];
u64 tid;
u32 proc_cat;
u8 main_thrd_prio;
u8 def_cpu_core;
u8 res;
u8 flags;
pkg2_kip1_sec_t sections[KIP1_NUM_SECTIONS];
u32 caps[0x20];
u8 data[];
} pkg2_kip1_t;
typedef struct _pkg2_kip1_info_t
{
pkg2_kip1_t *kip1;
u32 size;
link_t link;
} pkg2_kip1_info_t;
typedef struct _pkg2_kernel_id_t
{
u32 crc32c_id;
kernel_patch_t *kernel_patchset;
} pkg2_kernel_id_t;
typedef struct _kip1_patch_t
{
u32 offset; //section+offset of patch to apply
u32 length; //in bytes, 0 means last patch
const char* srcData; //that must match
const char* dstData; //that it gets replaced by
} kip1_patch_t;
typedef struct _kip1_patchset_t
{
const char* name; //NULL means end
kip1_patch_t* patches; //NULL means not necessary
} kip1_patchset_t;
typedef struct _kip1_id_t
{
const char* name;
u8 hash[16];
kip1_patchset_t* patchset;
} kip1_id_t;
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2);
int pkg2_has_kip(link_t *info, u64 tid);
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);
void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1);
void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);
const char* pkg2_patch_kips(link_t *info, char* patchNames);
const pkg2_kernel_id_t *pkg2_identify(u32 id);
pkg2_hdr_t *pkg2_decrypt(void *data);
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info);
#endif

View File

@@ -0,0 +1,66 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "hos.h"
#include "../utils/types.h"
// Exosphère mailbox defines.
#define EXO_MAGIC_ADDR 0x40002E40
#define EXO_MAGIC_VAL 0x31434258
#define EXO_FWNO_ADDR 0x40002E44
#define EXO_FLAGS_ADDR 0x40002E48
#define EXO_FLAG_620_KGN (1 << 0)
#define EXO_FLAG_DBG_PRIV (1 << 1)
#define EXO_FLAG_DBG_USER (1 << 2)
void config_exosphere(const char *id, u32 kb, bool debug)
{
u32 exoFwNo = 0;
u32 exoFlags = 0;
vu32 *mb_exo_magic = (vu32 *)EXO_MAGIC_ADDR;
vu32 *mb_exo_fw_no = (vu32 *)EXO_FWNO_ADDR;
vu32 *mb_exo_flags = (vu32 *)EXO_FLAGS_ADDR;
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
if (!strcmp(id, "20161121183008"))
exoFwNo = 1;
else
exoFwNo = 2;
break;
case KB_FIRMWARE_VERSION_300:
exoFwNo = 3;
break;
default:
exoFwNo = kb + 1;
break;
}
if (kb >= KB_FIRMWARE_VERSION_620)
exoFlags |= EXO_FLAG_620_KGN;
if (debug)
exoFlags |= EXO_FLAG_DBG_PRIV | EXO_FLAG_DBG_USER;
// Set mailbox values.
*mb_exo_magic = EXO_MAGIC_VAL;
*mb_exo_fw_no = exoFwNo;
*mb_exo_flags = exoFlags;
}

View File

@@ -0,0 +1,24 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _SECMON_EXO_H_
#define _SECMON_EXO_H_
#include "../utils/types.h"
void config_exosphere(const char *id, u32 kb, bool debug);
#endif

175
bootloader/ianos/ianos.c Normal file
View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 2018 M4xw
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "ianos.h"
#include "../utils/types.h"
#include "../libs/elfload/elfload.h"
#include "../../common/common_module.h"
#include "../mem/heap.h"
#include "../gfx/gfx.h"
#define IRAM_LIB_ADDR 0x4002B000
#define DRAM_LIB_ADDR 0xE0000000
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern heap_t _heap;
extern void *sd_file_read(char *path);
extern bool sd_mount();
extern void sd_unmount();
void *elfBuf = NULL;
void *fileBuf = NULL;
static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig)
{
bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t));
bdkParameters->gfxCon = &gfx_con;
bdkParameters->gfxCtx = &gfx_ctxt;
bdkParameters->memcpy = (memcpy_t)&memcpy;
bdkParameters->memset = (memset_t)&memset;
bdkParameters->sharedHeap = &_heap;
entrypoint(moduleConfig, bdkParameters);
}
static void *_ianos_alloc_cb(el_ctx *ctx, Elf_Addr phys, Elf_Addr virt, Elf_Addr size)
{
(void)ctx;
(void)phys;
(void)size;
return (void *)virt;
}
static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t offset)
{
(void)ctx;
memcpy(dest, fileBuf + offset, numberBytes);
return true;
}
void ianos_print_error(int errorno)
{
switch (errorno)
{
case 1:
gfx_printf(&gfx_con, "Can't find library!\n");
break;
case 2:
gfx_printf(&gfx_con, "Cant init ELF context!\n");
break;
case 3:
gfx_printf(&gfx_con, "Cant alloc memory!\n");
break;
case 4:
gfx_printf(&gfx_con, "Error loading ELF!\n");
break;
case 5:
gfx_printf(&gfx_con, "Error relcating ELF!\n");
break;
}
}
//TODO: Support shared libraries.
int ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
{
int res = 0;
if (sdmount)
{
if (!sd_mount())
{
res = 0xFFFF;
goto elfLoadFinalOut;
}
}
fileBuf = sd_file_read(path);
if (sdmount)
sd_unmount();
if (!fileBuf)
{
res = 1;
goto elfLoadFinalOut;
}
el_ctx ctx;
ctx.pread = _ianos_read_cb;
if (el_init(&ctx))
{
res = 2;
goto elfLoadFinalOut;
}
// Set our relocated library's buffer.
switch (type & 0xFFFF)
{
case EXEC_ELF:
case AR64_ELF:
elfBuf = (void *)DRAM_LIB_ADDR;
sd_unmount();
break;
default:
elfBuf = memalign(ctx.align, ctx.memsz);
}
if (!elfBuf)
{
res = 3;
goto elfLoadFinalOut;
}
// Load and relocate library.
ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf;
if (el_load(&ctx, _ianos_alloc_cb))
{
res = 4;
goto elfFreeOut;
}
if (el_relocate(&ctx))
{
res = 5;
goto elfFreeOut;
}
// Launch.
uintptr_t epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr;
_ianos_call_ep(ep, moduleConfig);
elfFreeOut:
if ((u32)elfBuf >= 0x90000000 && (u32)elfBuf <= DRAM_LIB_ADDR)
free(elfBuf);
free(fileBuf);
elfBuf = NULL;
fileBuf = NULL;
elfLoadFinalOut:
return res;
}

34
bootloader/ianos/ianos.h Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018 M4xw
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef IANOS_H
#define IANOS_H
#include "../utils/types.h"
typedef enum
{
DRAM_LIB = 0, // DRAM library.
EXEC_ELF = 1, // Executable elf that does not return.
DR64_LIB = 2, // AARCH64 DRAM library.
AR64_ELF = 3, // Executable elf that does not return.
KEEP_IN_RAM = (1 << 31) // Shared library mask.
} elfType_t;
int ianos_loader(bool sdmount, char *path, elfType_t type, void* config);
#endif

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2018 rajkosto
* Copyright (c) 2018 SciresM
*
* 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 <stdlib.h>
#include <string.h>
#include "blz.h"
const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter)
{
if (compDataLen < sizeof(blz_footer))
return NULL;
const blz_footer *srcFooter = (const blz_footer*)&compData[compDataLen - sizeof(blz_footer)];
if (outFooter != NULL)
memcpy(outFooter, srcFooter, sizeof(blz_footer)); // Must be a memcpy because no umaligned accesses on ARMv4.
return srcFooter;
}
// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM!
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer)
{
u32 addl_size = footer->addl_size;
u32 header_size = footer->header_size;
u32 cmp_and_hdr_size = footer->cmp_and_hdr_size;
unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size;
u32 cmp_ofs = cmp_and_hdr_size - header_size;
u32 out_ofs = cmp_and_hdr_size + addl_size;
while (out_ofs)
{
unsigned char control = cmp_start[--cmp_ofs];
for (unsigned int i=0; i<8; i++)
{
if (control & 0x80)
{
if (cmp_ofs < 2)
return 0; // Out of bounds.
cmp_ofs -= 2;
u16 seg_val = ((unsigned int)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs];
u32 seg_size = ((seg_val >> 12) & 0xF) + 3;
u32 seg_ofs = (seg_val & 0x0FFF) + 3;
if (out_ofs < seg_size) // Kernel restricts segment copy to stay in bounds.
seg_size = out_ofs;
out_ofs -= seg_size;
for (unsigned int j = 0; j < seg_size; j++)
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
}
else
{
// Copy directly.
if (cmp_ofs < 1)
return 0; //out of bounds
cmp_start[--out_ofs] = cmp_start[--cmp_ofs];
}
control <<= 1;
if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done.
return 1;
}
}
return 1;
}
int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize)
{
blz_footer footer;
const blz_footer *compFooterPtr = blz_get_footer(compData, compDataLen, &footer);
if (compFooterPtr == NULL)
return 0;
// Decompression must be done in-place, so need to copy the relevant compressed data first.
unsigned int numCompBytes = (const unsigned char*)(compFooterPtr)-compData;
memcpy(dstData, compData, numCompBytes);
memset(&dstData[numCompBytes], 0, dstSize - numCompBytes);
return blz_uncompress_inplace(dstData, compDataLen, &footer);
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2018 rajkosto
*
* 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/>.
*/
#ifndef _BLZ_H_
#define _BLZ_H_
#include "../../utils/types.h"
typedef struct _blz_footer
{
u32 cmp_and_hdr_size;
u32 header_size;
u32 addl_size;
} blz_footer;
// Returns pointer to footer in compData if present, additionally copies it to outFooter if not NULL.
const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter);
// Returns 0 on failure.
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer);
// Returns 0 on failure.
int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize);
#endif

0
ipl/lz.c → bootloader/libs/compr/lz.c Executable file → Normal file
View File

0
ipl/lz.h → bootloader/libs/compr/lz.h Executable file → Normal file
View File

View File

@@ -0,0 +1,589 @@
/* $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $ */
/*
* Copyright (c) 1995, 1996 Erik Theisen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* imported sys/exec_elf.h from OpenBSD */
#ifndef ELF_H
#define ELF_H
#include <stdint.h>
typedef uint8_t Elf_Byte;
typedef uint32_t Elf32_Addr; /* Unsigned program address */
typedef uint32_t Elf32_Off; /* Unsigned file offset */
typedef int32_t Elf32_Sword; /* Signed large integer */
typedef uint32_t Elf32_Word; /* Unsigned large integer */
typedef uint16_t Elf32_Half; /* Unsigned medium integer */
typedef uint64_t Elf64_Addr;
typedef uint64_t Elf64_Off;
typedef int32_t Elf64_Shalf;
#ifdef __alpha__
typedef int64_t Elf64_Sword;
typedef uint64_t Elf64_Word;
#else
typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
#endif
typedef int64_t Elf64_Sxword;
typedef uint64_t Elf64_Xword;
typedef uint32_t Elf64_Half;
typedef uint16_t Elf64_Quarter;
/*
* e_ident[] identification indexes
* See http://www.sco.com/developers/gabi/latest/ch4.eheader.html
*/
#define EI_MAG0 0 /* file ID */
#define EI_MAG1 1 /* file ID */
#define EI_MAG2 2 /* file ID */
#define EI_MAG3 3 /* file ID */
#define EI_CLASS 4 /* file class */
#define EI_DATA 5 /* data encoding */
#define EI_VERSION 6 /* ELF header version */
#define EI_OSABI 7 /* OS/ABI ID */
#define EI_ABIVERSION 8 /* ABI version */
#define EI_PAD 9 /* start of pad bytes */
#define EI_NIDENT 16 /* Size of e_ident[] */
/* e_ident[] magic number */
#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */
#define ELFMAG1 'E' /* e_ident[EI_MAG1] */
#define ELFMAG2 'L' /* e_ident[EI_MAG2] */
#define ELFMAG3 'F' /* e_ident[EI_MAG3] */
#define ELFMAG "\177ELF" /* magic */
#define SELFMAG 4 /* size of magic */
/* e_ident[] file class */
#define ELFCLASSNONE 0 /* invalid */
#define ELFCLASS32 1 /* 32-bit objs */
#define ELFCLASS64 2 /* 64-bit objs */
#define ELFCLASSNUM 3 /* number of classes */
/* e_ident[] data encoding */
#define ELFDATANONE 0 /* invalid */
#define ELFDATA2LSB 1 /* Little-Endian */
#define ELFDATA2MSB 2 /* Big-Endian */
#define ELFDATANUM 3 /* number of data encode defines */
/* e_ident[] Operating System/ABI */
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
#define ELFOSABI_HPUX 1 /* HP-UX operating system */
#define ELFOSABI_NETBSD 2 /* NetBSD */
#define ELFOSABI_LINUX 3 /* GNU/Linux */
#define ELFOSABI_HURD 4 /* GNU/Hurd */
#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
#define ELFOSABI_SOLARIS 6 /* Solaris */
#define ELFOSABI_MONTEREY 7 /* Monterey */
#define ELFOSABI_IRIX 8 /* IRIX */
#define ELFOSABI_FREEBSD 9 /* FreeBSD */
#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
#define ELFOSABI_MODESTO 11 /* Novell Modesto */
#define ELFOSABI_OPENBSD 12 /* OpenBSD */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
/* e_ident */
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
/* ELF Header */
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
Elf32_Half e_type; /* object file type */
Elf32_Half e_machine; /* machine */
Elf32_Word e_version; /* object file version */
Elf32_Addr e_entry; /* virtual entry point */
Elf32_Off e_phoff; /* program header table offset */
Elf32_Off e_shoff; /* section header table offset */
Elf32_Word e_flags; /* processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size */
Elf32_Half e_phentsize; /* program header entry size */
Elf32_Half e_phnum; /* number of program header entries */
Elf32_Half e_shentsize; /* section header entry size */
Elf32_Half e_shnum; /* number of section header entries */
Elf32_Half e_shstrndx; /* section header table's "section
header string table" entry offset */
} Elf32_Ehdr;
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Id bytes */
Elf64_Quarter e_type; /* file type */
Elf64_Quarter e_machine; /* machine type */
Elf64_Half e_version; /* version number */
Elf64_Addr e_entry; /* entry point */
Elf64_Off e_phoff; /* Program hdr offset */
Elf64_Off e_shoff; /* Section hdr offset */
Elf64_Half e_flags; /* Processor flags */
Elf64_Quarter e_ehsize; /* sizeof ehdr */
Elf64_Quarter e_phentsize; /* Program header entry size */
Elf64_Quarter e_phnum; /* Number of program headers */
Elf64_Quarter e_shentsize; /* Section header entry size */
Elf64_Quarter e_shnum; /* Number of section headers */
Elf64_Quarter e_shstrndx; /* String table index */
} Elf64_Ehdr;
/* e_type */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* relocatable file */
#define ET_EXEC 2 /* executable file */
#define ET_DYN 3 /* shared object file */
#define ET_CORE 4 /* core file */
#define ET_NUM 5 /* number of types */
#define ET_LOPROC 0xff00 /* reserved range for processor */
#define ET_HIPROC 0xffff /* specific e_type */
/* e_machine */
#define EM_NONE 0 /* No Machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola 68000 */
#define EM_88K 5 /* Motorola 88000 */
#define EM_486 6 /* Intel 80486 - unused? */
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */
/*
* Don't know if EM_MIPS_RS4_BE,
* EM_SPARC64, EM_PARISC,
* or EM_PPC are ABI compliant
*/
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */
#define EM_PARISC 15 /* HPPA */
#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */
#define EM_PPC 20 /* PowerPC */
#define EM_ARM 40 /* ARM AArch32 */
#define EM_ALPHA 41 /* DEC ALPHA */
#define EM_SH 42 /* Hitachi/Renesas Super-H */
#define EM_SPARCV9 43 /* SPARC version 9 */
#define EM_IA_64 50 /* Intel IA-64 Processor */
#define EM_AMD64 62 /* AMD64 architecture */
#define EM_VAX 75 /* DEC VAX */
#define EM_AARCH64 183 /* ARM AArch64 */
/* Non-standard */
#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */
/* Version */
#define EV_NONE 0 /* Invalid */
#define EV_CURRENT 1 /* Current */
#define EV_NUM 2 /* number of versions */
/* Section Header */
typedef struct
{
Elf32_Word sh_name; /* name - index into section header
* string table section */
Elf32_Word sh_type; /* type */
Elf32_Word sh_flags; /* flags */
Elf32_Addr sh_addr; /* address */
Elf32_Off sh_offset; /* file offset */
Elf32_Word sh_size; /* section size */
Elf32_Word sh_link; /* section header table index link */
Elf32_Word sh_info; /* extra information */
Elf32_Word sh_addralign; /* address alignment */
Elf32_Word sh_entsize; /* section entry size */
} Elf32_Shdr;
typedef struct
{
Elf64_Half sh_name; /* section name */
Elf64_Half sh_type; /* section type */
Elf64_Xword sh_flags; /* section flags */
Elf64_Addr sh_addr; /* virtual address */
Elf64_Off sh_offset; /* file offset */
Elf64_Xword sh_size; /* section size */
Elf64_Half sh_link; /* link to another */
Elf64_Half sh_info; /* misc info */
Elf64_Xword sh_addralign; /* memory alignment */
Elf64_Xword sh_entsize; /* table entry size */
} Elf64_Shdr;
/* Special Section Indexes */
#define SHN_UNDEF 0 /* undefined */
#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */
#define SHN_LOPROC 0xff00 /* reserved range for processor */
#define SHN_HIPROC 0xff1f /* specific section indexes */
#define SHN_ABS 0xfff1 /* absolute value */
#define SHN_COMMON 0xfff2 /* common symbol */
#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */
/* sh_type */
#define SHT_NULL 0 /* inactive */
#define SHT_PROGBITS 1 /* program defined information */
#define SHT_SYMTAB 2 /* symbol table section */
#define SHT_STRTAB 3 /* string table section */
#define SHT_RELA 4 /* relocation section with addends*/
#define SHT_HASH 5 /* symbol hash table section */
#define SHT_DYNAMIC 6 /* dynamic section */
#define SHT_NOTE 7 /* note section */
#define SHT_NOBITS 8 /* no space section */
#define SHT_REL 9 /* relation section without addends */
#define SHT_SHLIB 10 /* reserved - purpose unknown */
#define SHT_DYNSYM 11 /* dynamic symbol table section */
#define SHT_NUM 12 /* number of section types */
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
#define SHT_HIPROC 0x7fffffff /* specific section header types */
#define SHT_LOUSER 0x80000000 /* reserved range for application */
#define SHT_HIUSER 0xffffffff /* specific indexes */
/* Section names */
#define ELF_BSS ".bss" /* uninitialized data */
#define ELF_DATA ".data" /* initialized data */
#define ELF_DEBUG ".debug" /* debug */
#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */
#define ELF_DYNSTR ".dynstr" /* dynamic string table */
#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */
#define ELF_FINI ".fini" /* termination code */
#define ELF_GOT ".got" /* global offset table */
#define ELF_HASH ".hash" /* symbol hash table */
#define ELF_INIT ".init" /* initialization code */
#define ELF_REL_DATA ".rel.data" /* relocation data */
#define ELF_REL_FINI ".rel.fini" /* relocation termination code */
#define ELF_REL_INIT ".rel.init" /* relocation initialization code */
#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */
#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */
#define ELF_REL_TEXT ".rel.text" /* relocation code */
#define ELF_RODATA ".rodata" /* read-only data */
#define ELF_SHSTRTAB ".shstrtab" /* section header string table */
#define ELF_STRTAB ".strtab" /* string table */
#define ELF_SYMTAB ".symtab" /* symbol table */
#define ELF_TEXT ".text" /* code */
/* Section Attribute Flags - sh_flags */
#define SHF_WRITE 0x1 /* Writable */
#define SHF_ALLOC 0x2 /* occupies memory */
#define SHF_EXECINSTR 0x4 /* executable */
#define SHF_TLS 0x400 /* thread local storage */
#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \
* specific section attributes */
/* Symbol Table Entry */
typedef struct elf32_sym
{
Elf32_Word st_name; /* name - index into string table */
Elf32_Addr st_value; /* symbol value */
Elf32_Word st_size; /* symbol size */
unsigned char st_info; /* type and binding */
unsigned char st_other; /* 0 - no defined meaning */
Elf32_Half st_shndx; /* section header index */
} Elf32_Sym;
typedef struct
{
Elf64_Half st_name; /* Symbol name index in str table */
Elf_Byte st_info; /* type / binding attrs */
Elf_Byte st_other; /* unused */
Elf64_Quarter st_shndx; /* section index of symbol */
Elf64_Xword st_value; /* value of symbol */
Elf64_Xword st_size; /* size of symbol */
} Elf64_Sym;
/* Symbol table index */
#define STN_UNDEF 0 /* undefined */
/* Extract symbol info - st_info */
#define ELF32_ST_BIND(x) ((x) >> 4)
#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf)
#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
#define ELF64_ST_BIND(x) ((x) >> 4)
#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf)
#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
/* Symbol Binding - ELF32_ST_BIND - st_info */
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
#define STB_WEAK 2 /* like global - lower precedence */
#define STB_NUM 3 /* number of symbol bindings */
#define STB_LOPROC 13 /* reserved range for processor */
#define STB_HIPROC 15 /* specific symbol bindings */
/* Symbol type - ELF32_ST_TYPE - st_info */
#define STT_NOTYPE 0 /* not specified */
#define STT_OBJECT 1 /* data object */
#define STT_FUNC 2 /* function */
#define STT_SECTION 3 /* section */
#define STT_FILE 4 /* file */
#define STT_TLS 6 /* thread local storage */
#define STT_LOPROC 13 /* reserved range for processor */
#define STT_HIPROC 15 /* specific symbol types */
/* Relocation entry with implicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
} Elf32_Rel;
/* Relocation entry with explicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
Elf32_Sword r_addend;
} Elf32_Rela;
/* Extract relocation info - r_info */
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
typedef struct
{
Elf64_Xword r_offset; /* where to do it */
Elf64_Xword r_info; /* index & type of relocation */
} Elf64_Rel;
typedef struct
{
Elf64_Xword r_offset; /* where to do it */
Elf64_Xword r_info; /* index & type of relocation */
Elf64_Sxword r_addend; /* adjustment value */
} Elf64_Rela;
#define ELF64_R_SYM(info) ((info) >> 32)
#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF)
#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t))
#if defined(__mips64__) && defined(__MIPSEL__)
/*
* The 64-bit MIPS ELF ABI uses a slightly different relocation format
* than the regular ELF ABI: the r_info field is split into several
* pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details).
*/
#undef ELF64_R_SYM
#undef ELF64_R_TYPE
#undef ELF64_R_INFO
#define ELF64_R_TYPE(info) (swap32((info) >> 32))
#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF)
#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s))
#endif /* __mips64__ && __MIPSEL__ */
/* Program Header */
typedef struct
{
Elf32_Word p_type; /* segment type */
Elf32_Off p_offset; /* segment offset */
Elf32_Addr p_vaddr; /* virtual address of segment */
Elf32_Addr p_paddr; /* physical address - ignored? */
Elf32_Word p_filesz; /* number of bytes in file for seg. */
Elf32_Word p_memsz; /* number of bytes in mem. for seg. */
Elf32_Word p_flags; /* flags */
Elf32_Word p_align; /* memory alignment */
} Elf32_Phdr;
typedef struct
{
Elf64_Half p_type; /* entry type */
Elf64_Half p_flags; /* flags */
Elf64_Off p_offset; /* offset */
Elf64_Addr p_vaddr; /* virtual address */
Elf64_Addr p_paddr; /* physical address */
Elf64_Xword p_filesz; /* file size */
Elf64_Xword p_memsz; /* memory size */
Elf64_Xword p_align; /* memory & file alignment */
} Elf64_Phdr;
/* Segment types - p_type */
#define PT_NULL 0 /* unused */
#define PT_LOAD 1 /* loadable segment */
#define PT_DYNAMIC 2 /* dynamic linking section */
#define PT_INTERP 3 /* the RTLD */
#define PT_NOTE 4 /* auxiliary information */
#define PT_SHLIB 5 /* reserved - purpose undefined */
#define PT_PHDR 6 /* program header */
#define PT_TLS 7 /* thread local storage */
#define PT_LOOS 0x60000000 /* reserved range for OS */
#define PT_HIOS 0x6fffffff /* specific segment types */
#define PT_LOPROC 0x70000000 /* reserved range for processor */
#define PT_HIPROC 0x7fffffff /* specific segment types */
#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */
#define PT_GANDR_KERNEL 0x67646b6c /* gdkl */
/* Segment flags - p_flags */
#define PF_X 0x1 /* Executable */
#define PF_W 0x2 /* Writable */
#define PF_R 0x4 /* Readable */
#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */
/* specific segment flags */
/* Dynamic structure */
typedef struct
{
Elf32_Sword d_tag; /* controls meaning of d_val */
union {
Elf32_Word d_val; /* Multiple meanings - see d_tag */
Elf32_Addr d_ptr; /* program virtual address */
} d_un;
} Elf32_Dyn;
typedef struct
{
Elf64_Xword d_tag; /* controls meaning of d_val */
union {
Elf64_Addr d_ptr;
Elf64_Xword d_val;
} d_un;
} Elf64_Dyn;
/* Dynamic Array Tags - d_tag */
#define DT_NULL 0 /* marks end of _DYNAMIC array */
#define DT_NEEDED 1 /* string table offset of needed lib */
#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */
#define DT_PLTGOT 3 /* address PLT/GOT */
#define DT_HASH 4 /* address of symbol hash table */
#define DT_STRTAB 5 /* address of string table */
#define DT_SYMTAB 6 /* address of symbol table */
#define DT_RELA 7 /* address of relocation table */
#define DT_RELASZ 8 /* size of relocation table */
#define DT_RELAENT 9 /* size of relocation entry */
#define DT_STRSZ 10 /* size of string table */
#define DT_SYMENT 11 /* size of symbol table entry */
#define DT_INIT 12 /* address of initialization func. */
#define DT_FINI 13 /* address of termination function */
#define DT_SONAME 14 /* string table offset of shared obj */
#define DT_RPATH 15 /* string table offset of library \
* search path */
#define DT_SYMBOLIC 16 /* start sym search in shared obj. */
#define DT_REL 17 /* address of rel. tbl. w addends */
#define DT_RELSZ 18 /* size of DT_REL relocation table */
#define DT_RELENT 19 /* size of DT_REL relocation entry */
#define DT_PLTREL 20 /* PLT referenced relocation entry */
#define DT_DEBUG 21 /* bugger */
#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */
#define DT_JMPREL 23 /* add. of PLT's relocation entries */
#define DT_BIND_NOW 24 /* Bind now regardless of env setting */
#define DT_LOOS 0x6000000d /* reserved range for OS */
#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */
#define DT_LOPROC 0x70000000 /* reserved range for processor */
#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */
/* some other useful tags */
#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */
#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */
#define DT_FLAGS_1 0x6ffffffb
/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */
#define DF_1_NOW 0x00000001
#define DF_1_GLOBAL 0x00000002
#define DF_1_GROUP 0x00000004
#define DF_1_NODELETE 0x00000008
#define DF_1_LOADFLTR 0x00000010
#define DF_1_INITFIRST 0x00000020
#define DF_1_NOOPEN 0x00000040
#define DF_1_ORIGIN 0x00000080
#define DF_1_DIRECT 0x00000100
#define DF_1_TRANS 0x00000200
#define DF_1_INTERPOSE 0x00000400
#define DF_1_NODEFLIB 0x00000800
#define DF_1_NODUMP 0x00001000
#define DF_1_CONLFAT 0x00002000
/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */
#define DT_NUM (DT_JMPREL + 1)
/*
* Note Definitions
*/
typedef struct
{
Elf32_Word namesz;
Elf32_Word descsz;
Elf32_Word type;
} Elf32_Note;
typedef struct
{
Elf64_Half namesz;
Elf64_Half descsz;
Elf64_Half type;
} Elf64_Note;
#if defined(ELFSIZE) && (ELFSIZE == 32)
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Phdr Elf32_Phdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Rel Elf32_Rel
#define Elf_RelA Elf32_Rela
#define Elf_Dyn Elf32_Dyn
#define Elf_Half Elf32_Half
#define Elf_Word Elf32_Word
#define Elf_Sword Elf32_Sword
#define Elf_Addr Elf32_Addr
#define Elf_Off Elf32_Off
#define Elf_Nhdr Elf32_Nhdr
#define Elf_Note Elf32_Note
#define ELF_R_SYM ELF32_R_SYM
#define ELF_R_TYPE ELF32_R_TYPE
#define ELF_R_INFO ELF32_R_INFO
#define ELFCLASS ELFCLASS32
#define ELF_ST_BIND ELF32_ST_BIND
#define ELF_ST_TYPE ELF32_ST_TYPE
#define ELF_ST_INFO ELF32_ST_INFO
#elif defined(ELFSIZE) && (ELFSIZE == 64)
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Rel Elf64_Rel
#define Elf_RelA Elf64_Rela
#define Elf_Dyn Elf64_Dyn
#define Elf_Half Elf64_Half
#define Elf_Word Elf64_Word
#define Elf_Sword Elf64_Sword
#define Elf_Addr Elf64_Addr
#define Elf_Off Elf64_Off
#define Elf_Nhdr Elf64_Nhdr
#define Elf_Note Elf64_Note
#define ELF_R_SYM ELF64_R_SYM
#define ELF_R_TYPE ELF64_R_TYPE
#define ELF_R_INFO ELF64_R_INFO
#define ELFCLASS ELFCLASS64
#define ELF_ST_BIND ELF64_ST_BIND
#define ELF_ST_TYPE ELF64_ST_TYPE
#define ELF_ST_INFO ELF64_ST_INFO
#endif
#endif

View File

@@ -0,0 +1,49 @@
/*
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ELFARCH_H
#define ELFARCH_H
#if defined(__i386__)
#define EM_THIS EM_386
#define EL_ARCH_USES_REL
#elif defined(__amd64__)
#define EM_THIS EM_AMD64
#define EL_ARCH_USES_RELA
#elif defined(__arm__)
#define EM_THIS EM_ARM
#define EL_ARCH_USES_REL
#elif defined(__aarch64__)
#define EM_THIS EM_AARCH64
#define EL_ARCH_USES_RELA
#define EL_ARCH_USES_REL
#else
#error specify your ELF architecture
#endif
#if defined(__LP64__) || defined(__LLP64__)
#define ELFSIZE 64
#else
#define ELFSIZE 32
#endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define ELFDATATHIS ELFDATA2LSB
#else
#define ELFDATATHIS ELFDATA2MSB
#endif
#endif

View File

@@ -0,0 +1,324 @@
/*
* Copyright © 2018, M4xw
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "elfload.h"
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset)
{
return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO;
}
#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize))
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i)
{
el_status rv = EL_OK;
for (; *i < ctx->ehdr.e_phnum; (*i)++)
{
if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i))))
return rv;
if (phdr->p_type == type)
{
return rv;
}
}
*i = -1;
return rv;
}
#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize))
el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i)
{
el_status rv = EL_OK;
for (; *i < ctx->ehdr.e_shnum; (*i)++)
{
if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i))))
return rv;
if (shdr->sh_type == type)
{
return rv;
}
}
*i = -1;
return rv;
}
el_status el_init(el_ctx *ctx)
{
el_status rv = EL_OK;
if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0)))
return rv;
/* validate header */
if (!IS_ELF(ctx->ehdr))
return EL_NOTELF;
if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS)
return EL_WRONGBITS;
if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS)
return EL_WRONGENDIAN;
if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT)
return EL_NOTELF;
if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN)
return EL_NOTEXEC;
if (ctx->ehdr.e_machine != EM_THIS)
return EL_WRONGARCH;
if (ctx->ehdr.e_version != EV_CURRENT)
return EL_NOTELF;
/* load phdrs */
Elf_Phdr ph;
/* iterate through, calculate extents */
ctx->base_load_paddr = ctx->base_load_vaddr = 0;
ctx->align = 1;
ctx->memsz = 0;
unsigned i = 0;
for (;;)
{
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
return rv;
if (i == (unsigned)-1)
break;
Elf_Addr phend = ph.p_vaddr + ph.p_memsz;
if (phend > ctx->memsz)
ctx->memsz = phend;
if (ph.p_align > ctx->align)
ctx->align = ph.p_align;
i++;
}
// Program Header
if (ctx->ehdr.e_type == ET_DYN)
{
i = 0;
if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i)))
return rv;
if (i == (unsigned)-1)
return EL_NODYN;
ctx->dynoff = ph.p_offset;
ctx->dynsize = ph.p_filesz;
}
else
{
ctx->dynoff = 0;
ctx->dynsize = 0;
}
// Section String Table
if (ctx->ehdr.e_type == ET_DYN)
{
i = ctx->ehdr.e_shstrndx - 1;
if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i)))
return rv;
// Reset
i = 0;
if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i)))
return rv;
if (i == (unsigned)-1)
return EL_NODYN;
}
return rv;
}
/*
typedef void* (*el_alloc_cb)(
el_ctx *ctx,
Elf_Addr phys,
Elf_Addr virt,
Elf_Addr size);
*/
el_status el_load(el_ctx *ctx, el_alloc_cb alloc)
{
el_status rv = EL_OK;
/* address deltas */
Elf_Addr pdelta = ctx->base_load_paddr;
Elf_Addr vdelta = ctx->base_load_vaddr;
/* iterate paddrs */
Elf_Phdr ph;
unsigned i = 0;
for (;;)
{
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
return rv;
if (i == (unsigned)-1)
break;
Elf_Addr pload = ph.p_paddr + pdelta;
Elf_Addr vload = ph.p_vaddr + vdelta;
/* allocate mem */
char *dest = alloc(ctx, pload, vload, ph.p_memsz);
if (!dest)
return EL_ENOMEM;
EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n",
ph.p_offset, ph.p_vaddr, dest);
/* read loaded portion */
if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset)))
return rv;
/* zero mem-only portion */
memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz);
i++;
}
return rv;
}
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag)
{
el_status rv = EL_OK;
size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn);
for (unsigned i = 0; i < ndyn; i++)
{
if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn)))
return rv;
if (dyn->d_tag == tag)
return EL_OK;
}
dyn->d_tag = DT_NULL;
return EL_OK;
}
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type)
{
el_status rv = EL_OK;
Elf_Dyn rel, relsz, relent;
if ((rv = el_finddyn(ctx, &rel, type)))
return rv;
if ((rv = el_finddyn(ctx, &relsz, type + 1)))
return rv;
if ((rv = el_finddyn(ctx, &relent, type + 2)))
return rv;
if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL)
{
ri->entrysize = 0;
ri->tablesize = 0;
ri->tableoff = 0;
}
else
{
ri->tableoff = rel.d_un.d_ptr;
ri->tablesize = relsz.d_un.d_val;
ri->entrysize = relent.d_un.d_val;
}
return rv;
}
extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel);
extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela);
el_status el_relocate(el_ctx *ctx)
{
el_status rv = EL_OK;
// not dynamic
if (ctx->ehdr.e_type != ET_DYN)
return EL_OK;
char *base = (char *)ctx->base_load_paddr;
el_relocinfo ri;
#ifdef EL_ARCH_USES_REL
if ((rv = el_findrelocs(ctx, &ri, DT_REL)))
return rv;
if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize)
{
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
ri.entrysize, sizeof(Elf_Rel));
return EL_BADREL;
}
size_t relcnt = ri.tablesize / sizeof(Elf_Rel);
Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff);
for (size_t i = 0; i < relcnt; i++)
{
if ((rv = el_applyrel(ctx, &reltab[i])))
return rv;
}
#endif
#ifdef EL_ARCH_USES_RELA
if ((rv = el_findrelocs(ctx, &ri, DT_RELA)))
return rv;
if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize)
{
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
ri.entrysize, sizeof(Elf_RelA));
return EL_BADREL;
}
size_t relacnt = ri.tablesize / sizeof(Elf_RelA);
Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff);
for (size_t i = 0; i < relacnt; i++)
{
if ((rv = el_applyrela(ctx, &relatab[i])))
return rv;
}
#endif
#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA)
#error No relocation type defined!
#endif
return rv;
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright © 2018, M4xw
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ELFLOAD_H
#define ELFLOAD_H
#include <stddef.h>
#include "elfarch.h"
#include "elf.h"
#include "../../utils/types.h"
#ifdef DEBUG
#include "../../gfx/gfx.h"
extern gfx_con_t gfx_con;
#define EL_DEBUG(format, ...) \
gfx_printf(&gfx_con, format __VA_OPT__(, ) __VA_ARGS__)
#else
#define EL_DEBUG(...) \
do \
{ \
} while (0)
#endif
typedef enum
{
EL_OK = 0,
EL_EIO,
EL_ENOMEM,
EL_NOTELF,
EL_WRONGBITS,
EL_WRONGENDIAN,
EL_WRONGARCH,
EL_WRONGOS,
EL_NOTEXEC,
EL_NODYN,
EL_BADREL,
} el_status;
typedef struct el_ctx
{
bool (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset);
/* base_load_* -> address we are actually going to load at
*/
Elf_Addr
base_load_paddr,
base_load_vaddr;
/* size in memory of binary */
Elf_Addr memsz;
/* required alignment */
Elf_Addr align;
/* ELF header */
Elf_Ehdr ehdr;
// Section Header Str Table
Elf_Shdr shstr;
Elf_Shdr symtab;
/* Offset of dynamic table (0 if not ET_DYN) */
Elf_Off dynoff;
/* Size of dynamic table (0 if not ET_DYN) */
Elf_Addr dynsize;
} el_ctx;
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset);
el_status el_init(el_ctx *ctx);
typedef void *(*el_alloc_cb)(
el_ctx *ctx,
Elf_Addr phys,
Elf_Addr virt,
Elf_Addr size);
el_status el_load(el_ctx *ctx, el_alloc_cb alloccb);
/* find the next phdr of type \p type, starting at \p *i.
* On success, returns EL_OK with *i set to the phdr number, and the phdr loaded
* in *phdr.
*
* If the end of the phdrs table was reached, *i is set to -1 and the contents
* of *phdr are undefined
*/
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i);
/* Relocate the loaded executable */
el_status el_relocate(el_ctx *ctx);
/* find a dynamic table entry
* returns the entry on success, dyn->d_tag = DT_NULL on failure
*/
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type);
typedef struct
{
Elf_Off tableoff;
Elf_Addr tablesize;
Elf_Addr entrysize;
} el_relocinfo;
/* find all information regarding relocations of a specific type.
*
* pass DT_REL or DT_RELA for type
* sets ri->entrysize = 0 if not found
*/
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type);
#endif

View File

@@ -0,0 +1,84 @@
/*
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "elfload.h"
#if defined(__aarch64__)
#define R_AARCH64_NONE 0
#define R_AARCH64_RELATIVE 1027
el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel)
{
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
uint32_t type = ELF_R_TYPE(rel->r_info);
uint32_t sym = ELF_R_SYM(rel->r_info);
switch (type)
{
case R_AARCH64_NONE:
EL_DEBUG("R_AARCH64_NONE\n");
break;
case R_AARCH64_RELATIVE:
if (sym)
{
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
return EL_BADREL;
}
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
*p = rel->r_addend + ctx->base_load_vaddr;
break;
default:
EL_DEBUG("Bad relocation %u\n", type);
return EL_BADREL;
}
return EL_OK;
}
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
{
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
uint32_t type = ELF_R_TYPE(rel->r_info);
uint32_t sym = ELF_R_SYM(rel->r_info);
switch (type)
{
case R_AARCH64_NONE:
EL_DEBUG("R_AARCH64_NONE\n");
break;
case R_AARCH64_RELATIVE:
if (sym)
{
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
return EL_BADREL;
}
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
*p += ctx->base_load_vaddr;
break;
default:
EL_DEBUG("Bad relocation %u\n", type);
return EL_BADREL;
}
return EL_OK;
}
#endif

View File

@@ -0,0 +1,66 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <m4x@m4xw.net> wrote this file. As long as you retain this notice you can do
* whatever you want with this stuff. If we meet some day, and you think this
* stuff is worth it, you can buy me a beer in return. M4xw
* ----------------------------------------------------------------------------
*/
#include "elfload.h"
#if defined(__arm__)
// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf
#define R_ARM_NONE 0
#define R_ARM_ABS32 2
#define R_ARM_JUMP_SLOT 22
#define R_ARM_GLOB_DAT 21
#define R_ARM_RELATIVE 23
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
{
uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset
uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr
#if 0 // For later symbol usage
Elf32_Sym *elfSym;
const char *symbolName;
// We resolve relocs from the originating elf-image
elfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym;
int strtab_offset = ctx->shstr.sh_offset;
char *strtab = (char *)buffteg + strtab_offset;
symbolName = strtab + elfSym->st_name;
//EL_DEBUG("Str: %s sz: %x val: %x\n", symbolName, elfSym->st_size, elfSym->st_value);
#endif
switch (type)
{
case R_ARM_NONE:
EL_DEBUG("R_ARM_NONE\n");
break;
case R_ARM_JUMP_SLOT:
case R_ARM_ABS32:
case R_ARM_GLOB_DAT:
// Stubbed for later purpose
//*p += elfSym->st_value; // + vaddr from sec
//*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now
break;
case R_ARM_RELATIVE: // Needed for PIE
if (sym)
{
return EL_BADREL;
}
*p += ctx->base_load_vaddr;
break;
default:
return EL_BADREL;
}
return EL_OK;
}
#endif

2
ipl/diskio.c → bootloader/libs/fatfs/diskio.c Executable file → Normal file
View File

@@ -9,7 +9,7 @@
#include <string.h>
#include "diskio.h" /* FatFs lower layer API */
#include "sdmmc.h"
#include "../../storage/sdmmc.h"
extern sdmmc_storage_t sd_storage;

2
ipl/diskio.h → bootloader/libs/fatfs/diskio.h Executable file → Normal file
View File

@@ -9,7 +9,7 @@
extern "C" {
#endif
#include "integer.h"
#include "../../utils/types.h"
/* Status of Disk Functions */

939
ipl/ff.c → bootloader/libs/fatfs/ff.c Executable file → Normal file

File diff suppressed because it is too large Load Diff

20
ipl/ff.h → bootloader/libs/fatfs/ff.h Executable file → Normal file
View File

@@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13a /
/ FatFs - Generic FAT Filesystem module R0.13b /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2017, ChaN, all right reserved.
/ Copyright (C) 2018, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
@@ -20,13 +20,13 @@
#ifndef FF_DEFINED
#define FF_DEFINED 89352 /* Revision ID */
#define FF_DEFINED 63463 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h" /* Basic integer types */
#include "../../utils/types.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if FF_DEFINED != FFCONF_DEF
@@ -45,6 +45,12 @@ typedef struct {
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#endif
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
#endif
#endif
/* Type of path name strings on FatFs API */
@@ -60,7 +66,11 @@ typedef WCHAR TCHAR;
typedef char TCHAR;
#define _T(x) u8 ## x
#define _TEXT(x) u8 ## x
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 2)
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
typedef DWORD TCHAR;
#define _T(x) U ## x
#define _TEXT(x) U ## x
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
#error Wrong FF_LFN_UNICODE setting
#else /* ANSI/OEM code in SBCS/DBCS */
typedef char TCHAR;

28
ipl/ffconf.h → bootloader/libs/fatfs/ffconf.h Executable file → Normal file
View File

@@ -2,7 +2,7 @@
/ FatFs - Configuration file
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 89352 /* Revision ID */
#define FFCONF_DEF 63463 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
@@ -33,7 +33,7 @@
/ 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 0
#define FF_USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
@@ -97,7 +97,7 @@
*/
#define FF_USE_LFN 1
#define FF_USE_LFN 3
#define FF_MAX_LFN 255
/* The FF_USE_LFN switches the support for LFN (long file name).
/
@@ -123,6 +123,7 @@
/ 0: ANSI/OEM in current CP (TCHAR = char)
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
/ 2: Unicode in UTF-8 (TCHAR = char)
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
/
/ Also behavior of string I/O functions will be affected by this option.
/ When LFN is not enabled, this option has no effect. */
@@ -168,11 +169,16 @@
#define FF_STR_VOLUME_ID 0
#define FF_VOLUME_STRS "sd"
/* FF_STR_VOLUME_ID switches string support for volume ID.
/ When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as:
/
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/
#define FF_MULTI_PARTITION 0
@@ -226,7 +232,7 @@
#define FF_FS_EXFAT 1
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ When enable exFAT, also LFN needs to be enabled.
/ To enable exFAT, also LFN needs to be enabled.
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
@@ -234,9 +240,9 @@
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2018
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
/* The option FF_FS_NORTC switches timestamp function. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON,

View File

@@ -0,0 +1,39 @@
/*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */
/* (C) ChaN, 2017 */
/* (C) CTCaer, 2018 */
/*------------------------------------------------------------------------*/
#include "ff.h"
#include "../../mem/heap.h"
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */
UINT msize /* Number of bytes to allocate */
)
{
return malloc(msize); /* Allocate a new memory block with POSIX API */
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do for null) */
)
{
free(mblock); /* Free the memory block with POSIX API */
}
#endif

187
ipl/ffunicode.c → bootloader/libs/fatfs/ffunicode.c Executable file → Normal file
View File

@@ -27,7 +27,7 @@
#if FF_USE_LFN /* This module is blanked when non-LFN configuration */
#if FF_DEFINED != 89352 /* Revision ID */
#if FF_DEFINED != 63463 /* Revision ID */
#error Wrong include file (ff.h).
#endif
@@ -40,8 +40,7 @@
/*------------------------------------------------------------------------*/
#if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0
static
const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@@ -53,8 +52,7 @@ const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0
static
const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
@@ -66,8 +64,7 @@ const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0
static
const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
@@ -79,8 +76,7 @@ const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0
static
const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
@@ -92,8 +88,7 @@ const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0
static
const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
@@ -105,8 +100,7 @@ const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0
static
const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@@ -118,8 +112,7 @@ const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0
static
const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
@@ -131,8 +124,7 @@ const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0
static
const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */
static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
@@ -144,8 +136,7 @@ const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0
static
const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@@ -157,8 +148,7 @@ const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0
static
const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */
static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@@ -170,8 +160,7 @@ const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0
static
const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */
static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@@ -183,8 +172,7 @@ const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0
static
const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@@ -196,8 +184,7 @@ const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0
static
const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */
static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
@@ -209,8 +196,7 @@ const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table *
};
#endif
#if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0
static
const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
@@ -222,8 +208,7 @@ const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0
static
const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
@@ -235,8 +220,7 @@ const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0
static
const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
@@ -248,8 +232,7 @@ const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0
static
const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
@@ -283,7 +266,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
c = (WCHAR)uni;
} else { /* Non-ASCII */
if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it a valid code? */
if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */
for (c = 0; c < 0x80 && uni != p[c]; c++) ;
c = (c + 0x80) & 0xFF;
}
@@ -330,30 +313,28 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
{
const WCHAR *p;
WCHAR c = 0, uc;
UINT i, n, li, hi;
UINT i = 0, n, li, hi;
if (uni < 0x80) { /* ASCII? */
c = (WCHAR)uni;
} else { /* Non-ASCII */
if (uni < 0x10000) { /* Is it in BMP? */
if (cp == FF_CODE_PAGE) { /* Is it a valid code? */
uc = (WCHAR)uni;
p = CVTBL(uni2oem, FF_CODE_PAGE);
hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1;
li = 0;
for (n = 16; n; n--) {
i = li + (hi - li) / 2;
if (uc == p[i * 2]) break;
if (uc > p[i * 2]) {
li = i;
} else {
hi = i;
}
if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */
uc = (WCHAR)uni;
p = CVTBL(uni2oem, FF_CODE_PAGE);
hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1;
li = 0;
for (n = 16; n; n--) {
i = li + (hi - li) / 2;
if (uc == p[i * 2]) break;
if (uc > p[i * 2]) {
li = i;
} else {
hi = i;
}
if (n != 0) c = p[i * 2 + 1];
}
if (n != 0) c = p[i * 2 + 1];
}
}
@@ -368,14 +349,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
{
const WCHAR *p;
WCHAR c = 0;
UINT i, n, li, hi;
UINT i = 0, n, li, hi;
if (oem < 0x80) { /* ASCII? */
c = oem;
} else { /* Extended char */
if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */
if (cp == FF_CODE_PAGE) { /* Is it valid code page? */
p = CVTBL(oem2uni, FF_CODE_PAGE);
hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1;
li = 0;
@@ -405,7 +386,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
#if FF_CODE_PAGE == 0
static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0};
static const WCHAR *const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0};
static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0};
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
@@ -426,20 +407,20 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
uc = (WCHAR)uni;
p = 0;
if (cp < 900) { /* SBCS */
for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */
for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */
p = cp_table[i];
if (p) { /* Is it a valid CP ? */
if (p) { /* Is it valid code page ? */
for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */
c = (c + 0x80) & 0xFF;
}
} else { /* DBCS */
switch (cp) {
switch (cp) { /* Get conversion table */
case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break;
case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break;
case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break;
case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break;
}
if (p) { /* Is it a valid code page? */
if (p) { /* Is it valid code page? */
li = 0;
for (n = 16; n; n--) { /* Find OEM code */
i = li + (hi - li) / 2;
@@ -518,50 +499,90 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
DWORD uni /* Unicode code point to be up-converted */
)
{
/* Compressed upper conversion table */
static const WORD cvt1[] = { /* U+0000 - U+0FFF */
const WORD *p;
WORD uc, bc, nc, cmd;
static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */
/* Basic Latin */
0x0061,0x031A,
/* Latin-1 Supplement */
0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178,
0x00E0,0x0317,
0x00F8,0x0307,
0x00FF,0x0001,0x0178,
/* Latin Extended-A */
0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106,
0x0100,0x0130,
0x0132,0x0106,
0x0139,0x0110,
0x014A,0x012E,
0x0179,0x0106,
/* Latin Extended-B */
0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,
0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128,
0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A,
0x01CD,0x0110,
0x01DD,0x0001,0x018E,
0x01DE,0x0112,
0x01F3,0x0003,0x01F1,0x01F4,0x01F4,
0x01F8,0x0128,
0x0222,0x0112,
0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241,
0x0246,0x010A,
/* IPA Extensions */
0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,
/* Greek, Coptic */
0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311,
0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118,
0x037B,0x0003,0x03FD,0x03FE,0x03FF,
0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A,
0x03B1,0x0311,
0x03C2,0x0002,0x03A3,0x03A3,
0x03C4,0x0308,
0x03CC,0x0003,0x038C,0x038E,0x038F,
0x03D8,0x0118,
0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,
/* Cyrillic */
0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144,
0x0430,0x0320,
0x0450,0x0710,
0x0460,0x0122,
0x048A,0x0136,
0x04C1,0x010E,
0x04CF,0x0001,0x04C0,
0x04D0,0x0144,
/* Armenian */
0x0561,0x0426,
0x0000
0x0000 /* EOT */
};
static const WORD cvt2[] = { /* U+1000 - U+FFFF */
static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */
/* Phonetic Extensions */
0x1D7D,0x0001,0x2C63,
/* Latin Extended Additional */
0x1E00,0x0196, 0x1EA0,0x015A,
0x1E00,0x0196,
0x1EA0,0x015A,
/* Greek Extended */
0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606,
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608,
0x1F00,0x0608,
0x1F10,0x0606,
0x1F20,0x0608,
0x1F30,0x0608,
0x1F40,0x0606,
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F,
0x1F60,0x0608,
0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,
0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF3,0x0001,0x1FFC,
0x1F80,0x0608,
0x1F90,0x0608,
0x1FA0,0x0608,
0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
0x1FCC,0x0001,0x1FC3,
0x1FD0,0x0602,
0x1FE0,0x0602,
0x1FE5,0x0001,0x1FEC,
0x1FF3,0x0001,0x1FFC,
/* Letterlike Symbols */
0x214E,0x0001,0x2132,
/* Number forms */
0x2170,0x0210, 0x2184,0x0001,0x2183,
0x2170,0x0210,
0x2184,0x0001,0x2183,
/* Enclosed Alphanumerics */
0x24D0,0x051A, 0x2C30,0x042F,
0x24D0,0x051A,
0x2C30,0x042F,
/* Latin Extended-C */
0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102,
0x2C60,0x0102,
0x2C67,0x0106, 0x2C75,0x0102,
/* Coptic */
0x2C80,0x0164,
/* Georgian Supplement */
@@ -569,18 +590,16 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
/* Full-width */
0xFF41,0x031A,
0x0000
0x0000 /* EOT */
};
const WORD *p;
WORD uc, bc, nc, cmd;
if (uni < 0x10000) { /* Is it in BMP? */
uc = (WORD)uni;
p = uc < 0x1000 ? cvt1 : cvt2;
for (;;) {
bc = *p++; /* Get block base */
if (!bc || uc < bc) break;
bc = *p++; /* Get the block base */
if (bc == 0 || uc < bc) break; /* Not matched? */
nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */
if (uc < bc + nc) { /* In the block? */
switch (cmd) {
@@ -596,7 +615,7 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
}
break;
}
if (!cmd) p += nc;
if (cmd == 0) p += nc; /* Skip table if needed */
}
uni = uc;
}

2
ipl/link.ld → bootloader/link.ld Executable file → Normal file
View File

@@ -1,7 +1,7 @@
ENTRY(_start)
SECTIONS {
PROVIDE(__ipl_start = 0x40003000);
PROVIDE(__ipl_start = 0x40008000);
. = __ipl_start;
.text : {
*(.text*);

1191
bootloader/main.c Normal file

File diff suppressed because it is too large Load Diff

38
ipl/emc.h → bootloader/mem/emc.h Executable file → Normal file
View File

@@ -1,23 +1,23 @@
/*
* arch/arm/mach-tegra/tegra21_emc.h
*
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
* arch/arm/mach-tegra/tegra21_emc.h
*
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef _EMC_H_
#define _EMC_H_

61
ipl/heap.c → bootloader/mem/heap.c Executable file → Normal file
View File

@@ -1,35 +1,23 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 M4xw
*
* 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 "heap.h"
typedef struct _hnode
{
int used;
u32 size;
struct _hnode *prev;
struct _hnode *next;
} hnode_t;
typedef struct _heap
{
u32 start;
hnode_t *first;
} heap_t;
#include "../../common/common_heap.h"
static void _heap_create(heap_t *heap, u32 start)
{
@@ -37,12 +25,12 @@ static void _heap_create(heap_t *heap, u32 start)
heap->first = NULL;
}
static u32 _heap_alloc(heap_t *heap, u32 size)
static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
{
hnode_t *node, *new;
int search = 1;
size = ALIGN(size, 0x10);
size = ALIGN(size, alignment);
if (!heap->first)
{
@@ -110,7 +98,7 @@ static void _heap_free(heap_t *heap, u32 addr)
}
}
static heap_t _heap;
heap_t _heap;
void heap_init(u32 base)
{
@@ -119,18 +107,23 @@ void heap_init(u32 base)
void *malloc(u32 size)
{
return (void *)_heap_alloc(&_heap, size);
return (void *)_heap_alloc(&_heap, size, 0x10);
}
void *memalign(u32 align, u32 size)
{
return (void *)_heap_alloc(&_heap, size, align);
}
void *calloc(u32 num, u32 size)
{
void *res = (void *)_heap_alloc(&_heap, num * size);
void *res = (void *)_heap_alloc(&_heap, num * size, 0x10);
memset(res, 0, num * size);
return res;
}
void free(void *buf)
{
if (buf != NULL)
if ((buf != NULL) || ((u32)buf > (_heap.start - 1)))
_heap_free(&_heap, (u32)buf);
}

28
bootloader/mem/heap.h Normal file
View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _HEAP_H_
#define _HEAP_H_
#include "../utils/types.h"
void heap_init(u32 base);
void *malloc(u32 size);
void *calloc(u32 num, u32 size);
void free(void *buf);
void *memalign(u32 align, u32 size);
#endif

41
ipl/mc.c → bootloader/mem/mc.c Executable file → Normal file
View File

@@ -1,9 +1,9 @@
#include "mc.h"
#include "t210.h"
#include "clock.h"
#include "util.h"
#include "../mem/mc.h"
#include "../soc/t210.h"
#include "../soc/clock.h"
#include "../utils/util.h"
void mc_config_tsec_carveout(u32 bom, u32 size1mb, int lock)
void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock)
{
MC(MC_SEC_CARVEOUT_BOM) = bom;
MC(MC_SEC_CARVEOUT_SIZE_MB) = size1mb;
@@ -20,14 +20,15 @@ void mc_config_carveout()
MC(MC_VIDEO_PROTECT_SIZE_MB) = 0;
MC(MC_VIDEO_PROTECT_REG_CTRL) = 1;
//Configure TSEC carveout @ 0x90000000, 1MB.
//mc_config_tsec_carveout(0x90000000, 1, 0);
mc_config_tsec_carveout(0, 0, 1);
// Configure TSEC carveout @ 0x90000000, 1MB.
//mc_config_tsec_carveout(0x90000000, 1, false);
mc_config_tsec_carveout(0, 0, true);
MC(MC_MTS_CARVEOUT_BOM) = 0;
MC(MC_MTS_CARVEOUT_SIZE_MB) = 0;
MC(MC_MTS_CARVEOUT_ADR_HI) = 0;
MC(MC_MTS_CARVEOUT_REG_CTRL) = 1;
MC(MC_SECURITY_CARVEOUT1_BOM) = 0;
MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0;
@@ -42,12 +43,13 @@ void mc_config_carveout()
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT1_CFG0) = 0x4000006;
MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000;
MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3000000;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3100000;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
@@ -56,6 +58,7 @@ void mc_config_carveout()
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E;
MC(MC_SECURITY_CARVEOUT3_BOM) = 0;
MC(MC_SECURITY_CARVEOUT3_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0;
@@ -70,6 +73,7 @@ void mc_config_carveout()
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT3_CFG0) = 0x4401E7E;
MC(MC_SECURITY_CARVEOUT4_BOM) = 0;
MC(MC_SECURITY_CARVEOUT4_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0;
@@ -84,6 +88,7 @@ void mc_config_carveout()
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT4_CFG0) = 0x8F;
MC(MC_SECURITY_CARVEOUT5_BOM) = 0;
MC(MC_SECURITY_CARVEOUT5_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0;
@@ -102,7 +107,8 @@ void mc_config_carveout()
void mc_enable_ahb_redirect()
{
CLOCK(0x3A4) = (CLOCK(0x3A4) & 0xFFF7FFFF) | 0x80000;
// Enable ARC_CLK_OVR_ON.
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = (CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) & 0xFFF7FFFF) | 0x80000;
//MC(MC_IRAM_REG_CTRL) &= 0xFFFFFFFE;
MC(MC_IRAM_BOM) = 0x40000000;
MC(MC_IRAM_TOM) = 0x4003F000;
@@ -112,22 +118,23 @@ void mc_disable_ahb_redirect()
{
MC(MC_IRAM_BOM) = 0xFFFFF000;
MC(MC_IRAM_TOM) = 0;
//Disable IRAM_CFG_WRITE_ACCESS (sticky).
// Disable IRAM_CFG_WRITE_ACCESS (sticky).
//MC(MC_IRAM_REG_CTRL) = MC(MC_IRAM_REG_CTRL) & 0xFFFFFFFE | 1;
CLOCK(0x3A4) &= 0xFFF7FFFF;
// Disable ARC_CLK_OVR_ON.
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= 0xFFF7FFFF;
}
void mc_enable()
{
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000;
//Enable MIPI CAL clock.
// Enable MIPI CAL clock.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000;
//Enable MC clock.
// Enable MC clock.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
//Enable EMC DLL clock.
// Enable EMC DLL clock.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & 0xFFFFBFFF) | 0x4000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x2000001; //Clear EMC and MC reset.
sleep(5);
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; //Clear EMC and MC reset.
usleep(5);
//#ifdef CONFIG_ENABLE_AHB_REDIRECT
mc_disable_ahb_redirect();

14
bootloader/mem/mc.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef _MC_H_
#define _MC_H_
#include "../utils/types.h"
#include "../mem/mc_t210.h"
void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock);
void mc_config_carveout();
void mc_config_carveout_finalize();
void mc_enable_ahb_redirect();
void mc_disable_ahb_redirect();
void mc_enable();
#endif

22
ipl/mc_t210.h → bootloader/mem/mc_t210.h Executable file → Normal file
View File

@@ -1,15 +1,15 @@
/*
* Copyright (c) 2014, NVIDIA Corporation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that 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.
*/
* Copyright (c) 2014, NVIDIA Corporation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that 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.
*/
#ifndef _MC_T210_H_
#define _MC_T210_H_

125
ipl/sdram.c → bootloader/mem/sdram.c Executable file → Normal file
View File

@@ -1,36 +1,37 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
*
* 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 "i2c.h"
#include "t210.h"
#include "../soc/i2c.h"
#include "../soc/t210.h"
#include "mc.h"
#include "emc.h"
#include "pmc.h"
#include "util.h"
#include "fuse.h"
#include "max77620.h"
#include "sdram_param_t210.h"
#include "../soc/pmc.h"
#include "../utils/util.h"
#include "../soc/fuse.h"
#include "../power/max77620.h"
#include "../mem/sdram_param_t210.h"
#include "../soc/clock.h"
#define CONFIG_SDRAM_COMPRESS_CFG
#ifdef CONFIG_SDRAM_COMPRESS_CFG
#include "lz.h"
#include "sdram_lz.inl"
#include "../libs/compr/lz.h"
#include "sdram_config_lz.inl"
#else
#include "sdram.inl"
#include "sdram_config.inl"
#endif
static u32 _get_sdram_id()
@@ -40,43 +41,43 @@ static u32 _get_sdram_id()
static void _sdram_config(const sdram_params_t *params)
{
PMC(0x45C) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
sleep(params->pmc_io_dpd3_req_wait);
PMC(APBDEV_PMC_IO_DPD3_REQ) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
usleep(params->pmc_io_dpd3_req_wait);
u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000;
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req >> 16 << 16) ^ 0x3FFF0000;
sleep(params->pmc_io_dpd4_req_wait);
usleep(params->pmc_io_dpd4_req_wait);
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF;
sleep(params->pmc_io_dpd4_req_wait);
usleep(params->pmc_io_dpd4_req_wait);
PMC(APBDEV_PMC_WEAK_BIAS) = 0;
sleep(1);
usleep(1);
CLOCK(0x98) = params->pllm_setup_control;
CLOCK(0x9C) = 0;
CLOCK(0x90) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20);
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20);
u32 wait_end = TMR(0x10) + 300;
while (!(CLOCK(0x90) & 0x8000000))
u32 wait_end = get_tmr_us() + 300;
while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000))
{
if (TMR(0x10) >= wait_end)
if (get_tmr_us() >= wait_end)
goto break_nosleep;
}
sleep(10);
usleep(10);
break_nosleep:
CLOCK(0x19C) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF);
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF);
if (params->emc_clock_source_dll)
CLOCK(0x664) = params->emc_clock_source_dll;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
if (params->clear_clock2_mc1)
CLOCK(0x44C) = 0x40000000;
CLOCK(0x328) = 0x2000001;
CLOCK(0x284) = 0x4000;
CLOCK(0x30C) = 0x2000001;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001;
EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0;
EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;
EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2;
EMC(EMC_TIMING_CONTROL) = 1;
sleep(1);
usleep(1);
EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg;
if (params->emc_bct_spare2)
*(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3;
@@ -297,7 +298,7 @@ break_nosleep:
EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;
EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
sleep(params->emc_auto_cal_wait);
usleep(params->emc_auto_cal_wait);
if (params->emc_bct_spare8)
*(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9;
EMC(EMC_CFG_2) = params->emc_cfg2;
@@ -392,8 +393,8 @@ break_nosleep:
*(vu32 *)(4 * (params->boot_rom_patch_control + 0x1C000000)) = params->boot_rom_patch_data;
MC(MC_TIMING_CONTROL) = 1;
}
PMC(0x45C) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
sleep(params->pmc_io_dpd3_req_wait);
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
usleep(params->pmc_io_dpd3_req_wait);
if (!params->emc_auto_cal_interval)
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2;
@@ -408,29 +409,29 @@ break_nosleep:
}
}
EMC(EMC_TIMING_CONTROL) = 1;
sleep(params->emc_timing_control_wait);
PMC(0x4E4) &= 0xFFF8007F;
sleep(params->pmc_ddr_ctrl_wait);
usleep(params->emc_timing_control_wait);
PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F;
usleep(params->pmc_ddr_ctrl_wait);
if (params->memory_type == 2)
{
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
sleep(params->emc_pin_extra_wait + 200);
usleep(params->emc_pin_extra_wait + 200);
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
sleep(params->emc_pin_extra_wait + 500);
usleep(params->emc_pin_extra_wait + 500);
}
if (params->memory_type == 3)
{
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
sleep(params->emc_pin_extra_wait + 200);
usleep(params->emc_pin_extra_wait + 200);
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
sleep(params->emc_pin_extra_wait + 2000);
usleep(params->emc_pin_extra_wait + 2000);
}
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 0x101;
sleep(params->emc_pin_program_wait);
usleep(params->emc_pin_program_wait);
if (params->memory_type != 3)
EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1;
if (params->memory_type == 1)
sleep(params->emc_pin_extra_wait + 200);
usleep(params->emc_pin_extra_wait + 200);
if (params->memory_type == 3)
{
if (params->emc_bct_spare10)
@@ -448,17 +449,17 @@ break_nosleep:
if (params->emc_zcal_warm_cold_boot_enables & 1)
{
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0;
sleep(params->emc_zcal_init_wait);
usleep(params->emc_zcal_init_wait);
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3;
if (!(params->emc_dev_select & 2))
{
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1;
sleep(params->emc_zcal_init_wait);
usleep(params->emc_zcal_init_wait);
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3;
}
}
}
PMC(0x1D0) = params->pmc_ddr_cfg;
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
if (params->memory_type - 1 <= 2)
{
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
@@ -485,7 +486,7 @@ break_nosleep:
MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of MC registers.
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers.
}
const void *sdram_get_params()
@@ -506,11 +507,11 @@ void sdram_init()
//TODO: sdram_id should be in [0,4].
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_SD_CFG2, 0x05);
i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_SD1, 40); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD1, 40); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
sleep(params->pmc_vddp_sel_wait);
usleep(params->pmc_vddp_sel_wait);
PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR);
PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power;
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;

24
bootloader/mem/sdram.h Normal file
View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _SDRAM_H_
#define _SDRAM_H_
void sdram_init();
const void *sdram_get_params();
void sdram_lp0_save_params(const void *params);
#endif

28
ipl/sdram.inl → bootloader/mem/sdram_config.inl Executable file → Normal file
View File

@@ -1,18 +1,18 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
static const u8 _dram_cfg_0[1896] = {
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,

28
ipl/sdram_lz.inl → bootloader/mem/sdram_config_lz.inl Executable file → Normal file
View File

@@ -1,18 +1,18 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
static const u8 _dram_cfg_lz[1262] = {
0x17, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00,

17
ipl/sdram_lp0.c → bootloader/mem/sdram_lp0.c Executable file → Normal file
View File

@@ -1,6 +1,8 @@
/*
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
* Copyright 2014 Google Inc.
* Copyright (C) 2018 naehrwert
* 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,
@@ -12,9 +14,9 @@
* more details.
*/
#include "t210.h"
#include "pmc_t210_lp0.h"
#include "sdram_param_t210_lp0.h"
#include "../soc/t210.h"
#include "../soc/pmc_lp0_t210.h"
#include "sdram_lp0_param_t210.h"
/*
* This function reads SDRAM parameters from the common BCT format and
@@ -45,7 +47,7 @@ void sdram_lp0_save_params(const void *params)
#define c32(value, pmcreg) pmc->pmcreg = value
//TODO: pkg1.1 (1.X - 3.X) reads them from MC.
//Patch carveout parameters.
// Patch carveout parameters.
/*sdram->McGeneralizedCarveout1Bom = 0;
sdram->McGeneralizedCarveout1BomHi = 0;
sdram->McGeneralizedCarveout1Size128kb = 0;
@@ -118,14 +120,14 @@ void sdram_lp0_save_params(const void *params)
sdram->McGeneralizedCarveout5Cfg0 = 0x8F;*/
//TODO: this is 4.X+ behaviour which seems to work fine for < 4.X.
//Patch carveout parameters.
// Patch carveout parameters.
sdram->McGeneralizedCarveout1Cfg0 = 0;
sdram->McGeneralizedCarveout2Cfg0 = 0;
sdram->McGeneralizedCarveout3Cfg0 = 0;
sdram->McGeneralizedCarveout4Cfg0 = 0;
sdram->McGeneralizedCarveout5Cfg0 = 0;
//Patch SDRAM parameters.
// Patch SDRAM parameters.
u32 t0 = sdram->EmcSwizzleRank0Byte0 << 5 >> 29 > sdram->EmcSwizzleRank0Byte0 << 1 >> 29;
u32 t1 = (t0 & 0xFFFFFFEF) | ((sdram->EmcSwizzleRank1Byte0 << 5 >> 29 > sdram->EmcSwizzleRank1Byte0 << 1 >> 29) << 4);
u32 t2 = (t1 & 0xFFFFFFFD) | ((sdram->EmcSwizzleRank0Byte1 << 5 >> 29 > sdram->EmcSwizzleRank0Byte1 << 1 >> 29) << 1);
@@ -835,7 +837,8 @@ void sdram_lp0_save_params(const void *params)
s(EmcAutoCalWait, 9:0, scratch101, 31:22);
s(SwizzleRankByteEncode, 15:0, scratch190, 15:0);
switch (sdram->MemoryType) {
switch (sdram->MemoryType)
{
case NvBootMemoryType_LpDdr2:
case NvBootMemoryType_LpDdr4:
s(EmcMrwLpddr2ZcalWarmBoot, 23:16, scratch5, 7:0);

View File

@@ -0,0 +1,964 @@
/*
* Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved.
* Copyright 2014 Google Inc.
* 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.
*/
/**
* Defines the SDRAM parameter structure.
*
* Note that PLLM is used by EMC. The field names are in camel case to ease
* directly converting BCT config files (*.cfg) into C structure.
*/
#ifndef __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__
#define __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__
#include "../utils/types.h"
enum
{
/* Specifies the memory type to be undefined */
NvBootMemoryType_None = 0,
/* Specifies the memory type to be DDR SDRAM */
NvBootMemoryType_Ddr = 0,
/* Specifies the memory type to be LPDDR SDRAM */
NvBootMemoryType_LpDdr = 0,
/* Specifies the memory type to be DDR2 SDRAM */
NvBootMemoryType_Ddr2 = 0,
/* Specifies the memory type to be LPDDR2 SDRAM */
NvBootMemoryType_LpDdr2,
/* Specifies the memory type to be DDR3 SDRAM */
NvBootMemoryType_Ddr3,
/* Specifies the memory type to be LPDDR4 SDRAM */
NvBootMemoryType_LpDdr4,
NvBootMemoryType_Num,
/* Specifies an entry in the ram_code table that's not in use */
NvBootMemoryType_Unused = 0X7FFFFFF,
};
/**
* Defines the SDRAM parameter structure
*/
struct sdram_params
{
/* Specifies the type of memory device */
u32 MemoryType;
/* MC/EMC clock source configuration */
/* Specifies the M value for PllM */
u32 PllMInputDivider;
/* Specifies the N value for PllM */
u32 PllMFeedbackDivider;
/* Specifies the time to wait for PLLM to lock (in microseconds) */
u32 PllMStableTime;
/* Specifies misc. control bits */
u32 PllMSetupControl;
/* Specifies the P value for PLLM */
u32 PllMPostDivider;
/* Specifies value for Charge Pump Gain Control */
u32 PllMKCP;
/* Specifies VCO gain */
u32 PllMKVCO;
/* Spare BCT param */
u32 EmcBctSpare0;
/* Spare BCT param */
u32 EmcBctSpare1;
/* Spare BCT param */
u32 EmcBctSpare2;
/* Spare BCT param */
u32 EmcBctSpare3;
/* Spare BCT param */
u32 EmcBctSpare4;
/* Spare BCT param */
u32 EmcBctSpare5;
/* Spare BCT param */
u32 EmcBctSpare6;
/* Spare BCT param */
u32 EmcBctSpare7;
/* Spare BCT param */
u32 EmcBctSpare8;
/* Spare BCT param */
u32 EmcBctSpare9;
/* Spare BCT param */
u32 EmcBctSpare10;
/* Spare BCT param */
u32 EmcBctSpare11;
/* Spare BCT param */
u32 EmcBctSpare12;
/* Spare BCT param */
u32 EmcBctSpare13;
/* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */
u32 EmcClockSource;
u32 EmcClockSourceDll;
/* Defines possible override for PLLLM_MISC2 */
u32 ClkRstControllerPllmMisc2Override;
/* enables override for PLLLM_MISC2 */
u32 ClkRstControllerPllmMisc2OverrideEnable;
/* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */
u32 ClearClk2Mc1;
/* Auto-calibration of EMC pads */
/* Specifies the value for EMC_AUTO_CAL_INTERVAL */
u32 EmcAutoCalInterval;
/*
* Specifies the value for EMC_AUTO_CAL_CONFIG
* Note: Trigger bits are set by the SDRAM code.
*/
u32 EmcAutoCalConfig;
/* Specifies the value for EMC_AUTO_CAL_CONFIG2 */
u32 EmcAutoCalConfig2;
/* Specifies the value for EMC_AUTO_CAL_CONFIG3 */
u32 EmcAutoCalConfig3;
/* Specifies the values for EMC_AUTO_CAL_CONFIG4-8 */
u32 EmcAutoCalConfig4;
u32 EmcAutoCalConfig5;
u32 EmcAutoCalConfig6;
u32 EmcAutoCalConfig7;
u32 EmcAutoCalConfig8;
/* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */
u32 EmcAutoCalVrefSel0;
u32 EmcAutoCalVrefSel1;
/* Specifies the value for EMC_AUTO_CAL_CHANNEL */
u32 EmcAutoCalChannel;
/* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */
u32 EmcPmacroAutocalCfg0;
u32 EmcPmacroAutocalCfg1;
u32 EmcPmacroAutocalCfg2;
u32 EmcPmacroRxTerm;
u32 EmcPmacroDqTxDrv;
u32 EmcPmacroCaTxDrv;
u32 EmcPmacroCmdTxDrv;
u32 EmcPmacroAutocalCfgCommon;
u32 EmcPmacroZctrl;
/*
* Specifies the time for the calibration
* to stabilize (in microseconds)
*/
u32 EmcAutoCalWait;
u32 EmcXm2CompPadCtrl;
u32 EmcXm2CompPadCtrl2;
u32 EmcXm2CompPadCtrl3;
/*
* DRAM size information
* Specifies the value for EMC_ADR_CFG
*/
u32 EmcAdrCfg;
/*
* Specifies the time to wait after asserting pin
* CKE (in microseconds)
*/
u32 EmcPinProgramWait;
/* Specifies the extra delay before/after pin RESET/CKE command */
u32 EmcPinExtraWait;
u32 EmcPinGpioEn;
u32 EmcPinGpio;
/*
* Specifies the extra delay after the first writing
* of EMC_TIMING_CONTROL
*/
u32 EmcTimingControlWait;
/* Timing parameters required for the SDRAM */
/* Specifies the value for EMC_RC */
u32 EmcRc;
/* Specifies the value for EMC_RFC */
u32 EmcRfc;
/* Specifies the value for EMC_RFC_PB */
u32 EmcRfcPb;
/* Specifies the value for EMC_RFC_CTRL2 */
u32 EmcRefctrl2;
/* Specifies the value for EMC_RFC_SLR */
u32 EmcRfcSlr;
/* Specifies the value for EMC_RAS */
u32 EmcRas;
/* Specifies the value for EMC_RP */
u32 EmcRp;
/* Specifies the value for EMC_R2R */
u32 EmcR2r;
/* Specifies the value for EMC_W2W */
u32 EmcW2w;
/* Specifies the value for EMC_R2W */
u32 EmcR2w;
/* Specifies the value for EMC_W2R */
u32 EmcW2r;
/* Specifies the value for EMC_R2P */
u32 EmcR2p;
/* Specifies the value for EMC_W2P */
u32 EmcW2p;
u32 EmcTppd;
u32 EmcCcdmw;
/* Specifies the value for EMC_RD_RCD */
u32 EmcRdRcd;
/* Specifies the value for EMC_WR_RCD */
u32 EmcWrRcd;
/* Specifies the value for EMC_RRD */
u32 EmcRrd;
/* Specifies the value for EMC_REXT */
u32 EmcRext;
/* Specifies the value for EMC_WEXT */
u32 EmcWext;
/* Specifies the value for EMC_WDV */
u32 EmcWdv;
u32 EmcWdvChk;
u32 EmcWsv;
u32 EmcWev;
/* Specifies the value for EMC_WDV_MASK */
u32 EmcWdvMask;
u32 EmcWsDuration;
u32 EmcWeDuration;
/* Specifies the value for EMC_QUSE */
u32 EmcQUse;
/* Specifies the value for EMC_QUSE_WIDTH */
u32 EmcQuseWidth;
/* Specifies the value for EMC_IBDLY */
u32 EmcIbdly;
/* Specifies the value for EMC_OBDLY */
u32 EmcObdly;
/* Specifies the value for EMC_EINPUT */
u32 EmcEInput;
/* Specifies the value for EMC_EINPUT_DURATION */
u32 EmcEInputDuration;
/* Specifies the value for EMC_PUTERM_EXTRA */
u32 EmcPutermExtra;
/* Specifies the value for EMC_PUTERM_WIDTH */
u32 EmcPutermWidth;
/* Specifies the value for EMC_PUTERM_ADJ */
////u32 EmcPutermAdj;
/* Specifies the value for EMC_QRST */
u32 EmcQRst;
/* Specifies the value for EMC_QSAFE */
u32 EmcQSafe;
/* Specifies the value for EMC_RDV */
u32 EmcRdv;
/* Specifies the value for EMC_RDV_MASK */
u32 EmcRdvMask;
/* Specifies the value for EMC_RDV_EARLY */
u32 EmcRdvEarly;
/* Specifies the value for EMC_RDV_EARLY_MASK */
u32 EmcRdvEarlyMask;
/* Specifies the value for EMC_QPOP */
u32 EmcQpop;
/* Specifies the value for EMC_REFRESH */
u32 EmcRefresh;
/* Specifies the value for EMC_BURST_REFRESH_NUM */
u32 EmcBurstRefreshNum;
/* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */
u32 EmcPreRefreshReqCnt;
/* Specifies the value for EMC_PDEX2WR */
u32 EmcPdEx2Wr;
/* Specifies the value for EMC_PDEX2RD */
u32 EmcPdEx2Rd;
/* Specifies the value for EMC_PCHG2PDEN */
u32 EmcPChg2Pden;
/* Specifies the value for EMC_ACT2PDEN */
u32 EmcAct2Pden;
/* Specifies the value for EMC_AR2PDEN */
u32 EmcAr2Pden;
/* Specifies the value for EMC_RW2PDEN */
u32 EmcRw2Pden;
/* Specifies the value for EMC_CKE2PDEN */
u32 EmcCke2Pden;
/* Specifies the value for EMC_PDEX2CKE */
u32 EmcPdex2Cke;
/* Specifies the value for EMC_PDEX2MRR */
u32 EmcPdex2Mrr;
/* Specifies the value for EMC_TXSR */
u32 EmcTxsr;
/* Specifies the value for EMC_TXSRDLL */
u32 EmcTxsrDll;
/* Specifies the value for EMC_TCKE */
u32 EmcTcke;
/* Specifies the value for EMC_TCKESR */
u32 EmcTckesr;
/* Specifies the value for EMC_TPD */
u32 EmcTpd;
/* Specifies the value for EMC_TFAW */
u32 EmcTfaw;
/* Specifies the value for EMC_TRPAB */
u32 EmcTrpab;
/* Specifies the value for EMC_TCLKSTABLE */
u32 EmcTClkStable;
/* Specifies the value for EMC_TCLKSTOP */
u32 EmcTClkStop;
/* Specifies the value for EMC_TREFBW */
u32 EmcTRefBw;
/* FBIO configuration values */
/* Specifies the value for EMC_FBIO_CFG5 */
u32 EmcFbioCfg5;
/* Specifies the value for EMC_FBIO_CFG7 */
u32 EmcFbioCfg7;
/* Specifies the value for EMC_FBIO_CFG8 */
u32 EmcFbioCfg8;
/* Command mapping for CMD brick 0 */
u32 EmcCmdMappingCmd0_0;
u32 EmcCmdMappingCmd0_1;
u32 EmcCmdMappingCmd0_2;
u32 EmcCmdMappingCmd1_0;
u32 EmcCmdMappingCmd1_1;
u32 EmcCmdMappingCmd1_2;
u32 EmcCmdMappingCmd2_0;
u32 EmcCmdMappingCmd2_1;
u32 EmcCmdMappingCmd2_2;
u32 EmcCmdMappingCmd3_0;
u32 EmcCmdMappingCmd3_1;
u32 EmcCmdMappingCmd3_2;
u32 EmcCmdMappingByte;
/* Specifies the value for EMC_FBIO_SPARE */
u32 EmcFbioSpare;
/* Specifies the value for EMC_CFG_RSV */
u32 EmcCfgRsv;
/* MRS command values */
/* Specifies the value for EMC_MRS */
u32 EmcMrs;
/* Specifies the MP0 command to initialize mode registers */
u32 EmcEmrs;
/* Specifies the MP2 command to initialize mode registers */
u32 EmcEmrs2;
/* Specifies the MP3 command to initialize mode registers */
u32 EmcEmrs3;
/* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */
u32 EmcMrw1;
/* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */
u32 EmcMrw2;
/* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */
u32 EmcMrw3;
/* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */
u32 EmcMrw4;
/* Specifies the programming to LPDDR2 Mode Register 3? at cold boot */
u32 EmcMrw6;
/* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */
u32 EmcMrw8;
/* Specifies the programming to LPDDR2 Mode Register 11? at cold boot */
u32 EmcMrw9;
/* Specifies the programming to LPDDR2 Mode Register 12 at cold boot */
u32 EmcMrw10;
/* Specifies the programming to LPDDR2 Mode Register 14 at cold boot */
u32 EmcMrw12;
/* Specifies the programming to LPDDR2 Mode Register 14? at cold boot */
u32 EmcMrw13;
/* Specifies the programming to LPDDR2 Mode Register 22 at cold boot */
u32 EmcMrw14;
/*
* Specifies the programming to extra LPDDR2 Mode Register
* at cold boot
*/
u32 EmcMrwExtra;
/*
* Specifies the programming to extra LPDDR2 Mode Register
* at warm boot
*/
u32 EmcWarmBootMrwExtra;
/*
* Specify the enable of extra Mode Register programming at
* warm boot
*/
u32 EmcWarmBootExtraModeRegWriteEnable;
/*
* Specify the enable of extra Mode Register programming at
* cold boot
*/
u32 EmcExtraModeRegWriteEnable;
/* Specifies the EMC_MRW reset command value */
u32 EmcMrwResetCommand;
/* Specifies the EMC Reset wait time (in microseconds) */
u32 EmcMrwResetNInitWait;
/* Specifies the value for EMC_MRS_WAIT_CNT */
u32 EmcMrsWaitCnt;
/* Specifies the value for EMC_MRS_WAIT_CNT2 */
u32 EmcMrsWaitCnt2;
/* EMC miscellaneous configurations */
/* Specifies the value for EMC_CFG */
u32 EmcCfg;
/* Specifies the value for EMC_CFG_2 */
u32 EmcCfg2;
/* Specifies the pipe bypass controls */
u32 EmcCfgPipe;
u32 EmcCfgPipeClk;
u32 EmcFdpdCtrlCmdNoRamp;
u32 EmcCfgUpdate;
/* Specifies the value for EMC_DBG */
u32 EmcDbg;
u32 EmcDbgWriteMux;
/* Specifies the value for EMC_CMDQ */
u32 EmcCmdQ;
/* Specifies the value for EMC_MC2EMCQ */
u32 EmcMc2EmcQ;
/* Specifies the value for EMC_DYN_SELF_REF_CONTROL */
u32 EmcDynSelfRefControl;
/* Specifies the value for MEM_INIT_DONE */
u32 AhbArbitrationXbarCtrlMemInitDone;
/* Specifies the value for EMC_CFG_DIG_DLL */
u32 EmcCfgDigDll;
u32 EmcCfgDigDll_1;
/* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */
u32 EmcCfgDigDllPeriod;
/* Specifies the value of *DEV_SELECTN of various EMC registers */
u32 EmcDevSelect;
/* Specifies the value for EMC_SEL_DPD_CTRL */
u32 EmcSelDpdCtrl;
/* Pads trimmer delays */
u32 EmcFdpdCtrlDq;
u32 EmcFdpdCtrlCmd;
u32 EmcPmacroIbVrefDq_0;
u32 EmcPmacroIbVrefDq_1;
u32 EmcPmacroIbVrefDqs_0;
u32 EmcPmacroIbVrefDqs_1;
u32 EmcPmacroIbRxrt;
u32 EmcCfgPipe1;
u32 EmcCfgPipe2;
/* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */
u32 EmcPmacroQuseDdllRank0_0;
u32 EmcPmacroQuseDdllRank0_1;
u32 EmcPmacroQuseDdllRank0_2;
u32 EmcPmacroQuseDdllRank0_3;
u32 EmcPmacroQuseDdllRank0_4;
u32 EmcPmacroQuseDdllRank0_5;
u32 EmcPmacroQuseDdllRank1_0;
u32 EmcPmacroQuseDdllRank1_1;
u32 EmcPmacroQuseDdllRank1_2;
u32 EmcPmacroQuseDdllRank1_3;
u32 EmcPmacroQuseDdllRank1_4;
u32 EmcPmacroQuseDdllRank1_5;
u32 EmcPmacroObDdllLongDqRank0_0;
u32 EmcPmacroObDdllLongDqRank0_1;
u32 EmcPmacroObDdllLongDqRank0_2;
u32 EmcPmacroObDdllLongDqRank0_3;
u32 EmcPmacroObDdllLongDqRank0_4;
u32 EmcPmacroObDdllLongDqRank0_5;
u32 EmcPmacroObDdllLongDqRank1_0;
u32 EmcPmacroObDdllLongDqRank1_1;
u32 EmcPmacroObDdllLongDqRank1_2;
u32 EmcPmacroObDdllLongDqRank1_3;
u32 EmcPmacroObDdllLongDqRank1_4;
u32 EmcPmacroObDdllLongDqRank1_5;
u32 EmcPmacroObDdllLongDqsRank0_0;
u32 EmcPmacroObDdllLongDqsRank0_1;
u32 EmcPmacroObDdllLongDqsRank0_2;
u32 EmcPmacroObDdllLongDqsRank0_3;
u32 EmcPmacroObDdllLongDqsRank0_4;
u32 EmcPmacroObDdllLongDqsRank0_5;
u32 EmcPmacroObDdllLongDqsRank1_0;
u32 EmcPmacroObDdllLongDqsRank1_1;
u32 EmcPmacroObDdllLongDqsRank1_2;
u32 EmcPmacroObDdllLongDqsRank1_3;
u32 EmcPmacroObDdllLongDqsRank1_4;
u32 EmcPmacroObDdllLongDqsRank1_5;
u32 EmcPmacroIbDdllLongDqsRank0_0;
u32 EmcPmacroIbDdllLongDqsRank0_1;
u32 EmcPmacroIbDdllLongDqsRank0_2;
u32 EmcPmacroIbDdllLongDqsRank0_3;
u32 EmcPmacroIbDdllLongDqsRank1_0;
u32 EmcPmacroIbDdllLongDqsRank1_1;
u32 EmcPmacroIbDdllLongDqsRank1_2;
u32 EmcPmacroIbDdllLongDqsRank1_3;
u32 EmcPmacroDdllLongCmd_0;
u32 EmcPmacroDdllLongCmd_1;
u32 EmcPmacroDdllLongCmd_2;
u32 EmcPmacroDdllLongCmd_3;
u32 EmcPmacroDdllLongCmd_4;
u32 EmcPmacroDdllShortCmd_0;
u32 EmcPmacroDdllShortCmd_1;
u32 EmcPmacroDdllShortCmd_2;
/*
* Specifies the delay after asserting CKE pin during a WarmBoot0
* sequence (in microseconds)
*/
u32 WarmBootWait;
/* Specifies the value for EMC_ODT_WRITE */
u32 EmcOdtWrite;
/* Periodic ZQ calibration */
/*
* Specifies the value for EMC_ZCAL_INTERVAL
* Value 0 disables ZQ calibration
*/
u32 EmcZcalInterval;
/* Specifies the value for EMC_ZCAL_WAIT_CNT */
u32 EmcZcalWaitCnt;
/* Specifies the value for EMC_ZCAL_MRW_CMD */
u32 EmcZcalMrwCmd;
/* DRAM initialization sequence flow control */
/* Specifies the MRS command value for resetting DLL */
u32 EmcMrsResetDll;
/* Specifies the command for ZQ initialization of device 0 */
u32 EmcZcalInitDev0;
/* Specifies the command for ZQ initialization of device 1 */
u32 EmcZcalInitDev1;
/*
* Specifies the wait time after programming a ZQ initialization
* command (in microseconds)
*/
u32 EmcZcalInitWait;
/*
* Specifies the enable for ZQ calibration at cold boot [bit 0]
* and warm boot [bit 1]
*/
u32 EmcZcalWarmColdBootEnables;
/*
* Specifies the MRW command to LPDDR2 for ZQ calibration
* on warmboot
*/
/* Is issued to both devices separately */
u32 EmcMrwLpddr2ZcalWarmBoot;
/*
* Specifies the ZQ command to DDR3 for ZQ calibration on warmboot
* Is issued to both devices separately
*/
u32 EmcZqCalDdr3WarmBoot;
u32 EmcZqCalLpDdr4WarmBoot;
/*
* Specifies the wait time for ZQ calibration on warmboot
* (in microseconds)
*/
u32 EmcZcalWarmBootWait;
/*
* Specifies the enable for DRAM Mode Register programming
* at warm boot
*/
u32 EmcMrsWarmBootEnable;
/*
* Specifies the wait time after sending an MRS DLL reset command
* in microseconds)
*/
u32 EmcMrsResetDllWait;
/* Specifies the extra MRS command to initialize mode registers */
u32 EmcMrsExtra;
/* Specifies the extra MRS command at warm boot */
u32 EmcWarmBootMrsExtra;
/* Specifies the EMRS command to enable the DDR2 DLL */
u32 EmcEmrsDdr2DllEnable;
/* Specifies the MRS command to reset the DDR2 DLL */
u32 EmcMrsDdr2DllReset;
/* Specifies the EMRS command to set OCD calibration */
u32 EmcEmrsDdr2OcdCalib;
/*
* Specifies the wait between initializing DDR and setting OCD
* calibration (in microseconds)
*/
u32 EmcDdr2Wait;
/* Specifies the value for EMC_CLKEN_OVERRIDE */
u32 EmcClkenOverride;
/*
* Specifies LOG2 of the extra refresh numbers after booting
* Program 0 to disable
*/
u32 EmcExtraRefreshNum;
/* Specifies the master override for all EMC clocks */
u32 EmcClkenOverrideAllWarmBoot;
/* Specifies the master override for all MC clocks */
u32 McClkenOverrideAllWarmBoot;
/* Specifies digital dll period, choosing between 4 to 64 ms */
u32 EmcCfgDigDllPeriodWarmBoot;
/* Pad controls */
/* Specifies the value for PMC_VDDP_SEL */
u32 PmcVddpSel;
/* Specifies the wait time after programming PMC_VDDP_SEL */
u32 PmcVddpSelWait;
/* Specifies the value for PMC_DDR_PWR */
u32 PmcDdrPwr;
/* Specifies the value for PMC_DDR_CFG */
u32 PmcDdrCfg;
/* Specifies the value for PMC_IO_DPD3_REQ */
u32 PmcIoDpd3Req;
/* Specifies the wait time after programming PMC_IO_DPD3_REQ */
u32 PmcIoDpd3ReqWait;
u32 PmcIoDpd4ReqWait;
/* Specifies the value for PMC_REG_SHORT */
u32 PmcRegShort;
/* Specifies the value for PMC_NO_IOPOWER */
u32 PmcNoIoPower;
u32 PmcDdrCntrlWait;
u32 PmcDdrCntrl;
/* Specifies the value for EMC_ACPD_CONTROL */
u32 EmcAcpdControl;
/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE_CFG */
////u32 EmcSwizzleRank0ByteCfg;
/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */
u32 EmcSwizzleRank0Byte0;
/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */
u32 EmcSwizzleRank0Byte1;
/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */
u32 EmcSwizzleRank0Byte2;
/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */
u32 EmcSwizzleRank0Byte3;
/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE_CFG */
////u32 EmcSwizzleRank1ByteCfg;
/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */
u32 EmcSwizzleRank1Byte0;
/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */
u32 EmcSwizzleRank1Byte1;
/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */
u32 EmcSwizzleRank1Byte2;
/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */
u32 EmcSwizzleRank1Byte3;
/* Specifies the value for EMC_TXDSRVTTGEN */
u32 EmcTxdsrvttgen;
/* Specifies the value for EMC_DATA_BRLSHFT_0 */
u32 EmcDataBrlshft0;
u32 EmcDataBrlshft1;
u32 EmcDqsBrlshft0;
u32 EmcDqsBrlshft1;
u32 EmcCmdBrlshft0;
u32 EmcCmdBrlshft1;
u32 EmcCmdBrlshft2;
u32 EmcCmdBrlshft3;
u32 EmcQuseBrlshft0;
u32 EmcQuseBrlshft1;
u32 EmcQuseBrlshft2;
u32 EmcQuseBrlshft3;
u32 EmcDllCfg0;
u32 EmcDllCfg1;
u32 EmcPmcScratch1;
u32 EmcPmcScratch2;
u32 EmcPmcScratch3;
u32 EmcPmacroPadCfgCtrl;
u32 EmcPmacroVttgenCtrl0;
u32 EmcPmacroVttgenCtrl1;
u32 EmcPmacroVttgenCtrl2;
u32 EmcPmacroBrickCtrlRfu1;
u32 EmcPmacroCmdBrickCtrlFdpd;
u32 EmcPmacroBrickCtrlRfu2;
u32 EmcPmacroDataBrickCtrlFdpd;
u32 EmcPmacroBgBiasCtrl0;
u32 EmcPmacroDataPadRxCtrl;
u32 EmcPmacroCmdPadRxCtrl;
u32 EmcPmacroDataRxTermMode;
u32 EmcPmacroCmdRxTermMode;
u32 EmcPmacroDataPadTxCtrl;
u32 EmcPmacroCommonPadTxCtrl;
u32 EmcPmacroCmdPadTxCtrl;
u32 EmcCfg3;
u32 EmcPmacroTxPwrd0;
u32 EmcPmacroTxPwrd1;
u32 EmcPmacroTxPwrd2;
u32 EmcPmacroTxPwrd3;
u32 EmcPmacroTxPwrd4;
u32 EmcPmacroTxPwrd5;
u32 EmcConfigSampleDelay;
u32 EmcPmacroBrickMapping0;
u32 EmcPmacroBrickMapping1;
u32 EmcPmacroBrickMapping2;
u32 EmcPmacroTxSelClkSrc0;
u32 EmcPmacroTxSelClkSrc1;
u32 EmcPmacroTxSelClkSrc2;
u32 EmcPmacroTxSelClkSrc3;
u32 EmcPmacroTxSelClkSrc4;
u32 EmcPmacroTxSelClkSrc5;
u32 EmcPmacroDdllBypass;
u32 EmcPmacroDdllPwrd0;
u32 EmcPmacroDdllPwrd1;
u32 EmcPmacroDdllPwrd2;
u32 EmcPmacroCmdCtrl0;
u32 EmcPmacroCmdCtrl1;
u32 EmcPmacroCmdCtrl2;
/* DRAM size information */
/* Specifies the value for MC_EMEM_ADR_CFG */
u32 McEmemAdrCfg;
/* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */
u32 McEmemAdrCfgDev0;
/* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */
u32 McEmemAdrCfgDev1;
u32 McEmemAdrCfgChannelMask;
/* Specifies the value for MC_EMEM_BANK_SWIZZLECfg0 */
u32 McEmemAdrCfgBankMask0;
/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */
u32 McEmemAdrCfgBankMask1;
/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */
u32 McEmemAdrCfgBankMask2;
/*
* Specifies the value for MC_EMEM_CFG which holds the external memory
* size (in KBytes)
*/
u32 McEmemCfg;
/* MC arbitration configuration */
/* Specifies the value for MC_EMEM_ARB_CFG */
u32 McEmemArbCfg;
/* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */
u32 McEmemArbOutstandingReq;
u32 McEmemArbRefpbHpCtrl;
u32 McEmemArbRefpbBankCtrl;
/* Specifies the value for MC_EMEM_ARB_TIMING_RCD */
u32 McEmemArbTimingRcd;
/* Specifies the value for MC_EMEM_ARB_TIMING_RP */
u32 McEmemArbTimingRp;
/* Specifies the value for MC_EMEM_ARB_TIMING_RC */
u32 McEmemArbTimingRc;
/* Specifies the value for MC_EMEM_ARB_TIMING_RAS */
u32 McEmemArbTimingRas;
/* Specifies the value for MC_EMEM_ARB_TIMING_FAW */
u32 McEmemArbTimingFaw;
/* Specifies the value for MC_EMEM_ARB_TIMING_RRD */
u32 McEmemArbTimingRrd;
/* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */
u32 McEmemArbTimingRap2Pre;
/* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */
u32 McEmemArbTimingWap2Pre;
/* Specifies the value for MC_EMEM_ARB_TIMING_R2R */
u32 McEmemArbTimingR2R;
/* Specifies the value for MC_EMEM_ARB_TIMING_W2W */
u32 McEmemArbTimingW2W;
/* Specifies the value for MC_EMEM_ARB_TIMING_R2W */
u32 McEmemArbTimingR2W;
/* Specifies the value for MC_EMEM_ARB_TIMING_W2R */
u32 McEmemArbTimingW2R;
u32 McEmemArbTimingRFCPB;
/* Specifies the value for MC_EMEM_ARB_DA_TURNS */
u32 McEmemArbDaTurns;
/* Specifies the value for MC_EMEM_ARB_DA_COVERS */
u32 McEmemArbDaCovers;
/* Specifies the value for MC_EMEM_ARB_MISC0 */
u32 McEmemArbMisc0;
/* Specifies the value for MC_EMEM_ARB_MISC1 */
u32 McEmemArbMisc1;
u32 McEmemArbMisc2;
/* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */
u32 McEmemArbRing1Throttle;
/* Specifies the value for MC_EMEM_ARB_OVERRIDE */
u32 McEmemArbOverride;
/* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */
u32 McEmemArbOverride1;
/* Specifies the value for MC_EMEM_ARB_RSV */
u32 McEmemArbRsv;
u32 McDaCfg0;
u32 McEmemArbTimingCcdmw;
/* Specifies the value for MC_CLKEN_OVERRIDE */
u32 McClkenOverride;
/* Specifies the value for MC_STAT_CONTROL */
u32 McStatControl;
/* Specifies the value for MC_VIDEO_PROTECT_BOM */
u32 McVideoProtectBom;
/* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */
u32 McVideoProtectBomAdrHi;
/* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */
u32 McVideoProtectSizeMb;
/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */
u32 McVideoProtectVprOverride;
/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */
u32 McVideoProtectVprOverride1;
/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */
u32 McVideoProtectGpuOverride0;
/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */
u32 McVideoProtectGpuOverride1;
/* Specifies the value for MC_SEC_CARVEOUT_BOM */
u32 McSecCarveoutBom;
/* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */
u32 McSecCarveoutAdrHi;
/* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */
u32 McSecCarveoutSizeMb;
/* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.
VIDEO_PROTECT_WRITEAccess */
u32 McVideoProtectWriteAccess;
/* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.
SEC_CARVEOUT_WRITEAccess */
u32 McSecCarveoutProtectWriteAccess;
/* Write-Protect Regions (WPR) */
u32 McGeneralizedCarveout1Bom;
u32 McGeneralizedCarveout1BomHi;
u32 McGeneralizedCarveout1Size128kb;
u32 McGeneralizedCarveout1Access0;
u32 McGeneralizedCarveout1Access1;
u32 McGeneralizedCarveout1Access2;
u32 McGeneralizedCarveout1Access3;
u32 McGeneralizedCarveout1Access4;
u32 McGeneralizedCarveout1ForceInternalAccess0;
u32 McGeneralizedCarveout1ForceInternalAccess1;
u32 McGeneralizedCarveout1ForceInternalAccess2;
u32 McGeneralizedCarveout1ForceInternalAccess3;
u32 McGeneralizedCarveout1ForceInternalAccess4;
u32 McGeneralizedCarveout1Cfg0;
u32 McGeneralizedCarveout2Bom;
u32 McGeneralizedCarveout2BomHi;
u32 McGeneralizedCarveout2Size128kb;
u32 McGeneralizedCarveout2Access0;
u32 McGeneralizedCarveout2Access1;
u32 McGeneralizedCarveout2Access2;
u32 McGeneralizedCarveout2Access3;
u32 McGeneralizedCarveout2Access4;
u32 McGeneralizedCarveout2ForceInternalAccess0;
u32 McGeneralizedCarveout2ForceInternalAccess1;
u32 McGeneralizedCarveout2ForceInternalAccess2;
u32 McGeneralizedCarveout2ForceInternalAccess3;
u32 McGeneralizedCarveout2ForceInternalAccess4;
u32 McGeneralizedCarveout2Cfg0;
u32 McGeneralizedCarveout3Bom;
u32 McGeneralizedCarveout3BomHi;
u32 McGeneralizedCarveout3Size128kb;
u32 McGeneralizedCarveout3Access0;
u32 McGeneralizedCarveout3Access1;
u32 McGeneralizedCarveout3Access2;
u32 McGeneralizedCarveout3Access3;
u32 McGeneralizedCarveout3Access4;
u32 McGeneralizedCarveout3ForceInternalAccess0;
u32 McGeneralizedCarveout3ForceInternalAccess1;
u32 McGeneralizedCarveout3ForceInternalAccess2;
u32 McGeneralizedCarveout3ForceInternalAccess3;
u32 McGeneralizedCarveout3ForceInternalAccess4;
u32 McGeneralizedCarveout3Cfg0;
u32 McGeneralizedCarveout4Bom;
u32 McGeneralizedCarveout4BomHi;
u32 McGeneralizedCarveout4Size128kb;
u32 McGeneralizedCarveout4Access0;
u32 McGeneralizedCarveout4Access1;
u32 McGeneralizedCarveout4Access2;
u32 McGeneralizedCarveout4Access3;
u32 McGeneralizedCarveout4Access4;
u32 McGeneralizedCarveout4ForceInternalAccess0;
u32 McGeneralizedCarveout4ForceInternalAccess1;
u32 McGeneralizedCarveout4ForceInternalAccess2;
u32 McGeneralizedCarveout4ForceInternalAccess3;
u32 McGeneralizedCarveout4ForceInternalAccess4;
u32 McGeneralizedCarveout4Cfg0;
u32 McGeneralizedCarveout5Bom;
u32 McGeneralizedCarveout5BomHi;
u32 McGeneralizedCarveout5Size128kb;
u32 McGeneralizedCarveout5Access0;
u32 McGeneralizedCarveout5Access1;
u32 McGeneralizedCarveout5Access2;
u32 McGeneralizedCarveout5Access3;
u32 McGeneralizedCarveout5Access4;
u32 McGeneralizedCarveout5ForceInternalAccess0;
u32 McGeneralizedCarveout5ForceInternalAccess1;
u32 McGeneralizedCarveout5ForceInternalAccess2;
u32 McGeneralizedCarveout5ForceInternalAccess3;
u32 McGeneralizedCarveout5ForceInternalAccess4;
u32 McGeneralizedCarveout5Cfg0;
/* Specifies enable for CA training */
u32 EmcCaTrainingEnable;
/* Set if bit 6 select is greater than bit 7 select; uses aremc.
spec packet SWIZZLE_BIT6_GT_BIT7 */
u32 SwizzleRankByteEncode;
/* Specifies enable and offset for patched boot ROM write */
u32 BootRomPatchControl;
/* Specifies data for patched boot ROM write */
u32 BootRomPatchData;
/* Specifies the value for MC_MTS_CARVEOUT_BOM */
u32 McMtsCarveoutBom;
/* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */
u32 McMtsCarveoutAdrHi;
/* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */
u32 McMtsCarveoutSizeMb;
/* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */
u32 McMtsCarveoutRegCtrl;
/* End */
};
#endif /* __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ */

View File

@@ -37,7 +37,8 @@
/**
* Defines the SDRAM parameter structure
*/
typedef struct _sdram_params {
typedef struct _sdram_params
{
/* Specifies the type of memory device */
u32 memory_type;

162
bootloader/power/bq24193.c Normal file
View File

@@ -0,0 +1,162 @@
/*
* Battery charger driver for Nintendo Switch's TI BQ24193
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "bq24193.h"
#include "../soc/i2c.h"
#include "../utils/util.h"
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
{
u8 data;
switch (prop) {
case BQ24193_InputVoltageLimit: // Input voltage limit (mV).
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource);
data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3;
*value += ((data >> 0) & 1) ? 80 : 0;
*value += ((data >> 1) & 1) ? 160 : 0;
*value += ((data >> 2) & 1) ? 320 : 0;
*value += ((data >> 3) & 1) ? 640 : 0;
*value += 3880;
break;
case BQ24193_InputCurrentLimit: // Input current limit (mA).
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource);
data &= BQ24193_INCONFIG_INLIMIT_MASK;
switch (data)
{
case 0:
*value = 100;
break;
case 1:
*value = 150;
break;
case 2:
*value = 500;
break;
case 3:
*value = 900;
break;
case 4:
*value = 1200;
break;
case 5:
*value = 1500;
break;
case 6:
*value = 2000;
break;
case 7:
*value = 3000;
break;
}
break;
case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV).
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig);
*value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1;
*value *= 100;
*value += 3000;
break;
case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA).
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr);
data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2;
*value += ((data >> 0) & 1) ? 64 : 0;
*value += ((data >> 1) & 1) ? 128 : 0;
*value += ((data >> 2) & 1) ? 256 : 0;
*value += ((data >> 3) & 1) ? 512 : 0;
*value += ((data >> 4) & 1) ? 1024 : 0;
*value += ((data >> 5) & 1) ? 2048 : 0;
*value += 512;
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr);
data &= BQ24193_CHRGCURR_20PCT_MASK;
if (data)
*value = *value * 20 / 100; // Fast charge current limit is 20%.
break;
case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV).
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
*value += ((data >> 0) & 1) ? 16 : 0;
*value += ((data >> 1) & 1) ? 32 : 0;
*value += ((data >> 2) & 1) ? 64 : 0;
*value += ((data >> 3) & 1) ? 128 : 0;
*value += ((data >> 4) & 1) ? 256 : 0;
*value += ((data >> 5) & 1) ? 512 : 0;
*value += 3504;
break;
case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV).
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
data &= BQ24193_IRTHERMAL_THERM_MASK;
if (data)
*value = 300;
else
*value = 100;
break;
case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC).
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_IRCompThermal);
data &= BQ24193_IRTHERMAL_THERM_MASK;
switch (data)
{
case 0:
*value = 60;
break;
case 1:
*value = 80;
break;
case 2:
*value = 100;
break;
case 3:
*value = 120;
break;
}
break;
case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Status);
*value = (data & BQ24193_STATUS_CHRG_MASK) >> 4;
break;
case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot.
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_FaultReg);
*value = data & BQ24193_FAULT_THERM_MASK;
break;
case BQ24193_DevID: // Dev ID.
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart);
*value = data & BQ24193_VENDORPART_DEV_MASK;
break;
case BQ24193_ProductNumber: // Product number.
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart);
*value = (data & BQ24193_VENDORPART_PN_MASK) >> 3;
break;
default:
return -1;
}
return 0;
}
void bq24193_fake_battery_removal()
{
u8 value;
// Disable watchdog to keep BATFET disabled.
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer);
value &= ~BQ24193_CHRGTERM_WATCHDOG_MASK;
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer, value);
// Force BATFET to disabled state. This disconnects the battery from the system.
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc);
value |= BQ24193_MISC_BATFET_DI_MASK;
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value);
}

119
bootloader/power/bq24193.h Normal file
View File

@@ -0,0 +1,119 @@
/*
* Battery charger driver for Nintendo Switch's TI BQ24193
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef __BQ24193_H_
#define __BQ24193_H_
#define BQ24193_I2C_ADDR 0x6B
// REG 0 masks.
#define BQ24193_INCONFIG_INLIMIT_MASK (7<<0)
#define BQ24193_INCONFIG_VINDPM_MASK 0x78
#define BQ24193_INCONFIG_HIZ_EN_MASK (1<<7)
// REG 1 masks.
#define BQ24193_PORCONFIG_BOOST_MASK (1<<0)
#define BQ24193_PORCONFIG_SYSMIN_MASK (7<<1)
#define BQ24193_PORCONFIG_CHGCONFIG_MASK (3<<4)
#define BQ24193_PORCONFIG_I2CWATCHDOG_MASK (1<<6)
#define BQ24193_PORCONFIG_RESET_MASK (1<<7)
// REG 2 masks.
#define BQ24193_CHRGCURR_20PCT_MASK (1<<0)
#define BQ24193_CHRGCURR_ICHG_MASK 0xFC
// REG 3 masks.
#define BQ24193_PRECHRG_ITERM 0x0F
#define BQ24193_PRECHRG_IPRECHG 0xF0
// REG 4 masks.
#define BQ24193_CHRGVOLT_VTHRES (1<<0)
#define BQ24193_CHRGVOLT_BATTLOW (1<<1)
#define BQ24193_CHRGVOLT_VREG 0xFC
// REG 5 masks.
#define BQ24193_CHRGTERM_ISET_MASK (1<<0)
#define BQ24193_CHRGTERM_CHGTIMER_MASK (3<<1)
#define BQ24193_CHRGTERM_ENTIMER_MASK (1<<3)
#define BQ24193_CHRGTERM_WATCHDOG_MASK (3<<4)
#define BQ24193_CHRGTERM_TERM_ST_MASK (1<<6)
#define BQ24193_CHRGTERM_TERM_EN_MASK (1<<7)
// REG 6 masks.
#define BQ24193_IRTHERMAL_THERM_MASK (3<<0)
#define BQ24193_IRTHERMAL_VCLAMP_MASK (7<<2)
#define BQ24193_IRTHERMAL_BATTCOMP_MASK (7<<5)
// REG 7 masks.
#define BQ24193_MISC_INT_MASK (3<<0)
#define BQ24193_MISC_VSET_MASK (1<<4)
#define BQ24193_MISC_BATFET_DI_MASK (1<<5)
#define BQ24193_MISC_TMR2X_EN_MASK (1<<6)
#define BQ24193_MISC_DPDM_EN_MASK (1<<7)
// REG 8 masks.
#define BQ24193_STATUS_VSYS_MASK (1<<0)
#define BQ24193_STATUS_THERM_MASK (1<<1)
#define BQ24193_STATUS_PG_MASK (1<<2)
#define BQ24193_STATUS_DPM_MASK (1<<3)
#define BQ24193_STATUS_CHRG_MASK (3<<4)
#define BQ24193_STATUS_VBUS_MASK (3<<6)
// REG 9 masks.
#define BQ24193_FAULT_THERM_MASK (7<<0)
#define BQ24193_FAULT_BATT_OVP_MASK (1<<3)
#define BQ24193_FAULT_CHARGE_MASK (3<<4)
#define BQ24193_FAULT_BOOST_MASK (1<<6)
#define BQ24193_FAULT_WATCHDOG_MASK (1<<7)
// REG A masks.
#define BQ24193_VENDORPART_DEV_MASK (3<<0)
#define BQ24193_VENDORPART_PN_MASK (7<<3)
enum BQ24193_reg {
BQ24193_InputSource = 0x00,
BQ24193_PORConfig = 0x01,
BQ24193_ChrgCurr = 0x02,
BQ24193_PreChrgTerm = 0x03,
BQ24193_ChrgVolt = 0x04,
BQ24193_ChrgTermTimer = 0x05,
BQ24193_IRCompThermal = 0x06,
BQ24193_Misc = 0x07,
BQ24193_Status = 0x08,
BQ24193_FaultReg = 0x09,
BQ24193_VendorPart = 0x0A,
};
enum BQ24193_reg_prop {
BQ24193_InputVoltageLimit, // REG 0.
BQ24193_InputCurrentLimit, // REG 0.
BQ24193_SystemMinimumVoltage, // REG 1.
BQ24193_FastChargeCurrentLimit, // REG 2.
BQ24193_ChargeVoltageLimit, // REG 4.
BQ24193_RechargeThreshold, // REG 4.
BQ24193_ThermalRegulation, // REG 6.
BQ24193_ChargeStatus, // REG 8.
BQ24193_TempStatus, // REG 9.
BQ24193_DevID, // REG A.
BQ24193_ProductNumber, // REG A.
};
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value);
void bq24193_fake_battery_removal();
#endif /* __BQ24193_H_ */

266
bootloader/power/max17050.c Normal file
View File

@@ -0,0 +1,266 @@
/*
* Fuel gauge driver for Nintendo Switch's Maxim 17050
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
* Copyright (C) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This driver is based on max17040_battery.c
*/
#include "max17050.h"
#include "../soc/i2c.h"
#include "../utils/util.h"
/* Status register bits */
#define STATUS_POR_BIT (1 << 1)
#define STATUS_BST_BIT (1 << 3)
#define STATUS_VMN_BIT (1 << 8)
#define STATUS_TMN_BIT (1 << 9)
#define STATUS_SMN_BIT (1 << 10)
#define STATUS_BI_BIT (1 << 11)
#define STATUS_VMX_BIT (1 << 12)
#define STATUS_TMX_BIT (1 << 13)
#define STATUS_SMX_BIT (1 << 14)
#define STATUS_BR_BIT (1 << 15)
#define VFSOC0_LOCK 0x0000
#define VFSOC0_UNLOCK 0x0080
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
int max17050_get_property(enum MAX17050_reg reg, int *value)
{
u16 data;
switch (reg)
{
case MAX17050_Age: // Age (percent). Based on 100% x (FullCAP Register/DesignCap).
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Age);
*value = data >> 8; /* Show MSB. 1% increments */
break;
case MAX17050_Cycles: // Cycle count.
i2c_recv_buf_small((u8 *)value, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Cycles);
break;
case MAX17050_MinVolt: // Voltage max/min
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MinMaxVolt);
*value = (data & 0xff) * 20; /* Voltage MIN. Units of 20mV */
break;
case MAX17050_MaxVolt: // Voltage max/min
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MinMaxVolt);
*value = (data >> 8) * 20; /* Voltage MAX. Units of LSB = 20mV */
break;
case MAX17050_V_empty: // Voltage min design.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_V_empty);
*value = (data >> 7) * 10; /* Units of LSB = 10mV */
break;
case MAX17050_VCELL: // Voltage now.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL);
*value = data * 625 / 8 / 1000;
break;
case MAX17050_AvgVCELL: // Voltage avg.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL);
*value = data * 625 / 8 / 1000;
break;
case MAX17050_OCVInternal: // Voltage ocv.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_OCVInternal);
*value = data * 625 / 8 / 1000;
break;
case MAX17050_RepSOC: // Capacity %.
i2c_recv_buf_small((u8 *)value, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepSOC);
break;
case MAX17050_DesignCap: // Charge full design.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap);
data = data * 5 / 10;
*value = data;
break;
case MAX17050_FullCAP: // Charge full.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FullCAP);
data = data * 5 / 10;
*value = data;
break;
case MAX17050_RepCap: // Charge now.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepCap);
data = data * 5 / 10;
*value = data;
break;
case MAX17050_TEMP: // Temp.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_TEMP);
*value = (s16)data;
*value = *value * 10 / 256;
break;
case MAX17050_Current: // Current now.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Current);
*value = (s16)data;
*value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR;
break;
case MAX17050_AvgCurrent: // Current avg.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgCurrent);
*value = (s16)data;
*value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR;
break;
default:
return -1;
}
return 0;
}
static int _max17050_write_verify_reg(u8 reg, u16 value)
{
int retries = 8;
int ret;
u16 read_value;
do
{
ret = i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2);
i2c_recv_buf_small((u8 *)&read_value, 2, I2C_1, MAXIM17050_I2C_ADDR, reg);
if (read_value != value)
{
ret = -1;
retries--;
}
} while (retries && read_value != value);
return ret;
}
static void _max17050_override_por(u8 reg, u16 value)
{
if (value)
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2);
}
static void _max17050_load_new_capacity_params()
{
u16 fullcap, repSoc, dq_acc, dp_acc;
fullcap = 0x2476; // 4667mAh design capacity.
dq_acc = 0x10bc; // From a healthy fuel gauge.
dp_acc = 0x5e09; // =||=
repSoc = 0x6400; // 100%.
_max17050_write_verify_reg(MAX17050_RemCap, fullcap);
_max17050_write_verify_reg(MAX17050_RepCap, fullcap);
_max17050_write_verify_reg(MAX17050_dQacc, dq_acc);
_max17050_write_verify_reg(MAX17050_dPacc, dp_acc);
_max17050_write_verify_reg(MAX17050_FullCAP, fullcap);
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, (u8 *)&fullcap, 2);
_max17050_write_verify_reg(MAX17050_FullCAPNom, fullcap);
/* Update SOC register with new SOC */
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepSOC, (u8 *)&repSoc, 2);
}
static void _max17050_reset_vfsoc0_reg()
{
u16 lockVal = 0;
u16 vfSoc = 0x6440; // >100% for fully charged battery
lockVal = VFSOC0_UNLOCK;
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2);
_max17050_write_verify_reg(MAX17050_VFSOC0, vfSoc);
lockVal = VFSOC0_LOCK;
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2);
}
static void _max17050_update_capacity_regs()
{
u16 value = 0x2476; // Set to 4667mAh design capacity.
_max17050_write_verify_reg(MAX17050_FullCAP, value);
_max17050_write_verify_reg(MAX17050_FullCAPNom, value);
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, config->design_cap, 2);
}
static void _max17050_write_config_regs()
{
u16 value = 0;
value = 0x7254;
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_CONFIG, (u8 *)&value, 2);
value = 0x2473;
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_LearnCFG, (u8 *)&value, 2);
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FilterCFG, (u8 *)&value, 2)
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RelaxCFG, (u8 *)&value, 2)
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FullSOCThr, (u8 *)&value, 2)
}
/*
* Block write all the override values coming from platform data.
* This function MUST be called before the POR initialization proceedure
* specified by maxim.
*/
static void _max17050_override_por_values()
{
u16 dq_acc = 0x10bc; // From a healthy fuel gauge.
u16 dp_acc = 0x5e09; // =||=
_max17050_override_por(MAX17050_dQacc, dq_acc);
_max17050_override_por(MAX17050_dPacc, dp_acc);
//_max17050_override_por(MAX17050_RCOMP0, config->rcomp0); //0x58
//_max17050_override_por(MAX17050_TempCo, config->tcompc0); //0x1b22
//u16 k_empty0 = 0x439;
//_max17050_override_por(map, MAX17050_K_empty0, k_empty0); // Unknown cell data
}
static void _max17050_set_por_bit(u16 value)
{
_max17050_write_verify_reg(MAX17050_STATUS, value);
}
int max17050_fix_configuration()
{
/* Init phase, set the POR bit */
_max17050_set_por_bit(STATUS_POR_BIT);
/* Override POR values */
_max17050_override_por_values();
/* After Power up, the MAX17050 requires 500ms in order
* to perform signal debouncing and initial SOC reporting
*/
msleep(500);
/* Initialize configaration */
_max17050_write_config_regs();
/* update capacity params */
_max17050_update_capacity_regs();
/* delay must be atleast 350mS to allow VFSOC
* to be calculated from the new configuration
*/
msleep(350);
/* reset vfsoc0 reg */
_max17050_reset_vfsoc0_reg();
/* load new capacity params */
_max17050_load_new_capacity_params();
/* Init complete, Clear the POR bit */
//_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR?
// Sets POR, BI, BR.
_max17050_set_por_bit(0x8801);
return 0;
}

127
bootloader/power/max17050.h Normal file
View File

@@ -0,0 +1,127 @@
/*
* Fuel gauge driver for Nintendo Switch's Maxim 17050
* Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
* Copyright (C) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __MAX17050_H_
#define __MAX17050_H_
#define MAX17050_STATUS_BattAbsent (1 << 3)
#define MAX17050_DEFAULT_SNS_RESISTOR 10000
/* Consider RepCap which is less then 10 units below FullCAP full */
#define MAX17050_FULL_THRESHOLD 10
#define MAX17050_CHARACTERIZATION_DATA_SIZE 48
#define MAXIM17050_I2C_ADDR 0x36
enum MAX17050_reg {
MAX17050_STATUS = 0x00,
MAX17050_VALRT_Th = 0x01,
MAX17050_TALRT_Th = 0x02,
MAX17050_SALRT_Th = 0x03,
MAX17050_AtRate = 0x04,
MAX17050_RepCap = 0x05,
MAX17050_RepSOC = 0x06,
MAX17050_Age = 0x07,
MAX17050_TEMP = 0x08,
MAX17050_VCELL = 0x09,
MAX17050_Current = 0x0A,
MAX17050_AvgCurrent = 0x0B,
MAX17050_SOC = 0x0D,
MAX17050_AvSOC = 0x0E,
MAX17050_RemCap = 0x0F,
MAX17050_FullCAP = 0x10,
MAX17050_TTE = 0x11,
MAX17050_QRTbl00 = 0x12,
MAX17050_FullSOCThr = 0x13,
MAX17050_RSLOW = 0x14,
MAX17050_AvgTA = 0x16,
MAX17050_Cycles = 0x17,
MAX17050_DesignCap = 0x18,
MAX17050_AvgVCELL = 0x19,
MAX17050_MinMaxTemp = 0x1A,
MAX17050_MinMaxVolt = 0x1B,
MAX17050_MinMaxCurr = 0x1C,
MAX17050_CONFIG = 0x1D,
MAX17050_ICHGTerm = 0x1E,
MAX17050_AvCap = 0x1F,
MAX17050_ManName = 0x20,
MAX17050_DevName = 0x21,
MAX17050_QRTbl10 = 0x22,
MAX17050_FullCAPNom = 0x23,
MAX17050_TempNom = 0x24,
MAX17050_TempLim = 0x25,
MAX17050_TempHot = 0x26,
MAX17050_AIN = 0x27,
MAX17050_LearnCFG = 0x28,
MAX17050_FilterCFG = 0x29,
MAX17050_RelaxCFG = 0x2A,
MAX17050_MiscCFG = 0x2B,
MAX17050_TGAIN = 0x2C,
MAX17050_TOFF = 0x2D,
MAX17050_CGAIN = 0x2E,
MAX17050_COFF = 0x2F,
MAX17050_QRTbl20 = 0x32,
MAX17050_SOC_empty = 0x33,
MAX17050_T_empty = 0x34,
MAX17050_FullCAP0 = 0x35,
MAX17050_LAvg_empty = 0x36,
MAX17050_FCTC = 0x37,
MAX17050_RCOMP0 = 0x38,
MAX17050_TempCo = 0x39,
MAX17050_V_empty = 0x3A,
MAX17050_K_empty0 = 0x3B,
MAX17050_TaskPeriod = 0x3C,
MAX17050_FSTAT = 0x3D,
MAX17050_SHDNTIMER = 0x3F,
MAX17050_QRTbl30 = 0x42,
MAX17050_dQacc = 0x45,
MAX17050_dPacc = 0x46,
MAX17050_VFSOC0 = 0x48,
MAX17050_QH = 0x4D,
MAX17050_QL = 0x4E,
MAX17050_MinVolt = 0x50, // Custom ID. Not to be sent to i2c.
MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c.
MAX17050_VFSOC0Enable = 0x60,
MAX17050_MODELChrTbl = 0x80,
MAX17050_OCV = 0xEE,
MAX17050_OCVInternal = 0xFB,
MAX17050_VFSOC = 0xFF,
};
int max17050_get_property(enum MAX17050_reg reg, int *value);
int max17050_fix_configuration();
#endif /* __MAX17050_H_ */

4
ipl/max77620.h → bootloader/power/max77620.h Executable file → Normal file
View File

@@ -11,6 +11,8 @@
#ifndef _MFD_MAX77620_H_
#define _MFD_MAX77620_H_
#define MAX77620_I2C_ADDR 0x3C
/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */
#define MAX77620_REG_CNFGGLBL1 0x00
#define MAX77620_REG_CNFGGLBL2 0x01
@@ -265,7 +267,9 @@
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4)
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1)
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
/* CNFG BBC registers */

65
ipl/max7762x.c → bootloader/power/max7762x.c Executable file → Normal file
View File

@@ -1,28 +1,23 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
*
* 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 "max7762x.h"
#include "max77620.h"
#include "i2c.h"
#include "util.h"
#include "gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#include "../soc/i2c.h"
#include "../utils/util.h"
#define REGULATOR_SD 0
#define REGULATOR_LDO 1
@@ -73,8 +68,8 @@ int max77620_regulator_get_status(u32 id)
const max77620_regulator_t *reg = &_pmic_regulators[id];
if (reg->type == REGULATOR_SD)
return (i2c_recv_byte(I2C_5, 0x3C, MAX77620_REG_STATSD) & reg->status_mask) ? 0 : 1;
return (i2c_recv_byte(I2C_5, 0x3C, reg->cfg_addr) & 8) ? 1 : 0;
return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_STATSD) & reg->status_mask) ? 0 : 1;
return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->cfg_addr) & 8) ? 1 : 0;
}
int max77620_regulator_config_fps(u32 id)
@@ -84,7 +79,7 @@ int max77620_regulator_config_fps(u32 id)
const max77620_regulator_t *reg = &_pmic_regulators[id];
i2c_send_byte(I2C_5, 0x3C, reg->fps_addr, (reg->fps_src << 6) | (reg->pu_period << 3) | (reg->pd_period));
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr, (reg->fps_src << 6) | (reg->pu_period << 3) | (reg->pd_period));
return 1;
}
@@ -100,10 +95,10 @@ int max77620_regulator_set_voltage(u32 id, u32 mv)
return 0;
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
u8 val = i2c_recv_byte(I2C_5, 0x3C, reg->volt_addr);
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr);
val = (val & ~reg->volt_mask) | (mult & reg->volt_mask);
i2c_send_byte(I2C_5, 0x3C, reg->volt_addr, val);
sleep(1000);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
usleep(1000);
return 1;
}
@@ -116,13 +111,13 @@ int max77620_regulator_enable(u32 id, int enable)
const max77620_regulator_t *reg = &_pmic_regulators[id];
u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr;
u8 val = i2c_recv_byte(I2C_5, 0x3C, addr);
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, addr);
if (enable)
val = (val & ~reg->enable_mask) | ((3 << reg->enable_shift) & reg->enable_mask);
else
val &= ~reg->enable_mask;
i2c_send_byte(I2C_5, 0x3C, addr, val);
sleep(1000);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val);
usleep(1000);
return 1;
}
@@ -131,11 +126,17 @@ void max77620_config_default()
{
for (u32 i = 1; i <= REGULATOR_MAX; i++)
{
i2c_recv_byte(I2C_5, 0x3C, MAX77620_REG_CID4);
i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4);
max77620_regulator_config_fps(i);
max77620_regulator_set_voltage(i, _pmic_regulators[i].mv_default);
if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE)
max77620_regulator_enable(i, 1);
}
i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_SD_CFG2, 4);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 4);
}
void max77620_low_battery_monitor_config()
{
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1,
MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_LBHYST_N | MAX77620_CNFGGLBL1_LBDAC_N);
}

114
bootloader/power/max7762x.h Normal file
View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _MAX7762X_H_
#define _MAX7762X_H_
#include "../utils/types.h"
/*
* Switch Power domains (max77620):
* Name | Usage | uV step | uV min | uV default | uV max | Init
*-------+---------------+---------+--------+------------+---------+------------------
* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1)
* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
* ldo3 | | 50000 | 800000 | 3100000 | 3100000 |
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
* ldo5 | | 50000 | 800000 | 1800000 | 1800000 |
* ldo6 | | 50000 | 800000 | 2900000 | 2900000 |
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
*/
/*
* MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode
* MAX77620_REG_GPIOx: 0x9 sets output and enable
*/
/*! MAX77620 partitions. */
#define REGULATOR_SD0 0
#define REGULATOR_SD1 1
#define REGULATOR_SD2 2
#define REGULATOR_SD3 3
#define REGULATOR_LDO0 4
#define REGULATOR_LDO1 5
#define REGULATOR_LDO2 6
#define REGULATOR_LDO3 7
#define REGULATOR_LDO4 8
#define REGULATOR_LDO5 9
#define REGULATOR_LDO6 10
#define REGULATOR_LDO7 11
#define REGULATOR_LDO8 12
#define REGULATOR_MAX 12
#define MAX77621_CPU_I2C_ADDR 0x1B
#define MAX77621_GPU_I2C_ADDR 0x1C
#define MAX77621_VOUT_REG 0
#define MAX77621_VOUT_DVC_REG 1
#define MAX77621_CONTROL1_REG 2
#define MAX77621_CONTROL2_REG 3
/* MAX77621_VOUT */
#define MAX77621_VOUT_ENABLE (1 << 7)
#define MAX77621_VOUT_MASK 0x7F
/* MAX77621_VOUT_DVC_DVS */
#define MAX77621_DVS_VOUT_MASK 0x7F
/* MAX77621_CONTROL1 */
#define MAX77621_SNS_ENABLE (1 << 7)
#define MAX77621_FPWM_EN_M (1 << 6)
#define MAX77621_NFSR_ENABLE (1 << 5)
#define MAX77621_AD_ENABLE (1 << 4)
#define MAX77621_BIAS_ENABLE (1 << 3)
#define MAX77621_FREQSHIFT_9PER (1 << 2)
#define MAX77621_RAMP_12mV_PER_US 0x0
#define MAX77621_RAMP_25mV_PER_US 0x1
#define MAX77621_RAMP_50mV_PER_US 0x2
#define MAX77621_RAMP_200mV_PER_US 0x3
#define MAX77621_RAMP_MASK 0x3
/* MAX77621_CONTROL2 */
#define MAX77621_WDTMR_ENABLE (1 << 6)
#define MAX77621_DISCH_ENBABLE (1 << 5)
#define MAX77621_FT_ENABLE (1 << 4)
#define MAX77621_T_JUNCTION_120 (1 << 7)
#define MAX77621_CKKADV_TRIP_DISABLE 0xC
#define MAX77621_CKKADV_TRIP_75mV_PER_US 0x0
#define MAX77621_CKKADV_TRIP_150mV_PER_US 0x4
#define MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8
#define MAX77621_INDUCTOR_MIN_30_PER 0x0
#define MAX77621_INDUCTOR_NOMINAL 0x1
#define MAX77621_INDUCTOR_PLUS_30_PER 0x2
#define MAX77621_INDUCTOR_PLUS_60_PER 0x3
int max77620_regulator_get_status(u32 id);
int max77620_regulator_config_fps(u32 id);
int max77620_regulator_set_voltage(u32 id, u32 mv);
int max77620_regulator_enable(u32 id, int enable);
void max77620_config_default();
void max77620_low_battery_monitor_config();
#endif

34
bootloader/reloc.S Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
/*
* TODO: the placement of the relocator is a bit fragile atm, maybe we
* should include it in start.S and copy it to some known good
* place in IRAM instead. Basically we want it as far back atm
* as it might be overwritten during relocation.
*/
.section .text.reloc
.arm
.globl _reloc_ipl
.type _reloc_ipl, %function
_reloc_ipl:
LDMIA R0!, {R4-R7}
STMIA R1!, {R4-R7}
SUBS R2, #0x10
BNE _reloc_ipl
BX R3

73
ipl/se.c → bootloader/sec/se.c Executable file → Normal file
View File

@@ -1,24 +1,28 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 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 "se.h"
#include "heap.h"
#include "t210.h"
#include "se_t210.h"
#include "../sec/se.h"
#include "../mem/heap.h"
#include "../soc/t210.h"
#include "../sec/se_t210.h"
#include "../utils/util.h"
typedef struct _se_ll_t
{
@@ -101,6 +105,9 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src
static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
{
if (!src || !dst)
return 0;
u8 *block = (u8 *)malloc(0x10);
memset(block, 0, 0x10);
@@ -160,7 +167,9 @@ int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst);
return _se_execute(OP_START, NULL, 0, input, 0x10);
}
@@ -254,3 +263,31 @@ int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u
return 1;
}
// se_calc_sha256() was derived from Atmosphère's se_calculate_sha256.
int se_calc_sha256(void *dst, const void *src, u32 src_size)
{
int res;
// Setup config for SHA256, size = BITS(src_size).
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_SHA_CONFIG_REG_OFFSET) = 1;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3);
SE(0x208) = 0;
SE(0x20C) = 0;
SE(0x210) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3);
SE(0x218) = 0;
SE(0x21C) = 0;
SE(0x220) = 0;
// Trigger the operation.
res = _se_execute(OP_START, NULL, 0, src, src_size);
// Copy output hash.
u32 *dst32 = (u32 *)dst;
for (u32 i = 0; i < 8; i++)
dst32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2)));
return res;
}

3
ipl/se.h → bootloader/sec/se.h Executable file → Normal file
View File

@@ -17,7 +17,7 @@
#ifndef _SE_H_
#define _SE_H_
#include "types.h"
#include "../utils/types.h"
void se_rsa_acc_ctrl(u32 rs, u32 flags);
void se_key_acc_ctrl(u32 ks, u32 flags);
@@ -26,5 +26,6 @@ void se_aes_key_clear(u32 ks);
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
int se_calc_sha256(void *dst, const void *src, u32 src_size);
#endif

2
ipl/se_t210.h → bootloader/sec/se_t210.h Executable file → Normal file
View File

@@ -21,7 +21,7 @@
#ifndef _CRYPTO_TEGRA_SE_H
#define _CRYPTO_TEGRA_SE_H
#include "types.h"
#include "../utils/types.h"
#define TEGRA_SE_CRA_PRIORITY 300
#define TEGRA_SE_COMPOSITE_PRIORITY 400

272
bootloader/sec/tsec.c Normal file
View File

@@ -0,0 +1,272 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* 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 "../sec/tsec.h"
#include "../sec/tsec_t210.h"
#include "../sec/se_t210.h"
#include "../soc/clock.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../mem/heap.h"
#include "../mem/mc.h"
#include "../utils/util.h"
#include "../hos/hos.h"
/* #include "../gfx/gfx.h"
extern gfx_con_t gfx_con; */
static int _tsec_dma_wait_idle()
{
u32 timeout = get_tmr_ms() + 10000;
while (!(TSEC(TSEC_DMATRFCMD) & TSEC_DMATRFCMD_IDLE))
if (get_tmr_ms() > timeout)
return 0;
return 1;
}
static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offset)
{
u32 cmd;
if (not_imem)
cmd = TSEC_DMATRFCMD_SIZE_256B; // DMA 256 bytes
else
cmd = TSEC_DMATRFCMD_IMEM; // DMA IMEM (Instruction memmory)
TSEC(TSEC_DMATRFMOFFS) = i_offset;
TSEC(TSEC_DMATRFFBOFFS) = pa_offset;
TSEC(TSEC_DMATRFCMD) = cmd;
return _tsec_dma_wait_idle();
}
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
{
int res = 0;
u8 *fwbuf = NULL;
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
//Enable clocks.
clock_enable_host1x();
clock_enable_tsec();
clock_enable_sor_safe();
clock_enable_sor0();
clock_enable_sor1();
clock_enable_kfuse();
//Configure Falcon.
TSEC(TSEC_DMACTL) = 0;
TSEC(TSEC_IRQMSET) =
TSEC_IRQMSET_EXT(0xFF) |
TSEC_IRQMSET_WDTMR |
TSEC_IRQMSET_HALT |
TSEC_IRQMSET_EXTERR |
TSEC_IRQMSET_SWGEN0 |
TSEC_IRQMSET_SWGEN1;
TSEC(TSEC_IRQDEST) =
TSEC_IRQDEST_EXT(0xFF) |
TSEC_IRQDEST_HALT |
TSEC_IRQDEST_EXTERR |
TSEC_IRQDEST_SWGEN0 |
TSEC_IRQDEST_SWGEN1;
TSEC(TSEC_ITFEN) = TSEC_ITFEN_CTXEN | TSEC_ITFEN_MTHDEN;
if (!_tsec_dma_wait_idle())
{
res = -1;
goto out;
}
//Load firmware or emulate memio environment for newer TSEC fw.
if (kb <= KB_FIRMWARE_VERSION_600)
{
fwbuf = (u8 *)malloc(0x2000);
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf + 0x1000, 0x100);
memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size);
TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8;
}
else
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
for (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100)
{
if (!_tsec_dma_pa_to_internal_100(false, addr, addr))
{
res = -2;
goto out_free;
}
}
if (kb >= KB_FIRMWARE_VERSION_620)
{
// Init SMMU translation for TSEC.
pdir = smmu_init_for_tsec();
smmu_init(tsec_ctxt->secmon_base);
// Enable SMMU
if (!smmu_is_used())
smmu_enable();
// Clock reset controller.
car = page_alloc(1);
memcpy(car, (void *)CLOCK_BASE, 0x1000);
car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2;
smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE);
// Fuse driver.
fuse = page_alloc(1);
memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400);
fuse[0x82C / 4] = 0;
fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1;
fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1;
smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE);
// Power management controller.
pmc = page_alloc(1);
smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE);
// Flow control.
flowctrl = page_alloc(1);
smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE);
// Security engine.
se = page_alloc(1);
memcpy(se, (void *)SE_BASE, 0x1000);
smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE);
// Memory controller.
mc = page_alloc(1);
memcpy(mc, (void *)MC_BASE, 0x1000);
mc[MC_IRAM_BOM / 4] = 0;
mc[MC_IRAM_TOM / 4] = 0x80000000;
smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE);
// IRAM
iram = page_alloc(0x30);
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
// Exception vectors
evec = page_alloc(1);
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
}
//Execute firmware.
HOST1X(0x3300) = 0x34C2E1DA;
TSEC(TSEC_STATUS) = 0;
TSEC(TSEC_BOOTKEYVER) = tsec_ctxt->key_ver;
TSEC(TSEC_BOOTVEC) = 0;
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
if (kb <= KB_FIRMWARE_VERSION_600)
{
if (!_tsec_dma_wait_idle())
{
res = -3;
goto out_free;
}
u32 timeout = get_tmr_ms() + 2000;
while (!TSEC(TSEC_STATUS))
if (get_tmr_ms() > timeout)
{
res = -4;
goto out_free;
}
if (TSEC(TSEC_STATUS) != 0xB0B0B0B0)
{
res = -5;
goto out_free;
}
//Fetch result.
HOST1X(0x3300) = 0;
u32 buf[4];
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB);
buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB);
buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB);
SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0;
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0;
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0;
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0;
memcpy(tsec_keys, &buf, 0x10);
}
else
{
u32 start = get_tmr_us();
u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
u32 key[16] = {0};
u32 kidx = 0;
while (memcmp((u8 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4)), "PK11", 4))
{
smmu_flush_all();
if (k == se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
continue;
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
key[kidx++] = k;
// Failsafe.
if ((u32)get_tmr_us() - start > 500000)
break;
}
if (kidx != 8)
{
res = -6;
smmu_deinit_for_tsec();
goto out;
}
memcpy(tsec_keys, &key, 0x20);
memcpy(tsec_ctxt->pkg1, iram, 0x30000);
smmu_deinit_for_tsec();
// for (int i = 0; i < kidx; i++)
// gfx_printf(&gfx_con, "key %08X\n", key[i]);
// gfx_printf(&gfx_con, "cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
// u32 errst = MC(MC_ERR_STATUS);
// gfx_printf(&gfx_con, " MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
// gfx_printf(&gfx_con, " type: %02X\n", errst >> 28);
// gfx_printf(&gfx_con, " smmu: %02X\n", (errst >> 25) & 3);
// gfx_printf(&gfx_con, " dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
// gfx_printf(&gfx_con, " cid: %02x\n", errst & 0xFF);
}
out_free:;
free(fwbuf);
out:;
//Disable clocks.
clock_disable_kfuse();
clock_disable_sor1();
clock_disable_sor0();
clock_disable_sor_safe();
clock_disable_tsec();
clock_disable_host1x();
return res;
}

15
ipl/tsec.h → bootloader/sec/tsec.h Executable file → Normal file
View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* 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,
@@ -17,8 +18,18 @@
#ifndef _TSEC_H_
#define _TSEC_H_
#include "types.h"
#include "../utils/types.h"
int tsec_query(u8 *dst, u32 rev, void *fw);
typedef struct _tsec_ctxt_t
{
u32 key_ver;
void *fw;
u32 size;
void *pkg1;
u32 pkg11_off;
u32 secmon_base;
} tsec_ctxt_t;
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt);
#endif

View File

@@ -0,0 +1,50 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _TSEC_T210_H_
#define _TSEC_T210_H_
#define TSEC_BOOTKEYVER 0x1040
#define TSEC_STATUS 0x1044
#define TSEC_ITFEN 0x1048
#define TSEC_ITFEN_CTXEN (1 << 0)
#define TSEC_ITFEN_MTHDEN (1 << 1)
#define TSEC_IRQMSET 0x1010
#define TSEC_IRQMSET_WDTMR (1 << 1)
#define TSEC_IRQMSET_HALT (1 << 4)
#define TSEC_IRQMSET_EXTERR (1 << 5)
#define TSEC_IRQMSET_SWGEN0 (1 << 6)
#define TSEC_IRQMSET_SWGEN1 (1 << 7)
#define TSEC_IRQMSET_EXT(val) (((val) & 0xFF) << 8)
#define TSEC_IRQDEST 0x101C
#define TSEC_IRQDEST_HALT (1 << 4)
#define TSEC_IRQDEST_EXTERR (1 << 5)
#define TSEC_IRQDEST_SWGEN0 (1 << 6)
#define TSEC_IRQDEST_SWGEN1 (1 << 7)
#define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8)
#define TSEC_CPUCTL 0x1100
#define TSEC_CPUCTL_STARTCPU (1 << 1)
#define TSEC_BOOTVEC 0x1104
#define TSEC_DMACTL 0x110C
#define TSEC_DMATRFBASE 0x1110
#define TSEC_DMATRFMOFFS 0x1114
#define TSEC_DMATRFCMD 0x1118
#define TSEC_DMATRFCMD_IDLE (1 << 1)
#define TSEC_DMATRFCMD_IMEM (1 << 4)
#define TSEC_DMATRFCMD_SIZE_256B (6 << 8)
#define TSEC_DMATRFFBOFFS 0x111C
#endif

212
ipl/clock.c → bootloader/soc/clock.c Executable file → Normal file
View File

@@ -1,77 +1,104 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
*
* 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 "clock.h"
#include "t210.h"
#include "util.h"
#include "sdmmc.h"
#include "../soc/clock.h"
#include "../soc/t210.h"
#include "../utils/util.h"
#include "../storage/sdmmc.h"
static const clock_t _clock_uart[] = {
/* UART A */ { 4, 0x10, 0x178, 6, 0, 0 },
/* UART B */ { 4, 0x10, 0x17C, 7, 0, 0 },
/* UART C */ { 8, 0x14, 0x1A0, 0x17, 0, 0 },
/* clock_t: reset, enable, source, index, clk_src, clk_div */
static const clock_t _clock_uart[] = {
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
/* UART D */ { 0 },
/* UART E */ { 0 }
};
static const clock_t _clock_i2c[] = {
/* I2C1 */ { 4, 0x10, 0x124, 0xC, 6, 0 },
/* I2C2 */ { 0 },
/* I2C3 */ { 0 },
/* I2C4 */ { 0 },
/* I2C5 */ { 8, 0x14, 0x128, 0xF, 6, 0 },
/* I2C6 */ { 0 }
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 0xC, 6, 0 },
/* I2C2 */ { 0 },
/* I2C3 */ { 0 },
/* I2C4 */ { 0 },
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 0xF, 6, 0 },
/* I2C6 */ { 0 }
};
static clock_t _clock_se = { 0x358, 0x360, 0x42C, 0x1F, 0, 0 };
static clock_t _clock_se = {
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 0x1F, 0, 0
};
static clock_t _clock_unk2 = {
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 0x1E, 0, 0
};
static clock_t _clock_host1x = { 4, 0x10, 0x180, 0x1C, 4, 3 };
static clock_t _clock_tsec = { 0xC, 0x18, 0x1F4, 0x13, 0, 2 };
static clock_t _clock_sor_safe = { 0x2A4, 0x298, 0, 0x1E, 0, 0 };
static clock_t _clock_sor0 = { 0x28C, 0x280, 0, 0x16, 0, 0 };
static clock_t _clock_sor1 = { 0x28C, 0x280, 0x410, 0x17, 0, 2 };
static clock_t _clock_kfuse = { 8, 0x14, 0, 8, 0, 0 };
static clock_t _clock_host1x = {
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 4, 3
};
static clock_t _clock_tsec = {
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 0x13, 0, 2
};
static clock_t _clock_sor_safe = {
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 0x1E, 0, 0
};
static clock_t _clock_sor0 = {
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 0x16, 0, 0
};
static clock_t _clock_sor1 = {
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 0x17, 0, 2
};
static clock_t _clock_kfuse = {
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0
};
static clock_t _clock_cl_dvfs = { 0x35C, 0x364, 0, 0x1B, 0, 0 };
static clock_t _clock_coresight = { 0xC, 0x18, 0x1D4, 9, 0, 4};
static clock_t _clock_cl_dvfs = {
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 0x1B, 0, 0
};
static clock_t _clock_coresight = {
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4
};
static clock_t _clock_pwm = {
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 0x11, 6, 4
};
void clock_enable(const clock_t *clk)
{
//Put clock into reset.
// Put clock into reset.
CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index);
//Disable.
// Disable.
CLOCK(clk->enable) &= ~(1 << clk->index);
//Configure clock source if required.
// Configure clock source if required.
if (clk->source)
CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29);
//Enable.
// Enable.
CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index);
//Take clock off reset.
// Take clock off reset.
CLOCK(clk->reset) &= ~(1 << clk->index);
}
void clock_disable(const clock_t *clk)
{
//Put clock into reset.
// Put clock into reset.
CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index);
//Disable.
// Disable.
CLOCK(clk->enable) &= ~(1 << clk->index);
}
void clock_enable_fuse(u32 enable)
void clock_enable_fuse(bool enable)
{
CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) = (CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) & 0xEFFFFFFF) | ((enable & 1) << 28);
}
@@ -86,11 +113,21 @@ void clock_enable_i2c(u32 idx)
clock_enable(&_clock_i2c[idx]);
}
void clock_disable_i2c(u32 idx)
{
clock_disable(&_clock_i2c[idx]);
}
void clock_enable_se()
{
clock_enable(&_clock_se);
}
void clock_enable_unk2()
{
clock_enable(&_clock_unk2);
}
void clock_enable_host1x()
{
clock_enable(&_clock_host1x);
@@ -144,12 +181,12 @@ void clock_disable_sor1()
void clock_enable_kfuse()
{
//clock_enable(&_clock_kfuse);
CLOCK(0x8) = (CLOCK(0x8) & 0xFFFFFEFF) | 0x100;
CLOCK(0x14) &= 0xFFFFFEFF;
CLOCK(0x14) = (CLOCK(0x14) & 0xFFFFFEFF) | 0x100;
sleep(10);
CLOCK(0x8) &= 0xFFFFFEFF;
sleep(20);
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & 0xFFFFFEFF) | 0x100;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= 0xFFFFFEFF;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & 0xFFFFFEFF) | 0x100;
usleep(10);
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF;
usleep(20);
}
void clock_disable_kfuse()
@@ -162,40 +199,60 @@ void clock_enable_cl_dvfs()
clock_enable(&_clock_cl_dvfs);
}
void clock_disable_cl_dvfs()
{
clock_disable(&_clock_cl_dvfs);
}
void clock_enable_coresight()
{
clock_enable(&_clock_coresight);
}
#define L_SWR_SDMMC1_RST (1<<14)
#define L_SWR_SDMMC2_RST (1<<9)
#define L_SWR_SDMMC4_RST (1<<15)
#define U_SWR_SDMMC3_RST (1<<5)
void clock_disable_coresight()
{
clock_disable(&_clock_coresight);
}
#define L_CLK_ENB_SDMMC1 (1<<14)
#define L_CLK_ENB_SDMMC2 (1<<9)
#define L_CLK_ENB_SDMMC4 (1<<15)
#define U_CLK_ENB_SDMMC3 (1<<5)
void clock_enable_pwm()
{
clock_enable(&_clock_pwm);
}
#define L_SET_SDMMC1_RST (1<<14)
#define L_SET_SDMMC2_RST (1<<9)
#define L_SET_SDMMC4_RST (1<<15)
#define U_SET_SDMMC3_RST (1<<5)
void clock_disable_pwm()
{
clock_disable(&_clock_pwm);
}
#define L_CLR_SDMMC1_RST (1<<14)
#define L_CLR_SDMMC2_RST (1<<9)
#define L_CLR_SDMMC4_RST (1<<15)
#define U_CLR_SDMMC3_RST (1<<5)
#define L_SWR_SDMMC1_RST (1 << 14)
#define L_SWR_SDMMC2_RST (1 << 9)
#define L_SWR_SDMMC4_RST (1 << 15)
#define U_SWR_SDMMC3_RST (1 << 5)
#define L_SET_CLK_ENB_SDMMC1 (1<<14)
#define L_SET_CLK_ENB_SDMMC2 (1<<9)
#define L_SET_CLK_ENB_SDMMC4 (1<<15)
#define U_SET_CLK_ENB_SDMMC3 (1<<5)
#define L_CLK_ENB_SDMMC1 (1 << 14)
#define L_CLK_ENB_SDMMC2 (1 << 9)
#define L_CLK_ENB_SDMMC4 (1 << 15)
#define U_CLK_ENB_SDMMC3 (1 << 5)
#define L_CLR_CLK_ENB_SDMMC1 (1<<14)
#define L_CLR_CLK_ENB_SDMMC2 (1<<9)
#define L_CLR_CLK_ENB_SDMMC4 (1<<15)
#define U_CLR_CLK_ENB_SDMMC3 (1<<5)
#define L_SET_SDMMC1_RST (1 << 14)
#define L_SET_SDMMC2_RST (1 << 9)
#define L_SET_SDMMC4_RST (1 << 15)
#define U_SET_SDMMC3_RST (1 << 5)
#define L_CLR_SDMMC1_RST (1 << 14)
#define L_CLR_SDMMC2_RST (1 << 9)
#define L_CLR_SDMMC4_RST (1 << 15)
#define U_CLR_SDMMC3_RST (1 << 5)
#define L_SET_CLK_ENB_SDMMC1 (1 << 14)
#define L_SET_CLK_ENB_SDMMC2 (1 << 9)
#define L_SET_CLK_ENB_SDMMC4 (1 << 15)
#define U_SET_CLK_ENB_SDMMC3 (1 << 5)
#define L_CLR_CLK_ENB_SDMMC1 (1 << 14)
#define L_CLR_CLK_ENB_SDMMC2 (1 << 9)
#define L_CLR_CLK_ENB_SDMMC4 (1 << 15)
#define U_CLR_CLK_ENB_SDMMC3 (1 << 5)
static int _clock_sdmmc_is_reset(u32 id)
{
@@ -331,7 +388,8 @@ static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
divisor = 2;
break;
default:
return 0;
*pout = 24728;
divisor = 31;
}
_clock_sdmmc_table[2 * id] = val;
@@ -436,7 +494,7 @@ void clock_sdmmc_enable(u32 id, u32 val)
_clock_sdmmc_config_clock_source_inner(&div, id, val);
_clock_sdmmc_set_enable(id);
_clock_sdmmc_is_reset(id);
sleep((100000 + div - 1) / div);
usleep((100000 + div - 1) / div);
_clock_sdmmc_clear_reset(id);
_clock_sdmmc_is_reset(id);
}

167
bootloader/soc/clock.h Normal file
View File

@@ -0,0 +1,167 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _CLOCK_H_
#define _CLOCK_H_
#include "../utils/types.h"
/*! Clock registers. */
#define CLK_RST_CONTROLLER_RST_SOURCE 0x0
#define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4
#define CLK_RST_CONTROLLER_RST_DEVICES_H 0x8
#define CLK_RST_CONTROLLER_RST_DEVICES_U 0xC
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_L 0x10
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_H 0x14
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_U 0x18
#define CLK_RST_CONTROLLER_CCLK_BURST_POLICY 0x20
#define CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER 0x24
#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY 0x28
#define CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER 0x2C
#define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE 0x30
#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48
#define CLK_RST_CONTROLLER_OSC_CTRL 0x50
#define CLK_RST_CONTROLLER_PLLC_BASE 0x80
#define CLK_RST_CONTROLLER_PLLC_MISC 0x88
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0
#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4
#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8
#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 0x164
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C
#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288
#define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C
#define CLK_RST_CONTROLLER_RST_DEV_X_SET 0x290
#define CLK_RST_CONTROLLER_RST_DEV_X_CLR 0x294
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y 0x298
#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET 0x29C
#define CLK_RST_CONTROLLER_CLK_ENB_Y_CLR 0x2A0
#define CLK_RST_CONTROLLER_RST_DEVICES_Y 0x2A4
#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2A8
#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2AC
#define CLK_RST_CONTROLLER_RST_DEV_L_SET 0x300
#define CLK_RST_CONTROLLER_RST_DEV_L_CLR 0x304
#define CLK_RST_CONTROLLER_RST_DEV_H_SET 0x308
#define CLK_RST_CONTROLLER_RST_DEV_H_CLR 0x30C
#define CLK_RST_CONTROLLER_RST_DEV_U_SET 0x310
#define CLK_RST_CONTROLLER_RST_DEV_U_CLR 0x314
#define CLK_RST_CONTROLLER_CLK_ENB_L_SET 0x320
#define CLK_RST_CONTROLLER_CLK_ENB_L_CLR 0x324
#define CLK_RST_CONTROLLER_CLK_ENB_H_SET 0x328
#define CLK_RST_CONTROLLER_CLK_ENB_H_CLR 0x32C
#define CLK_RST_CONTROLLER_CLK_ENB_U_SET 0x330
#define CLK_RST_CONTROLLER_CLK_ENB_U_CLR 0x334
#define CLK_RST_CONTROLLER_RST_DEVICES_V 0x358
#define CLK_RST_CONTROLLER_RST_DEVICES_W 0x35C
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_V 0x360
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_W 0x364
#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2 0x388
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488
#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C
#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL 0x66C
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
#define CLK_NO_SOURCE 0x0
/*! Generic clock descriptor. */
typedef struct _clock_t
{
u32 reset;
u32 enable;
u32 source;
u8 index;
u8 clk_src;
u8 clk_div;
} clock_t;
/*! Generic clock enable/disable. */
void clock_enable(const clock_t *clk);
void clock_disable(const clock_t *clk);
/*! Clock control for specific hardware portions. */
void clock_enable_fuse(bool enable);
void clock_enable_uart(u32 idx);
void clock_enable_i2c(u32 idx);
void clock_disable_i2c(u32 idx);
void clock_enable_se();
void clock_enable_unk2();
void clock_enable_host1x();
void clock_disable_host1x();
void clock_enable_tsec();
void clock_disable_tsec();
void clock_enable_sor_safe();
void clock_disable_sor_safe();
void clock_enable_sor0();
void clock_disable_sor0();
void clock_enable_sor1();
void clock_disable_sor1();
void clock_enable_kfuse();
void clock_disable_kfuse();
void clock_enable_cl_dvfs();
void clock_disable_cl_dvfs();
void clock_enable_coresight();
void clock_disable_coresight();
void clock_enable_pwm();
void clock_disable_pwm();
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val);
void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type);
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
void clock_sdmmc_enable(u32 id, u32 val);
void clock_sdmmc_disable(u32 id);
#endif

133
bootloader/soc/cluster.c Normal file
View File

@@ -0,0 +1,133 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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 "../soc/cluster.h"
#include "../soc/i2c.h"
#include "../soc/clock.h"
#include "../utils/util.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../power/max77620.h"
#include "../power/max7762x.h"
void _cluster_enable_power()
{
u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & 0xDF);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH);
// Enable cores power.
// 1-3.x: MAX77621_NFSR_ENABLE.
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG,
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE);
// 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL.
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL);
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | 0x37);
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | 0x37);
}
int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
{
// Check if the partition has already been turned on.
if (enable && PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
return 1;
u32 i = 5001;
while (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & 0x100)
{
usleep(1);
i--;
if (i < 1)
return 0;
}
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0);
i = 5001;
while (i > 0)
{
if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
break;
usleep(1);
i--;
}
return 1;
}
void cluster_boot_cpu0(u32 entry)
{
// Set ACTIVE_CLUSER to FAST.
FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= 0xFFFFFFFE;
_cluster_enable_power();
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000))
{
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7;
usleep(2);
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02;
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02;
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) = (CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) & 0xFFFBFFFF) | 0x40000;
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x40404E02;
}
while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x8000000))
;
// Configure MSELECT source and enable clock.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) & 0x1FFFFF00) | 6;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) & 0xFFFFFFF7) | 8;
// Configure initial CPU clock frequency and enable clock.
CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888;
CLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = 0x80000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = 1;
clock_enable_coresight();
// CAR2PMC_CPU_ACK_WIDTH should be set to 0.
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
// Enable CPU rail.
_cluster_pmc_enable_partition(1, 0, true);
// Enable cluster 0 non-CPU.
_cluster_pmc_enable_partition(0x8000, 15, true);
// Enable CE0.
_cluster_pmc_enable_partition(0x4000, 14, true);
// Request and wait for RAM repair.
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1;
while (!(FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) & 2))
;
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
// Set reset vector.
SB(SB_AA64_RESET_LOW) = entry | 1;
SB(SB_AA64_RESET_HIGH) = 0;
// Non-secure reset vector write disable.
SB(SB_CSR) = 2;
(void)SB(SB_CSR);
// Clear MSELECT reset.
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7;
// Clear NONCPU reset.
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000;
// Clear CPU0 reset.
// < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x41010001;
}

37
bootloader/soc/cluster.h Normal file
View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _CLUSTER_H_
#define _CLUSTER_H_
#include "../utils/types.h"
/*! Flow controller registers. */
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C
#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
#define FLOW_CTLR_CPU0_CSR 0x8
#define FLOW_CTLR_CPU1_CSR 0x18
#define FLOW_CTLR_CPU2_CSR 0x20
#define FLOW_CTLR_CPU3_CSR 0x28
#define FLOW_CTLR_RAM_REPAIR 0x40
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
void cluster_boot_cpu0(u32 entry);
#endif

325
bootloader/soc/fuse.c Normal file
View File

@@ -0,0 +1,325 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 shuffle2
* Copyright (c) 2018 balika011
*
* 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 "../soc/fuse.h"
#include "../soc/t210.h"
#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x))
static const u32 evp_thunk_template[] = {
0xe92d0007, // STMFD SP!, {R0-R2}
0xe1a0200e, // MOV R2, LR
0xe2422002, // SUB R2, R2, #2
0xe5922000, // LDR R2, [R2]
0xe20220ff, // AND R2, R2, #0xFF
0xe1a02082, // MOV R2, R2,LSL#1
0xe59f001c, // LDR R0, =evp_thunk_template
0xe59f101c, // LDR R1, =thunk_end
0xe0411000, // SUB R1, R1, R0
0xe59f0018, // LDR R0, =iram_evp_thunks
0xe0800001, // ADD R0, R0, R1
0xe0822000, // ADD R2, R2, R0
0xe3822001, // ORR R2, R2, #1
0xe8bd0003, // LDMFD SP!, {R0,R1}
0xe12fff12, // BX R2
0x001007b0, // off_1007EC DCD evp_thunk_template
0x001007f8, // off_1007F0 DCD thunk_end
0x40004c30, // off_1007F4 DCD iram_evp_thunks
// thunk_end is here
};
static const u32 evp_thunk_template_len = sizeof(evp_thunk_template);
// treated as 12bit values
static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11};
void fuse_disable_program()
{
FUSE(FUSE_DISABLEREGPROGRAM) = 1;
}
u32 fuse_read_odm(u32 idx)
{
return FUSE(FUSE_RESERVED_ODMX(idx));
}
void fuse_wait_idle()
{
u32 ctrl;
do
{
ctrl = FUSE(FUSE_CTRL);
} while (((ctrl >> 16) & 0x1f) != 4);
}
u32 parity32_even(u32 *words, u32 count)
{
u32 acc = words[0];
for (u32 i = 1; i < count; i++)
{
acc ^= words[i];
}
u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff;
u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8;
u32 x = hi ^ lo;
lo = ((x & 0xf) ^ (x >> 4)) & 3;
hi = ((x & 0xf) ^ (x >> 4)) >> 2;
x = hi ^ lo;
return (x & 1) ^ (x >> 1);
}
int patch_hash_one(u32 *word)
{
u32 bits20_31 = *word & 0xfff00000;
u32 parity_bit = parity32_even(&bits20_31, 1);
u32 hash = 0;
for (u32 i = 0; i < 12; i++)
{
if (*word & (1 << (20 + i)))
{
hash ^= hash_vals[i];
}
}
if (hash == 0)
{
if (parity_bit == 0)
{
return 0;
}
*word ^= 1 << 24;
return 1;
}
if (parity_bit == 0)
{
return 3;
}
for (u32 i = 0; i < ARRAYSIZE(hash_vals); i++)
{
if (hash_vals[i] == hash)
{
*word ^= 1 << (20 + i);
return 1;
}
}
return 2;
}
int patch_hash_multi(u32 *words, u32 count)
{
u32 parity_bit = parity32_even(words, count);
u32 bits0_14 = words[0] & 0x7fff;
u32 bit15 = words[0] & 0x8000;
u32 bits16_19 = words[0] & 0xf0000;
u32 hash = 0;
words[0] = bits16_19;
for (u32 i = 0; i < count; i++)
{
u32 w = words[i];
if (w)
{
for (u32 bitpos = 0; bitpos < 32; bitpos++)
{
if ((w >> bitpos) & 1)
{
hash ^= 0x4000 + i * 32 + bitpos;
}
}
}
}
hash ^= bits0_14;
// stupid but this is what original code does.
// equivalent to original words[0] &= 0xfff00000
words[0] = bits16_19 ^ bit15 ^ bits0_14;
if (hash == 0)
{
if (parity_bit == 0)
{
return 0;
}
words[0] ^= 0x8000;
return 1;
}
if (parity_bit == 0)
{
return 3;
}
u32 bitcount = hash - 0x4000;
if (bitcount < 16 || bitcount >= count * 32)
{
u32 num_set = 0;
for (u32 bitpos = 0; bitpos < 15; bitpos++)
{
if ((hash >> bitpos) & 1)
{
num_set++;
}
}
if (num_set != 1)
{
return 2;
}
words[0] ^= hash;
return 1;
}
words[bitcount / 32] ^= 1 << (hash & 0x1f);
return 1;
}
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
{
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 total_read = 0;
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
word_count &= 0x7f;
word_addr = 191;
while (word_count)
{
total_read += word_count;
if (total_read >= ARRAYSIZE(words))
{
break;
}
for (u32 i = 0; i < word_count; i++)
{
FUSE(FUSE_ADDR) = word_addr--;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
words[i] = FUSE(FUSE_RDATA);
}
word0 = words[0];
if (patch_hash_multi(words, word_count) >= 2)
{
return 1;
}
u32 ipatch_count = (words[0] >> 16) & 0xf;
if (ipatch_count)
{
for (u32 i = 0; i < ipatch_count; i++)
{
u32 word = words[i];
u32 addr = (word >> 16) * 2;
u32 data = word & 0xffff;
ipatch(addr, data);
}
}
words[0] = word0;
if ((word0 >> 25) == 0)
break;
if (patch_hash_one(&word0) >= 2)
{
return 3;
}
word_count = word0 >> 25;
}
return 0;
}
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
{
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 total_read = 0;
int evp_thunk_written = 0;
void *evp_thunk_dst_addr = 0;
memset(iram_evp_thunks, 0, *iram_evp_thunks_len);
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
word_count &= 0x7f;
word_addr = 191;
while (word_count)
{
total_read += word_count;
if (total_read >= ARRAYSIZE(words))
{
break;
}
for (u32 i = 0; i < word_count; i++)
{
FUSE(FUSE_ADDR) = word_addr--;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
words[i] = FUSE(FUSE_RDATA);
}
word0 = words[0];
if (patch_hash_multi(words, word_count) >= 2)
{
return 1;
}
u32 ipatch_count = (words[0] >> 16) & 0xf;
u32 insn_count = word_count - ipatch_count - 1;
if (insn_count)
{
if (!evp_thunk_written)
{
evp_thunk_dst_addr = (void *)iram_evp_thunks;
memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len);
evp_thunk_dst_addr += evp_thunk_template_len;
evp_thunk_written = 1;
*iram_evp_thunks_len = evp_thunk_template_len;
//write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks);
}
u32 thunk_patch_len = insn_count * sizeof(u32);
memcpy(evp_thunk_dst_addr, &words[ipatch_count + 1], thunk_patch_len);
evp_thunk_dst_addr += thunk_patch_len;
*iram_evp_thunks_len += thunk_patch_len;
}
words[0] = word0;
if ((word0 >> 25) == 0)
break;
if (patch_hash_one(&word0) >= 2)
{
return 3;
}
word_count = word0 >> 25;
}
return 0;
}
void read_raw_ipatch_fuses(u32 *words)
{
for (u32 i = 0; i < 0x100; i++)
{
FUSE(FUSE_ADDR) = i;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
words[i] = FUSE(FUSE_RDATA);
}
}

62
bootloader/soc/fuse.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 shuffle2
* Copyright (c) 2018 balika011
*
* 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/>.
*/
#ifndef _FUSE_H_
#define _FUSE_H_
#include "../utils/types.h"
/*! Fuse registers. */
#define FUSE_CTRL 0x0
#define FUSE_ADDR 0x4
#define FUSE_RDATA 0x8
#define FUSE_WDATA 0xC
#define FUSE_TIME_RD1 0x10
#define FUSE_TIME_RD2 0x14
#define FUSE_TIME_PGM1 0x18
#define FUSE_TIME_PGM2 0x1C
#define FUSE_PRIV2INTFC 0x20
#define FUSE_FUSEBYPASS 0x24
#define FUSE_PRIVATEKEYDISABLE 0x28
#define FUSE_DISABLEREGPROGRAM 0x2C
#define FUSE_WRITE_ACCESS_SW 0x30
#define FUSE_PWR_GOOD_SW 0x34
#define FUSE_SKU_INFO 0x110
#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c
#define FUSE_PRIVATE_KEY0 0x1A4
#define FUSE_PRIVATE_KEY1 0x1A8
#define FUSE_PRIVATE_KEY2 0x1AC
#define FUSE_PRIVATE_KEY3 0x1B0
/*! Fuse commands. */
#define FUSE_READ 0x1
#define FUSE_WRITE 0x2
#define FUSE_SENSE 0x3
#define FUSE_CMD_MASK 0x3
/*! Fuse cache registers. */
#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x))
void fuse_disable_program();
u32 fuse_read_odm(u32 idx);
void fuse_wait_idle();
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len);
void read_raw_ipatch_fuses(u32 *words);
#endif

32
ipl/gpio.c → bootloader/soc/gpio.c Executable file → Normal file
View File

@@ -1,21 +1,21 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
*
* 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 "gpio.h"
#include "t210.h"
#include "../soc/gpio.h"
#include "../soc/t210.h"
static const u16 _gpio_cnf[31] = {
0x000, 0x004, 0x008, 0x00C,

30
ipl/gpio.h → bootloader/soc/gpio.h Executable file → Normal file
View File

@@ -1,23 +1,23 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _GPIO_H_
#define _GPIO_H_
#include "types.h"
#include "../utils/types.h"
#define GPIO_MODE_SPIO 0
#define GPIO_MODE_GPIO 1

258
bootloader/soc/hw_init.c Normal file
View File

@@ -0,0 +1,258 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "hw_init.h"
#include "../gfx/di.h"
#include "../mem/mc.h"
#include "../mem/sdram.h"
#include "../power/max77620.h"
#include "../power/max7762x.h"
#include "../sec/se.h"
#include "../sec/se_t210.h"
#include "../soc/clock.h"
#include "../soc/fuse.h"
#include "../soc/gpio.h"
#include "../soc/i2c.h"
#include "../soc/pinmux.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../soc/uart.h"
#include "../storage/sdmmc.h"
#include "../utils/util.h"
extern sdmmc_t sd_sdmmc;
void _config_oscillators()
{
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4;
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071;
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE;
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | 0x400000;
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | 0x1000;
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | 0x2000000;
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10;
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF;
PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz)
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444;
CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000;
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2;
}
void _config_gpios()
{
PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE);
gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
gpio_output_enable(GPIO_PORT_H, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
pinmux_config_i2c(I2C_1);
pinmux_config_i2c(I2C_5);
pinmux_config_uart(UART_A);
// Configure volume up/down as inputs.
gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO);
gpio_config(GPIO_PORT_X, GPIO_PIN_7, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE);
}
void _config_pmc_scratch()
{
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF;
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE;
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10;
}
void _mbist_workaround()
{
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF;
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000u;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
usleep(2);
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S2_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S3_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S3_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S4_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE;
DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4;
VIC(0x8C) = 0xFFFFFFFF;
usleep(2);
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0;
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000;
}
void _config_se_brom()
{
// Bootrom part we skipped.
u32 sbk[4] = {
FUSE(FUSE_PRIVATE_KEY0),
FUSE(FUSE_PRIVATE_KEY1),
FUSE(FUSE_PRIVATE_KEY2),
FUSE(FUSE_PRIVATE_KEY3)
};
// Set SBK to slot 14.
se_aes_key_set(14, sbk, 0x10);
// Lock SBK from being read.
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E;
// This memset needs to happen here, else TZRAM will behave weirdly later on.
memset((void *)TZRAM_BASE, 0, 0x10000);
PMC(APBDEV_PMC_CRYPTO_OP) = 0;
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
// Lock SSK (although it's not set and unused anyways).
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
// Clear the boot reason to avoid problems later
PMC(APBDEV_PMC_SCRATCH200) = 0x0;
PMC(APBDEV_PMC_RST_STATUS) = 0x0;
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
}
void config_hw()
{
// Bootrom stuff we skipped by going through rcm.
_config_se_brom();
//FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11;
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F;
PMC(APBDEV_PMC_SCRATCH49) = ((PMC(APBDEV_PMC_SCRATCH49) >> 1) << 1) & 0xFFFFFFFD;
_mbist_workaround();
clock_enable_se();
// Enable fuse clock.
clock_enable_fuse(true);
// Disable fuse programming.
fuse_disable_program();
mc_enable();
_config_oscillators();
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
_config_gpios();
//clock_enable_uart(UART_C);
//uart_init(UART_C, 115200);
clock_enable_cl_dvfs();
clock_enable_i2c(I2C_1);
clock_enable_i2c(I2C_5);
clock_enable_unk2();
i2c_init(I2C_1);
i2c_init(I2C_5);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, 0x40);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, 0x78);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, 0x38);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, 0x3A);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, 0x38);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_LDO4, 0xF);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_LDO8, 0xC7);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD0, 0x4F);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD1, 0x29);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD3, 0x1B);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, 0x22); // 3.x+
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD0, 42); //42 = (1125000uV - 600000) / 12500 -> 1.125V
_config_pmc_scratch(); // Missing from 4.x+
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333;
sdram_init();
}
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
{
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
if (extra_reconfig)
{
msleep(10);
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN;
clock_disable_cl_dvfs();
// Disable Joy-con GPIOs.
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_SPIO);
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_SPIO);
}
// Power off display.
display_end();
// Enable clock to USBD and init SDMMC1 to avoid hangs with bad hw inits.
if (magic == 0xBAADF00D)
{
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0);
clock_disable_cl_dvfs();
msleep(200);
}
}

26
bootloader/soc/hw_init.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018 naehrwert
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _HW_INIT_H_
#define _HW_INIT_H_
#include "../utils/types.h"
void config_hw();
void reconfig_hw_workaround(bool extra_reconfig, u32 magic);
#endif

143
bootloader/soc/i2c.c Normal file
View File

@@ -0,0 +1,143 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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 "i2c.h"
#include "../utils/util.h"
static u32 i2c_addrs[] = {
0x7000C000, 0x7000C400, 0x7000C500,
0x7000C700, 0x7000D000, 0x7000D100
};
static void _i2c_wait(vu32 *base)
{
base[I2C_CONFIG_LOAD] = 0x25;
for (u32 i = 0; i < 20; i++)
{
usleep(1);
if (!(base[I2C_CONFIG_LOAD] & 1))
break;
}
}
static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
{
if (size > 4)
return 0;
u32 tmp = 0;
memcpy(&tmp, buf, size);
vu32 *base = (vu32 *)i2c_addrs[idx];
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
base[I2C_CMD_DATA1] = tmp; //Set value.
base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode.
_i2c_wait(base); //Kick transaction.
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
while (base[I2C_STATUS] & 0x100)
;
if (base[I2C_STATUS] << 28)
return 0;
return 1;
}
static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
{
if (size > 8)
return 0;
vu32 *base = (vu32 *)i2c_addrs[idx];
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode.
_i2c_wait(base); // Kick transaction.
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
while (base[I2C_STATUS] & 0x100)
;
if (base[I2C_STATUS] << 28)
return 0;
u32 tmp = base[I2C_CMD_DATA1]; // Get LS value.
if (size > 4)
{
memcpy(buf, &tmp, 4);
tmp = base[I2C_CMD_DATA2]; // Get MS value.
memcpy(buf + 4, &tmp, size - 4);
}
else
memcpy(buf, &tmp, size);
return 1;
}
void i2c_init(u32 idx)
{
vu32 *base = (vu32 *)i2c_addrs[idx];
base[I2C_CLK_DIVISOR_REGISTER] = 0x50001;
base[I2C_BUS_CLEAR_CONFIG] = 0x90003;
_i2c_wait(base);
for (u32 i = 0; i < 10; i++)
{
usleep(20000);
if (base[INTERRUPT_STATUS_REGISTER] & 0x800)
break;
}
(vu32)base[I2C_BUS_CLEAR_STATUS];
base[INTERRUPT_STATUS_REGISTER] = base[INTERRUPT_STATUS_REGISTER];
}
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
{
u8 tmp[4];
if (size > 3)
return 0;
tmp[0] = y;
memcpy(tmp + 1, buf, size);
return _i2c_send_pkt(idx, x, tmp, size + 1);
}
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y)
{
int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1);
if (res)
res = _i2c_recv_pkt(idx, buf, size, x);
return res;
}
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b)
{
return i2c_send_buf_small(idx, x, y, &b, 1);
}
u8 i2c_recv_byte(u32 idx, u32 x, u32 y)
{
u8 tmp = 0;
i2c_recv_buf_small(&tmp, 1, idx, x, y);
return tmp;
}

46
bootloader/soc/i2c.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _I2C_H_
#define _I2C_H_
#include "../utils/types.h"
#define I2C_1 0
#define I2C_2 1
#define I2C_3 2
#define I2C_4 3
#define I2C_5 4
#define I2C_6 5
#define I2C_CNFG 0x00
#define I2C_CMD_ADDR0 0x01
#define I2C_CMD_DATA1 0x03
#define I2C_CMD_DATA2 0x04
#define I2C_STATUS 0x07
#define INTERRUPT_STATUS_REGISTER 0x1A
#define I2C_CLK_DIVISOR_REGISTER 0x1B
#define I2C_BUS_CLEAR_CONFIG 0x21
#define I2C_BUS_CLEAR_STATUS 0x22
#define I2C_CONFIG_LOAD 0x23
void i2c_init(u32 idx);
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size);
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y);
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b);
u8 i2c_recv_byte(u32 idx, u32 x, u32 y);
#endif

42
bootloader/soc/kfuse.c Normal file
View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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 "../soc/kfuse.h"
#include "../soc/clock.h"
#include "../soc/t210.h"
int kfuse_read(u32 *buf)
{
int res = 0;
clock_enable_kfuse();
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
;
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
goto out;
KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC;
for (int i = 0; i < KFUSE_NUM_WORDS; i++)
buf[i] = KFUSE(KFUSE_KEYS);
res = 1;
out:;
clock_disable_kfuse();
return res;
}

41
bootloader/soc/kfuse.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _KFUSE_H_
#define _KFUSE_H_
#include "../utils/types.h"
#define KFUSE_STATE_SOFTRESET (1 << 31)
#define KFUSE_STATE_STOP (1 << 25)
#define KFUSE_STATE_RESTART (1 << 24)
#define KFUSE_STATE_CRCPASS (1 << 17)
#define KFUSE_STATE_DONE (1 << 16)
#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00
#define KFUSE_STATE_ERRBLOCK_SHIFT 8
#define KFUSE_STATE_CURBLOCK_MASK 0x3F
#define KFUSE_KEYADDR_AUTOINC (1<<16)
#define KFUSE_STATE 0x80
#define KFUSE_KEYADDR 0x88
#define KFUSE_KEYS 0x8C
#define KFUSE_NUM_WORDS 144
int kfuse_read(u32 *buf);
#endif

32
bootloader/soc/pinmux.c Normal file
View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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 "../soc/pinmux.h"
#include "../soc/t210.h"
void pinmux_config_uart(u32 idx)
{
PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = 0;
PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;
PINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0;
PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN;
}
void pinmux_config_i2c(u32 idx)
{
PINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = PINMUX_INPUT_ENABLE;
PINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = PINMUX_INPUT_ENABLE;
}

89
bootloader/soc/pinmux.h Normal file
View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _PINMUX_H_
#define _PINMUX_H_
#include "../utils/types.h"
/*! APB MISC registers. */
#define APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL 0x8D4
#define APB_MISC_GP_SDMMC3_CLK_LPBK_CONTROL 0x8D8
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
#define APB_MISC_GP_VGPIO_GPIO_MUX_SEL 0xB74
/*! Pinmux registers. */
#define PINMUX_AUX_SDMMC1_CLK 0x00
#define PINMUX_AUX_SDMMC1_CMD 0x04
#define PINMUX_AUX_SDMMC1_DAT3 0x08
#define PINMUX_AUX_SDMMC1_DAT2 0x0C
#define PINMUX_AUX_SDMMC1_DAT1 0x10
#define PINMUX_AUX_SDMMC1_DAT0 0x14
#define PINMUX_AUX_SDMMC3_CLK 0x1C
#define PINMUX_AUX_SDMMC3_CMD 0x20
#define PINMUX_AUX_SDMMC3_DAT0 0x24
#define PINMUX_AUX_SDMMC3_DAT1 0x28
#define PINMUX_AUX_SDMMC3_DAT2 0x2C
#define PINMUX_AUX_SDMMC3_DAT3 0x30
#define PINMUX_AUX_DMIC3_CLK 0xB4
#define PINMUX_AUX_UART2_TX 0xF4
#define PINMUX_AUX_UART3_TX 0x104
#define PINMUX_AUX_WIFI_EN 0x1B4
#define PINMUX_AUX_WIFI_RST 0x1B8
#define PINMUX_AUX_NFC_EN 0x1D0
#define PINMUX_AUX_NFC_INT 0x1D4
#define PINMUX_AUX_LCD_BL_PWM 0x1FC
#define PINMUX_AUX_LCD_BL_EN 0x200
#define PINMUX_AUX_LCD_RST 0x204
#define PINMUX_AUX_GPIO_PE6 0x248
#define PINMUX_AUX_GPIO_PH6 0x250
#define PINMUX_AUX_GPIO_PZ1 0x280
/*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */
#define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x))
#define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x))
#define PINMUX_AUX_UARTX_RTS(x) (0xEC + 0x10 * (x))
#define PINMUX_AUX_UARTX_CTS(x) (0xF0 + 0x10 * (x))
/*! 0:GEN1, 1:GEN2, 2:GEN3, 3:CAM, 4:PWR */
#define PINMUX_AUX_X_I2C_SCL(x) (0xBC + 8 * (x))
#define PINMUX_AUX_X_I2C_SDA(x) (0xC0 + 8 * (x))
#define PINMUX_FUNC_MASK (3 << 0)
#define PINMUX_PULL_MASK (3 << 2)
#define PINMUX_PULL_NONE (0 << 2)
#define PINMUX_PULL_DOWN (1 << 2)
#define PINMUX_PULL_UP (2 << 2)
#define PINMUX_TRISTATE (1 << 4)
#define PINMUX_PARKED (1 << 5)
#define PINMUX_INPUT_ENABLE (1 << 6)
#define PINMUX_LOCK (1 << 7)
#define PINMUX_LPDR (1 << 8)
#define PINMUX_HSM (1 << 9)
#define PINMUX_IO_HV (1 << 10)
#define PINMUX_OPEN_DRAIN (1 << 11)
#define PINMUX_SCHMT (1 << 12)
#define PINMUX_DRIVE_1X (0 << 13)
#define PINMUX_DRIVE_2X (1 << 13)
#define PINMUX_DRIVE_3X (2 << 13)
#define PINMUX_DRIVE_4X (3 << 13)
void pinmux_config_uart(u32 idx);
void pinmux_config_i2c(u32 idx);
#endif

65
bootloader/soc/pmc.h Normal file
View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
*
* 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/>.
*/
#ifndef _PMC_H_
#define _PMC_H_
/*! PMC registers. */
#define APBDEV_PMC_CNTRL 0x0
#define PMC_CNTRL_MAIN_RST (1 << 4)
#define APBDEV_PMC_SEC_DISABLE 0x4
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
#define APBDEV_PMC_PWRGATE_STATUS 0x38
#define APBDEV_PMC_NO_IOPOWER 0x44
#define APBDEV_PMC_SCRATCH0 0x50
#define APBDEV_PMC_SCRATCH1 0x54
#define APBDEV_PMC_SCRATCH20 0xA0
#define APBDEV_PMC_PWR_DET_VAL 0xE4
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
#define APBDEV_PMC_DDR_PWR 0xE8
#define APBDEV_PMC_CRYPTO_OP 0xF4
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
#define APBDEV_PMC_RST_STATUS 0x1B4
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
#define APBDEV_PMC_VDDP_SEL 0x1CC
#define APBDEV_PMC_DDR_CFG 0x1D0
#define APBDEV_PMC_SCRATCH49 0x244
#define APBDEV_PMC_TSC_MULT 0x2B4
#define APBDEV_PMC_SEC_DISABLE2 0x2C4
#define APBDEV_PMC_WEAK_BIAS 0x2C8
#define APBDEV_PMC_REG_SHORT 0x2CC
#define APBDEV_PMC_SEC_DISABLE3 0x2D8
#define APBDEV_PMC_SECURE_SCRATCH21 0x334
#define APBDEV_PMC_SECURE_SCRATCH32 0x360
#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4
#define APBDEV_PMC_CNTRL2 0x440
#define APBDEV_PMC_IO_DPD3_REQ 0x45C
#define APBDEV_PMC_IO_DPD4_REQ 0x464
#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4
#define APBDEV_PMC_UTMIP_PAD_CFG3 0x4CC
#define APBDEV_PMC_DDR_CNTRL 0x4E4
#define APBDEV_PMC_SEC_DISABLE4 0x5B0
#define APBDEV_PMC_SEC_DISABLE5 0x5B4
#define APBDEV_PMC_SEC_DISABLE6 0x5B8
#define APBDEV_PMC_SEC_DISABLE7 0x5BC
#define APBDEV_PMC_SEC_DISABLE8 0x5C0
#define APBDEV_PMC_SCRATCH188 0x810
#define APBDEV_PMC_SCRATCH190 0x818
#define APBDEV_PMC_SCRATCH200 0x840
#endif

View File

@@ -0,0 +1,564 @@
/*
* Copyright (c) 2010-2015, NVIDIA CORPORATION. All rights reserved.
*
* 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.
*/
#ifndef _TEGRA210_PMC_H_
#define _TEGRA210_PMC_H_
#include "../utils/types.h"
struct tegra_pmc_regs
{
u32 cntrl;
u32 sec_disable;
u32 pmc_swrst;
u32 wake_mask;
u32 wake_lvl;
u32 wake_status;
u32 sw_wake_status;
u32 dpd_pads_oride;
u32 dpd_sample;
u32 dpd_enable;
u32 pwrgate_timer_off;
u32 clamp_status;
u32 pwrgate_toggle;
u32 remove_clamping_cmd;
u32 pwrgate_status;
u32 pwrgood_timer;
u32 blink_timer;
u32 no_iopower;
u32 pwr_det;
u32 pwr_det_latch;
u32 scratch0;
u32 scratch1;
u32 scratch2;
u32 scratch3;
u32 scratch4;
u32 scratch5;
u32 scratch6;
u32 scratch7;
u32 scratch8;
u32 scratch9;
u32 scratch10;
u32 scratch11;
u32 scratch12;
u32 scratch13;
u32 scratch14;
u32 scratch15;
u32 scratch16;
u32 scratch17;
u32 scratch18;
u32 scratch19;
u32 odmdata;
u32 scratch21;
u32 scratch22;
u32 scratch23;
u32 secure_scratch0;
u32 secure_scratch1;
u32 secure_scratch2;
u32 secure_scratch3;
u32 secure_scratch4;
u32 secure_scratch5;
u32 cpupwrgood_timer;
u32 cpupwroff_timer;
u32 pg_mask;
u32 pg_mask_1;
u32 auto_wake_lvl;
u32 auto_wake_lvl_mask;
u32 wake_delay;
u32 pwr_det_val;
u32 ddr_pwr;
u32 usb_debounce_del;
u32 usb_a0;
u32 crypto_op;
u32 pllp_wb0_override;
u32 scratch24;
u32 scratch25;
u32 scratch26;
u32 scratch27;
u32 scratch28;
u32 scratch29;
u32 scratch30;
u32 scratch31;
u32 scratch32;
u32 scratch33;
u32 scratch34;
u32 scratch35;
u32 scratch36;
u32 scratch37;
u32 scratch38;
u32 scratch39;
u32 scratch40;
u32 scratch41;
u32 scratch42;
u32 bondout_mirror[3];
u32 sys_33v_en;
u32 bondout_mirror_access;
u32 gate;
u32 wake2_mask;
u32 wake2_lvl;
u32 wake2_status;
u32 sw_wake2_status;
u32 auto_wake2_lvl_mask;
u32 pg_mask_2;
u32 pg_mask_ce1;
u32 pg_mask_ce2;
u32 pg_mask_ce3;
u32 pwrgate_timer_ce[7];
u32 pcx_edpd_cntrl;
u32 osc_edpd_over;
u32 clk_out_cntrl;
u32 sata_pwrgt;
u32 sensor_ctrl;
u32 rst_status;
u32 io_dpd_req;
u32 io_dpd_status;
u32 io_dpd2_req;
u32 io_dpd2_status;
u32 sel_dpd_tim;
u32 vddp_sel;
u32 ddr_cfg;
u32 e_no_vttgen;
u8 _rsv0[4];
u32 pllm_wb0_override_freq;
u32 test_pwrgate;
u32 pwrgate_timer_mult;
u32 dis_sel_dpd;
u32 utmip_uhsic_triggers;
u32 utmip_uhsic_saved_state;
u32 utmip_pad_cfg;
u32 utmip_term_pad_cfg;
u32 utmip_uhsic_sleep_cfg;
u32 utmip_uhsic_sleepwalk_cfg;
u32 utmip_sleepwalk_p[3];
u32 uhsic_sleepwalk_p0;
u32 utmip_uhsic_status;
u32 utmip_uhsic_fake;
u32 bondout_mirror3[5 - 3];
u32 secure_scratch6;
u32 secure_scratch7;
u32 scratch43;
u32 scratch44;
u32 scratch45;
u32 scratch46;
u32 scratch47;
u32 scratch48;
u32 scratch49;
u32 scratch50;
u32 scratch51;
u32 scratch52;
u32 scratch53;
u32 scratch54;
u32 scratch55;
u32 scratch0_eco;
u32 por_dpd_ctrl;
u32 scratch2_eco;
u32 utmip_uhsic_line_wakeup;
u32 utmip_bias_master_cntrl;
u32 utmip_master_config;
u32 td_pwrgate_inter_part_timer;
u32 utmip_uhsic2_triggers;
u32 utmip_uhsic2_saved_state;
u32 utmip_uhsic2_sleep_cfg;
u32 utmip_uhsic2_sleepwalk_cfg;
u32 uhsic2_sleepwalk_p1;
u32 utmip_uhsic2_status;
u32 utmip_uhsic2_fake;
u32 utmip_uhsic2_line_wakeup;
u32 utmip_master2_config;
u32 utmip_uhsic_rpd_cfg;
u32 pg_mask_ce0;
u32 pg_mask3[5 - 3];
u32 pllm_wb0_override2;
u32 tsc_mult;
u32 cpu_vsense_override;
u32 glb_amap_cfg;
u32 sticky_bits;
u32 sec_disable2;
u32 weak_bias;
u32 reg_short;
u32 pg_mask_andor;
u8 _rsv1[0x2c];
u32 secure_scratch8; /* offset 0x300 */
u32 secure_scratch9;
u32 secure_scratch10;
u32 secure_scratch11;
u32 secure_scratch12;
u32 secure_scratch13;
u32 secure_scratch14;
u32 secure_scratch15;
u32 secure_scratch16;
u32 secure_scratch17;
u32 secure_scratch18;
u32 secure_scratch19;
u32 secure_scratch20;
u32 secure_scratch21;
u32 secure_scratch22;
u32 secure_scratch23;
u32 secure_scratch24;
u32 secure_scratch25;
u32 secure_scratch26;
u32 secure_scratch27;
u32 secure_scratch28;
u32 secure_scratch29;
u32 secure_scratch30;
u32 secure_scratch31;
u32 secure_scratch32;
u32 secure_scratch33;
u32 secure_scratch34;
u32 secure_scratch35;
u32 secure_scratch36;
u32 secure_scratch37;
u32 secure_scratch38;
u32 secure_scratch39;
u32 secure_scratch40;
u32 secure_scratch41;
u32 secure_scratch42;
u32 secure_scratch43;
u32 secure_scratch44;
u32 secure_scratch45;
u32 secure_scratch46;
u32 secure_scratch47;
u32 secure_scratch48;
u32 secure_scratch49;
u32 secure_scratch50;
u32 secure_scratch51;
u32 secure_scratch52;
u32 secure_scratch53;
u32 secure_scratch54;
u32 secure_scratch55;
u32 secure_scratch56;
u32 secure_scratch57;
u32 secure_scratch58;
u32 secure_scratch59;
u32 secure_scratch60;
u32 secure_scratch61;
u32 secure_scratch62;
u32 secure_scratch63;
u32 secure_scratch64;
u32 secure_scratch65;
u32 secure_scratch66;
u32 secure_scratch67;
u32 secure_scratch68;
u32 secure_scratch69;
u32 secure_scratch70;
u32 secure_scratch71;
u32 secure_scratch72;
u32 secure_scratch73;
u32 secure_scratch74;
u32 secure_scratch75;
u32 secure_scratch76;
u32 secure_scratch77;
u32 secure_scratch78;
u32 secure_scratch79;
u32 _rsv0x420[8];
u32 cntrl2; /* 0x440 */
u32 _rsv0x444[2];
u32 event_counter; /* 0x44C */
u32 fuse_control;
u32 scratch1_eco;
u32 _rsv0x458[1];
u32 io_dpd3_req; /* 0x45C */
u32 io_dpd3_status;
u32 io_dpd4_req;
u32 io_dpd4_status;
u32 _rsv0x46C[30];
u32 ddr_cntrl; /* 0x4E4 */
u32 _rsv0x4E8[70];
u32 scratch56; /* 0x600 */
u32 scratch57;
u32 scratch58;
u32 scratch59;
u32 scratch60;
u32 scratch61;
u32 scratch62;
u32 scratch63;
u32 scratch64;
u32 scratch65;
u32 scratch66;
u32 scratch67;
u32 scratch68;
u32 scratch69;
u32 scratch70;
u32 scratch71;
u32 scratch72;
u32 scratch73;
u32 scratch74;
u32 scratch75;
u32 scratch76;
u32 scratch77;
u32 scratch78;
u32 scratch79;
u32 scratch80;
u32 scratch81;
u32 scratch82;
u32 scratch83;
u32 scratch84;
u32 scratch85;
u32 scratch86;
u32 scratch87;
u32 scratch88;
u32 scratch89;
u32 scratch90;
u32 scratch91;
u32 scratch92;
u32 scratch93;
u32 scratch94;
u32 scratch95;
u32 scratch96;
u32 scratch97;
u32 scratch98;
u32 scratch99;
u32 scratch100;
u32 scratch101;
u32 scratch102;
u32 scratch103;
u32 scratch104;
u32 scratch105;
u32 scratch106;
u32 scratch107;
u32 scratch108;
u32 scratch109;
u32 scratch110;
u32 scratch111;
u32 scratch112;
u32 scratch113;
u32 scratch114;
u32 scratch115;
u32 scratch116;
u32 scratch117;
u32 scratch118;
u32 scratch119;
u32 scratch120; /* 0x700 */
u32 scratch121;
u32 scratch122;
u32 scratch123;
u32 scratch124;
u32 scratch125;
u32 scratch126;
u32 scratch127;
u32 scratch128;
u32 scratch129;
u32 scratch130;
u32 scratch131;
u32 scratch132;
u32 scratch133;
u32 scratch134;
u32 scratch135;
u32 scratch136;
u32 scratch137;
u32 scratch138;
u32 scratch139;
u32 scratch140;
u32 scratch141;
u32 scratch142;
u32 scratch143;
u32 scratch144;
u32 scratch145;
u32 scratch146;
u32 scratch147;
u32 scratch148;
u32 scratch149;
u32 scratch150;
u32 scratch151;
u32 scratch152;
u32 scratch153;
u32 scratch154;
u32 scratch155;
u32 scratch156;
u32 scratch157;
u32 scratch158;
u32 scratch159;
u32 scratch160;
u32 scratch161;
u32 scratch162;
u32 scratch163;
u32 scratch164;
u32 scratch165;
u32 scratch166;
u32 scratch167;
u32 scratch168;
u32 scratch169;
u32 scratch170;
u32 scratch171;
u32 scratch172;
u32 scratch173;
u32 scratch174;
u32 scratch175;
u32 scratch176;
u32 scratch177;
u32 scratch178;
u32 scratch179;
u32 scratch180;
u32 scratch181;
u32 scratch182;
u32 scratch183;
u32 scratch184;
u32 scratch185;
u32 scratch186;
u32 scratch187;
u32 scratch188;
u32 scratch189;
u32 scratch190;
u32 scratch191;
u32 scratch192;
u32 scratch193;
u32 scratch194;
u32 scratch195;
u32 scratch196;
u32 scratch197;
u32 scratch198;
u32 scratch199;
u32 scratch200;
u32 scratch201;
u32 scratch202;
u32 scratch203;
u32 scratch204;
u32 scratch205;
u32 scratch206;
u32 scratch207;
u32 scratch208;
u32 scratch209;
u32 scratch210;
u32 scratch211;
u32 scratch212;
u32 scratch213;
u32 scratch214;
u32 scratch215;
u32 scratch216;
u32 scratch217;
u32 scratch218;
u32 scratch219;
u32 scratch220;
u32 scratch221;
u32 scratch222;
u32 scratch223;
u32 scratch224;
u32 scratch225;
u32 scratch226;
u32 scratch227;
u32 scratch228;
u32 scratch229;
u32 scratch230;
u32 scratch231;
u32 scratch232;
u32 scratch233;
u32 scratch234;
u32 scratch235;
u32 scratch236;
u32 scratch237;
u32 scratch238;
u32 scratch239;
u32 scratch240;
u32 scratch241;
u32 scratch242;
u32 scratch243;
u32 scratch244;
u32 scratch245;
u32 scratch246;
u32 scratch247;
u32 scratch248;
u32 scratch249;
u32 scratch250;
u32 scratch251;
u32 scratch252;
u32 scratch253;
u32 scratch254;
u32 scratch255;
u32 scratch256;
u32 scratch257;
u32 scratch258;
u32 scratch259;
u32 scratch260;
u32 scratch261;
u32 scratch262;
u32 scratch263;
u32 scratch264;
u32 scratch265;
u32 scratch266;
u32 scratch267;
u32 scratch268;
u32 scratch269;
u32 scratch270;
u32 scratch271;
u32 scratch272;
u32 scratch273;
u32 scratch274;
u32 scratch275;
u32 scratch276;
u32 scratch277;
u32 scratch278;
u32 scratch279;
u32 scratch280;
u32 scratch281;
u32 scratch282;
u32 scratch283;
u32 scratch284;
u32 scratch285;
u32 scratch286;
u32 scratch287;
u32 scratch288;
u32 scratch289;
u32 scratch290;
u32 scratch291;
u32 scratch292;
u32 scratch293;
u32 scratch294;
u32 scratch295;
u32 scratch296;
u32 scratch297;
u32 scratch298;
u32 scratch299; /* 0x9CC */
u32 _rsv0x9D0[50];
u32 secure_scratch80; /* 0xa98 */
u32 secure_scratch81;
u32 secure_scratch82;
u32 secure_scratch83;
u32 secure_scratch84;
u32 secure_scratch85;
u32 secure_scratch86;
u32 secure_scratch87;
u32 secure_scratch88;
u32 secure_scratch89;
u32 secure_scratch90;
u32 secure_scratch91;
u32 secure_scratch92;
u32 secure_scratch93;
u32 secure_scratch94;
u32 secure_scratch95;
u32 secure_scratch96;
u32 secure_scratch97;
u32 secure_scratch98;
u32 secure_scratch99;
u32 secure_scratch100;
u32 secure_scratch101;
u32 secure_scratch102;
u32 secure_scratch103;
u32 secure_scratch104;
u32 secure_scratch105;
u32 secure_scratch106;
u32 secure_scratch107;
u32 secure_scratch108;
u32 secure_scratch109;
u32 secure_scratch110;
u32 secure_scratch111;
u32 secure_scratch112;
u32 secure_scratch113;
u32 secure_scratch114;
u32 secure_scratch115;
u32 secure_scratch116;
u32 secure_scratch117;
u32 secure_scratch118;
u32 secure_scratch119;
};
#endif /* _TEGRA210_PMC_H_ */

171
bootloader/soc/smmu.c Normal file
View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 balika011
*
* 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 "smmu.h"
#include "../soc/cluster.h"
#include "../soc/t210.h"
#include "../mem/mc_t210.h"
#include "../utils/util.h"
#include "../utils/aarch64_util.h"
bool smmu_used = false;
u8 *_pageheap = (u8 *)SMMU_HEAP_ADDR;
//Enabling SMMU requires a TZ secure write: MC(MC_SMMU_CONFIG) = 1;
u8 smmu_payload[] __attribute__((aligned(16))) = {
0x41, 0x01, 0x00, 0x58, // 0x00: LDR X1, =0x70019010
0x20, 0x00, 0x80, 0xD2, // 0x04: MOV X0, #0x1
0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1]
0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS
0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH
0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop
0x00, 0x00, 0x80, 0xD2, // 0x18: MOV X0, #0x0
0x20, 0x00, 0x00, 0xB9, // 0x1C: STR W0, [X1]
0x80, 0x00, 0x00, 0x58, // 0x20: LDR X0, =0x4002B000
0x00, 0x00, 0x1F, 0xD6, // 0x28: BR X0
0x10, 0x90, 0x01, 0x70, // 0x28: MC_SMMU_CONFIG
0x00, 0x00, 0x00, 0x00, // 0x2C:
0x00, 0x00, 0x00, 0x00, // 0x30: secmon address
0x00, 0x00, 0x00, 0x00 // 0x34:
};
void *page_alloc(u32 num)
{
u8 *res = _pageheap;
_pageheap += 0x1000 * num;
memset(res, 0, 0x1000 * num);
return res;
}
u32 *smmu_alloc_pdir()
{
u32 *pdir = (u32 *)page_alloc(1);
for (int pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)
pdir[pdn] = _PDE_VACANT(pdn);
return pdir;
}
void smmu_flush_regs()
{
(void)MC(MC_SMMU_PTB_DATA);
}
void smmu_flush_all()
{
MC(MC_SMMU_PTC_FLUSH) = 0;
smmu_flush_regs();
MC(MC_SMMU_TLB_FLUSH) = 0;
smmu_flush_regs();
}
void smmu_init(u32 secmon_base)
{
MC(MC_SMMU_PTB_ASID) = 0;
MC(MC_SMMU_PTB_DATA) = 0;
MC(MC_SMMU_TLB_CONFIG) = 0x30000030;
MC(MC_SMMU_PTC_CONFIG) = 0x28000F3F;
MC(MC_SMMU_PTC_FLUSH) = 0;
MC(MC_SMMU_TLB_FLUSH) = 0;
// Set the secmon address
*(u32 *)(smmu_payload + 0x30) = secmon_base;
}
void smmu_enable()
{
if (smmu_used)
return;
cluster_boot_cpu0((u32)smmu_payload);
smmu_used = true;
msleep(100);
smmu_flush_all();
}
bool smmu_is_used()
{
return smmu_used;
}
void smmu_exit()
{
*(uint32_t *)(smmu_payload + 0x14) = _NOP();
}
u32 *smmu_init_domain4(u32 dev_base, u32 asid)
{
u32 *pdir = smmu_alloc_pdir();
MC(MC_SMMU_PTB_ASID) = asid;
MC(MC_SMMU_PTB_DATA) = SMMU_MK_PDIR((u32)pdir, _PDIR_ATTR);
smmu_flush_regs();
MC(dev_base) = 0x80000000 | (asid << 24) | (asid << 16) | (asid << 8) | (asid);
smmu_flush_regs();
return pdir;
}
u32 *smmu_get_pte(u32 *pdir, u32 iova)
{
u32 ptn = SMMU_ADDR_TO_PFN(iova);
u32 pdn = SMMU_ADDR_TO_PDN(iova);
u32 *ptbl;
if (pdir[pdn] != _PDE_VACANT(pdn))
ptbl = (u32 *)((pdir[pdn] & SMMU_PFN_MASK) << SMMU_PDIR_SHIFT);
else
{
ptbl = (u32 *)page_alloc(1);
u32 addr = SMMU_PDN_TO_ADDR(pdn);
for (int pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SMMU_PAGE_SIZE)
ptbl[pn] = _PTE_VACANT(addr);
pdir[pdn] = SMMU_MK_PDE((u32)ptbl, _PDE_ATTR | _PDE_NEXT);
smmu_flush_all();
}
return &ptbl[ptn % SMMU_PTBL_COUNT];
}
void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr)
{
for (int i = 0; i < cnt; i++)
{
u32 *pte = smmu_get_pte(pdir, addr);
*pte = SMMU_ADDR_TO_PFN(page) | attr;
addr += 0x1000;
page += 0x1000;
}
smmu_flush_all();
}
u32 *smmu_init_for_tsec()
{
return smmu_init_domain4(MC_SMMU_TSEC_ASID, 1);
}
void smmu_deinit_for_tsec()
{
MC(MC_SMMU_PTB_ASID) = 1;
MC(MC_SMMU_PTB_DATA) = 0;
MC(MC_SMMU_TSEC_ASID) = 0;
smmu_flush_regs();
}

82
bootloader/soc/smmu.h Normal file
View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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 "../utils/types.h"
#define SMMU_HEAP_ADDR 0xA0000000
#define MC_INTSTATUS 0x0
#define MC_INTMASK 0x4
#define MC_ERR_STATUS 0x8
#define MC_ERR_ADR 0xc
#define MC_SMMU_CONFIG 0x10
#define MC_SMMU_TLB_CONFIG 0x14
#define MC_SMMU_PTC_CONFIG 0x18
#define MC_SMMU_PTB_ASID 0x1c
#define MC_SMMU_PTB_DATA 0x20
#define MC_SMMU_TLB_FLUSH 0x30
#define MC_SMMU_PTC_FLUSH 0x34
#define MC_SMMU_ASID_SECURITY 0x38
#define MC_SMMU_TSEC_ASID 0x294
#define MC_SMMU_TRANSLATION_ENABLE_0 0x228
#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c
#define MC_SMMU_TRANSLATION_ENABLE_2 0x230
#define MC_SMMU_TRANSLATION_ENABLE_3 0x234
#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98
#define SMMU_PDE_NEXT_SHIFT 28
#define MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT 29
#define MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT 30
#define MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT 31
#define SMMU_PAGE_SHIFT 12
#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT)
#define SMMU_PDIR_COUNT 1024
#define SMMU_PDIR_SIZE (sizeof(u32) * SMMU_PDIR_COUNT)
#define SMMU_PTBL_COUNT 1024
#define SMMU_PTBL_SIZE (sizeof(u32) * SMMU_PTBL_COUNT)
#define SMMU_PDIR_SHIFT 12
#define SMMU_PDE_SHIFT 12
#define SMMU_PTE_SHIFT 12
#define SMMU_PFN_MASK 0x000FFFFF
#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12)
#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22)
#define SMMU_PDN_TO_ADDR(addr) ((pdn) << 22)
#define _READABLE (1 << MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT)
#define _WRITABLE (1 << MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT)
#define _NONSECURE (1 << MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT)
#define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT)
#define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR)
#define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR)
#define SMMU_MK_PDIR(page, attr) (((page) >> SMMU_PDIR_SHIFT) | (attr))
#define SMMU_MK_PDE(page, attr) (((page) >> SMMU_PDE_SHIFT) | (attr))
void *page_alloc(u32 num);
u32 *smmu_alloc_pdir();
void smmu_flush_regs();
void smmu_flush_all();
void smmu_init(u32 secmon_base);
void smmu_enable();
bool smmu_is_used();
void smmu_exit();
u32 *smmu_init_domain4(u32 dev_base, u32 asid);
u32 *smmu_get_pte(u32 *pdir, u32 iova);
void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr);
u32 *smmu_init_for_tsec();
void smmu_deinit_for_tsec();

Some files were not shown because too many files have changed in this diff Show More