Handle ExtendedStates::AllocateNew(void * & state) { Handle res = ExtendedStatesAllocator.AllocateObject(state); if (!res.IsOkayResult()) return res; if (templateState != nullptr) ::memcpy(state, templateState, ExtendedStatesAllocator.ObjectSize); return HandleResult::Okay; }
Handle ExtendedStates::AllocateTemplate(void * & state) { if (templateState != nullptr || !ExtendedStates::Initialized) return HandleResult::UnsupportedOperation; Handle res = ExtendedStatesAllocator.AllocateObject(state); if (!res.IsOkayResult()) return res; templateState = state; ::memset(state, 0, ExtendedStatesAllocator.ObjectSize); // Clear all the bits, for the cheap (f)xsave implementations that just // leave the reserved bits/bytes/whatever unchanged. return HandleResult::Okay; }
void TestCmdo() { CMDO(1, "a", "alpha", String); CMDO(2, "b", "beta", String); CMDO(3, "c", "gamma", String); CMDO(4, "s", "sierra", BooleanByPresence); CMDO(5, "x", "xenulol", BooleanByPresence); CMDO(6, "y", "york", BooleanByPresence); Handle res; res = parser.StartParsing(OptionsString1); ASSERT(res.IsOkayResult() , "Failed to start parsing command-line options: %H" , res); // for (size_t i = 0; i < parser.Length; ++i) // if (parser.InputString[i] == '\0') // parser.InputString[i] = '_'; // msg("Length of \"%S\" is: %us.%n", parser.Length, parser.InputString, parser.Length); ASSERT(parser.TokenCount == 7 , "Parser should have identified %us tokens, not %us." , (size_t)7, parser.TokenCount); PARSE_OPT(1); PARSE_OPT(2); PARSE_OPT(3); PARSE_OPT(4); PARSE_OPT(5); PARSE_OPT(6); CHECK_STR(1, "test a"); CHECK_STR(2, "yada yada"); CHECK_STR(3, "rada"); CHECK_BOL(4, true); CHECK_BOL(5, true); CHECK_BOL(6, false); // AND NOW ROUND 2! new (&parser) CommandLineOptionParser(); res = parser.StartParsing(OptionsString2); ASSERT(res.IsOkayResult() , "Failed to start parsing command-line options: %H" , res); // for (size_t i = 0; i < parser.Length; ++i) // if (parser.InputString[i] == '\0') // parser.InputString[i] = '_'; // msg("Length of \"%S\" is: %us.%n", parser.Length, parser.InputString, parser.Length); ASSERT(parser.TokenCount == 6 , "Parser should have identified %us tokens, not %us." , (size_t)6, parser.TokenCount); PARSE_OPT(1); PARSE_OPT(2); PARSE_OPT(3); PARSE_OPT(4); PARSE_OPT(5); PARSE_OPT(6); CHECK_STR(1, "test a"); CHECK_STR(2, "yada yada"); CHECK_STR(3, "rada"); CHECK_BOL(4, true); CHECK_BOL(5, true); CHECK_BOL(6, false); // AND NOW ROUND 3! CMDO(a, "1", "one", SignedInteger); CMDO(b, "2", "two", SignedInteger); CMDO(c, "3", "three", SignedInteger); CMDO(d, "4", "four", SignedInteger); CMDO(e, "BT", "BT", BooleanExplicit); CMDO(f, "BF", "BF", BooleanExplicit); new (&parser) CommandLineOptionParser(); res = parser.StartParsing(OptionsString3); ASSERT(res.IsOkayResult() , "Failed to start parsing command-line options: %H" , res); // for (size_t i = 0; i < parser.Length; ++i) // if (parser.InputString[i] == '\0') // parser.InputString[i] = '_'; // msg("Length of \"%S\" is: %us.%n", parser.Length, parser.InputString, parser.Length); ASSERT(parser.TokenCount == 11 , "Parser should have identified %us tokens, not %us." , (size_t)11, parser.TokenCount); PARSE_OPT(a); PARSE_OPT(b); PARSE_OPT(c); PARSE_OPT(d); PARSE_OPT(e); PARSE_OPT(f); CHECK_SINT(a, -0x60); CHECK_SINT(b, -987); CHECK_SINT(c, 0123); CHECK_SINT(d, 0xCA); CHECK_BOL(e, true); CHECK_BOL(f, false); // AND FINALLY ROUND 4! CMDO(01, "a", "aaa", String); CMDO_LINKED(02, "b", "bbb", String, 01); CMDO_LINKED(03, "c", "ccc", String, 02); CMDO_LINKED(04, "d", "ddd", BooleanByPresence, 03); CMDO_LINKED(05, "e", "eee", BooleanByPresence, 04); CMDO_LINKED(06, "freud", "booohoooo", BooleanByPresence, 05); CMDO_LINKED(07, "g", "ggg", BooleanByPresence, 06); new (&parser) CommandLineOptionParser(); res = parser.StartParsing(OptionsString4); ASSERT(res.IsOkayResult() , "Failed to start parsing command-line options: %H" , res); ASSERT(parser.TokenCount == 8 , "Parser should have identified %us tokens, not %us." , (size_t)8, parser.TokenCount); CommandLineOptionBatchState batch; ASSERT(!batch.IsValid(), "Batch should be invalid."); res = parser.StartBatch(batch, &CMDO_07); ASSERT(batch.IsValid(), "Batch should be valid."); ASSERT(!batch.IsFinished(), "Batch should not be finished."); ASSERT(res.IsOkayResult() , "Failed to start batch for processing command-line options: %H" , res); // This shan't ever happen. size_t counter = 0; while (!(res = batch.Next()).IsResult(HandleResult::UnsupportedOperation)) { // msg("?? %H ??%n", res); if (counter < 5 || counter == 6) { ASSERT(res.IsOkayResult() , "Failed batch step #%us of command-line options processing: %H" , counter, res); } else { ASSERT(counter == 5 , "Counter shouldn't exceed 6! It is %us." , counter); ASSERT(res.IsResult(HandleResult::NotFound) , "Failed batch step #%us of command-line options processing: %H" , counter, res); } ASSERT(batch.IsFinished() == (counter == 6) , "Batch should only be finished on step 6; current step is %us." , counter); ++counter; } ASSERT(batch.IsFinished(), "Batch should be finished."); CHECK_PARSED(01); CHECK_PARSED(02); CHECK_PARSED(03); CHECK_PARSED(04); CHECK_PARSED(06); CHECK_PARSED(07); CHECK_STR(01, "1"); CHECK_STR(02, "2"); CHECK_STR(03, "3"); CHECK_BOL(04, true); CHECK_BOL(05, false); CHECK_BOL(06, true); CHECK_BOL(07, true); }
void TestApplication() { // First get the loadtest app's location. ASSERT(InitRd::Loaded); Handle file = InitRd::FindItem("/apps/loadtest.exe"); ASSERT(file.IsType(HandleType::InitRdFile) , "Failed to find loadtest app in InitRD: %H.", file); FileBoundaries bnd = InitRd::GetFileBoundaries(file); ASSERT(bnd.Start != 0 && bnd.Size != 0); // Then attempt parsing it. Handle res = HandleLoadtest(bnd.Start, bnd.Size); ASSERT(res.IsOkayResult(), "Error in handling loadtest app: %H.", res); // Then prepare the necessary processes and threads. TestRegionLock.Reset(); TestRegionLock.Acquire(); new (&testProcess) Process(); Vmm::Initialize(&testProcess); new (&testThread) Thread(&testProcess); new (&testWatcher) Thread(&testProcess); // DEBUG_TERM_ << "Created app test process and threads." << Terminals::EndLine; // Then the test thread. uintptr_t stackVaddr = nullvaddr; res = Vmm::AllocatePages(nullptr, 3 * PageSize , MemoryAllocationOptions::Commit | MemoryAllocationOptions::VirtualKernelHeap | MemoryAllocationOptions::GuardLow | MemoryAllocationOptions::GuardHigh , MemoryFlags::Global | MemoryFlags::Writable , MemoryContent::ThreadStack , stackVaddr); ASSERT(res.IsOkayResult() , "Failed to allocate stack for test userland thread: %H." , res); testThread.KernelStackTop = stackVaddr + 3 * PageSize; testThread.KernelStackBottom = stackVaddr; testThread.EntryPoint = &JumpToRing3; InitializeThreadState(&testThread); // This sets up the thread so it goes directly to the entry point when switched to. withInterrupts (false) BootstrapThread.IntroduceNext(&testThread); // DEBUG_TERM_ << "Initialized app test main thread." << Terminals::EndLine; // Then the watcher thread. stackVaddr = nullvaddr; res = Vmm::AllocatePages(nullptr, 3 * PageSize , MemoryAllocationOptions::Commit | MemoryAllocationOptions::VirtualKernelHeap | MemoryAllocationOptions::GuardLow | MemoryAllocationOptions::GuardHigh , MemoryFlags::Global | MemoryFlags::Writable , MemoryContent::ThreadStack , stackVaddr); ASSERT(res.IsOkayResult() , "Failed to allocate stack for test watcher thread: %H." , res); testWatcher.KernelStackTop = stackVaddr + 3 * PageSize; testWatcher.KernelStackBottom = stackVaddr; testWatcher.EntryPoint = &WatchTestThread; InitializeThreadState(&testWatcher); // This sets up the thread so it goes directly to the entry point when switched to. withInterrupts (false) testThread.IntroduceNext(&testWatcher); // DEBUG_TERM_ << "Initialized app test watcher thread." << Terminals::EndLine; // That's all, folks. The other threads finish the work. }
void * JumpToRing3(void * arg) { (void)arg; Handle res; // First, the userland stack page. uintptr_t userStackBottom = nullvaddr; res = Vmm::AllocatePages(&testProcess , userStackPageCount * PageSize , MemoryAllocationOptions::AllocateOnDemand | MemoryAllocationOptions::VirtualUser | MemoryAllocationOptions::GuardLow | MemoryAllocationOptions::GuardHigh , MemoryFlags::Userland | MemoryFlags::Writable , MemoryContent::ThreadStack , userStackBottom); ASSERT(res.IsOkayResult() , "Failed to allocate userland stack for app test thread: %H." , res); uintptr_t userStackTop = userStackBottom + userStackPageCount * PageSize; // DEBUG_TERM_ << "Initialized userland stack for app test main thread." << Terminals::EndLine; // Then, deploy the runtime. StartupData * stdat = nullptr; res = Runtime64::Deploy(rtlib_base, stdat); ASSERT(res.IsOkayResult() , "Failed to deploy runtime64 library into test app process: %H." , res); ASSERT(stdat != nullptr); // Then pass on the app image. res = Vmm::AllocatePages(nullptr , RoundUp(loadtestEnd - loadtestStart, PageSize) , MemoryAllocationOptions::Commit | MemoryAllocationOptions::VirtualUser , MemoryFlags::Userland | MemoryFlags::Writable , MemoryContent::Generic , appVaddr); ASSERT(res.IsOkayResult() , "Failed to allocate pages for test app image: %H." , res); memmove(reinterpret_cast<void *>(appVaddr) , reinterpret_cast<void const *>(loadtestStart) , loadtestEnd - loadtestStart); stdat->MemoryImageStart = appVaddr; stdat->MemoryImageEnd = loadtestEnd - loadtestStart + appVaddr; // DEBUG_TERM_ << "Deployed 64-bit runtime for app test process." << Terminals::EndLine; // Finally, a region for test incrementation. vaddr_t testRegVaddr = 0x300000000000; res = Vmm::AllocatePages(&testProcess , 0x30000 , MemoryAllocationOptions::AllocateOnDemand | MemoryAllocationOptions::VirtualUser , MemoryFlags::Userland | MemoryFlags::Writable , MemoryContent::Generic , testRegVaddr); ASSERT(res.IsOkayResult() , "Failed to allocate app test region in userland: %H.%n" "Stack is between %Xp and %Xp." , res, userStackBottom, userStackTop); // DEBUG_TERM_ << "Created test region for app test process." << Terminals::EndLine; TestRegionLock.Release(); // And finish by going to ring 3. // DEBUG_TERM_ << "About to go to ring 3!" << EndLine; CpuInstructions::InvalidateTlb(reinterpret_cast<void const *>(rtlib_base + Runtime64::Template.GetEntryPoint())); GoToRing3_64(rtlib_base + Runtime64::Template.GetEntryPoint(), userStackTop); }