mirror of
https://github.com/HikariKnight/quickpassthrough.git
synced 2024-09-19 11:28:46 -04:00
remove old unused code
This commit is contained in:
parent
675083fb19
commit
bd8f67decc
7 changed files with 0 additions and 886 deletions
|
@ -21,13 +21,4 @@ func Tui() {
|
||||||
|
|
||||||
// New WIP Tui
|
// New WIP Tui
|
||||||
pages.Welcome()
|
pages.Welcome()
|
||||||
/*
|
|
||||||
// Make a blank model to keep our state in
|
|
||||||
m := NewModel()
|
|
||||||
|
|
||||||
// Start the program with the model
|
|
||||||
p := tea.NewProgram(m, tea.WithAltScreen())
|
|
||||||
_, err = p.Run()
|
|
||||||
errorcheck.ErrorCheck(err, "Failed to initialize UI")
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/HikariKnight/quickpassthrough/internal/logger"
|
|
||||||
"github.com/HikariKnight/quickpassthrough/pkg/command"
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
||||||
var cmd tea.Cmd
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case tea.KeyMsg:
|
|
||||||
|
|
||||||
// If we are not done
|
|
||||||
if m.focused != INSTALL && m.focused != DONE {
|
|
||||||
// Setup keybindings
|
|
||||||
switch msg.String() {
|
|
||||||
case "ctrl+c", "q":
|
|
||||||
// Exit when user presses Q or CTRL+C
|
|
||||||
return m, tea.Quit
|
|
||||||
|
|
||||||
case "enter":
|
|
||||||
if m.width != 0 {
|
|
||||||
// Process the selected item, if the return value is true then exit alt screen
|
|
||||||
if !m.processSelection() {
|
|
||||||
return m, tea.ExitAltScreen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "ctrl+z", "backspace":
|
|
||||||
// Go backwards in the model
|
|
||||||
if m.focused > 0 && m.focused != DONE {
|
|
||||||
m.focused--
|
|
||||||
return m, nil
|
|
||||||
} else {
|
|
||||||
// If we are at the beginning, just exit
|
|
||||||
return m, tea.Quit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If we are done then handle keybindings a bit differently
|
|
||||||
// Setup keybindings for authDialog
|
|
||||||
switch msg.String() {
|
|
||||||
case "ctrl+z":
|
|
||||||
// Since we have no QuickEmu support, skip the usb controller configuration
|
|
||||||
m.focused = VIDEO
|
|
||||||
|
|
||||||
case "ctrl+c":
|
|
||||||
// Exit when user presses CTRL+C
|
|
||||||
return m, tea.Quit
|
|
||||||
|
|
||||||
case "enter":
|
|
||||||
// If we are on the INSTALL dialog
|
|
||||||
if m.focused == INSTALL && m.authDialog.Value() != "" {
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Getting authentication token by elevating with sudo once")
|
|
||||||
|
|
||||||
// Elevate with sudo
|
|
||||||
command.Elevate(
|
|
||||||
base64.StdEncoding.EncodeToString(
|
|
||||||
[]byte(
|
|
||||||
m.authDialog.Value(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Attempting to free hash from memory")
|
|
||||||
|
|
||||||
// Blank the password field
|
|
||||||
m.authDialog.SetValue("")
|
|
||||||
|
|
||||||
fmt.Println(titleStyle.Render("Working... Application frozen until done, check debug.log for progress"))
|
|
||||||
|
|
||||||
// Start installation and send the password to the command
|
|
||||||
m.install()
|
|
||||||
|
|
||||||
// Move to the DONE dialog
|
|
||||||
m.focused = DONE
|
|
||||||
|
|
||||||
// Exit the alt screen as the output on the done dialog needs to be scrollable
|
|
||||||
return m, tea.ClearScreen
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Quit the application if we are on a different view
|
|
||||||
return m, tea.Quit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issue an UI update
|
|
||||||
m.authDialog, cmd = m.authDialog.Update(msg)
|
|
||||||
return m, cmd
|
|
||||||
}
|
|
||||||
case tea.WindowSizeMsg:
|
|
||||||
if m.width == 0 {
|
|
||||||
// Initialize the static lists and make sure the content
|
|
||||||
// does not extend past the screen
|
|
||||||
m.initLists(msg.Width, msg.Height)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Else we are loaded and will update the sizing on the fly
|
|
||||||
m.height = msg.Height
|
|
||||||
m.width = msg.Width
|
|
||||||
|
|
||||||
// TODO: Find a better way to resize widgets when word wrapping happens
|
|
||||||
// BUG: currently breaks the UI rendering if word wrapping happens in some cases...
|
|
||||||
views := len(m.lists)
|
|
||||||
if msg.Width > 83 {
|
|
||||||
for i := 0; i < views; i++ {
|
|
||||||
m.lists[i].SetSize(m.width-m.offsetx[i], m.height-m.offsety[i])
|
|
||||||
// Update the styles with the correct width
|
|
||||||
dialogStyle = dialogStyle.Width(m.width)
|
|
||||||
listStyle = listStyle.Width(m.width)
|
|
||||||
titleStyle = titleStyle.Width(m.width - 4)
|
|
||||||
choiceStyle = choiceStyle.Width(m.width)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run another update loop
|
|
||||||
m.lists[m.focused], cmd = m.lists[m.focused].Update(msg)
|
|
||||||
return m, cmd
|
|
||||||
}
|
|
|
@ -1,257 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/HikariKnight/ls-iommu/pkg/errorcheck"
|
|
||||||
"github.com/HikariKnight/quickpassthrough/internal/configs"
|
|
||||||
"github.com/HikariKnight/quickpassthrough/internal/logger"
|
|
||||||
"github.com/HikariKnight/quickpassthrough/pkg/command"
|
|
||||||
"github.com/HikariKnight/quickpassthrough/pkg/fileio"
|
|
||||||
"github.com/HikariKnight/quickpassthrough/pkg/uname"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This function processes the enter event
|
|
||||||
func (m *model) processSelection() bool {
|
|
||||||
switch m.focused {
|
|
||||||
case GPUS:
|
|
||||||
// Gets the selected item
|
|
||||||
selectedItem := m.lists[m.focused].SelectedItem()
|
|
||||||
|
|
||||||
// Gets the IOMMU group of the selected item
|
|
||||||
iommu_group_regex := regexp.MustCompile(`(\d{1,3})`)
|
|
||||||
iommu_group := iommu_group_regex.FindString(selectedItem.(item).desc)
|
|
||||||
|
|
||||||
// Add the gpu group to our model (this is so we can grab the vbios details later)
|
|
||||||
m.gpu_group = iommu_group
|
|
||||||
|
|
||||||
// Get all the gpu devices and related devices (same device id or in the same group)
|
|
||||||
items := iommuList2ListItem(getIOMMU("-grr", "-i", m.gpu_group, "-F", "vendor:,prod_name,optional_revision:,device_id"))
|
|
||||||
|
|
||||||
// Add the devices to the list
|
|
||||||
m.lists[GPU_GROUP].SetItems(items)
|
|
||||||
|
|
||||||
// Change focus to next index
|
|
||||||
m.focused++
|
|
||||||
|
|
||||||
case GPU_GROUP:
|
|
||||||
// Get the config
|
|
||||||
config := configs.GetConfig()
|
|
||||||
|
|
||||||
// Get the vbios path
|
|
||||||
m.vbios_path = getIOMMU("-g", "-i", m.gpu_group, "--rom")[0]
|
|
||||||
|
|
||||||
// Generate the VBIOS dumper script once the user has selected a GPU
|
|
||||||
configs.GenerateVBIOSDumper(m.vbios_path)
|
|
||||||
|
|
||||||
// Get the device ids for the selected gpu using ls-iommu
|
|
||||||
m.gpu_IDs = getIOMMU("-gr", "-i", m.gpu_group, "--id")
|
|
||||||
|
|
||||||
// If the kernel_args file already exists
|
|
||||||
if fileio.FileExist(config.Path.CMDLINE) {
|
|
||||||
// Delete it as we will have to make a new one anyway
|
|
||||||
err := os.Remove(config.Path.CMDLINE)
|
|
||||||
errorcheck.ErrorCheck(err, fmt.Sprintf("Could not remove %s", config.Path.CMDLINE))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write initial kernel_arg file
|
|
||||||
configs.Set_Cmdline(m.gpu_IDs)
|
|
||||||
|
|
||||||
// Change focus to the next view
|
|
||||||
m.focused++
|
|
||||||
|
|
||||||
case USB:
|
|
||||||
// Gets the selected item
|
|
||||||
selectedItem := m.lists[m.focused].SelectedItem()
|
|
||||||
|
|
||||||
// Gets the IOMMU group of the selected item
|
|
||||||
iommu_group_regex := regexp.MustCompile(`(\d{1,3})`)
|
|
||||||
iommu_group := iommu_group_regex.FindString(selectedItem.(item).desc)
|
|
||||||
|
|
||||||
// Get the USB controllers in the selected iommu group
|
|
||||||
items := iommuList2ListItem(getIOMMU("-ur", "-i", iommu_group, "-F", "vendor:,prod_name,optional_revision:,device_id"))
|
|
||||||
|
|
||||||
// Add the items to the list
|
|
||||||
m.lists[USB_GROUP].SetItems(items)
|
|
||||||
|
|
||||||
// Change focus to next index
|
|
||||||
m.focused++
|
|
||||||
|
|
||||||
case USB_GROUP:
|
|
||||||
m.focused++
|
|
||||||
|
|
||||||
case VBIOS:
|
|
||||||
// This is just an OK Dialog
|
|
||||||
m.focused++
|
|
||||||
|
|
||||||
case VIDEO:
|
|
||||||
// This is a YESNO Dialog
|
|
||||||
// Gets the selected item
|
|
||||||
selectedItem := m.lists[m.focused].SelectedItem()
|
|
||||||
|
|
||||||
// Get our config struct
|
|
||||||
config := configs.GetConfig()
|
|
||||||
|
|
||||||
// If user selected yes then
|
|
||||||
if selectedItem.(item).title == "YES" {
|
|
||||||
// Add disable VFIO video to the config
|
|
||||||
configs.DisableVFIOVideo(1)
|
|
||||||
} else {
|
|
||||||
// Add disable VFIO video to the config
|
|
||||||
configs.DisableVFIOVideo(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have files for modprobe
|
|
||||||
if fileio.FileExist(config.Path.MODPROBE) {
|
|
||||||
// Configure modprobe
|
|
||||||
configs.Set_Modprobe(m.gpu_IDs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a folder for dracut
|
|
||||||
if fileio.FileExist(config.Path.DRACUT) {
|
|
||||||
// Configure dracut
|
|
||||||
configs.Set_Dracut()
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a mkinitcpio.conf file
|
|
||||||
if fileio.FileExist(config.Path.MKINITCPIO) {
|
|
||||||
configs.Set_Mkinitcpio()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure grub2 here as we can make the config without sudo
|
|
||||||
if config.Bootloader == "grub2" {
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Configuring grub2 manually")
|
|
||||||
configs.Configure_Grub2()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go to the next view
|
|
||||||
//m.focused++
|
|
||||||
|
|
||||||
// Because we have no QuickEmu support yet, just skip USB Controller configuration
|
|
||||||
m.focused = INSTALL
|
|
||||||
return true
|
|
||||||
|
|
||||||
case INTRO:
|
|
||||||
// This is an OK Dialog
|
|
||||||
// Create the config folder and the files related to this system
|
|
||||||
configs.InitConfigs()
|
|
||||||
|
|
||||||
// Go to the next view
|
|
||||||
m.focused++
|
|
||||||
|
|
||||||
case DONE:
|
|
||||||
// Return true so that the application will exit nicely
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return false as we are not done
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function starts the install process
|
|
||||||
// It takes 1 auth string as variable
|
|
||||||
func (m *model) install() {
|
|
||||||
// Get the config
|
|
||||||
config := configs.GetConfig()
|
|
||||||
|
|
||||||
// Make a stringlist to keep the output to show the user
|
|
||||||
var output []string
|
|
||||||
|
|
||||||
// Based on the bootloader, setup the configuration
|
|
||||||
if config.Bootloader == "kernelstub" {
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Configuring systemd-boot using kernelstub")
|
|
||||||
|
|
||||||
// Configure kernelstub
|
|
||||||
output = append(output, configs.Set_KernelStub())
|
|
||||||
|
|
||||||
} else if config.Bootloader == "grubby" {
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Configuring bootloader using grubby")
|
|
||||||
|
|
||||||
// Configure kernelstub
|
|
||||||
output = append(output, configs.Set_Grubby())
|
|
||||||
|
|
||||||
} else if config.Bootloader == "grub2" {
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Configuring grub2 manually")
|
|
||||||
grub_output, _ := configs.Set_Grub2()
|
|
||||||
output = append(output, grub_output...)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
kernel_args := fileio.ReadFile(config.Path.CMDLINE)
|
|
||||||
logger.Printf("Unsupported bootloader, please add the below line to your bootloaders kernel arguments\n%s", kernel_args)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A lot of linux systems support modprobe along with their own module system
|
|
||||||
// So copy the modprobe files if we have them
|
|
||||||
modprobeFile := fmt.Sprintf("%s/vfio.conf", config.Path.MODPROBE)
|
|
||||||
if fileio.FileExist(modprobeFile) {
|
|
||||||
// Copy initramfs-tools module to system
|
|
||||||
output = append(output, configs.CopyToSystem(modprobeFile, "/etc/modprobe.d/vfio.conf"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the config files for the system we have
|
|
||||||
initramfsFile := fmt.Sprintf("%s/modules", config.Path.INITRAMFS)
|
|
||||||
dracutFile := fmt.Sprintf("%s/vfio.conf", config.Path.DRACUT)
|
|
||||||
if fileio.FileExist(initramfsFile) {
|
|
||||||
// Copy initramfs-tools module to system
|
|
||||||
output = append(output, configs.CopyToSystem(initramfsFile, "/etc/initramfs-tools/modules"))
|
|
||||||
|
|
||||||
// Copy the modules file to /etc/modules
|
|
||||||
output = append(output, configs.CopyToSystem(config.Path.ETCMODULES, "/etc/modules"))
|
|
||||||
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Executing: sudo update-initramfs -u")
|
|
||||||
|
|
||||||
// Update initramfs
|
|
||||||
output = append(output, "Executed: sudo update-initramfs -u\nSee debug.log for detailed output")
|
|
||||||
cmd_out, cmd_err, _ := command.RunErr("sudo", "update-initramfs", "-u")
|
|
||||||
|
|
||||||
cmd_out = append(cmd_out, cmd_err...)
|
|
||||||
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf(strings.Join(cmd_out, "\n"))
|
|
||||||
} else if fileio.FileExist(dracutFile) {
|
|
||||||
// Copy dracut config to /etc/dracut.conf.d/vfio
|
|
||||||
output = append(output, configs.CopyToSystem(dracutFile, "/etc/dracut.conf.d/vfio"))
|
|
||||||
|
|
||||||
// Get systeminfo
|
|
||||||
sysinfo := uname.New()
|
|
||||||
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Executing: sudo dracut -f -v --kver %s", sysinfo.Release)
|
|
||||||
|
|
||||||
// Update initramfs
|
|
||||||
output = append(output, fmt.Sprintf("Executed: sudo dracut -f -v --kver %s\nSee debug.log for detailed output", sysinfo.Release))
|
|
||||||
cmd_out, cmd_err, _ := command.RunErr("sudo", "dracut", "-f", "-v", "--kver", sysinfo.Release)
|
|
||||||
|
|
||||||
cmd_out = append(cmd_out, cmd_err...)
|
|
||||||
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf(strings.Join(cmd_out, "\n"))
|
|
||||||
} else if fileio.FileExist(config.Path.MKINITCPIO) {
|
|
||||||
// Copy dracut config to /etc/dracut.conf.d/vfio
|
|
||||||
output = append(output, configs.CopyToSystem(config.Path.MKINITCPIO, "/etc/mkinitcpio.conf"))
|
|
||||||
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Executing: sudo mkinitcpio -P")
|
|
||||||
|
|
||||||
// Update initramfs
|
|
||||||
output = append(output, "Executed: sudo mkinitcpio -P\nSee debug.log for detailed output")
|
|
||||||
cmd_out, cmd_err, _ := command.RunErr("sudo", "mkinitcpio", "-P")
|
|
||||||
|
|
||||||
cmd_out = append(cmd_out, cmd_err...)
|
|
||||||
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf(strings.Join(cmd_out, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
m.installOutput = output
|
|
||||||
m.focused++
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,168 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/HikariKnight/quickpassthrough/internal/configs"
|
|
||||||
"github.com/HikariKnight/quickpassthrough/pkg/fileio"
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
|
||||||
"github.com/charmbracelet/lipgloss"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (m model) View() string {
|
|
||||||
if m.width != 0 {
|
|
||||||
title := ""
|
|
||||||
view := ""
|
|
||||||
switch m.focused {
|
|
||||||
case INTRO:
|
|
||||||
title = dialogStyle.Render(
|
|
||||||
fmt.Sprint(
|
|
||||||
titleStyle.MarginLeft(0).Render("Welcome to QuickPassthrough!"),
|
|
||||||
"\n\n",
|
|
||||||
"This script is meant to make it easier to setup GPU passthrough for\n",
|
|
||||||
"Qemu based systems. WITH DIFFERENT 2 GPUS ON THE HOST SYSTEM\n",
|
|
||||||
"However due to the complexity of GPU passthrough\n",
|
|
||||||
"This script assumes you know how to do (or have done) the following.\n\n",
|
|
||||||
"* You have already enabled IOMMU, VT-d, SVM and/or AMD-v\n inside your UEFI/BIOS advanced settings.\n",
|
|
||||||
"* Know how to edit your bootloader\n",
|
|
||||||
"* Have a bootloader timeout of at least 3 seconds to access the menu\n",
|
|
||||||
"* Enable & Configure kernel modules\n",
|
|
||||||
"* Have a backup/snapshot of your system in case the script causes your\n system to be unbootable\n\n",
|
|
||||||
"By continuing you accept that I am not liable if your system\n",
|
|
||||||
"becomes unbootable, as you will be asked to verify the files generated",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
view = listStyle.Render(m.lists[m.focused].View())
|
|
||||||
|
|
||||||
case GPUS:
|
|
||||||
title = titleStyle.MarginLeft(2).Render(
|
|
||||||
"Select a GPU to check the IOMMU groups of",
|
|
||||||
)
|
|
||||||
|
|
||||||
view = listStyle.Render(m.lists[m.focused].View())
|
|
||||||
|
|
||||||
case GPU_GROUP:
|
|
||||||
title = titleStyle.Render(
|
|
||||||
fmt.Sprint(
|
|
||||||
"Press ENTER/RETURN to set up all these devices for passthrough.\n",
|
|
||||||
"This list should only contain items related to your GPU.",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
view = listStyle.Render(m.lists[m.focused].View())
|
|
||||||
|
|
||||||
case USB:
|
|
||||||
title = titleStyle.Render(
|
|
||||||
"[OPTIONAL]: Select a USB Controller to check the IOMMU groups of",
|
|
||||||
)
|
|
||||||
|
|
||||||
view = listStyle.Render(m.lists[m.focused].View())
|
|
||||||
|
|
||||||
case USB_GROUP:
|
|
||||||
title = titleStyle.Render(
|
|
||||||
fmt.Sprint(
|
|
||||||
"Press ENTER/RETURN to set up all these devices for passthrough.\n",
|
|
||||||
"This list should only contain the USB controller you want to use.",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
view = listStyle.Render(m.lists[m.focused].View())
|
|
||||||
|
|
||||||
case VBIOS:
|
|
||||||
// Get the program directory
|
|
||||||
exe, _ := os.Executable()
|
|
||||||
scriptdir := filepath.Dir(exe)
|
|
||||||
|
|
||||||
// If we are using go run use the working directory instead
|
|
||||||
if strings.Contains(scriptdir, "/tmp/go-build") {
|
|
||||||
scriptdir, _ = os.Getwd()
|
|
||||||
}
|
|
||||||
|
|
||||||
text := dialogStyle.Render(
|
|
||||||
fmt.Sprint(
|
|
||||||
"Based on your GPU selection, a vbios extraction script has been generated for your convenience.\n",
|
|
||||||
"Passing a VBIOS rom to the card used for passthrough is required for some cards, but not all.\n",
|
|
||||||
"Some cards also requires you to patch your VBIOS romfile, check online if this is neccessary for your card!\n",
|
|
||||||
"The VBIOS will be read from:\n",
|
|
||||||
fmt.Sprintf(
|
|
||||||
"%s\n\n",
|
|
||||||
m.vbios_path,
|
|
||||||
),
|
|
||||||
"The script to extract the vbios has to be run as sudo and without a displaymanager running for proper dumping!\n",
|
|
||||||
"\n",
|
|
||||||
"You can run the script with:\n",
|
|
||||||
fmt.Sprintf(
|
|
||||||
"%s/utils/dump_vbios.sh",
|
|
||||||
scriptdir,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
title = fmt.Sprintf(text, m.vbios_path, scriptdir)
|
|
||||||
|
|
||||||
view = listStyle.Render(m.lists[m.focused].View())
|
|
||||||
|
|
||||||
case VIDEO:
|
|
||||||
title = dialogStyle.Render(
|
|
||||||
fmt.Sprint(
|
|
||||||
"Disabling video output in Linux for the card you want to use in a VM\n",
|
|
||||||
"will make it easier to successfully do the passthrough without issues.\n",
|
|
||||||
"\n",
|
|
||||||
"Do you want to force disable video output in linux on this card?",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
view = listStyle.Render(m.lists[m.focused].View())
|
|
||||||
|
|
||||||
case INSTALL:
|
|
||||||
title = dialogStyle.Render(
|
|
||||||
fmt.Sprint(
|
|
||||||
"The configuration files have been generated and are\n",
|
|
||||||
"located inside the \"config\" folder\n",
|
|
||||||
"\n",
|
|
||||||
"* The \"kernel_args\" file contains kernel arguments that your bootloader needs\n",
|
|
||||||
"* The \"quickemu\" folder contains files that might be\n useable for quickemu in the future\n",
|
|
||||||
"* The files inside the \"etc\" folder must be copied to your system.\n",
|
|
||||||
" NOTE: Verify that these files are correctly formated/edited!\n",
|
|
||||||
"* Once all files have been copied, you need to update your bootloader and rebuild\n",
|
|
||||||
" your initramfs using the tools to do so by your system.\n",
|
|
||||||
"\n",
|
|
||||||
"This program can do this for you, however the program will have to\n",
|
|
||||||
"type your password to sudo using STDIN, to avoid using STDIN press CTRL+C\n",
|
|
||||||
"and copy the files, update your bootloader and rebuild your initramfs manually.\n",
|
|
||||||
"If you want to go back and change something, press CTRL+Z\n",
|
|
||||||
"\nNOTE: A backup of the original files from the first run can be found in the backup folder",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
view = m.authDialog.View()
|
|
||||||
|
|
||||||
case WORKING:
|
|
||||||
title = titleStyle.Render("Applying configurations!")
|
|
||||||
view = ""
|
|
||||||
|
|
||||||
m.authDialog.Update(tea.KeyEnter)
|
|
||||||
tea.Batch()
|
|
||||||
|
|
||||||
case DONE:
|
|
||||||
title = titleStyle.Render("Applied configurations!")
|
|
||||||
|
|
||||||
view = dialogStyle.Render(fmt.Sprintf("%s\n\nPress Enter to Exit.", strings.Join(m.installOutput, "\n")))
|
|
||||||
|
|
||||||
// If the bootloader is unknown/unsupported
|
|
||||||
config := configs.GetConfig()
|
|
||||||
if config.Bootloader == "unknown" {
|
|
||||||
// Change the view to reflect that
|
|
||||||
view = dialogStyle.Render(fmt.Sprintf("%s\n\nI do not have a good way to reliably edit your bootloader!\nPlease add: %s\nTo your bootloaders kernel arguments.\nPress Enter to Exit.", strings.Join(m.installOutput, "\n"), fileio.ReadFile(config.Path.CMDLINE)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//return listStyle.SetString(fmt.Sprintf("%s\n\n", title)).Render(m.lists[m.focused].View())
|
|
||||||
return lipgloss.JoinVertical(lipgloss.Left, fmt.Sprintf("%s\n%s\n", title, view))
|
|
||||||
} else {
|
|
||||||
return "Loading..."
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,185 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os/user"
|
|
||||||
|
|
||||||
"github.com/HikariKnight/ls-iommu/pkg/errorcheck"
|
|
||||||
"github.com/charmbracelet/bubbles/list"
|
|
||||||
"github.com/charmbracelet/bubbles/textinput"
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Make a status type
|
|
||||||
type status int
|
|
||||||
|
|
||||||
// List item struct
|
|
||||||
type item struct {
|
|
||||||
title, desc string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions needed for item struct
|
|
||||||
func (i item) Title() string { return i.title }
|
|
||||||
func (i item) Description() string { return i.desc }
|
|
||||||
func (i item) FilterValue() string { return i.title }
|
|
||||||
|
|
||||||
// Main Model
|
|
||||||
type model struct {
|
|
||||||
fetched []bool
|
|
||||||
lists []list.Model
|
|
||||||
gpu_group string
|
|
||||||
gpu_IDs []string
|
|
||||||
vbios_path string
|
|
||||||
focused status
|
|
||||||
offsetx []int
|
|
||||||
offsety []int
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
authDialog textinput.Model
|
|
||||||
installOutput []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consts used to navigate the main model
|
|
||||||
const (
|
|
||||||
INTRO status = iota
|
|
||||||
GPUS
|
|
||||||
GPU_GROUP
|
|
||||||
VBIOS
|
|
||||||
VIDEO
|
|
||||||
USB
|
|
||||||
USB_GROUP
|
|
||||||
INSTALL
|
|
||||||
WORKING
|
|
||||||
DONE
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewModel() *model {
|
|
||||||
// Get the username
|
|
||||||
user, err := user.Current()
|
|
||||||
errorcheck.ErrorCheck(err, "Error getting username")
|
|
||||||
username := user.Username
|
|
||||||
|
|
||||||
// Create the auth input and focus it
|
|
||||||
authInput := textinput.New()
|
|
||||||
authInput.EchoMode = textinput.EchoPassword
|
|
||||||
authInput.Prompt = fmt.Sprintf("\n[sudo] password for %s: ", username)
|
|
||||||
authInput.Focus()
|
|
||||||
|
|
||||||
// Create a blank model and return it
|
|
||||||
return &model{
|
|
||||||
authDialog: authInput,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m model) Init() tea.Cmd {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *model) initLists(width, height int) {
|
|
||||||
defaultList := list.New([]list.Item{}, list.NewDefaultDelegate(), 0, 10)
|
|
||||||
choiceList := list.New([]list.Item{}, choiceDelegate{}, 0, 7)
|
|
||||||
|
|
||||||
// Disable features we wont need
|
|
||||||
defaultList.SetShowTitle(false)
|
|
||||||
defaultList.SetFilteringEnabled(false)
|
|
||||||
defaultList.SetSize(m.width, m.height)
|
|
||||||
choiceList.SetShowTitle(false)
|
|
||||||
choiceList.SetFilteringEnabled(false)
|
|
||||||
|
|
||||||
// Add height and width to our model so we can use it later
|
|
||||||
m.width = width
|
|
||||||
m.height = height
|
|
||||||
|
|
||||||
m.lists = []list.Model{
|
|
||||||
choiceList,
|
|
||||||
defaultList,
|
|
||||||
defaultList,
|
|
||||||
choiceList,
|
|
||||||
choiceList,
|
|
||||||
defaultList,
|
|
||||||
defaultList,
|
|
||||||
choiceList,
|
|
||||||
choiceList,
|
|
||||||
choiceList,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure offsets for sizing
|
|
||||||
m.offsetx = []int{
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
}
|
|
||||||
m.offsety = []int{
|
|
||||||
18, 2, 3, 13, 5, 2, 3, 12, 0, 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the styles with the correct width
|
|
||||||
dialogStyle = dialogStyle.Width(m.width)
|
|
||||||
listStyle = listStyle.Width(m.width)
|
|
||||||
titleStyle = titleStyle.Width(m.width - 4)
|
|
||||||
choiceStyle = choiceStyle.Width(m.width)
|
|
||||||
|
|
||||||
// Make m.fetched and set all values to FALSE
|
|
||||||
m.fetched = []bool{}
|
|
||||||
for range m.lists {
|
|
||||||
m.fetched = append(m.fetched, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set INTRO to the focused view
|
|
||||||
m.focused = INTRO
|
|
||||||
|
|
||||||
// Init INTRO choices
|
|
||||||
items := []list.Item{
|
|
||||||
item{title: "CONTINUE"},
|
|
||||||
}
|
|
||||||
//m.lists[INTRO].SetHeight(5)
|
|
||||||
m.lists[INTRO].SetItems(items)
|
|
||||||
m.lists[INTRO].SetSize(m.width-m.offsetx[INTRO], m.height-m.offsety[INTRO])
|
|
||||||
|
|
||||||
// Init GPU list
|
|
||||||
items = iommuList2ListItem(getIOMMU("-g", "-F", "vendor:,prod_name,optional_revision:,device_id"))
|
|
||||||
m.lists[GPUS].SetItems(items)
|
|
||||||
m.lists[GPUS].SetSize(m.width-m.offsetx[GPUS], m.height-m.offsety[GPUS])
|
|
||||||
m.fetched[GPUS] = true
|
|
||||||
|
|
||||||
// Setup the initial GPU_GROUP list
|
|
||||||
// The content in this list is generated from the selected choice from the GPU view
|
|
||||||
m.lists[GPU_GROUP].SetSize(m.width-m.offsetx[GPU_GROUP], m.height-m.offsety[GPU_GROUP])
|
|
||||||
|
|
||||||
// Init USB Controller list
|
|
||||||
items = iommuList2ListItem(getIOMMU("-u", "-F", "vendor:,prod_name,optional_revision:,device_id"))
|
|
||||||
m.lists[USB].SetItems(items)
|
|
||||||
m.lists[USB].SetSize(m.width-m.offsetx[USB], m.height-m.offsety[USB])
|
|
||||||
m.fetched[USB] = true
|
|
||||||
|
|
||||||
// Setup the initial USB_GROUP list
|
|
||||||
// The content in this list is generated from the selected choice from the USB view
|
|
||||||
m.lists[USB_GROUP].SetSize(m.width-m.offsetx[USB_GROUP], m.height-m.offsety[USB_GROUP])
|
|
||||||
|
|
||||||
// Init VBIOS choices
|
|
||||||
items = []list.Item{
|
|
||||||
item{title: "OK"},
|
|
||||||
}
|
|
||||||
m.lists[VBIOS].SetItems(items)
|
|
||||||
m.lists[VBIOS].SetSize(m.width-m.offsetx[VBIOS], m.height-m.offsety[VBIOS])
|
|
||||||
|
|
||||||
// Init VIDEO disable choises
|
|
||||||
items = []list.Item{
|
|
||||||
item{title: "YES"},
|
|
||||||
item{title: "NO"},
|
|
||||||
}
|
|
||||||
m.lists[VIDEO].SetItems(items)
|
|
||||||
m.lists[VIDEO].SetSize(m.width-m.offsetx[VIDEO], m.height-m.offsety[VIDEO])
|
|
||||||
|
|
||||||
// Init DONE choises
|
|
||||||
items = []list.Item{
|
|
||||||
item{title: "WAITING"},
|
|
||||||
}
|
|
||||||
m.lists[WORKING].SetItems(items)
|
|
||||||
m.lists[WORKING].SetSize(m.width-m.offsetx[WORKING], m.height-m.offsety[WORKING])
|
|
||||||
|
|
||||||
// Init DONE choises
|
|
||||||
items = []list.Item{
|
|
||||||
item{title: "FINISH"},
|
|
||||||
}
|
|
||||||
m.lists[DONE].SetItems(items)
|
|
||||||
m.lists[DONE].SetSize(m.width-m.offsetx[DONE], m.height-m.offsety[DONE])
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/bubbles/list"
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
|
||||||
"github.com/charmbracelet/lipgloss"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
titleStyle = lipgloss.NewStyle().
|
|
||||||
Background(lipgloss.Color("#5F5FD7")).
|
|
||||||
Foreground(lipgloss.Color("#FFFFFF")).
|
|
||||||
PaddingLeft(2).PaddingRight(2)
|
|
||||||
helpStyle = lipgloss.NewStyle().
|
|
||||||
Foreground(lipgloss.Color(241))
|
|
||||||
listStyle = lipgloss.NewStyle().
|
|
||||||
PaddingLeft(2).
|
|
||||||
PaddingRight(2)
|
|
||||||
choiceStyle = lipgloss.NewStyle().
|
|
||||||
PaddingLeft(4).
|
|
||||||
PaddingRight(4)
|
|
||||||
selectedChoiceStyle = lipgloss.NewStyle().
|
|
||||||
PaddingLeft(2).
|
|
||||||
Foreground(lipgloss.Color("170"))
|
|
||||||
dialogStyle = lipgloss.NewStyle().
|
|
||||||
PaddingLeft(2)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Choice delegate (for our dialog boxes)
|
|
||||||
type choiceDelegate struct{}
|
|
||||||
|
|
||||||
func (d choiceDelegate) Height() int { return 1 }
|
|
||||||
func (d choiceDelegate) Spacing() int { return 0 }
|
|
||||||
func (d choiceDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
|
|
||||||
func (d choiceDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
|
|
||||||
i, ok := listItem.(item)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
str := i.title
|
|
||||||
|
|
||||||
fn := choiceStyle.Render
|
|
||||||
if index == m.Index() {
|
|
||||||
fn = func(s ...string) string {
|
|
||||||
return selectedChoiceStyle.Render("| " + strings.Join(s, " "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprint(w, fn(str))
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os/exec"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/HikariKnight/ls-iommu/pkg/errorcheck"
|
|
||||||
"github.com/HikariKnight/quickpassthrough/internal/logger"
|
|
||||||
"github.com/charmbracelet/bubbles/list"
|
|
||||||
"github.com/klauspost/cpuid/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getIOMMU(args ...string) []string {
|
|
||||||
var stdout, stderr bytes.Buffer
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("Executing: utils/ls-iommu %s\n", strings.Join(args, " "))
|
|
||||||
|
|
||||||
// Configure the ls-iommu command
|
|
||||||
cmd := exec.Command("utils/ls-iommu", args...)
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
cmd.Stdout = &stdout
|
|
||||||
|
|
||||||
// Execute the command
|
|
||||||
err := cmd.Run()
|
|
||||||
|
|
||||||
// Generate the correct iommu string for the system
|
|
||||||
var iommu_args string
|
|
||||||
cpuinfo := cpuid.CPU
|
|
||||||
// Write the argument based on which cpu the user got
|
|
||||||
switch cpuinfo.VendorString {
|
|
||||||
case "AuthenticAMD":
|
|
||||||
iommu_args = "iommu=pt amd_iommu=on"
|
|
||||||
case "GenuineIntel":
|
|
||||||
iommu_args = "iommu=pt intel_iommu=on"
|
|
||||||
}
|
|
||||||
|
|
||||||
// If ls-iommu returns an error then IOMMU is disabled
|
|
||||||
errorcheck.ErrorCheck(err,
|
|
||||||
fmt.Sprintf(
|
|
||||||
"IOMMU disabled in either UEFI/BIOS or in bootloader!\n"+
|
|
||||||
"For your bootloader, make sure you have added the kernel arguments:\n"+
|
|
||||||
"%s",
|
|
||||||
iommu_args,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Read the output
|
|
||||||
var items []string
|
|
||||||
output, _ := io.ReadAll(&stdout)
|
|
||||||
|
|
||||||
// Write to logger
|
|
||||||
logger.Printf("ls-iommu query returned\n%s", string(output))
|
|
||||||
|
|
||||||
// Parse the output line by line
|
|
||||||
scanner := bufio.NewScanner(strings.NewReader(string(output)))
|
|
||||||
for scanner.Scan() {
|
|
||||||
// Write the objects into the list
|
|
||||||
items = append(items, scanner.Text())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return our list of items
|
|
||||||
return items
|
|
||||||
}
|
|
||||||
|
|
||||||
func iommuList2ListItem(stringList []string) []list.Item {
|
|
||||||
// Make the []list.Item struct
|
|
||||||
items := []list.Item{}
|
|
||||||
|
|
||||||
deviceID := regexp.MustCompile(`\[[a-f0-9]{4}:[a-f0-9]{4}\]\s+`)
|
|
||||||
// Parse the output line by line
|
|
||||||
for _, v := range stringList {
|
|
||||||
// Get the current line and split by :
|
|
||||||
objects := strings.Split(v, ": ")
|
|
||||||
|
|
||||||
// Write the objects into the list
|
|
||||||
items = append(items, item{title: deviceID.ReplaceAllString(objects[2], ""), desc: fmt.Sprintf("%s: %s: DeviceID: %s", objects[0], objects[1], objects[3])})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return our list of items
|
|
||||||
return items
|
|
||||||
}
|
|
Loading…
Reference in a new issue