/* * allocate the TPA * * we first determine if ST RAM and/or alternate RAM is available for * allocation, based on the flags, the amount of RAM required and * the presence or absence of TT RAM. * * if no types are available (the requested amount is too large), we * return NULL. * * if only one type of RAM is available, we allocate it & return a * pointer to it. * * if both types are available, we normally allocate in alternate RAM * *except* if the amount of ST RAM is greater than the amount of * alternate RAM. In this case, we use a tiebreaker: bits 31-27 * of the flags field plus 1 is taken as a 4-bit number, which is * multiplied by 128K and added to the base amount needed to get a * "would like to have" amount. If this amount is larger than the * amount of alternate RAM, then we allocate in ST RAM. * * Reference: TT030 TOS Release Notes, Third Edition, 6 September 1991, * pages 29-30. * * returns: ptr to MD of allocated memory (NULL => failed) * updates 'avail' with the size of allocated memory */ static MD *alloc_tpa(ULONG flags,LONG needed,LONG *avail) { LONG st_ram_size; BOOL st_ram_available = FALSE; st_ram_size = (LONG) ffit(-1L, &pmd); if (st_ram_size >= needed) st_ram_available = TRUE; #if CONF_WITH_ALT_RAM { LONG alt_ram_size = 0L, tpasize; BOOL alt_ram_available = FALSE; if (has_alt_ram && (flags & PF_TTRAMLOAD)) { alt_ram_size = (LONG) ffit(-1L, &pmdalt); if (alt_ram_size >= needed) alt_ram_available = TRUE; } if (st_ram_available && alt_ram_available && (st_ram_size > alt_ram_size)) { tpasize = (((flags >> 28) & 0x0f) + 1) * TPASIZE_QUANTUM; if (needed+tpasize > alt_ram_size) alt_ram_available = FALSE; /* force allocation in ST RAM */ } if (alt_ram_available) { *avail = alt_ram_size; return ffit(alt_ram_size, &pmdalt); } }
/* allocate the environment, always in ST RAM */ static MD *alloc_env(char *env) { MD *env_md; int size; /* determine the env size */ if (env == NULL) env = run->p_env; size = (envsize(env) + 1) & ~1; /* must be even */ /* allocate it */ env_md = ffit((long) size, &pmd); if (env_md == NULL) return NULL; /* copy it */ memcpy(env_md->m_start, env, size); return env_md; }
long xmxalloc(long amount, int mode) { MD *m; long ret_value; #if DBGUMEM kprintf("BDOS: xmxalloc(%ld, %d)\n", amount, mode); #endif /* * if amount == -1L, return the size of the biggest block * */ if(amount == -1L) { switch(mode) { case MX_STRAM: ret_value = (long) ffit(-1L,&pmd); break; #if CONF_WITH_ALT_RAM case MX_TTRAM: ret_value = (long) ffit(-1L,&pmdalt); break; #endif case MX_PREFSTRAM: case MX_PREFTTRAM: /* TODO - I assume that the correct behaviour is to return * the biggest size in either pools. The documentation is unclear. */ { ret_value = (long) ffit(-1L,&pmd); #if CONF_WITH_ALT_RAM { long tmp = (long) ffit(-1L,&pmdalt); if(ret_value < tmp) ret_value = tmp; } #endif } break; default: /* unknown mode */ ret_value = 0; } goto ret; } /* * return NULL if asking for a negative or null amount */ if( amount <= 0 ) { ret_value = 0; goto ret; } /* * Pass the request on to the internal routine. */ switch(mode) { case MX_STRAM: m = ffit(amount,&pmd); break; #if CONF_WITH_ALT_RAM case MX_TTRAM: m = ffit(amount,&pmdalt); break; #endif case MX_PREFSTRAM: m = ffit(amount,&pmd); #if CONF_WITH_ALT_RAM if(m == NULL) m = ffit(amount,&pmdalt); #endif break; case MX_PREFTTRAM: #if CONF_WITH_ALT_RAM m = ffit(amount,&pmdalt); if(m == NULL) #endif m = ffit(amount,&pmd); break; default: /* unknown mode */ m = 0; } /* * The internal routine returned a pointer to a memory descriptor, or NULL * Return its pointer to the start of the block. */ if(m == NULL) { ret_value = 0; } else { ret_value = (long) m->m_start; } ret: #if DBGUMEM kprintf("BDOS: xmxalloc returns 0x%08lx\n", ret_value); dump_mem_map(); #endif return(ret_value); }
/* * xmxalloc - Function 0x44 (Mxalloc) */ void *xmxalloc(long amount, int mode) { MD *m; void *ret_value; KDEBUG(("BDOS: xmxalloc(%ld,0x%04x)\n",amount,mode)); mode &= MX_MODEMASK; /* ignore unsupported bits */ /* * if amount == -1L, return the size of the biggest block * */ if (amount == -1L) { switch(mode) { case MX_STRAM: ret_value = ffit(-1L,&pmd); break; #if CONF_WITH_ALT_RAM case MX_TTRAM: ret_value = ffit(-1L,&pmdalt); break; #endif case MX_PREFSTRAM: case MX_PREFTTRAM: /* * for the "preferred" options, the correct behaviour is to * return the biggest size in either pool - verified on TOS3 */ { ret_value = ffit(-1L,&pmd); #if CONF_WITH_ALT_RAM { void *tmp = ffit(-1L,&pmdalt); if (ret_value < tmp) ret_value = tmp; } #endif } break; default: /* unknown mode */ ret_value = NULL; } goto ret; } /* * return NULL if asking for a negative or null amount */ if (amount <= 0) { ret_value = NULL; goto ret; } /* * Pass the request on to the internal routine. */ switch(mode) { case MX_STRAM: m = ffit(amount,&pmd); break; #if CONF_WITH_ALT_RAM case MX_TTRAM: m = ffit(amount,&pmdalt); break; #endif case MX_PREFSTRAM: m = ffit(amount,&pmd); #if CONF_WITH_ALT_RAM if (m == NULL) m = ffit(amount,&pmdalt); #endif break; case MX_PREFTTRAM: #if CONF_WITH_ALT_RAM m = ffit(amount,&pmdalt); if (m == NULL) #endif m = ffit(amount,&pmd); break; default: /* unknown mode */ m = NULL; } /* * The internal routine returned a pointer to a memory descriptor, or NULL * Return its pointer to the start of the block. */ if (m == NULL) { ret_value = NULL; } else { ret_value = m->m_start; } ret: KDEBUG(("BDOS xmxalloc: returns 0x%08lx\n",(ULONG)ret_value)); dump_mem_map(); return ret_value; }
long xexec(WORD flag, char *path, char *tail, char *env) { PD *p; PGMHDR01 hdr; MD *m, *env_md; LONG rc; long max, needed; FH fh; D(("BDOS: xexec - flag or mode = %d\n", flag)); /* first branch - actions that do not require loading files */ switch(flag) { case PE_RELOCATE: p = (PD *) tail; rc = kpgm_relocate(p, (long)path); if(rc) { D(("BDOS: xexec - kpgm_relloc returned %ld (0x%lx)\n", rc, rc)); return(rc); } /* invalidate instruction cache for the TEXT segment only * programs that jump into their DATA, BSS or HEAP are kindly invited * to do their cache management themselves. */ invalidate_icache( p+1, p->p_tlen); return (long) p; case PE_BASEPAGE: /* just create a basepage */ env_md = alloc_env(env); if(env_md == NULL) { D(("xexec: Not Enough Memory!\n")); return(ENSMEM); } max = (long) ffit(-1L, &pmd); if(max >= sizeof(PD)) { m = ffit(max, &pmd); p = (PD *) m->m_start; } else { /* not even enough memory for basepage */ freeit(env_md, &pmd); D(("xexec: No memory for TPA\n")); return(ENSMEM); } /* memory ownership */ m->m_own = env_md->m_own = run; /* initialize the PD */ init_pd_fields(p, tail, max, env_md); init_pd_files(p); return (long) p; case PE_GOTHENFREE: /* set the owner of the memory to be this process */ p = (PD *) tail; set_owner(p, p, find_mpb(p)); set_owner(p->p_env, p, find_mpb(p->p_env)); /* fall through */ case PE_GO: p = (PD *) tail; proc_go(p); /* should not return ? */ return (long)p; case PE_LOADGO: case PE_LOAD: break; default: return EINVFN; } /* we now need to load a file */ D(("BDOS: xexec - trying to find the command ...\n")); if (ixsfirst(path,0,0L)) { D(("BDOS: Command %s not found!!!\n", path)); return(EFILNF); /* file not found */ } /* load the header - if IO error occurs now, the longjmp in rwabs will * jump directly back to bdosmain.c, which is not a problem because * we haven't allocated anything yet. */ rc = kpgmhdrld(path, &hdr, &fh); if(rc) { D(("BDOS: xexec - kpgmhdrld returned %ld (0x%lx)\n", rc, rc)); return(rc); } /* allocate the environment first, always in ST RAM */ env_md = alloc_env(env); if ( env_md == NULL ) { D(("xexec: Not Enough Memory!\n")); return(ENSMEM); } /* allocate the basepage depending on memory policy */ needed = hdr.h01_tlen + hdr.h01_dlen + hdr.h01_blen + sizeof(PD); max = 0; /* first try */ p = NULL; m = NULL; #if CONF_WITH_ALT_RAM if(has_alt_ram && (hdr.h01_flags & PF_TTRAMLOAD)) { /* use alternate ram preferably */ max = (long) ffit(-1L, &pmdalt); if(max >= needed) { m = ffit(max, &pmdalt); p = (PD *) m->m_start; } } #endif /* second try */ if(p == NULL) { max = (long) ffit(-1L, &pmd); if(max >= needed) { m = ffit(max, &pmd); p = (PD *) m->m_start; } } /* still failed? free env_md and return */ if(p == NULL) { D(("xexec: No memory for TPA\n")); freeit(env_md, &pmd); return(ENSMEM); } assert(m != NULL); /* memory ownership - the owner is either the new process being created, * or the parent */ if(flag == PE_LOADGO) { m->m_own = env_md->m_own = p; } else { m->m_own = env_md->m_own = run; } /* initialize the fields in the PD structure */ init_pd_fields(p, tail, max, env_md); /* set the flags (must be done after init_pd) */ p->p_flags = hdr.h01_flags; /* use static variable to avoid the obscure longjmp warning */ cur_p = p; cur_m = m; cur_env_md = env_md; /* we have now allocated memory, so we need to intercept longjmp. */ memcpy(bakbuf, errbuf, sizeof(errbuf)); if ( setjmp(errbuf) ) { kprintf("Error and longjmp in xexec()!\n"); /* free any memory allocated yet */ freeit(cur_env_md, &pmd); freeit(cur_m, find_mpb((void *)cur_m->m_start)); /* we still have to jump back to bdosmain.c so that the proper error * handling can occur. */ longjmp(bakbuf, 1); } /* now, load the rest of the program and perform relocation */ rc = kpgmld(cur_p, fh, &hdr); if ( rc ) { D(("BDOS: xexec - kpgmld returned %ld (0x%lx)\n", rc, rc)); /* free any memory allocated yet */ freeit(cur_env_md, &pmd); freeit(cur_m, find_mpb((void *)cur_m->m_start)); return rc; } /* at this point the program has been correctly loaded in memory, and * more IO errors cannot occur, so it is safe now to finish initializing * the new process. */ init_pd_files(cur_p); /* invalidate instruction cache for the TEXT segment only * programs that jump into their DATA, BSS or HEAP are kindly invited * to do their cache management themselves. */ invalidate_icache(((char *)cur_p) + sizeof(PD), hdr.h01_tlen); if(flag != PE_LOAD) proc_go(cur_p); return (long) cur_p; }