time_t time() { spinlockAcquire(&timeLock); time_t out = currentTime + (time_t) (getUptime()-timeUpdateStamp)/1000; spinlockRelease(&timeLock); return out; };
MODULE_INIT() { kprintf("isofs: registering the ISO filesystem\n"); spinlockRelease(&isoMountLock); registerFSDriver(&isoDriver); return 0; };
void initPhysMem(uint64_t numPages, MultibootMemoryMap *mmap, uint64_t mmapEnd) { frameStackPointer = 0; nextFrame = 0x400; numSystemFrames = numPages; while ((uint64_t)mmap < mmapEnd) { if (isUseableMemory(mmap)) { if (isFrameInArea(mmap, 0x400)) { break; }; }; mmap = (MultibootMemoryMap*) ((uint64_t) mmap + mmap->size + 4); }; if ((uint64_t)mmap >= mmapEnd) { panic("no RAM addresses detected!"); }; memoryMap = mmap; memoryMapEnd = mmapEnd; spinlockRelease(&physmemLock); };
int canSched(Thread *thread) { if (thread->wakeTime != 0) { uint64_t currentTime = (uint64_t) getTicks(); //if (thread->pid == 1) //{ // kprintf("process %d, wakeTime=%d, now=%d\n", (int) thread->pid, (int) thread->wakeTime, (int) currentTime); //}; //kprintf("TIME: %d; WAKEY: %d, FLAGS: %a\n", currentTime, thread->wakeTime, getFlagsRegister()); if (currentTime >= thread->wakeTime) { //kprintf("WAKING UP\n"); thread->wakeTime = 0; thread->flags &= ~THREAD_WAITING; }; }; if (thread->flags & THREAD_NOSCHED) return 0; #if 0 if (thread->pm != NULL) { if (spinlockTry(&thread->pm->lock)) { return 0; }; spinlockRelease(&thread->pm->lock); }; #endif return 1; };
uint64_t phmAllocFrame() { spinlockAcquire(&physmemLock); uint64_t out; if (frameStackPointer == 0) { uint64_t mmapStartFrame = memoryMap->baseAddr / 0x1000; uint64_t mmapNumFrames = memoryMap->len / 0x1000; uint64_t mmapEndFrame = mmapStartFrame + mmapNumFrames; if (mmapEndFrame == nextFrame) { loadNextMemory(); }; out = nextFrame; nextFrame++; } else { out = frameStack[--frameStackPointer]; }; spinlockRelease(&physmemLock); return out; };
void phmFreeFrame(uint64_t frame) { if (frame < 0x200) panic("attempted to free frame %d (below 2MB)", frame); spinlockAcquire(&physmemLock); frameStack[frameStackPointer++] = frame; spinlockRelease(&physmemLock); };
void initRTC() { spinlockRelease(&timeLock); KernelThreadParams rtcPars; memset(&rtcPars, 0, sizeof(KernelThreadParams)); rtcPars.stackSize = 0x4000; rtcPars.name = "RTC reader daemon"; CreateKernelThread(rtcThread, &rtcPars, NULL); };
void ipreasmInit() { spinlockRelease(&reasmLock); KernelThreadParams params; memset(¶ms, 0, sizeof(KernelThreadParams)); params.stackSize = DEFAULT_STACK_SIZE; params.name = "IP Reassembler"; params.flags = THREAD_WAITING; reasmHandle = CreateKernelThread(ipreasmThread, ¶ms, NULL); };
MODULE_FINI() { spinlockAcquire(&isoMountLock); if (isoMountCount > 0) { spinlockRelease(&isoMountLock); return 1; }; return 0; };
void DeleteDevice(Device ptr) { spinlockAcquire(&devfsLock); DeviceFile *dev = (DeviceFile*) ptr; if (dev->prev != NULL) dev->prev->next = dev->next; if (dev->next != NULL) dev->next->prev = dev->prev; if (dev->data != NULL) kfree(dev->data); spinlockRelease(&devfsLock); kfree(dev); };
static void rtcThread(void *data) { uint8_t second, minute, hour, day, month, year=0; uint8_t lastSecond, lastMinute, lastHour, lastDay, lastMonth, lastYear; uint8_t registerB; while (1) { do { lastYear = year; lastMonth = month; lastDay = day; lastHour = hour; lastMinute = minute; lastSecond = second; while (getUpdateInProgress()); second = getRTCRegister(0); minute = getRTCRegister(2); hour = getRTCRegister(4); day = getRTCRegister(7); month = getRTCRegister(8); year = getRTCRegister(9); } while ((second != lastSecond) || (minute != lastMinute) || (hour != lastHour) || (month != lastMonth) || (year != lastYear) || (day != lastDay)); registerB = getRTCRegister(0x0B); if (!(registerB & 0x04)) { second = (second & 0xF) + (second / 16) * 10; minute = (minute & 0xF) + (minute / 16) * 10; hour = ( (hour & 0x0F) + (((hour & 0x70) / 16) * 10) ) | (hour & 0x80); day = (day & 0xF) + (day / 16) * 10; month = (month & 0xF) + (month / 16) * 10; year = (year & 0xF) + (year / 16) * 10; }; if (!(registerB & 0x02) && (hour & 0x80)) { hour = ((hour & 0x7F) + 12) % 24; }; spinlockAcquire(&timeLock); currentTime = makeUnixTime(2000+year, month, day, hour, minute, second); timeUpdateStamp = getUptime(); spinlockRelease(&timeLock); sleep(RTC_UPDATE_INTERVAL); }; };
void initDevfs() { spinlockRelease(&devfsLock); devfs = (FileSystem*) kmalloc(sizeof(FileSystem)); memset(devfs, 0, sizeof(FileSystem)); devfs->fsname = "devfs"; devfs->openroot = openroot; strcpy(nullDevice.name, "null"); nullDevice.data = NULL; nullDevice.open = openNullDevice; nullDevice.prev = NULL; nullDevice.next = NULL; };
void switchTask(Regs *regs) { ASM("sti"); if (currentThread == NULL) { apic->timerInitCount = quantumTicks; return; }; if (spinlockTry(&schedLock)) { //kprintf_debug("WARNING: SCHED LOCKED\n"); apic->timerInitCount = quantumTicks; return; }; __sync_fetch_and_add(&switchTaskCounter, 1); // remember the context of this thread. fpuSave(¤tThread->fpuRegs); memcpy(¤tThread->regs, regs, sizeof(Regs)); // get the next thread do { currentThread = currentThread->next; } while (!canSched(currentThread)); // if there are signals waiting, and not currently being handled, then handle them. if (((currentThread->flags & THREAD_SIGNALLED) == 0) && (currentThread->sigcnt != 0)) { // if the syscall is interruptable, do the switch-back. if (currentThread->flags & THREAD_INT_SYSCALL) { //kprintf_debug("signal in queue, THREAD_INT_SYSCALL ok\n"); memcpy(¤tThread->regs, ¤tThread->intSyscallRegs, sizeof(Regs)); *((int64_t*)¤tThread->regs.rax) = -1; currentThread->therrno = EINTR; }; // i've found that catching signals in kernel mode is a bad idea if ((currentThread->regs.cs & 3) == 3) { dispatchSignal(currentThread); }; }; spinlockRelease(&schedLock); jumpToTask(); };
int sys_pipe(int *pipefd) { int rfd=-1, wfd=-1; FileTable *ftab = getCurrentThread()->ftab; spinlockAcquire(&ftab->spinlock); int i; for (i=0; i<MAX_OPEN_FILES; i++) { if (ftab->entries[i] == NULL) { if (rfd == -1) { rfd = i; } else if (wfd == -1) { wfd = i; break; }; }; }; if ((rfd == -1) || (wfd == -1)) { getCurrentThread()->therrno = EMFILE; return -1; }; Pipe *pipe = (Pipe*) kmalloc(sizeof(Pipe)); semInit(&pipe->sem); pipe->readcount = 0; pipe->writecount = 0; pipe->offRead = 0; pipe->offWrite = 0; pipe->size = 0; ftab->entries[rfd] = openPipe(pipe, O_RDONLY); ftab->entries[wfd] = openPipe(pipe, O_WRONLY); pipefd[0] = rfd; pipefd[1] = wfd; spinlockRelease(&ftab->spinlock); return 0; };
static int iso_unmount(FileSystem *fs) { ISOFileSystem *isofs = (ISOFileSystem*) fs->fsdata; semWait(&isofs->sem); if (isofs->numOpenInodes != 0) { kprintf_debug("isofs: cannot unmount because %d inodes are open\n", isofs->numOpenInodes); semSignal(&isofs->sem); return -1; }; vfsClose(isofs->fp); kfree(isofs); spinlockAcquire(&isoMountLock); isoMountCount--; spinlockRelease(&isoMountLock); return 0; };
Device AddDevice(const char *name, void *data, int (*open)(void*, File*, size_t), int flags) { if (strlen(name) > 15) { return NULL; }; DeviceFile *dev = (DeviceFile*) kmalloc(sizeof(DeviceFile)); strcpy(dev->name, name); dev->data = data; dev->open = open; dev->prev = NULL; dev->next = NULL; spinlockAcquire(&devfsLock); DeviceFile *last = &nullDevice; while (last->next != NULL) last = last->next; last->next = dev; dev->prev = last; spinlockRelease(&devfsLock); return dev; };
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; };
int threadClone(Regs *regs, int flags, MachineState *state) { Thread *thread = (Thread*) kmalloc(sizeof(Thread)); fpuSave(&thread->fpuRegs); memcpy(&thread->regs, regs, sizeof(Regs)); thread->regs.rax = 0; if (state != NULL) { memcpy(&thread->fpuRegs, &state->fpuRegs, 512); thread->regs.rdi = state->rdi; thread->regs.rsi = state->rsi; thread->regs.rbp = state->rbp; thread->regs.rbx = state->rbx; thread->regs.rdx = state->rdx; thread->regs.rcx = state->rcx; thread->regs.rax = state->rax; thread->regs.r8 = state->r8 ; thread->regs.r9 = state->r9 ; thread->regs.r10 = state->r10; thread->regs.r11 = state->r11; thread->regs.r12 = state->r12; thread->regs.r13 = state->r13; thread->regs.r14 = state->r14; thread->regs.r15 = state->r15; thread->regs.rip = state->rip; thread->regs.rsp = state->rsp; }; // kernel stack thread->stack = kmalloc(DEFAULT_STACK_SIZE); thread->stackSize = DEFAULT_STACK_SIZE; strcpy(thread->name, currentThread->name); thread->flags = 0; // process memory if (flags & CLONE_SHARE_MEMORY) { UprefProcessMemory(currentThread->pm); thread->pm = currentThread->pm; } else { if (currentThread->pm != NULL) { thread->pm = DuplicateProcessMemory(currentThread->pm); } else { thread->pm = CreateProcessMemory(); }; }; // assign pid spinlockAcquire(&schedLock); thread->pid = nextPid++; spinlockRelease(&schedLock); // remember parent pid thread->pidParent = currentThread->pid; // file table if (flags & CLONE_SHARE_FTAB) { ftabUpref(currentThread->ftab); thread->ftab = currentThread->ftab; } else { if (currentThread->ftab != NULL) { thread->ftab = ftabDup(currentThread->ftab); } else { thread->ftab = ftabCreate(); }; }; // inherit UIDs/GIDs from the parent thread->euid = currentThread->euid; thread->suid = currentThread->suid; thread->ruid = currentThread->ruid; thread->egid = currentThread->egid; thread->sgid = currentThread->sgid; thread->rgid = currentThread->rgid; // inherit the working directory strcpy(thread->cwd, currentThread->cwd); // duplicate the executable description. if (currentThread->fpexec == NULL) { thread->fpexec = NULL; } else { File *fpexec = (File*) kmalloc(sizeof(File)); memset(fpexec, 0, sizeof(File)); currentThread->fpexec->dup(currentThread->fpexec, fpexec, sizeof(File)); thread->fpexec = fpexec; }; // inherit the root signal handler thread->rootSigHandler = currentThread->rootSigHandler; // empty signal queue thread->sigput = 0; thread->sigfetch = 0; thread->sigcnt = 0; // exec params if (currentThread->pid != 0) { thread->execPars = (char*) kmalloc(currentThread->szExecPars); memcpy(thread->execPars, currentThread->execPars, currentThread->szExecPars); thread->szExecPars = currentThread->szExecPars; } else { thread->execPars = NULL; thread->szExecPars = 0; }; thread->therrno = 0; thread->wakeTime = 0; thread->umask = 0; memcpy(thread->groups, currentThread->groups, sizeof(gid_t)*16); thread->numGroups = currentThread->numGroups; // if the address space is shared, the errnoptr is now invalid; // otherwise, it can just stay where it is. if (flags & CLONE_SHARE_MEMORY) { thread->errnoptr = NULL; } else { thread->errnoptr = currentThread->errnoptr; }; // link into the runqueue spinlockAcquire(&schedLock); currentThread->next->prev = thread; thread->next = currentThread->next; thread->prev = currentThread; currentThread->next = thread; spinlockRelease(&schedLock); return thread->pid; };
Thread* CreateKernelThread(KernelThreadEntry entry, KernelThreadParams *params, void *data) { // params uint64_t stackSize = DEFAULT_STACK_SIZE; if (params != NULL) { if (params->stackSize != 0) stackSize = params->stackSize; }; const char *name = "Nameless thread"; if (params != NULL) { if (params->name != NULL) name = params->name; }; int threadFlags = 0; if (params != NULL) { threadFlags = params->flags; }; // allocate and fill in the thread structure Thread *thread = (Thread*) kmalloc(sizeof(Thread)); thread->stack = kmalloc(stackSize); thread->stackSize = stackSize; memset(&thread->fpuRegs, 0, 512); memset(&thread->regs, 0, sizeof(Regs)); thread->regs.rip = (uint64_t) entry; thread->regs.rsp = ((uint64_t) thread->stack + thread->stackSize - 8) & ~0xF; // -8 because we'll push the return address... thread->regs.cs = 8; thread->regs.ds = 16; thread->regs.ss = 0; thread->regs.rflags = getFlagsRegister() | (1 << 9); // enable interrupts in that thread strcpy(thread->name, name); thread->flags = threadFlags; thread->pm = NULL; thread->pid = 0; thread->pidParent = 0; thread->ftab = NULL; thread->rootSigHandler = 0; thread->sigput = 0; thread->sigfetch = 0; thread->sigcnt = 0; // kernel threads always run as root thread->euid = 0; thread->suid = 0; thread->ruid = 0; thread->egid = 0; thread->sgid = 0; thread->rgid = 0; // start all kernel threads in "/initrd" strcpy(thread->cwd, "/initrd"); // no executable attached thread->fpexec = NULL; // no errnoptr thread->errnoptr = NULL; // do not wake thread->wakeTime = 0; // no umask thread->umask = 0; // this will simulate a call from kernelThreadExit() to "entry()" // this is so that when entry() returns, the thread can safely exit. thread->regs.rdi = (uint64_t) data; *((uint64_t*)thread->regs.rsp) = (uint64_t) &kernelThreadExit; // link into the runqueue spinlockAcquire(&schedLock); currentThread->next->prev = thread; thread->next = currentThread->next; thread->prev = currentThread; currentThread->next = thread; // there is no need to update currentThread->prev, it will only be broken for the init // thread, which never exits, and therefore its prev will never need to be valid. spinlockRelease(&schedLock); return thread; };
static void close(Dir *dir) { spinlockRelease(&devfsLock); };
void unlockSched() { spinlockRelease(&schedLock); };
void initSched() { nextPid = 1; spinlockRelease(&schedLock); // create a new stack for this initial process firstThread.stack = kmalloc(DEFAULT_STACK_SIZE); firstThread.stackSize = DEFAULT_STACK_SIZE; // the value of registers do not matter except RSP and RIP, // also the startup function should never return. memset(&firstThread.fpuRegs, 0, 512); memset(&firstThread.regs, 0, sizeof(Regs)); firstThread.regs.rip = (uint64_t) &startupThread; firstThread.regs.rsp = (uint64_t) firstThread.stack + firstThread.stackSize; firstThread.regs.cs = 8; firstThread.regs.ds = 16; firstThread.regs.ss = 0; firstThread.regs.rflags = getFlagsRegister() | (1 << 9); // enable interrupts // other stuff strcpy(firstThread.name, "Startup thread"); firstThread.flags = 0; firstThread.pm = NULL; firstThread.pid = 0; firstThread.ftab = NULL; firstThread.rootSigHandler = 0; firstThread.sigput = 0; firstThread.sigfetch = 0; firstThread.sigcnt = 0; // UID/GID stuff firstThread.euid = 0; firstThread.suid = 0; firstThread.ruid = 0; firstThread.egid = 0; firstThread.sgid = 0; firstThread.rgid = 0; // set the working directory to /initrd by default. strcpy(firstThread.cwd, "/initrd"); // no executable firstThread.fpexec = NULL; // no error ptr firstThread.errnoptr = NULL; // no wakeing firstThread.wakeTime = 0; // no umask firstThread.umask = 0; // no supplementary groups firstThread.numGroups = 0; // linking firstThread.prev = &firstThread; firstThread.next = &firstThread; // switch to this new thread's context currentThread = &firstThread; apic->timerInitCount = quantumTicks; switchContext(&firstThread.regs); };
static void ipreasmThread(void *ignore) { // notice that we start in the waiting state, so as soon as we wake up, // scan the lists while (1) { spinlockAcquire(&reasmLock); //kprintf("REASSEMBLER TRIGGERED\n"); if (firstFragList == NULL) { ASM("cli"); reasmHandle->wakeTime = 0; reasmHandle->flags |= THREAD_WAITING; kyield(); }; IPFragmentList *list = firstFragList; int earliestDeadline = firstFragList->deadlineTicks; reasmHandle->wakeTime = 0; while (list != NULL) { if (getTicks() >= list->deadlineTicks) { // passed the deadline, just delete all fragments kprintf_debug("DEADLINE PASSED!\n"); IPFragment *frag = list->fragList; while (frag != NULL) { kprintf("FRAGMENT: offset=%d, size=%d, last=%d\n", (int) frag->fragOffset, (int) frag->fragSize, frag->lastFragment); IPFragment *next = frag->next; kfree(frag); frag = next; }; if (list == firstFragList) { firstFragList = list->next; }; if (list == lastFragList) { lastFragList = list->prev; }; if (list->prev != NULL) list->prev->next = list->next; if (list->next != NULL) list->next->prev = list->prev; IPFragmentList *nextList = list->next; kfree(list); list = nextList; } else { if (isFragmentListComplete(list)) { size_t packetSize = calculatePacketSize(list); char *buffer = (char*) kmalloc(packetSize); IPFragment *frag = list->fragList; while (frag != NULL) { memcpy(&buffer[frag->fragOffset], frag->data, frag->fragSize); IPFragment *next = frag->next; kfree(frag); frag = next; }; if (list->family == AF_INET) { struct sockaddr_in src; memset(&src, 0, sizeof(struct sockaddr_in)); src.sin_family = AF_INET; memcpy(&src.sin_addr, list->srcaddr, 4); struct sockaddr_in dest; memset(&dest, 0, sizeof(struct sockaddr_in)); dest.sin_family = AF_INET; memcpy(&dest.sin_addr, list->dstaddr, 4); onTransportPacket((struct sockaddr*)&src, (struct sockaddr*)&dest, sizeof(struct sockaddr_in), buffer, packetSize, list->proto); } else { struct sockaddr_in6 src; memset(&src, 0, sizeof(struct sockaddr_in6)); src.sin6_family = AF_INET6; memcpy(&src.sin6_addr, list->srcaddr, 16); struct sockaddr_in6 dest; memset(&dest, 0, sizeof(struct sockaddr_in6)); dest.sin6_family = AF_INET6; memcpy(&dest.sin6_addr, list->dstaddr, 16); onTransportPacket((struct sockaddr*) &src, (struct sockaddr*) &dest, sizeof(struct sockaddr_in6), buffer, packetSize, list->proto); }; if (list == firstFragList) { firstFragList = list->next; }; if (list == lastFragList) { lastFragList = list->prev; }; if (list->prev != NULL) list->prev->next = list->next; if (list->next != NULL) list->next->prev = list->prev; IPFragmentList *nextList = list->next; kfree(list); list = nextList; kprintf_debug("IPREASM: reassembled fragmented packet of size %d\n", (int) packetSize); kfree(buffer); } else { if (list->deadlineTicks < earliestDeadline) { earliestDeadline = list->deadlineTicks; }; list = list->next; }; }; }; ASM("cli"); reasmHandle->wakeTime = earliestDeadline; reasmHandle->flags |= THREAD_WAITING; spinlockRelease(&reasmLock); kyield(); }; };
void ipreasmPass(int family, char *srcaddr, char *dstaddr, int proto, uint32_t id, uint32_t fragOff, char *data, size_t fragSize, int moreFrags) { spinlockAcquire(&reasmLock); int found = 0; IPFragmentList *list; for (list=firstFragList; list!=NULL; list=list->next) { if (isMatchingFragmentList(list, family, srcaddr, dstaddr, id)) { if (list->proto != proto) { // ignore this packet because it's faulty kprintf_debug("OVERLAP\n"); spinlockRelease(&reasmLock); return; }; // see if this fragment is supposed to come before any that have so far arrived if (list->fragList->fragOffset > fragOff) { if (fragOff+fragSize > list->fragList->fragOffset) { // overlaps, reject kprintf_debug("OVERLAP\n"); spinlockRelease(&reasmLock); return; }; IPFragment *frag = NEW_EX(IPFragment, fragSize); frag->lastFragment = !moreFrags; frag->fragOffset = fragOff; frag->fragSize = fragSize; frag->prev = NULL; list->fragList->prev = frag; frag->next = list->fragList; memcpy(frag->data, data, fragSize); list->fragList = frag; } else { //kprintf_debug("here though\n"); // find where to place this fragment IPFragment *scan = list->fragList; while (scan != NULL) { if (scan->fragOffset == fragOff) { // duplicate; reject kprintf_debug("OVERLAP\n"); spinlockRelease(&reasmLock); return; }; int doit = 0; if (scan->next == NULL) { if (fragOff > scan->fragOffset) { if (scan->fragOffset+scan->fragSize > fragOff) { // overlaps kprintf_debug("OVERLAP\n"); spinlockRelease(&reasmLock); return; }; doit = 1; }; } else { if ((scan->fragOffset < fragOff) && (scan->next->fragOffset > fragOff)) { // reject this packet if it is overlapping if (scan->fragOffset+scan->fragSize > fragOff) { // overlaps previous fragment kprintf_debug("OVERLAP\n"); spinlockRelease(&reasmLock); return; }; if (fragOff+fragSize > scan->next->fragOffset) { // overlaps next fragment kprintf_debug("OVERLAP\n"); spinlockRelease(&reasmLock); return; }; doit = 1; }; }; if (doit) { // OK, we can finally place the fragment IPFragment *frag = NEW_EX(IPFragment, fragSize); frag->lastFragment = !moreFrags; frag->fragOffset = fragOff; frag->fragSize = fragSize; frag->prev = scan; frag->next = scan->next; if (scan->next != NULL) scan->next->prev = frag; scan->next = frag; memcpy(frag->data, data, fragSize); break; } else { scan = scan->next; }; }; }; found = 1; }; }; if (!found) { // create a new fragment list IPFragment *frag = NEW_EX(IPFragment, fragSize); frag->lastFragment = !moreFrags; frag->fragOffset = fragOff; frag->fragSize = fragSize; frag->prev = frag->next = NULL; memcpy(frag->data, data, fragSize); IPFragmentList *list = NEW(IPFragmentList); list->family = family; list->deadlineTicks = getTicks() + 60000; // deadline after 60 seconds memcpy(list->srcaddr, srcaddr, 16); memcpy(list->dstaddr, dstaddr, 16); list->id = id; list->proto = proto; list->fragList = frag; if (firstFragList == NULL) { firstFragList = lastFragList = list; list->prev = list->next = NULL; } else { lastFragList->next = list; list->next = NULL; list->prev = lastFragList; lastFragList = list; }; }; signalThread(reasmHandle); spinlockRelease(&reasmLock); };
static int isoMount(const char *image, FileSystem *fs, size_t szfs) { spinlockAcquire(&isoMountLock); int error; File *fp = vfsOpen(image, 0, &error); if (fp == NULL) { spinlockRelease(&isoMountLock); kprintf_debug("isofs: could not open %s\n", image); return -1; }; if (fp->seek == NULL) { spinlockRelease(&isoMountLock); kprintf_debug("isofs: %s cannot seek\n", image); vfsClose(fp); return -1; }; fp->seek(fp, 0x8000, SEEK_SET); ISOPrimaryVolumeDescriptor primary; if (vfsRead(fp, &primary, sizeof(ISOPrimaryVolumeDescriptor)) != sizeof(ISOPrimaryVolumeDescriptor)) { spinlockRelease(&isoMountLock); kprintf_debug("isofs: cannot read the whole ISOPrimaryVolumeDescriptor (EOF)\n"); vfsClose(fp); return -1; }; if (!checkPVD(&primary)) { spinlockRelease(&isoMountLock); kprintf_debug("isofs: the Primary Volume Descriptor is invalid\n"); vfsClose(fp); return -1; }; kprintf_debug("isofs: PVD validated\n"); ISOFileSystem *isofs = (ISOFileSystem*) kmalloc(sizeof(ISOFileSystem)); isofs->fp = fp; semInit(&isofs->sem); ISODirentHeader *rootDir = (ISODirentHeader*) &primary.rootDir; isofs->rootStart = (uint64_t)rootDir->startLBA * (uint64_t)primary.blockSize; isofs->rootEnd = isofs->rootStart + (uint64_t)rootDir->fileSize; isofs->blockSize = (uint64_t)primary.blockSize; isofs->numOpenInodes = 0; kprintf_debug("isofs: root directory start LBA is %a, block size is %d\n", rootDir->startLBA, primary.blockSize); fs->fsdata = isofs; fs->fsname = "isofs"; fs->openroot = iso_openroot; fs->unmount = iso_unmount; isoMountCount++; spinlockRelease(&isoMountLock); return 0; };