diff --git a/app/build.gradle b/app/build.gradle index 6d20a85..f22e573 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.vectras.vm" minSdk minApi targetSdk targetApi - versionCode 112 - versionName "4.0.8" + versionCode 113 + versionName "4.0.9" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true @@ -68,7 +68,14 @@ android { } buildToolsVersion '36.1.0' - ndkVersion '21' + ndkVersion '27.3.13750724' + + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } lint { abortOnError false diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..0eedb60 --- /dev/null +++ b/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.22.1) +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384") +project("native_helper") + +add_library(native_helper SHARED cpu-info.cpp) + +find_library(log-lib log) +target_link_libraries(native_helper ${log-lib}) \ No newline at end of file diff --git a/app/src/main/cpp/cpu-info.cpp b/app/src/main/cpp/cpu-info.cpp new file mode 100644 index 0000000..1ab37a5 --- /dev/null +++ b/app/src/main/cpp/cpu-info.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +#if defined(__aarch64__) + #include +#elif defined(__x86_64__) + #include +#endif + +extern "C" { + JNIEXPORT jint JNICALL + Java_com_vectras_vm_utils_CpuHelper_getCpuCores(JNIEnv* env, jobject obj) { + return sysconf(_SC_NPROCESSORS_CONF); + } + + JNIEXPORT jint JNICALL + Java_com_vectras_vm_utils_CpuHelper_getActiveCpuCores(JNIEnv* env, jobject obj) { + return sysconf(_SC_NPROCESSORS_ONLN); + } + + JNIEXPORT jint JNICALL + Java_com_vectras_vm_utils_CpuHelper_getCpuThreads(JNIEnv* env, jobject obj) { + unsigned int threads = std::thread::hardware_concurrency(); + return (threads > 0) ? (jint)threads : 1; + } + + JNIEXPORT jint JNICALL + Java_com_vectras_vm_utils_CpuHelper_check64Bit(JNIEnv* env, jobject obj) { + // 1: 64-bit, 0: 32-bit, -1: Unknown or error. + + #if defined(__aarch64__) + unsigned long hwcaps = getauxval(AT_HWCAP); + return (hwcaps > 0) ? 1 : 0; + #elif defined(__x86_64__) + unsigned int eax, ebx, ecx, edx; + if (__get_cpuid(0x80000001, &eax, &ebx, &ecx, &edx)) { + return (edx & (1 << 29)) ? 1 : 0; + } + return -1; // Failed to call CPUID. + #endif + + return 0; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/ExportRomActivity.java b/app/src/main/java/com/vectras/vm/ExportRomActivity.java index dd89e75..ba1eebc 100644 --- a/app/src/main/java/com/vectras/vm/ExportRomActivity.java +++ b/app/src/main/java/com/vectras/vm/ExportRomActivity.java @@ -128,6 +128,8 @@ public class ExportRomActivity extends AppCompatActivity { } vmConfigMap.put("cpu", current.cpu); + vmConfigMap.put("cores", current.cores); + vmConfigMap.put("threads", current.threads); boolean isUsingDiskInQemuExtraParams = VMManager.isHaveADisk(current.itemExtra); diff --git a/app/src/main/java/com/vectras/vm/StartVM.java b/app/src/main/java/com/vectras/vm/StartVM.java index 6a29f23..20f51f0 100644 --- a/app/src/main/java/com/vectras/vm/StartVM.java +++ b/app/src/main/java/com/vectras/vm/StartVM.java @@ -11,6 +11,7 @@ import com.vectras.vm.creator.VMCreatorSelector; import com.vectras.vm.main.vms.DataMainRoms; import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.setupwizard.SetupFeatureCore; +import com.vectras.vm.utils.CpuHelper; import com.vectras.vm.utils.FileUtils; import java.io.File; @@ -43,11 +44,27 @@ public class StartVM { String extraParams = vmData.itemExtra; + String cpuParams = ""; + String cpu = Objects.requireNonNull(VMCreatorSelector.getCpu(activity, MainSettingsManager.getArch(activity), vmData.cpu).get("value")).toString(); - if (!cpu.isEmpty() && !extraParams.contains("-cpu")) { - extraParams = "-cpu " + cpu + " " + extraParams; + if (!cpu.isEmpty() && !extraParams.contains("-cpu ")) { + cpuParams = " -cpu " + cpu; } + CpuHelper cpuHelper = new CpuHelper(); + + int cores = Integer.parseInt(Objects.requireNonNull(VMCreatorSelector.getCpuCore(MainSettingsManager.getArch(activity), vmConfigs.cores).get("value")).toString()); + int threads = Math.max(1, vmConfigs.threads + 1); + if (!extraParams.contains("-smp ")) { + if (cores * threads > cpuHelper.getCpuThreads()) { + cpuParams += " -smp sockets=1,cores=" + cpuHelper.getCpuCores() + ",threads=1"; + } else { + cpuParams += " -smp sockets=1,cores=" + cores + ",threads=" + threads; + } + } + + if (!cpuParams.isEmpty()) extraParams = cpuParams + " " + extraParams; + String bootFromParams = Objects.requireNonNull(VMCreatorSelector.getBootFrom(activity, vmData.bootFrom).get("value")).toString(); String showBootMenuParams = vmData.isShowBootMenu ? "menu=on" : ""; String bootParams = ""; diff --git a/app/src/main/java/com/vectras/vm/creator/ListManager.java b/app/src/main/java/com/vectras/vm/creator/ListManager.java index 23e68dd..ff00b91 100644 --- a/app/src/main/java/com/vectras/vm/creator/ListManager.java +++ b/app/src/main/java/com/vectras/vm/creator/ListManager.java @@ -4,6 +4,7 @@ import android.content.Context; import com.vectras.qemu.MainSettingsManager; import com.vectras.vm.R; +import com.vectras.vm.utils.CpuHelper; import java.util.ArrayList; import java.util.HashMap; @@ -113,6 +114,37 @@ public class ListManager { return list; } + public static ArrayList> cores(String arch) { + ArrayList> list = new ArrayList<>(); + + if (arch.equals(MainSettingsManager.PPC_ARCH)) { + putToList(list, "1", "1"); + putToList(list, "2", "2"); + } else { + CpuHelper cpuHelper = new CpuHelper(); + int cores = cpuHelper.getCpuCores(); + int addedCore = 1; + while (addedCore < cores + 1 && addedCore <= 8) { + if (addedCore == 1 || addedCore % 2 == 0) + putToList(list, String.valueOf(addedCore), String.valueOf(addedCore)); + addedCore++; + } + } + + return list; + } + + public static ArrayList> threads(String arch) { + ArrayList> list = new ArrayList<>(); + putToList(list, "1", "1"); + + if (!(arch.equals(MainSettingsManager.ARM64_ARCH) + || arch.equals(MainSettingsManager.PPC_ARCH))) + putToList(list, "2", "2"); + + return list; + } + public static void putToList ( ArrayList> listMap, diff --git a/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java b/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java index ac19988..15e586f 100644 --- a/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java +++ b/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java @@ -38,6 +38,7 @@ import com.vectras.vm.databinding.DialogProgressStyleBinding; import com.vectras.vm.main.MainActivity; import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.utils.ClipboardUltils; +import com.vectras.vm.utils.CpuHelper; import com.vectras.vm.utils.DeviceUtils; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; @@ -78,6 +79,8 @@ public class VMCreatorActivity extends AppCompatActivity { private String thumbnailPath = ""; private String vmID = VMManager.idGenerator(); private int cpu = 0; + private int cores = 0; + private int threads = 0; private boolean isShowBootMenu = false; private boolean isUseLocalTime = true; private boolean isUseUefi = false; @@ -301,6 +304,16 @@ public class VMCreatorActivity extends AppCompatActivity { binding.sbvCpu.setSubtitle(name); }))); + binding.sbvCore.setOnClickListener(v -> VMCreatorSelector.cpuCore(this, MainSettingsManager.getArch(this), cores, ((position, name, value) -> { + cores = position; + binding.sbvCore.setSubtitle(name); + }))); + + binding.sbvThread.setOnClickListener(v -> VMCreatorSelector.cpuThread(this, MainSettingsManager.getArch(this), threads, ((position, name, value) -> { + threads = position; + binding.sbvThread.setSubtitle(name); + }))); + binding.sbvBootfrom.setOnClickListener(v -> VMCreatorSelector.bootFrom(this, bootFrom, ((position, name, value) -> { bootFrom = position; binding.sbvBootfrom.setSubtitle(name); @@ -638,6 +651,12 @@ public class VMCreatorActivity extends AppCompatActivity { cpu = current.cpu; binding.sbvCpu.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpu(this, MainSettingsManager.getArch(this), current.cpu).get("name")).toString()); + cores = current.cores; + binding.sbvCore.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpuCore(MainSettingsManager.getArch(this), cores).get("value")).toString()); + + threads = current.threads; + binding.sbvThread.setSubtitle(String.valueOf(threads + 1)); + bootFrom = current.bootFrom; binding.sbvBootfrom.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getBootFrom(this, current.bootFrom).get("name")).toString()); isShowBootMenu = current.isShowBootMenu; @@ -669,21 +688,35 @@ public class VMCreatorActivity extends AppCompatActivity { defQemuParams = switch (MainSettingsManager.getArch(this)) { case "ARM64" -> "-M virt,virtualization=true -accel tcg,thread=multi -net nic,model=e1000 -net user -device nec-usb-xhci -device usb-kbd -device usb-mouse -device VGA"; - case "PPC" -> "-M mac99 -accel tcg,thread=multi -smp 1"; + case "PPC" -> "-M mac99 -accel tcg,thread=multi"; default -> - "-M pc -accel tcg,thread=multi -smp 4 -vga std -netdev user,id=usernet -device e1000,netdev=usernet -usb -device usb-tablet"; + "-M pc -accel tcg,thread=multi -vga std -netdev user,id=usernet -device e1000,netdev=usernet -usb -device usb-tablet"; }; } else { defQemuParams = switch (MainSettingsManager.getArch(this)) { case "ARM64" -> "-M virt -net nic,model=e1000 -net user -device nec-usb-xhci -device usb-kbd -device usb-mouse -device VGA"; - case "PPC" -> "-M mac99 -smp 1"; + case "PPC" -> "-M mac99 1"; default -> - "-M pc -smp 4 -vga std -netdev user,id=usernet -device e1000,netdev=usernet -usb -device usb-tablet"; + "-M pc -vga std -netdev user,id=usernet -device e1000,netdev=usernet -usb -device usb-tablet"; }; } binding.title.setText(getString(R.string.new_vm)); binding.qemu.setText(defQemuParams); + + String currentArch = MainSettingsManager.getArch(this); + + if (currentArch.equals(MainSettingsManager.X86_64_ARCH)) { + cores = Math.min(1, VMCreatorSelector.getCpuCorePosition(new CpuHelper().getCpuCores() - 1)); + binding.sbvCore.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpuCore(currentArch, cores).get("value")).toString()); + } else if (currentArch.equals(MainSettingsManager.ARM64_ARCH)) { + cores = Math.min(2, VMCreatorSelector.getCpuCorePosition(new CpuHelper().getCpuCores() - 1)); + binding.sbvCore.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpuCore(currentArch, cores).get("value")).toString()); + } else { + binding.sbvCore.setSubtitle("1"); + } + + binding.sbvThread.setSubtitle("1"); } private void checkVMID() { @@ -802,6 +835,8 @@ public class VMCreatorActivity extends AppCompatActivity { current.itemName = Objects.requireNonNull(binding.title.getText()).toString(); current.itemIcon = thumbnailPath; current.cpu = cpu; + current.cores = cores; + current.threads = threads; current.itemPath = Objects.requireNonNull(binding.drive.getText()).toString(); current.imgCdrom = Objects.requireNonNull(binding.cdrom.getText()).toString(); current.sharedFolder = sharedFolder; diff --git a/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java b/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java index 41940cc..952fea0 100644 --- a/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java +++ b/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java @@ -29,16 +29,34 @@ public class VMCreatorSelector { void onSelected(int position, String name, String value); } + public static void cpu(Activity activity, String arch, int position, SelectorCallback callback) { + showDialog(activity, ListManager.cpus(activity, arch), position, callback, activity.getString(R.string.processor)); + } + public static HashMap getCpu(Context context, String arch, int position) { return ListManager.cpus(context, arch).get(position); } - public static HashMap getBootFrom(Context context, int position) { - return ListManager.bootFrom(context).get(position); + public static void cpuCore(Activity activity, String arch, int position, SelectorCallback callback) { + showDialog(activity, ListManager.cores(arch), position, callback, activity.getString(R.string.core)); } - public static void cpu(Activity activity, String arch, int position, SelectorCallback callback) { - showDialog(activity, ListManager.cpus(activity, arch), position, callback, activity.getString(R.string.processor)); + public static int getCpuCorePosition(int core) { + if (core > 8) return 7; + if (core > 2) return core - 2; + return core - 1; + } + + public static HashMap getCpuCore(String arch, int position) { + return ListManager.cores(arch).get(position); + } + + public static void cpuThread(Activity activity, String arch, int position, SelectorCallback callback) { + showDialog(activity, ListManager.threads(arch), position, callback, activity.getString(R.string.thread)); + } + + public static HashMap getBootFrom(Context context, int position) { + return ListManager.bootFrom(context).get(position); } public static void bootFrom(Activity activity, int position, SelectorCallback callback) { diff --git a/app/src/main/java/com/vectras/vm/main/vms/DataMainRoms.java b/app/src/main/java/com/vectras/vm/main/vms/DataMainRoms.java index bc24369..d279286 100644 --- a/app/src/main/java/com/vectras/vm/main/vms/DataMainRoms.java +++ b/app/src/main/java/com/vectras/vm/main/vms/DataMainRoms.java @@ -4,6 +4,8 @@ import com.google.gson.annotations.SerializedName; public class DataMainRoms { public int cpu = 0; + public int cores = 0; + public int threads = 0; @SerializedName( value = "icon", diff --git a/app/src/main/java/com/vectras/vm/utils/CpuHelper.java b/app/src/main/java/com/vectras/vm/utils/CpuHelper.java new file mode 100644 index 0000000..75f915d --- /dev/null +++ b/app/src/main/java/com/vectras/vm/utils/CpuHelper.java @@ -0,0 +1,16 @@ +package com.vectras.vm.utils; + +public class CpuHelper { + static { + System.loadLibrary("native_helper"); + } + + public native int getCpuCores(); + public native int getActiveCpuCores(); + public native int getCpuThreads(); + public native int check64Bit(); + + public boolean is64Bit() { + return check64Bit() == 1; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/utils/DeviceUtils.java b/app/src/main/java/com/vectras/vm/utils/DeviceUtils.java index 43e4ca8..a6eaeb5 100644 --- a/app/src/main/java/com/vectras/vm/utils/DeviceUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/DeviceUtils.java @@ -67,9 +67,7 @@ public class DeviceUtils { } public static boolean is64bit() { - return Build.SUPPORTED_ABIS[0].contains("64") && - Build.SUPPORTED_64_BIT_ABIS != null && - Build.SUPPORTED_64_BIT_ABIS.length > 0; + return new CpuHelper().is64Bit(); } public static boolean isArm() { return Build.SUPPORTED_ABIS[0].contains("arm"); diff --git a/app/src/main/res/layout/activity_vm_creator.xml b/app/src/main/res/layout/activity_vm_creator.xml index 0fc486b..0e00275 100644 --- a/app/src/main/res/layout/activity_vm_creator.xml +++ b/app/src/main/res/layout/activity_vm_creator.xml @@ -203,6 +203,20 @@ app:title="@string/processor" app:subtitle="@string/defaulttext" /> + + + + diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index aa89071..3661b7a 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -558,6 +558,10 @@ Không thể lưu ở đây, hãy chọn một nơi khác. Bộ xử lý Bo mạch chủ + Nhân + Nhân + Luồng + Luồng Vterm diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ae5fa45..6743b3b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -569,6 +569,10 @@ Cannot save here, please choose another location. Processor Board + Core + Cores + Thread + Threads diff --git a/qemu/11.0.0.sh b/qemu/11.0.0.sh new file mode 100644 index 0000000..86a5f94 --- /dev/null +++ b/qemu/11.0.0.sh @@ -0,0 +1,16 @@ + +#Example for arm64-v8a +apk update +apk add --no-cache bash curl tar rsync flex build-base git meson bison ninja python3 py3-pip libcap-ng-dev glib-dev pixman-dev sdl2-dev sdl2_image-dev sndio alsa-utils alsaconf zlib-dev libaio-dev liburing-dev libcap libcap-ng libssh lzo snappy capstone libcbor libdw gtk+3.0-dev libssh-dev libnfs-dev libseccomp-dev lzo-dev snappy-dev capstone-dev ndctl-libs libcbor-dev libselinux libselinux-dev fuse-dev vde2-dev nmap sndio-dev pipewire-dev alsa-lib-dev vte3-dev keyutils keyutils-dev rng-tools nettle-dev libgcrypt libgcrypt-dev gnutls-dev iasl gcc-objc rust libudev-zero-dev ndctl-dev libu2f-server libu2f-server-dev libbpf libbpf-dev rdma-core-openrc curl-dev linux-pam linux-pam-dev net-snmp-dev jack-dev fuse3 fuse3-dev linux-virt +pip install Ninja Sphinx --break-system-packages +pip install meson --upgrade --break-system-packages +pip install sphinx-rtd-theme --break-system-packages +export CFLAGS="-O2 -march=armv8-a+crc+nosve" +export CXXFLAGS="$CFLAGS" +export LDFLAGS="-march=armv8-a+crc+nosve" +wget https://download.qemu.org/qemu-11.0.0.tar.xz +tar xf qemu-11.0.0.tar.xz +cd qemu-11.0.0 +mkdir ../build && cd ../build +../qemu-11.0.0/configure --enable-gtk --enable-sdl --enable-libssh --enable-cap-ng +ninja -j$(nproc) \ No newline at end of file diff --git a/qemu/9.2.2.sh b/qemu/9.2.2.sh new file mode 100644 index 0000000..0c9b8bd --- /dev/null +++ b/qemu/9.2.2.sh @@ -0,0 +1,23 @@ +#Example for arm64-v8a +apk update +apk add --no-cache bash curl tar rsync flex build-base git meson bison ninja python3 py3-pip libcap-ng-dev glib-dev pixman-dev sdl2-dev sdl2_image-dev sndio alsa-utils alsaconf zlib-dev libaio-dev liburing-dev libcap libcap-ng libssh lzo snappy capstone libcbor libdw gtk+3.0-dev libssh-dev libnfs-dev libseccomp-dev lzo-dev snappy-dev capstone-dev ndctl-libs libcbor-dev libselinux libselinux-dev fuse-dev vde2-dev nmap sndio-dev pipewire-dev alsa-lib-dev vte3-dev keyutils keyutils-dev rng-tools nettle-dev libgcrypt libgcrypt-dev gnutls-dev iasl gcc-objc rust libudev-zero-dev ndctl-dev libu2f-server libu2f-server-dev libbpf libbpf-dev rdma-core-openrc curl-dev linux-pam linux-pam-dev net-snmp-dev jack-dev fuse3 fuse3-dev linux-virt +pip install Ninja Sphinx --break-system-packages +pip install meson --upgrade --break-system-packages +pip install sphinx-rtd-theme --break-system-packages +export CFLAGS="-O2 -march=armv8-a+crc+nosve" +export CXXFLAGS="$CFLAGS" +export LDFLAGS="-march=armv8-a+crc+nosve" +mkdir myqemu && cd myqemu +git clone https://github.com/kjliew/qemu-3dfx.git +cd qemu-3dfx +echo "" > ~/myqemu/qemu-3dfx/qemu-1/hw/mesa/mglmapbo.c +nano ~/myqemu/qemu-3dfx/qemu-1/hw/mesa/mglmapbo.c +wget https://download.qemu.org/qemu-9.2.2.tar.xz +tar xf qemu-9.2.2.tar.xz +cd qemu-9.2.2 +rsync -r ../qemu-0/hw/3dfx ../qemu-1/hw/mesa ./hw/ +patch -p0 -i ../00-qemu92x-mesa-glide.patch +bash ../scripts/sign_commit +mkdir ../build && cd ../build +../qemu-9.2.2/configure --enable-gtk --enable-sdl --enable-libssh --enable-cap-ng +ninja -j$(nproc) \ No newline at end of file diff --git a/qemu/mglmapbo.c b/qemu/mglmapbo.c new file mode 100644 index 0000000..835147e --- /dev/null +++ b/qemu/mglmapbo.c @@ -0,0 +1,12 @@ +//Example for arm64-v8a +//Qemu 9.2.2 +//Fix when building with ARM CPUs +//No need to fix if you don't get errors or don't use Mesa. +//qemu-9.2.2/hw/mesa/mglmapbo.c +//... +#include +//... +//#define _mm_crc32_u64 __builtin_arm_crc32cd +//🠃🠃🠃🠃🠃 +#define _mm_crc32_u64 __crc32cd +//... \ No newline at end of file diff --git a/web/data/UpdateConfig.json b/web/data/UpdateConfig.json index feb65e0..181901c 100644 --- a/web/data/UpdateConfig.json +++ b/web/data/UpdateConfig.json @@ -5,11 +5,11 @@ "url": "https://github.com/xoureldeen/Vectras-VM-Android/releases", "Message": "

4.0.0

\nBugs fixed.", "cancellable": true, - "versionCodeBeta":"111", - "versionNameBeta":"4.0.8", - "versionNameBetas":"4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,4.0.7,4.0.8", + "versionCodeBeta":"113", + "versionNameBeta":"4.0.9", + "versionNameBetas":"4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,4.0.7,4.0.8,4.0.9", "sizeBeta": "45 MB", "urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases", - "MessageBeta": "

4.0.8

Bugs fixed.", + "MessageBeta": "

4.0.9

Bugs fixed.", "cancellableBeta": true }