static void here(void) { PUSH(pointer2cell(dict) + dicthead); #ifdef CONFIG_DEBUG_INTERNAL printk("here: %x\n", pointer2cell(dict) + dicthead); #endif }
static int printf_console(const char *fmt, ...) { cell tmp; char buf[512]; va_list args; int i; va_start(args, fmt); i = vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); /* Push to the Forth interpreter for console output */ tmp = rstackcnt; PUSH(pointer2cell(buf)); PUSH((int)strlen(buf)); trampoline[1] = findword("type"); PUSHR(PC); PC = pointer2cell(trampoline); while (rstackcnt > tmp) { dbg_interp_printk("printf_console: NEXT\n"); next(); } return i; }
ucell lfa2nfa(ucell ilfa) { /* get offset from dictionary start */ ilfa = ilfa - (ucell)pointer2cell(dict); ilfa--; /* skip status */ while (dict[--ilfa] == 0); /* skip all pad bytes */ ilfa -= (dict[ilfa] - 128); return ilfa + (ucell)pointer2cell(dict); }
void bind_func( const char *name, void (*func)(void) ) { PUSH( pointer2cell(func) ); push_str( name ); fword("is-cfunc"); }
void init_trampoline(ucell *tramp) { tramp[0] = DOCOL; tramp[1] = 0; tramp[2] = target_ucell(pointer2cell(tramp) + 3 * sizeof(ucell)); tramp[3] = 0; }
/* ( -- cstr ) */ static void grubfs_files_get_fstype( grubfs_info_t *mi ) { grubfs_t *gfs = mi->gfs; PUSH( pointer2cell(strdup(gfs->fsys->name)) ); }
static ucell findsemis_wordlist(ucell xt, ucell wordlist) { ucell tmplfa, nextlfa, nextcfa; if (!wordlist) return 0; tmplfa = read_ucell(cell2pointer(wordlist)); nextcfa = lfa2cfa(tmplfa); /* Catch the special case where the lfa of the word we * want is the last word in the dictionary; in that case * the end of the word is given by "here" - 1 */ if (nextcfa == xt) return pointer2cell(dict) + dicthead - sizeof(cell); while (tmplfa) { /* Peek ahead and see if the next CFA in the list is the * one we are searching for */ nextlfa = read_ucell(cell2pointer(tmplfa)); nextcfa = lfa2cfa(nextlfa); /* If so, count back 1 cell from the current NFA */ if (nextcfa == xt) return lfa2nfa(tmplfa) - sizeof(cell); tmplfa = nextlfa; } return 0; }
static void spfetch(void) { // FIXME this can only work if the stack pointer // is within range. ucell tmp = pointer2cell(&(dstack[dstackcnt])); PUSH(tmp); }
xt_t bind_noname_func( void (*func)(void) ) { PUSH( pointer2cell(func) ); fword("is-noname-cfunc"); return POP_xt(); }
void update_nvram( void ) { PUSH( pointer2cell(nvram.config->data) ); PUSH( nvram.config_size ); fword("nvram-store-configs"); arch_nvram_put( nvram.data ); }
/* ( -- cstr ) */ static void grubfs_files_get_path( grubfs_info_t *mi ) { grubfile_t *file = mi->gfs->fd; const char *path = file->path; RET( pointer2cell(strdup(path)) ); }
ucell fstrlen(ucell fstr) { fstr -= pointer2cell(dict)+1; //fstr -= pointer2cell(dict); FIXME while (dict[++fstr] < 128) ; return dict[fstr] - 128; }
ucell load_dictionary(const char *data, ucell len) { u32 checksum=0; const char *checksum_walk; ucell *walk, *reloc_table; dictionary_header_t *header=(dictionary_header_t *)data; /* assertions */ if (len <= (sizeof(dictionary_header_t)) || strncmp(DICTID, data, 8)) return 0; #ifdef CONFIG_DEBUG_DICTIONARY dump_header(header); #endif checksum_walk=data; while (checksum_walk<data+len) { checksum+=read_long(checksum_walk); checksum_walk+=sizeof(u32); } if(checksum) { printk("Checksum invalid (%08x)!\n", checksum); return 0; } data += sizeof(dictionary_header_t); dicthead = target_long(header->length); memcpy(dict, data, dicthead); reloc_table=(ucell *)(data+dicthead); #ifdef CONFIG_DEBUG_DICTIONARY printk("\nmoving dictionary (%x bytes) to %x\n", (ucell)dicthead, (ucell)dict); printk("\ndynamic relocation..."); #endif for (walk = (ucell *) dict; walk < (ucell *) (dict + dicthead); walk++) { int pos, bit, l; l=(walk-(ucell *)dict); pos=l/BITS; bit=l&~(-BITS); if (reloc_table[pos] & target_ucell((ucell)1ULL << bit)) { // printk("%lx, pos %x, bit %d\n",*walk, pos, bit); write_ucell(walk, read_ucell(walk)+pointer2cell(dict)); } } #ifdef CONFIG_DEBUG_DICTIONARY printk(" done.\n"); #endif last = (ucell *)(dict + target_ucell(header->last)); return -1; }
static void execute(void) { /* EXECUTE */ ucell address = POP(); dbg_interp_printk("execute: %x\n", address); PUSHR(PC); trampoline[1] = target_ucell(address); PC = pointer2cell(trampoline); }
void bind_xtfunc( const char *name, xt_t xt, ucell arg, void (*func)(void) ) { PUSH_xt( xt ); PUSH( arg ); PUSH( pointer2cell(func) ); push_str( name ); fword("is-xt-cfunc"); }
int ofmem_posix_memalign( void **memptr, size_t alignment, size_t size ) { ofmem_t *ofmem = ofmem_arch_get_private(); alloc_desc_t *d, **pp; void *ret; ucell top; phys_addr_t pa; if( !size ) return ENOMEM; if( !ofmem->next_malloc ) ofmem->next_malloc = (char*)ofmem_arch_get_malloc_base(); size = align_size(size + sizeof(alloc_desc_t), alignment); /* look in the freelist */ for( pp=&ofmem->mfree; *pp && (**pp).size < size; pp = &(**pp).next ) { } /* waste at most 4K by taking an entry from the freelist */ if( *pp && (**pp).size > size + 0x1000 ) { /* Alignment should be on physical not virtual address */ pa = va2pa((uintptr_t)*pp + sizeof(alloc_desc_t)); pa = align_ptr(pa, alignment); ret = (void *)pa2va(pa); memset( ret, 0, (**pp).size - sizeof(alloc_desc_t) ); *pp = (**pp).next; *memptr = ret; return 0; } top = ofmem_arch_get_heap_top(); /* Alignment should be on physical not virtual address */ pa = va2pa((uintptr_t)ofmem->next_malloc + sizeof(alloc_desc_t)); pa = align_ptr(pa, alignment); ret = (void *)pa2va(pa); if( pointer2cell(ret) + size > top ) { printk("out of malloc memory (%x)!\n", size ); return ENOMEM; } d = (alloc_desc_t*)((uintptr_t)ret - sizeof(alloc_desc_t)); ofmem->next_malloc += size; d->next = NULL; d->size = size; memset( ret, 0, size - sizeof(alloc_desc_t) ); *memptr = ret; return 0; }
static void doival(void) { ucell r, *p = (ucell *)(*(ucell *) cell2pointer(PC) + sizeof(ucell)); ucell ibase = get_myself(); dbg_interp_printk("ivar, offset: %d size: %d\n", p[0], p[1] ); r = ibase ? ibase + p[0] : pointer2cell(&p[2]); PUSH( *(ucell *)cell2pointer(r) ); }
static void doidefer(void) { ucell *p = (ucell *)(*(ucell *) cell2pointer(PC) + sizeof(ucell)); ucell ibase = get_myself(); dbg_interp_printk("doidefer, offset: %d size: %d\n", p[0], p[1] ); PUSHR(PC); PC = ibase ? ibase + p[0] : pointer2cell(&p[2]); PC -= sizeof(ucell); }
int enterforth(xt_t xt) { ucell *_cfa = (ucell*)cell2pointer(xt); cell tmp; if (read_ucell(_cfa) != DOCOL) { trampoline[1] = target_ucell(xt); _cfa = trampoline; } if (rstackcnt < 0) { rstackcnt = 0; } tmp = rstackcnt; interruptforth = FORTH_INTSTAT_CLR; PUSHR(PC); PC = pointer2cell(_cfa); while (rstackcnt > tmp && !(interruptforth & FORTH_INTSTAT_STOP)) { if (debug_xt_list->next == NULL) { while (rstackcnt > tmp && !interruptforth) { dbg_interp_printk("enterforth: NEXT\n"); next(); } } else { while (rstackcnt > tmp && !interruptforth) { dbg_interp_printk("enterforth: NEXT_DBG\n"); next_dbg(); } } /* Always clear the debug mode change flag */ interruptforth = interruptforth & (~FORTH_INTSTAT_DBG); } #if 0 /* return true if we took an exception. The caller should normally * handle exceptions by returning immediately since the throw * is supposed to abort the execution of this C-code too. */ if (rstackcnt != tmp) { printk("EXCEPTION DETECTED!\n"); } #endif return rstackcnt != tmp; }
static void semis_dbg(void) { struct debug_xt *debug_xt_item, *debug_xt_up = NULL; /* If current semis is in our debug xt list, disable debug mode */ debug_xt_item = debug_xt_list; while (debug_xt_item->next) { if (debug_xt_item->xt_semis == PC) { if (debug_xt_item->mode != DEBUG_MODE_STEPUP) { /* Handle the normal case */ fstrncpy(xtname, lfa2nfa(debug_xt_item->xt_docol - sizeof(cell)), MAXNFALEN); printf_console("\n[ Finished %s ] ", xtname); /* Reset to step mode in case we were in trace mode */ debug_xt_item->mode = DEBUG_MODE_STEP; } else { /* This word requires execution of the debugger "Up" * semantics. However we can't do this here since we * are iterating through the debug list, and we need * to change it. So we do it afterwards. */ debug_xt_up = debug_xt_item; } } debug_xt_item = debug_xt_item->next; } /* Execute debugger "Up" semantics if required */ if (debug_xt_up) { /* Only add the parent word if it is not within the trampoline */ if (rstack[rstackcnt] != (cell)pointer2cell(&trampoline[1])) { del_debug_xt(debug_xt_up->xt_docol); add_debug_xt(findxtfromcell(rstack[rstackcnt])); fstrncpy(xtname, lfa2nfa(findxtfromcell(rstack[rstackcnt]) - sizeof(cell)), MAXNFALEN); printf_console("\n[ Up to %s ] ", xtname); } else { fstrncpy(xtname, lfa2nfa(findxtfromcell(debug_xt_up->xt_docol) - sizeof(cell)), MAXNFALEN); printf_console("\n[ Finished %s (Unable to go up, hit trampoline) ] ", xtname); del_debug_xt(debug_xt_up->xt_docol); } debug_xt_up = NULL; } PC = POPR(); }
static int build_dictionary(void) { ucell lfa = 0; unsigned int i; /* we need a temporary place for latest outside the dictionary */ latest = &lfa; /* starting a new dictionary: clear dicthead */ dicthead = 0; #ifdef CONFIG_DEBUG_DICTIONARY printk("building dictionary, %d primitives.\nbuilt words:", sizeof(wordnames) / sizeof(void *)); #endif for (i = 0; i < sizeof(wordnames) / sizeof(void *); i++) { if (strlen(wordnames[i]) != 0) { fcreate((char *) wordnames[i], i); #ifdef CONFIG_DEBUG_DICTIONARY printk(" %s", wordnames[i]); #endif } } #ifdef CONFIG_DEBUG_DICTIONARY printk(".\n"); #endif /* get last/latest and state */ state = buildvariable("state", 0); last = buildvariable("forth-last", 0); latest = buildvariable("latest", 0); *latest = target_ucell(pointer2cell(latest)-2*sizeof(cell)); base=buildvariable("base", 10); buildconstant("/c", sizeof(u8)); buildconstant("/w", sizeof(u16)); buildconstant("/l", sizeof(u32)); buildconstant("/n", sizeof(ucell)); buildconstant("/x", sizeof(u64)); reveal(); if (verbose) { printk("Dictionary initialization finished.\n"); } return 0; }
/* ( -- cstr ) */ static void hfsp_files_get_path( hfsp_info_t *mi ) { char *buf; hfsp_file_t *t = mi->hfspfile; if( !t->path ) RET ( 0 ); buf = malloc(strlen(t->path) + 1); strncpy( buf, t->path, strlen(t->path) ); buf[strlen(t->path)] = 0; PUSH(pointer2cell(buf)); }
static void herewrite(void) { ucell tmp = POP(); /* converted pointer */ dicthead = tmp - pointer2cell(dict); #ifdef CONFIG_DEBUG_INTERNAL printk("here!: new value: %x\n", tmp); #endif if (dictlimit && dicthead >= dictlimit) { printk("Dictionary space overflow:" " dicthead=" FMT_ucellx " dictlimit=" FMT_ucellx "\n", dicthead, dictlimit); } }
/* ( -- cstr|0 ) */ static void hfsp_files_volume_name( hfsp_info_t *mi ) { int fd; char *volname = malloc(VOLNAME_SIZE); fd = open_ih(my_self()); if (fd >= 0) { get_hfs_vol_name(fd, volname, VOLNAME_SIZE); close_io(fd); } else { volname[0] = '\0'; } PUSH(pointer2cell(volname)); }
static void ofmem_set_property( phandle_t ph, const char *name, const char *buf, int len ) { /* This is very similar to set_property() in libopenbios/bindings.c but allows us to set the property pointer directly, rather than having to copy it into the Forth dictonary every time we update the memory properties */ if( !ph ) { printk("ofmem_set_property: NULL phandle\n"); return; } PUSH(pointer2cell(buf)); PUSH(len); push_str(name); PUSH_ph(ph); fword("encode-property"); }
void nvconf_init( void ) { int once=0; /* initialize nvram structure completely */ nvram.config = NULL; nvram.config_size = 0; nvram.size = arch_nvram_size(); nvram.data = malloc( nvram.size ); arch_nvram_get( nvram.data ); bind_func( "update-nvram", update_nvram ); for( ;; ) { nvpart_t *p = NULL; int err; while( (err=next_nvpart(&p)) > 0 ) { if( nvpart_checksum(p) != p->checksum ) { err = -1; break; } if( p->signature == NV_SIG_SYSTEM ) { nvram.config = p; nvram.config_size = nvpart_size(p) - 0x10; if( !once++ ) { PUSH( pointer2cell(p->data) ); PUSH( nvram.config_size ); fword("nvram-load-configs"); } } } if( err || !nvram.config ) { printk("nvram error detected, zapping pram\n"); zap_nvram(); if( !once++ ) fword("set-defaults"); continue; } break; } }
static void fcreate(const char *word, ucell cfaval) { if (strlen(word) == 0) { printk("WARNING: tried to create unnamed word.\n"); return; } writestring(word); /* get us at least 1 byte for flags */ writebyte(0); paddict(sizeof(cell)); /* set flags high bit. */ dict[dicthead - 1] = 128; /* lfa and cfa */ writecell(read_ucell(latest)); *latest = target_ucell(pointer2cell(dict) + dicthead - sizeof(cell)); writecell(cfaval); }
static int getchar_console(void) { cell tmp; /* Push to the Forth interpreter for console output */ tmp = rstackcnt; trampoline[1] = findword("key"); PUSHR(PC); PC = pointer2cell(trampoline); while (rstackcnt > tmp) { dbg_interp_printk("getchar_console: NEXT\n"); next(); } return POP(); }
/* * Compare two dictionaries constructed at different addresses. When * the cells don't match, a need for relocation is detected and the * corresponding bit in reloc_table bitmap is set. */ static void relocation_table(unsigned char * dict_one, unsigned char *dict_two, int length) { ucell *d1=(ucell *)dict_one, *d2=(ucell *)dict_two; ucell *reloc_table; int pos, bit; int l=(length+(sizeof(cell)-1))/sizeof(ucell), i; /* prepare relocation table */ relocation_length=(length+BITS-1)/BITS; reloc_table = malloc(relocation_length*sizeof(cell)); memset(reloc_table,0,relocation_length*sizeof(cell)); for (i=0; i<l; i++) { pos=i/BITS; bit=i&~(-BITS); if(d1[i]==d2[i]) { reloc_table[pos] &= target_ucell(~((ucell)1ULL << bit)); // This check might bring false positives in data. //if(d1[i] >= pointer2cell(dict_one) && // d1[i] <= pointer2cell(dict_one+length)) // printk("\nWARNING: inconsistent relocation (%x:%x)!\n", d1[i], d2[i]); } else { /* This is a pointer, it needs relocation, d2==dict */ reloc_table[pos] |= target_ucell((ucell)1ULL << bit); d2[i] = target_ucell(target_ucell(d2[i]) - pointer2cell(d2)); } } #ifdef CONFIG_DEBUG_DICTIONARY printk("dict1 %lx dict2 %lx dict %lx\n",dict_one, dict_two, dict); for (i=0; i< relocation_length ; i++) printk("reloc %d %lx\n",i+1, reloc_table[i]); #endif relocation_address=reloc_table; }
void evangelionbios_init( void ) { // Bind the saved program state context into Forth PUSH(pointer2cell((void *)&__context)); feval("['] __context cell+ !"); #if defined(CONFIG_DRIVER_FW_CFG) // Bind the Forth fw_cfg file interface bind_func("fw-cfg-read-file", forth_fw_cfg_read_file); #endif // Bind the C implementation of (init-program) into Forth bind_func("(init-program)", init_program); // Bind the C implementation of (go) into Forth bind_func("(go)", go); // Bind the LE access words bind_func("le-w!", lewstore); bind_func("le-l!", lelstore); bind_func("le-w@", lewfetch); bind_func("le-l@", lelfetch); }