public static MemoryRegion AllocateRegion(USize size, AllocatePageOptions options = default) { var pages = KMath.DivCeil(size, 4096); var start = AllocatePages(pages, options); return(new MemoryRegion(start, pages * 4096)); }
private static unsafe int ReadResultDisk(int msgId, byte *buf, uint bufSize) { var lineType = ReadByte(); Assert.True(lineType == (byte)LineType.ResultFile); var msgId_ = ReadInt32(); Assert.True(msgId_ == msgId); var len = ReadInt32(); Assert.True(len <= bufSize); if (len <= 0) { return(0); } var blocks = KMath.DivCeil((uint)len, 512); var tmpBuf = new byte[blocks * 512]; SharedDisk.ReadBlock(0, blocks, tmpBuf); for (var i = 0; i < len; i++) { buf[i] = tmpBuf[i]; } RuntimeMemory.FreeObject(tmpBuf); return(len); }
public static MemoryRegion AllocateRegion(this IPageFrameAllocator allocator, USize size, AllocatePageOptions options = default) { var pages = KMath.DivCeil(size, 4096); var p = allocator.AllocatePages(pages, options); return(new MemoryRegion(allocator.GetAddress(p), pages * 4096)); }
private static uint Cmd_GetPhysicalMemory(SysCallContext *context, SystemMessage *args) { var physAddr = args->Arg1; var pages = KMath.DivCeil(args->Arg2, 4096); KernelMessage.WriteLine("Got Request for {0:X8} pages at Physical Addr {1:X8}", pages, physAddr); var proc = Scheduler.GetCurrentThread().Process; var virtAddr = proc.UserPageAllocator.AllocatePagesAddr(pages); proc.PageTable.Map(virtAddr, physAddr, pages * 4096); return(virtAddr); }
private static uint Cmd_RequestMessageBuffer(SysCallContext *context, SystemMessage *args) { var size = args->Arg1; var targetProcessID = (int)args->Arg2; var pages = KMath.DivCeil(size, 4096); var currentProc = Scheduler.GetCurrentThread().Process; var tableCurrent = currentProc.PageTable; var targetProc = ProcessManager.System; if (targetProcessID > 0) { targetProc = ProcessManager.GetProcess(targetProcessID); } var tableTarget = targetProc.PageTable; var virtHead = VirtualPageManager.AllocatePages( pages, new AllocatePageOptions { Pool = PageAllocationPool.Global, }); var virtAddr = virtHead; for (var pageIdx = 0; pageIdx < pages; pageIdx++) { var physAddr = PageTable.KernelTable.GetPhysicalAddressFromVirtual(virtAddr); if (tableCurrent != PageTable.KernelTable) { tableCurrent.Map(virtAddr, physAddr, flush: true); } if (tableTarget != PageTable.KernelTable) { tableTarget.Map(virtAddr, physAddr, flush: true); } virtAddr += 4096; } // TODO: implement TargetProcess.RegisterMessageBuffer, because of individual VirtAddr currentProc.GlobalAllocations.Add(new GlobalAllocation { Addr = virtHead, TargetProcID = targetProcessID }); return(virtHead); }
public unsafe override void SetWritable(uint virtAddr, uint size) { //KernelMessage.WriteLine("Unprotect Memory: Start={0:X}, End={1:X}", virtAddr, virtAddr + size); var pages = KMath.DivCeil(size, 4096); for (var i = 0; i < pages; i++) { var entry = GetTableEntry(virtAddr); entry->Writable = true; virtAddr += 4096; } Flush(); }
public static void UnMap(this IPageTable table, Addr virtAddr, USize length, bool flush = false) { if (KConfig.Log.MemoryMapping && length > 4096) { KernelMessage.WriteLine("UnMap: virt={0:X8}, length={2:X8}", virtAddr, length); } var pages = KMath.DivCeil(length, 4096); for (var i = 0; i < pages; i++) { table.MapVirtualAddressToPhysical(virtAddr, 0, false); virtAddr += 4096; } if (flush) { table.Flush(); } }
public unsafe static void InitialKernelProtect_MakeWritable_BySize(uint virtAddr, uint size) { if (!UseKernelWriteProtection) { return; } //KernelMessage.WriteLine("Unprotect Memory: Start={0:X}, End={1:X}", virtAddr, virtAddr + size); var pages = KMath.DivCeil(size, 4096); for (var i = 0; i < pages; i++) { var entry = PageTable.GetTableEntry(virtAddr); entry->Writable = true; virtAddr += 4096; } Native.SetCR3(PageTable.AddrPageDirectory); }
/// <summary> /// Sync specific mappings with another table. /// </summary> public static void MapCopy(this IPageTable table, IPageTable fromTable, Addr virtAddr, USize length, bool present = true, bool flush = false) { if (KConfig.Log.MemoryMapping && length > 4096) { KernelMessage.WriteLine("MapCopy: virt={0:X8}, length={1:X8}", virtAddr, length); } var pages = KMath.DivCeil(length, 4096); for (var i = 0; i < pages; i++) { var physAddr = fromTable.GetPhysicalAddressFromVirtual(virtAddr); table.MapVirtualAddressToPhysical(virtAddr, physAddr, present); virtAddr += 4096; } if (flush) { table.Flush(); } }
private void SetInitialPageStatus(KernelMemoryMapArray *maps, PageStatus status) { for (var i = 0; i < maps->Count; i++) { var map = maps->Items[i]; if (map.Start >= BootInfo.Header->InstalledPhysicalMemory) { continue; } if ((map.AddressSpaceKind & AddressSpaceKind.Physical) == 0) { continue; } var mapPages = KMath.DivCeil(map.Size, 4096); var fistPageNum = KMath.DivFloor(map.Start, 4096); KernelMessage.WriteLine("Mark Pages from {0:X8}, Size {1:X8}, Type {2}, FirstPage {3}, Pages {4}, Status {5}", map.Start, map.Size, (uint)map.Type, (uint)fistPageNum, mapPages, (uint)status); for (var p = fistPageNum; p < fistPageNum + mapPages; p++) { var addr = p * 4096; if (!Region.Contains(addr)) { continue; } if (addr >= BootInfo.Header->InstalledPhysicalMemory) { KernelMessage.WriteLine("addr >= BootInfo.Header->InstalledPhysicalMemory"); break; } var page = GetPageByNum(p); Assert.IsSet(page, "page == null"); page->Status = status; } } }
public static unsafe Thread CreateThread(Process proc, ThreadStartOptions options) { Thread thread; uint threadID; lock (SyncRoot) { threadID = FindEmptyThreadSlot(); if (threadID == 0) { ResetTerminatedThreads(); threadID = FindEmptyThreadSlot(); Assert.False(threadID == 0 && Enabled, "No more free Thread-Slots!"); } thread = Threads[threadID]; thread.Status = ThreadStatus.Creating; } // Debug: //options.User = false; thread.User = proc.User; thread.Debug = options.Debug; thread.DebugName = options.DebugName; thread.Priority = options.Priority; var stackSize = options.StackSize; var argBufSize = options.ArgumentBufferSize; thread.ArgumentBufferSize = options.ArgumentBufferSize; var stackPages = KMath.DivCeil(stackSize, PhysicalPageManager.PageSize); if (KConfig.Log.Threads >= KLogLevel.Trace) { KernelMessage.WriteLine("Requesting {0} stack pages", stackPages); } var debugPadding = 8u; stackSize = stackPages * PhysicalPageManager.PageSize; var stack = new Pointer((void *)VirtualPageManager.AllocatePages(stackPages, new AllocatePageOptions { DebugName = "ThreadStack" })); PageTable.KernelTable.SetWritable((uint)stack, stackSize); if (thread.User && proc.PageTable != PageTable.KernelTable) { proc.PageTable.MapCopy(PageTable.KernelTable, (uint)stack, stackSize); } stackSize -= debugPadding; var stackBottom = stack + (int)stackSize; if (KConfig.Log.Threads >= KLogLevel.Trace) { KernelMessage.Write("Create Thread {0}. EntryPoint: {1:X8} Stack: {2:X8}-{3:X8} Type: ", threadID, options.MethodAddr, (uint)stack, (uint)stackBottom - 1); } if (KConfig.Log.Threads >= KLogLevel.Trace) { if (thread.User) { KernelMessage.Write("User"); } else { KernelMessage.Write("Kernel"); } } if (KConfig.Log.Threads >= KLogLevel.Trace) { if (thread.DebugName != null) { KernelMessage.Write(" Thread DebugName: {0}", thread.DebugName); } if (thread.Process != null) { KernelMessage.WriteLine(" Process: {0}", thread.Process.Path); } } // -- kernel stack thread.KernelStackSize = 4 * 4096; //thhread.tssAddr = RawVirtualFrameAllocator.RequestRawVirtalMemoryPages(1); PageTable.KernelTable.SetWritable(KernelStart.TssAddr, 4096); thread.KernelStack = VirtualPageManager.AllocatePages( KMath.DivCeil(thread.KernelStackSize, 4096), new AllocatePageOptions { DebugName = "ThreadKernelStack" }); // TODO: Decrease Kernel Stack, because Stack have to be changed directly because of multi-threading. thread.KernelStackBottom = thread.KernelStack + thread.KernelStackSize; if (KConfig.Log.Threads >= KLogLevel.Trace) { KernelMessage.WriteLine("tssEntry: {0:X8}, tssKernelStack: {1:X8}-{2:X8}", KernelStart.TssAddr, thread.KernelStack, thread.KernelStackBottom - 1); } PageTable.KernelTable.SetWritable(thread.KernelStack, 256 * 4096); // --- uint stackStateOffset = 8; stackStateOffset += argBufSize; uint cS = 0x08; if (thread.User) { cS = 0x1B; } var stateSize = thread.User ? IDTTaskStack.Size : IDTStack.Size; thread.StackTop = (uint)stack; thread.StackBottom = (uint)stackBottom; Intrinsic.Store32(stackBottom, 4, 0xFF00001); // Debug Marker Intrinsic.Store32(stackBottom, 0, 0xFF00002); // Debug Marker Intrinsic.Store32(stackBottom, -4, (uint)stackBottom); Intrinsic.Store32(stackBottom, -(8 + (int)argBufSize), SignalThreadTerminationMethodAddress.ToInt32()); // Address of method that will raise a interrupt signal to terminate thread uint argAddr = (uint)stackBottom - argBufSize; IDTTaskStack *stackState = null; if (thread.User) { stackState = (IDTTaskStack *)VirtualPageManager.AllocatePages(1, new AllocatePageOptions { DebugName = "ThreadStackState" }); if (proc.PageTable != PageTable.KernelTable) { proc.PageTable.MapCopy(PageTable.KernelTable, (uint)stackState, IDTTaskStack.Size); } } else { stackState = (IDTTaskStack *)(stackBottom - 8 - IDTStack.Size); // IDTStackSize is correct - we don't need the Task-Members. } thread.StackState = stackState; if (thread.User && KConfig.Log.Threads >= KLogLevel.Trace) { KernelMessage.WriteLine("StackState at {0:X8}", (uint)stackState); } stackState->Stack.EFLAGS = X86_EFlags.Reserved1; if (thread.User) { // Never set this values for Non-User, otherwise you will override stack informations. stackState->TASK_SS = 0x23; stackState->TASK_ESP = (uint)stackBottom - (uint)stackStateOffset; proc.PageTable.MapCopy(PageTable.KernelTable, thread.KernelStack, thread.KernelStackSize); proc.PageTable.MapCopy(PageTable.KernelTable, KernelStart.TssAddr, 4096); } if (thread.User && options.AllowUserModeIOPort) { byte IOPL = 3; stackState->Stack.EFLAGS = (X86_EFlags)((uint)stackState->Stack.EFLAGS).SetBits(12, 2, IOPL); } stackState->Stack.CS = cS; stackState->Stack.EIP = options.MethodAddr; stackState->Stack.EBP = (uint)(stackBottom - (int)stackStateOffset).ToInt32(); thread.DataSelector = thread.User ? 0x23u : 0x10u; UninterruptableMonitor.Enter(proc.Threads); try { thread.Process = proc; proc.Threads.Add(thread); } finally { UninterruptableMonitor.Exit(proc.Threads); } ThreadsAllocated++; if (ThreadsAllocated > ThreadsMaxAllocated) { ThreadsMaxAllocated = ThreadsAllocated; if (KConfig.Log.Threads >= KLogLevel.Trace) { KernelMessage.WriteLine("Threads Max Allocated: {0}. Allocated {0} Active: {1}", ThreadsMaxAllocated, ThreadsAllocated, GetActiveThreadCount()); } if (KConfig.Log.Threads >= KLogLevel.Trace) { DumpStats(); } } else if (KConfig.Log.Threads >= KLogLevel.Debug) { KernelMessage.WriteLine("Threads Allocated {0} Active: {1}", ThreadsAllocated, GetActiveThreadCount()); } return(thread); }
private static uint RequiredPagesForSize(USize size) { return(KMath.DivCeil(size, 4096)); }
private static unsafe Process CreateProcessFromElf(ElfSections elf, string path, uint argumentBufferSize = 0) { var proc = CreateEmptyProcess(new ProcessCreateOptions() { User = true }); KernelMessage.WriteLine("Create proc: {0}, PID: {1}", path, proc.ProcessID); proc.Path = path; proc.PageTable = PageTable.CreateInstance(); var allocator = new UserInitialPageAllocator() { DebugName = "UserInitial" }; allocator.Setup(new MemoryRegion(500 * 1024 * 1024, 60 * 1024 * 1014), AddressSpaceKind.Virtual); proc.UserPageAllocator = allocator; // Setup User PageTable proc.PageTableAllocAddr = VirtualPageManager.AllocatePages( KMath.DivCeil(proc.PageTable.InitalMemoryAllocationSize, 4096), new AllocatePageOptions { Pool = PageAllocationPool.Identity }); PageTable.KernelTable.SetWritable(proc.PageTableAllocAddr, proc.PageTable.InitalMemoryAllocationSize); proc.PageTable.UserProcSetup(proc.PageTableAllocAddr); proc.PageTable.Map(proc.PageTableAllocAddr, proc.PageTableAllocAddr, proc.PageTable.InitalMemoryAllocationSize); proc.PageTable.MapCopy(PageTable.KernelTable, BootInfoMemoryType.KernelTextSegment); proc.PageTable.SetExecutable(BootInfoMemoryType.KernelTextSegment); proc.PageTable.MapCopy(PageTable.KernelTable, Address.InterruptControlBlock, 4096); proc.PageTable.MapCopy(PageTable.KernelTable, KernelMemoryMapManager.Header->Used.GetMap(BootInfoMemoryType.GDT)); proc.PageTable.MapCopy(PageTable.KernelTable, KernelMemoryMapManager.Header->Used.GetMap(BootInfoMemoryType.IDT)); proc.PageTable.MapCopy(PageTable.KernelTable, KernelMemoryMapManager.Header->Used.GetMap(BootInfoMemoryType.TSS)); var tmpKernelElfHeaders = SetupElfHeader(proc, elf); // Setup ELF Sections for (uint i = 0; i < elf.ProgramHeaderCount; i++) { var section = elf.GetProgramHeader(i); var memSize = section->MemSz; var fileSize = section->FileSz; var virtAddr = section->VAddr; var srcAddr = elf.GetProgramPhysAddr(section); if (memSize == 0) { continue; } KernelMessage.WriteLine("Setup Program Section VAddr {0:X8} SrcAddr {1:X8} Size {2:X8}", virtAddr, srcAddr, memSize); if (virtAddr == Addr.Zero) { var mem = allocator.AllocatePagesAddr(KMath.DivCeil(memSize, 4096)); tmpKernelElfHeaders[i].Addr = mem; virtAddr = mem; } // Map the Sections proc.PageTable.MapCopy(PageTable.KernelTable, srcAddr, virtAddr, memSize); if (i == 0) // TODO: Flags { proc.PageTable.SetReadonly(virtAddr, memSize); } if (memSize > fileSize) { MemoryOperation.Clear(srcAddr + fileSize, memSize - fileSize); } //if (name->Equals(".text")) // proc.PageTable.SetExecutable(virtAddr, size); } KernelMessage.WriteLine("proc sections are ready"); for (uint i = 0; i < elf.SectionHeaderCount; i++) { var section = elf.GetSectionHeader(i); var size = section->Size; var virtAddr = section->Addr; var srcAddr = elf.GetSectionPhysAddr(section); if (size == 0) { continue; } var name = elf.GetSectionName(section); if (virtAddr == Addr.Zero) { } else { if (name->Equals(".bss")) { MemoryOperation.Clear(srcAddr, size); proc.BrkBase = virtAddr + size; KernelMessage.WriteLine("sbrk_base: {0:X8}", proc.BrkBase); } } } // Detect Thread-Main var entryPoint = GetMainEntryPointFromElf(elf); KernelMessage.WriteLine("EntryPoint: {0:X8}", entryPoint); var defaultDispatchEntryPoint = GetDispatchEntryPointFromElf(elf); if (defaultDispatchEntryPoint != Addr.Zero) { KernelMessage.WriteLine("DispatchEntryPoint: {0:X8}", defaultDispatchEntryPoint); proc.Service.Init(defaultDispatchEntryPoint); } var mainThread = Scheduler.CreateThread(proc, new ThreadStartOptions(entryPoint) { ArgumentBufferSize = argumentBufferSize, AllowUserModeIOPort = true, DebugName = "UserProcMainThread", }); KernelMessage.WriteLine("Created Process {0} ProcessID={1}", path, proc.ProcessID); return(proc); }
private static unsafe Process StartProcessFromElf(ElfSections elf, string path, uint argumentBufferSize = 0) { var proc = CreateEmptyProcess(new ProcessCreateOptions() { User = true }); KernelMessage.WriteLine("Create proc: {0}, PID: {1}", path, proc.ProcessID); proc.Path = path; proc.PageTable = PageTable.CreateInstance(); var allocator = new UserInitialPageAllocator() { DebugName = "UserInitial" }; allocator.Setup(new MemoryRegion(500 * 1024 * 1024, 60 * 1024 * 1014), AddressSpaceKind.Virtual); proc.UserPageAllocator = allocator; // Setup User PageTable proc.PageTableAllocAddr = VirtualPageManager.AllocatePages( KMath.DivCeil(proc.PageTable.InitalMemoryAllocationSize, 4096), new AllocatePageOptions { Pool = PageAllocationPool.Identity }); PageTable.KernelTable.SetWritable(proc.PageTableAllocAddr, proc.PageTable.InitalMemoryAllocationSize); proc.PageTable.UserProcSetup(proc.PageTableAllocAddr); proc.PageTable.Map(proc.PageTableAllocAddr, proc.PageTableAllocAddr, proc.PageTable.InitalMemoryAllocationSize); proc.PageTable.MapCopy(PageTable.KernelTable, BootInfoMemoryType.KernelTextSegment); proc.PageTable.SetExecutable(BootInfoMemoryType.KernelTextSegment); proc.PageTable.MapCopy(PageTable.KernelTable, Address.InterruptControlBlock, 4096); proc.PageTable.MapCopy(PageTable.KernelTable, KernelMemoryMapManager.Header->Used.GetMap(BootInfoMemoryType.GDT)); proc.PageTable.MapCopy(PageTable.KernelTable, KernelMemoryMapManager.Header->Used.GetMap(BootInfoMemoryType.IDT)); proc.PageTable.MapCopy(PageTable.KernelTable, KernelMemoryMapManager.Header->Used.GetMap(BootInfoMemoryType.TSS)); var tmpKernelElfHeaders = SetupElfHeader(proc, elf); // Setup ELF Sections for (uint i = 0; i < elf.SectionHeaderCount; i++) { var section = elf.GetSectionHeader(i); var name = elf.GeSectionName(section); var size = section->Size; var virtAddr = section->Addr; var srcAddr = elf.GetSectionPhysAddr(section); if (size == 0) { continue; } if (virtAddr == Addr.Zero) { var mem = allocator.AllocatePagesAddr(KMath.DivCeil(size, 4096)); tmpKernelElfHeaders[i].Addr = mem; virtAddr = mem; } var sb = new StringBuffer(); sb.Append("Map section "); sb.Append(name); sb.Append(" virt={0:X8} src={1:X8} size={2:X8}", virtAddr, srcAddr, size); KernelMessage.WriteLine(sb); //MemoryOperation.Copy4(elf.GetSectionPhysAddr(section), section->Addr, section->Size); // Map the Sections proc.PageTable.MapCopy(PageTable.KernelTable, srcAddr, virtAddr, size); if (name->Equals(".text")) { proc.PageTable.SetExecutable(virtAddr, size); } } KernelMessage.WriteLine("proc sections are ready"); // Detect Thread-Main var entryPoint = GetEntryPointFromElf(elf); KernelMessage.WriteLine("EntryPoint: {0:X8}", entryPoint); var mainThread = Scheduler.CreateThread(proc, new ThreadStartOptions(entryPoint) { ArgumentBufferSize = argumentBufferSize, AllowUserModeIOPort = true, DebugName = "UserProcMainThread", }); KernelMessage.WriteLine("Starting {0} on Thread {1}", path, mainThread.ThreadID); proc.Start(); return(proc); }