void dstrprepend(dstr_t *ds, const char *str) { dstr_t *copy = create_dstr(); dstrcpy(copy, ds->data); dstrcpy(ds, str); dstrcatf(ds, "%s", copy->data); free_dstr(copy); }
void G_GetActionBindings(char *buff, char *action) { int i; char *p; p = buff; *p = 0; for(i = 0; i < NUMKEYS; i++) { if(IsSameAction(action, KeyActions[i])) { if(p != buff) *(p++) = ','; M_GetKeyName(p, i); p += dstrlen(p); if(p - buff >= MAX_MENUACTION_LENGTH) return; } } for(i = 0; i < MOUSE_BUTTONS; i++) { if(IsSameAction(action, MouseActions[i])) { if(p != buff) *(p++) = ','; if(i < MOUSE_BUTTONS-2) { dstrcpy(p, "mouse?"); p[5] = i + '1'; p += 6; } if(p - buff >= MAX_MENUACTION_LENGTH) return; } if(IsSameAction(action, Mouse2Actions[i])) { if(p != buff) *(p++) = ','; dstrcpy(p, "mouse2?"); p[6] = i + '1'; p += 7; if(p - buff >= MAX_MENUACTION_LENGTH) return; } } }
void G_UnregisterAction(char *name) { action_t *action; action_t *tree; char buff[256]; dstrcpy(buff, name); dstrlwr(buff); action = FindAction(buff); if(!action) return; if(!action->children[0]) { ReplaceActionWith(action, action->children[1]); } else if(!action->children[1]) { ReplaceActionWith(action, action->children[0]); } else { tree = action->children[1]; while(tree->children[0]) tree = tree->children[0]; tree->children[0] = action->children[0]; action->children[0]->parent = tree; G_OptimizeActionTree(); } G_FreeAction(action); }
t_tree mFuncCallExpr(t_tree pActuals, const char *pFuncName, int pLineNr) { t_tree node = allocateNode(kFuncCallExpr, pLineNr); node->Node.FuncCallExpr.Actuals = pActuals; node->Node.FuncCallExpr.FuncName = dstrcpy(pFuncName); return node; }
char *(Z_Strdup) (const char *s, int tag, void *user, const char *file, int line) { #ifdef ZONEFILE Z_LogPrintf("* Z_Strdup(file=%s:%d)\n", file, line); #endif return dstrcpy((Z_Malloc) (dstrlen(s) + 1, tag, user, file, line), s); }
t_tree mRead(const char *pId, int pLineNr) { t_tree node = allocateNode(kRead, pLineNr); node->Node.Read.Next = NULL; node->Node.Read.Id = dstrcpy(pId); return node; }
static void TrapProcessCreateHandler(uint32 *trapArgs, int sysmode) { char allargs[SIZE_ARG_BUFF]; char name[100]; int i=0, j=0, k=0; uint32 args[MAX_ARGS]; char *destination; // The first argument is the name of the executable file i=0; for(i=0;i<100; i++) allargs[i] = 0; i=0; if(!sysmode) { //Get the arguments into the sytem space MemoryCopyUserToSystem (currentPCB, trapArgs, args, sizeof (args)); do { MemoryCopyUserToSystem (currentPCB,((char*)args[0])+i,name+i,1); i++; } while ((i < sizeof (name)) && (name[i-1] != '\0')); } else { bcopy (trapArgs, args, sizeof (args)); dstrncpy ((char *)args[0], name, sizeof (name)); } name[sizeof(name)-1] = '\0'; // null terminate the name i=0; if(!sysmode) { //Copy the rest of the arguments to the system space for(j=0; (j<11)&&(args[j]!=0); j++) { k=0; do { MemoryCopyUserToSystem (currentPCB,((char*)args[j])+k,allargs+i,1); i++; k++; } while ((i<sizeof(allargs)) && (allargs[i-1]!='\0')); } } else { destination = &allargs[0]; for(j=0; (j<11)&&(args[j]!=0); j++) { k = dstrlen((char *)args[j]); //length of the argument if(&destination[k]-allargs>100) { printf("Fatal: Cumulative length of all arguments > 100\n"); exitsim(); } dstrcpy(destination, (char *)args[j]); destination[k] = '\0'; } } allargs[sizeof(allargs)-1] = '\0'; // null terminate the name ProcessFork(0, (uint32)allargs, name, 1); }
t_tree mFuncCallStmnt(t_tree pActuals, const char *pFuncName, int pLineNr) { t_tree node = allocateNode(kFuncCallStmnt, pLineNr); node->Node.FuncCallStmnt.Next = NULL; node->Node.FuncCallStmnt.Actuals = pActuals; node->Node.FuncCallStmnt.FuncName = dstrcpy(pFuncName); return node; }
t_tree mAssign(const char *pId , t_tree pExpr, int pLineNr) { t_tree node = allocateNode(kAssign, pLineNr); node->Node.Assign.Next = NULL; node->Node.Assign.Id = dstrcpy(pId); node->Node.Assign.Expr = pExpr; return node; }
t_tree mVariable(vKind pVarKind, const char *pName, eType pType, int pLineNr) { t_tree node = allocateNode(kVariable, pLineNr); node->Node.Variable.Next = NULL; node->Node.Variable.VarKind = pVarKind; node->Node.Variable.Name = dstrcpy(pName); node->Node.Variable.Type = pType; return node; }
t_tree mFunction(t_tree pVariables, t_tree pStmnts, const char *pName, eType pType, int pLineNr) { t_tree node = allocateNode(kFunction, pLineNr); node->Node.Function.Next = NULL; node->Node.Function.Variables = pVariables; node->Node.Function.Stmnts = pStmnts; node->Node.Function.Name = dstrcpy(pName); node->Node.Function.Type = pType; return node; }
void G_UnbindAction(char *action) { int i; for(i = 0; i < NUMKEYS; i++) { if(IsSameAction(action, KeyActions[i])) { char p[16]; M_GetKeyName(p, i); Unbind(p); return; } } for(i = 0; i < MOUSE_BUTTONS; i++) { if(IsSameAction(action, MouseActions[i])) { char p[16]; if(i < MOUSE_BUTTONS-2) { dstrcpy(p, "mouse?"); p[5] = i + '1'; } Unbind(p); return; } if(IsSameAction(action, Mouse2Actions[i])) { char p[16]; dstrcpy(p, "mouse2?"); p[6] = i + '1'; Unbind(p); return; } } }
char * dstrcat (char *onto, const char *addn) { char *konto = onto; while (*onto != '\0') { onto++; } dstrcpy (onto, addn); return (konto); }
void CON_CvarRegister(cvar_t *variable) { char *oldstr; // first check to see if it has allready been defined if(CON_CvarGet(variable->name)) { CON_Printf(WHITE, "CON_CvarRegister: Can't register variable %s, already defined\n", variable->name); return; } // copy the value off, because future sets will Z_Free it oldstr = variable->string; variable->string = Z_Malloc(dstrlen(variable->string)+1, PU_STATIC, 0); dstrcpy(variable->string, oldstr); variable->value = datof(variable->string); variable->defvalue = Z_Malloc(dstrlen(variable->string)+1, PU_STATIC, 0); dstrcpy(variable->defvalue, variable->string); // link the variable in variable->next = cvarcap; cvarcap = variable; }
extern void symtab_add(t_symtab *symtab, const char *s) { t_symrec *symrec = calloc(sizeof(t_symrec), 1); if (symrec == NULL) { error_message("Out of memory when creating a symbol table record"); exit(-1); } symrec->symtab = symtab; symrec->s = dstrcpy(s); llist_insert_last(symtab->list, symrec); if (symtab->lookup_table) { hash_insert(symtab->lookup_table, symrec->s, symrec); } }
/// /// BuildKeywordString static char *BuildKeywordString(void) { char *keywords = NULL; ULONG i; ENTER(); dstrcpy(&keywords, C->AttachmentKeywords); for(i=0; IntMimeTypeArray[i].ContentType != NULL; i++) { if(IsStrEmpty(IntMimeTypeArray[i].Extension) == FALSE) { char *copy; // split the space separated extensions and build a string of // comma separated extensions with leading '.' if((copy = strdup(IntMimeTypeArray[i].Extension)) != NULL) { char *ext = copy; do { char *e; if((e = strpbrk(ext, " ")) != NULL) *e++ = '\0'; if(dstrlen(keywords) != 0) dstrcat(&keywords, ","); dstrcat(&keywords, "."); dstrcat(&keywords, ext); ext = e; } while(ext != NULL); free(copy); } } } D(DBF_GUI, "build keyword string '%s'", keywords); RETURN(keywords); return keywords; }
void G_OutputBindings(FILE *fh) { int i; alist_t *al; char name[MAX_KEY_NAME_LENGTH]; cvar_t *var; for(i = 0; i < NUMKEYS; i++) { al = KeyActions[i]; if(!al) continue; M_GetKeyName(name, i); OutputActions(fh, al, name); } dstrcpy(name, "mouse"); for(i = 0; i < MOUSE_BUTTONS; i++) { al = MouseActions[i]; if(al) { name[5] = i+'1'; name[6] = 0; OutputActions(fh, al, name); } } for(i = 0; i< MOUSE_BUTTONS; i++) { al = Mouse2Actions[i]; if(al) { name[5] = '2'; name[6] = i+'1'; name[7] = 0; OutputActions(fh, al, name); } } // cvars for(var = cvarcap; var; var = var->next) fprintf(fh, "seta \"%s\" \"%s\"\n", var->name, var->string); }
int M_GetKeyName(char *buff, int key) { keyinfo_t *pkey; if (((key >= 'a') && (key <= 'z')) || ((key >= '0') && (key <= '9'))) { buff[0] = (char)toupper(key); buff[1] = 0; return true; } for (pkey = Keys; pkey->name; pkey++) { if (pkey->code == key) { dstrcpy(buff, pkey->name); return true; } } sprintf(buff, "Key%02x", key); return false; }
/* * Replace the first occurrence of 'find' after the index 'start' with 'repl' * Returns the position right after the replaced string */ int dstrreplace(dstr_t *ds, const char *find, const char *repl, int start) { char *p; dstr_t *copy = create_dstr(); int end = -1; dstrcpy(copy, ds->data); if ((p = strstr(©->data[start], find))) { dstrncpy(ds, copy->data, p - copy->data); dstrcatf(ds, "%s", repl); end = ds->len; dstrcatf(ds, "%s", p + strlen(find)); } free_dstr(copy); return end; }
void TryActions(alist_t *al, dboolean up) { if(!al) return; if(up) { action_t *action; char buff[256]; if(al->next || (al->cmd[0] != '+')) return; dstrcpy(buff, al->cmd); buff[0] = '-'; action = FindAction(buff); if(action) action->proc(action->data, al->param); return; } AddActions(DoRunActions(al, false)); }
void CON_CvarSet(char *var_name, char *value) { cvar_t *var; dboolean changed; var = CON_CvarGet(var_name); if(!var) { // there is an error in C code if this happens CON_Printf(WHITE, "CON_CvarSet: variable %s not found\n", var_name); return; } changed = dstrcmp(var->string, value); Z_Free(var->string); // free the old value string var->string = Z_Malloc(dstrlen(value)+1, PU_STATIC, 0); dstrcpy(var->string, value); var->value = datof(var->string); if(var->callback) var->callback(var); }
//---------------------------------------------------------------------- // // main // // This routine is called when the OS starts up. It allocates a // PCB for the first process - the one corresponding to the initial // thread of execution. Note that the stack pointer is already // set correctly by _osinit (assembly language code) to point // to the stack for the 0th process. This stack isn't very big, // though, so it should be replaced by the system stack of the // currently running process. // //---------------------------------------------------------------------- void main (int argc, char *argv[]) { int i,j; int n; char buf[120]; char *userprog = (char *)0; int base=0; int numargs=0; char allargs[SIZE_ARG_BUFF]; int allargs_offset = 0; debugstr[0] = '\0'; printf ("Got %d arguments.\n", argc); printf ("Available memory: 0x%x -> 0x%x.\n", (int)lastosaddress, MemoryGetSize ()); printf ("Argument count is %d.\n", argc); for (i = 0; i < argc; i++) { printf ("Argument %d is %s.\n", i, argv[i]); } FsModuleInit (); for (i = 0; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'D': dstrcpy (debugstr, argv[++i]); break; case 'i': n = dstrtol (argv[++i], (void *)0, 0); ditoa (n, buf); printf ("Converted %s to %d=%s\n", argv[i], n, buf); break; case 'f': { int start, codeS, codeL, dataS, dataL, fd, j; int addr = 0; static unsigned char buf[200]; fd = ProcessGetCodeInfo (argv[++i], &start, &codeS, &codeL, &dataS, &dataL); printf ("File %s -> start=0x%08x\n", argv[i], start); printf ("File %s -> code @ 0x%08x (size=0x%08x)\n", argv[i], codeS, codeL); printf ("File %s -> data @ 0x%08x (size=0x%08x)\n", argv[i], dataS, dataL); while ((n = ProcessGetFromFile (fd, buf, &addr, sizeof (buf))) > 0) { for (j = 0; j < n; j += 4) { printf ("%08x: %02x%02x%02x%02x\n", addr + j - n, buf[j], buf[j+1], buf[j+2], buf[j+3]); } } close (fd); break; } case 'u': userprog = argv[++i]; base = i; // Save the location of the user program's name break; default: printf ("Option %s not recognized.\n", argv[i]); break; } if(userprog) break; } } dbprintf ('i', "About to initialize queues.\n"); AQueueModuleInit (); dbprintf ('i', "After initializing queues.\n"); MemoryModuleInit (); dbprintf ('i', "After initializing memory.\n"); ProcessModuleInit (); dbprintf ('i', "After initializing processes.\n"); SynchModuleInit (); dbprintf ('i', "After initializing synchronization tools.\n"); KbdModuleInit (); dbprintf ('i', "After initializing keyboard.\n"); ClkModuleInit (); dbprintf ('i', "After initializing clock.\n"); for (i = 0; i < 100; i++) { buf[i] = 'a'; } i = FsOpen ("vm", FS_MODE_WRITE); dbprintf ('i', "VM Descriptor is %d\n", i); FsSeek (i, 0, FS_SEEK_SET); FsWrite (i, buf, 80); FsClose (i); // Setup command line arguments if (userprog != (char *)0) { numargs=0; allargs_offset = 0; // Move through each of the argv addresses for(i=0; i<argc-base; i++) { // At each argv address, copy the string into allargs, including the '\0' for(j=0; allargs_offset < SIZE_ARG_BUFF; j++) { allargs[allargs_offset++] = argv[i+base][j]; if (argv[i+base][j] == '\0') break; // end of this string } numargs++; } allargs[SIZE_ARG_BUFF-1] = '\0'; // set last char to NULL for safety ProcessFork(0, (uint32)allargs, userprog, 1); } else { dbprintf('i', "No user program passed!\n"); } ClkStart(); dbprintf ('i', "Set timer quantum to %d, about to run first process.\n", processQuantum); intrreturn (); // Should never be called because the scheduler exits when there // are no runnable processes left. exitsim(); // NEVER RETURNS! }
//-------------------------------------------------------------------- // // int process_create(char *exec_name, ...); // // Here we support reading command-line arguments. Maximum MAX_ARGS // command-line arguments are allowed. Also the total length of the // arguments including the terminating '\0' should be less than or // equal to SIZE_ARG_BUFF. // //-------------------------------------------------------------------- static void TrapProcessCreateHandler(uint32 *trapArgs, int sysmode) { char allargs[SIZE_ARG_BUFF]; // Stores full string of arguments (unparsed) char name[PROCESS_MAX_NAME_LENGTH]; // Local copy of name of executable (100 chars or less) char *username=NULL; // Pointer to user-space address of exec_name string int i=0, j=0; // Loop index variables char *args[MAX_ARGS]; // All parsed arguments (char *'s) int allargs_position = 0; // Index into current "position" in allargs char *userarg = NULL; // Current pointer to user argument string int numargs = 0; // Number of arguments passed on command line dbprintf('p', "TrapProcessCreateHandler: function started\n"); // Initialize allargs string to all NULL's for safety for(i=0;i<SIZE_ARG_BUFF; i++) { allargs[i] = '\0'; } // First deal with user-space addresses if(!sysmode) { dbprintf('p', "TrapProcessCreateHandler: creating user process\n"); // Get the known arguments into the kernel space. // Argument 0: user-space pointer to name of executable MemoryCopyUserToSystem (currentPCB, (char *)(trapArgs+0), (char *)&username, sizeof(char *)); // Copy the user-space string at user-address "username" into kernel space for(i=0; i<PROCESS_MAX_NAME_LENGTH; i++) { MemoryCopyUserToSystem(currentPCB, (char *)(username+i), (char *)&(name[i]), sizeof(char)); // Check for end of user-space string if (name[i] == '\0') break; } dbprintf('p', "TrapProcessCreateHandler: just parsed executable name (%s) from trapArgs\n", name); if (i == PROCESS_MAX_NAME_LENGTH) { printf("TrapProcessCreateHandler: length of executable filename longer than allowed!\n"); exitsim(); } // Copy the program name into "allargs", since it has to be the first argument (i.e. argv[0]) allargs_position = 0; dstrcpy(&(allargs[allargs_position]), name); allargs_position += dstrlen(name) + 1; // The "+1" is so we're pointing just beyond the NULL // Rest of arguments: a series of char *'s until we hit NULL or MAX_ARGS for(i=0; i<MAX_ARGS; i++) { // First, must copy the char * itself into kernel space in order to read its value MemoryCopyUserToSystem(currentPCB, (char *)(trapArgs+1+i), (char *)&userarg, sizeof(char *)); // If this is a NULL in the set of char *'s, this is the end of the list if (userarg == NULL) break; // Store a pointer to the kernel-space location where we're copying the string args[i] = &(allargs[allargs_position]); // Copy the string into the allargs, starting where we left off last time through this loop for (j=0; j<SIZE_ARG_BUFF; j++) { MemoryCopyUserToSystem(currentPCB, (char *)(userarg+j), (char *)&(allargs[allargs_position]), sizeof(char)); // Move current character in allargs to next spot allargs_position++; // Check that total length of arguments is still ok if (allargs_position == SIZE_ARG_BUFF) { printf("TrapProcessCreateHandler: strlen(all arguments) > maximum length allowed!\n"); exitsim(); } // Check for end of user-space string if (allargs[allargs_position-1] == '\0') break; } } if (i == MAX_ARGS) { printf("TrapProcessCreateHandler: too many arguments on command line (did you forget to pass a NULL?)\n"); exitsim(); } numargs = i+1; // Arguments are now setup } else { // Addresses are already in kernel space, so just copy into our local variables // for simplicity // Argument 0: (char *) name of program dstrncpy(name, (char *)(trapArgs[0]), PROCESS_MAX_NAME_LENGTH); // Copy the program name into "allargs", since it has to be the first argument (i.e. argv[0]) allargs_position = 0; dstrcpy(&(allargs[allargs_position]), name); allargs_position += dstrlen(name) + 1; // The "+1" is so that we are now pointing just beyond the "null" in the name allargs_position = 0; for (i=0; i<MAX_ARGS; i++) { userarg = (char *)(trapArgs[i+1]); if (userarg == NULL) break; // found last argument // Store the address of where we're copying the string args[i] = &(allargs[allargs_position]); // Copy string into allargs for(j=0; j<SIZE_ARG_BUFF; j++) { allargs[allargs_position] = userarg[j]; allargs_position++; if (allargs_position == SIZE_ARG_BUFF) { printf("TrapProcessCreateHandler: strlen(all arguments) > maximum length allowed!\n"); exitsim(); } // Check for end of user-space string if (allargs[allargs_position-1] == '\0') break; } } if (i == MAX_ARGS) { printf("TrapProcessCreateHandler: too many arguments on command line (did you forget to pass a NULL?)\n"); exitsim(); } numargs = i+1; } ProcessFork(0, (uint32)allargs, name, 1); }
size_t dstrfreadl(dstring_t dest, FILE *fp) { char *start; /* points to beginning of buffer */ char *bufpos; /* our current position in DSTRBUF(dest) */ char *status; /* tests for NULL when we encounter EOF */ ptrdiff_t bufcount = 0; /* how many characters we've read so far */ dstring_t temp; /* temporary dstring_t object */ /* make sure dest is initialized */ if (NULL == dest) { _setdstrerrno(DSTR_UNINITIALIZED); return 0; } /* make sure fp is an opened file */ if (NULL == fp) { _setdstrerrno(DSTR_UNOPENED_FILE); return 0; } /* allocate space for temp */ if (DSTR_SUCCESS != dstrnalloc(&temp, dstrallocsize(dest))) { return 0; } bufpos = start = DSTRBUF(temp); /* *start = '\0'; */ /* loop until we've read a whole line */ while (1) { status = fgets(bufpos, DSTRBUFLEN(temp) - bufcount, fp); /* EOF or read error encountered */ if (status == NULL) { /* if we read something, we should keep it */ if (dstrlen(temp) > 0) { break; } /* there's nothing to read */ if (feof(fp)) { _setdstrerrno(DSTR_EOF); } else { _setdstrerrno(DSTR_FILE_ERROR); } dstrfree(&temp); return 0; } /* make sure bufpos points to our current position */ bufpos = start + dstrlen(temp); /* we're done */ if ('\n' == bufpos[-1]) { break; } /* if we can't get more memory, we can't finish the line */ if (DSTR_SUCCESS != dstrealloc(&temp, DSTRBUFLEN(temp) * 2)) { dstrfree(&temp); return 0; } /* make sure you update start, lest you suffer the wrath of glibc... */ start = DSTRBUF(temp); bufpos = start + dstrlen(temp); /* the +1 at the end is to make sure the '\0' is counted */ bufcount = bufpos - start + 1; } /* copy our new string into dest only if we read something */ if (dstrlen(temp) > 0) { /* does dest need more space than it already has? */ if (DSTRBUFLEN(dest) < dstrlen(temp) + 1) { if (DSTR_SUCCESS != dstrealloc(&dest, dstrlen(temp) + 1)) { dstrfree(&temp); return 0; } } dstrcpy(dest, temp); if (DSTR_SUCCESS != dstrerrno) { dstrfree(&temp); return 0; } } /* indicate success and return */ _setdstrerrno(DSTR_SUCCESS); dstrfree(&temp); return dstrlen(dest); }
//---------------------------------------------------------------------- // // ProcessFork // // Create a new process and make it runnable. This involves the // following steps: // * Allocate resources for the process (PCB, memory, etc.) // * Initialize the resources // * Place the PCB on the runnable queue // // NOTE: This code has been tested for system processes, but not // for user processes. // //---------------------------------------------------------------------- int ProcessFork (VoidFunc func, uint32 param, char *name, int isUser) { int i,j; // Loop index variable int fd, n; // Used for reading code from files. int start, codeS, codeL; // Used for reading code from files. int dataS, dataL; // Used for reading code from files. int addr = 0; // Used for reading code from files. unsigned char buf[100]; // Used for reading code from files. uint32 *stackframe; // Stores address of current stack frame. PCB *pcb; // Holds pcb while we build it for this process. int intrs; // Stores previous interrupt settings. uint32 initial_user_params[MAX_ARGS+2]; // Initial memory for user parameters (argc, argv) // initial_user_params[0] = argc // initial_user_params[1] = argv, points to initial_user_params[2] // initial_user_params[2] = address of string for argv[0] // initial_user_params[3] = address of string for argv[1] // ... uint32 argc=0; // running counter for number of arguments uint32 offset; // Used in parsing command line argument strings, holds offset (in bytes) from // beginning of the string to the current argument. uint32 initial_user_params_bytes; // total number of bytes in initial user parameters array int newpage; int index; int *p; intrs = DisableIntrs (); dbprintf ('I', "ProcessFork-Old interrupt value was 0x%x.\n", intrs); dbprintf ('p', "ProcessFork-Entering ProcessFork args=0x%x 0x%x %s %d\n", (int)func, param, name, isUser); // Get a free PCB for the new process if (AQueueEmpty(&freepcbs)) { printf ("ProcessFork-FATAL error: no free processes!\n"); exitsim (); // NEVER RETURNS! } pcb = (PCB *)AQueueObject(AQueueFirst (&freepcbs)); dbprintf ('p', "ProcessFork-Got a link @ 0x%x\n", (int)(pcb->l)); if (AQueueRemove (&(pcb->l)) != QUEUE_SUCCESS) { printf("ProcessFork-FATAL ERROR: could not remove link from freepcbsQueue in ProcessFork!\n"); exitsim(); } // This prevents someone else from grabbing this process ProcessSetStatus (pcb, PROCESS_STATUS_RUNNABLE); // At this point, the PCB is allocated and nobody else can get it. // However, it's not in the run queue, so it won't be run. Thus, we // can turn on interrupts here. RestoreIntrs (intrs); // Copy the process name into the PCB. dstrcpy(pcb->name, name); //---------------------------------------------------------------------- // This section initializes the memory for this process //---------------------------------------------------------------------- // Allocate 1 page for system stack, 1 page for user stack (at top of // virtual address space), and 4 pages for user code and global data. //--------------------------------------------------------- // STUDENT: allocate pages for a new process here. The // code below assumes that you set the "stackframe" variable // equal to the last 4-byte-aligned address in physical page // for the system stack. //--------------------------------------------------------- //////////////////////////////////////////////////////////////// // JSM, allocate 6 physical pages for new process // First, get L2 Page Table for index 0 of L1 Page Table index = MemoryAllocateL2PT(); if (index == -1) { printf ("ProcessFork-FATAL: couldn't allocate L2 Page Table for index 0 of L1 Page Table - no free page tables!\n"); exitsim (); // NEVER RETURNS! } // Assign L1 entry to address of start of L2 Page Table pcb->pagetable[0] = (uint32)&level2_pt_block[index]; p = (uint32 *)pcb->pagetable[0];//L2 // Allocate 4 pages for code and data for(i = 0; i < 4; i++) { newpage = MemoryAllocatePage(); if (newpage == 0) { printf ("ProcessFork-FATAL: couldn't allocate memory - no free pages!\n"); exitsim (); // NEVER RETURNS! } dbprintf('p', "ProcessFork-Allocating physical page #%d (Address 0x%.8X) for process virtual page #%d (data/code)\n", newpage, (newpage*MEM_PAGE_SIZE), i); *(p+i) = ((newpage*MEM_PAGE_SIZE) | MEM_PTE_VALID); dbprintf('p', "Contents at 0x%.8X: 0x%.8X\n\n", (int)(p+i), *(p+i)); } ///////////////////////////////////////////////////// //YF ADDED allocate page for heap // First, initialize the heapfree map for (j=0; j<MEM_MAX_HEAP_FREEMAP; j++){ pcb->HeapFreeMap[j] = 0; } for (j =0; j<MEM_MAX_HEAP_POINTER_ARRAY; j++){ pcb->HeapPtrSizes[j] = 0; } index = MemoryAllocateL2PT(); if (index == -1) { printf ("ProcessFork-FATAL: couldn't allocate L2 Page Table for index 0 of L1 Page Table - no free page tables!\n"); exitsim (); // NEVER RETURNS! } // Assign L1 entry to address of start of L2 Page Table pcb->pagetable[0] = (uint32)&level2_pt_block[index]; p = (uint32 *)pcb->pagetable[0]; newpage = MemoryAllocatePage(); if (newpage == 0) { printf ("ProcessFork-FATAL: couldn't allocate memory - no free pages!\n"); exitsim (); // NEVER RETURNS! } dbprintf('p', "ProcessFork-Allocating physical page #%d (Address 0x%.8X) for process virtual page #%d (Heap Allocation)\n", newpage, (newpage*MEM_PAGE_SIZE), i); //address for catch in Memory translate. UserHeap Address =0x4000 = *(p+i) = ((newpage*MEM_PAGE_SIZE) | MEM_PTE_VALID | MEM_PTE_HEAP); //TODO ProcessFork: marked as a heap. pcb->userHeapArea = (uint32 *)(newpage*MEM_PAGE_SIZE); dbprintf('p', "Heap area is at physical address:0x%.8X L2 Address: 0x%.8X\n", (int)(newpage*MEM_PAGE_SIZE), *(p+i)); dbprintf('p', "Contents at 0x%.8X: 0x%.8X\n\n", (int)(p+i), *(p+i)); //Done with Heap allocation /////////////////////////////////////////////////////////////////////////////////////////////////// // Allocate page for user stack // First, get L2 Page Table for index 15 of L1 Page Table index = MemoryAllocateL2PT(); if (index == -1) { printf ("ProcessFork-FATAL: couldn't allocate L2 Page Table for index 0 of L1 Page Table - no free page tables!\n"); exitsim (); // NEVER RETURNS! } // Assign L1 entry to address of start of L2 Page Table pcb->pagetable[MEM_L1_PAGE_TABLE_SIZE-1] = (uint32)&level2_pt_block[index]; p = (uint32 *)pcb->pagetable[MEM_L1_PAGE_TABLE_SIZE-1]; newpage = MemoryAllocatePage(); if (newpage == 0) { printf ("ProcessFork-FATAL: couldn't allocate memory - no free pages!\n"); exitsim (); // NEVER RETURNS! } dbprintf('p', "ProcessFork-Allocating physical page #%d (Address 0x%.8X) for process virtual page #%d (user stack)\n\n", newpage, (newpage*MEM_PAGE_SIZE), (MEM_L1_PAGE_TABLE_SIZE*MEM_L2_PAGE_TABLE_SIZE)-1); *(p+(MEM_L2_PAGE_TABLE_SIZE-1)) = ((newpage*MEM_PAGE_SIZE) | MEM_PTE_VALID); dbprintf('p', "Contents at 0x%.8X: 0x%.8X\n\n", (int)(p+(MEM_L2_PAGE_TABLE_SIZE-1)), *(p+(MEM_L2_PAGE_TABLE_SIZE-1))); // Allocate page for system stack newpage = MemoryAllocatePage(); if (newpage == 0) { printf ("ProcessFork-FATAL: couldn't allocate memory - no free pages!\n"); exitsim (); // NEVER RETURNS! } dbprintf('p', "ProcessFork-Allocating physical page #%d (Address 0x%.8X) for process system stack\n\n", newpage, (newpage*MEM_PAGE_SIZE)); pcb->sysStackArea = newpage * MEM_PAGE_SIZE; stackframe = (uint32 *)(pcb->sysStackArea + (MEM_PAGE_SIZE-4)); dbprintf('p', "ProcessFork-Initializing system stack pointer to 0x%.8X\n\n", (uint32)stackframe); //////////////////////////////////////////////////////////////// // Now that the stack frame points at the bottom of the system stack memory area, we need to // move it up (decrement it) by one stack frame size because we're about to fill in the // initial stack frame that will be loaded for this PCB when it gets switched in by // ProcessSchedule the first time. stackframe -= PROCESS_STACK_FRAME_SIZE; // The system stack pointer is set to the base of the current interrupt stack frame. pcb->sysStackPtr = stackframe; // The current stack frame pointer is set to the same thing. pcb->currentSavedFrame = stackframe; //---------------------------------------------------------------------- // This section sets up the stack frame for the process. This is done // so that the frame looks to the interrupt handler like the process // was "suspended" right before it began execution. The standard // mechanism of swapping in the registers and returning to the place // where it was "interrupted" will then work. //---------------------------------------------------------------------- // The previous stack frame pointer is set to 0, meaning there is no // previous frame. dbprintf('m', "ProcessFork-ProcessFork: stackframe = 0x%x\n", (int)stackframe); stackframe[PROCESS_STACK_PREV_FRAME] = 0; //---------------------------------------------------------------------- // STUDENT: setup the PTBASE, PTBITS, and PTSIZE here on the current // stack frame. //---------------------------------------------------------------------- // JSM added PTBASE, PTBITS, and PTSIZE on stack frame ////////////////////////////////////////////////////////// stackframe[PROCESS_STACK_PTBASE] = (uint32)&(pcb->pagetable[0]); dbprintf('p', "ProcessFork-PTBASE: 0x%.8X\n\n", (uint32)&(pcb->pagetable[0])); stackframe[PROCESS_STACK_PTSIZE] = MEM_L1_PAGE_TABLE_SIZE; dbprintf('p', "ProcessFork-PTSIZE: 0x%.8X\n\n", MEM_L1_PAGE_TABLE_SIZE); stackframe[PROCESS_STACK_PTBITS] = (MEM_L2FIELD_FIRST_BITNUM << 16) | MEM_L1FIELD_FIRST_BITNUM; dbprintf('p', "ProcessFork-PTBITS: 0x%.8X\n\n", (MEM_L2FIELD_FIRST_BITNUM << 16) | MEM_L1FIELD_FIRST_BITNUM); ////////////////////////////////////////////////////////// if (isUser) {//user prog .dlx.obj dbprintf ('p', "ProcessFork-About to load %s\n", name); fd = ProcessGetCodeInfo (name, &start, &codeS, &codeL, &dataS, &dataL); if (fd < 0) { // Free newpage and pcb so we don't run out... ProcessFreeResources (pcb); return (-1); } dbprintf ('p', "ProcessFork-File %s -> start=0x%08x\n", name, start); dbprintf ('p', "ProcessFork-File %s -> code @ 0x%08x (size=0x%08x)\n", name, codeS, codeL); dbprintf ('p', "ProcessFork-File %s -> data @ 0x%08x (size=0x%08x)\n", name, dataS, dataL); while ((n = ProcessGetFromFile (fd, buf, &addr, sizeof (buf))) > 0) { dbprintf ('p', "ProcessFork-Placing %d bytes at vaddr %08x.\n", n, addr - n); // Copy the data to user memory. Note that the user memory needs to // have enough space so that this copy will succeed! MemoryCopySystemToUser (pcb, buf, (char *)(addr - n), n); } FsClose (fd); stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_USER; //---------------------------------------------------------------------- // STUDENT: setup the initial user stack pointer here as the top // of the process's virtual address space (4-byte aligned). //---------------------------------------------------------------------- // JSM initialized user stack pointer ////////////////////////////////////////////////////////// stackframe[PROCESS_STACK_USER_STACKPOINTER] = (MEM_MAX_VIRTUAL_ADDRESS-3); dbprintf('p', "ProcessFork-USER_STACKPOINTER: 0x%.8X\n\n", stackframe[PROCESS_STACK_USER_STACKPOINTER]); ////////////////////////////////////////////////////////// //-------------------------------------------------------------------- // This part is setting up the initial user stack with argc and argv. //-------------------------------------------------------------------- // Copy the entire set of strings of command line parameters onto the user stack. // The "param" variable is a pointer to the start of a sequenial set of strings, // each ending with its own '\0' character. The final "string" of the sequence // must be an empty string to indicate that the sequence is done. Since we // can't figure out how long the set of strings actually is in this scenario, // we have to copy the maximum possible string length and parse things manually. stackframe[PROCESS_STACK_USER_STACKPOINTER] -= SIZE_ARG_BUFF; MemoryCopySystemToUser (pcb, (char *)param, (char *)stackframe[PROCESS_STACK_USER_STACKPOINTER], SIZE_ARG_BUFF); // Now that the main string is copied into the user space, we need to setup // argv as an array of pointers into that string, and argc as the total // number of arguments found in the string. The first call to get_argument // should return 0 as the offset of the first string. offset = get_argument((char *)param); // Compute the addresses in user space of where each string for the command line arguments // begins. These addresses make up the argv array. for(argc=0; argc < MAX_ARGS; argc++) { // The "+2" is because initial_user_params[0] is argc, and initial_user_params[1] is argv. // The address can be found as the current stack pointer (which points to the start of // the params list) plus the byte offset of the parameter from the beginning of // the list of parameters. initial_user_params[argc+2] = stackframe[PROCESS_STACK_USER_STACKPOINTER] + offset; offset = get_argument(NULL); if (offset == 0) { initial_user_params[argc+2+1] = 0; // last entry should be a null value break; } } // argc is currently the index of the last command line argument. We need it to instead // be the number of command line arguments, so we increment it by 1. argc++; // Now argc can be stored properly initial_user_params[0] = argc; // Compute where initial_user_params[3] will be copied in user space as the // base of the array of string addresses. The entire initial_user_params array // of uint32's will be copied onto the stack. We'll move the stack pointer by // the necessary amount, then start copying the array. Therefore, initial_user_params[3] // will reside at the current stack pointer value minus the number of command line // arguments (argc). initial_user_params[1] = stackframe[PROCESS_STACK_USER_STACKPOINTER] - (argc*sizeof(uint32)); // Now copy the actual memory. Remember that stacks grow down from the top of memory, so // we need to move the stack pointer first, then do the copy. The "+2", as before, is // because initial_user_params[0] is argc, and initial_user_params[1] is argv. initial_user_params_bytes = (argc + 2) * sizeof(uint32); stackframe[PROCESS_STACK_USER_STACKPOINTER] -= initial_user_params_bytes; MemoryCopySystemToUser (pcb, (char *)initial_user_params, (char *)(stackframe[PROCESS_STACK_USER_STACKPOINTER]), initial_user_params_bytes); // Set the correct address at which to execute a user process. stackframe[PROCESS_STACK_IAR] = (uint32)start; // Flag this as a user process pcb->flags |= PROCESS_TYPE_USER; } else { // Don't worry about messing with any code here for kernel processes because // there aren't any kernel processes in DLXOS. // Set r31 to ProcessExit(). This will only be called for a system // process; user processes do an exit() trap. stackframe[PROCESS_STACK_IREG+31] = (uint32)ProcessExit; // Set the stack register to the base of the system stack. //stackframe[PROCESS_STACK_IREG+29]=pcb->sysStackArea + MEM_PAGESIZE; // Set the initial parameter properly by placing it on the stack frame // at the location pointed to by the "saved" stack pointer (r29). *((uint32 *)(stackframe[PROCESS_STACK_IREG+29])) = param; // Set up the initial address at which to execute. This is done by // placing the address into the IAR slot of the stack frame. stackframe[PROCESS_STACK_IAR] = (uint32)func; // Set the initial value for the interrupt status register stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_SYS; // Mark this as a system process. pcb->flags |= PROCESS_TYPE_SYSTEM; } // Place the PCB onto the run queue. intrs = DisableIntrs (); if ((pcb->l = AQueueAllocLink(pcb)) == NULL) { printf("FATAL ERROR: could not get link for forked PCB in ProcessFork!\n"); exitsim(); } if (AQueueInsertLast(&runQueue, pcb->l) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not insert link into runQueue in ProcessFork!\n"); exitsim(); } RestoreIntrs (intrs); // If this is the first process, make it the current one if (currentPCB == NULL) { dbprintf ('p', "Setting currentPCB=0x%x, stackframe=0x%x\n", (int)pcb, (int)(pcb->currentSavedFrame)); currentPCB = pcb; } dbprintf ('p', "Leaving ProcessFork (%s)\n", name); // Return the process number (found by subtracting the PCB number // from the base of the PCB array). return (pcb - pcbs); }
int tun_read_ev(int idx, dbuf_t *d, void *p) { lua_State *L; http_parser_t *parser = &http_parser; http_parser_init(parser); L = lua_open(); lua_init_state(L); if(http_parser_data(parser, d->buf, d->dsize)) { char *reply = "File not found!\n"; char *content_type = "text/plain"; char headers[512]; char trailer[1024]; char *xfile; size_t xfile_sz; debug(DBG_GLOBAL, 1, "Parser done. Method: '%s', URI: '%s'", parser->req_method, parser->req_uri); if(strstr(parser->req_uri, ".css")) { content_type = "text/css"; } else if(strstr(parser->req_uri, ".html")) { content_type = "text/html"; } else if(strstr(parser->req_uri, ".js")) { content_type = "application/javascript"; } else if(strstr(parser->req_uri, ".png")) { content_type = "image/png"; } memcpy(trailer, parser->end, parser->content_length); trailer[parser->content_length] = 0; debug(DBG_GLOBAL, 0, "Parser trailer: '%s'", trailer); xfile = mz_zip_extract_archive_file_to_heap("data.zip", parser->req_uri+1, &xfile_sz, 0); if(xfile) { debug(0, 0, "File '%s' => size is %d", parser->req_uri+1, xfile_sz); xfile[xfile_sz] = 0; if(strstr(parser->req_uri, ".lua")) { if(luaL_loadstring(L, xfile)) { debug(0, 0, "Lua file load error: %s", lua_tostring(L,-1)); } else { lua_pcall(L, 0, LUA_MULTRET, 0); lua_getglobal(L, "request"); lua_pushinteger(L, idx); int err = lua_pcall(L, 1, 0, 0); if (err != 0) { debug(0,0,"%d: LUA error %s\n",getpid(), lua_tostring(L,-1)); } } } else { snprintf(headers, sizeof(headers)-1, "HTTP/1.0 200 OK\r\nConnection: keep-alive\r\nContent-length: %d\r\nContent-type: %s\r\n\r\n", (int)xfile_sz, content_type); dunlock(sock_write_data(idx, dstrcpy(headers), NULL)); dunlock(sock_write_data(idx, dalloc_ptr(xfile, xfile_sz), NULL)); xfile = NULL; } } else { snprintf(headers, sizeof(headers)-1, "HTTP/1.0 404 Not Found\r\nConnection: keep-alive\r\nContent-length: %d\r\nContent-type: %s\r\n\r\n", (int)strlen(reply), content_type); dunlock(sock_send_data(idx, dstrcpy(headers), NULL)); dunlock(sock_send_data(idx, dstrcpy(reply), NULL)); } if(xfile) { free(xfile); } lua_close(L); } else { lua_close(L); return 0; } // printf("Got packet, sending back!\n"); return -1; }
void G_PlayDemo(const char* name) { int i; int p; char filename[256]; gameaction = ga_nothing; endDemo = false; p = M_CheckParm("-playdemo"); if(p && p < myargc-1) { // 20120107 bkw: add .lmp extension if missing. if(dstrrchr(myargv[p+1], '.')) { dstrcpy(filename, myargv[p+1]); } else { dsprintf(filename, "%s.lmp", myargv[p+1]); } CON_DPrintf("--------Reading demo %s--------\n", filename); if(M_ReadFile(filename, &demobuffer) == -1) { gameaction = ga_exitdemo; return; } demo_p = demobuffer; } else { if(W_CheckNumForName(name) == -1) { gameaction = ga_exitdemo; return; } CON_DPrintf("--------Playing demo %s--------\n", name); demobuffer = demo_p = W_CacheLumpName(name, PU_STATIC); } if(strncmp((char*)demo_p, "DM64", 4)) { I_Error("G_PlayDemo: Mismatched demo header"); return; } G_SaveDefaults(); demo_p++; demo_p++; demo_p++; demo_p++; demo_p++; startskill = *demo_p++; startmap = *demo_p++; deathmatch = *demo_p++; respawnparm = *demo_p++; respawnitem = *demo_p++; fastparm = *demo_p++; nomonsters = *demo_p++; consoleplayer = *demo_p++; rngseed = *demo_p++ & 0xff; rngseed <<= 8; rngseed += *demo_p++ & 0xff; rngseed <<= 8; rngseed += *demo_p++ & 0xff; rngseed <<= 8; rngseed += *demo_p++ & 0xff; gameflags = *demo_p++ & 0xff; gameflags <<= 8; gameflags += *demo_p++ & 0xff; gameflags <<= 8; gameflags += *demo_p++ & 0xff; gameflags <<= 8; gameflags += *demo_p++ & 0xff; compatflags = *demo_p++ & 0xff; compatflags <<= 8; compatflags += *demo_p++ & 0xff; compatflags <<= 8; compatflags += *demo_p++ & 0xff; compatflags <<= 8; compatflags += *demo_p++ & 0xff; for(i = 0; i < MAXPLAYERS; i++) { playeringame[i] = *demo_p++; } G_InitNew(startskill, startmap); if(playeringame[1]) { netgame = true; netdemo = true; } precache = true; usergame = false; demoplayback = true; G_RunGame(); iwadDemo = false; }
//---------------------------------------------------------------------- // // ProcessFork // // Create a new process and make it runnable. This involves the // following steps: // * Allocate resources for the process (PCB, memory, etc.) // * Initialize the resources // * Place the PCB on the runnable queue // // NOTE: This code has been tested for system processes, but not // for user processes. // //---------------------------------------------------------------------- int ProcessFork (VoidFunc func, uint32 param, char *name, int isUser) { int i; // Loop index variable int fd, n; // Used for reading code from files. int start, codeS, codeL; // Used for reading code from files. int dataS, dataL; // Used for reading code from files. int addr = 0; // Used for reading code from files. unsigned char buf[100]; // Used for reading code from files. uint32 *stackframe; // Stores address of current stack frame. PCB *pcb; // Holds pcb while we build it for this process. int intrs; // Stores previous interrupt settings. uint32 initial_user_params[MAX_ARGS+2]; // Initial memory for user parameters (argc, argv) // initial_user_params[0] = argc // initial_user_params[1] = argv, points to initial_user_params[2] // initial_user_params[2] = address of string for argv[0] // initial_user_params[3] = address of string for argv[1] // ... uint32 argc=0; // running counter for number of arguments uint32 offset; // Used in parsing command line argument strings, holds offset (in bytes) from // beginning of the string to the current argument. uint32 initial_user_params_bytes; // total number of bytes in initial user parameters array int newPage; intrs = DisableIntrs (); dbprintf ('I', "Old interrupt value was 0x%x.\n", intrs); dbprintf ('p', "Entering ProcessFork args=0x%x 0x%x %s %d\n", (int)func, param, name, isUser); // Get a free PCB for the new process if (AQueueEmpty(&freepcbs)) { printf ("FATAL error: no free processes!\n"); exitsim (); // NEVER RETURNS! } pcb = (PCB *)AQueueObject(AQueueFirst (&freepcbs)); dbprintf ('p', "Got a link @ 0x%x\n", (int)(pcb->l)); if (AQueueRemove (&(pcb->l)) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not remove link from freepcbsQueue in ProcessFork!\n"); exitsim(); } // This prevents someone else from grabbing this process ProcessSetStatus (pcb, PROCESS_STATUS_RUNNABLE); // At this point, the PCB is allocated and nobody else can get it. // However, it's not in the run queue, so it won't be run. Thus, we // can turn on interrupts here. RestoreIntrs (intrs); // Copy the process name into the PCB. dstrcpy(pcb->name, name); //---------------------------------------------------------------------- // This section initializes the memory for this process //---------------------------------------------------------------------- // Allocate 1 page for system stack, 1 page for user stack (at top of // virtual address space), and 4 pages for user code and global data. //--------------------------------------------------------- // STUDENT: allocate pages for a new process here. The // code below assumes that you set the "stackframe" variable // equal to the last 4-byte-aligned address in physical page // for the system stack. //--------------------------------------------------------- // Pages for code and global data and Heap pcb->npages = 5; for(i = 0; i < pcb->npages; i++) { newPage = MemoryAllocPage(); if(newPage == MEM_FAIL) { printf ("FATAL: couldn't allocate memory - no free pages!\n"); ProcessFreeResources (pcb); return PROCESS_FORK_FAIL; } pcb->pagetable[i] = MemorySetupPte (newPage); } // Initialize nodes in pool for (i = 1; i <= MEM_HEAP_MAX_NODES; i++) { pcb->htree_array[i].parent = NULL; pcb->htree_array[i].cleft = NULL; pcb->htree_array[i].crght = NULL; pcb->htree_array[i].index = i; pcb->htree_array[i].size = -1; pcb->htree_array[i].addr = -1; pcb->htree_array[i].inuse = 0; pcb->htree_array[i].order = -1; } // Initialize Heap tree pcb->htree_array[1].size = MEM_PAGESIZE; pcb->htree_array[1].addr = 0; pcb->htree_array[1].order = 7; // user stack pcb->npages += 1; newPage = MemoryAllocPage(); if(newPage == MEM_FAIL) { printf ("FATAL: couldn't allocate user stack - no free pages!\n"); ProcessFreeResources (pcb); return PROCESS_FORK_FAIL; } pcb->pagetable[MEM_ADDRESS_TO_PAGE(MEM_MAX_VIRTUAL_ADDRESS)] = MemorySetupPte (newPage); // for system stack newPage = MemoryAllocPage (); if(newPage == MEM_FAIL) { printf ("FATAL: couldn't allocate system stack - no free pages!\n"); ProcessFreeResources (pcb); return PROCESS_FORK_FAIL; } pcb->sysStackArea = newPage * MEM_PAGESIZE; //---------------------------------------------------------------------- // Stacks grow down from the top. The current system stack pointer has // to be set to the bottom of the interrupt stack frame, which is at the // high end (address-wise) of the system stack. stackframe = (uint32 *)(pcb->sysStackArea + MEM_PAGESIZE - 4); dbprintf('p', "ProcessFork: SystemStack page=%d sysstackarea=0x%x\n", newPage, pcb->sysStackArea); // Now that the stack frame points at the bottom of the system stack memory area, we need to // move it up (decrement it) by one stack frame size because we're about to fill in the // initial stack frame that will be loaded for this PCB when it gets switched in by // ProcessSchedule the first time. stackframe -= PROCESS_STACK_FRAME_SIZE; // The system stack pointer is set to the base of the current interrupt stack frame. pcb->sysStackPtr = stackframe; // The current stack frame pointer is set to the same thing. pcb->currentSavedFrame = stackframe; dbprintf ('p', "Setting up PCB @ 0x%x (sys stack=0x%x, mem=0x%x, size=0x%x)\n", (int)pcb, pcb->sysStackArea, pcb->pagetable[0], pcb->npages * MEM_PAGESIZE); //---------------------------------------------------------------------- // This section sets up the stack frame for the process. This is done // so that the frame looks to the interrupt handler like the process // was "suspended" right before it began execution. The standard // mechanism of swapping in the registers and returning to the place // where it was "interrupted" will then work. //---------------------------------------------------------------------- // The previous stack frame pointer is set to 0, meaning there is no // previous frame. dbprintf('p', "ProcessFork: stackframe = 0x%x\n", (int)stackframe); stackframe[PROCESS_STACK_PREV_FRAME] = 0; //---------------------------------------------------------------------- // STUDENT: setup the PTBASE, PTBITS, and PTSIZE here on the current // stack frame. //---------------------------------------------------------------------- // Set the base of the level 1 page table. If there's only one page // table level, this is it. For 2-level page tables, put the address // of the level 1 page table here. For 2-level page tables, we'll also // have to build up the necessary tables.... stackframe[PROCESS_STACK_PTBASE] = (uint32)(&(pcb->pagetable[0])); // Set the size (maximum number of entries) of the level 1 page table. // In our case, it's just one page, but it could be larger. stackframe[PROCESS_STACK_PTSIZE] = MEM_PAGE_TBL_SIZE; // Set the number of bits for both the level 1 and level 2 page tables. // This can be changed on a per-process basis if desired. For now, // though, it's fixed. stackframe[PROCESS_STACK_PTBITS] = (MEM_L1FIELD_FIRST_BITNUM << 16) + MEM_L1FIELD_FIRST_BITNUM; if (isUser) { dbprintf ('p', "About to load %s\n", name); fd = ProcessGetCodeInfo (name, &start, &codeS, &codeL, &dataS, &dataL); if (fd < 0) { // Free newPage and pcb so we don't run out... ProcessFreeResources (pcb); return (-1); } dbprintf ('p', "File %s -> start=0x%08x\n", name, start); dbprintf ('p', "File %s -> code @ 0x%08x (size=0x%08x)\n", name, codeS, codeL); dbprintf ('p', "File %s -> data @ 0x%08x (size=0x%08x)\n", name, dataS, dataL); while ((n = ProcessGetFromFile (fd, buf, &addr, sizeof (buf))) > 0) { dbprintf ('i', "Placing %d bytes at vaddr %08x.\n", n, addr - n); // Copy the data to user memory. Note that the user memory needs to // have enough space so that this copy will succeed! MemoryCopySystemToUser (pcb, buf, (char *)(addr - n), n); } FsClose (fd); stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_USER; //---------------------------------------------------------------------- // STUDENT: setup the initial user stack pointer here as the top // of the process's virtual address space (4-byte aligned). //---------------------------------------------------------------------- stackframe[PROCESS_STACK_USER_STACKPOINTER] = MEM_MAX_VIRTUAL_ADDRESS - 3; dbprintf('p', "ProcessFork: UserStack usrsp=0x%x\n", stackframe[PROCESS_STACK_USER_STACKPOINTER]); //-------------------------------------------------------------------- // This part is setting up the initial user stack with argc and argv. //-------------------------------------------------------------------- // Copy the entire set of strings of command line parameters onto the user stack. // The "param" variable is a pointer to the start of a sequenial set of strings, // each ending with its own '\0' character. The final "string" of the sequence // must be an empty string to indicate that the sequence is done. Since we // can't figure out how long the set of strings actually is in this scenario, // we have to copy the maximum possible string length and parse things manually. stackframe[PROCESS_STACK_USER_STACKPOINTER] -= SIZE_ARG_BUFF; MemoryCopySystemToUser (pcb, (char *)param, (char *)stackframe[PROCESS_STACK_USER_STACKPOINTER], SIZE_ARG_BUFF); // Now that the main string is copied into the user space, we need to setup // argv as an array of pointers into that string, and argc as the total // number of arguments found in the string. The first call to get_argument // should return 0 as the offset of the first string. offset = get_argument((char *)param); // Compute the addresses in user space of where each string for the command line arguments // begins. These addresses make up the argv array. for(argc=0; argc < MAX_ARGS; argc++) { // The "+2" is because initial_user_params[0] is argc, and initial_user_params[1] is argv. // The address can be found as the current stack pointer (which points to the start of // the params list) plus the byte offset of the parameter from the beginning of // the list of parameters. initial_user_params[argc+2] = stackframe[PROCESS_STACK_USER_STACKPOINTER] + offset; offset = get_argument(NULL); if (offset == 0) { initial_user_params[argc+2+1] = 0; // last entry should be a null value break; } } // argc is currently the index of the last command line argument. We need it to instead // be the number of command line arguments, so we increment it by 1. argc++; // Now argc can be stored properly initial_user_params[0] = argc; // Compute where initial_user_params[3] will be copied in user space as the // base of the array of string addresses. The entire initial_user_params array // of uint32's will be copied onto the stack. We'll move the stack pointer by // the necessary amount, then start copying the array. Therefore, initial_user_params[3] // will reside at the current stack pointer value minus the number of command line // arguments (argc). initial_user_params[1] = stackframe[PROCESS_STACK_USER_STACKPOINTER] - (argc*sizeof(uint32)); // Now copy the actual memory. Remember that stacks grow down from the top of memory, so // we need to move the stack pointer first, then do the copy. The "+2", as before, is // because initial_user_params[0] is argc, and initial_user_params[1] is argv. initial_user_params_bytes = (argc + 2) * sizeof(uint32); stackframe[PROCESS_STACK_USER_STACKPOINTER] -= initial_user_params_bytes; MemoryCopySystemToUser (pcb, (char *)initial_user_params, (char *)(stackframe[PROCESS_STACK_USER_STACKPOINTER]), initial_user_params_bytes); // Set the correct address at which to execute a user process. stackframe[PROCESS_STACK_IAR] = (uint32)start; // Flag this as a user process pcb->flags |= PROCESS_TYPE_USER; } else { // Don't worry about messing with any code here for kernel processes because // there aren't any kernel processes in DLXOS. // Set r31 to ProcessExit(). This will only be called for a system // process; user processes do an exit() trap. stackframe[PROCESS_STACK_IREG+31] = (uint32)ProcessExit; // Set the stack register to the base of the system stack. //stackframe[PROCESS_STACK_IREG+29]=pcb->sysStackArea + MEM_PAGESIZE; // Set the initial parameter properly by placing it on the stack frame // at the location pointed to by the "saved" stack pointer (r29). *((uint32 *)(stackframe[PROCESS_STACK_IREG+29])) = param; // Set up the initial address at which to execute. This is done by // placing the address into the IAR slot of the stack frame. stackframe[PROCESS_STACK_IAR] = (uint32)func; // Set the initial value for the interrupt status register stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_SYS; // Mark this as a system process. pcb->flags |= PROCESS_TYPE_SYSTEM; } // Place the PCB onto the run queue. intrs = DisableIntrs (); if ((pcb->l = AQueueAllocLink(pcb)) == NULL) { printf("FATAL ERROR: could not get link for forked PCB in ProcessFork!\n"); exitsim(); } if (AQueueInsertLast(&runQueue, pcb->l) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not insert link into runQueue in ProcessFork!\n"); exitsim(); } RestoreIntrs (intrs); // If this is the first process, make it the current one if (currentPCB == NULL) { dbprintf ('p', "Setting currentPCB=0x%x, stackframe=0x%x\n", (int)pcb, (int)(pcb->currentSavedFrame)); currentPCB = pcb; } dbprintf ('p', "Leaving ProcessFork (%s)\n", name); // Return the process number (found by subtracting the PCB number // from the base of the PCB array). return (pcb - pcbs); }
//---------------------------------------------------------------------- // // ProcessFork // // Create a new process and make it runnable. This involves the // following steps: // * Allocate resources for the process (PCB, memory, etc.) // * Initialize the resources // * Place the PCB on the runnable queue // // NOTE: This code has been tested for system processes, but not // for user processes. // //---------------------------------------------------------------------- int ProcessFork (VoidFunc func, uint32 param, int p_nice, int p_info,char *name, int isUser) { int i, j, fd, n; Link *l; int start, codeS, codeL, dataS, dataL; uint32 *stackframe; int newPage; PCB *pcb; int addr = 0; int intrs; unsigned char buf[100]; uint32 dum[MAX_ARGS+8], count, offset; char *str; intrs = DisableIntrs (); dbprintf ('I', "Old interrupt value was 0x%x.\n", intrs); dbprintf ('p', "Entering ProcessFork args=0x%x 0x%x %s %d\n", func, param, name, isUser); // Get a free PCB for the new process if (QueueEmpty (&freepcbs)) { printf ("FATAL error: no free processes!\n"); exitsim (); // NEVER RETURNS! } l = QueueFirst (&freepcbs); dbprintf ('p', "Got a link @ 0x%x\n", l); QueueRemove (l); pcb = (PCB *)(l->object); // This prevents someone else from grabbing this process ProcessSetStatus (pcb, PROCESS_STATUS_RUNNABLE); // At this point, the PCB is allocated and nobody else can get it. // However, it's not in the run queue, so it won't be run. Thus, we // can turn on interrupts here. dbprintf ('I', "Before restore interrupt value is 0x%x.\n", CurrentIntrs()); RestoreIntrs (intrs); dbprintf ('I', "New interrupt value is 0x%x.\n", CurrentIntrs()); // Copy the process name into the PCB. dstrcpy (pcb->name, name); //---------------------------------------------------------------------- // This section initializes the memory for this process //---------------------------------------------------------------------- // For now, we'll use one user page and a page for the system stack. // For system processes, though, all pages must be contiguous. // Of course, system processes probably need just a single page for // their stack, and don't need any code or data pages allocated for them. pcb->npages = 1; newPage = MemoryAllocPage (); if (newPage == 0) { printf ("aFATAL: couldn't allocate memory - no free pages!\n"); exitsim (); // NEVER RETURNS! } pcb->pagetable[0] = MemorySetupPte (newPage); newPage = MemoryAllocPage (); if (newPage == 0) { printf ("bFATAL: couldn't allocate system stack - no free pages!\n"); exitsim (); // NEVER RETURNS! } pcb->sysStackArea = newPage * MEMORY_PAGE_SIZE; //--------------------------------------- // Lab3: initialized pcb member for your scheduling algorithm here //-------------------------------------- pcb->p_nice = p_nice < 0 ? 0 : p_nice; pcb->p_info = p_info; pcb->sleeptime = my_timer_get(); pcb->estcpu = 0; pcb->prio = PUSER; pcb->processed = 1 - processedFlag; pcb->estcputime = 0; //---------------------------------------------------------------------- // Stacks grow down from the top. The current system stack pointer has // to be set to the bottom of the interrupt stack frame, which is at the // high end (address-wise) of the system stack. stackframe = ((uint32 *)(pcb->sysStackArea + MEMORY_PAGE_SIZE)) - (PROCESS_STACK_FRAME_SIZE + 8); // The system stack pointer is set to the base of the current interrupt // stack frame. pcb->sysStackPtr = stackframe; // The current stack frame pointer is set to the same thing. pcb->currentSavedFrame = stackframe; dbprintf ('p', "Setting up PCB @ 0x%x (sys stack=0x%x, mem=0x%x, size=0x%x)\n", pcb, pcb->sysStackArea, pcb->pagetable[0], pcb->npages * MEMORY_PAGE_SIZE); //---------------------------------------------------------------------- // This section sets up the stack frame for the process. This is done // so that the frame looks to the interrupt handler like the process // was "suspended" right before it began execution. The standard // mechanism of swapping in the registers and returning to the place // where it was "interrupted" will then work. //---------------------------------------------------------------------- // The previous stack frame pointer is set to 0, meaning there is no // previous frame. stackframe[PROCESS_STACK_PREV_FRAME] = 0; // Set the base of the level 1 page table. If there's only one page // table level, this is it. For 2-level page tables, put the address // of the level 1 page table here. For 2-level page tables, we'll also // have to build up the necessary tables.... stackframe[PROCESS_STACK_PTBASE] = (uint32)&(pcb->pagetable[0]); // Set the size (maximum number of entries) of the level 1 page table. // In our case, it's just one page, but it could be larger. stackframe[PROCESS_STACK_PTSIZE] = pcb->npages; // Set the number of bits for both the level 1 and level 2 page tables. // This can be changed on a per-process basis if desired. For now, // though, it's fixed. stackframe[PROCESS_STACK_PTBITS] = (MEMORY_L1_PAGE_SIZE_BITS + (MEMORY_L2_PAGE_SIZE_BITS << 16)); if (isUser) { dbprintf ('p', "About to load %s\n", name); fd = ProcessGetCodeInfo (name, &start, &codeS, &codeL, &dataS, &dataL); if (fd < 0) { // Free newpage and pcb so we don't run out... ProcessFreeResources (pcb); return (-1); } dbprintf ('p', "File %s -> start=0x%08x\n", name, start); dbprintf ('p', "File %s -> code @ 0x%08x (size=0x%08x)\n", name, codeS, codeL); dbprintf ('p', "File %s -> data @ 0x%08x (size=0x%08x)\n", name, dataS, dataL); while ((n = ProcessGetFromFile (fd, buf, &addr, sizeof (buf))) > 0) { dbprintf ('p', "Placing %d bytes at vaddr %08x.\n", n, addr - n); // Copy the data to user memory. Note that the user memory needs to // have enough space so that this copy will succeed! MemoryCopySystemToUser (pcb, buf, addr - n, n); } FsClose (fd); stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_USER; // Set the initial stack pointer correctly. Currently, it's just set // to the top of the (single) user address space allocated to this // process. str = (char *)param; stackframe[PROCESS_STACK_IREG+29] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF; // Copy the initial parameter to the top of stack MemoryCopySystemToUser (pcb, (char *)str, (char *)stackframe[PROCESS_STACK_IREG+29], SIZE_ARG_BUFF-32); offset = get_argument((char *)param); dum[2] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF + offset; for(count=3;;count++) { offset=get_argument(NULL); dum[count] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF + offset; if(offset==0) { break; } } dum[0] = count-2; dum[1] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF - (count-2)*4; MemoryCopySystemToUser (pcb, (char *)dum, (char *)(stackframe[PROCESS_STACK_IREG+29]-count*4), (count)*sizeof(uint32)); stackframe[PROCESS_STACK_IREG+29] -= 4*count; // Set the correct address at which to execute a user process. stackframe[PROCESS_STACK_IAR] = (uint32)start; pcb->flags |= PROCESS_TYPE_USER; } else { // Set r31 to ProcessExit(). This will only be called for a system // process; user processes do an exit() trap. stackframe[PROCESS_STACK_IREG+31] = (uint32)ProcessExit; // Set the stack register to the base of the system stack. stackframe[PROCESS_STACK_IREG+29]=pcb->sysStackArea + MEMORY_PAGE_SIZE-32; // Set the initial parameter properly by placing it on the stack frame // at the location pointed to by the "saved" stack pointer (r29). *((uint32 *)(stackframe[PROCESS_STACK_IREG+29])) = param; // Set up the initial address at which to execute. This is done by // placing the address into the IAR slot of the stack frame. stackframe[PROCESS_STACK_IAR] = (uint32)func; // Set the initial value for the interrupt status register stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_SYS; // Mark this as a system process. pcb->flags |= PROCESS_TYPE_SYSTEM; } // Place the PCB onto the run queue. intrs = DisableIntrs (); QueueInsertLast (&runQueue[pcb->prio/4], l); RestoreIntrs (intrs); // If this is the first process, make it the current one if (currentPCB == NULL) { dbprintf ('p', "Setting currentPCB=0x%x, stackframe=0x%x\n", pcb, pcb->currentSavedFrame); currentPCB = pcb; } dbprintf ('p', "Leaving ProcessFork (%s)\n", name); // Return the process number (found by subtracting the PCB number // from the base of the PCB array). return (pcb - pcbs); }
//---------------------------------------------------------------------- // // main // // This routine is called when the OS starts up. It allocates a // PCB for the first process - the one corresponding to the initial // thread of execution. Note that the stack pointer is already // set correctly by _osinit (assembly language code) to point // to the stack for the 0th process. This stack isn't very big, // though, so it should be replaced by the system stack of the // currently running process. // //---------------------------------------------------------------------- main (int argc, char *argv[]) { int i, j; int n; char buf[120]; char *userprog = (char *)0; static PCB temppcb; uint32 addr; extern void SysprocCreateProcesses (); char *param[12]={NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; int base; debugstr[0] = '\0'; MyFuncRetZero(); printf ("Got %d arguments.\n", argc); printf ("Available memory: 0x%x -> 0x%x.\n", lastosaddress, MemoryGetSize ()); printf ("Argument count is %d.\n", argc); for (i = 0; i < argc; i++) { printf ("Argument %d is %s.\n", i, argv[i]); } // *((int *)0xfff00100) = 't'; FsModuleInit (); for (i = 0; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'D': dstrcpy (debugstr, argv[++i]); break; case 'i': n = dstrtol (argv[++i], (void *)0, 0); ditoa (n, buf); printf ("Converted %s to %d=%s\n", argv[i], n, buf); break; case 'f': { int start, codeS, codeL, dataS, dataL, fd, j; int addr = 0; static unsigned char buf[200]; fd = ProcessGetCodeInfo (argv[++i], &start, &codeS, &codeL, &dataS, &dataL); printf ("File %s -> start=0x%08x\n", argv[i], start); printf ("File %s -> code @ 0x%08x (size=0x%08x)\n", argv[i], codeS, codeL); printf ("File %s -> data @ 0x%08x (size=0x%08x)\n", argv[i], dataS, dataL); while ((n = ProcessGetFromFile (fd, buf, &addr, sizeof (buf))) > 0) { for (j = 0; j < n; j += 4) { printf ("%08x: %02x%02x%02x%02x\n", addr + j - n, buf[j], buf[j+1], buf[j+2], buf[j+3]); } } close (fd); break; } case 'u': userprog = argv[++i]; base = i; break; default: printf ("Option %s not recognized.\n", argv[i]); break; } if(userprog) break; } } dbprintf ('i', "About to initialize queues.\n"); QueueModuleInit (); dbprintf ('i', "After initializing queues.\n"); MemoryModuleInit (); dbprintf ('i', "After initializing memory.\n"); ProcessModuleInit (); dbprintf ('i', "After initializing processes.\n"); ShareModuleInit (); dbprintf ('i', "After initializing shared memory.\n"); SynchModuleInit (); dbprintf ('i', "After initializing synchronization tools.\n"); KbdModuleInit (); dbprintf ('i', "After initializing keyboard.\n"); for (i = 0; i < 100; i++) { buf[i] = 'a'; } i = FsOpen ("vm", FS_MODE_WRITE); dbprintf ('i', "VM Descriptor is %d\n", i); FsSeek (i, 0, FS_SEEK_SET); FsWrite (i, buf, 80); FsClose (i); if (userprog != (char *)0) { for(i=base;i<argc&&i-base<11; i++) { param[i-base] = argv[i]; } process_create(0,0,param[0], param[1], param[2], param[3], param[4], param[5], param[6], param[7], param[8], param[9], param[10], param[11]); // ProcessFork (0, (uint32)"Help Me man!", userprog, 1); } SysprocCreateProcesses (); dbprintf ('i', "Created processes - about to set timer quantum.\n"); TimerSet (processQuantum); dbprintf ('i', "Set timer quantum to %d, about to run first process.\n", processQuantum); intrreturn (); // Should never be called because the scheduler exits when there // are no runnable processes left. exitsim(); // NEVER RETURNS! }