diff options
Diffstat (limited to 'slof/fs/elf.fs')
-rw-r--r-- | slof/fs/elf.fs | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/slof/fs/elf.fs b/slof/fs/elf.fs new file mode 100644 index 0000000..8f1c7b7 --- /dev/null +++ b/slof/fs/elf.fs @@ -0,0 +1,305 @@ +\ ***************************************************************************** +\ * 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 +\ ****************************************************************************/ + +\ ELF 32 bit header + +STRUCT + /l field ehdr>e_ident + /c field ehdr>e_class + /c field ehdr>e_data + /c field ehdr>e_version + /c field ehdr>e_pad + /l field ehdr>e_ident_2 + /l field ehdr>e_ident_3 + /w field ehdr>e_type + /w field ehdr>e_machine + /l field ehdr>e_version + /l field ehdr>e_entry + /l field ehdr>e_phoff + /l field ehdr>e_shoff + /l field ehdr>e_flags + /w field ehdr>e_ehsize + /w field ehdr>e_phentsize + /w field ehdr>e_phnum + /w field ehdr>e_shentsize + /w field ehdr>e_shnum + /w field ehdr>e_shstrndx +END-STRUCT + + +\ ELF 32 bit program header + +STRUCT + /l field phdr>p_type + /l field phdr>p_offset + /l field phdr>p_vaddr + /l field phdr>p_paddr + /l field phdr>p_filesz + /l field phdr>p_memsz + /l field phdr>p_flags + /l field phdr>p_align +END-STRUCT + +\ Provide word to load image to an offset of vaddr +0 value elf-segment-offset + +: xlate-vaddr32 ( programm-header-addr -- addr ) + phdr>p_vaddr l@ elf-segment-offset + +; + + +\ ELF 64 bit header + +STRUCT + /l field ehdr64>e_ident + /c field ehdr64>e_class + /c field ehdr64>e_data + /c field ehdr64>e_version + /c field ehdr64>e_pad + /l field ehdr64>e_ident_2 + /l field ehdr64>e_ident_3 + /w field ehdr64>e_type + /w field ehdr64>e_machine + /l field ehdr64>e_version + cell field ehdr64>e_entry + cell field ehdr64>e_phoff + cell field ehdr64>e_shoff + /l field ehdr64>e_flags + /w field ehdr64>e_ehsize + /w field ehdr64>e_phentsize + /w field ehdr64>e_phnum + /w field ehdr64>e_shentsize + /w field ehdr64>e_shnum + /w field ehdr64>e_shstrndx +END-STRUCT + + +\ ELF 64 bit program header + +STRUCT + /l field phdr64>p_type + /l field phdr64>p_flags + cell field phdr64>p_offset + cell field phdr64>p_vaddr + cell field phdr64>p_paddr + cell field phdr64>p_filesz + cell field phdr64>p_memsz + cell field phdr64>p_align +END-STRUCT + + +\ Claim memory for segment +\ Abort, if no memory available + +false value elf-claim? +0 value last-claim + +: claim-segment ( file-addr program-header-addr -- ) + elf-claim? IF + >r + here last-claim , to last-claim \ Setup ptr to last claim + \ Put addr and size ain the data space + r@ phdr>p_vaddr l@ dup , r> phdr>p_memsz l@ dup , ( file-addr addr size ) + 0 ['] claim CATCH IF ABORT" Memory for ELF file already in use " THEN + THEN + 2drop +; + +: claim-segment64 ( file-addr program-header-addr -- ) + elf-claim? IF + >r + here last-claim , to last-claim \ Setup ptr to last claim + \ Put addr and size ain the data space + r@ phdr64>p_vaddr @ dup , r> phdr64>p_memsz @ dup , ( file-addr addr size ) + 0 ['] claim CATCH IF ABORT" Memory for ELF file already in use " THEN + THEN + 2drop +; + +: load-segment ( file-addr program-header-addr -- ) + >r + ( file-addr R: program-header-addr ) + \ Copy into storage + r@ phdr>p_offset l@ + r@ xlate-vaddr32 r@ phdr>p_filesz l@ move + + ( R: programm-header-addr ) + \ Clear BSS + r@ xlate-vaddr32 r@ phdr>p_filesz l@ + + r@ phdr>p_memsz l@ r@ phdr>p_filesz l@ - erase + + ( R: programm-header-addr ) + \ Flush cache + r@ xlate-vaddr32 r> phdr>p_memsz l@ dup 0= IF 2drop ELSE flushcache THEN +; + +: load-segments ( file-addr -- ) + ( file-addr ) + dup dup ehdr>e_phoff l@ + \ Calculate program header address + + ( file-addr program-header-addr ) + over ehdr>e_phnum w@ 0 ?DO \ loop e_phnum times + + ( file-addr program-header-addr ) + dup phdr>p_type l@ 1 = IF \ PT_LOAD ? + + ( file-addr program-header-addr ) + 2dup claim-segment \ claim segment + + ( file-addr program-header-addr ) + 2dup load-segment THEN \ copy segment + + ( file-addr program-header-addr ) + over ehdr>e_phentsize w@ + LOOP \ step to next header + + ( file-addr program-header-addr ) + over ehdr>e_entry l@ + + ( file-addr program-header-addr ) + nip nip \ cleanup +; + +: load-segment64 ( file-addr program-header-addr -- ) + >r + ( file-addr R: program-header-addr ) + \ Copy into storage + r@ phdr64>p_offset @ + r@ phdr64>p_vaddr @ r@ phdr64>p_filesz @ move + + ( R: programm-header-addr ) + \ Clear BSS + r@ phdr64>p_vaddr @ r@ phdr64>p_filesz @ + + r@ phdr64>p_memsz @ r@ phdr64>p_filesz @ - erase + + ( R: programm-header-addr ) + \ Flush cache + r@ phdr64>p_vaddr @ r> phdr64>p_memsz @ dup 0= IF 2drop ELSE flushcache THEN +; + +: load-segments64 ( file-addr -- entry ) + ( file-addr ) + dup dup ehdr64>e_phoff @ + \ Calculate program header address + + ( file-addr program-header-addr ) + over ehdr64>e_phnum w@ 0 ?DO \ loop e_phnum times + + ( file-addr program-header-addr ) + dup phdr64>p_type l@ 1 = IF \ PT_LOAD ? + + ( file-addr program-header-addr ) + 2dup claim-segment64 \ claim segment + + ( file-addr program-header-addr ) + 2dup load-segment64 THEN \ copy segment + + ( file-addr program-header-addr ) + over ehdr64>e_phentsize w@ + LOOP \ step to next header + + ( file-addr program-header-addr ) + over ehdr64>e_entry @ + + ( file-addr program-header-addr entry ) + nip nip \ cleanup +; + +\ Return type of ELF image, abort if not valid +\ 1: 32 Bit PPC image +\ 2: 64 Bit PPC image +\ 5: 32 Bit SPU image + +: elf-check-file ( file-addr -- image-type ) + ( file-addr ) + dup ehdr>e_ident l@-be 7f454c46 <> IF + ABORT" Not an ELF executable" + THEN + + ( file-addr ) + dup ehdr>e_data c@ + ?bigendian IF + 2 <> ABORT" Not a Big Endian ELF file" + ELSE + 2 = ABORT" Not a Little Endian ELF file" + THEN + + ( file-addr ) + dup ehdr>e_type w@ 2 <> ABORT" Not an ELF executable" + + ( file-addr ) + dup ehdr>e_machine w@ + CASE + 14 OF ehdr>e_class c@ ENDOF \ PPC 32 bit executable + 15 OF ehdr>e_class c@ ENDOF \ PPC 64 bit executable + 17 OF ehdr>e_class c@ 4 or ENDOF \ SPU 32 bit executable + dup OF drop ABORT" Not a PPC / SPU ELF executable" ENDOF + ENDCASE +; + +: load-elf32 ( file-addr -- entry ) + + ( file-addr) + load-segments +; + +: load-elf32-claim ( file-addr -- claim-list entry ) + true to elf-claim? + 0 to last-claim + ['] load-elf32 CATCH IF false to elf-claim? ABORT THEN + last-claim swap + false to elf-claim? +; + + +: load-elf64 ( file-addr -- entry ) + + ( file-addr) + load-segments64 +; + +: load-elf64-claim ( file-addr -- claim-list entry ) + true to elf-claim? + 0 to last-claim + ['] load-elf64 CATCH IF false to elf-claim? ABORT THEN + last-claim swap + false to elf-claim? +; + +: load-elf-file ( file-addr -- entry 32-bit ) + + ( file-addr ) + dup elf-check-file + + ( file-addr 1|2|x ) + + CASE + 1 OF 0 to elf-segment-offset load-elf32 true ENDOF + 2 OF 0 to elf-segment-offset load-elf64 false ENDOF + 5 OF load-elf32 true ENDOF + dup OF true ABORT" load-elf-file: Not valid image" ENDOF + ENDCASE +; + +\ Method to load SPU image + +: elf-spu-load ( ls-start-addr file-addr -- entry ) + swap to elf-segment-offset + load-elf-file drop +; + +\ Release memory claimed before + +: elf-release ( claim-list -- ) + BEGIN + dup cell+ ( claim-list claim-list-addr ) + dup @ swap cell+ @ ( claim-list claim-list-addr claim-list-sz ) + release ( claim-list ) + @ dup 0= ( Next-element ) + UNTIL + drop +; |