-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LoadFragment 2 OK #2
Merged
Merged
Changes from 10 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
f4d01bd
load_fragment2
hensldm ed55b3c
dma.h
hensldm 535ab04
og DoRelocation
hensldm 8a42654
comment format
hensldm 5f32179
A few more docs
hensldm ea4d39e
symbol
hensldm 5bec446
remove _ from loadfragment2
hensldm f813b14
ptrdiff_t
hensldm 4a4d73d
Merge remote-tracking branch 'upstream/main' into load
hensldm f42c6fa
z_std_dma.h
hensldm fa97d5d
Merge remote-tracking branch 'upstream/main' into load
hensldm b572fdd
Format
hensldm 8ba3d66
load.h -> loadfragment.h
hensldm d9e44da
laodframgnet2 file optflags
hensldm c19f7e6
Small notes
hensldm bfe7f6a
Merge remote-tracking branch 'upstream/main' into load
hensldm f216a50
Per directory O2
hensldm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#ifndef LOAD_H | ||
#define LOAD_H | ||
|
||
#include "ultra64.h" | ||
|
||
extern s32 gOverlayLogSeverity; | ||
|
||
#define RELOC_SECTION(reloc) ((reloc) >> 30) | ||
#define RELOC_OFFSET(reloc) ((reloc) & 0xFFFFFF) | ||
#define RELOC_TYPE_MASK(reloc) ((reloc) & 0x3F000000) | ||
#define RELOC_TYPE_SHIFT 24 | ||
|
||
/* MIPS Relocation Types, matches the MIPS ELF spec */ | ||
#define R_MIPS_32 2 | ||
#define R_MIPS_26 4 | ||
#define R_MIPS_HI16 5 | ||
#define R_MIPS_LO16 6 | ||
|
||
typedef enum { | ||
/* 0 */ RELOC_SECTION_NULL, | ||
/* 1 */ RELOC_SECTION_TEXT, | ||
/* 2 */ RELOC_SECTION_DATA, | ||
/* 3 */ RELOC_SECTION_RODATA, | ||
/* 4 */ RELOC_SECTION_MAX | ||
} RelocSectionId; | ||
|
||
typedef struct OverlayRelocationSection { | ||
/* 0x00 */ u32 textSize; | ||
/* 0x04 */ u32 dataSize; | ||
/* 0x08 */ u32 rodataSize; | ||
/* 0x0C */ u32 bssSize; | ||
/* 0x10 */ u32 nRelocations; | ||
/* 0x14 */ u32 relocations[1]; // size is nRelocations | ||
} OverlayRelocationSection; // size >= 0x18 | ||
|
||
s32 Overlay_Load(void *vromStart, void *vromEnd, void *ovlStart, void *ovlEnd, void *vramStart, void *vramEnd, void *allocatedRamAddr, OverlayRelocationSection *ovlRelocs); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
/** | ||
* @file loadfragment2.c | ||
* | ||
* Functions used to process and relocate dynamically loadable code segments (overlays). | ||
* | ||
*/ | ||
#include "global.h" | ||
#include "load.h" | ||
#include "z_std_dma.h" | ||
|
||
void DoRelocation(void *allocatedRamAddr, OverlayRelocationSection *ovlRelocs, void *vramStart); | ||
|
||
s32 Overlay_Load(void *vromStart, void *vromEnd, void *ovlStart, void *ovlEnd, void *vramStart, void *vramEnd, | ||
void *allocatedRamAddr, OverlayRelocationSection *ovlRelocs) { | ||
OverlayRelocationSection *ovl = ovlRelocs; | ||
s32 vromSize = (uintptr_t)vromEnd - (uintptr_t)vromStart; | ||
s32 ovlSize = (uintptr_t)ovlEnd - (uintptr_t)ovlStart; | ||
s32 vramSize = (uintptr_t)vramEnd - (uintptr_t)vramStart; | ||
void *end = (void *)((uintptr_t)allocatedRamAddr + vromSize); | ||
|
||
DmaMgr_RequestSync(allocatedRamAddr, vromStart, vromSize); | ||
DmaMgr_RequestSync(ovl, ovlStart, ovlSize); | ||
DoRelocation(allocatedRamAddr, ovl, vramStart); | ||
|
||
if (ovl->bssSize != 0) { | ||
bzero(end, ovl->bssSize); | ||
} | ||
|
||
osWritebackDCache(allocatedRamAddr, vramSize); | ||
osInvalICache(allocatedRamAddr, vramSize); | ||
return vramSize; | ||
} | ||
|
||
// Extract MIPS register rs from an instruction word | ||
#define MIPS_REG_RS(insn) (((insn) >> 0x15) & 0x1F) | ||
|
||
// Extract MIPS register rt from an instruction word | ||
#define MIPS_REG_RT(insn) (((insn) >> 0x10) & 0x1F) | ||
|
||
// Extract MIPS jump target from an instruction word | ||
#define MIPS_JUMP_TARGET(insn) (((insn)&0x03FFFFFF) << 2) | ||
|
||
/** | ||
* Performs runtime relocation of overlay files, loadable code segments. | ||
* | ||
* Overlays are expected to be loadable anywhere in direct-mapped cached (KSEG0) memory, with some appropriate | ||
* alignment requirements; memory addresses in such code must be updated once loaded in order to execute properly. | ||
* When compiled, overlays are given 'fake' KSEG0 RAM addresses larger than the total possible available main memory | ||
* (>= 0x80800000), such addresses are referred to as Virtual RAM (VRAM) to distinguish them. When loading the overlay | ||
* the relocation table produced at compile time is consulted to determine where and how to update these VRAM addresses | ||
* to correct RAM addresses based on the location the overlay was loaded at, enabling the code to execute at this | ||
* address as if it were compiled to run at this address. | ||
* | ||
* Each relocation is represented by a packed 32-bit value, formatted in the following way: | ||
* - [31:30] 2-bit section id, taking values from the `RelocSectionId` enum. | ||
* - [29:24] 6-bit relocation type describing which relocation operation should be performed. Same as ELF32 MIPS. | ||
* - [23: 0] 24-bit section-relative offset indicating where in the section to apply this relocation. | ||
* | ||
* @param allocatedRamAddr Memory address the binary was loaded at. | ||
* @param ovlRelocs Overlay relocation section containing overlay section layout and runtime relocations. | ||
* @param vramStart Virtual RAM address that the overlay was compiled at. | ||
*/ | ||
void DoRelocation(void *allocatedRamAddr, OverlayRelocationSection *ovlRelocs, void *vramStart) { | ||
uintptr_t sections[RELOC_SECTION_MAX]; | ||
u32 *relocDataP; | ||
u32 reloc; | ||
u32 relocData; | ||
u32 isLoNeg; | ||
uintptr_t allocu32 = (uintptr_t)allocatedRamAddr; | ||
u32 i; | ||
u32 *regValP; | ||
//! MIPS ELF relocation does not generally require tracking register values, so at first glance it appears this | ||
//! register tracking was an unnecessary complication. However there is a bug in the IDO compiler that can cause | ||
//! relocations to be emitted in the wrong order under rare circumstances when the compiler attempts to reuse a | ||
//! previous HI16 relocation for a different LO16 relocation as an optimization. This register tracking is likely | ||
//! a workaround to prevent improper matching of unrelated HI16 and LO16 relocations that would otherwise arise | ||
//! due to the incorrect ordering. | ||
u32 *luiRefs[32]; | ||
u32 luiVals[32]; | ||
u32 *luiInstRef; | ||
UNUSED u32 dbg; | ||
ptrdiff_t relocOffset = 0; | ||
u32 relocatedValue = 0; | ||
UNUSED uintptr_t unrelocatedAddress = 0; | ||
uintptr_t relocatedAddress = 0; | ||
UNUSED s32 pad; | ||
|
||
if (gOverlayLogSeverity >= 3) {} | ||
|
||
sections[RELOC_SECTION_NULL] = 0; | ||
sections[RELOC_SECTION_TEXT] = allocu32; | ||
sections[RELOC_SECTION_DATA] = ovlRelocs->textSize + allocu32; | ||
sections[RELOC_SECTION_RODATA] = ovlRelocs->dataSize + sections[RELOC_SECTION_DATA]; | ||
|
||
for (i = 0; i < ovlRelocs->nRelocations; i++) { | ||
reloc = ovlRelocs->relocations[i]; | ||
// This will always resolve to a 32-bit aligned address as each section | ||
// containing code or pointers must be aligned to at least 4 bytes and the | ||
// MIPS ABI defines the offset of both 16-bit and 32-bit relocations to be | ||
// the start of the 32-bit word containing the target. | ||
relocDataP = (u32 *)(sections[RELOC_SECTION(reloc)] + RELOC_OFFSET(reloc)); | ||
relocData = *relocDataP; | ||
|
||
switch (RELOC_TYPE_MASK(reloc)) { | ||
case R_MIPS_32 << RELOC_TYPE_SHIFT: | ||
// Handles 32-bit address relocation, used for things such as jump tables and pointers in data. | ||
// Just relocate the full address. | ||
|
||
// Check address is valid for relocation | ||
if ((*relocDataP & 0x0F000000) == 0) { | ||
relocOffset = *relocDataP - (uintptr_t)vramStart; | ||
relocatedValue = relocOffset + allocu32; | ||
unrelocatedAddress = relocData; | ||
relocatedAddress = relocatedValue; | ||
*relocDataP = relocatedAddress; | ||
} | ||
break; | ||
|
||
case R_MIPS_26 << RELOC_TYPE_SHIFT: | ||
// Handles 26-bit address relocation, used for jumps and jals. | ||
// Extract the address from the target field of the J-type MIPS instruction. | ||
// Relocate the address and update the instruction. | ||
if (1) { | ||
relocOffset = PHYS_TO_K0(MIPS_JUMP_TARGET(*relocDataP)) - (uintptr_t)vramStart; | ||
unrelocatedAddress = PHYS_TO_K0(MIPS_JUMP_TARGET(*relocDataP)); | ||
relocatedValue = (*relocDataP & 0xFC000000) | (((allocu32 + relocOffset) & 0x0FFFFFFF) >> 2); | ||
relocatedAddress = PHYS_TO_K0(MIPS_JUMP_TARGET(relocatedValue)); | ||
*relocDataP = relocatedValue; | ||
} | ||
break; | ||
|
||
case R_MIPS_HI16 << RELOC_TYPE_SHIFT: | ||
// Handles relocation for a hi/lo pair, part 1. | ||
// Store the reference to the LUI instruction (hi) using the `rt` register of the instruction. | ||
// This will be updated later in the `R_MIPS_LO16` section. | ||
|
||
luiRefs[MIPS_REG_RT(*relocDataP)] = relocDataP; | ||
luiVals[MIPS_REG_RT(*relocDataP)] = *relocDataP; | ||
break; | ||
|
||
case R_MIPS_LO16 << RELOC_TYPE_SHIFT: | ||
// Handles relocation for a hi/lo pair, part 2. | ||
// Grab the stored LUI (hi) from the `R_MIPS_HI16` section using the `rs` register of the instruction. | ||
// The full address is calculated, relocated, and then used to update both the LUI and lo instructions. | ||
// If the lo part is negative, add 1 to the LUI value. | ||
// Note: The lo instruction is assumed to have a signed immediate. | ||
|
||
luiInstRef = luiRefs[MIPS_REG_RS(*relocDataP)]; | ||
regValP = &luiVals[MIPS_REG_RS(*relocDataP)]; | ||
|
||
// Check address is valid for relocation | ||
if ((((*regValP << 0x10) + (s16)*relocDataP) & 0x0F000000) == 0) { | ||
relocOffset = ((*regValP << 0x10) + (s16)*relocDataP) - (uintptr_t)vramStart; | ||
isLoNeg = ((relocOffset + allocu32) & 0x8000) ? 1 : 0; // adjust for signed immediate | ||
unrelocatedAddress = (*luiInstRef << 0x10) + (s16)relocData; | ||
*luiInstRef = | ||
(*luiInstRef & 0xFFFF0000) | ((((relocOffset + allocu32) >> 0x10) & 0xFFFF) + isLoNeg); | ||
relocatedValue = (*relocDataP & 0xFFFF0000) | ((relocOffset + allocu32) & 0xFFFF); | ||
|
||
relocatedAddress = (*luiInstRef << 0x10) + (s16)relocatedValue; | ||
*relocDataP = relocatedValue; | ||
} | ||
break; | ||
} | ||
|
||
dbg = 16; | ||
switch (RELOC_TYPE_MASK(reloc)) { | ||
case R_MIPS_32 << RELOC_TYPE_SHIFT: | ||
dbg += 6; | ||
FALLTHROUGH; | ||
case R_MIPS_26 << RELOC_TYPE_SHIFT: | ||
dbg += 10; | ||
FALLTHROUGH; | ||
case R_MIPS_LO16 << RELOC_TYPE_SHIFT: | ||
if (gOverlayLogSeverity >= 3) {} | ||
// Adding a break prevents matching | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#include "global.h" | ||
|
||
s32 gOverlayLogSeverity = 2; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is only going to be for loadfragment2 it seems better to name it after the file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loadfragment2 isn't the only file that will include this. Any folder that uses
Overlay_Relocate
will as well. That I do see a point in naming it something likeloadfragment.h
so will do that (I don't really want to add the 2).