Пример #1
0
void thread_free(struct thread *thread) {
	uintptr_t i;

	/* free FPU/SSE data */
	if (thread->fxdata) {
		heap_free(thread->fxdata, 512);
		thread->fxdata = NULL;
	}

	/* remove thread from scheduler */
	schedule_remove(thread);

	/* free message packet if it exists */
	if (thread->msg) {
		
		/* free packet contents */
		for (i = 0; i < thread->msg->count; i++) {
			frame_free(thread->msg->frame[i]);
		}

		/* free the message packet structure */
		heap_free(thread->msg->frame, thread->msg->count * sizeof(uint32_t));
		heap_free(thread->msg, sizeof(struct msg));

	}

	/* free thread local storage if it exists */
	if (thread->stack) {
		i = (thread->stack - SSPACE) / SEGSZ;

		thread->proc->thread[i] = NULL;

		space_exmap(thread->proc->space);
	
		for (i = thread->stack; i < thread->stack + SEGSZ; i += PAGESZ) {
			if ((page_exget(i) & PF_PRES) != 0) {
				frame_free(page_ufmt(page_exget(i)));
				page_exset(i, 0);
			}
		}
	}

	/* free thread structure */
	heap_free(thread, sizeof(struct thread));
}
Пример #2
0
void kcall(struct thread *image) {

	if (image->flags & TF_USER) {
		// perform syscall

		// save user state
		image->usr_eip = image->eip;
		image->usr_esp = image->useresp;

		// switch to system mode
		image->ss = 0x21;
		image->ds = 0x21;
		image->cs = 0x19;
		image->flags &= ~TF_USER;

		// restore system state
		image->eip = image->sys_eip;
		image->useresp = image->sys_esp;		

		return;
	}

	switch (image->eax) {

	case KCALL_SPAWN: {

		int id = thread_new();
		if (id == -1) {
			// failure to create new thread
			image->eax = -1;
			break;
		}

		struct thread *thread = thread_get(id);
		struct t_info *state = (void*) image->ebx;

		// initialize thread state
		thread->useresp = state->regs.esp;
		thread->esp     = (uintptr_t) &thread->num;
		thread->ss      = 0x21;
		thread->ds      = 0x21;
		thread->cs      = 0x19;
		thread->eflags  = image->eflags;
		thread->eip     = state->regs.eip;
		thread->ebp     = state->regs.ebp;
		thread->esi     = state->regs.esi;
		thread->edi     = state->regs.edi;
		thread->edx     = state->regs.edx;
		thread->ecx     = state->regs.ecx;
		thread->ebx     = state->regs.ebx;
		thread->eax     = state->regs.eax;

		// add to scheduler queue
		thread->state = TS_QUEUED;
		schedule_push(thread);

		image->eax = id;
		break;
	}

	case KCALL_REAP: {

		struct thread *target = thread_get(image->ebx);

		if (target->state != TS_PAUSED) {
			image->eax = TE_STATE;
		}
		else {

			if (image->ecx) {
				save_info((void*) image->ecx, target);
			}

			image->eax = 0;
			thread_kill(target);
		}

		break;
	}

	case KCALL_GETTID: {

		image->eax = image->id;

		break;
	}

	case KCALL_YIELD: {
		
		thread_save(image);
		schedule_push(image);
		image->state = TS_QUEUED;

		break;
	}

	case KCALL_PAUSE: {

		struct thread *target = thread_get(image->ebx);
		if (image->ebx == (uint32_t) -1) target = image;

		if (!target) {
			image->eax = TE_EXIST;
		}
		else switch (target->state) {
		case TS_RUNNING:

			// pause (normal, from running)
			thread_save(target);
			target->state = TS_PAUSED;
			
			image->eax = 0;
			break;

		case TS_QUEUED:

			// pause (normal, from queued)
			schedule_remv(target);
			target->state = TS_PAUSED;

			image->eax = 0;
			break;

		case TS_WAITING:

			// pause (waiting)
			event_remv(target->id, target->event);
			target->state = TS_PAUSEDW;

			image->eax = 0;
			break;

		default:

			// invalid state transition
			image->eax = TE_STATE;
			break;
		}

		break;
	}

	case KCALL_RESUME: {

		struct thread *target = thread_get(image->ebx);
		if (!target) {
			image->eax = TE_EXIST;
		}
		else switch (target->state) {
		case TS_PAUSED:

			// resume thread by scheduling
			schedule_push(target);
			target->state = TS_QUEUED;

			image->eax = 0;
			break;

		case TS_PAUSEDW:

			// resume thread by entering wait queue
			event_wait(target->id, target->event);
			target->state = TS_WAITING;

			image->eax = 0;
			break;

		default:

			image->eax = TE_STATE;
			break;
		}

		break;
	}

	case KCALL_GETSTATE: {

		struct thread *target = thread_get(image->ebx);
		if (image->ebx == (uint32_t) -1) target = image;

		if (!target) {
			image->eax = TE_EXIST;
		}
		else if (target->state != TS_PAUSED && target->state != TS_PAUSEDW && target != image) {
			image->eax = TE_STATE;
		}
		else {
			save_info((void*) image->ecx, target);
			image->eax = 0;
		}
		
		break;
	}

	case KCALL_SETSTATE: {

		struct thread *target = thread_get(image->ebx);
		if (image->ebx == (uint32_t) -1) target = image;

		if (!target) {
			image->eax = TE_EXIST;
		}
		else switch (target->state) {
		case TS_PAUSED:
		case TS_PAUSEDW:
		case TS_RUNNING: {

			struct t_info *src = (void*) image->ecx;

			if (src->flags & TF_DEAD) {

				// kill thread
				if (target->state == TS_RUNNING) {
					thread_save(target);
					target->state = TS_PAUSED;
				}

				// notify reaper
				dead_push(target);
			}

			if (target->pctx != src->pctx) {

				// change paging contexts
				pctx_load(src->pctx);
			}

			// save thread state
			target->pctx  = src->pctx;
			target->flags = src->flags;
			target->fault = src->fault;

			if (target->state != TS_RUNNING) {

				// save register state
				target->edi = src->regs.edi;
				target->esi = src->regs.esi;
				target->ebp = src->regs.ebp;
				target->useresp = src->regs.esp;
				target->ebx = src->regs.ebx;
				target->edx = src->regs.edx;
				target->ecx = src->regs.ecx;
				target->eax = src->regs.eax;
				target->eip = src->regs.eip;
				target->eflags = src->regs.eflags;

				// save MMX/SSE state
				if (!target->fxdata) target->fxdata = heap_alloc(512);
				memcpy(target->fxdata, &src->regs.fxdata[0], 512);
			}

			target->usr_eip = src->usr_ip;
			target->usr_esp = src->usr_sp;

			image->eax = 0;
			break;
		}

		default:

			image->eax = TE_STATE;
			break;
		}

		break;
	}

	case KCALL_GETDEAD: {

		if (dead_peek()) {
			struct thread *dead = dead_pull();
			image->eax = dead->id;
		}
		else {
			thread_save(image);
			image->state = TS_PAUSED;

			dead_wait(image);
		}

		break;
	}

	case KCALL_GETFAULT: {

		if (fault_peek()) {
			struct thread *fault = fault_pull();
			image->eax = fault->id;
		}
		else {
			thread_save(image);
			image->state = TS_PAUSED;

			fault_wait(image);
		}

		break;
	}

	case KCALL_WAIT: {
		
		image->eax = event_wait(image->id, image->ebx);

		break;

	}

	case KCALL_RESET: {

		if (image->ebx < 240) {
			extern int irqstate[EV_COUNT];

			irqstate[image->ebx] = 0;
			irq_unmask(image->ebx);
		}

		image->eax = 0;

		break;
	}

	case KCALL_SYSRET: {

		// save system state
		image->sys_eip = image->eip;
		image->sys_esp = image->useresp;
		
		// perform return value swap-in
		image->eax = image->ebp;

		// switch to usermode
		image->ss = 0x33;
		image->ds = 0x33;
		image->cs = 0x2B;
		image->flags |= TF_USER;

		// restore user state
		image->eip = image->usr_eip;
		image->useresp = image->usr_esp;

		break;
	}

	case KCALL_NEWPCTX: {

		image->eax = pctx_new();

		break;
	}

	case KCALL_FREEPCTX: {

		image->eax = pctx_free(image->ebx);

		break;
	}


	case KCALL_SETFRAME: {

		page_set(image->ebx, page_fmt(image->ecx, page_get(image->ebx)));
		image->eax = 0;

		break;
	}

	case KCALL_SETFLAGS: {

		page_set(image->ebx, page_fmt(page_ufmt(page_get(image->ebx)), image->ecx));
		image->eax = 0;

		break;
	}

	case KCALL_GETFRAME: {

		uint32_t off  = image->ebx & 0xFFF;
		uint32_t page = image->ebx & ~0xFFF;
		image->eax = page_ufmt(page_get(page)) | off;

		break;
	}

	case KCALL_GETFLAGS: {

		image->eax = page_get(image->ebx) & PF_MASK;

		break;
	}

	case KCALL_NEWFRAME: {

		uint64_t frame = frame_new();
		image->eax = frame & 0xFFFFFFFF;
		image->ebx = frame >> 32ULL;

		break;
	}

	case KCALL_FREEFRAME: {

		frame_free(image->ebx);

		image->eax = 0;
		break;
	}

	case KCALL_TAKEFRAME: {
		
		image->eax = 1;
		break;
	}	

	default: {

		debug_printf("warning: unimplemented kcall %d\n", image->eax);
		image->eax = -1;

		break;
	}

	}
}