// Allocates and initializes a new environment. // On success, the new environment is stored in *newenv_store. // // Returns 0 on success, < 0 on failure. Errors include: // -E_NO_FREE_ENV if all NENVS environments are allocated // -E_NO_MEM on memory exhaustion int env_alloc(struct Env **newenv_store, envid_t parent_id) { int32_t generation; int r; struct Env *e; if (!(e = LIST_FIRST(&env_free_list))) return -E_NO_FREE_ENV; // Allocate and set up the page directory for this environment. if ((r = env_mem_init(e)) < 0) return r; // Generate an env_id for this environment. generation = (e->env_id + (1 << ENVGENSHIFT)) & ~(NENV - 1); if (generation <= 0) // Don't create a negative env_id. generation = 1 << ENVGENSHIFT; e->env_id = generation | (e - envs); // Set the basic status variables. e->env_parent_id = parent_id; e->env_status = ENV_RUNNABLE; e->env_runs = 0; // Clear out all the saved register state, // to prevent the register values // of a prior environment inhabiting this Env structure // from "leaking" into our new environment. memset(&e->env_tf, 0, sizeof(e->env_tf)); // Set up appropriate initial values for the segment registers. // GD_UD is the user data segment selector in the GDT, and // GD_UT is the user text segment selector (see inc/memlayout.h). // The low 2 bits of each segment register contains the // Requestor Privilege Level (RPL); 3 means user mode. e->env_tf.tf_ds = GD_UD | 3; e->env_tf.tf_es = GD_UD | 3; e->env_tf.tf_ss = GD_UD | 3; e->env_tf.tf_esp = USTACKTOP; e->env_tf.tf_cs = GD_UT | 3; // You will set e->env_tf.tf_eip later. // commit the allocation LIST_REMOVE(e, env_link); *newenv_store = e; cprintf("[%08x] new env %08x\n", curenv ? curenv->env_id : 0, e->env_id); return 0; }
// // Allocates and initializes a new environment. // On success, the new environment is stored in *newenv_store. // // Returns 0 on success, < 0 on failure. Errors include: // -E_NO_FREE_ENV if all NENVS environments are allocated // -E_NO_MEM on memory exhaustion // int env_alloc(struct Env **newenv_store, envid_t parent_id) { int32_t generation; int r; struct Env *e = env_free_list; if (!e) return -E_NO_FREE_ENV; // Allocate and set up the page directory for this environment. if ((r = env_mem_init(e)) < 0) return r; // Generate an env_id for this environment. generation = (e->env_id + (1 << ENVGENSHIFT)) & ~(NENV - 1); if (generation <= 0) // Don't create a negative env_id. generation = 1 << ENVGENSHIFT; e->env_id = generation | (e - envs); // Set the basic status variables. e->env_parent_id = parent_id; e->env_status = ENV_RUNNABLE; e->env_runs = 0; e->env_priority = 10; // Clear out all the saved register state, // to prevent the register values // of a prior environment inhabiting this Env structure // from "leaking" into our new environment. memset(&e->env_tf, 0, sizeof(e->env_tf)); // Set up appropriate initial values for the segment registers. // GD_UD is the user data segment selector in the GDT, and // GD_UT is the user text segment selector (see inc/memlayout.h). // The low 2 bits of each segment register contains the // Requestor Privilege Level (RPL); 3 means user mode. e->env_tf.tf_ds = GD_UD | 3; e->env_tf.tf_es = GD_UD | 3; e->env_tf.tf_ss = GD_UD | 3; e->env_tf.tf_esp = USTACKTOP; e->env_tf.tf_cs = GD_UT | 3; e->env_tf.tf_eflags |= FL_IF; // You will set e->env_tf.tf_eip later. // Enable interrupts while in user mode. // LAB 4: Your code here. // Clear the page fault handler until user installs one. e->env_pgfault_upcall = 0; // Also clear the IPC receiving flag. e->env_ipc_recving = 0; // If this is the buffer cache server (env_id == ENVID_BUFCACHE) // give it I/O privileges. // LAB 5: Your code here. if (e->env_id == ENVID_BUFCACHE) e->env_tf.tf_eflags |= FL_IOPL_3; // commit the allocation env_free_list = e->env_link; *newenv_store = e; cprintf("[%08x] new env %08x\n", curenv ? curenv->env_id : 0, e->env_id); return 0; }