| /****************************************************************************** |
| * Copyright (c) 2004, 2008 IBM Corporation |
| * All rights reserved. |
| * This program and the accompanying materials |
| * are made available under the terms of the BSD License |
| * which accompanies this distribution, and is available at |
| * http://www.opensource.org/licenses/bsd-license.php |
| * |
| * Contributors: |
| * IBM Corporation - initial implementation |
| *****************************************************************************/ |
| #include "macros.h" |
| #include "romfs.h" |
| |
| /******************************************************************* |
| * Wrapper for romfs_lookup. |
| * |
| * Input: |
| * R3 = address of filename string |
| * R4 = address of struct romfs_t |
| * 0: file size (return) |
| * 8: flags (return) |
| * 10: fileaddr (return and input: tells if first search) |
| * 18: nextfile (return) |
| * 20: namep (return) |
| * |
| * Find File Procedure |
| * - set filename and rombase, on return 0 file properties are stored |
| * in romfs_t else struct not valid |
| * |
| * Listing procedure |
| * - clear romfs_t (important!) |
| * - set filename = NULL and rombase and call returns first file |
| * with properties in romfs_t including next-file pointer |
| * - if nextpointer is non-zero then just the next file is returned |
| * |
| * Returns: |
| * <Success>: |
| * R3 = 0 |
| * romfs_t is updated |
| * <FileNotFound>: |
| * R3 = 1 |
| * romfs_t not touched |
| * |
| * Potentially modifies the following registers: |
| * |
| |
| Example usage from C: |
| |
| int list_bootrom() |
| { |
| struct romfs_t rfs; |
| int i; |
| |
| printf("Build: "__TIME__" "__DATE__" \n"); |
| |
| i = 0; |
| memset((void*) &rfs, 0, sizeof(struct romfs_t)); |
| printf(" No. File Data Size Name\n"); |
| |
| while (romfs_stat(NULL, &rfs) == 0) { |
| i++; |
| printf(" %02d: %08X %08X %7d %s\n", |
| i, rfs.fileaddr, rfs.datap, |
| rfs.size, rfs.namep); |
| } |
| if (0 == i) { |
| printf("Error in reading ROMFS\n"); |
| return 1; |
| } |
| return 0; |
| } |
| *******************************************************************/ |
| #define RFS_T_SIZE 0x00 |
| #define RFS_T_FLAGS 0x08 |
| #define RFS_T_FILEADDR 0x10 |
| #define RFS_T_NEXT 0x18 |
| #define RFS_T_NAME 0x20 |
| #define RFS_T_DATA 0x28 |
| |
| #define RFS_H_NEXT 0x00 |
| #define RFS_H_SIZE 0x08 |
| #define RFS_H_FLAGS 0x10 |
| #define RFS_H_DATA 0x18 |
| #define RFS_H_NAME 0x20 |
| |
| ENTRY(romfs_stat_file) |
| /* save link register and romfs_t pointer */ |
| mflr r15 |
| mr r16, r4 |
| |
| /* if filename R3 is 0 then its a listing request */ |
| /* if not then just continue to lookup name */ |
| /* save R4 to R8 which is the address of header */ |
| li r7, 0 |
| cmpd r3, r7 |
| beq romfs_list |
| bl romfs_lookup |
| mfsprg r8, 1 |
| |
| /* if file found then go to romfs_fill_properties */ |
| /* else return 1 to caller */ |
| cmpwi r3, 0 |
| beq romfs_fill_properties |
| b romfs_stat_end |
| |
| romfs_list: |
| /* check if fileaddr == 0, in this case its */ |
| /* the first search on this handle, so return all */ |
| /* info for file at rombase (R8=R4) */ |
| ld r6, RFS_T_FILEADDR(r4) |
| mfsprg r8, 1 |
| li r7, 0 |
| cmpd r7, r6 |
| beq romfs_fill_properties |
| |
| /* check if next file != 0 by looking into */ |
| /* romfs_t, if not then return (next = 0) 1 */ |
| li r7, 0 |
| ld r4, RFS_T_NEXT(r4) |
| cmpd r7, r4 |
| li r3, 1 |
| beq romfs_stat_end |
| |
| /* now next file is available so move R8 to next */ |
| /* file address */ |
| mr r8, r4 |
| |
| romfs_fill_properties: |
| /* set properties in romfs_t takes R8 as address */ |
| /* to file header and R16 as address of romfs_t */ |
| mfsprg r3, 1 |
| std r8, RFS_T_FILEADDR(r16) |
| |
| ld r4, RFS_H_NEXT(r8) |
| li r7, 0 |
| cmpd r7, r4 |
| beq $ + (2 * 4) /* =0 so add no rombase */ |
| add r4, r4, r3 |
| std r4, RFS_T_NEXT(r16) |
| |
| ld r4, RFS_H_SIZE(r8) |
| std r4, RFS_T_SIZE(r16) |
| ld r4, RFS_H_FLAGS(r8) |
| std r4, RFS_T_FLAGS(r16) |
| |
| ld r4, RFS_H_DATA(r8) |
| add r4, r4, r3 |
| std r4, RFS_T_DATA(r16) |
| |
| addi r4, r8, RFS_H_NAME |
| std r4, RFS_T_NAME(r16) |
| |
| li r3, 0 |
| |
| /* restore romfs_t pointer and link register */ |
| romfs_stat_end: |
| mr r5, r16 |
| mtlr r15 |
| blr |
| |
| /******************************************************************* |
| * Copies the data of file referenced by name string to address |
| * requires root address of filesystem. |
| * FIXME: ignores flags |
| * |
| * Input: |
| * R3 = address of filename string |
| * R4 = ROMBASE |
| * R5 = destination address |
| * |
| * Returns: |
| * <Success>: R3 = 0, R6 = size, <FileNotFound>: R3 = 1 |
| * R5 is kept |
| * |
| * Potentially modifies the following registers: |
| * ctr, r15, r16, r17, r18 |
| * |
| * Uses the following calls with subsequent register modification: |
| * - romfs_lookup |
| *******************************************************************/ |
| ASM_ENTRY(romfs_load) |
| mflr r15 |
| |
| /* save R5 twice */ |
| /* lookup file, input regs */ |
| /* are already set */ |
| /* if not found, just return */ |
| mr r16, r5 |
| mr r17, r5 |
| bl romfs_lookup |
| cmpwi r3, 1 |
| bne 0f |
| mtlr r15 |
| blr /* abort, not found */ |
| |
| /* save data size for return */ |
| /* found, copy data */ |
| /* data size is in R6 */ |
| 0: |
| //mr r3, r6 |
| mtctr r6 |
| addi r16, r16, -1 /* dest */ |
| addi r5, r5, -1 /* source*/ |
| |
| /* data is expected to be */ |
| /* 8 byte aligned */ |
| /* copy loop */ |
| 0: lbzu r18, 1(r5) |
| stbu r18, 1(r16) |
| bdnz 0b |
| |
| /* restore size, keep padding */ |
| /* restore target address */ |
| /* return */ |
| mr r5, r17 |
| mtlr r15 |
| blr |
| |
| /******************************************************************* |
| * looks up a file based on filename |
| * |
| * Input: |
| * R3 = address of filename string |
| * R4 = ROMBASE |
| * |
| * Returns: |
| * <Success>: |
| * R3 = 0 |
| * R4 = address of file header |
| * R5 = address of data (real address) |
| * R6 = size of data |
| * R7 = flags for file |
| * <FileNotFound>: |
| * R3 = 1 |
| * |
| * Potentially modifies the following registers: |
| * R3, R4, R5, R6, R7, R8, R9 |
| * |
| * Uses the following calls with subsequent register modification: |
| * - romfs_namematch |
| *******************************************************************/ |
| ASM_ENTRY(romfs_lookup) |
| mflr r9 |
| |
| romfs_lookup_next: |
| /* save current file base */ |
| mr r8, r4 |
| /* name to look for */ |
| mr r10, r3 |
| /* name of file */ |
| mr r5, r4 |
| addi r5, r5, (4 /* elems */ * 8 /* elem-size */) |
| mr r11, r5 /* for namematch */ |
| /* compare */ |
| bl romfs_namematch |
| cmpwi r12, 1 |
| bne romfs_lookup_match |
| |
| /* load next pointer */ |
| /* check if next is 0 */ |
| /* apply root-offset */ |
| ld r5, 0(r4) |
| cmpwi r5, 0 |
| add r4, r4, r5 |
| bne romfs_lookup_next |
| /* last file reached, abort */ |
| li r3, 1 |
| mtlr r9 |
| blr |
| |
| /* here the name did match */ |
| /* r4 is still usable here and */ |
| /* pointing to the initial file */ |
| /* load r5 with data ptr */ |
| /* load r6 with data size */ |
| /* load r7 with flags */ |
| /* get abs addr of data */ |
| romfs_lookup_match: |
| li r3, 0 |
| ld r5, (3 * 8)(r4) /* data */ |
| ld r6, (1 * 8)(r4) /* len */ |
| ld r7, (2 * 8)(r4) /* flags */ |
| add r5, r5, r8 |
| mtlr r9 |
| blr |
| |
| /******************************************************************* |
| * compares two strings in memory, |
| * both must be null-terminated and 8-byte aligned |
| * |
| * Input: |
| * R10 = string 1 |
| * R11 = string 2 |
| * |
| * Returns: |
| * <Match>: R12 = 0 <NoMatch>: R12 = 1 |
| * |
| * Potentially modifies the following registers: |
| * R10, R11, r12, r13, r14 |
| *******************************************************************/ |
| romfs_namematch: |
| subi r10, r10, 8 |
| subi r11, r11, 8 |
| |
| /* |
| * load chars as 8byte chunk from current pos, name is |
| * always 8 byte aligned :) |
| */ |
| romfs_cmp_loop: |
| ldu r13, 8(r10) /* A */ |
| ldu r14, 8(r11) /* B */ |
| |
| cmpd r13, r14 |
| li r12, 1 |
| beq 1f |
| blr |
| |
| 1: andi. r14, r14, 0xff |
| bne romfs_cmp_loop |
| |
| li r12, 0 |
| blr |
| |
| /******************************************************************* |
| * wrapper for romfs_lookup |
| * this function saves the registers from r13 - r15 on the stack |
| * calls romfs_lookup |
| * restores the saved registers |
| * |
| * the return parameters are copied to (r5) and (r5) has to |
| * be 0x20 big |
| *******************************************************************/ |
| ENTRY(c_romfs_lookup) |
| stdu r1,-0x50(r1) # allocate space on stack |
| |
| mflr r0 # save link register |
| std r0,0x30(r1) |
| |
| std r15,0x38(r1) # save r15 |
| std r14,0x40(r1) # save r14 |
| std r13,0x48(r1) # and r13 |
| |
| mr r15,r5 # save the pointer for the return value |
| |
| bl romfs_lookup # do the thing |
| |
| ld r0,0x30(r1) # restore link register |
| mtlr r0 |
| |
| std r4,0x00(r15) # copy return values |
| std r5,0x08(r15) # to the return pointer |
| std r6,0x10(r15) |
| std r7,0x18(r15) |
| |
| ld r13,0x48(r1) # restore registers from stack |
| ld r14,0x40(r1) |
| ld r15,0x38(r1) |
| |
| addi r1,r1,0x50 # cleanup stack |
| |
| blr |