summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO30
-rw-r--r--Makefile5
-rw-r--r--PKGBUILD84
-rw-r--r--dkms.conf.in15
-rw-r--r--efi-patches.txt25
-rw-r--r--unlocker.patch62
-rw-r--r--unlocker.py387
-rw-r--r--vmmon.patch1025
-rw-r--r--vmnet.patch590
-rw-r--r--vmware-networks-configuration.service7
-rw-r--r--vmware-networks.path8
-rw-r--r--vmware-usbarbitrator.path8
-rw-r--r--vmware-workstation.install21
13 files changed, 1830 insertions, 437 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 8249b5a42f5a..9243c36ca929 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -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
-
diff --git a/Makefile b/Makefile
index 4b589921549f..f025addbd4b1 100644
--- a/Makefile
+++ b/Makefile
@@ -2,10 +2,7 @@
MODULES = \
vmmon \
- vmnet \
- #vmblock \
- #vmci \
- #vsock
+ vmnet
all: $(foreach m, $(MODULES), $m.ko)
diff --git a/PKGBUILD b/PKGBUILD
index 04791b0a675e..f51b48b0f0af 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -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
}