diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1bb0588
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/dotnet-28be3e9a006d90d8c6e87d4353b77882829df718-x64-bootstrap.tar.xz
+/dotnet-arm64-prebuilts-2021-10-04.tar.gz
+/dotnet-s390x-prebuilts-2021-10-01.tar.gz
diff --git a/EMPTY b/EMPTY
deleted file mode 100644
index 0519ecb..0000000
--- a/EMPTY
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/arcade-no-apphost.patch b/arcade-no-apphost.patch
new file mode 100644
index 0000000..cec03a1
--- /dev/null
+++ b/arcade-no-apphost.patch
@@ -0,0 +1,36 @@
+Index: a/src/Microsoft.DotNet.GitSync.CommitManager/Microsoft.DotNet.GitSync.CommitManager.csproj
+===================================================================
+--- a/src/Microsoft.DotNet.GitSync.CommitManager/Microsoft.DotNet.GitSync.CommitManager.csproj
++++ b/src/Microsoft.DotNet.GitSync.CommitManager/Microsoft.DotNet.GitSync.CommitManager.csproj
+@@ -5,6 +5,7 @@
+ netcoreapp3.1
+ latest
+ true
++ false
+
+
+
+Index: a/src/Microsoft.DotNet.SwaggerGenerator/Microsoft.DotNet.SwaggerGenerator.CmdLine/Microsoft.DotNet.SwaggerGenerator.CmdLine.csproj
+===================================================================
+--- a/src/Microsoft.DotNet.SwaggerGenerator/Microsoft.DotNet.SwaggerGenerator.CmdLine/Microsoft.DotNet.SwaggerGenerator.CmdLine.csproj
++++ b/src/Microsoft.DotNet.SwaggerGenerator/Microsoft.DotNet.SwaggerGenerator.CmdLine/Microsoft.DotNet.SwaggerGenerator.CmdLine.csproj
+@@ -9,6 +9,7 @@
+ dotnet-swaggergen
+ false
+ true
++ false
+
+
+
+Index: a/src/Microsoft.DotNet.XUnitConsoleRunner/src/Microsoft.DotNet.XUnitConsoleRunner.csproj
+===================================================================
+--- a/src/Microsoft.DotNet.XUnitConsoleRunner/src/Microsoft.DotNet.XUnitConsoleRunner.csproj
++++ b/src/Microsoft.DotNet.XUnitConsoleRunner/src/Microsoft.DotNet.XUnitConsoleRunner.csproj
+@@ -11,6 +11,7 @@
+ 2.5.1
+ true
+ Major
++ false
+
+
+
diff --git a/aspnetcore-add-arm64-crossgen-dependencies.patch b/aspnetcore-add-arm64-crossgen-dependencies.patch
new file mode 100644
index 0000000..0bba983
--- /dev/null
+++ b/aspnetcore-add-arm64-crossgen-dependencies.patch
@@ -0,0 +1,12 @@
+diff --git a/eng/Dependencies.props b/eng/Dependencies.props
+index 8a50fb9f21..a13b74fb51 100644
+--- a/eng/Dependencies.props
++++ b/eng/Dependencies.props
+@@ -99,6 +99,7 @@ and are generated based on the last package release.
+
+
+
++
+
+
+
diff --git a/aspnetcore-dont-check-eol-targets.patch b/aspnetcore-dont-check-eol-targets.patch
new file mode 100644
index 0000000..7ab712d
--- /dev/null
+++ b/aspnetcore-dont-check-eol-targets.patch
@@ -0,0 +1,11 @@
+--- a/eng/SourceBuild.props
++++ b/eng/SourceBuild.props
+@@ -69,6 +69,8 @@
+
+
+ $(InnerBuildArgs) /p:SourceBuildRuntimeIdentifier=$(TargetRuntimeIdentifier)
++ $(InnerBuildArgs) /p:CheckEolTargetFramework=false
++ $(InnerBuildArgs) /p:EnablePreviewFeatures=true
+
+
+
diff --git a/aspnetcore-no-shared-compilation.patch b/aspnetcore-no-shared-compilation.patch
new file mode 100644
index 0000000..f29acfd
--- /dev/null
+++ b/aspnetcore-no-shared-compilation.patch
@@ -0,0 +1,13 @@
+Index: source-build-tarball/src/aspnetcore.4ab0cf33ecb1c25a38422f5b11810e4c8a91d8eb/Directory.Build.props
+===================================================================
+--- a/Directory.Build.props
++++ b/Directory.Build.props
+@@ -48,6 +48,8 @@
+
+
+ true
++
++ false
+
+
+
+ $(OtherFlags) --nowarn:1204
+
+Index: tests/benchmarks/TaskPerf/TaskPerf.fsproj
+===================================================================
+--- a/tests/benchmarks/TaskPerf/TaskPerf.fsproj
++++ b/tests/benchmarks/TaskPerf/TaskPerf.fsproj
+@@ -4,6 +4,7 @@
+ net5.0
+ Exe
+ true
++ false
+
+ $(OtherFlags) --nowarn:1204
+
diff --git a/fsharp-no-shared-compilation.patch b/fsharp-no-shared-compilation.patch
new file mode 100644
index 0000000..21ec960
--- /dev/null
+++ b/fsharp-no-shared-compilation.patch
@@ -0,0 +1,12 @@
+Index: a/FSharpBuild.Directory.Build.props
+===================================================================
+--- a/FSharpBuild.Directory.Build.props
++++ b/FSharpBuild.Directory.Build.props
+@@ -21,6 +21,7 @@
+ 4.4.0
+ 1182;0025;$(WarningsAsErrors)
+ $(OtherFlags) --nowarn:3384
++ false
+
+
+
diff --git a/fsharp-use-work-tree-with-git-apply.patch b/fsharp-use-work-tree-with-git-apply.patch
new file mode 100644
index 0000000..810cf67
--- /dev/null
+++ b/fsharp-use-work-tree-with-git-apply.patch
@@ -0,0 +1,11 @@
+--- a/eng/SourceBuild.props
++++ b/eng/SourceBuild.props
+@@ -15,7 +15,7 @@
+
+
+
+
diff --git a/nuget-client-use-work-tree-with-git-apply.patch b/nuget-client-use-work-tree-with-git-apply.patch
new file mode 100644
index 0000000..e1785ae
--- /dev/null
+++ b/nuget-client-use-work-tree-with-git-apply.patch
@@ -0,0 +1,28 @@
+From 691babb1c8316e2f829fbcf9f2aa14f4b7711960 Mon Sep 17 00:00:00 2001
+From: Omair Majid
+Date: Thu, 9 Sep 2021 10:03:36 -0400
+Subject: [PATCH] [ArPow] Use --work-tree with git apply
+
+This makes things work bettern in a source-tarball build (where there
+may not be a .git directory), or there might be a .git directory but
+it's for a different repo than the one we are building.
+---
+ eng/source-build/source-build.proj | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/eng/source-build/source-build.proj b/eng/source-build/source-build.proj
+index 6f90f9793..72058ac88 100644
+--- a/eng/source-build/source-build.proj
++++ b/eng/source-build/source-build.proj
+@@ -55,7 +55,7 @@
+
+
+
+
+--
+2.31.1
+
diff --git a/roslyn-analyzers-no-apphost.patch b/roslyn-analyzers-no-apphost.patch
new file mode 100644
index 0000000..f4e7f4b
--- /dev/null
+++ b/roslyn-analyzers-no-apphost.patch
@@ -0,0 +1,12 @@
+Index: roslyn-analyzers.e71e518713d6d578569bba6c5d401e405eee6058/src/Tools/ReleaseNotesUtil/ReleaseNotesUtil.csproj
+===================================================================
+--- a/src/Tools/ReleaseNotesUtil/ReleaseNotesUtil.csproj
++++ b/src/Tools/ReleaseNotesUtil/ReleaseNotesUtil.csproj
+@@ -3,6 +3,7 @@
+ Exe
+ netcoreapp3.1
+ true
++ false
+
+
+
diff --git a/roslyn-no-apphost.patch b/roslyn-no-apphost.patch
new file mode 100644
index 0000000..b2511f9
--- /dev/null
+++ b/roslyn-no-apphost.patch
@@ -0,0 +1,125 @@
+Index: a/src/Interactive/csi/csi.csproj
+===================================================================
+--- a/src/Interactive/csi/csi.csproj
++++ b/src/Interactive/csi/csi.csproj
+@@ -6,6 +6,7 @@
+ Exe
+ CSharpInteractive
+ netcoreapp3.1;net472
++ false
+
+
+
+Index: roslyn.dae39045cd460ba44053ff2af2217da126c25dbf/src/Interactive/vbi/vbi.vbproj
+===================================================================
+--- a/src/Interactive/vbi/vbi.vbproj
++++ b/src/Interactive/vbi/vbi.vbproj
+@@ -7,6 +7,7 @@
+ Sub Main
+ netcoreapp3.1;net472
+
++ false
+
+
+
+Index: roslyn.dae39045cd460ba44053ff2af2217da126c25dbf/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj
+===================================================================
+--- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj
++++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj
+@@ -14,6 +14,7 @@
+ $(RoslynPortableRuntimeIdentifiers)
+ false
+ false
++ false
+
+
+
+Index: roslyn.dae39045cd460ba44053ff2af2217da126c25dbf/src/Tools/PrepareTests/PrepareTests.csproj
+===================================================================
+--- a/src/Tools/PrepareTests/PrepareTests.csproj
++++ b/src/Tools/PrepareTests/PrepareTests.csproj
+@@ -7,6 +7,7 @@
+ false
+ false
+ false
++ false
+
+
+
+Index: roslyn.dae39045cd460ba44053ff2af2217da126c25dbf/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/CompilersBoundTreeGenerator.csproj
+===================================================================
+--- a/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/CompilersBoundTreeGenerator.csproj
++++ b/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/CompilersBoundTreeGenerator.csproj
+@@ -11,8 +11,9 @@
+ True
+ netcoreapp3.1
+ false
++ false
+
+
+
+
+-
+\ No newline at end of file
++
+Index: roslyn.dae39045cd460ba44053ff2af2217da126c25dbf/src/Tools/Source/CompilerGeneratorTools/Source/CSharpErrorFactsGenerator/CSharpErrorFactsGenerator.csproj
+===================================================================
+--- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpErrorFactsGenerator/CSharpErrorFactsGenerator.csproj
++++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpErrorFactsGenerator/CSharpErrorFactsGenerator.csproj
+@@ -10,5 +10,6 @@
+ True
+ netcoreapp3.1
+ false
++ false
+
+-
+\ No newline at end of file
++
+Index: roslyn.dae39045cd460ba44053ff2af2217da126c25dbf/src/Tools/Source/CompilerGeneratorTools/Source/IOperationGenerator/CompilersIOperationGenerator.csproj
+===================================================================
+--- a/src/Tools/Source/CompilerGeneratorTools/Source/IOperationGenerator/CompilersIOperationGenerator.csproj
++++ b/src/Tools/Source/CompilerGeneratorTools/Source/IOperationGenerator/CompilersIOperationGenerator.csproj
+@@ -8,5 +8,6 @@
+ True
+ net5.0
+ false
++ false
+
+
+Index: roslyn.dae39045cd460ba44053ff2af2217da126c25dbf/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicErrorFactsGenerator/VisualBasicErrorFactsGenerator.vbproj
+===================================================================
+--- a/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicErrorFactsGenerator/VisualBasicErrorFactsGenerator.vbproj
++++ b/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicErrorFactsGenerator/VisualBasicErrorFactsGenerator.vbproj
+@@ -12,5 +12,6 @@
+ True
+ netcoreapp3.1
+ false
++ false
+
+-
+\ No newline at end of file
++
+Index: roslyn.dae39045cd460ba44053ff2af2217da126c25dbf/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/VisualBasicSyntaxGenerator.vbproj
+===================================================================
+--- a/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/VisualBasicSyntaxGenerator.vbproj
++++ b/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/VisualBasicSyntaxGenerator.vbproj
+@@ -13,6 +13,7 @@
+ True
+ netcoreapp3.1
+ false
++ false
+
+
+
+Index: roslyn.dae39045cd460ba44053ff2af2217da126c25dbf/src/Tools/Source/RunTests/RunTests.csproj
+===================================================================
+--- a/src/Tools/Source/RunTests/RunTests.csproj
++++ b/src/Tools/Source/RunTests/RunTests.csproj
+@@ -7,6 +7,7 @@
+ true
+ false
+ false
++ false
+
+
+
diff --git a/roslyn-no-shared-compilation.patch b/roslyn-no-shared-compilation.patch
new file mode 100644
index 0000000..2c1f7c0
--- /dev/null
+++ b/roslyn-no-shared-compilation.patch
@@ -0,0 +1,13 @@
+Index: source-build-tarball/src/roslyn.2cb3d482e3c09760d1b204c597be93f49dba3349/eng/targets/Settings.props
+===================================================================
+--- a/eng/targets/Settings.props
++++ b/eng/targets/Settings.props
+@@ -39,6 +39,8 @@
+ Microsoft.Common.CurrentVersion.targets to see how it is consumed -->
+ false
+
++ false
++
+ false
+ enable
+
diff --git a/runtime-arm64-lld-fix.patch b/runtime-arm64-lld-fix.patch
new file mode 100644
index 0000000..5972f45
--- /dev/null
+++ b/runtime-arm64-lld-fix.patch
@@ -0,0 +1,13 @@
+diff --git a/eng/native/init-compiler.sh b/eng/native/init-compiler.sh
+index 567d18da474..927b3071e92 100755
+--- a/eng/native/init-compiler.sh
++++ b/eng/native/init-compiler.sh
+@@ -108,7 +108,7 @@ if [[ -z "$CC" ]]; then
+ fi
+
+ if [[ "$compiler" == "clang" ]]; then
+- if command -v "lld$desired_version" > /dev/null; then
++ if command -v lld || command -v "lld$desired_version" > /dev/null; then
+ # Only lld version >= 9 can be considered stable
+ if [[ "$majorVersion" -ge 9 ]]; then
+ LDFLAGS="-fuse-ld=lld"
diff --git a/runtime-bigendian-ilasm-pdb.patch b/runtime-bigendian-ilasm-pdb.patch
new file mode 100644
index 0000000..00c31ec
--- /dev/null
+++ b/runtime-bigendian-ilasm-pdb.patch
@@ -0,0 +1,80 @@
+Index: a/src/coreclr/ilasm/writer.cpp
+===================================================================
+--- a/src/coreclr/ilasm/writer.cpp
++++ b/src/coreclr/ilasm/writer.cpp
+@@ -212,26 +212,28 @@ HRESULT Assembler::CreateDebugDirectory(
+ param.debugDirData = NULL;
+
+ // get module ID
+- DWORD rsds = 0x53445352;
+- DWORD pdbAge = 0x1;
++ DWORD rsds = VAL32(0x53445352);
++ DWORD pdbAge = VAL32(0x1);
++ GUID pdbGuid = *m_pPortablePdbWriter->GetGuid();
++ SwapGuid(&pdbGuid);
+ DWORD len = sizeof(rsds) + sizeof(GUID) + sizeof(pdbAge) + (DWORD)strlen(m_szPdbFileName) + 1;
+ BYTE* dbgDirData = new BYTE[len];
+
+ DWORD offset = 0;
+ memcpy_s(dbgDirData + offset, len, &rsds, sizeof(rsds)); // RSDS
+ offset += sizeof(rsds);
+- memcpy_s(dbgDirData + offset, len, m_pPortablePdbWriter->GetGuid(), sizeof(GUID)); // PDB GUID
++ memcpy_s(dbgDirData + offset, len, &pdbGuid, sizeof(GUID)); // PDB GUID
+ offset += sizeof(GUID);
+ memcpy_s(dbgDirData + offset, len, &pdbAge, sizeof(pdbAge)); // PDB AGE
+ offset += sizeof(pdbAge);
+ memcpy_s(dbgDirData + offset, len, m_szPdbFileName, strlen(m_szPdbFileName) + 1); // PDB PATH
+
+ debugDirIDD.Characteristics = 0;
+- debugDirIDD.TimeDateStamp = m_pPortablePdbWriter->GetTimestamp();
+- debugDirIDD.MajorVersion = 0x100;
+- debugDirIDD.MinorVersion = 0x504d;
+- debugDirIDD.Type = IMAGE_DEBUG_TYPE_CODEVIEW;
+- debugDirIDD.SizeOfData = len;
++ debugDirIDD.TimeDateStamp = VAL32(m_pPortablePdbWriter->GetTimestamp());
++ debugDirIDD.MajorVersion = VAL16(0x100);
++ debugDirIDD.MinorVersion = VAL16(0x504d);
++ debugDirIDD.Type = VAL32(IMAGE_DEBUG_TYPE_CODEVIEW);
++ debugDirIDD.SizeOfData = VAL32(len);
+ debugDirIDD.AddressOfRawData = 0; // will be updated bellow
+ debugDirIDD.PointerToRawData = 0; // will be updated bellow
+
+Index: a/src/coreclr/md/enc/pdbheap.cpp
+===================================================================
+--- a/src/coreclr/md/enc/pdbheap.cpp
++++ b/src/coreclr/md/enc/pdbheap.cpp
+@@ -26,6 +26,16 @@ HRESULT PdbHeap::SetData(PORT_PDB_STREAM
+ (sizeof(ULONG) * data->typeSystemTableRowsSize);
+ m_data = new BYTE[m_size];
+
++#if BIGENDIAN
++ PORT_PDB_STREAM swappedData = *data;
++ SwapGuid(&swappedData.id.pdbGuid);
++ swappedData.id.pdbTimeStamp = VAL32(swappedData.id.pdbTimeStamp);
++ swappedData.entryPoint = VAL32(swappedData.entryPoint);
++ swappedData.referencedTypeSystemTables = VAL64(swappedData.referencedTypeSystemTables);
++ // typeSystemTableRows and typeSystemTableRowsSize handled below
++ data = &swappedData;
++#endif
++
+ ULONG offset = 0;
+ if (memcpy_s(m_data + offset, m_size, &data->id, sizeof(data->id)))
+ return E_FAIL;
+@@ -39,9 +49,17 @@ HRESULT PdbHeap::SetData(PORT_PDB_STREAM
+ return E_FAIL;
+ offset += sizeof(data->referencedTypeSystemTables);
+
++#if !BIGENDIAN
+ if (memcpy_s(m_data + offset, m_size, data->typeSystemTableRows, sizeof(ULONG) * data->typeSystemTableRowsSize))
+ return E_FAIL;
+ offset += sizeof(ULONG) * data->typeSystemTableRowsSize;
++#else
++ for (int i = 0; i < data->typeSystemTableRowsSize; i++)
++ {
++ SET_UNALIGNED_VAL32(m_data + offset, data->typeSystemTableRows[i]);
++ offset += sizeof(ULONG);
++ }
++#endif
+
+ _ASSERTE(offset == m_size);
+
diff --git a/runtime-mono-memfunc-cgroup.patch b/runtime-mono-memfunc-cgroup.patch
new file mode 100644
index 0000000..b4c8fba
--- /dev/null
+++ b/runtime-mono-memfunc-cgroup.patch
@@ -0,0 +1,755 @@
+Index: a/src/mono/mono/utils/memfuncs.c
+===================================================================
+--- a/src/mono/mono/utils/memfuncs.c
++++ b/src/mono/mono/utils/memfuncs.c
+@@ -343,6 +343,9 @@ mono_determine_physical_ram_available_si
+ host_page_size (host, &page_size);
+ return (guint64) vmstat.free_count * page_size;
+
++#elif defined (__FreeBSD__) || defined (__linux__) || defined (__APPLE__)
++ return (getPhysicalMemoryAvail());
++
+ #elif defined (HAVE_SYSCONF)
+ gint64 page_size = -1, num_pages = -1;
+
+Index: a/src/mono/mono/utils/memfuncs.h
+===================================================================
+--- a/src/mono/mono/utils/memfuncs.h
++++ b/src/mono/mono/utils/memfuncs.h
+@@ -24,5 +24,10 @@ MONO_COMPONENT_API void mono_gc_memmove_
+ void mono_gc_memmove_aligned (void *dest, const void *src, size_t size);
+ guint64 mono_determine_physical_ram_size (void);
+ guint64 mono_determine_physical_ram_available_size (void);
++#if defined (__FreeBSD__) || defined (__linux__) || defined (__APPLE__)
++size_t getRestrictedPhysicalMemoryLimit(void);
++gboolean getPhysicalMemoryUsed(size_t *);
++size_t getPhysicalMemoryAvail(void);
++#endif
+
+ #endif
+Index: a/src/mono/mono/utils/mono-cgroup.c
+===================================================================
+--- /dev/null
++++ b/src/mono/mono/utils/mono-cgroup.c
+@@ -0,0 +1,709 @@
++// Licensed to the .NET Foundation under one or more agreements.
++// The .NET Foundation licenses this file to you under the MIT license.
++
++/*++
++
++Module Name:
++
++ mono-cgroup.cpp
++
++Abstract:
++ Read the memory limit for the current process
++--*/
++#ifdef __FreeBSD__
++#define _WITH_GETLINE
++#endif
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#if defined(__APPLE__) || defined(__FreeBSD__)
++#include
++#include
++#else
++#include
++#endif
++#include
++#include
++
++#ifndef SIZE_T_MAX
++# define SIZE_T_MAX (~(size_t)0)
++#endif
++
++#define CGROUP2_SUPER_MAGIC 0x63677270
++#define TMPFS_MAGIC 0x01021994
++
++#define PROC_MOUNTINFO_FILENAME "/proc/self/mountinfo"
++#define PROC_CGROUP_FILENAME "/proc/self/cgroup"
++#define PROC_STATM_FILENAME "/proc/self/statm"
++#define CGROUP1_MEMORY_LIMIT_FILENAME "/memory.limit_in_bytes"
++#define CGROUP2_MEMORY_LIMIT_FILENAME "/memory.max"
++#define CGROUP_MEMORY_STAT_FILENAME "/memory.stat"
++
++static void initialize(void);
++static gboolean readMemoryValueFromFile(const char *, guint64 *);
++static gboolean getPhysicalMemoryLimit(guint64 *);
++static gboolean getPhysicalMemoryUsage(size_t *);
++static int findCGroupVersion(void);
++static gboolean isCGroup1MemorySubsystem(const char *);
++static char *findCGroupPath(gboolean (*is_subsystem)(const char *));
++static void findHierarchyMount(gboolean (*is_subsystem)(const char *), char **, char **);
++static char *findCGroupPathForSubsystem(gboolean (*is_subsystem)(const char *));
++static gboolean getCGroupMemoryLimit(guint64 *, const char *);
++static gboolean getCGroupMemoryUsage(size_t *);
++static size_t getPhysicalMemoryTotal(guint64);
++
++size_t getRestrictedPhysicalMemoryLimit(void);
++gboolean getPhysicalMemoryUsed(size_t *);
++size_t getPhysicalMemoryAvail(void);
++
++// the cgroup version number or 0 to indicate cgroups are not found or not enabled
++static int s_cgroup_version;
++
++static char *s_memory_cgroup_path = NULL;
++
++static const char *s_mem_stat_key_names[4];
++static size_t s_mem_stat_key_lengths[4];
++static size_t s_mem_stat_n_keys = 0;
++static long pageSize;
++
++/**
++ * @initialize
++ *
++ * Initialize variables used by the calculation routines.
++ */
++static void
++initialize()
++{
++ s_cgroup_version = findCGroupVersion();
++ s_memory_cgroup_path = findCGroupPath(s_cgroup_version == 1 ? &isCGroup1MemorySubsystem : NULL);
++
++ if (s_cgroup_version == 1) {
++ s_mem_stat_n_keys = 4;
++ s_mem_stat_key_names[0] = "total_inactive_anon ";
++ s_mem_stat_key_names[1] = "total_active_anon ";
++ s_mem_stat_key_names[2] = "total_dirty ";
++ s_mem_stat_key_names[3] = "total_unevictable ";
++ } else {
++ s_mem_stat_n_keys = 3;
++ s_mem_stat_key_names[0] = "anon ";
++ s_mem_stat_key_names[1] = "file_dirty ";
++ s_mem_stat_key_names[2] = "unevictable ";
++ }
++
++ for (size_t i = 0; i < s_mem_stat_n_keys; i++)
++ s_mem_stat_key_lengths[i] = strlen(s_mem_stat_key_names[i]);
++
++ pageSize = sysconf(_SC_PAGE_SIZE);
++}
++
++/**
++ * @readMemoryValueFromFile
++ *
++ * @param[in] filename - name of file containing value
++ * @param[out] val - pointer to the result area
++ * @returns True or False depending if value was found
++ *
++ * Read a value from a specified /sys/fs/cgroup/memory file
++ */
++static gboolean
++readMemoryValueFromFile(const char* filename, guint64* val)
++{
++ gboolean result = FALSE;
++ char *line = NULL;
++ size_t lineLen = 0;
++ char *endptr = NULL;
++ guint64 num = 0, multiplier;
++ FILE *file = NULL;
++
++ if (val == NULL) {
++ file = fopen(filename, "r");
++ if (file != NULL) {
++ if (getline(&line, &lineLen, file) != -1) {
++ errno = 0;
++ num = strtoull(line, &endptr, 0);
++ if (line != endptr && errno == 0) {
++ multiplier = 1;
++
++ switch (*endptr)
++ {
++ case 'g':
++ case 'G':
++ multiplier = 1024;
++ case 'm':
++ case 'M':
++ multiplier = multiplier * 1024;
++ case 'k':
++ case 'K':
++ multiplier = multiplier * 1024;
++ }
++
++ *val = num * multiplier;
++ result = TRUE;
++ if (*val / multiplier != num)
++ result = FALSE;
++ }
++ }
++ }
++ }
++
++ if (file)
++ fclose(file);
++ free(line);
++ return result;
++}
++
++/**
++ * @getPhysicalMemoryLimit
++ *
++ * @param[out] val - pointer to the result area
++ * @returns True or False depending if a limit was found
++ *
++ * Interrogate the cgroup memory values to determine if there's
++ * a limit on physical memory.
++ */
++static gboolean
++getPhysicalMemoryLimit(guint64 *val)
++{
++ if (s_mem_stat_n_keys == 0)
++ initialize();
++
++ if (s_cgroup_version == 0)
++ return FALSE;
++ else if (s_cgroup_version == 1)
++ return getCGroupMemoryLimit(val, CGROUP1_MEMORY_LIMIT_FILENAME);
++ else if (s_cgroup_version == 2)
++ return getCGroupMemoryLimit(val, CGROUP2_MEMORY_LIMIT_FILENAME);
++ else {
++ g_assert(!"Unknown cgroup version.");
++ return FALSE;
++ }
++}
++
++/**
++ * @getPhysicalMemoryUsage
++ *
++ * @param[out] val - pointer to the result area
++ * @returns True or False depending if a usage value was found
++ *
++ * Interrogate the cgroup memory values to determine how much
++ * memory is in use.
++ */
++static gboolean
++getPhysicalMemoryUsage(size_t *val)
++{
++ if (s_cgroup_version == 0)
++ return FALSE;
++ else if (s_cgroup_version == 1)
++ return getCGroupMemoryUsage(val);
++ else if (s_cgroup_version == 2)
++ return getCGroupMemoryUsage(val);
++ else {
++ g_assert(!"Unknown cgroup version.");
++ return FALSE;
++ }
++}
++
++/**
++ * @findGroupVersion
++ *
++ * @returns cgroup version
++ *
++ * Inspect the /sys/fs/cgroup hierachy to determine what version of
++ * group we are using
++ */
++static int
++findCGroupVersion()
++{
++ // It is possible to have both cgroup v1 and v2 enabled on a system.
++ // Most non-bleeding-edge Linux distributions fall in this group. We
++ // look at the file system type of /sys/fs/cgroup to determine which
++ // one is the default. For more details, see:
++ // https://systemd.io/CGROUP_DELEGATION/#three-different-tree-setups-
++ // We dont care about the difference between the "legacy" and "hybrid"
++ // modes because both of those involve cgroup v1 controllers managing
++ // resources.
++
++
++ struct statfs stats;
++ int result = statfs("/sys/fs/cgroup", &stats);
++ if (result != 0)
++ return 0;
++
++ switch (stats.f_type) {
++ case TMPFS_MAGIC: return 1;
++ case CGROUP2_SUPER_MAGIC: return 2;
++ default:
++ g_assert(!"Unexpected file system type for /sys/fs/cgroup");
++ return 0;
++ }
++}
++
++/**
++ * @isCGroup1MemorySubsystem
++ *
++ * @param[in] strTok - Token for comparison
++ * @returns True if token matches "memory"
++ *
++ * Check if we've found the memory component of /sys/fs/cgroup
++ */
++static gboolean
++isCGroup1MemorySubsystem(const char *strTok)
++{
++ return strcmp("memory", strTok) == 0;
++}
++
++/**
++ * @findCGroupPath
++ *
++ * @param[in] is_subsystem - Function used to compare tokens
++ * @returns Path to cgroup
++ *
++ * Navigate the /sys/fs/cgroup to try and find the correct cgroup path
++ */
++static char *
++findCGroupPath(gboolean (*is_subsystem)(const char *))
++{
++ char *cgroup_path = NULL;
++ char *hierarchy_mount = NULL;
++ char *hierarchy_root = NULL;
++ char *cgroup_path_relative_to_mount = NULL;
++ size_t common_path_prefix_len;
++
++ findHierarchyMount(is_subsystem, &hierarchy_mount, &hierarchy_root);
++ if (hierarchy_mount != NULL && hierarchy_root != NULL) {
++
++ cgroup_path_relative_to_mount = findCGroupPathForSubsystem(is_subsystem);
++ if (cgroup_path_relative_to_mount != NULL) {
++
++ cgroup_path = (char*)malloc(strlen(hierarchy_mount) + strlen(cgroup_path_relative_to_mount) + 1);
++ if (cgroup_path != NULL) {
++
++ strcpy(cgroup_path, hierarchy_mount);
++ // For a host cgroup, we need to append the relative path.
++ // The root and cgroup path can share a common prefix of the path that should not be appended.
++ // Example 1 (docker):
++ // hierarchy_mount: /sys/fs/cgroup/cpu
++ // hierarchy_root: /docker/87ee2de57e51bc75175a4d2e81b71d162811b179d549d6601ed70b58cad83578
++ // cgroup_path_relative_to_mount: /docker/87ee2de57e51bc75175a4d2e81b71d162811b179d549d6601ed70b58cad83578/my_named_cgroup
++ // append do the cgroup_path: /my_named_cgroup
++ // final cgroup_path: /sys/fs/cgroup/cpu/my_named_cgroup
++ //
++ // Example 2 (out of docker)
++ // hierarchy_mount: /sys/fs/cgroup/cpu
++ // hierarchy_root: /
++ // cgroup_path_relative_to_mount: /my_named_cgroup
++ // append do the cgroup_path: /my_named_cgroup
++ // final cgroup_path: /sys/fs/cgroup/cpu/my_named_cgroup
++ common_path_prefix_len = strlen(hierarchy_root);
++ if ((common_path_prefix_len == 1) ||
++ (strncmp(hierarchy_root, cgroup_path_relative_to_mount, common_path_prefix_len) != 0))
++ common_path_prefix_len = 0;
++
++ g_assert((cgroup_path_relative_to_mount[common_path_prefix_len] == '/') ||
++ (cgroup_path_relative_to_mount[common_path_prefix_len] == '\0'));
++
++ strcat(cgroup_path, cgroup_path_relative_to_mount + common_path_prefix_len);
++ }
++ }
++ }
++
++ free(hierarchy_mount);
++ free(hierarchy_root);
++ free(cgroup_path_relative_to_mount);
++ return cgroup_path;
++}
++
++/**
++ * @findHierarchyMount
++ *
++ * @param[in] is_subsystem - Comparison function
++ * @param[out] pmountpath -
++ * @param[out] pmountroot -
++ *
++ * Check the /proc filesystem to determine the root and mount path of /sys/fs/cgroup data
++ */
++static void
++findHierarchyMount(gboolean (*is_subsystem)(const char *), char** pmountpath, char** pmountroot)
++{
++ char *line = NULL;
++ size_t lineLen = 0, maxLineLen = 0;
++ char *filesystemType = NULL;
++ char *options = NULL;
++ char *mountpath = NULL;
++ char *mountroot = NULL;
++
++ FILE *mountinfofile = fopen(PROC_MOUNTINFO_FILENAME, "r");
++ if (mountinfofile == NULL)
++ goto done;
++
++ while (getline(&line, &lineLen, mountinfofile) != -1) {
++ if (filesystemType == NULL || lineLen > maxLineLen) {
++ free(filesystemType);
++ filesystemType = NULL;
++ free(options);
++ options = NULL;
++ filesystemType = (char*)malloc(lineLen+1);
++ if (filesystemType == NULL)
++ goto done;
++ options = (char*)malloc(lineLen+1);
++ if (options == NULL)
++ goto done;
++ maxLineLen = lineLen;
++ }
++
++ char *separatorChar = strstr(line, " - ");
++
++ // See man page of proc to get format for /proc/self/mountinfo file
++ int sscanfRet = sscanf(separatorChar,
++ " - %s %*s %s",
++ filesystemType,
++ options);
++ if (sscanfRet != 2) {
++ g_assert(!"Failed to parse mount info file contents with sscanf.");
++ goto done;
++ }
++
++ if (strncmp(filesystemType, "cgroup", 6) == 0) {
++ gboolean isSubsystemMatch = is_subsystem == NULL;
++ if (!isSubsystemMatch) {
++ char *context = NULL;
++ char *strTok = strtok_r(options, ",", &context);
++ while (!isSubsystemMatch && strTok != NULL)
++ {
++ isSubsystemMatch = is_subsystem(strTok);
++ strTok = strtok_r(NULL, ",", &context);
++ }
++ }
++ if (isSubsystemMatch) {
++ mountpath = (char*)malloc(lineLen+1);
++ if (mountpath == NULL)
++ goto done;
++ mountroot = (char*)malloc(lineLen+1);
++ if (mountroot == NULL)
++ goto done;
++
++ sscanfRet = sscanf(line,
++ "%*s %*s %*s %s %s ",
++ mountroot,
++ mountpath);
++ if (sscanfRet != 2)
++ g_assert(!"Failed to parse mount info file contents with sscanf.");
++
++ // assign the output arguments and clear the locals so we don't free them.
++ *pmountpath = mountpath;
++ *pmountroot = mountroot;
++ mountpath = mountroot = NULL;
++ }
++ }
++ }
++done:
++ free(mountpath);
++ free(mountroot);
++ free(filesystemType);
++ free(options);
++ free(line);
++ if (mountinfofile)
++ fclose(mountinfofile);
++}
++
++/**
++ * @findCGroupPathForSubsystem
++ *
++ * @param[in] is_subsystem - Comparison function
++ * @returns cgroup path for the memory subsystem
++ *
++ * Check the /proc filesystem to determine the root and mount path of /sys/fs/cgroup data
++ */
++static char *
++findCGroupPathForSubsystem(gboolean (*is_subsystem)(const char *))
++{
++ char *line = NULL;
++ size_t lineLen = 0;
++ size_t maxLineLen = 0;
++ char *subsystem_list = NULL;
++ char *cgroup_path = NULL;
++ gboolean result = FALSE;
++
++ FILE *cgroupfile = fopen(PROC_CGROUP_FILENAME, "r");
++ if (cgroupfile == NULL)
++ goto done;
++
++ while (!result && getline(&line, &lineLen, cgroupfile) != -1) {
++ if (subsystem_list == NULL || lineLen > maxLineLen) {
++ free(subsystem_list);
++ subsystem_list = NULL;
++ free(cgroup_path);
++ cgroup_path = NULL;
++ subsystem_list = (char*)malloc(lineLen+1);
++ if (subsystem_list == NULL)
++ goto done;
++ cgroup_path = (char*)malloc(lineLen+1);
++ if (cgroup_path == NULL)
++ goto done;
++ maxLineLen = lineLen;
++ }
++
++ if (s_cgroup_version == 1) {
++ // See man page of proc to get format for /proc/self/cgroup file
++ int sscanfRet = sscanf(line,
++ "%*[^:]:%[^:]:%s",
++ subsystem_list,
++ cgroup_path);
++ if (sscanfRet != 2) {
++ g_assert(!"Failed to parse cgroup info file contents with sscanf.");
++ goto done;
++ }
++
++ char* context = NULL;
++ char* strTok = strtok_r(subsystem_list, ",", &context);
++ while (strTok != NULL) {
++ if (is_subsystem(strTok)) {
++ result = TRUE;
++ break;
++ }
++ strTok = strtok_r(NULL, ",", &context);
++ }
++ } else if (s_cgroup_version == 2) {
++ // See https://www.kernel.org/doc/Documentation/cgroup-v2.txt
++ // Look for a "0::/some/path"
++ int sscanfRet = sscanf(line,
++ "0::%s",
++ cgroup_path);
++ if (sscanfRet == 1)
++ {
++ result = TRUE;
++ }
++ } else {
++ g_assert(!"Unknown cgroup version in mountinfo.");
++ goto done;
++ }
++ }
++done:
++ free(subsystem_list);
++ if (!result) {
++ free(cgroup_path);
++ cgroup_path = NULL;
++ }
++ free(line);
++ if (cgroupfile)
++ fclose(cgroupfile);
++ return cgroup_path;
++}
++
++/**
++ * @getCGroupMemoryLimit
++ *
++ * @param[out] val - Memory limit
++ * @param[in] filename - name of file from which to extract limit
++ * @returns True if value found
++ *
++ * Extract memory limit from specified /sys/fs/cgroup/memory file
++ */
++static gboolean
++getCGroupMemoryLimit(guint64 *val, const char *filename)
++{
++ if (s_memory_cgroup_path == NULL)
++ return FALSE;
++
++ char* mem_limit_filename = NULL;
++ if (asprintf(&mem_limit_filename, "%s%s", s_memory_cgroup_path, filename) < 0)
++ return FALSE;
++
++ gboolean result = readMemoryValueFromFile(mem_limit_filename, val);
++ free(mem_limit_filename);
++ return result;
++}
++
++/**
++ * @getCGroupMemoryUsage
++ *
++ * @param[out] val - Memory limit
++ * @returns True if value found
++ *
++ * Extract memory usage from /sys/fs/cgroup/memory.stat file
++ */
++static gboolean
++getCGroupMemoryUsage(size_t *val)
++{
++ if (s_memory_cgroup_path == NULL)
++ return FALSE;
++
++ char *stat_filename = NULL;
++ if (asprintf(&stat_filename, "%s%s", s_memory_cgroup_path, CGROUP_MEMORY_STAT_FILENAME) < 0)
++ return FALSE;
++
++ FILE *stat_file = fopen(stat_filename, "r");
++ free(stat_filename);
++ if (stat_file == NULL)
++ return FALSE;
++
++ char *line = NULL;
++ size_t lineLen = 0;
++ size_t readValues = 0;
++ char *endptr;
++
++ *val = 0;
++ while (getline(&line, &lineLen, stat_file) != -1 && readValues < s_mem_stat_n_keys) {
++ for (size_t i = 0; i < s_mem_stat_n_keys; i++) {
++ if (strncmp(line, s_mem_stat_key_names[i], s_mem_stat_key_lengths[i]) == 0) {
++ errno = 0;
++ const char *startptr = line + s_mem_stat_key_lengths[i];
++ *val += strtoll(startptr, &endptr, 10);
++ if (endptr != startptr && errno == 0)
++ readValues++;
++
++ break;
++ }
++ }
++ }
++
++ fclose(stat_file);
++ free(line);
++
++ if (readValues == s_mem_stat_n_keys)
++ return TRUE;
++
++ return FALSE;
++}
++
++/**
++ * @getRestrictedPhysicalMemoryLimit
++ *
++ * @returns Physical memory limit
++ *
++ * Determine if there are any limits on memory and return the value
++ * if so. Zero represents no limit.
++ */
++size_t
++getRestrictedPhysicalMemoryLimit()
++{
++ guint64 physical_memory_limit = 0;
++
++ if (s_mem_stat_n_keys == 0)
++ initialize();
++
++ if (!getPhysicalMemoryLimit(&physical_memory_limit))
++ return 0;
++
++ // If there's no memory limit specified on the container this
++ // actually returns 0x7FFFFFFFFFFFF000 (2^63-1 rounded down to
++ // 4k which is a common page size). So we know we are not
++ // running in a memory restricted environment.
++ if (physical_memory_limit > 0x7FFFFFFF00000000)
++ return 0;
++
++ return (getPhysicalMemoryTotal(physical_memory_limit));
++}
++
++/**
++ * @getPhysicalMemoryTotal
++ *
++ * @param[in] physical_memory_limit - The max memory on the system
++ * @returns Physical memory total
++ *
++ * Check the input limit against any system limits or actual memory on system
++ */
++static size_t
++getPhysicalMemoryTotal(size_t physical_memory_limit)
++{
++ struct rlimit curr_rlimit;
++ size_t rlimit_soft_limit = (size_t)RLIM_INFINITY;
++ if (getrlimit(RLIMIT_AS, &curr_rlimit) == 0)
++ rlimit_soft_limit = curr_rlimit.rlim_cur;
++ physical_memory_limit = (physical_memory_limit < rlimit_soft_limit) ?
++ physical_memory_limit : rlimit_soft_limit;
++
++ // Ensure that limit is not greater than real memory size
++ long pages = sysconf(_SC_PHYS_PAGES);
++ if (pages != -1) {
++ if (pageSize != -1) {
++ physical_memory_limit = (physical_memory_limit < (size_t)pages * pageSize) ?
++ physical_memory_limit : (size_t)pages * pageSize;
++ }
++ }
++
++ if (physical_memory_limit > ULONG_MAX) {
++ // It is observed in practice when the memory is unrestricted, Linux control
++ // group returns a physical limit that is bigger than the address space
++ return ULONG_MAX;
++ } else
++ return (size_t)physical_memory_limit;
++}
++
++/**
++ * @getPhysicalMemoryUsed
++ *
++ * @param[out] val - pointer to the memory usage value
++ * @returns True if we are able to determine usage
++ *
++ * Determine the amount of memory in use
++ */
++gboolean
++getPhysicalMemoryUsed(size_t *val)
++{
++ gboolean result = FALSE;
++ size_t linelen;
++ char *line = NULL;
++
++ if (val == NULL)
++ return FALSE;
++
++ // Linux uses cgroup usage to trigger oom kills.
++ if (getPhysicalMemoryUsage(val))
++ return TRUE;
++
++ // process resident set size.
++ FILE* file = fopen(PROC_STATM_FILENAME, "r");
++ if (file != NULL && getline(&line, &linelen, file) != -1) {
++ char* context = NULL;
++ char* strTok = strtok_r(line, " ", &context);
++ strTok = strtok_r(NULL, " ", &context);
++
++ errno = 0;
++ *val = strtoull(strTok, NULL, 0);
++ if (errno == 0) {
++ if (pageSize != -1) {
++ *val = *val * pageSize;
++ result = TRUE;
++ }
++ }
++ }
++
++ if (file)
++ fclose(file);
++ free(line);
++ return result;
++}
++
++/**
++ * @getPhysicalMemoryAvail
++ *
++ * @returns Amount of memory available
++ *
++ * Determine the amount of memory available by examininig any limits and
++ * checking what memory is in use.
++ */
++size_t
++getPhysicalMemoryAvail()
++{
++ size_t max, used, avail, sysAvail;
++
++ max = getRestrictedPhysicalMemoryLimit();
++
++ if (max == 0)
++ max = getPhysicalMemoryTotal(ULONG_MAX);
++
++ if (getPhysicalMemoryUsed(&used))
++ avail = max - used;
++ else
++ avail = max;
++
++ sysAvail = sysconf(_SC_AVPHYS_PAGES) * pageSize;
++ return (avail < sysAvail ? avail : sysAvail);
++}
+Index: a/src/mono/mono/utils/CMakeLists.txt
+===================================================================
+--- a/src/mono/mono/utils/CMakeLists.txt
++++ b/src/mono/mono/utils/CMakeLists.txt
+@@ -32,6 +32,7 @@ set(utils_common_sources
+ mono-sha1.c
+ mono-logger.c
+ mono-logger-internals.h
++ mono-cgroup.c
+ mono-codeman.c
+ mono-counters.c
+ mono-compiler.h
diff --git a/runtime-no-shared-compilation.patch b/runtime-no-shared-compilation.patch
new file mode 100644
index 0000000..fefe89e
--- /dev/null
+++ b/runtime-no-shared-compilation.patch
@@ -0,0 +1,12 @@
+Index: source-build-tarball/src/runtime.826f81a11ad17f415668fe1cb934bdaf00d36ea2/Directory.Build.props
+===================================================================
+--- a/Directory.Build.props
++++ b/Directory.Build.props
+@@ -7,6 +7,7 @@
+ For offline builds we still set OfficialBuildId but we need to build all the packages for a single
+ leg only, so we also take DotNetBuildFromSource into account. -->
+ true
++ false
+
+
+
diff --git a/sdk-enable-preview.patch b/sdk-enable-preview.patch
new file mode 100644
index 0000000..7a452a2
--- /dev/null
+++ b/sdk-enable-preview.patch
@@ -0,0 +1,10 @@
+--- a/eng/SourceBuild.props
++++ b/eng/SourceBuild.props
+@@ -8,6 +8,7 @@
+
+
+ $(InnerBuildArgs) /p:Projects="$(InnerSourceBuildRepoRoot)\source-build.slnf"
++ $(InnerBuildArgs) /p:EnablePreviewFeatures=true
+
+
+
diff --git a/sdk-telemetry-optout.patch b/sdk-telemetry-optout.patch
new file mode 100644
index 0000000..d6e6464
--- /dev/null
+++ b/sdk-telemetry-optout.patch
@@ -0,0 +1,18 @@
+diff --git a/src/Cli/dotnet/Program.cs b/src/Cli/dotnet/Program.cs
+index de1ebb9e6..6bbf479de 100644
+--- a/src/Cli/dotnet/Program.cs
++++ b/src/Cli/dotnet/Program.cs
+@@ -28,6 +28,13 @@ public class Program
+
+ public static int Main(string[] args)
+ {
++ // opt out of telemetry by default if the env var is unset
++ string telemetryValue = Environment.GetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT");
++ if (String.IsNullOrEmpty(telemetryValue))
++ {
++ Environment.SetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT", "1");
++ }
++
+ DebugHelper.HandleDebugSwitch(ref args);
+
+ // Capture the current timestamp to calculate the host overhead.
diff --git a/source-build-reference-packages-no-shared-compilation.patch b/source-build-reference-packages-no-shared-compilation.patch
new file mode 100644
index 0000000..b2932d9
--- /dev/null
+++ b/source-build-reference-packages-no-shared-compilation.patch
@@ -0,0 +1,12 @@
+Index: a/src/Directory.Build.props
+===================================================================
+--- a/src/Directory.Build.props
++++ b/src/Directory.Build.props
+@@ -9,6 +9,7 @@
+
+ true
+ true
++ false
+