diff options
-rw-r--r-- | .SRCINFO | 30 | ||||
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | PKGBUILD | 84 | ||||
-rw-r--r-- | dkms.conf.in | 15 | ||||
-rw-r--r-- | efi-patches.txt | 25 | ||||
-rw-r--r-- | unlocker.patch | 62 | ||||
-rw-r--r-- | unlocker.py | 387 | ||||
-rw-r--r-- | vmmon.patch | 1025 | ||||
-rw-r--r-- | vmnet.patch | 590 | ||||
-rw-r--r-- | vmware-networks-configuration.service | 7 | ||||
-rw-r--r-- | vmware-networks.path | 8 | ||||
-rw-r--r-- | vmware-usbarbitrator.path | 8 | ||||
-rw-r--r-- | vmware-workstation.install | 21 |
13 files changed, 1830 insertions, 437 deletions
@@ -1,21 +1,19 @@ pkgbase = vmware-workstation11 pkgdesc = The industry standard for running multiple operating systems as virtual machines on a single Linux PC. pkgver = 11.1.4 - pkgrel = 8 + pkgrel = 30 url = https://www.vmware.com/products/workstation-for-linux.html install = vmware-workstation.install arch = x86_64 license = custom makedepends = sqlite - makedepends = python - makedepends = dmg2dir - makedepends = uefitool-git depends = dkms depends = ncurses5-compat-libs depends = fuse2 depends = gtkmm depends = libcanberra depends = hicolor-icon-theme + depends = libxcrypt-compat depends = fontconfig depends = freetype2 depends = vmware-keymaps @@ -29,6 +27,7 @@ pkgbase = vmware-workstation11 conflicts = vmware-systemd-services options = !strip options = emptydirs + options = !debug backup = etc/vmware/config backup = etc/vmware/hostd/authorization.xml backup = etc/vmware/hostd/config.xml @@ -58,14 +57,12 @@ pkgbase = vmware-workstation11 source = vmware-networks-configuration.service source = vmware-networks.service source = vmware-usbarbitrator.service + source = vmware-networks.path + source = vmware-usbarbitrator.path source = dkms.conf.in source = Makefile source = vmmon.patch source = vmnet.patch - source = https://download3.vmware.com/software/fusion/file/VMware-Fusion-7.1.3-3204469.dmg - source = unlocker-3.0.2.py::https://raw.githubusercontent.com/DrDonk/unlocker/3.0.2/unlocker.py - source = unlocker.patch - source = efi-unlocker-patch-1.0.0.txt::https://raw.githubusercontent.com/DrDonk/efi-unlocker/1.0.0/patches.txt sha256sums = d6b158a03d94db2d274dbf695337c564987f373c1ff5896665f3d1590617bc04 sha256sums = 12e7b16abf8d7e858532edabb8868919c678063c566a6535855b194aac72d55e sha256sums = da1698bf4e73ae466c1c7fc93891eba4b9c4581856649635e6532275dbfea141 @@ -81,17 +78,14 @@ pkgbase = vmware-workstation11 sha256sums = f9440479f3ae5ad0a39bba3150276627878bf83d6879444fb327c53a1dbb5a4d sha256sums = 42594b60085d0bbef01ab07b9f8b0d18640001107ce61cc0ddf02d0ab415140f sha256sums = e4c2e97acf07c52de570dd4333d67acfb593db719937a563c6075ab773dcce33 - sha256sums = e3812b78158672c7d96b6a58877681462f3fbdfe99a948b32c80c755c8682450 + sha256sums = 9b4fbe0ba83f761a2eb9ecd05d48428f8b0a5b3abd8404ccbd928408e682f02b sha256sums = c0a5aea785db06921fb350d36d5e0fd9a14f5eee0c835686ec6fea1af8c92245 sha256sums = d7a9fbf39a0345ae2f14f7f389f30b1110f605d187e0c241e99bbb18993c250d - sha256sums = 05e26d8b21d190ebabb7f693998114d9d5991d9dfb71acb4d990293a65b6b487 - sha256sums = 6ce902b1dab8fc69be253abd8e79017011985eca850ff7acc7282f9ab668e35d - sha256sums = b6d4969ffa5c40417cdbeb27b2ba3b115be5156a40ddc12cec098a8d68ad5acf - sha256sums = f05224da9a82b290bc800d2d470b378addb5dee2b811724f210a1ae214ab4e52 - sha256sums = 9ba3e002cc2ed3d3adc96b8b748d49c72069acac35f0fcc71ceaa7729895da17 - sha256sums = 29e0b0db9c0296ab81eee543803c4bd430e2c69c76e33492910e17280da1c05c - sha256sums = 4fb4a7914aee656df170e35b3ef952aaaa2ed10161e560dfa097688861127b1d - sha256sums = 392c1effcdec516000e9f8ffc97f2586524d8953d3e7d6f2c5f93f2acd809d91 + sha256sums = 16a73931894a65d43da489ff25d07647c0ecddf60d443b103bceca63504910fe + sha256sums = fe1b1be8297f4170406f97dd1f8b385d911faf45afe19cbc0c26b8092b3ddf8d + sha256sums = 10562d11d50edab9abc2b29c8948714edcb9b084f99b3766d07ddd21259e372e + sha256sums = 273d4357599a3e54259c78cc49054fef8ecfd2c2eda35cbcde3a53a62777a5ac + sha256sums = 3c98e7ab9b9a4e159ee94d3ad4d3e3441f803a5fe6c1c5d87ec1d7875877aaf5 + sha256sums = c67445e4a404cdce89141bdb97ceefb63aae2aa93ac62c4c8b4dc57d9606c907 pkgname = vmware-workstation11 - @@ -2,10 +2,7 @@ MODULES = \ vmmon \ - vmnet \ - #vmblock \ - #vmci \ - #vsock + vmnet all: $(foreach m, $(MODULES), $m.ko) @@ -1,16 +1,9 @@ # Maintainer: Jean-Marc Lenoir <archlinux "at" jihemel "dot" com> -############################################################################ -# Patch VMware Workstation to enable macOS guests support -# Uncomment the line below to enable it - +# To enable macOS guests support, uncomment the line below: #_enable_macOS_guests=y - # CAUTION: Running macOS on VMware Workstation on non Apple computer is forbidden by # Apple and VMware EULAs. -# Source of the patch: https://github.com/DrDonk/unlocker -# Forum: https://www.insanelymac.com/forum/topic/335757-macos-unlocker-v30-for-vmware-workstation/ -############################################################################ # vmware-keymaps dependency is needed to avoid some conflicts when you install # this package with vmware-horizon-client. If you don't plan to install @@ -23,7 +16,7 @@ pkgname=vmware-workstation11 pkgver=11.1.4 _buildver=3848939 _pkgver=${pkgver}_${_buildver} -pkgrel=8 +pkgrel=30 pkgdesc='The industry standard for running multiple operating systems as virtual machines on a single Linux PC.' arch=(x86_64) url='https://www.vmware.com/products/workstation-for-linux.html' @@ -47,6 +40,7 @@ depends=( gtkmm libcanberra hicolor-icon-theme + libxcrypt-compat # needed for ovftool # needed to replace internal libs: fontconfig freetype2 @@ -92,6 +86,8 @@ source=( 'vmware-networks-configuration.service' 'vmware-networks.service' 'vmware-usbarbitrator.service' + 'vmware-networks.path' + 'vmware-usbarbitrator.path' 'dkms.conf.in' 'Makefile' @@ -117,16 +113,18 @@ sha256sums=( 'f9440479f3ae5ad0a39bba3150276627878bf83d6879444fb327c53a1dbb5a4d' '42594b60085d0bbef01ab07b9f8b0d18640001107ce61cc0ddf02d0ab415140f' 'e4c2e97acf07c52de570dd4333d67acfb593db719937a563c6075ab773dcce33' - 'e3812b78158672c7d96b6a58877681462f3fbdfe99a948b32c80c755c8682450' + '9b4fbe0ba83f761a2eb9ecd05d48428f8b0a5b3abd8404ccbd928408e682f02b' 'c0a5aea785db06921fb350d36d5e0fd9a14f5eee0c835686ec6fea1af8c92245' 'd7a9fbf39a0345ae2f14f7f389f30b1110f605d187e0c241e99bbb18993c250d' + '16a73931894a65d43da489ff25d07647c0ecddf60d443b103bceca63504910fe' + 'fe1b1be8297f4170406f97dd1f8b385d911faf45afe19cbc0c26b8092b3ddf8d' - '05e26d8b21d190ebabb7f693998114d9d5991d9dfb71acb4d990293a65b6b487' - '6ce902b1dab8fc69be253abd8e79017011985eca850ff7acc7282f9ab668e35d' - 'b6d4969ffa5c40417cdbeb27b2ba3b115be5156a40ddc12cec098a8d68ad5acf' - 'f05224da9a82b290bc800d2d470b378addb5dee2b811724f210a1ae214ab4e52' + '10562d11d50edab9abc2b29c8948714edcb9b084f99b3766d07ddd21259e372e' + '273d4357599a3e54259c78cc49054fef8ecfd2c2eda35cbcde3a53a62777a5ac' + '3c98e7ab9b9a4e159ee94d3ad4d3e3441f803a5fe6c1c5d87ec1d7875877aaf5' + 'c67445e4a404cdce89141bdb97ceefb63aae2aa93ac62c4c8b4dc57d9606c907' ) -options=(!strip emptydirs) +options=(!strip emptydirs !debug) if [ -z "$_remove_vmware_keymaps_dependency" ]; then depends+=( @@ -138,28 +136,26 @@ _isoimages=(freebsd linux netware solaris windows winPre2k) if [ -n "$_enable_macOS_guests" ]; then -_vmware_fusion_ver=7.1.3_3204469 +_vmware_fusion_ver=7.1.3 +_vmware_fusion_buildver=3204469 +_vmware_fusion_ver_full=${_vmware_fusion_ver}_${_vmware_fusion_buildver} # List of VMware Fusion versions: https://softwareupdate.vmware.com/cds/vmw-desktop/fusion/ -_unlocker_ver=3.0.2 -_efi_unlocker_ver=1.0.0 - makedepends+=( python - dmg2dir - uefitool-git + dmg2img + p7zip + uefitool ) source+=( - "https://download3.vmware.com/software/fusion/file/VMware-Fusion-${_vmware_fusion_ver/_/-}.dmg" - "unlocker-${_unlocker_ver}.py::https://raw.githubusercontent.com/DrDonk/unlocker/${_unlocker_ver}/unlocker.py" - 'unlocker.patch' - "efi-unlocker-patch-${_efi_unlocker_ver}.txt::https://raw.githubusercontent.com/DrDonk/efi-unlocker/${_efi_unlocker_ver}/patches.txt" + "https://download3.vmware.com/software/fusion/file/VMware-Fusion-${_vmware_fusion_ver_full/_/-}.dmg" + "unlocker.py" + "efi-patches.txt" ) sha256sums+=( '9ba3e002cc2ed3d3adc96b8b748d49c72069acac35f0fcc71ceaa7729895da17' - '29e0b0db9c0296ab81eee543803c4bd430e2c69c76e33492910e17280da1c05c' - '4fb4a7914aee656df170e35b3ef952aaaa2ed10161e560dfa097688861127b1d' + '8a61e03d0edbbf60c1c84a43aa87a6e950f82d2c71b968888f019345c2f684f3' '392c1effcdec516000e9f8ffc97f2586524d8953d3e7d6f2c5f93f2acd809d91' ) @@ -179,13 +175,13 @@ _create_database_file() { for isoimage in ${_isoimages[@]} do local version=$(cat "$srcdir/extracted/vmware-tools-$isoimage/manifest.xml" | grep -oPm1 "(?<=<version>)[^<]+") - sqlite3 "$database_filename" "INSERT INTO components(name,version,buildNumber,component_core_id,longName,description,type) VALUES(\"vmware-tools-$isoimage\",\"$version\",\"${_pkgver#*_}\",1,\"$isoimage\",\"$isoimage\",1);" + sqlite3 "$database_filename" "INSERT INTO components(name,version,buildNumber,component_core_id,longName,description,type) VALUES('vmware-tools-$isoimage','$version',${_pkgver#*_},1,'$isoimage','$isoimage',1);" done if [ -n "$_enable_macOS_guests" ]; then for isoimage in ${_fusion_isoimages[@]} do - sqlite3 "$database_filename" "INSERT INTO components(name,version,buildNumber,component_core_id,longName,description,type) VALUES(\"vmware-tools-$isoimage\",\"1\",\"${_vmware_fusion_ver#*_}\",1,\"$isoimage\",\"$isoimage\",1);" + sqlite3 "$database_filename" "INSERT INTO components(name,version,buildNumber,component_core_id,longName,description,type) VALUES('vmware-tools-$isoimage','1',${_vmware_fusion_ver_full#*_},1,'$isoimage','$isoimage',1);" done fi } @@ -199,16 +195,9 @@ prepare() { --extract "$extracted_dir" if [ -n "$_enable_macOS_guests" ]; then - dmg2dir -q --tmp="$srcdir/dmg2dir" --overwrite-dir --overwrite-img VMware-Fusion-${_vmware_fusion_ver/_/-}.dmg - for isoimage in ${_fusion_isoimages[@]} - do - install -Dm 644 "$srcdir/VMware-Fusion-${_vmware_fusion_ver/_/-}/VMware Fusion/VMware Fusion.app/Contents/Library/isoimages/$isoimage.iso" "$srcdir/fusion-isoimages/$isoimage.iso" - install -Dm 644 "$srcdir/VMware-Fusion-${_vmware_fusion_ver/_/-}/VMware Fusion/VMware Fusion.app/Contents/Library/isoimages/$isoimage.iso.sig" "$srcdir/fusion-isoimages/$isoimage.iso.sig" - done - rm -rf "$srcdir/dmg2dir" + dmg2img -s VMware-Fusion-${_vmware_fusion_ver_full/_/-}.dmg VMware-Fusion-${_vmware_fusion_ver_full/_/-}.iso + 7z e -y VMware-Fusion-${_vmware_fusion_ver_full/_/-}.iso VMware\ Fusion/VMware\ Fusion.app/Contents/Library/isoimages/\* -o"fusion-isoimages" > /dev/null 2>&1 || true - cp "$srcdir/unlocker-${_unlocker_ver}.py" "$srcdir/unlocker.py" - patch -Np1 < unlocker.patch sed -i -e "s|/usr/lib/vmware/|${pkgdir}/usr/lib/vmware/|" "$srcdir/unlocker.py" fi } @@ -219,7 +208,7 @@ package() { # Make directories and copy files. mkdir -p \ - "$pkgdir/etc"/{cups,pam.d,modprobe.d,profile.d,thnuclnt,vmware} \ + "$pkgdir/etc"/{cups,pam.d,modprobe.d,thnuclnt,vmware} \ "$pkgdir/usr"/{share,bin} \ "$pkgdir/usr/include/vmware-vix" \ "$pkgdir/usr/lib"/{vmware/setup,vmware-vix,vmware-ovftool,vmware-installer/"$vmware_installer_version",cups/filter,modules-load.d} \ @@ -244,6 +233,7 @@ package() { vmware-network-editor-ui/bin/* \ vmware-player-app/bin/* \ "$pkgdir/usr/bin" + rm -f "$pkgdir/usr/bin/vm-support" cp -r \ vmware-workstation/lib/* \ @@ -337,7 +327,9 @@ fi vmware-authd.service \ vmware-networks-configuration.service \ vmware-networks.service \ - vmware-usbarbitrator.service + vmware-usbarbitrator.service \ + vmware-networks.path \ + vmware-usbarbitrator.path do install -Dm 644 \ "$srcdir/$service_file" \ @@ -439,7 +431,7 @@ fi -e "s/@PKGVER@/$_pkgver/g" \ -i "$dkms_dir/dkms.conf" - for module in vmmon vmnet; do # vmblock vmci vsock + for module in vmmon vmnet; do tar -xf "vmware-vmx/lib/modules/source/$module.tar" -C "$dkms_dir" msg "Patching $module module for DKMS" patch -p2 --read-only=ignore --directory="$dkms_dir/$module-only" < "$srcdir/$module.patch" @@ -448,8 +440,8 @@ fi rm -r "$pkgdir/usr/lib/vmware/modules"/{binary,source} if [ -n "$_enable_macOS_guests" ]; then - msg "Patching VMware for macOS guest support" - python "$srcdir/unlocker.py" > /dev/null + msg "Patching VMware to enable macOS guest support" + python3 "$srcdir/unlocker.py" > /dev/null for isoimage in ${_fusion_isoimages[@]} do @@ -457,14 +449,14 @@ if [ -n "$_enable_macOS_guests" ]; then install -Dm 644 "$srcdir/fusion-isoimages/$isoimage.iso.sig" "$pkgdir/usr/lib/vmware/isoimages/$isoimage.iso.sig" done - msg "Patching EFI firmwares to remove the check for server versions" - _efi_arch=(32 64) + msg "Patching EFI firmwares to disable macOS server checking" + _efi_arch=("32" "64") for arch in ${_efi_arch[@]} do objcopy "$pkgdir"/usr/lib/vmware/bin/vmware-vmx -O binary -j efi${arch} --set-section-flags efi${arch}=a efi${arch}.rom.Z perl -e 'use Compress::Zlib; my $v; read STDIN, $v, '$(stat -c%s "./efi${arch}.rom.Z")'; $v = uncompress($v); print $v;' < efi${arch}.rom.Z > efi${arch}.rom - uefipatch efi${arch}.rom "$srcdir/efi-unlocker-patch-${_efi_unlocker_ver}.txt" -o efi${arch}.rom > /dev/null + uefipatch efi${arch}.rom "$srcdir/efi-patches.txt" -o efi${arch}.rom > /dev/null perl -e 'use Compress::Zlib; my $v; read STDIN, $v, '$(stat -c%s "./efi${arch}.rom")'; $v = compress($v); print $v;' < efi${arch}.rom > efi${arch}.rom.Z objcopy "$pkgdir"/usr/lib/vmware/bin/vmware-vmx --update-section efi${arch}=efi${arch}.rom.Z diff --git a/dkms.conf.in b/dkms.conf.in index 64c93aa0c18c..5c7adc58ecde 100644 --- a/dkms.conf.in +++ b/dkms.conf.in @@ -13,18 +13,3 @@ DEST_MODULE_LOCATION[0]="/kernel/drivers/misc" BUILT_MODULE_NAME[1]="vmnet" BUILT_MODULE_LOCATION[1]='vmnet-only' DEST_MODULE_LOCATION[1]="/kernel/drivers/net" - -# seems that this module is never used -#BUILT_MODULE_NAME[2]="vmblock" -#BUILT_MODULE_LOCATION[2]='vmblock-only' -#DEST_MODULE_LOCATION[2]="/kernel/fs/vmblock" - -# vmci is already provided by the kernel with vmw_vmci -#BUILT_MODULE_NAME[3]="vmci" -#BUILT_MODULE_LOCATION[3]='vmci-only' -#DEST_MODULE_LOCATION[3]="/kernel/drivers/misc" - -# vsock is already provided by the kernel -#BUILT_MODULE_NAME[4]="vsock" -#BUILT_MODULE_LOCATION[4]='vsock-only' -#DEST_MODULE_LOCATION[4]="/kernel/net/vmw_vsock" diff --git a/efi-patches.txt b/efi-patches.txt new file mode 100644 index 000000000000..6451d1db0315 --- /dev/null +++ b/efi-patches.txt @@ -0,0 +1,25 @@ +# Patch string format +# FileGuid SectionType PatchType:FindPatternOrOffset:ReplacePattern +# Please ensure that the latest symbol in patch string is space + +# Possible section types: +# PE32 image 10 +# Position-independent code 11 +# TE Image 12 +# DXE Dependency 13 +# Version information 14 +# User interface string 15 +# 16-bit code 16 +# Guided freeform 18 +# Raw data 19 +# PEI Dependency 1B +# SMM Dependency 1C +# Please do not try another section types, it can make the resulting image broken + +# Possible patch types: +# P - pattern-based, first parameter is a pattern to find, second - a pattern to replace +# O - offset-based, first parameter is hexadecimal offset, second - a pattern to replace +# Patterns can have . as "any possible value" symbol + +# VMware remove macOS Server check ServerVersion.plist -> SystemVersion.plist +961578FE-B6B7-44C3-AF35-6BC705CD3B3F 10 P:530065007200760065007200560065007200730069006F006E002E0070006C00690073007400:530079007300740065006D00560065007200730069006F006E002E0070006C00690073007400 diff --git a/unlocker.patch b/unlocker.patch deleted file mode 100644 index 7c32fa83f288..000000000000 --- a/unlocker.patch +++ /dev/null @@ -1,62 +0,0 @@ -diff --git a/unlocker.py b/unlocker.py -index decbc51..0f9d3f6 100755 ---- a/unlocker.py -+++ b/unlocker.py -@@ -44,6 +44,7 @@ - from __future__ import print_function - import codecs - import os -+import re - import struct - import sys - -@@ -55,7 +56,11 @@ - if sys.platform == 'win32' \ - or sys.platform == 'cli': - # noinspection PyUnresolvedReferences -- from _winreg import * -+ if sys.version_info > (3, 0): -+ from winreg import * -+ else: -+ from _winreg import * -+ - - - def bytetohex(data): -@@ -301,9 +306,10 @@ def patchbase(name): - f = open(name, 'r+b') - - # Entry to search for in GOS table -- # Should work for 12 & 14 of Workstation... -- darwin = b'\x10\x00\x00\x00\x10\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00' \ -- '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' -+ # Should work for Workstation 12-15... -+ darwin = re.compile( -+ b'\x10\x00\x00\x00[\x10|\x20]\x00\x00\x00[\x01|\x02]\x00\x00\x00\x00\x00\x00\x00' -+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') - - # Read file into string variable - base = f.read() -@@ -311,19 +317,14 @@ def patchbase(name): - # Loop through each entry and set top bit - # 0xBE --> 0xBF (WKS 12) - # 0x3E --> 0x3F (WKS 14) -- offset = 0 -- while offset < len(base): -- offset = base.find(darwin, offset) -- if offset == -1: -- break -+ for m in darwin.finditer(base): -+ offset = m.start() - f.seek(offset + 32) - flag = ord(f.read(1)) - flag = set_bit(flag, 0) -- flag = chr(flag) - f.seek(offset + 32) -- f.write(flag) -+ f.write(bytes([flag])) - print('GOS Patched flag @: ' + hex(offset)) -- offset += 40 - - # Tidy up - f.flush() diff --git a/unlocker.py b/unlocker.py new file mode 100644 index 000000000000..8ac86cb92951 --- /dev/null +++ b/unlocker.py @@ -0,0 +1,387 @@ +#!/usr/bin/env python3 +""" +vSMC Header Structure +Offset Length Struct Type Description +---------------------------------------- +0x00/00 0x08/08 Q ptr Offset to key table +0x08/08 0x04/4 I int Number of private keys +0x0C/12 0x04/4 I int Number of public keys + +vSMC Key Data Structure +Offset Length Struct Type Description +---------------------------------------- +0x00/00 0x04/04 4s int Key name (byte reversed e.g. #KEY is YEK#) +0x04/04 0x01/01 B byte Length of returned data +0x05/05 0x04/04 4s int Data type (byte reversed e.g. ui32 is 23iu) +0x09/09 0x01/01 B byte Flag R/W +0x0A/10 0x06/06 6x byte Padding +0x10/16 0x08/08 Q ptr Internal VMware routine +0x18/24 0x30/48 48B byte Data +""" + +import codecs +import os +import re +import struct +import sys + +if sys.version_info < (3, 6): + sys.stderr.write('You need Python 3.6 or later\n') + sys.exit(1) + +# Setup imports depending on whether IronPython or CPython +if sys.platform in ('cli', 'win32'): + # noinspection PyUnresolvedReferences + from winreg import * + + +def bytetohex(data): + return ''.join('{:02X} '.format(c) for c in data) + + +def joinpath(folder, filename): + return os.path.join(folder, filename) + + +def printkey(i, offset, smc_key, smc_data): + print(str(i + 1).zfill(3) + + ' ' + hex(offset) + + ' ' + smc_key[0][::-1].decode('UTF-8') + + ' ' + str(smc_key[1]).zfill(2) + + ' ' + smc_key[2][::-1].replace(b'\x00', b' ').decode('UTF-8') + + ' ' + '{0:#0{1}x}'.format(smc_key[3], 4) + + ' ' + hex(smc_key[4]) + + ' ' + bytetohex(smc_data)) + + +def set_bit(value, bit): + return value | (1 << bit) + + +def clear_bit(value, bit): + return value & ~(1 << bit) + + +def test_bit(value, bit): + return value & bit + + +E_CLASS64 = 2 +E_SHT_RELA = 4 + + +# noinspection PyUnusedLocal +def patchelf(f, oldoffset, newoffset): + f.seek(0) + magic = f.read(4) + if not magic == b'\x7fELF': + raise Exception('Magic number does not match') + + ei_class = struct.unpack('=B', f.read(1))[0] + if ei_class != E_CLASS64: + raise Exception('Not 64bit elf header: ' + ei_class) + + f.seek(40) + e_shoff = struct.unpack('=Q', f.read(8))[0] + f.seek(58) + e_shentsize = struct.unpack('=H', f.read(2))[0] + e_shnum = struct.unpack('=H', f.read(2))[0] + e_shstrndx = struct.unpack('=H', f.read(2))[0] + + print('e_shoff: 0x{:x} e_shentsize: 0x{:x} e_shnum:0x{:x} e_shstrndx:0x{:x}'.format(e_shoff, e_shentsize, + e_shnum, e_shstrndx)) + + for i in range(0, e_shnum): + f.seek(e_shoff + i * e_shentsize) + e_sh = struct.unpack('=LLQQQQLLQQ', f.read(e_shentsize)) + e_sh_name = e_sh[0] + e_sh_type = e_sh[1] + e_sh_offset = e_sh[4] + e_sh_size = e_sh[5] + e_sh_entsize = e_sh[9] + if e_sh_type == E_SHT_RELA: + e_sh_nument = int(e_sh_size / e_sh_entsize) + print('RELA at 0x{:x} with {:d} entries'.format(e_sh_offset, e_sh_nument)) + for j in range(0, e_sh_nument): + f.seek(e_sh_offset + e_sh_entsize * j) + rela = struct.unpack('=QQq', f.read(e_sh_entsize)) + r_offset = rela[0] + r_info = rela[1] + r_addend = rela[2] + if r_addend == oldoffset: + r_addend = newoffset + f.seek(e_sh_offset + e_sh_entsize * j) + f.write(struct.pack('=QQq', r_offset, r_info, r_addend)) + print('Relocation modified at: ' + hex(e_sh_offset + e_sh_entsize * j)) + + +def patchkeys(f, key): + # Setup struct pack string + key_pack = '=4sB4sB6xQ' + smc_old_memptr = 0 + smc_new_memptr = 0 + + # Do Until OSK1 read + i = 0 + while True: + + # Read key into struct str and data byte str + offset = key + (i * 72) + f.seek(offset) + smc_key = struct.unpack(key_pack, f.read(24)) + smc_data = f.read(smc_key[1]) + + # Reset pointer to beginning of key entry + f.seek(offset) + + if smc_key[0] == b'SKL+': + # Use the +LKS data routine for OSK0/1 + smc_new_memptr = smc_key[4] + print('+LKS Key: ') + printkey(i, offset, smc_key, smc_data) + + elif smc_key[0] == b'0KSO': + # Write new data routine pointer from +LKS + print('OSK0 Key Before:') + printkey(i, offset, smc_key, smc_data) + smc_old_memptr = smc_key[4] + f.seek(offset) + f.write(struct.pack(key_pack, smc_key[0], smc_key[1], smc_key[2], smc_key[3], smc_new_memptr)) + f.flush() + + # Write new data for key + f.seek(offset + 24) + smc_new_data = codecs.encode('bheuneqjbexolgurfrjbeqfthneqrqcy', 'rot_13') + f.write(smc_new_data.encode('UTF-8')) + f.flush() + + # Re-read and print key + f.seek(offset) + smc_key = struct.unpack(key_pack, f.read(24)) + smc_data = f.read(smc_key[1]) + print('OSK0 Key After:') + printkey(i, offset, smc_key, smc_data) + + elif smc_key[0] == b'1KSO': + # Write new data routine pointer from +LKS + print('OSK1 Key Before:') + printkey(i, offset, smc_key, smc_data) + smc_old_memptr = smc_key[4] + f.seek(offset) + f.write(struct.pack(key_pack, smc_key[0], smc_key[1], smc_key[2], smc_key[3], smc_new_memptr)) + f.flush() + + # Write new data for key + f.seek(offset + 24) + smc_new_data = codecs.encode('rnfrqbagfgrny(p)NccyrPbzchgreVap', 'rot_13') + f.write(smc_new_data.encode('UTF-8')) + f.flush() + + # Re-read and print key + f.seek(offset) + smc_key = struct.unpack(key_pack, f.read(24)) + smc_data = f.read(smc_key[1]) + print('OSK1 Key After:') + printkey(i, offset, smc_key, smc_data) + + # Finished so get out of loop + break + + # elif smc_key[0] == b'WPPK': + # # Set the old SMC password as an addtional marker that vmx has been patched + # # This has no functional value except for checking status + # print('KPPW Key Before:') + # printkey(i, offset, smc_key, smc_data) + # f.seek(offset + 24) + # f.write('SpecialisRevelio'.encode('UTF-8')) + # + # # Re-read and print key + # f.seek(offset) + # smc_key = struct.unpack(key_pack, f.read(24)) + # smc_data = f.read(smc_key[1]) + # print('KPPW Key After:') + # printkey(i, offset, smc_key, smc_data) + + else: + pass + + i += 1 + return smc_old_memptr, smc_new_memptr + + +def patchsmc(name, sharedobj): + with open(name, 'r+b') as f: + + smc_old_memptr = 0 + smc_new_memptr = 0 + + # Read file into string variable + vmx = f.read() + + print('File: ' + name + '\n') + + # Setup hex string for vSMC headers + # These are the private and public key counts + smc_header_v0 = b'\xF2\x00\x00\x00\xF0\x00\x00\x00' + smc_header_v1 = b'\xB4\x01\x00\x00\xB0\x01\x00\x00' + + # Setup hex string for #KEY key + key_key = b'\x59\x45\x4B\x23\x04\x32\x33\x69\x75' + + # Setup hex string for $Adr key + adr_key = b'\x72\x64\x41\x24\x04\x32\x33\x69\x75' + + # Find the vSMC headers + smc_header_v0_offset = vmx.find(smc_header_v0) - 8 + smc_header_v1_offset = vmx.find(smc_header_v1) - 8 + + # Find '#KEY' keys + smc_key0 = vmx.find(key_key) + smc_key1 = vmx.rfind(key_key) + + # Find '$Adr' key table + smc_adr = vmx.find(adr_key) + + # Print vSMC0 tables and keys + print('appleSMCTableV0 (smc.version = "0")') + print('appleSMCTableV0 Address : ' + hex(smc_header_v0_offset)) + print('appleSMCTableV0 Private Key #: 0xF2/242') + print('appleSMCTableV0 Public Key #: 0xF0/240') + + if (smc_adr - smc_key0) != 72: + print('appleSMCTableV0 Table : ' + hex(smc_key0)) + smc_old_memptr, smc_new_memptr = patchkeys(f, smc_key0) + elif (smc_adr - smc_key1) != 72: + print('appleSMCTableV0 Table : ' + hex(smc_key1)) + smc_old_memptr, smc_new_memptr = patchkeys(f, smc_key1) + + print() + + # Print vSMC1 tables and keys + print('appleSMCTableV1 (smc.version = "1")') + print('appleSMCTableV1 Address : ' + hex(smc_header_v1_offset)) + print('appleSMCTableV1 Private Key #: 0x01B4/436') + print('appleSMCTableV1 Public Key #: 0x01B0/432') + + if (smc_adr - smc_key0) == 72: + print('appleSMCTableV1 Table : ' + hex(smc_key0)) + smc_old_memptr, smc_new_memptr = patchkeys(f, smc_key0) + elif (smc_adr - smc_key1) == 72: + print('appleSMCTableV1 Table : ' + hex(smc_key1)) + smc_old_memptr, smc_new_memptr = patchkeys(f, smc_key1) + + print() + + # Find matching RELA record in .rela.dyn in ESXi ELF files + # This is temporary code until proper ELF parsing written + if sharedobj: + print('Modifying RELA records from: ' + hex(smc_old_memptr) + ' to ' + hex(smc_new_memptr)) + patchelf(f, smc_old_memptr, smc_new_memptr) + + # Tidy up + f.flush() + f.close() + + +def patchbase(name): + # Patch file + print('GOS Patching: ' + name) + f = open(name, 'r+b') + + # Entry to search for in GOS table + # Should work for Workstation 12-15... + darwin = re.compile( + b'\x10\x00\x00\x00[\x10|\x20]\x00\x00\x00[\x01|\x02]\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + + # Read file into string variable + base = f.read() + + # Loop through each entry and set top bit + # 0xBE --> 0xBF (WKS 12/13) + # 0x3E --> 0x3F (WKS 14+) + for m in darwin.finditer(base): + offset = m.start() + f.seek(offset + 32) + flag = ord(f.read(1)) + flag = set_bit(flag, 0) + # flag = chr(flag) + f.seek(offset + 32) + f.write(bytes([flag])) + print('GOS Patched flag @: ' + hex(offset)) + + # Tidy up + f.flush() + f.close() + print('GOS Patched: ' + name) + + +def patchvmkctl(name): + # Patch file + print('smcPresent Patching: ' + name) + f = open(name, 'r+b') + + # Read file into string variable + vmkctl = f.read() + applesmc = vmkctl.find(b'applesmc') + f.seek(applesmc) + f.write(b'vmkernel') + + # Tidy up + f.flush() + f.close() + print('smcPresent Patched: ' + name) + + +# noinspection PyUnresolvedReferences +def main(): + # Work around absent Platform module on VMkernel + if os.name == 'nt' or os.name == 'cli': + osname = 'windows' + else: + osname = os.uname()[0].lower() + + # vmwarebase = '' + vmx_so = False + + # Setup default paths + if osname == 'linux': + # TODO: Dynamically find Linux installation + # Path the install is stored in /etc/vmware/config + # libdir = "/usr/lib/vmware" + vmx_path = '/usr/lib/vmware/bin/' + vmx = joinpath(vmx_path, 'vmware-vmx') + vmx_debug = joinpath(vmx_path, 'vmware-vmx-debug') + vmx_stats = joinpath(vmx_path, 'vmware-vmx-stats') + vmx_so = True + if os.path.isfile('/usr/lib/vmware/lib/libvmwarebase.so/libvmwarebase.so'): + vmwarebase = '/usr/lib/vmware/lib/libvmwarebase.so/libvmwarebase.so' + else: + vmwarebase = '/usr/lib/vmware/lib/libvmwarebase.so.0/libvmwarebase.so.0' + + elif osname == 'windows': + reg = ConnectRegistry(None, HKEY_LOCAL_MACHINE) + key = OpenKey(reg, r'SOFTWARE\Wow6432Node\VMware, Inc.\VMware Workstation') + vmwarebase_path = QueryValueEx(key, 'InstallPath')[0] + vmx_path = QueryValueEx(key, 'InstallPath64')[0] + vmx = joinpath(vmx_path, 'vmware-vmx.exe') + vmx_debug = joinpath(vmx_path, 'vmware-vmx-debug.exe') + vmx_stats = joinpath(vmx_path, 'vmware-vmx-stats.exe') + vmwarebase = joinpath(vmwarebase_path, 'vmwarebase.dll') + + else: + print('Unknown Operating System: ' + osname) + return + + # Patch the vmx executables skipping stats version for Player + patchsmc(vmx, vmx_so) + patchsmc(vmx_debug, vmx_so) + if os.path.isfile(vmx_stats): + patchsmc(vmx_stats, vmx_so) + + # Patch vmwarebase for Workstation and Player + patchbase(vmwarebase) + + +if __name__ == '__main__': + main() diff --git a/vmmon.patch b/vmmon.patch index 49856121ae62..9a62baa87f17 100644 --- a/vmmon.patch +++ b/vmmon.patch @@ -1,6 +1,6 @@ --- a/vmmon/Makefile +++ b/vmmon/Makefile -@@ -43,7 +43,11 @@ INCLUDE += -I$(SRCROOT)/shared +@@ -43,7 +43,11 @@ endif @@ -37,7 +37,7 @@ MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild --- a/vmmon/common/hostif.h +++ b/vmmon/common/hostif.h -@@ -122,14 +122,10 @@ EXTERN MPN64 HostIF_GetNextAnonPage(VMDriver *vm, MPN64 mpn); +@@ -122,14 +122,10 @@ EXTERN MPN64 HostIF_GetNextAnonPage(VMDr EXTERN int HostIF_GetLockedPageList(VMDriver *vm, VA64 uAddr, unsigned int numPages); @@ -55,7 +55,7 @@ #if defined __APPLE__ // There is no need for a fast clock lock on Mac OS. #define HostIF_FastClockLock(_callerID) do {} while (0) -@@ -145,4 +141,8 @@ EXTERN void HostIF_FreeMachinePage(MPN64 mpn); +@@ -145,4 +141,8 @@ EXTERN void HostIF_FreeMachinePage(MPN64 EXTERN int HostIF_SafeRDMSR(uint32 msr, uint64 *val); @@ -247,7 +247,7 @@ #if defined(_WIN64) # include "x86.h" # include "vmmon-asm-x86-64.h" -@@ -708,11 +718,28 @@ TaskRestoreHostGDTTRLDT(Descriptor *tempGDTBase, +@@ -708,11 +718,28 @@ TaskRestoreHostGDTTRLDT(Descriptor *temp */ desc = (Descriptor *)((VA)HOST_KERNEL_LA_2_VA(hostGDT64.offset + tr)); @@ -288,13 +288,10 @@ * We can't allocate memory with interrupts disabled on all hosts --- a/vmmon/common/vmx86.c +++ b/vmmon/common/vmx86.c -@@ -720,6 +720,35 @@ cleanup: - } - - -+/* -+ *---------------------------------------------------------------------- -+ * +@@ -723,6 +723,35 @@ cleanup: + /* + *---------------------------------------------------------------------- + * + * Vmx86_LookupUserMPN -- + * + * Look up the MPN of a locked user page by user VA under the VM lock. @@ -321,9 +318,12 @@ +} + + - /* - *---------------------------------------------------------------------- ++/* ++ *---------------------------------------------------------------------- ++ * + * Vmx86_ReleaseVM -- * + * Release a VM (either created here or from a bind). --- a/vmmon/common/vmx86.h +++ b/vmmon/common/vmx86.h @@ -106,6 +106,7 @@ extern PseudoTSC pseudoTSC; @@ -405,27 +405,14 @@ -# define compat_pud_present(pgd) pgd_present(pgd) -typedef pml4_t compat_pgd_t; -typedef pgd_t compat_pud_t; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) -+# define compat_p4d_offset(pgd, address) p4d_offset(pgd, address) -+# define compat_p4d_present(p4d) p4d_present(p4d) -+# define compat_p4d_large(p4d) p4d_large(p4d) -+# define compat_p4d_pfn(p4d) p4d_pfn(p4d) -+# define COMPAT_P4D_MASK P4D_MASK -+typedef p4d_t compat_p4d_t; - #else +-#else -# define compat_pgd_offset(mm, address) pgd_offset(mm, address) -# define compat_pgd_present(pgd) pgd_present(pgd) -# define compat_pud_offset(pgd, address) (pgd) -# define compat_pud_present(pud) (1) -typedef pgd_t compat_pgd_t; -typedef pgd_t compat_pud_t; -+# define compat_p4d_offset(pgd, address) (pgd) -+# define compat_p4d_present(p4d) (1) -+# define compat_p4d_large(p4d) (0) -+# define compat_p4d_pfn(p4d) INVALID_MPN /* Not used */ -+# define COMPAT_P4D_MASK 0 /* Not used */ -+typedef pgd_t compat_p4d_t; - #endif +-#endif - - -#define compat_pgd_offset_k(mm, address) pgd_offset_k(address) @@ -434,11 +421,7 @@ -/* Introduced somewhere in 2.6.0, + backported to some 2.4 RedHat kernels */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pte_pfn) -# define pte_pfn(pte) page_to_pfn(compat_pte_page(pte)) -+/* p[gu]d_large did not exist before 2.6.25 */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) -+# define pud_large(pud) 0 -+# define pgd_large(pgd) 0 - #endif +-#endif - - -/* A page_table_lock field is added to struct mm_struct in 2.3.10 --hpreg */ @@ -446,6 +429,26 @@ -# define compat_get_page_table_lock(_mm) (&(_mm)->page_table_lock) -#else -# define compat_get_page_table_lock(_mm) NULL ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) ++# define compat_p4d_offset(pgd, address) p4d_offset(pgd, address) ++# define compat_p4d_present(p4d) p4d_present(p4d) ++# define compat_p4d_large(p4d) p4d_large(p4d) ++# define compat_p4d_pfn(p4d) p4d_pfn(p4d) ++# define COMPAT_P4D_MASK P4D_MASK ++typedef p4d_t compat_p4d_t; ++#else ++# define compat_p4d_offset(pgd, address) (pgd) ++# define compat_p4d_present(p4d) (1) ++# define compat_p4d_large(p4d) (0) ++# define compat_p4d_pfn(p4d) INVALID_MPN /* Not used */ ++# define COMPAT_P4D_MASK 0 /* Not used */ ++typedef pgd_t compat_p4d_t; ++#endif ++/* p[gu]d_large did not exist before 2.6.25 */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) ++# define pud_large(pud) 0 ++# define pgd_large(pgd) 0 ++#endif +/* pud_pfn did not exist before 3.8. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) +# define pud_pfn(pud) INVALID_MPN @@ -467,45 +470,55 @@ #endif /* __COMPAT_PGTABLE_H__ */ --- a/vmmon/include/pgtbl.h +++ b/vmmon/include/pgtbl.h -@@ -26,154 +26,14 @@ +@@ -26,15 +26,14 @@ #include "compat_spinlock.h" #include "compat_page.h" --/* -- *----------------------------------------------------------------------------- -- * ++ + /* + *----------------------------------------------------------------------------- + * - * PgtblPte2MPN -- - * - * Returns the page structure associated to a Page Table Entry. -- * ++ * PgtblVa2MPNLocked -- + * - * This function is not allowed to schedule() because it can be called while - * holding a spinlock --hpreg -- * -- * Results: -- * INVALID_MPN on failure -- * mpn on success -- * -- * Side effects: -- * None -- * -- *----------------------------------------------------------------------------- -- */ -- --static INLINE MPN64 ++ * Walks through the hardware page tables to try to find the pte ++ * associated to a virtual address. Then maps PTE to MPN. + * + * Results: + * INVALID_MPN on failure +@@ -47,230 +46,70 @@ + */ + + static INLINE MPN64 -PgtblPte2MPN(pte_t *pte) // IN --{ -- MPN64 mpn; ++PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process ++ VA addr) // IN: Address in the virtual address ++ // space of that process + { ++ pgd_t *pgd; ++ compat_p4d_t *p4d; + MPN64 mpn; - if (pte_present(*pte) == 0) { -- return INVALID_MPN; -- } ++ ++ pgd = pgd_offset(mm, addr); ++ if (pgd_present(*pgd) == 0) { + return INVALID_MPN; + } - mpn = pte_pfn(*pte); - if (mpn >= INVALID_MPN) { -- return INVALID_MPN; -- } ++ if (pgd_large(*pgd)) { ++ /* Linux kernel does not support PGD huge pages. */ ++ /* return pgd_pfn(*pgd) + ((addr & PGD_MASK) >> PAGE_SHIFT); */ + return INVALID_MPN; + } - return mpn; -} - -- + -/* - *----------------------------------------------------------------------------- - * @@ -576,8 +589,15 @@ - if (pmd_present(*pmd) == 0) { - pmd_unmap(pmd); - return NULL; -- } -- ++ p4d = compat_p4d_offset(pgd, addr); ++ if (compat_p4d_present(*p4d) == 0) { ++ return INVALID_MPN; + } ++ if (compat_p4d_large(*p4d)) { ++ mpn = compat_p4d_pfn(*p4d) + ((addr & ~COMPAT_P4D_MASK) >> PAGE_SHIFT); ++ } else { ++ pud_t *pud; + - pte = pte_offset_map(pmd, addr); - pmd_unmap(pmd); - return pte; @@ -609,40 +629,69 @@ - return PgtblPGD2PTELocked(compat_pgd_offset(mm, addr), addr); -} - - - /* - *----------------------------------------------------------------------------- - * - * PgtblVa2MPNLocked -- - * +- +-/* +- *----------------------------------------------------------------------------- +- * +- * PgtblVa2MPNLocked -- +- * - * Retrieve MPN for a given va. - * - * Caller must call pte_unmap if valid pte returned. The mm->page_table_lock - * must be held, so this function is not allowed to schedule() --hpreg -+ * Walks through the hardware page tables to try to find the pte -+ * associated to a virtual address. Then maps PTE to MPN. - * - * Results: - * INVALID_MPN on failure -@@ -188,89 +48,64 @@ PgtblVa2PTELocked(struct mm_struct *mm, // IN: Mm structure of a process - static INLINE MPN64 - PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process - VA addr) // IN: Address in the virtual address -+ // space of that process - { +- * +- * Results: +- * INVALID_MPN on failure +- * mpn on success +- * +- * Side effects: +- * None +- * +- *----------------------------------------------------------------------------- +- */ +- +-static INLINE MPN64 +-PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process +- VA addr) // IN: Address in the virtual address +-{ - pte_t *pte; -+ pgd_t *pgd; -+ compat_p4d_t *p4d; -+ MPN64 mpn; - +- - pte = PgtblVa2PTELocked(mm, addr); - if (pte != NULL) { - MPN64 mpn = PgtblPte2MPN(pte); - pte_unmap(pte); - return mpn; -+ pgd = pgd_offset(mm, addr); -+ if (pgd_present(*pgd) == 0) { -+ return INVALID_MPN; ++ pud = pud_offset(p4d, addr); ++ if (pud_present(*pud) == 0) { ++ return INVALID_MPN; ++ } ++ if (pud_large(*pud)) { ++ mpn = pud_pfn(*pud) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); ++ } else { ++ pmd_t *pmd; ++ ++ pmd = pmd_offset(pud, addr); ++ if (pmd_present(*pmd) == 0) { ++ return INVALID_MPN; ++ } ++ if (pmd_large(*pmd)) { ++ mpn = pmd_pfn(*pmd) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); ++ } else { ++ pte_t *pte; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,5,0) ++ pte = pte_offset_kernel(pmd, addr); ++#else ++ pte = pte_offset_map(pmd, addr); ++#endif ++ if (pte_present(*pte) == 0) { ++ pte_unmap(pte); ++ return INVALID_MPN; ++ } ++ mpn = pte_pfn(*pte); ++ pte_unmap(pte); ++ } ++ } } - return INVALID_MPN; -} @@ -680,16 +729,15 @@ - MPN64 mpn = PgtblPte2MPN(pte); - pte_unmap(pte); - return mpn; -+ if (pgd_large(*pgd)) { -+ /* Linux kernel does not support PGD huge pages. */ -+ /* return pgd_pfn(*pgd) + ((addr & PGD_MASK) >> PAGE_SHIFT); */ -+ return INVALID_MPN; ++ if (mpn >= INVALID_MPN) { ++ mpn = INVALID_MPN; } - return INVALID_MPN; --} ++ return mpn; + } -#endif - - +- -/* - *----------------------------------------------------------------------------- - * @@ -718,50 +766,10 @@ - struct page *page = PgtblPte2Page(pte); - pte_unmap(pte); - return page; -+ p4d = compat_p4d_offset(pgd, addr); -+ if (compat_p4d_present(*p4d) == 0) { -+ return INVALID_MPN; -+ } -+ if (compat_p4d_large(*p4d)) { -+ mpn = compat_p4d_pfn(*p4d) + ((addr & ~COMPAT_P4D_MASK) >> PAGE_SHIFT); - } else { +- } else { - return NULL; -+ pud_t *pud; -+ -+ pud = pud_offset(p4d, addr); -+ if (pud_present(*pud) == 0) { -+ return INVALID_MPN; -+ } -+ if (pud_large(*pud)) { -+ mpn = pud_pfn(*pud) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); -+ } else { -+ pmd_t *pmd; -+ -+ pmd = pmd_offset(pud, addr); -+ if (pmd_present(*pmd) == 0) { -+ return INVALID_MPN; -+ } -+ if (pmd_large(*pmd)) { -+ mpn = pmd_pfn(*pmd) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); -+ } else { -+ pte_t *pte; -+ -+ pte = pte_offset_map(pmd, addr); -+ if (pte_present(*pte) == 0) { -+ pte_unmap(pte); -+ return INVALID_MPN; -+ } -+ mpn = pte_pfn(*pte); -+ pte_unmap(pte); -+ } -+ } -+ } -+ if (mpn >= INVALID_MPN) { -+ mpn = INVALID_MPN; - } +- } -} -+ return mpn; -+} /* @@ -777,10 +785,9 @@ - if (compat_get_page_table_lock(mm)) { - spin_unlock(compat_get_page_table_lock(mm)); - } -+ spin_unlock(&mm->page_table_lock); - return mpn; - } - +- return mpn; +-} +- - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -/* @@ -813,8 +820,9 @@ - if (compat_get_page_table_lock(mm)) { - spin_unlock(compat_get_page_table_lock(mm)); - } -- return mpn; --} ++ spin_unlock(&mm->page_table_lock); + return mpn; + } -#endif - - @@ -851,28 +859,18 @@ - return page; -} - -- + #endif /* __PGTBL_H__ */ --- a/vmmon/linux/driver.c +++ b/vmmon/linux/driver.c -@@ -80,6 +80,16 @@ - - struct VMXLinuxState linuxState; - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) -+static inline void do_gettimeofday(struct timeval *tv) -+{ -+ struct timespec64 now; -+ -+ ktime_get_real_ts64(&now); -+ tv->tv_sec = now.tv_sec; -+ tv->tv_usec = now.tv_nsec / 1000; -+} -+#endif - - /* - *---------------------------------------------------------------------- -@@ -108,7 +108,11 @@ +@@ -101,14 +101,16 @@ static int LinuxDriver_Open(struct inode + */ + int LinuxDriver_Ioctl(struct inode *inode, struct file *filp, + u_int iocmd, unsigned long ioarg); +-#if defined(HAVE_UNLOCKED_IOCTL) || defined(HAVE_COMPAT_IOCTL) + static long LinuxDriver_UnlockedIoctl(struct file *filp, + u_int iocmd, unsigned long ioarg); +-#endif static int LinuxDriver_Close(struct inode *inode, struct file *filp); static unsigned int LinuxDriverPoll(struct file *file, poll_table *wait); @@ -885,7 +883,7 @@ static int LinuxDriverFault(struct vm_area_struct *vma, struct vm_fault *fault); #else static struct page *LinuxDriverNoPage(struct vm_area_struct *vma, -@@ -117,7 +117,7 @@ +@@ -117,7 +119,7 @@ static struct page *LinuxDriverNoPage(st #endif static int LinuxDriverMmap(struct file *filp, struct vm_area_struct *vma); @@ -894,7 +892,69 @@ static struct vm_operations_struct vmuser_mops = { #ifdef VMW_NOPAGE_2624 -@@ -244,7 +259,7 @@ LinuxDriverEstimateTSCkHz(void) +@@ -166,61 +168,15 @@ VMX86_RegisterMonitor(int value) // IN: + return 1291; + } + +-#ifndef HAVE_COMPAT_IOCTL +-static int +-LinuxDriver_Ioctl32_Handler(unsigned int fd, +- unsigned int iocmd, +- unsigned long ioarg, +- struct file *filp) +-{ +- int ret = -ENOTTY; +- +- if (filp && filp->f_op && filp->f_op->ioctl == LinuxDriver_Ioctl) { +- ret = LinuxDriver_Ioctl(filp->f_dentry->d_inode, filp, iocmd, ioarg); +- } +- +- return ret; +-} +-#endif /* !HAVE_COMPAT_IOCTL */ +- + static int + register_ioctl32_handlers(void) + { +-#ifndef HAVE_COMPAT_IOCTL +- { +- int i; +- +- for (i = IOCTL_VMX86_FIRST; i < IOCTL_VMX86_LAST; i++) { +- int retval = register_ioctl32_conversion(i, +- LinuxDriver_Ioctl32_Handler); +- +- if (retval) { +- Warning("Fail to register ioctl32 conversion for cmd %d\n", i); +- +- return retval; +- } +- } +- } +-#endif /* !HAVE_COMPAT_IOCTL */ + return 0; + } + + static void + unregister_ioctl32_handlers(void) + { +-#ifndef HAVE_COMPAT_IOCTL +- { +- int i; +- +- for (i = IOCTL_VMX86_FIRST; i < IOCTL_VMX86_LAST; i++) { +- int retval = unregister_ioctl32_conversion(i); +- +- if (retval) { +- Warning("Fail to unregister ioctl32 conversion for cmd %d\n", i); +- } +- } +- } +-#endif /* !HAVE_COMPAT_IOCTL */ + } + + +@@ -244,7 +200,7 @@ unregister_ioctl32_handlers(void) */ static void @@ -903,7 +963,25 @@ { Vmx86_GetkHzEstimate(&linuxState.startTime); } -@@ -287,9 +302,13 @@ init_module(void) +@@ -253,7 +209,7 @@ + /* + *---------------------------------------------------------------------- + * +- * init_module -- ++ * LinuxDriverInit -- + * + * linux module entry point. Called by /sbin/insmod command + * +@@ -266,7 +222,7 @@ + */ + + int +-init_module(void) ++LinuxDriverInit(void) + { + int retval; + +@@ -287,9 +243,13 @@ */ init_waitqueue_head(&linuxState.pollQueue); @@ -918,7 +996,22 @@ linuxState.fastClockThread = NULL; linuxState.fastClockFile = NULL; -@@ -365,9 +363,13 @@ init_module(void) +@@ -310,14 +270,8 @@ + memset(&vmuser_fops, 0, sizeof vmuser_fops); + vmuser_fops.owner = THIS_MODULE; + vmuser_fops.poll = LinuxDriverPoll; +-#ifdef HAVE_UNLOCKED_IOCTL + vmuser_fops.unlocked_ioctl = LinuxDriver_UnlockedIoctl; +-#else +- vmuser_fops.ioctl = LinuxDriver_Ioctl; +-#endif +-#ifdef HAVE_COMPAT_IOCTL + vmuser_fops.compat_ioctl = LinuxDriver_UnlockedIoctl; +-#endif + vmuser_fops.open = LinuxDriver_Open; + vmuser_fops.release = LinuxDriver_Close; + vmuser_fops.mmap = LinuxDriverMmap; +@@ -365,9 +319,13 @@ */ Vmx86_ReadTSCAndUptime(&linuxState.startTime); @@ -933,7 +1026,58 @@ tscTimer.expires = jiffies + 4 * HZ; add_timer(&tscTimer); -@@ -903,7 +907,7 @@ +@@ -381,7 +339,7 @@ + /* + *---------------------------------------------------------------------- + * +- * cleanup_module -- ++ * LinuxDriverExit -- + * + * Called by /sbin/rmmod + * +@@ -390,7 +348,7 @@ + */ + + void +-cleanup_module(void) ++LinuxDriverExit(void) + { + unregister_ioctl32_handlers(); + +@@ -764,7 +722,6 @@ void + LinuxDriverWakeUp(Bool selective) // IN: + { + if (selective && linuxState.pollList != NULL) { +- struct timeval tv; + VmTimeType now; + VMLinux *p; + VMLinux *next; +@@ -777,8 +734,7 @@ LinuxDriverWakeUp(Bool selective) // IN + #else + HostIF_PollListLock(1); + #endif +- do_gettimeofday(&tv); +- now = tv.tv_sec * 1000000ULL + tv.tv_usec; ++ now = ktime_get_ns() / NSEC_PER_USEC; + + for (p = linuxState.pollList; p != NULL; p = next) { + next = p->pollForw; +@@ -850,12 +806,10 @@ LinuxDriverPoll(struct file *filp, // I + } + } else { + if (linuxState.fastClockThread && vmLinux->pollTimeoutPtr != NULL) { +- struct timeval tv; ++ u64 now = ktime_get_ns() / NSEC_PER_USEC; + +- do_gettimeofday(&tv); + poll_wait(filp, &vmLinux->pollQueue, wait); +- vmLinux->pollTime = *vmLinux->pollTimeoutPtr + +- tv.tv_sec * 1000000ULL + tv.tv_usec; ++ vmLinux->pollTime = *vmLinux->pollTimeoutPtr + now; + if (vmLinux->pollBack == NULL) { + #ifdef POLLSPINLOCK + unsigned long flags; +@@ -903,7 +857,7 @@ LinuxDriverPoll(struct file *filp, // I */ static void @@ -942,7 +1086,7 @@ { LinuxDriverWakeUp(FALSE); } -@@ -928,7 +934,15 @@ +@@ -928,7 +882,15 @@ LinuxDriverPollTimeout(unsigned long cli *----------------------------------------------------------------------------- */ @@ -959,7 +1103,7 @@ static int LinuxDriverFault(struct vm_area_struct *vma, //IN struct vm_fault *fault) //IN/OUT #else -@@ -937,6 +946,9 @@ +@@ -937,6 +899,9 @@ static struct page *LinuxDriverNoPage(st int *type) //OUT: Fault type #endif { @@ -969,7 +1113,19 @@ VMLinux *vmLinux = (VMLinux *) vma->vm_file->private_data; unsigned long pg; struct page* page; -@@ -1398,7 +1410,6 @@ LinuxDriver_Ioctl(struct file *filp, // IN: +@@ -1106,7 +1071,11 @@ LinuxDriverMmap(struct file *filp, + return err; + } + /* Clear VM_IO, otherwise SuSE's kernels refuse to do get_user_pages */ ++#if COMPAT_LINUX_VERSION_CHECK_LT(6, 3, 0) + vma->vm_flags &= ~VM_IO; ++#else ++ vm_flags_clear(vma, VM_IO); ++#endif + + return 0; + } +@@ -1398,7 +1363,6 @@ LinuxDriver_Ioctl(struct inode *inode, case IOCTL_VMX86_CREATE_VM: case IOCTL_VMX86_INIT_CROSSGDT: case IOCTL_VMX86_SET_UID: @@ -977,7 +1133,7 @@ #if defined(__linux__) && defined(VMX86_DEVEL) case IOCTL_VMX86_LOOK_UP_LARGE_MPN: #endif -@@ -1411,8 +1423,6 @@ LinuxDriver_Ioctl(struct file *filp, // IN: +@@ -1411,8 +1375,6 @@ LinuxDriver_Ioctl(struct inode *inode, case IOCTL_VMX86_GET_KHZ_ESTIMATE: case IOCTL_VMX86_GET_ALL_CPUID: case IOCTL_VMX86_GET_ALL_MSRS: @@ -986,7 +1142,7 @@ case IOCTL_VMX86_SET_POLL_TIMEOUT_PTR: case IOCTL_VMX86_GET_KERNEL_CLOCK_RATE: case IOCTL_VMX86_GET_REFERENCE_CLOCK_HZ: -@@ -1579,7 +1589,7 @@ LinuxDriver_Ioctl(struct file *filp, // IN: +@@ -1579,7 +1541,7 @@ LinuxDriver_Ioctl(struct inode *inode, if (retval) { break; } @@ -995,7 +1151,7 @@ retval = HostIF_CopyToUser((void *)ioarg, &args, sizeof args); break; } -@@ -1912,7 +1922,7 @@ LinuxDriver_Ioctl(struct file *filp, // IN: +@@ -1912,7 +1874,7 @@ LinuxDriver_Ioctl(struct inode *inode, if (retval) { break; } @@ -1004,7 +1160,7 @@ break; } -@@ -1923,7 +1933,7 @@ LinuxDriver_Ioctl(struct file *filp, // IN: +@@ -1923,7 +1885,7 @@ LinuxDriver_Ioctl(struct inode *inode, if (retval) { break; } @@ -1013,9 +1169,49 @@ break; } +@@ -2052,7 +2014,6 @@ exit: + } + + +-#if defined(HAVE_UNLOCKED_IOCTL) || defined(HAVE_COMPAT_IOCTL) + /* + *----------------------------------------------------------------------------- + * +@@ -2075,7 +2036,6 @@ LinuxDriver_UnlockedIoctl(struct file *f + { + return LinuxDriver_Ioctl(NULL, filp, iocmd, ioarg); + } +-#endif + + + /* +@@ -2198,3 +2162,5 @@ + * by default (i.e., neither mkinitrd nor modprobe will accept it). + */ + MODULE_INFO(supported, "external"); ++module_init(LinuxDriverInit); ++module_exit(LinuxDriverExit); --- a/vmmon/linux/hostif.c +++ b/vmmon/linux/hostif.c -@@ -77,19 +77,22 @@ +@@ -44,10 +44,6 @@ + + #include <linux/smp.h> + +-#ifndef HAVE_UNLOCKED_IOCTL +-#include <linux/smp_lock.h> +-#endif +- + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) + # include <asm/asm.h> + #endif +@@ -72,24 +68,30 @@ + #endif + + #include <asm/io.h> ++#include <asm/tlbflush.h> ++#include <asm/irq_vectors.h> + #include <asm/uaccess.h> + #include <linux/mc146818rtc.h> #include <linux/capability.h> #include <linux/kthread.h> #include <linux/wait.h> @@ -1024,6 +1220,7 @@ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include <linux/taskstats_kern.h> // For linux/sched/signal.h without version check +#endif ++#include <linux/eventfd.h> #include "vmware.h" #include "x86apic.h" @@ -1040,7 +1237,76 @@ #include "vmhost.h" #include "x86msr.h" #include "apic.h" -@@ -1010,7 +1013,7 @@ HostIF_FreeLockedPages(VMDriver *vm, // IN: VM instance pointer +@@ -119,6 +121,13 @@ + # define close_rtc(filp, files) filp_close(filp, files) + #endif + ++/* task's state is read-once rather than volatile from 5.14-rc2. */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) || defined(get_current_state) ++#define get_task_state(task) READ_ONCE((task)->__state) ++#else ++#define get_task_state(task) ((task)->state) ++#endif ++ + #define UPTIME_FREQ CONST64(1000000) + + /* +@@ -478,7 +487,7 @@ + while ((vcpuid = VCPUSet_FindFirst(&req)) != VCPUID_INVALID) { + struct task_struct *t = vm->vmhost->vcpuSemaTask[vcpuid]; + VCPUSet_Remove(&req, vcpuid); +- if (t && (t->state & TASK_INTERRUPTIBLE)) { ++ if (t && (get_task_state(t) & TASK_INTERRUPTIBLE)) { + wake_up_process(t); + } + } +@@ -630,6 +632,15 @@ HostIF_FastClockUnlock(int callerID) // + MutexUnlock(&fastClockMutex, callerID); + } + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) ++static int crosspage_set_exec(pte_t *pte, unsigned long addr, void *data) ++{ ++ struct page *p = data; ++ ++ set_pte(pte, mk_pte(p, VM_PAGE_KERNEL_EXEC)); ++ return 0; ++} ++#endif + + /* + *----------------------------------------------------------------------------- +@@ -696,7 +707,29 @@ HostIF_PollListUnlock(int callerID) // I + static void * + MapCrossPage(struct page *p) // IN: + { ++#if COMPAT_LINUX_VERSION_CHECK_LT(5, 8, 0) + return vmap(&p, 1, VM_MAP, VM_PAGE_KERNEL_EXEC); ++#else ++ void *addr; ++ ++ addr = vmap(&p, 1, VM_MAP, VM_PAGE_KERNEL_EXEC); ++ if (!addr) ++ return NULL; ++ ++ /* Starting with 5.8, vmap() always sets the NX bit, but the cross ++ * page needs to be executable. */ ++ if (apply_to_page_range(current->mm, (unsigned long)addr, PAGE_SIZE, ++ crosspage_set_exec, p)) { ++ vunmap(addr); ++ return NULL; ++ } ++ ++ preempt_disable(); ++ __flush_tlb_all(); ++ preempt_enable(); ++ ++ return addr; ++#endif + } + + +@@ -1010,7 +1043,7 @@ HostIF_FreeLockedPages(VMDriver *vm, int HostIF_Init(VMDriver *vm) // IN: { @@ -1049,7 +1315,7 @@ if (vm->memtracker == NULL) { return -1; } -@@ -1165,10 +1173,7 @@ +@@ -1165,10 +1198,7 @@ HostIFGetUserPages(void *uvAddr, { int retval; @@ -1061,7 +1327,7 @@ return retval != numPages; } -@@ -1606,9 +1606,13 @@ +@@ -1606,9 +1636,13 @@ HostIF_EstimateLockedPageLimit(const VMD * since at least 2.6.0. */ @@ -1075,7 +1341,7 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) return MemDefaults_CalcMaxLockedPages(totalPhysicalPages); -@@ -1626,12 +1631,34 @@ HostIF_EstimateLockedPageLimit(const VMDriver* vm, // IN +@@ -1626,13 +1660,37 @@ HostIF_EstimateLockedPageLimit(const VMD unsigned int reservedPages = MEMDEFAULTS_MIN_HOST_PAGES; unsigned int hugePages = (vm == NULL) ? 0 : BYTES_2_PAGES(vm->memInfo.hugePageBytes); @@ -1087,7 +1353,7 @@ + unsigned int lockedPages = hugePages + reservedPages; + unsigned int anonPages; unsigned int swapPages = BYTES_2_PAGES(linuxState.swapSize); -+ + + /* global_page_state is global_zone_page_state in 4.14. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + lockedPages += global_zone_page_state(NR_PAGETABLE); @@ -1095,7 +1361,9 @@ + lockedPages += global_page_state(NR_PAGETABLE); +#endif + /* NR_SLAB_* moved from zone to node in 4.13. */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) ++ lockedPages += global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B); ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) + lockedPages += global_node_page_state(NR_SLAB_UNRECLAIMABLE); +#else + lockedPages += global_page_state(NR_SLAB_UNRECLAIMABLE); @@ -1112,10 +1380,11 @@ +#else + anonPages = global_page_state(NR_ANON_PAGES); +#endif - ++ if (anonPages > swapPages) { lockedPages += anonPages - swapPages; -@@ -1691,6 +1717,49 @@ + } +@@ -1691,6 +1749,49 @@ HostIF_WaitForFreePages(unsigned int tim /* *---------------------------------------------------------------------- * @@ -1165,7 +1434,7 @@ * HostIFReadUptimeWork -- * * Reads the current uptime. The uptime is based on getimeofday, -@@ -1719,16 +1788,12 @@ +@@ -1719,16 +1820,12 @@ HostIF_WaitForFreePages(unsigned int tim static uint64 HostIFReadUptimeWork(unsigned long *j) // OUT: current jiffies { @@ -1182,7 +1451,7 @@ retry: do { version = VersionedAtomic_BeginTryRead(&uptimeState.version); -@@ -1737,13 +1802,12 @@ +@@ -1737,13 +1834,12 @@ HostIFReadUptimeWork(unsigned long *j) monoBase = uptimeState.monotimeBase; } while (!VersionedAtomic_EndTryRead(&uptimeState.version, version)); @@ -1197,7 +1466,7 @@ uptime += upBase; /* -@@ -1794,7 +1818,7 @@ HostIFReadUptimeWork(unsigned long *j) // OUT: current jiffies +@@ -1794,7 +1890,7 @@ HostIFReadUptimeWork(unsigned long *j) */ static void @@ -1206,7 +1475,7 @@ { unsigned long jifs; uintptr_t flags; -@@ -1848,16 +1912,19 @@ +@@ -1848,16 +1944,19 @@ HostIFUptimeResyncMono(unsigned long dat void HostIF_InitUptime(void) { @@ -1232,7 +1501,7 @@ mod_timer(&uptimeState.timer, jiffies + HZ); } -@@ -2028,15 +2052,15 @@ HostIF_MapCrossPage(VMDriver *vm, // IN +@@ -2028,15 +2127,15 @@ HostIF_MapCrossPage(VMDriver *vm, // IN return NULL; } vPgAddr = (VA) MapCrossPage(page); @@ -1251,38 +1520,166 @@ ret = vPgAddr | (((VA)p) & (PAGE_SIZE - 1)); -@@ -2278,7 +2345,7 @@ isVAReadable(VA r) // IN: +@@ -2273,16 +2372,26 @@ HostIF_VMLockIsHeld(VMDriver *vm) // IN + static Bool + isVAReadable(VA r) // IN: + { +- mm_segment_t old_fs; + uint32 dummy; int ret; ++#if defined(HAVE_GET_KERNEL_NOFAULT) || LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) ++ /* ++ * Exists from 5.10, first indicated by HAVE_GET_KERNEL_NOFAULT, ++ * and from post-5.17 just existing everywhere. ++ */ ++ ret = get_kernel_nofault(dummy, (void *)r); ++#else ++ { ++ mm_segment_t old_fs; ++ old_fs = get_fs(); - set_fs(get_ds()); + set_fs(KERNEL_DS); r = APICR_TO_ADDR(r, APICR_VERSION); ret = HostIF_CopyFromUser(&dummy, (void*)r, sizeof(dummy)); set_fs(old_fs); -@@ -2479,7 +2546,7 @@ HostIF_SemaphoreWait(VMDriver *vm, // IN: +- ++ } ++#endif + return ret == 0; + } + +@@ -2311,7 +2416,7 @@ SetVMAPICAddr(VMDriver *vm, // IN/OUT: d + volatile void *hostapic; + + ASSERT_ON_COMPILE(APICR_SIZE <= PAGE_SIZE); +- hostapic = (volatile void *) ioremap_nocache(ma, PAGE_SIZE); ++ hostapic = (volatile void *) ioremap(ma, PAGE_SIZE); + if (hostapic) { + if ((APIC_VERSIONREG(hostapic) & 0xF0) == 0x10) { + vm->hostAPIC.base = (volatile uint32 (*)[4]) hostapic; +@@ -2467,7 +2572,6 @@ HostIF_SemaphoreWait(VMDriver *vm, // + uint64 *args) // IN: + { + struct file *file; +- mm_segment_t old_fs; + int res; + int waitFD = args[0]; + int timeoutms = args[2]; +@@ -2478,22 +2582,19 @@ HostIF_SemaphoreWait(VMDriver *vm, // + return MX_WAITERROR; } - old_fs = get_fs(); +- old_fs = get_fs(); - set_fs(get_ds()); -+ set_fs(KERNEL_DS); - +- { struct poll_wqueues table; -@@ -2608,7 +2675,7 @@ HostIF_SemaphoreSignal(uint64 *args) // IN: + unsigned int mask; + + poll_initwait(&table); +- current->state = TASK_INTERRUPTIBLE; ++ __set_current_state(TASK_INTERRUPTIBLE); + mask = file->f_op->poll(file, &table.pt); + if (!(mask & (POLLIN | POLLERR | POLLHUP))) { + vm->vmhost->vcpuSemaTask[vcpuid] = current; + schedule_timeout(timeoutms * HZ / 1000); // convert to Hz + vm->vmhost->vcpuSemaTask[vcpuid] = NULL; + } +- current->state = TASK_RUNNING; ++ __set_current_state(TASK_RUNNING); + poll_freewait(&table); } - old_fs = get_fs(); +@@ -2502,9 +2603,11 @@ HostIF_SemaphoreWait(VMDriver *vm, // + * the code to happily deal with a pipe or an eventfd. We only care about + * reading no bytes (EAGAIN - non blocking fd) or sizeof(uint64). + */ +- +- res = file->f_op->read(file, (char *) &value, sizeof value, &file->f_pos); +- ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ res = kernel_read(file, file->f_pos, (char *)&value, sizeof value); ++#else ++ res = kernel_read(file, &value, sizeof value, &file->f_pos); ++#endif + if (res == sizeof value) { + res = MX_WAITNORMAL; + } else { +@@ -2513,7 +2616,6 @@ HostIF_SemaphoreWait(VMDriver *vm, // + } + } + +- set_fs(old_fs); + fput(file); + + /* +@@ -2566,7 +2675,7 @@ + FOR_EACH_VCPU_IN_SET(vcs, vcpuid) { + struct task_struct *t = vm->vmhost->vcpuSemaTask[vcpuid]; + vm->vmhost->vcpuSemaTask[vcpuid] = NULL; +- if (t && (t->state & TASK_INTERRUPTIBLE)) { ++ if (t && (get_task_state(t) & TASK_INTERRUPTIBLE)) { + wake_up_process(t); + } + } ROF_EACH_VCPU_IN_SET(); +@@ -2596,8 +2698,8 @@ HostIF_SemaphoreForceWakeup(VMDriver *vm + int + HostIF_SemaphoreSignal(uint64 *args) // IN: + { ++ struct eventfd_ctx *eventfd; + struct file *file; +- mm_segment_t old_fs; + int res; + int signalFD = args[1]; + uint64 value = 1; // make an eventfd happy should it be there +@@ -2607,22 +2709,36 @@ HostIF_SemaphoreSignal(uint64 *args) // + return MX_WAITERROR; + } + +- old_fs = get_fs(); - set_fs(get_ds()); -+ set_fs(KERNEL_DS); ++ /* ++ * If it's eventfd, use specific eventfd interface as kernel writes ++ * to eventfd may not be allowed in kernel 5.10 and later. ++ */ ++ eventfd = eventfd_ctx_fileget(file); ++ if (!IS_ERR(eventfd)) { ++#if COMPAT_LINUX_VERSION_CHECK_LT(6, 8, 0) ++ eventfd_signal(eventfd, 1); ++#else ++ eventfd_signal(eventfd); ++#endif ++ fput(file); ++ return MX_WAITNORMAL; ++ } /* * Always write sizeof(uint64) bytes. This works fine for eventfd and -@@ -2850,13 +2874,75 @@ HostIF_CallOnEachCPU(void (*func)(void*), // IN: function to call - } + * pipes. The data written is formatted to make an eventfd happy should + * it be present. + */ +- +- res = file->f_op->write(file, (char *) &value, sizeof value, &file->f_pos); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ res = kernel_write(file, (char *)&value, sizeof value, file->f_pos); ++#else ++ res = kernel_write(file, &value, sizeof value, &file->f_pos); ++#endif + if (res == sizeof value) { + res = MX_WAITNORMAL; + } -+/* +- set_fs(old_fs); + fput(file); + + /* +@@ -2851,12 +2963,74 @@ HostIF_CallOnEachCPU(void (*func)(void*) + + + /* + *----------------------------------------------------------------------------- + * + * HostIFCheckTrackedMPN -- @@ -1343,7 +1740,7 @@ +} + + - /* ++/* *---------------------------------------------------------------------- * * HostIF_ReadPage -- @@ -1356,7 +1753,7 @@ * * Results: * 0 on success -@@ -2869,7 +2955,8 @@ HostIF_CallOnEachCPU(void (*func)(void*), // IN: function to call +@@ -2869,7 +3043,8 @@ HostIF_CallOnEachCPU(void (*func)(void*) */ int @@ -1366,7 +1763,7 @@ VA64 addr, // buffer for data Bool kernelBuffer) // is the buffer in kernel space? { -@@ -2881,6 +2968,9 @@ HostIF_ReadPage(MPN64 mpn, // MPN of the page +@@ -2881,6 +3056,9 @@ HostIF_ReadPage(MPN64 mpn, // if (mpn == INVALID_MPN) { return -EFAULT; } @@ -1376,7 +1773,7 @@ page = pfn_to_page(mpn); ptr = kmap(page); -@@ -2904,8 +2994,8 @@ HostIF_ReadPage(MPN64 mpn, // MPN of the page +@@ -2904,8 +3082,8 @@ HostIF_ReadPage(MPN64 mpn, // * * HostIF_WritePage -- * @@ -1387,7 +1784,7 @@ * * Results: * 0 on success -@@ -2918,9 +3008,9 @@ HostIF_ReadPage(MPN64 mpn, // MPN of the page +@@ -2918,9 +3096,9 @@ HostIF_ReadPage(MPN64 mpn, // */ int @@ -1400,7 +1797,7 @@ { void const *buf = VA64ToPtr(addr); int ret = 0; -@@ -2947,6 +3037,45 @@ HostIF_WritePage(MPN64 mpn, // MPN of the page +@@ -2947,6 +3125,45 @@ HostIF_WritePage(MPN64 mpn, / return ret; } @@ -1446,7 +1843,51 @@ /* *---------------------------------------------------------------------- -@@ -3464,7 +3477,6 @@ HostIF_SetFastClockRate(unsigned int rate) // IN: Frequency in Hz. +@@ -3160,21 +3377,9 @@ HostIFDoIoctl(struct file *filp, + u_int iocmd, + unsigned long ioarg) + { +-#ifdef HAVE_UNLOCKED_IOCTL + if (filp->f_op->unlocked_ioctl) { + return filp->f_op->unlocked_ioctl(filp, iocmd, ioarg); + } +-#else +- if (filp->f_op->ioctl) { +- long err; +- +- lock_kernel(); +- err = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, iocmd, ioarg); +- unlock_kernel(); +- +- return err; +- } +-#endif + return -ENOIOCTLCMD; + } + #endif //VMON_USE_HIGH_RES_TIMERS +@@ -3304,12 +3509,9 @@ HostIFFastClockThread(void *data) // IN + { + struct file *filp = (struct file *) data; + int res; +- mm_segment_t oldFS; + unsigned int rate = 0; + unsigned int prevRate = 0; + +- oldFS = get_fs(); +- set_fs(KERNEL_DS); + allow_signal(SIGKILL); + set_user_nice(current, linuxState.fastClockPriority); + +@@ -3343,8 +3545,6 @@ HostIFFastClockThread(void *data) // IN + + out: + LinuxDriverWakeUp(TRUE); +- set_fs(oldFS); +- + /* + * Do not exit thread until we are told to do so. + */ +@@ -3464,7 +3664,6 @@ HostIF_SetFastClockRate(unsigned int rat } } else { if (linuxState.fastClockThread) { @@ -1454,7 +1895,7 @@ kthread_stop(linuxState.fastClockThread); close_rtc(linuxState.fastClockFile, current->files); -@@ -3512,7 +3684,12 @@ +@@ -3512,7 +3711,12 @@ HostIF_MapUserMem(VA addr, ASSERT(handle); @@ -1484,3 +1925,185 @@ break; } +From 4c2a103fd2d71f2084f1fe7ceacb816b9832ffa2 Mon Sep 17 00:00:00 2001 +From: Michal Kubecek <mkubecek@suse.cz> +Date: Sun, 22 Oct 2023 23:24:05 +0200 +Subject: [PATCH] vmmon: use get_user_pages to get page PFN + +As a side effect of mainline commit 0d940a9b270b ("mm/pgtable: allow +pte_offset_map[_lock]() to fail") in 6.5-rc1, __pte_offset_map(), called by +pte_offset_map(), is no longer exported. WMware developers decided to hack +around this by replacing pte_offset_map() by pte_offset_kernel() which does +not seem to be a good idea and apparently may trigger warn checks in RCU +code on some systems as mentioned in the discussion on issue #223. +Therefore let's use the same solution as we had for 17.0.2 and older +versions as it does not show these problems. + +Based on an upstream IRC discussion and the hva_to_pfn_*() family of +functions in KVM code, what PgtblVa2MPNLocked() does seems to be an +incomplete and partial open coded logic of get_user_pages() and as it is +only used to get PFN from a virtual address, it can be easily implemented +using get_user_pages() family. + +Without knowledge what exactly are the PFNs used for in VMware, it is hard +to guess the right flags, these seem to work and have been tested by +multiple users over last few weeks. + +We could likely use get_user_pages() also on older kernels and it might be +actually cleaner and more reliable as existing open coded implementation +does not seem to handle some corner cases but without knowledge of VMware +internals, it will be safer to stick to existing code where possible. +--- + vmmon-only/include/pgtbl.h | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/vmmon-only/include/pgtbl.h b/vmmon-only/include/pgtbl.h +index 3f43c62..7eaa49a 100644 +--- a/vmmon-only/include/pgtbl.h ++++ b/vmmon-only/include/pgtbl.h +@@ -25,6 +25,7 @@ + #include "compat_pgtable.h" + #include "compat_spinlock.h" + #include "compat_page.h" ++#include "compat_version.h" + + + /* +@@ -45,6 +46,7 @@ + *----------------------------------------------------------------------------- + */ + ++#if COMPAT_LINUX_VERSION_CHECK_LT(6, 5, 0) // only used by PgtblVa2MPN() below + static INLINE MPN64 + PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process + VA addr) // IN: Address in the virtual address +@@ -110,6 +112,7 @@ PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process + } + return mpn; + } ++#endif + + + /* +@@ -129,6 +132,8 @@ PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process + *----------------------------------------------------------------------------- + */ + ++#if COMPAT_LINUX_VERSION_CHECK_LT(6, 5, 0) ++ + static INLINE MPN64 + PgtblVa2MPN(VA addr) // IN + { +@@ -143,4 +148,24 @@ PgtblVa2MPN(VA addr) // IN + return mpn; + } + ++#else /* COMPAT_LINUX_VERSION_CHECK_LT(6, 5, 0) */ ++ ++static INLINE MPN64 ++PgtblVa2MPN(VA addr) // IN ++{ ++ struct page *page; ++ int npages; ++ MPN mpn; ++ ++ npages = get_user_pages_unlocked(addr, 1, &page, FOLL_HWPOISON); ++ if (npages != 1) ++ return INVALID_MPN; ++ mpn = page_to_pfn(page); ++ put_page(page); ++ ++ return mpn; ++} ++ ++#endif /* COMPAT_LINUX_VERSION_CHECK_LT(6, 5, 0) */ ++ + #endif /* __PGTBL_H__ */ +From 218fec600d0af1c5e9f4af819b216fb9c69bb838 Mon Sep 17 00:00:00 2001 +From: Michal Kubecek <mkubecek@suse.cz> +Date: Fri, 12 Jan 2024 08:30:33 +0100 +Subject: [PATCH] modules: fix build with -Wmissing-prototypes + +Mainline commit 0fcb70851fbf ("Makefile.extrawarn: turn on +missing-prototypes globally") in 6.8-rc1 enables -Wmissing-prototypes +globally, revealing a lot of unclean code and also some actual problems. +This is also the case in vmmon and vmnet modules. + +Most of them are addressed by making functions used only within one file +static. The missing prototype of random_get_entropy_fallback() is handled +by including <linux/timex.h> rather than <asm/timex.h>. + +Finally, there are four functions in vmnet module which are actually used +in multiple files but instead of proper declarations, their prototype is +duplicated in vmnet-only/driver.c, risking that the two copies won't match +(which actually happened in one case). The cleanest solution would be +creating separate header files for them (bridge.h, netif.h, userif.h and +vnetUserListener.h) and including them in the respective source file and +driver.c. As the developers already handle similar cases by simply putting +the declarations into vnetInt.h, let us do the same to keep things simple. +--- + vmmon-only/common/vmx86.c | 2 +- + vmmon-only/linux/driver.c | 4 ++-- + vmmon-only/linux/hostif.c | 6 +++--- + vmnet-only/bridge.c | 2 +- + vmnet-only/driver.c | 16 ++-------------- + vmnet-only/vnetInt.h | 7 +++++++ + 6 files changed, 16 insertions(+), 21 deletions(-) + +diff --git a/vmmon-only/common/vmx86.c b/vmmon-only/common/vmx86.c +index 156e94a9..c5ed3e25 100644 +--- a/vmmon-only/common/vmx86.c ++++ b/vmmon-only/common/vmx86.c +@@ -58,7 +58,7 @@ + #include "x86svm.h" + #include "x86cpuid_asm.h" + #if defined(linux) +-#include <asm/timex.h> ++#include <linux/timex.h> + #endif + #include "x86perfctr.h" + +diff --git a/vmmon-only/linux/driver.c b/vmmon-only/linux/driver.c +index 9c855869..32e9c5ea 100644 +--- a/vmmon-only/linux/driver.c ++++ b/vmmon-only/linux/driver.c +@@ -221,7 +221,7 @@ LinuxDriverInitTSCkHz(void) + *---------------------------------------------------------------------- + */ + +-int ++static int + LinuxDriverInit(void) + { + int retval; +@@ -347,7 +347,7 @@ LinuxDriverInit(void) + *---------------------------------------------------------------------- + */ + +-void ++static void + LinuxDriverExit(void) + { + unregister_ioctl32_handlers(); +diff --git a/vmmon-only/linux/hostif.c b/vmmon-only/linux/hostif.c +index 3bce32c3..b83e21d3 100644 +--- a/vmmon-only/linux/hostif.c ++++ b/vmmon-only/linux/hostif.c +@@ -3110,7 +3110,7 @@ HostIF_ReadPage(VMDriver *vm, // IN: The VM instance + *---------------------------------------------------------------------- + */ + +-int ++static int + HostIFWritePageWork(MPN64 mpn, // MPN of the page + VA64 addr, // data to write to the page + Bool kernelBuffer) // is the buffer in kernel space? +@@ -3416,7 +3416,7 @@ HostIFDoIoctl(struct file *filp, + *---------------------------------------------------------------------- + */ + +-int ++static int + HostIFStartTimer(Bool rateChanged, //IN: Did rate change? + unsigned int rate, //IN: current clock rate + struct file *filp) //IN: /dev/rtc descriptor diff --git a/vmnet.patch b/vmnet.patch index ae2b7a0baebb..7ff679b5a80b 100644 --- a/vmnet.patch +++ b/vmnet.patch @@ -1,6 +1,6 @@ --- a/vmnet/Makefile +++ b/vmnet/Makefile -@@ -43,7 +43,11 @@ INCLUDE += -I$(SRCROOT)/shared +@@ -43,7 +43,11 @@ endif @@ -37,7 +37,26 @@ MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild --- a/vmnet/bridge.c +++ b/vmnet/bridge.c -@@ -636,7 +636,7 @@ +@@ -26,6 +26,9 @@ + #include <linux/slab.h> + #include <linux/poll.h> + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 10) ++#include <net/gso.h> ++#endif + #include <linux/netdevice.h> + #include <linux/etherdevice.h> + #include <linux/mm.h> +@@ -65,7 +65,7 @@ + #endif + + #if LOGLEVEL >= 4 +-static struct timeval vnetTime; ++static u64 vnetTime; + #endif + + typedef struct VNetBridge VNetBridge; +@@ -636,7 +636,7 @@ VNetBridgeReceiveFromVNet(VNetJack unsigned long flags; int i; @@ -46,7 +65,30 @@ clone->dev = dev; clone->protocol = eth_type_trans(clone, dev); -@@ -1143,11 +1143,16 @@ +@@ -687,16 +687,13 @@ + } + spin_unlock_irqrestore(&bridge->historyLock, flags); + +- /* +- * We used to cli() before calling netif_rx() here. It was probably +- * unneeded (as we never did it in netif.c, and the code worked). In +- * any case, now that we are using netif_rx_ni(), we should certainly +- * not do it, or netif_rx_ni() will deadlock on the cli() lock --hpreg +- */ +- +- netif_rx_ni(clone); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) ++ netif_rx_ni(clone); ++#else ++ netif_rx(clone); ++#endif + # if LOGLEVEL >= 4 +- do_gettimeofday(&vnetTime); ++ vnetTime = ktime_get_ns(); + # endif + } + } +@@ -1143,11 +1143,16 @@ VNetBridgeNotifyLogBridgeUpError(int err static int VNetBridgeNotify(struct notifier_block *this, // IN: callback data (bridge) u_long msg, // IN: type of event @@ -65,9 +107,26 @@ switch (msg) { case NETDEV_UNREGISTER: LOG(2, (KERN_DEBUG "bridge-%s: interface %s is unregistering\n", +@@ -1656,12 +1661,11 @@ VNetBridgeReceiveFromDev(struct sk_buff + + # if LOGLEVEL >= 4 + { +- struct timeval now; +- do_gettimeofday(&now); ++ u64 now; ++ ++ now = ktime_get_ns(); + LOG(3, (KERN_DEBUG "bridge-%s: time %d\n", +- bridge->name, +- (int)((now.tv_sec * 1000000 + now.tv_usec) +- - (vnetTime.tv_sec * 1000000 + vnetTime.tv_usec)))); ++ bridge->name, (int)((now - vnetTime) / NSEC_PER_USEC))); + } + # endif + --- a/vmnet/compat_netdevice.h +++ b/vmnet/compat_netdevice.h -@@ -337,4 +337,11 @@ +@@ -337,4 +337,11 @@ typedef netdev_features_t compat_netdev_ typedef u32 compat_netdev_features_t; #endif @@ -79,9 +138,53 @@ +#endif + #endif /* __COMPAT_NETDEVICE_H__ */ +--- a/vmnet/driver.c ++++ b/vmnet/driver.c +@@ -279,7 +279,7 @@ + /* + *---------------------------------------------------------------------- + * +- * init_module -- ++ * LinuxDriverInit -- + * + * linux module entry point. Called by /sbin/insmod command. + * Initializes module and Registers this driver for a +@@ -296,7 +296,7 @@ + */ + + int +-init_module(void) ++LinuxDriverInit(void) + { + int retval; + +@@ -358,7 +358,7 @@ + /* + *---------------------------------------------------------------------- + * +- * cleanup_module -- ++ * LinuxDriverExit -- + * + * Called by /sbin/rmmod. Unregisters this driver for a + * vnet major #, and deinitializes the modules. The 64-bit +@@ -375,7 +375,7 @@ + */ + + void +-cleanup_module(void) ++LinuxDriverExit(void) + { + unregister_chrdev(VNET_MAJOR_NUMBER, "vmnet"); + VNetProtoUnregister(); +@@ -1705,3 +1705,5 @@ + * by default (i.e., neither mkinitrd nor modprobe will accept it). + */ + MODULE_INFO(supported, "external"); ++module_init(LinuxDriverInit); ++module_exit(LinuxDriverExit); --- a/vmnet/netif.c +++ b/vmnet/netif.c -@@ -149,7 +149,7 @@ +@@ -149,7 +149,7 @@ VNetNetIf_Create(char *devName, // IN: memcpy(deviceName, devName, sizeof deviceName); NULL_TERMINATE_STRING(deviceName); @@ -90,7 +193,31 @@ dev = alloc_netdev(sizeof *netIf, deviceName, NET_NAME_USER, VNetNetIfSetup); #else dev = alloc_netdev(sizeof *netIf, deviceName, VNetNetIfSetup); -@@ -465,7 +465,7 @@ +@@ -219,7 +219,11 @@ + + memset(&netIf->stats, 0, sizeof netIf->stats); + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) + memcpy(dev->dev_addr, netIf->port.paddr, sizeof netIf->port.paddr); ++#else ++ eth_hw_addr_set(dev, netIf->port.paddr); ++#endif + + if (register_netdev(dev) != 0) { + LOG(0, (KERN_NOTICE "%s: could not register network device\n", +@@ -311,7 +315,11 @@ + /* send to the host interface */ + skb->dev = netIf->dev; + skb->protocol = eth_type_trans(skb, netIf->dev); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) + netif_rx_ni(skb); ++#else ++ netif_rx(skb); ++#endif + netIf->stats.rx_packets++; + + return; +@@ -465,7 +465,7 @@ VNetNetifStartXmit(struct sk_buff *sk VNetSend(&netIf->port.jack, skb); netIf->stats.tx_packets++; @@ -99,6 +226,72 @@ return 0; } +@@ -498,7 +506,11 @@ + return -EINVAL; + } + memcpy(netIf->port.paddr, addr->sa_data, dev->addr_len); +- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) ++ memcpy(dev->dev_addr, netIf->port.paddr, dev->addr_len); ++#else ++ eth_hw_addr_set(dev, netIf->port.paddr); ++#endif + return 0; + } + +--- a/vmnet/procfs.c ++++ a/vmnet/procfs.c +@@ -137,6 +137,7 @@ VNetProcShow(struct seq_file *p, // IN: + } + + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) + /* + *---------------------------------------------------------------------- + * +@@ -168,6 +169,7 @@ static struct file_operations fops = { + .release = single_release, + }; + #endif ++#endif + + + /* +@@ -203,7 +205,12 @@ VNetProcMakeEntryInt(VNetProcEntry *pa + } else { + ent->data = data; + ent->fn = fn; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) ++ ent->pde = proc_create_single_data(name, mode, parent->pde, ++ VNetProcShow, ent); ++#else + ent->pde = proc_create_data(name, mode, parent->pde, &fops, ent); ++#endif + } + if (ent->pde != NULL) { + *ret = ent; +--- a/vmnet/smac.c ++++ b/vmnet/smac.c +@@ -4115,7 +4115,7 @@ + + void SMACINT + SMAC_SetMac(SMACState *state, // IN: state to update +- uint8 *mac) // IN: pointer to host adapter's MAC ++ const uint8 *mac) // IN: pointer to host adapter's MAC + { + VNETKdPrintCall(("SMAC_SetMac")); + ASSERT(state); +--- a/vmnet/smac.h ++++ b/vmnet/smac.h +@@ -72,7 +72,7 @@ + void SMACINT + SMAC_InitState(struct SMACState **ptr); // IN: state to alloc/init + void SMACINT +-SMAC_SetMac(struct SMACState *state, uint8 *mac); // IN: state, and host MAC ++SMAC_SetMac(struct SMACState *state, const uint8 *mac); // IN: state, and host MAC + void SMACINT + SMAC_CleanupState(struct SMACState **ptr); // IN: state to cleanup/dealloc + --- a/vmnet/userif.c +++ b/vmnet/userif.c @@ -36,6 +36,9 @@ @@ -111,7 +304,24 @@ #include <net/checksum.h> #include <net/sock.h> -@@ -112,10 +113,7 @@ +@@ -81,11 +84,11 @@ static int VNetUserIfSetUplinkState(VNe + extern unsigned int vnet_max_qlen; + + #if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) +-# define compat_kmap(page) kmap(page) +-# define compat_kunmap(page) kunmap(page) +-#else +-# define compat_kmap(page) kmap((page).p) +-# define compat_kunmap(page) kunmap((page).p) ++# define skb_frag_page(frag) (frag)->page ++# define skb_frag_size(frag) (frag)->size ++#endif ++#if COMPAT_LINUX_VERSION_CHECK_LT(5, 4, 0) ++# define skb_frag_off(frag) (frag)->page_offset + #endif + + /* +@@ -112,10 +115,7 @@ UserifLockPage(VA addr) // IN struct page *page = NULL; int retval; @@ -123,7 +333,7 @@ if (retval != 1) { return NULL; -@@ -143,16 +143,21 @@ +@@ -143,16 +143,21 @@ UserifLockPage(VA addr) // IN */ static INLINE int @@ -149,7 +359,7 @@ *p = UserifLockPage(uAddr); if (*p == NULL) { -@@ -164,7 +169,7 @@ +@@ -164,7 +169,7 @@ VNetUserIfMapPtr(VA uAddr, // IN: } static INLINE int @@ -158,7 +368,7 @@ struct page **p, // OUT: locked page uint32 **ptr) // OUT: kernel mapped pointer { -@@ -209,7 +214,7 @@ +@@ -209,7 +214,7 @@ VNetUserIfSetupNotify(VNetUserIF *userIf return -EBUSY; } @@ -167,7 +377,7 @@ &pollPtr)) < 0) { return retval; } -@@ -227,7 +232,7 @@ +@@ -227,7 +232,7 @@ VNetUserIfSetupNotify(VNetUserIF *userIf goto error_free; } @@ -176,80 +386,72 @@ &recvClusterPage, &recvClusterCount)) < 0) { goto error_free; ---- a/vmnet/vmnetInt.h -+++ b/vmnet/vmnetInt.h -@@ -77,7 +77,7 @@ - - - extern struct proto vmnet_proto; --#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) || defined(sk_net_refcnt) - # define compat_sk_alloc(_bri, _pri) sk_alloc(&init_net, \ - PF_NETLINK, _pri, &vmnet_proto, 1) - #elif defined(VMW_NETDEV_HAS_NET) -From f404bc6855ea2c731b617d3b0a2971481eb31cbd Mon Sep 17 00:00:00 2001 -From: Michal Kubecek <mkubecek@suse.cz> -Date: Thu, 19 Sep 2019 12:20:20 +0200 -Subject: [PATCH] vmnet: handle switch of skb_frag_t to bio_vec - -The switch from custom skb_frag_t implementation to bio_vec in v5.4-rc1 is -mostly transparent for modules which use accessor for skb_frag_t members. -Unfortunately many users access the members directly and function -VNetCsumCopyDatagram() in vmnet is one of those. - -Use accessors everywhere so that vmnet code is compatible with kernel 5.4 -and newer. Use "compat_" prefix to avoid clashes with backports adding the -accessors to older codebase. ---- - vmnet-only/userif.c | 39 +++++++++++++++++++++++++++++---------- - 1 file changed, 29 insertions(+), 10 deletions(-) - -diff --git a/vmnet-only/userif.c b/vmnet-only/userif.c -index d385088..aab9478 100644 ---- a/vmnet-only/userif.c -+++ b/vmnet-only/userif.c -@@ -84,13 +84,31 @@ static int VNetUserIfSetUplinkState(VNetPort *port, uint8 linkUp); - extern unsigned int vnet_max_qlen; - - #if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) --# define compat_kmap(page) kmap(page) --# define compat_kunmap(page) kunmap(page) -+# define compat_kmap_frag(frag) kmap((frag)->page) -+# define compat_kunmap_frag(page) kunmap((frag)->page) - #else --# define compat_kmap(page) kmap((page).p) --# define compat_kunmap(page) kunmap((page).p) -+# define compat_kmap_frag(frag) kmap(skb_frag_page(frag)) -+# define compat_kunmap_frag(frag) kunmap(skb_frag_page(frag)) - #endif - -+static unsigned int compat_skb_frag_size(const skb_frag_t *frag) -+{ -+#if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) -+ return frag->size; -+#else -+ return skb_frag_size(frag); -+#endif -+} +@@ -537,6 +542,50 @@ + /* + *---------------------------------------------------------------------- + * ++ * VNetCsumAndCopyToUser -- ++ * ++ * Checksum data and copy them to userspace. ++ * ++ * Results: ++ * folded checksum (non-zero value) on success, ++ * err set to 0 on success, negative errno on failure. ++ * ++ * Side effects: ++ * Data copied to the buffer. ++ * ++ *---------------------------------------------------------------------- ++ */ + -+static unsigned int compat_skb_frag_off(const skb_frag_t *frag) ++static unsigned int ++VNetCsumAndCopyToUser(const void *src, // IN: Source ++ void *dst, // IN: Destination ++ int len, // IN: Bytes to copy ++ int *err) // OUT: Error code +{ -+#if COMPAT_LINUX_VERSION_CHECK_LT(5, 4, 0) -+ return frag->page_offset; ++ unsigned int csum; ++ ++#if COMPAT_LINUX_VERSION_CHECK_LT(5, 10, 0) ++ csum = csum_and_copy_to_user(src, dst, len, 0, err); ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) ++ csum = csum_and_copy_to_user(src, dst, len); ++ *err = (csum == 0) ? -EFAULT : 0; +#else -+ return skb_frag_off(frag); ++ if (!user_access_begin(dst, len)) { ++ *err = -EFAULT; ++ csum = 0; ++ } else { ++ *err = 0; ++ csum = csum_partial_copy_nocheck(src, dst, len); ++ user_access_end(); ++ } +#endif ++ return csum; +} + - /* - *----------------------------------------------------------------------------- ++ ++/* ++ *---------------------------------------------------------------------- ++ * + * VNetCsumCopyDatagram -- * -@@ -590,20 +608,21 @@ VNetCsumCopyDatagram(const struct sk_buff *skb, // IN: skb to copy + * Copy part of datagram to userspace doing checksum at same time. +@@ -576,7 +581,7 @@ VNetCsumCopyDatagram(const struct sk_buf + return -EINVAL; + } + +- csum = csum_and_copy_to_user(skb->data + offset, curr, len, 0, &err); ++ csum = VNetCsumAndCopyToUser(skb->data + offset, curr, len, &err); + if (err) { + return err; + } +@@ -585,20 +595,20 @@ VNetCsumCopyDatagram(const struct sk_buf for (frag = skb_shinfo(skb)->frags; frag != skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags; frag++) { - if (frag->size > 0) { -+ if (compat_skb_frag_size(frag) > 0) { ++ if (skb_frag_size(frag) > 0) { unsigned int tmpCsum; const void *vaddr; @@ -257,18 +459,246 @@ index d385088..aab9478 100644 - tmpCsum = csum_and_copy_to_user(vaddr + frag->page_offset, - curr, frag->size, 0, &err); - compat_kunmap(frag->page); -+ vaddr = compat_kmap_frag(frag); -+ tmpCsum = csum_and_copy_to_user(vaddr + compat_skb_frag_off(frag), -+ curr, compat_skb_frag_size(frag), 0, -+ &err); -+ compat_kunmap_frag(frag); ++ vaddr = kmap(skb_frag_page(frag)); ++ tmpCsum = VNetCsumAndCopyToUser(vaddr + skb_frag_off(frag), ++ curr, skb_frag_size(frag), &err); ++ kunmap(skb_frag_page(frag)); if (err) { return err; } csum = csum_block_add(csum, tmpCsum, curr - buf); - curr += frag->size; -+ curr += compat_skb_frag_size(frag); ++ curr += skb_frag_size(frag); + } + } + +Fixing VMWare Player on Linux when using DHCP addresses: https://www.nikhef.nl/~janjust/vmnet/ +@@ -1012,6 +1028,9 @@ + userIf = (VNetUserIF *)port->jack.private; + hubJack = port->jack.peer; + ++ /* never send link down events */ ++ if (!linkUp) return 0; ++ + if (port->jack.state == FALSE || hubJack == NULL) { + return -EINVAL; + } +--- a/vmnet/vmnetInt.h ++++ b/vmnet/vmnetInt.h +@@ -77,7 +77,7 @@ + + + extern struct proto vmnet_proto; +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) || defined(sk_net_refcnt) + # define compat_sk_alloc(_bri, _pri) sk_alloc(&init_net, \ + PF_NETLINK, _pri, &vmnet_proto, 1) + #elif defined(VMW_NETDEV_HAS_NET) +--- a/vmnet/vnetEvent.c ++++ b/vmnet/vnetEvent.c +@@ -60,10 +60,12 @@ + + struct VNetEvent_EventNode { + VNetEvent_EventNode *nextEvent; +- VNet_EventHeader event; ++ union { ++ VNet_EventHeader header; ++ VNet_LinkStateEvent lse; ++ } event; + }; + +-#define EVENT_NODE_HEADER_SIZE offsetof(struct VNetEvent_EventNode, event) + + struct VNetEvent_Mechanism { + VNetKernel_SpinLock lock; /* mechanism lock */ +@@ -369,6 +371,10 @@ + return VNetKernel_EINVAL; + } + ++ if (e->size > sizeof(p->event)) { ++ return VNetKernel_EINVAL; ++ } ++ + /* lock */ + VNetKernel_SpinLockAcquire(&m->lock); + m->handlerTask = VNetKernel_ThreadCurrent(); +@@ -378,22 +384,15 @@ + while (TRUE) { + p = *q; + if (p == NULL || +- (p->event.eventId == e->eventId && p->event.type == e->type)) { ++ (p->event.header.eventId == e->eventId && p->event.header.type == e->type)) { + break; + } + q = &p->nextEvent; + } + +- /* remove previously sent event */ +- if (p != NULL && p->event.size != e->size) { +- *q = p->nextEvent; +- VNetKernel_MemoryFree(p); +- p = NULL; +- } +- + /* insert new event into event list*/ + if (p == NULL) { +- p = VNetKernel_MemoryAllocate(EVENT_NODE_HEADER_SIZE + e->size); ++ p = VNetKernel_MemoryAllocate(sizeof(*p)); + if (p == NULL) { + m->handlerTask = NULL; + VNetKernel_SpinLockRelease(&m->lock); +@@ -485,8 +484,8 @@ + while (s != NULL) { + e = s->firstEvent; + while (e != NULL) { +- if ((e->event.classSet & classMask) != 0) { +- h(data, &e->event); ++ if ((e->event.header.classSet & classMask) != 0) { ++ h(data, &e->event.header); + } + e = e->nextEvent; } +--- a/vmnet/vnetUserListener.c +--- b/vmnet/vnetUserListener.c +@@ -42,10 +42,12 @@ + + struct VNetUserListener_EventNode { + VNetUserListener_EventNode *nextEvent; +- VNet_EventHeader event; ++ union { ++ VNet_EventHeader header; ++ VNet_LinkStateEvent lse; ++ } event; + }; + +-#define EVENT_NODE_HEADER_SIZE offsetof(struct VNetUserListener_EventNode, event) + + typedef struct VNetUserListener { + VNetPort port; /* base port/jack */ +@@ -220,7 +222,7 @@ + VNetUserListener_EventNode *t; + + /* allocate and initialize event node */ +- t = kmalloc(EVENT_NODE_HEADER_SIZE + e->size, GFP_ATOMIC); ++ t = kmalloc(sizeof *t, GFP_ATOMIC); + if (t == NULL) { + LOG(0, (KERN_DEBUG "VNetUserListenerEventHandler, out of memory\n")); + return; +@@ -299,7 +301,7 @@ + spin_unlock(&userListener->lock); + + /* return data and free event */ +- n = t->event.size; ++ n = t->event.header.size; + if (count < n) { + n = count; } +From add7a6d8b99565fdfa79098315b0a69fd244eda3 Mon Sep 17 00:00:00 2001 +From: Michal Kubecek <mkubecek@suse.cz> +Date: Fri, 12 Jan 2024 08:30:33 +0100 +Subject: [PATCH] modules: fix build with -Wmissing-prototypes + +Mainline commit 0fcb70851fbf ("Makefile.extrawarn: turn on +missing-prototypes globally") in 6.8-rc1 enables -Wmissing-prototypes +globally, revealing a lot of unclean code and also some actual problems. +This is also the case in vmmon and vmnet modules. + +Most of them are addressed by making functions used only within one file +static. A special case are Vmx86_MapPage() and Vmx86_UnmapPage() which were +defined since Workstation 14.0.0 but they are not actually used anywhere +until 15.0.0 so that dropping them seems to be the best option. + +The missing prototype of random_get_entropy_fallback() is handled by +including <linux/timex.h> rather than <asm/timex.h>. + +Finally, there are four functions in vmnet module which are actually used +in multiple files but instead of proper declarations, their prototype is +duplicated in vmnet-only/driver.c, risking that the two copies won't match +(which actually happened in one case). The cleanest solution would be +creating separate header files for them (bridge.h, netif.h, userif.h and +vnetUserListener.h) and including them in the respective source file and +driver.c. As the developers already handle similar cases by simply putting +the declarations into vnetInt.h, let us do the same to keep things simple. +--- + vmmon-only/bootstrap/monLoaderVmmon.c | 1 + + vmmon-only/common/vmx86.c | 50 +-------------------------- + vmmon-only/linux/driver.c | 4 +-- + vmmon-only/linux/hostif.c | 6 ++-- + vmnet-only/bridge.c | 2 +- + vmnet-only/driver.c | 16 ++------- + vmnet-only/vnetInt.h | 7 ++++ + 7 files changed, 17 insertions(+), 69 deletions(-) + +diff --git a/vmnet-only/bridge.c b/vmnet-only/bridge.c +index b144adab..b46df795 100644 +--- a/vmnet-only/bridge.c ++++ b/vmnet-only/bridge.c +@@ -1576,7 +1576,7 @@ VNetBridgeComputeHeaderPos(struct sk_buff *skb) // IN: buffer to examine + *---------------------------------------------------------------------- + */ + +-void ++static void + VNetBridgeSendLargePacket(struct sk_buff *skb, // IN: packet to split + VNetBridge *bridge) // IN: bridge + { +diff --git a/vmnet-only/driver.c b/vmnet-only/driver.c +index 602bbfa1..a6f6a7d9 100644 +--- a/vmnet-only/driver.c ++++ b/vmnet-only/driver.c +@@ -50,18 +50,6 @@ + + #include "vmnetInt.h" + +-/* +- * Initialization and creation routines from other files. +- * Putting them here reduces the need for so many header files. +- */ +- +-extern int VNetUserIf_Create(VNetPort **ret); +-extern int VNetNetIf_Create(char *devName, VNetPort **ret, int hubNum); +-extern int VNetBridge_Create(char *devName, uint32 flags, VNetJack *hubJack, +- VNetPort **ret); +-extern int VNetUserListener_Create(uint32 classMask, VNetJack *hubJack, VNetPort **ret); +- +- + /* + * Structure for cycle detection of host interfaces. This + * struct is only used by VNetCycleDetectIf(). +@@ -295,7 +283,7 @@ VNetRemovePortFromList(const VNetPort *port) // IN: port to remove from list + *---------------------------------------------------------------------- + */ +-int ++static int + LinuxDriverInit(void) + { + int retval; +@@ -374,7 +362,7 @@ vmnet_init_module(void) + *---------------------------------------------------------------------- + */ + +-void ++static void + LinuxDriverExit(void) + { + unregister_chrdev(VNET_MAJOR_NUMBER, "vmnet"); +diff --git a/vmnet-only/vnetInt.h b/vmnet-only/vnetInt.h +index 5f41269d..cb25e3b8 100644 +--- a/vmnet-only/vnetInt.h ++++ b/vmnet-only/vnetInt.h +@@ -225,6 +225,13 @@ extern int VNetProc_Init(void); + + extern void VNetProc_Cleanup(void); + ++int VNetNetIf_Create(char *devName, VNetPort **ret, int hubNum); ++int VNetUserIf_Create(VNetPort **ret); ++int VNetBridge_Create(const char *devName, uint32 flags, VNetJack *hubJack, ++ VNetPort **ret); ++int VNetUserListener_Create(uint32 classMask, VNetJack *hubJack, ++ VNetPort **port); ++ + + /* + *---------------------------------------------------------------------- diff --git a/vmware-networks-configuration.service b/vmware-networks-configuration.service index 779b01a3171a..0d86867f955e 100644 --- a/vmware-networks-configuration.service +++ b/vmware-networks-configuration.service @@ -1,11 +1,6 @@ [Unit] Description=VMware Networks Configuration Generation -ConditionPathExists=|!/etc/vmware/networking -ConditionPathExists=|!/etc/vmware/vmnet1/dhcpd/dhcpd.conf -ConditionPathExists=|!/etc/vmware/vmnet1/dhcpd/dhcpd.leases -ConditionPathExists=|!/etc/vmware/vmnet8/dhcpd/dhcpd.conf -ConditionPathExists=|!/etc/vmware/vmnet8/dhcpd/dhcpd.leases -ConditionPathExists=|!/etc/vmware/vmnet8/nat/nat.conf +ConditionPathExists=!/etc/vmware/networking [Service] UMask=0077 diff --git a/vmware-networks.path b/vmware-networks.path new file mode 100644 index 000000000000..fb53ff4ba642 --- /dev/null +++ b/vmware-networks.path @@ -0,0 +1,8 @@ +[Unit] +Description=Monitor to Load-On-Demand the VMware Networks service + +[Path] +PathExistsGlob=/var/run/vmware/*/* + +[Install] +WantedBy=paths.target diff --git a/vmware-usbarbitrator.path b/vmware-usbarbitrator.path new file mode 100644 index 000000000000..e56473635d8b --- /dev/null +++ b/vmware-usbarbitrator.path @@ -0,0 +1,8 @@ +[Unit] +Description=Monitor to Load-On-Demand the VMware USB Arbitrator + +[Path] +PathExistsGlob=/var/run/vmware/*/* + +[Install] +WantedBy=paths.target diff --git a/vmware-workstation.install b/vmware-workstation.install index 36f5a3505e48..209995a25743 100644 --- a/vmware-workstation.install +++ b/vmware-workstation.install @@ -2,18 +2,29 @@ post_install() { cat << EOF ==> Before using VMware, you need to reboot or load vmw_vmci and vmmon kernel modules (in a terminal on root: modprobe -a vmw_vmci vmmon) -==> You may also need to enable some of these services: -- vmware-networks.service: to have network access inside VMs -- vmware-usbarbitrator.service: to connect USB devices inside VMs -- vmware-hostd.service: to share VMs on the network +==> You may also need to enable some of the following services: +- vmware-networks: to have network access inside VMs +- vmware-usbarbitrator: to connect USB devices inside VMs +- vmware-hostd: to share VMs on the network +These services can be activated during boot by enabling .service units or only when a VM is started by enabling .path units (except for vmware-hostd). EOF } +post_upgrade() { + if (( $(vercmp "$2" "11.1.4-16") < 0 )); then + cat << EOF + +Now vmware-networks and vmware-usbarbitrator services can be activated only when a VM is started by enabling .path units instead of .service units. + +EOF + fi +} + post_remove() { cat << EOF -==> To remove VMware settings, delete /etc/vmware and /etc/vmware-installer directories. +==> To completely clean VMware installation, you may have to manually delete /etc/vmware, /etc/vmware-installer and /usr/lib/vmware-installer directories if they still exist. EOF } |