121 lines
4.4 KiB
Go
121 lines
4.4 KiB
Go
package configs
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"regexp"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/HikariKnight/quickpassthrough/internal/common"
|
|
"github.com/HikariKnight/quickpassthrough/internal/logger"
|
|
"github.com/HikariKnight/quickpassthrough/pkg/fileio"
|
|
)
|
|
|
|
// Set_Mkinitcpio copies the content of /etc/mkinitcpio.conf to the config folder and does an inline replace/insert on the MODULES=() line
|
|
func Set_Mkinitcpio(config *Config) {
|
|
// Make sure we start from scratch by deleting any old file
|
|
if exists, _ := fileio.FileExist(config.Path.MKINITCPIO); exists {
|
|
_ = os.Remove(config.Path.MKINITCPIO)
|
|
}
|
|
|
|
// Make a regex to get the system path instead of the config path
|
|
syspath_re := regexp.MustCompile(`^config`)
|
|
sysfile := syspath_re.ReplaceAllString(config.Path.MKINITCPIO, "")
|
|
|
|
// Make a regex to find the modules line
|
|
module_line_re := regexp.MustCompile(`^MODULES=`)
|
|
hooks_line_re := regexp.MustCompile(`^HOOKS=`)
|
|
modules_re := regexp.MustCompile(`MODULES=\((.*)\)`)
|
|
vfio_modules_re := regexp.MustCompile(`(vfio_iommu_type1|vfio_pci|vfio_virqfd|vfio|vendor-reset)`)
|
|
|
|
// Read the mkinitcpio file
|
|
mkinitcpio_content := fileio.ReadLines(sysfile)
|
|
|
|
// Write to logger
|
|
logger.Printf("Read %s:\n%s\n", sysfile, strings.Join(mkinitcpio_content, "\n"))
|
|
|
|
for _, line := range mkinitcpio_content {
|
|
// If we are at the line starting with MODULES=
|
|
if module_line_re.MatchString(line) {
|
|
// Get the current modules
|
|
currentmodules := strings.Split(modules_re.ReplaceAllString(line, "${1}"), " ")
|
|
|
|
// Get the vfio modules we need to use
|
|
modules := vfio_modules()
|
|
|
|
// If vendor-reset is in the current modules
|
|
if strings.Contains(line, "vendor-reset") {
|
|
// Write to logger
|
|
logger.Printf("vendor-reset module detected in %s\nMaking sure it will be loaded before vfio\n", sysfile)
|
|
|
|
// Add vendor-reset first
|
|
modules = append([]string{"vendor-reset"}, modules...)
|
|
}
|
|
|
|
// Loop through current modules and add anything that isnt vfio or vendor-reset related
|
|
for _, v := range currentmodules {
|
|
// If what we find is not a vfio module or vendor-reset module
|
|
if !vfio_modules_re.MatchString(v) {
|
|
// Add module to module list
|
|
modules = append(modules, v)
|
|
}
|
|
}
|
|
|
|
// Write to logger
|
|
logger.Printf("Replacing line in %s:\n%s\nWith:\nMODULES=(%s)\n", config.Path.MKINITCPIO, line, strings.Join(modules, " "))
|
|
|
|
// Write the modules line we generated
|
|
fileio.AppendContent(fmt.Sprintf("MODULES=(%s)\n", strings.Join(modules, " ")), config.Path.MKINITCPIO)
|
|
} else if config.HasDuplicateDeviceIds && hooks_line_re.MatchString(line) {
|
|
setMkinitcpioEarlyBinds(config, line)
|
|
} else {
|
|
// Else just write the line to the config
|
|
fileio.AppendContent(fmt.Sprintf("%s\n", line), config.Path.MKINITCPIO)
|
|
}
|
|
}
|
|
}
|
|
|
|
func setMkinitcpioEarlyBinds(config *Config, hooksLine string) {
|
|
err := os.MkdirAll(config.Path.MKINITCPIOHOOKS, os.ModePerm)
|
|
common.ErrorCheck(err, "Error, could not create mkinitcpio hook config directory")
|
|
confToSystemPathRe := regexp.MustCompile(`^config`)
|
|
|
|
earlyBindHookConfigPath := path.Join(config.Path.MKINITCPIOHOOKS, "early-vfio-bind")
|
|
earlyBindHookSysPath := confToSystemPathRe.ReplaceAllString(earlyBindHookConfigPath, "")
|
|
config.EarlyBindFilePaths[earlyBindHookConfigPath] = earlyBindHookSysPath
|
|
if exists, _ := fileio.FileExist(earlyBindHookConfigPath); exists {
|
|
_ = os.Remove(earlyBindHookConfigPath)
|
|
}
|
|
|
|
logger.Printf("Writing to early bind hook to %s", earlyBindHookConfigPath)
|
|
vfioBindHook := fmt.Sprintf(`#!/bin/bash
|
|
run_hook() {
|
|
DEVS="%s"
|
|
|
|
for DEV in $DEVS; do
|
|
echo "vfio-pci" > /sys/bus/pci/devices/$DEV/driver_override
|
|
done
|
|
|
|
# Load the vfio-pci module
|
|
modprobe -i vfio-pci
|
|
}`, strings.Join(config.Gpu_Addresses, " "))
|
|
|
|
fileio.AppendContent(vfioBindHook, earlyBindHookConfigPath)
|
|
err = os.Chmod(earlyBindHookConfigPath, 0755)
|
|
common.ErrorCheck(err, fmt.Sprintf("Error, could not chmod %s", earlyBindHookConfigPath))
|
|
|
|
hooksString := strings.Trim(strings.Split(hooksLine, "=")[1], "()")
|
|
hooks := strings.Split(hooksString, " ")
|
|
customHook := "early-vfio-bind"
|
|
if !slices.Contains(hooks, customHook) {
|
|
hooks = append(hooks, customHook)
|
|
}
|
|
|
|
// Write to logger
|
|
logger.Printf("Replacing line in %s:\n%s\nWith:\nHOOKS=(%s)\n", config.Path.MKINITCPIO, hooksLine, strings.Join(hooks, " "))
|
|
|
|
// Write the modules line we generated
|
|
fileio.AppendContent(fmt.Sprintf("HOOKS=(%s)\n", strings.Join(hooks, " ")), config.Path.MKINITCPIO)
|
|
}
|