Exemplo n.º 1
0
void sleep(int ticks)
{
	if (getCurrentThread() == NULL)
	{
		// not ready to wait!
		uint64_t then = getUptime() + (uint64_t)ticks;
		while (getUptime() < then);
	}
	else
	{
		uint64_t then = getUptime() + (uint64_t)ticks;
		uint64_t nanoThen = then * (uint64_t)1000000;

		cli();
		lockSched();
		TimedEvent ev;
		timedPost(&ev, nanoThen);
		
		while (getNanotime() <= nanoThen)
		{
			waitThread(getCurrentThread());
			unlockSched();
			kyield();
			
			cli();
			lockSched();
		};
		
		timedCancel(&ev);
		unlockSched();
		sti();
	};
};
Exemplo n.º 2
0
void threadExit(Thread *thread, int status)
{
	if (thread->pid == 0)
	{
		panic("a kernel thread tried to threadExit()");
	};

	if (thread->pid == 1)
	{
		panic("init terminated with status %d!", status);
	};

	// don't break the CPU runqueue
	ASM("cli");
	lockSched();

	// init will adopt all orphans
	Thread *scan = thread;
	do
	{
		if (scan->pidParent == thread->pid)
		{
			scan->pidParent = 1;
		};
		scan = scan->next;
	} while (scan != thread);

	// terminate us
	thread->status = status;
	thread->flags |= THREAD_TERMINATED;

	// find the parent
	Thread *parent = thread;
	do
	{
		parent = parent->next;
	} while (parent->pid != thread->pidParent);

	// tell the parent that its child has died
	siginfo_t siginfo;
	siginfo.si_signo = SIGCHLD;
	if (status >= 0)
	{
		siginfo.si_code = CLD_EXITED;
	}
	else
	{
		siginfo.si_code = CLD_KILLED;
	};
	siginfo.si_pid = thread->pid;
	siginfo.si_status = status;
	siginfo.si_uid = thread->ruid;
	sendSignal(parent, &siginfo);
	unlockSched();
	ASM("sti");
};
Exemplo n.º 3
0
int signalPid(int pid, int signo)
{
	if (pid == currentThread->pid)
	{
		currentThread->therrno = EINVAL;
		return -1;
	};

	lockSched();
	Thread *thread = currentThread->next;

	while (thread != currentThread)
	{
		if (thread->pid == pid)
		{
			break;
		};
		thread = thread->next;
	};

	if (thread->flags & THREAD_TERMINATED)
	{
		currentThread->therrno = ESRCH;
		unlockSched();
		return -1;
	};

	if (thread == currentThread)
	{
		currentThread->therrno = ESRCH;
		unlockSched();
		return -1;
	};

	if (!canSendSignal(currentThread, thread, signo))
	{
		currentThread->therrno = EPERM;
		unlockSched();
		return -1;
	};

	siginfo_t si;
	si.si_signo = signo;
	if (signo != 0) sendSignal(thread, &si);

	unlockSched();
	return 0;
};
Exemplo n.º 4
0
static ssize_t termWrite(Inode *inode, File *file, const void *buffer, size_t size, off_t pos)
{
	if (getCurrentThread()->creds->pgid != termGroup)
	{
		cli();
		lockSched();
		siginfo_t si;
		si.si_signo = SIGTTOU;
		sendSignal(getCurrentThread(), &si);
		unlockSched();
		sti();
		ERRNO = ENOTTY;
		return -1;
	};

	kputbuf((const char*) buffer, size);
	return size;
};
Exemplo n.º 5
0
void onTick()
{
	lockSched();
	
	int doResched = 0;
	while (1)
	{
		if (timedEvents == NULL) break;
		if (getNanotime() <= timedEvents->nanotime) break;
		
		TimedEvent *ev = timedEvents;
		Thread *thread = ev->thread;
		timedEvents = ev->next;
		if (timedEvents != NULL) timedEvents->prev = NULL;
		ev->prev = ev->next = NULL;
		doResched = doResched || signalThread(thread);
	};
	
	unlockSched();
	if (doResched) kyield();
};
Exemplo n.º 6
0
static ssize_t termRead(Inode *inode, File *fp, void *buffer, size_t size, off_t pos)
{
	if (getCurrentThread()->creds->pgid != termGroup)
	{
		cli();
		lockSched();
		siginfo_t si;
		si.si_signo = SIGTTIN;
		sendSignal(getCurrentThread(), &si);
		unlockSched();
		sti();
		ERRNO = ENOTTY;
		return -1;
	};
	
	int count = semWaitGen(&semCount, (int) size, SEM_W_INTR, 0);
	if (count < 0)
	{
		ERRNO = -count;
		return -1;
	};

	semWait(&semInput);

	if (size > (size_t) count) size = (size_t) count;
	ssize_t out = 0;
	while (size > 0)
	{
		if (inputRead == INPUT_BUFFER_SIZE) inputRead = 0;
		size_t max = INPUT_BUFFER_SIZE - inputRead;
		if (max > size) max = size;
		memcpy(buffer, &inputBuffer[inputRead], max);
		size -= max;
		out += max;
		inputRead += max;
		buffer = (void*)((uint64_t)buffer + max);
	};
	semSignal(&semInput);
	return out;
};
Exemplo n.º 7
0
int elfExec(Regs *regs, const char *path, const char *pars, size_t parsz)
{
	//getCurrentThread()->therrno = ENOEXEC;

	vfsLockCreation();
	struct stat st;
	int error = vfsStat(path, &st);
	if (error != 0)
	{
		vfsUnlockCreation();
		return sysOpenErrno(error);
	};

	if (!vfsCanCurrentThread(&st, 1))
	{
		vfsUnlockCreation();
		getCurrentThread()->therrno = EPERM;
		return -1;
	};

	File *fp = vfsOpen(path, VFS_CHECK_ACCESS, &error);
	if (fp == NULL)
	{
		vfsUnlockCreation();
		return sysOpenErrno(error);
	};
	vfsUnlockCreation();

	if (fp->seek == NULL)
	{
		vfsClose(fp);
		getCurrentThread()->therrno = EIO;
		return -1;
	};

	if (fp->dup == NULL)
	{
		vfsClose(fp);
		getCurrentThread()->therrno = EIO;
		return -1;
	};

	Elf64_Ehdr elfHeader;
	if (vfsRead(fp, &elfHeader, sizeof(Elf64_Ehdr)) < sizeof(Elf64_Ehdr))
	{
		vfsClose(fp);
		getCurrentThread()->therrno = ENOEXEC;
		return -1;
	};

	if (memcmp(elfHeader.e_ident, "\x7f" "ELF", 4) != 0)
	{
		vfsClose(fp);
		getCurrentThread()->therrno = ENOEXEC;
		return -1;
	};

	if (elfHeader.e_ident[EI_CLASS] != ELFCLASS64)
	{
		vfsClose(fp);
		getCurrentThread()->therrno = ENOEXEC;
		return -1;
	};

	if (elfHeader.e_ident[EI_DATA] != ELFDATA2LSB)
	{
		vfsClose(fp);
		getCurrentThread()->therrno = ENOEXEC;
		return -1;
	};

	if (elfHeader.e_ident[EI_VERSION] != 1)
	{
		vfsClose(fp);
		getCurrentThread()->therrno = ENOEXEC;
		return -1;
	};

	if (elfHeader.e_type != ET_EXEC)
	{
		vfsClose(fp);
		getCurrentThread()->therrno = ENOEXEC;
		return -1;
	};

	if (elfHeader.e_phentsize < sizeof(Elf64_Phdr))
	{
		vfsClose(fp);
		getCurrentThread()->therrno = ENOEXEC;
		return -1;
	};

	ProgramSegment *segments = (ProgramSegment*) kmalloc(sizeof(ProgramSegment)*(elfHeader.e_phnum));
	memset(segments, 0, sizeof(ProgramSegment) * elfHeader.e_phnum);

	int interpNeeded = 0;
	Elf64_Dyn *dynamic;

	unsigned int i;
	for (i=0; i<elfHeader.e_phnum; i++)
	{
		fp->seek(fp, elfHeader.e_phoff + i * elfHeader.e_phentsize, SEEK_SET);
		Elf64_Phdr proghead;
		if (vfsRead(fp, &proghead, sizeof(Elf64_Phdr)) < sizeof(Elf64_Phdr))
		{
			kfree(segments);
			getCurrentThread()->therrno = ENOEXEC;
			return -1;
		};

		if (proghead.p_type == PT_PHDR)
		{
			continue;
		}
		else if (proghead.p_type == PT_NULL)
		{
			continue;
		}
		else if (proghead.p_type == PT_LOAD)
		{
			if (proghead.p_vaddr < 0x1000)
			{
				vfsClose(fp);
				kfree(segments);
				getCurrentThread()->therrno = ENOEXEC;
				return -1;
			};

			if ((proghead.p_vaddr+proghead.p_memsz) > 0x8000000000)
			{
				vfsClose(fp);
				kfree(segments);
				return -1;
			};

			uint64_t start = proghead.p_vaddr;
			segments[i].index = (start)/0x1000;

			uint64_t end = proghead.p_vaddr + proghead.p_memsz;
			uint64_t size = end - start;
			uint64_t numPages = ((start + size) / 0x1000) - segments[i].index + 1; 
			//if (size % 0x1000) numPages++;

			segments[i].count = (int) numPages;
			segments[i].fileOffset = proghead.p_offset;
			segments[i].memorySize = proghead.p_memsz;
			segments[i].fileSize = proghead.p_filesz;
			segments[i].loadAddr = proghead.p_vaddr;
			segments[i].flags = 0;

			if (proghead.p_flags & PF_R)
			{
				segments[i].flags |= PROT_READ;
			};

			if (proghead.p_flags & PF_W)
			{
				segments[i].flags |= PROT_WRITE;
			};

			if (proghead.p_flags & PF_X)
			{
				segments[i].flags |= PROT_EXEC;
			};
		}
		else if (proghead.p_type == PT_INTERP)
		{
			interpNeeded = 1;
		}
		else if (proghead.p_type == PT_DYNAMIC)
		{
			dynamic = (Elf64_Dyn*) proghead.p_vaddr;
		}
		else
		{
			kfree(segments);
			getCurrentThread()->therrno = ENOEXEC;
			return -1;
		};
	};

	// set the signal handler to default.
	getCurrentThread()->rootSigHandler = 0;

	// thread name
	strcpy(getCurrentThread()->name, path);

	// set the execPars
	Thread *thread = getCurrentThread();
	if (thread->execPars != NULL) kfree(thread->execPars);
	thread->execPars = (char*) kmalloc(parsz);
	thread->szExecPars = parsz;
	memcpy(thread->execPars, pars, parsz);

	// create a new address space
	ProcMem *pm = CreateProcessMemory();

	// switch the address space, so that AddSegment() can optimize mapping
	lockSched();
	ProcMem *oldPM = thread->pm;
	thread->pm = pm;
	unlockSched();
	SetProcessMemory(pm);
	DownrefProcessMemory(oldPM);

	// pass 1: allocate the frames and map them
	for (i=0; i<(elfHeader.e_phnum); i++)
	{
		if (segments[i].count > 0)
		{
			FrameList *fl = palloc_later(segments[i].count, segments[i].fileOffset, segments[i].fileSize);
			if (AddSegment(pm, segments[i].index, fl, segments[i].flags) != 0)
			{
				getCurrentThread()->therrno = ENOEXEC;
				pdownref(fl);
				DownrefProcessMemory(pm);
				break;
			};
			pdownref(fl);
		};
	};

	// change the fpexec
	if (thread->fpexec != NULL)
	{
		if (thread->fpexec->close != NULL) thread->fpexec->close(thread->fpexec);
		kfree(thread->fpexec);
	};
	thread->fpexec = fp;

	// make sure we jump to the entry upon return
	regs->rip = elfHeader.e_entry;

	// the errnoptr is now invalid
	thread->errnoptr = NULL;

	// close all files marked with O_CLOEXEC (on glidx a.k.a. FD_CLOEXEC)
	spinlockAcquire(&getCurrentThread()->ftab->spinlock);
	for (i=0; i<MAX_OPEN_FILES; i++)
	{
		File *fp = getCurrentThread()->ftab->entries[i];
		if (fp != NULL)
		{
			if (fp->oflag & O_CLOEXEC)
			{
				getCurrentThread()->ftab->entries[i] = NULL;
				vfsClose(fp);
			};
		};
	};
	spinlockRelease(&getCurrentThread()->ftab->spinlock);
	
	// suid/sgid stuff
	if (st.st_mode & VFS_MODE_SETUID)
	{
		thread->euid = st.st_uid;
		//thread->ruid = st.st_uid;
		//thread->suid = st.st_uid;
		thread->flags |= THREAD_REBEL;
	};

	if (st.st_mode & VFS_MODE_SETGID)
	{
		thread->egid = st.st_gid;
		//thread->rgid = st.st_gid;
		//thread->sgid = st.st_gid;
		thread->flags |= THREAD_REBEL;
	};

	if (interpNeeded)
	{
		linkInterp(regs, dynamic, pm);
	};

	return 0;
};
Exemplo n.º 8
0
int pollThread(Regs *regs, int pid, int *stat_loc, int flags)
{
	if (kernelStatus != KERNEL_RUNNING)
	{
		currentThread->therrno = EPERM;
		return -1;
	};

	int sigcnt = getCurrentThread()->sigcnt;

	lockSched();
	ASM("cli");
	Thread *threadToKill = NULL;
	Thread *thread = currentThread->next;
	while (thread != currentThread)
	{
		if (thread->pidParent == currentThread->pid)
		{
			if ((thread->pid == pid) || (pid == -1))
			{
				if (thread->flags & THREAD_TERMINATED)
				{
					threadToKill = thread;
					*stat_loc = thread->status;

					// unlink from the runqueue
					thread->prev->next = thread->next;
					thread->next->prev = thread->prev;

					break;
				};
			};
		};
		thread = thread->next;
	};

	// when WNOHANG is clear
	while ((threadToKill == NULL) && ((flags & WNOHANG) == 0))
	{
		//currentThread->flags |= THREAD_WAITING;
		//currentThread->therrno = ECHILD;
		//*((int*)&regs->rax) = -1;
		//switchTask(regs);
		getCurrentThread()->flags |= THREAD_WAITING;
		unlockSched();
		kyield();
		if (getCurrentThread()->sigcnt > sigcnt)
		{
			ERRNO = EINTR;
			return -1;
		};
		lockSched();
	};

	unlockSched();
	ASM("sti");

	// when WNOHANG is set
	if (threadToKill == NULL)
	{
		currentThread->therrno = ECHILD;
		return -1;
	};

	// there is a process ready to be deleted, it's already removed from the runqueue.
	kfree(thread->stack);
	DownrefProcessMemory(thread->pm);
	ftabDownref(thread->ftab);

	if (thread->fpexec != NULL)
	{
		if (thread->fpexec->close != NULL) thread->fpexec->close(thread->fpexec);
		kfree(thread->fpexec);
	};

	if (thread->execPars != NULL) kfree(thread->execPars);
	int ret = thread->pid;
	kfree(thread);

	return ret;
};
Exemplo n.º 9
0
int termIoctl(Inode *inode, File *fp, uint64_t cmd, void *argp)
{
	Thread *target = NULL;
	Thread *scan;
	int pgid;
	struct termios *tc = (struct termios*) argp;
	TermWinSize *winsz = (TermWinSize*) argp;
	
	switch (cmd)
	{
	case IOCTL_TTY_GETATTR:
		memcpy(tc, &termState, sizeof(struct termios));
		return 0;
	case IOCTL_TTY_SETATTR:
		termState.c_iflag = tc->c_iflag;
		termState.c_oflag = tc->c_oflag;
		termState.c_cflag = tc->c_cflag;
		termState.c_lflag = tc->c_lflag;
		return 0;
	case IOCTL_TTY_GETPGID:
		*((int*)argp) = termGroup;
		return 0;
	case IOCTL_TTY_SETPGID:
		if (getCurrentThread()->creds->sid != 1)
		{
			ERRNO = ENOTTY;
			return -1;
		};
		pgid = *((int*)argp);
		cli();
		lockSched();
		scan = getCurrentThread();
		do
		{
			if (scan->creds != NULL)
			{
				if (scan->creds->pgid == pgid)
				{
					target = scan;
					break;
				};
			};
			
			scan = scan->next;
		} while (scan != getCurrentThread());
		if (target == NULL)
		{
			unlockSched();
			sti();
			ERRNO = EPERM;
			return -1;
		};
		if (target->creds->sid != 1)
		{
			unlockSched();
			sti();
			ERRNO = EPERM;
			return -1;
		};
		unlockSched();
		sti();
		termGroup = pgid;
		return 0;
	case IOCTL_TTY_ISATTY:
		return 0;
	case IOCTL_TTY_GETSIZE:
		getConsoleSize(&winsz->ws_col, &winsz->ws_row);
		winsz->ws_xpixel = 0;
		winsz->ws_ypixel = 0;
		return 0;
	default:
		ERRNO = ENODEV;
		return -1;
	};
};