gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > dldipatch code help (Renamed)

#159192 - cornaljoe - Thu Jun 26, 2008 6:03 pm

Here is the code I'm using:

Code:
/*---------------------------------------------------------------------------------

   Quick DLDI chaining example
   Loads "/fat3.dldi" from the first device, then uses that to read from a
   second device.
   This is quickly written, messy code. No warranty is given.
   
   Copyright 2007 by Michael "Chishm" Chisholm

---------------------------------------------------------------------------------*/
#include <nds.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fat.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <sys/dir.h>
#include <sys/stat.h>

#include "dldi_chain.h"

#ifdef __cplusplus
extern "C" {
#endif

#define MAGIC_TOKEN 0xBF8DA5ED

#define FIX_ALL   0x01
#define FIX_GLUE   0x02
#define FIX_GOT   0x04
#define FIX_BSS   0x08

#define DLDI_VERSION 1

enum DldiOffsets {
   DO_magicString = 0x00,         // "\xED\xA5\x8D\xBF Chishm"
   DO_magicToken = 0x00,         // 0xBF8DA5ED
   DO_magicShortString = 0x04,      // " Chishm"
   DO_version = 0x0C,
   DO_driverSize = 0x0D,
   DO_fixSections = 0x0E,
   DO_allocatedSpace = 0x0F,

   DO_friendlyName = 0x10,

   DO_text_start = 0x40,         // Data start
   DO_data_end = 0x44,            // Data end
   DO_glue_start = 0x48,         // Interworking glue start   -- Needs address fixing
   DO_glue_end = 0x4C,            // Interworking glue end
   DO_got_start = 0x50,         // GOT start               -- Needs address fixing
   DO_got_end = 0x54,            // GOT end
   DO_bss_start = 0x58,         // bss start               -- Needs setting to zero
   DO_bss_end = 0x5C,            // bss end

   DO_driverStart = 0x60,
   // IO_INTERFACE data
   DO_ioType = 0x60,
   DO_features = 0x64,
   DO_startup = 0x68,   
   DO_isInserted = 0x6C,   
   DO_readSectors = 0x70,   
   DO_writeSectors = 0x74,
   DO_clearStatus = 0x78,
   DO_shutdown = 0x7C,
   DO_code = 0x80
};

const u8 dldiMagicString[] = "\xED\xA5\x8D\xBF Chishm";

#define READ_ADDR(d,o) (*(u32*)((d)+(o)))
#define WRITE_ADDR(d,o,v) *(u32*)((d)+(o)) = (v)

int dldiPatch (u8* data, u32 len) {
   unsigned int memOffset, ddmemOffset, relocationOffset;
   unsigned int ddmemStart, ddmemSize, ddmemEnd;
   unsigned int addrIter;

   // Make sure the DLDI file is valid and usable
   if (strcmp ((char*)dldiMagicString, (char*)&data[DO_magicString]) != 0) {
      return -1;
   }
   if (data[DO_version] != DLDI_VERSION) {
      return -1;
   }

   memOffset = (u32)data;

   ddmemOffset = READ_ADDR (data, DO_text_start);
   relocationOffset = memOffset - ddmemOffset;

   ddmemStart = READ_ADDR (data, DO_text_start);
   ddmemSize = (1 << data[DO_driverSize]);
   ddmemEnd = ddmemStart + ddmemSize;

   // Fix the section pointers in the header
   WRITE_ADDR (data, DO_text_start, READ_ADDR (data, DO_text_start) + relocationOffset);
   WRITE_ADDR (data, DO_data_end, READ_ADDR (data, DO_data_end) + relocationOffset);
   WRITE_ADDR (data, DO_glue_start, READ_ADDR (data, DO_glue_start) + relocationOffset);
   WRITE_ADDR (data, DO_glue_end, READ_ADDR (data, DO_glue_end) + relocationOffset);
   WRITE_ADDR (data, DO_got_start, READ_ADDR (data, DO_got_start) + relocationOffset);
   WRITE_ADDR (data, DO_got_end, READ_ADDR (data, DO_got_end) + relocationOffset);
   WRITE_ADDR (data, DO_bss_start, READ_ADDR (data, DO_bss_start) + relocationOffset);
   WRITE_ADDR (data, DO_bss_end, READ_ADDR (data, DO_bss_end) + relocationOffset);
   // Fix the function pointers in the header
   WRITE_ADDR (data, DO_startup, READ_ADDR (data, DO_startup) + relocationOffset);
   WRITE_ADDR (data, DO_isInserted, READ_ADDR (data, DO_isInserted) + relocationOffset);
   WRITE_ADDR (data, DO_readSectors, READ_ADDR (data, DO_readSectors) + relocationOffset);
   WRITE_ADDR (data, DO_writeSectors, READ_ADDR (data, DO_writeSectors) + relocationOffset);
   WRITE_ADDR (data, DO_clearStatus, READ_ADDR (data, DO_clearStatus) + relocationOffset);
   WRITE_ADDR (data, DO_shutdown, READ_ADDR (data, DO_shutdown) + relocationOffset);

   if (data[DO_fixSections] & FIX_ALL) {
      // Search through and fix pointers within the data section of the file
      for (addrIter = (READ_ADDR(data, DO_text_start) - ddmemStart); addrIter < (READ_ADDR(data, DO_data_end) - ddmemStart); addrIter++) {
         if ((ddmemStart <= READ_ADDR(data, addrIter)) && (READ_ADDR(data, addrIter) < ddmemEnd)) {
            WRITE_ADDR (data, addrIter, READ_ADDR(data, addrIter) + relocationOffset);
         }
      }
   }

   if (data[DO_fixSections] & FIX_GLUE) {
      // Search through and fix pointers within the glue section of the file
      for (addrIter = (READ_ADDR(data, DO_glue_start) - ddmemStart); addrIter < (READ_ADDR(data, DO_glue_end) - ddmemStart); addrIter++) {
         if ((ddmemStart <= READ_ADDR(data, addrIter)) && (READ_ADDR(data, addrIter) < ddmemEnd)) {
            WRITE_ADDR (data, addrIter, READ_ADDR(data, addrIter) + relocationOffset);
         }
      }
   }

   if (data[DO_fixSections] & FIX_GOT) {
      // Search through and fix pointers within the Global Offset Table section of the file
      for (addrIter = (READ_ADDR(data, DO_got_start) - ddmemStart); addrIter < (READ_ADDR(data, DO_got_end) - ddmemStart); addrIter++) {
         if ((ddmemStart <= READ_ADDR(data, addrIter)) && (READ_ADDR(data, addrIter) < ddmemEnd)) {
            WRITE_ADDR (data, addrIter, READ_ADDR(data, addrIter) + relocationOffset);
         }
      }
   }

   if (data[DO_fixSections] & FIX_BSS) {
      // Initialise the BSS to 0
      memset (&data[READ_ADDR(data, DO_bss_start) - ddmemStart] , 0, READ_ADDR(data, DO_bss_end) - READ_ADDR(data, DO_bss_start));
   }
   
   return 0;
}


//---------------------------------------------------------------------------------
void CustomFatInit() {
//---------------------------------------------------------------------------------

   fatInitDefault();
   
   FILE* customDriver = fopen ("/fat3.dldi", "rb");
   if (customDriver == NULL) {
      while(1) swiWaitForVBlank();
   }
   fseek (customDriver, 0, SEEK_END);
   size_t driverSize = ftell (customDriver);
   fseek (customDriver, 0, SEEK_SET);
   u8* driverData = malloc (driverSize);
   fread (driverData, 1, driverSize, customDriver);
   fclose (customDriver);
   
   if (dldiPatch (driverData, driverSize) < 0) {
      while(1) swiWaitForVBlank();
   }

   fatMountCustomInterface ((struct IO_INTERFACE_STRUCT*) (driverData + DO_driverStart), 8);
}

#ifdef __cplusplus
}
#endif


It's a modified version of Chishm dldi_chain demo posted here. I use this function in place of fatInitDefault() in order to load 2 FAT systems.

Everything seems fine only the custom interface thats loaded from 'fat0:/fat3.dldi' is only readable. When attempting to write to the disk (fat3:/) it writes a 0 byte file and freezes the DS. Anyone know how I can fix this? Thanks for the help.


Last edited by cornaljoe on Sat Jul 05, 2008 3:25 am; edited 1 time in total

#159210 - cornaljoe - Fri Jun 27, 2008 1:35 am

Ok I browsed over the source of libnds and even though I have no idea what I'm looking at I think I've found something that may help.

Code:
typedef struct {
   const IO_INTERFACE* disc;
   CACHE* cache;
   // Info about the partition
   bool readOnly;      // If this is set, then do not try writing to the disc             <- This is the key
   FS_TYPE filesysType;
   u32 totalSize;
   u32 rootDirStart;
   u32 rootDirCluster;
   u32 numberOfSectors;
   u32 dataStart;
   u32 bytesPerSector;
   u32 sectorsPerCluster;
   u32 bytesPerCluster;
   FAT fat;
   // Values that may change after construction
   u32 cwdCluster;         // Current working directory cluser
   u32 openFileCount;
} PARTITION;

and

// Check if this disc is writable, and set the readOnly property appropriately
   partition->readOnly = !(_FAT_disc_features(disc) & FEATURE_MEDIUM_CANWRITE);


Looking at that I've come to find using this should fix my problem:
Code:
_FAT_partitions[PI_CUSTOM]->readOnly = false;


But I can't use that in my source because none of the variables exist except PI_CUSTOM. Any ideas?

#159425 - cornaljoe - Mon Jun 30, 2008 5:54 pm

I recompiled libfat for test purposes and found the problem in the dldiPatch function. It seems to patch in a way that only allows read access to the disk. Anyone understand how the patching code works? I can't get ahold of chishm atm, he would be great help.

#159428 - elhobbs - Mon Jun 30, 2008 6:36 pm

has anyone tried adding print statments for data[DO_features] at various stages of the reloacation code? I think the bss section is for uninitialized data, but it does get forced to 0. could it be happening there? maybe you could try saving the data[DO_features] value before the relocation and then puting it back afterwords - this would at least tell you if the relocation code is the problem.

#159471 - cornaljoe - Tue Jul 01, 2008 6:53 pm

It seems that the relocation code works fine. I also tried initializing BSS normally with no luck aswell. Thanks for the suggestions but I'm still puzzled on what the problem could be.

#159475 - elhobbs - Tue Jul 01, 2008 7:40 pm

cornaljoe wrote:
It seems that the relocation code works fine. I also tried initializing BSS normally with no luck aswell. Thanks for the suggestions but I'm still puzzled on what the problem could be.
so, the FEATURE_MEDIUM_CANWRITE bit is set at data[DO_features] before and after relocation? that should be the determination for being able to write.

#159503 - cornaljoe - Wed Jul 02, 2008 2:45 am

Sorry I have very little knowledge of memory management but I'll give it a try. Here is the code I used to display the value of data[DO_features] before and after the relocation. I got the same result.

Code:
printf ("Features:          0x%08X\n", data[DO_features]);

Result:    0x00000013


According to disc_io.h
Code:
#define FEATURE_MEDIUM_CANREAD      0x00000001
#define FEATURE_MEDIUM_CANWRITE      0x00000002
#define FEATURE_SLOT_GBA         0x00000010
#define FEATURE_SLOT_NDS         0x00000020


So its being detected as Slot-2 but the last bit is set to 3 instead of 1/2. Cool I guess I did it right! Thanks I'm actually learning alot here. Can I just change the value to get it to work?

Edit: Wait 1 + 2 = 3 so does that mean its the value for reading and writing?

#159536 - fluff - Wed Jul 02, 2008 1:07 pm

cornaljoe wrote:
the last bit is set to 3 instead of 1/2


That's a pretty powerful bit! :P

cornaljoe wrote:

Edit: Wait 1 + 2 = 3 so does that mean its the value for reading and writing?


Yeah.

#159539 - silent_code - Wed Jul 02, 2008 1:17 pm

Quantum bits can "store" 3 states with 1bit: Yes, No, Maybe ;^)
_________________
July 5th 08: "Volumetric Shadow Demo" 1.6.0 (final) source released
June 5th 08: "Zombie NDS" WIP released!
It's all on my page, just click WWW below.

#159541 - elhobbs - Wed Jul 02, 2008 1:26 pm

silent_code wrote:
Quantum bits can "store" 3 states with 1bit: Yes, No, Maybe ;^)
off topic but I think you may be wrong. binary bits can store 8 states with 3 bits. a single quantum bit has three states. so wouldn't that mean it could store 27 states with 3 bits?

#159542 - silent_code - Wed Jul 02, 2008 1:31 pm

I am not an expert, but qbits have two states and a (range) superstate inbetween.

But I remember (may not be accurate, it's been a while) you could store 8bit worth of information in just 3qbits. That's because these qbits don't count as single bits in a qbit set, but rather all as an unit. That makes it not pow(2, 8) = 256, but pow(2, pow(2, 3)) = 256 for qbits. (The formula may be bogus for anything else than 3qbits, though.)
It's due to the parallel storage of multiple states in the qbit set (through "maybe"s)... Well, something like that. ;^)

Wikipedia says: One qbyte can not only store the numbers 0 to 255, it can also store them all, at the same time. Actually, non trivial sets (includes the qbit) can represent an infinite set of numbers, due to the non discrete nature of the superstate and qbit entanglement (I'm not sure about that, though - I'm not an expert.)
Brain hurt.
_________________
July 5th 08: "Volumetric Shadow Demo" 1.6.0 (final) source released
June 5th 08: "Zombie NDS" WIP released!
It's all on my page, just click WWW below.