Cómo se lanza un homebrew
Una de las partes más interesantes del HBL es cómo se carga y se arranca un EBOOT.PBP. La función que realiza esto se llama run_eboot. No voy a ver run_menu ya que básciamente es run_eboot con una serie de pruebas previas (comprobad como llama a run_eboot).
Código: Seleccionar todo
void run_eboot(const char *path, int is_eboot)
Recibe la ruta del EBOOT a cargar (path), y si es un PBP (is_eboot). Esto se debe a que un principio el HBL sólo cargaba ELFs, y si is_eboot es 0, se trata como un ELF, si es 1, como un EBOOT.
Código: Seleccionar todo
//Load Game config overrides
Carga los ajustes específicos para el homebrew elegido.
Código: Seleccionar todo
if (is_eboot)
Lo que comentaba antes. Si es un EBOOT, se debe llamar a elf_eboot_extract_open para localizar el ELF dentro del EBOOT. Si es un ELF, simplemente se abre.
Código: Seleccionar todo
memset(sceGeEdramGetAddr(), 0, sceGeEdramGetSize());
Limpia la memoria de vídeo.
Código: Seleccionar todo
mod_id = load_module(elf_file, path, (void*)PRX_LOAD_ADDRESS, offset);
Carga el ELF, ya sea el que se encuentra dentro de un EBOOT o uno suelto (como un PRX por ejemplo).
Código: Seleccionar todo
mod_id = start_module(mod_id);
Lanza el ELF.
Código: Seleccionar todo
return;
Hemos acabado.
Como recordaréis, es wait_for_eboot_end();, que vimos en el capítulo anterior, la que se encarga de detectar cuando acaba el EBOOT y luego cleanup de limpiar la memoria.
Tablas de estado del sistema (I): exportes
En tables.h se encuentra la definición de algunas de las tablas de estado del sistema que maneja HBL, concretamente las relacionadas con importes (syscalls y librerías). Vamos a echarles un vistazo.
Código: Seleccionar todo
typedef struct
{
u32 nid; // NID
u32 call; // Syscall/jump associated to the NID
unsigned int lib_index; // Index to the library descriptor tSceLibrary
} tNIDResolver;
Ésta es posiblemente la primera (y única en su momento) tabla del sistema de HBL.
- nid identifica la función en cuestión. En PSP cada función exportada (accesible desde otros módulos) se le debe asignar un NID, que no es más que un número de 32 bits sin signo.
- call es el syscall asociado a dicho NID (qué syscall debe usar el homebrew para llamar a la función identificada por el NID).
- lib_index es un índice a otra tabla, que indica a qué librería pertenece este NID. Las funciones exportadas por un módulo siempre deben pertenecer a una librería.
Se usa un array/vector estático (de tamaño fijo) que contiene tantos elementos de éstos como indica la constante NID_TABLE_SIZE. Es la siguiente estructura que nos encontramos, donde table es el mencionado array y num nos indica cuántos elementos de table están rellenados con información.
Código: Seleccionar todo
typedef struct
{
unsigned int num; // Number of nids on table
tNIDResolver table[NID_TABLE_SIZE]; // NID resolver
} HBLNIDTable;
Esta tabla contiene todos los syscalls que el HBL conoce. Los que no se encuentren en esta tabla se deberán de estimar matemáticamente llegado el momento.
Luego tenemos las tablas de librerías, cuyo elemento básico que describe una librería es el siguiente:
Código: Seleccionar todo
typedef struct
{
char name[MAX_LIBRARY_NAME_LENGTH]; // Library name
tCallingMode calling_mode; // Defines how library exports are called
unsigned int num_library_exports; // Number of exported functions in library
unsigned int num_known_exports; // Number of known exported functions (exports we know the syscall of)
u32 lowest_syscall; // Lowest syscall number found
u32 lowest_nid; // NID associated to lowest syscall
unsigned int lowest_index; // Lowest NID index nids_table
u32 highest_syscall; // Highest syscall number found
u32 gap; // Offset between the syscall for the highest and the lowest nid index in 6.20
} tSceLibrary;
- name guarda el nombre de la librería.
- calling_mode define de qué modo se llama a la librería (si salto o syscall, no entraré en detalles).
- num_library_exports guarda cuántas funciones diferentes en total se exportan en esta librería.
- num_known_exports guarda cuántos syscalls conoce el HBL del total de funciones exportadas (sólo aplica a las librerías syscall).
- lowest_syscall guarda el syscall más bajo de la librería que conoce el HBL.
- lowest_nid guarda el NID del syscall más bajo que conoce el HBL.
- lowest_index indica la posición en la tabla HBLNIDTable del syscall más bajo.
- highest_syscall indica el syscall más alto de la librería que concoce HBL.
- gap indica el hueco entre el syscall más bajo y el más alto en 6.20+ (no entraremos en detalles).
A una de estas estructuras es a lo que hace referencia el lib_index de tNIDResolver.
Obviamente esta estructura se argupa en un array, al igual que antes, donde se describen todas las librerías que conoce el HBL, tal que así:
Código: Seleccionar todo
typedef struct
{
unsigned int num;
tSceLibrary table[MAX_LIBRARIES];
} HBLLibTable;
donde la constante MAX_LIBRARIES define el número máximo de librerías que puede conocer el HBL.
Estas tablas son rellenadas por la función build_nid_table, que como algunos recordaréis, se llama en el bucle de la función principal del HBL (que vimos en el pasado capítulo).
Bueno, esto es todo por este capítulo, más intestinos en el próximo.
<< Anterior Siguiente >>