diff --git a/util/coreboot-configurator/README.md b/util/coreboot-configurator/README.md
new file mode 100644
index 0000000000..baf04903b2
--- /dev/null
+++ b/util/coreboot-configurator/README.md
@@ -0,0 +1,65 @@
+# coreboot-configurator ![alt text](images/StarLabs_Logo.png "Star Labs Systems")
+
+A simple GUI to change settings in coreboot's CBFS, via the nvramtool utility.
+
+![coreboot-configurator](images/coreboot-configurator.gif)
+# How to install
+## Ubuntu, Linux Mint, elementary OS, Zorin OS and other derivates
+##### Install
+```
+sudo add-apt-repository ppa:starlabs/coreboot
+sudo apt update
+sudo apt install coreboot-configurator
+```
+##### Uninstall
+```
+sudo apt purge coreboot-configurator
+```
+
+## Debian 11
+##### Install
+```
+echo "deb http://ppa.launchpad.net/starlabs/ppa/ubuntu focal main" | sudo tee -a /etc/apt/sources.list.d/starlabs-ubuntu-ppa-focal.list
+sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 17A20BAF70BEC3904545ACFF8F21C26C794386E3
+sudo apt update
+sudo apt install coreboot-configurator
+```
+
+##### Uninstall
+```
+sudo apt purge coreboot-configurator
+```
+
+## Manjaro
+##### Install
+```
+sudo pamac install coreboot-configurator
+```
+##### Uninstall
+```
+sudo pamac remove coreboot-configurator
+```
+
+## Other Distributions
+##### Install
+```
+git clone https://github.com/StarLabsLtd/coreboot-configurator.git
+cd coreboot-configurator
+meson build
+ninja -C build install
+```
+##### Uninstall
+```
+sudo ninja -C uninstall
+```
+
+# Advanced Mode
+Enabling advanced mode will all you to see all settings contained inside coreboot. Tread carefully :)
+
+## Copying or Reusing
+Included scripts are free software licensed under the terms of the [GNU General Public License, version 2](https://www.gnu.org/licenses/gpl-2.0.txt).
+
+# [© Star Labs® / All Rights Reserved.](https://starlabs.systems)
+Any issues or questions, please contact us at [support@starlabs.systems](mailto:supportstarlabs.systems)
+
+View our full range of Linux laptops at: [https://starlabs.systems](https://starlabs.systems)
diff --git a/util/coreboot-configurator/images/StarLabs_Logo.png b/util/coreboot-configurator/images/StarLabs_Logo.png
new file mode 100644
index 0000000000..bea381b799
Binary files /dev/null and b/util/coreboot-configurator/images/StarLabs_Logo.png differ
diff --git a/util/coreboot-configurator/images/coreboot-configurator.gif b/util/coreboot-configurator/images/coreboot-configurator.gif
new file mode 100644
index 0000000000..64e0a2f44c
Binary files /dev/null and b/util/coreboot-configurator/images/coreboot-configurator.gif differ
diff --git a/util/coreboot-configurator/meson.build b/util/coreboot-configurator/meson.build
new file mode 100644
index 0000000000..b3175ccdba
--- /dev/null
+++ b/util/coreboot-configurator/meson.build
@@ -0,0 +1,12 @@
+## SPDX-License-Identifier: GPL-2.0-only
+
+project('coreboot-configurator',
+ 'cpp',
+ version: '8',
+ license: ['GPL2', 'CC BY-SA 4.0'],
+ meson_version: '>= 0.53.0',
+ default_options: ['prefix=/usr',
+ 'cpp_std=c++14'],
+)
+
+subdir('src')
diff --git a/util/coreboot-configurator/meson_options.txt b/util/coreboot-configurator/meson_options.txt
new file mode 100644
index 0000000000..2dedd74024
--- /dev/null
+++ b/util/coreboot-configurator/meson_options.txt
@@ -0,0 +1,12 @@
+## SPDX-License-Identifier: GPL-2.0-only
+
+option('sizes',
+ type: 'array',
+ choices: ['24', '48', '96', '16', '32', '64', '128', '256', '512'],
+ description: 'Choose icon size(s)',
+)
+
+option('mock',
+ type : 'boolean',
+ value : false
+)
diff --git a/util/coreboot-configurator/src/README.md b/util/coreboot-configurator/src/README.md
new file mode 100644
index 0000000000..e3386242a2
--- /dev/null
+++ b/util/coreboot-configurator/src/README.md
@@ -0,0 +1,31 @@
+# Categories ![alt text](images/StarLabs_Logo.png "Star Labs Systems")
+
+CMOS values should be added to [categories.yaml](src/application/categories.yaml].
+
+This allows `coreboot-configurator` to display them in a relavant tab, with a nice
+name and help text. Without this, they will still be visible in the **Raw** tab.
+
+An example entry is below:
+```
+processor:
+ displayName: Processor
+ me_state:
+ displayName: Intel Management Engine
+ type: bool
+ help: Enable or disable the Intel Management Engine
+```
+
+To explain the options:
+```
+**tabgroup**: <- This is the reference to the tab group
+ displayName: **Hello World** <- This is the name of the group that the user
+ will see
+ **setting_1**: <- This is the value that should match the CMOS
+ option.
+ displayName: **Hi World** <- This is the name of the option that the user
+ will see.
+ type: **bool** <- Valid type are: bool (checkbox) and enum
+ <- (dropdown).
+ help: **Greet the World** <- Help text that is displayed when hovering on the
+ option.
+```
diff --git a/util/coreboot-configurator/src/application/AboutDialog.cpp b/util/coreboot-configurator/src/application/AboutDialog.cpp
new file mode 100644
index 0000000000..8282e0c063
--- /dev/null
+++ b/util/coreboot-configurator/src/application/AboutDialog.cpp
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include "AboutDialog.h"
+#include "NvramToolCli.h"
+#include "ui_AboutDialog.h"
+
+AboutDialog::AboutDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::AboutDialog)
+{
+ ui->setupUi(this);
+
+ ui->logoLabel->setPixmap(QPixmap(":/images/star.svg"));
+
+ ui->versionLabel->setText(""+NvramToolCli::version()+"");
+}
+
+AboutDialog::~AboutDialog()
+{
+ delete ui;
+}
diff --git a/util/coreboot-configurator/src/application/AboutDialog.h b/util/coreboot-configurator/src/application/AboutDialog.h
new file mode 100644
index 0000000000..7a3123335d
--- /dev/null
+++ b/util/coreboot-configurator/src/application/AboutDialog.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#pragma once
+
+#include
+
+namespace Ui {
+class AboutDialog;
+}
+
+class AboutDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AboutDialog(QWidget *parent = nullptr);
+ ~AboutDialog();
+
+private:
+ Ui::AboutDialog *ui;
+};
diff --git a/util/coreboot-configurator/src/application/AboutDialog.ui b/util/coreboot-configurator/src/application/AboutDialog.ui
new file mode 100644
index 0000000000..009acc24b9
--- /dev/null
+++ b/util/coreboot-configurator/src/application/AboutDialog.ui
@@ -0,0 +1,141 @@
+
+
+ AboutDialog
+
+
+
+ 0
+ 0
+ 412
+ 273
+
+
+
+ About
+
+
+ -
+
+
+ <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">coreboot configurator</span></p></body></html>
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p>A simple GUI to change settings in coreboot's CBFS, via the nvramtool utility.</p></body></html>
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p><a href="https://support.starlabs.systems"><span style=" text-decoration: underline; color:#0000ff;">starlabs.systems</span></a></p></body></html>
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Ok
+
+
+ true
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ AboutDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ AboutDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/util/coreboot-configurator/src/application/Configuration.cpp b/util/coreboot-configurator/src/application/Configuration.cpp
new file mode 100644
index 0000000000..9f383f83e2
--- /dev/null
+++ b/util/coreboot-configurator/src/application/Configuration.cpp
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include
+#include
+#include
+
+#include "Configuration.h"
+#include "Util.h"
+
+QMap Configuration::fromFile(const QString &curr_path)
+{
+ QFile curr_file(curr_path);
+
+ if ( !curr_file.open(QFile::ReadOnly)
+ || !curr_file.isReadable()
+ || curr_file.atEnd()) {
+ return {};
+ }
+
+ auto result = Util::parseParameters(curr_file);
+
+ curr_file.close();
+ return result;
+}
+
+
+bool Configuration::toFile(const QString &curr_path, const Parameters ¶ms)
+{
+ QFile output(curr_path);
+
+ if(!output.open(QFile::WriteOnly|QFile::Truncate)){
+ return false;
+ }
+ QTextStream outStream(&output);
+ for(auto it = params.begin(); it != params.end(); ++it){
+ outStream << it.key() << " = " << it.value() << "\n";
+ }
+
+ output.close();
+ return true;
+}
diff --git a/util/coreboot-configurator/src/application/Configuration.h b/util/coreboot-configurator/src/application/Configuration.h
new file mode 100644
index 0000000000..b2559d4960
--- /dev/null
+++ b/util/coreboot-configurator/src/application/Configuration.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+
+namespace Configuration {
+
+using Parameters = QMap;
+
+Parameters fromFile(const QString& curr_path);
+bool toFile(const QString& curr_path, const Parameters& params);
+
+}
diff --git a/util/coreboot-configurator/src/application/MainWindow.cpp b/util/coreboot-configurator/src/application/MainWindow.cpp
new file mode 100644
index 0000000000..d51937d161
--- /dev/null
+++ b/util/coreboot-configurator/src/application/MainWindow.cpp
@@ -0,0 +1,388 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "AboutDialog.h"
+#include "Configuration.h"
+#include "MainWindow.h"
+#include "NvramToolCli.h"
+#include "ToggleSwitch.h"
+#include "ui_MainWindow.h"
+
+static auto s_errorWindowTitle = MainWindow::tr("Error Occured");
+static auto s_nvramErrorMessage = MainWindow::tr("Nvramtool was not able to access cmos settings. Look at documentation for possible causes of errors.");
+
+QString makeNvramErrorMessage(const QString& error){
+ if(!error.trimmed().isEmpty()){
+ return QString(MainWindow::tr("%1
Error message:
%2")).arg(s_nvramErrorMessage,
+ Qt::convertFromPlainText(error));
+ }
+ return s_nvramErrorMessage;
+}
+
+namespace YAML {
+template <>
+struct convert{
+ static Node encode(const QString& rhs) { return Node(rhs.toUtf8().data()); }
+
+ static bool decode(const Node& node, QString& rhs) {
+ if (!node.IsScalar())
+ return false;
+ rhs = QString::fromStdString(node.Scalar());
+ return true;
+ }
+};
+}
+
+static auto s_metadataErrorMessage = MainWindow::tr("Can't load categories metadata file. Check your installation.");
+static constexpr char s_sudoProg[] = "/usr/bin/pkexec";
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ connect(ui->actionAbout, &QAction::triggered, this, [](){
+ AboutDialog().exec();
+ });
+
+#if MOCK
+ this->setWindowTitle("coreboot configurator "+tr("[MOCKED DATA]"));
+#else
+ this->setWindowTitle("coreboot configurator");
+#endif
+ this->setWindowIcon(QIcon::fromTheme("coreboot_configurator"));
+
+ QFile catFile(":/config/categories.yaml");
+
+ if(!catFile.open(QFile::ReadOnly)){
+ QMessageBox::critical(this, s_errorWindowTitle, s_metadataErrorMessage);
+ this->close();
+ return;
+ }
+
+ m_categories = YAML::Load(catFile.readAll());
+
+ if(m_categories.IsNull() || !m_categories.IsDefined()){
+ QMessageBox::critical(this, s_errorWindowTitle, s_metadataErrorMessage);
+ this->close();
+ return;
+ }
+
+ QShortcut* returnAction = new QShortcut(QKeySequence("Ctrl+Return"), this);
+ connect(returnAction, &QShortcut::activated, this, &MainWindow::on_saveButton_clicked);
+
+ generateUi();
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+void MainWindow::pullSettings()
+{
+ QString error;
+ m_parameters = NvramToolCli::readParameters(&error);
+
+ if(m_parameters.isEmpty()){
+ QMessageBox::critical(this, s_errorWindowTitle, makeNvramErrorMessage(error));
+
+ /* we need delayed close as initialization error happened before event loop start so we can't stop application properly */
+ QTimer::singleShot(0, this, &MainWindow::close);
+ }
+}
+
+void MainWindow::pushSettings()
+{
+ QString error;
+ if(!NvramToolCli::writeParameters(m_parameters, &error)){
+ QMessageBox::critical(this, s_errorWindowTitle, makeNvramErrorMessage(error));
+ }
+}
+
+
+QComboBox* MainWindow::createComboBox(const QString& key) {
+ auto box = new QComboBox(this);
+
+ auto opts = NvramToolCli::readOptions(key);
+
+ box->addItems(opts);
+ box->setCurrentText(m_parameters[key]);
+
+ connect(ui->advancedModeCheckBox, &QCheckBox::clicked, this, [box](bool clicked){
+ box->setEditable(clicked);
+ });
+
+ connect(this, &MainWindow::updateValue, this, [box, this, key](const QString& name){
+ if(key!=name || m_parameters[name]==box->currentText()){
+ return;
+ }
+ box->setCurrentText(m_parameters[name]);
+ });
+
+ connect(box, &QComboBox::currentTextChanged, this, [key, this](const QString& value){
+ if(value==m_parameters[key]){
+ return;
+ }
+ m_parameters[key] = value;
+ emit updateValue(key);
+ });
+
+ return box;
+}
+QString boolToString(bool value){
+ return value?QStringLiteral("Enable"):QStringLiteral("Disable");
+}
+bool stringToBool(const QString& str){
+ return str==QStringLiteral("Enable");
+}
+QCheckBox* MainWindow::createCheckBox(const QString& key) {
+ auto box = new ToggleSwitch(this);
+
+ box->setChecked(stringToBool(m_parameters[key]));
+
+ connect(this, &MainWindow::updateValue, this, [box, this, key](const QString& name){
+
+ if(key!=name || m_parameters[name]==boolToString(box->isChecked())){
+ return;
+ }
+ auto newValue = stringToBool(m_parameters[name]);
+
+ box->setChecked(newValue);
+ });
+
+ connect(box, &QCheckBox::clicked, this, [key, this](bool checked){
+ auto value = boolToString(checked);
+ if(value==m_parameters[key]){
+ return;
+ }
+ m_parameters[key] = value;
+ emit updateValue(key);
+ });
+
+ return box;
+}
+
+
+QTableWidget *MainWindow::createRawTable()
+{
+ /* Create Raw values table */
+ auto table = new QTableWidget(m_parameters.size(), 2);
+ table->setHorizontalHeaderLabels({tr("Key"), tr("Value")});
+ table->horizontalHeader()->setSectionResizeMode(0,QHeaderView::Stretch);
+ table->verticalHeader()->hide();
+ table->setSelectionBehavior(QTableWidget::SelectRows);
+
+ connect(table, &QTableWidget::cellChanged, this, [table, this](int row, int column){
+ if(column != 1 || row >= table->rowCount() || row < 0 ){
+ /* Weird state when changed cell is not a value cell */
+ return;
+ }
+ auto keyItem = table->item(row, 0);
+ auto valueItem = table->item(row, 1);
+
+ if(keyItem == nullptr || valueItem == nullptr){
+ /* Invalid cells */
+ return;
+ }
+
+ if(valueItem->text()==m_parameters[keyItem->text()]){
+ return;
+ }
+
+ m_parameters[keyItem->text()] = valueItem->text();
+ emit updateValue(keyItem->text());
+ });
+
+ auto it = m_parameters.begin();
+ for(int i = 0; isetFlags(item->flags() ^ Qt::ItemIsEditable);
+ table->setItem(i,0,item);
+
+ item = new QTableWidgetItem(it.value());
+ connect(this, &MainWindow::updateValue, this, [item, it, this](const QString& name){
+ if(it.key()!=name || m_parameters[name]==item->text()){
+ return;
+ }
+ item->setText(m_parameters[name]);
+ });
+
+ table->setItem(i,1,item);
+ }
+ return table;
+}
+
+void MainWindow::generateUi()
+{
+ pullSettings();
+
+ if(!m_categories.IsMap()){
+ return;
+ }
+ for(const auto& category : m_categories){
+ if(!category.second.IsMap()){
+ continue;
+ }
+ auto name = category.second["displayName"].as();
+
+ auto layout = new QVBoxLayout;
+
+ auto tabPage = new QWidget(this);
+ tabPage->setLayout(layout);
+
+ ui->centralTabWidget->addTab(tabPage, name);
+
+ for(const auto& value : category.second){
+ if(!value.second.IsMap() || !m_parameters.contains(value.first.as())){
+ continue;
+ }
+ auto displayName = value.second["displayName"];
+ if(!displayName.IsDefined()){
+ continue;
+ }
+ auto type = value.second["type"];
+ if(!type.IsDefined()){
+ continue;
+ }
+
+ auto controlLayout = new QHBoxLayout();
+
+ auto help = value.second["help"];
+
+ if(help.IsDefined()){
+ auto labelWithTooltip = new QWidget;
+ labelWithTooltip->setToolTip(help.as());
+ labelWithTooltip->setCursor({Qt::WhatsThisCursor});
+ labelWithTooltip->setLayout(new QHBoxLayout);
+
+ auto helpButton = new QLabel();
+ helpButton->setPixmap(QIcon::fromTheme("help-hint").pixmap(16,16));
+
+ {
+ auto layout = qobject_cast(labelWithTooltip->layout());
+ layout->addWidget(new QLabel(displayName.as()));
+ layout->addWidget(helpButton,1);
+ }
+ controlLayout->addWidget(labelWithTooltip, 0);
+ } else {
+ controlLayout->addWidget(new QLabel(displayName.as()), 0);
+ }
+
+ controlLayout->addStretch(1);
+
+ QWidget* res = nullptr;
+
+ if(type.as() == QStringLiteral("bool")){
+ res = createCheckBox(value.first.as());
+ } else if (type.as() == QStringLiteral("enum")){
+ res = createComboBox(value.first.as());
+ } else {
+ controlLayout->deleteLater();
+ continue;
+ }
+ res->setObjectName(value.first.as());
+
+ controlLayout->addWidget(res, 0);
+
+ layout->addLayout(controlLayout);
+ }
+ }
+
+ auto table = createRawTable();
+
+ connect(ui->advancedModeCheckBox, &QCheckBox::clicked, this, [table,this](bool clicked){
+ if(clicked && ui->centralTabWidget->widget(ui->centralTabWidget->count()-1) != table){
+ ui->centralTabWidget->addTab(table, tr("Raw"));
+ } else if(!clicked && ui->centralTabWidget->widget(ui->centralTabWidget->count()-1) == table) {
+ ui->centralTabWidget->removeTab(ui->centralTabWidget->count()-1);
+ }
+ });
+}
+
+void MainWindow::askForReboot()
+{
+ QMessageBox rebootDialog(QMessageBox::Question,
+ tr("Reboot"),
+ tr("Changes are saved. Do you want to reboot to apply changes?"));
+
+ auto nowButton = rebootDialog.addButton(tr("Reboot now"), QMessageBox::AcceptRole);
+ rebootDialog.addButton(tr("Reboot later"), QMessageBox::RejectRole);
+
+ rebootDialog.exec();
+ if(rebootDialog.clickedButton()==nowButton){
+ QProcess::startDetached(s_sudoProg, {"/usr/bin/systemctl", "reboot"});
+ this->close();
+ }
+}
+
+void MainWindow::readSettings(const QString &fileName)
+{
+ if(fileName.isEmpty()){
+ return;
+ }
+
+ auto configValues = Configuration::fromFile(fileName);
+
+ for(auto it = configValues.begin(); it != configValues.end(); ++it){
+ if(!m_parameters.contains(it.key())){
+ continue;
+ }
+ m_parameters[it.key()]=it.value();
+ emit updateValue(it.key());
+ }
+}
+
+void MainWindow::writeSettings(const QString &fileName)
+{
+ if(fileName.isEmpty()){
+ return;
+ }
+ if(!Configuration::toFile(fileName, m_parameters)){
+ QMessageBox::critical(this, tr("Error Occured"), tr("Can't open file to write"));
+ this->close();
+ }
+}
+
+
+void MainWindow::on_actionSave_triggered()
+{
+ auto filename = QFileDialog::getSaveFileName(this,
+ tr("Select File To Save"),
+ QDir::homePath(),
+ tr("Coreboot Configuration Files")+"(*.cfg)");
+ writeSettings(filename);
+}
+
+
+void MainWindow::on_actionLoad_triggered()
+{
+ auto filename = QFileDialog::getOpenFileName(this,
+ tr("Select File To Load"),
+ QDir::homePath(),
+ tr("Coreboot Configuration Files")+"(*.cfg)");
+
+ readSettings(filename);
+}
+
+
+void MainWindow::on_saveButton_clicked()
+{
+ ui->centralwidget->setEnabled(false);
+ ui->menubar->setEnabled(false);
+
+ pushSettings();
+
+ askForReboot();
+
+ ui->centralwidget->setEnabled(true);
+ ui->menubar->setEnabled(true);
+}
diff --git a/util/coreboot-configurator/src/application/MainWindow.h b/util/coreboot-configurator/src/application/MainWindow.h
new file mode 100644
index 0000000000..bf317a814f
--- /dev/null
+++ b/util/coreboot-configurator/src/application/MainWindow.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class MainWindow; }
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+signals:
+ void updateValue(const QString& key);
+
+private slots:
+ void on_actionSave_triggered(void);
+
+ void on_actionLoad_triggered(void);
+
+ void on_saveButton_clicked(void);
+
+private:
+ void pullSettings(void);
+ void pushSettings(void);
+
+ void generateUi(void);
+ void askForReboot(void);
+
+ void readSettings(const QString& fileName);
+ void writeSettings(const QString& fileName);
+
+ Configuration::Parameters m_parameters;
+ YAML::Node m_categories;
+
+ Ui::MainWindow *ui;
+
+ QComboBox *createComboBox(const QString &key);
+ QCheckBox *createCheckBox(const QString &key);
+
+ QTableWidget *createRawTable();
+};
diff --git a/util/coreboot-configurator/src/application/MainWindow.ui b/util/coreboot-configurator/src/application/MainWindow.ui
new file mode 100644
index 0000000000..0f59d80585
--- /dev/null
+++ b/util/coreboot-configurator/src/application/MainWindow.ui
@@ -0,0 +1,118 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 600
+ 400
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 600
+ 400
+
+
+
+
+ 600
+ 400
+
+
+
+ coreboot configurator
+
+
+
+ -
+
+
+ -
+
+
-
+
+
+ Advanced mode
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Save
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save to File...
+
+
+
+
+ Load from File...
+
+
+
+
+ About...
+
+
+
+
+
+
diff --git a/util/coreboot-configurator/src/application/NvramToolCli.cpp b/util/coreboot-configurator/src/application/NvramToolCli.cpp
new file mode 100644
index 0000000000..da844a043b
--- /dev/null
+++ b/util/coreboot-configurator/src/application/NvramToolCli.cpp
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include
+#include
+
+#include "NvramToolCli.h"
+#include "Util.h"
+
+static constexpr char s_sudoProg[] = "/usr/bin/pkexec";
+static constexpr char s_nvramToolProg[] = "/usr/sbin/nvramtool";
+
+#if MOCK
+
+QMap NvramToolCli::readParameters(QString *error) {
+ return QMap({
+ {"boot_option","Normal"},
+ {"reboot_counter","0x0"},
+ {"debug_level","Spew"},
+ {"vtd","Enable"},
+ {"power_profile","Performance"},
+ {"wireless","Enable"},
+ {"webcam","Enable"},
+ {"microphone","Enable"},
+ {"legacy_8254_timer","Enable"},
+ {"usb_always_on","Disable"},
+ {"kbl_timeout","Never"},
+ {"fn_ctrl_swap","Enable"},
+ {"max_charge","100%"},
+ {"power_on_after_fail","Disable"},
+ {"fn_lock_state","0x2"},
+ {"trackpad_state","0x40"},
+ {"kbl_brightness","0xc4"},
+ {"kbl_state","0x22"}
+ });
+}
+
+QStringList NvramToolCli::readOptions(const QString ¶meter, QString *error){
+ return (parameter=="power_profile")?
+ QStringList{
+ "Power Saver","Balanced","Performance"
+ } : QStringList{};
+}
+
+#else
+
+QMap NvramToolCli::readParameters(QString *error)
+{
+ QProcess nvramtoolProcess;
+ nvramtoolProcess.start(s_sudoProg, {s_nvramToolProg, "-a"});
+
+ nvramtoolProcess.waitForFinished();
+
+ if(error) *error = nvramtoolProcess.readAllStandardError();
+
+ if(nvramtoolProcess.exitCode() != 0){
+ return {};
+ }
+
+ return Util::parseParameters(nvramtoolProcess);
+}
+
+QStringList NvramToolCli::readOptions(const QString ¶meter, QString *error)
+{
+ QStringList result;
+
+ QProcess nvramtoolProcess;
+ nvramtoolProcess.start(s_sudoProg, {s_nvramToolProg, "-e", parameter});
+ nvramtoolProcess.waitForFinished();
+
+ if(error) *error = nvramtoolProcess.readAllStandardError();
+
+ while (nvramtoolProcess.canReadLine()) {
+ result.append(nvramtoolProcess.readLine().trimmed());
+ }
+
+ return result;
+}
+#endif
+
+bool NvramToolCli::writeParameters(const QMap ¶meters, QString *error)
+{
+
+#if MOCK
+ QTextStream outStream(stdout);
+#else
+ QProcess nvramtoolProcess;
+ nvramtoolProcess.start(s_sudoProg, {s_nvramToolProg, "-i"});
+ nvramtoolProcess.waitForStarted();
+ QTextStream outStream(&nvramtoolProcess);
+#endif
+ for(auto it = parameters.begin(); it != parameters.end(); ++it){
+ outStream << it.key() << " = " << it.value() << "\n";
+ }
+
+ outStream.flush();
+#if MOCK
+ return true;
+#else
+ nvramtoolProcess.closeWriteChannel();
+ nvramtoolProcess.waitForFinished();
+
+ if(error){
+ *error = nvramtoolProcess.readAllStandardError();
+ }
+
+ return nvramtoolProcess.exitCode()==0;
+#endif
+}
+
+
+
+QString NvramToolCli::version()
+{
+ QProcess nvramtoolProcess;
+ nvramtoolProcess.start(s_nvramToolProg, {"-v"});
+
+ nvramtoolProcess.waitForFinished();
+
+ return nvramtoolProcess.readAll();
+}
diff --git a/util/coreboot-configurator/src/application/NvramToolCli.h b/util/coreboot-configurator/src/application/NvramToolCli.h
new file mode 100644
index 0000000000..3bb5d0a6ea
--- /dev/null
+++ b/util/coreboot-configurator/src/application/NvramToolCli.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#pragma once
+
+#include
+#include
+#include
+
+#include "Configuration.h"
+
+/*
+ * Namespace for convinient functions to work with nvramtool CLI utility
+ */
+namespace NvramToolCli {
+
+Configuration::Parameters readParameters(QString* error = nullptr);
+QStringList readOptions(const QString& parameter, QString* error = nullptr);
+bool writeParameters(const Configuration::Parameters& parameters, QString* error = nullptr);
+QString version();
+
+}
diff --git a/util/coreboot-configurator/src/application/ToggleSwitch.cpp b/util/coreboot-configurator/src/application/ToggleSwitch.cpp
new file mode 100644
index 0000000000..b0a399e01c
--- /dev/null
+++ b/util/coreboot-configurator/src/application/ToggleSwitch.cpp
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "ToggleSwitch.h"
+#include "ToggleSwitch.svg.h"
+
+const QByteArray ToggleSwitch::s_toggleOffSvgContent = ToggleSwitchSVG::s_toggledOffContent;
+const QByteArray ToggleSwitch::s_toggleOnSvgContent = ToggleSwitchSVG::s_toggledOnContent;
+const int ToggleSwitch::s_colorPosInToggleOn = ToggleSwitch::s_toggleOnSvgContent.indexOf("#1a73e8");
+
+ToggleSwitch::ToggleSwitch(QWidget *parent) : QCheckBox(parent){
+
+ setFixedWidth(50);
+ setFixedHeight(width()/2);
+
+ m_toggleOnSvgContentColored = s_toggleOnSvgContent;
+}
+
+void ToggleSwitch::paintEvent(QPaintEvent *event){
+ QPainter p(this);
+
+ if(isChecked()){
+ auto accent = palette().highlight().color();
+ m_toggleOnSvgContentColored = m_toggleOnSvgContentColored.replace(s_colorPosInToggleOn, 7, accent.name().toLatin1());
+
+ m_svgr.load(m_toggleOnSvgContentColored);
+ } else {
+ m_svgr.load(s_toggleOffSvgContent);
+ }
+
+ m_svgr.render(&p, this->rect());
+ p.end();
+}
diff --git a/util/coreboot-configurator/src/application/ToggleSwitch.h b/util/coreboot-configurator/src/application/ToggleSwitch.h
new file mode 100644
index 0000000000..191dc5ef96
--- /dev/null
+++ b/util/coreboot-configurator/src/application/ToggleSwitch.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+
+/*
+ * The ToggleSwitch class represents Toggle Switch widget based on QCheckBox and toggles svg with colorscheme support
+ */
+class ToggleSwitch : public QCheckBox {
+ Q_OBJECT
+public:
+ explicit ToggleSwitch(QWidget* parent = nullptr);
+
+private:
+ QSvgRenderer m_svgr;
+
+ static const QByteArray s_toggleOnSvgContent;
+ static const QByteArray s_toggleOffSvgContent;
+ static const int s_colorPosInToggleOn;
+
+ QByteArray m_toggleOnSvgContentColored;
+
+ /* QWidget interface */
+protected:
+ void paintEvent(QPaintEvent *event) override;
+
+ /* QAbstractButton interface */
+protected:
+ bool hitButton(const QPoint &pos) const override
+ {
+ /* needs to be clickable on */
+ return rect().contains(pos);
+ }
+};
diff --git a/util/coreboot-configurator/src/application/ToggleSwitch.svg.h b/util/coreboot-configurator/src/application/ToggleSwitch.svg.h
new file mode 100644
index 0000000000..4aeb12b122
--- /dev/null
+++ b/util/coreboot-configurator/src/application/ToggleSwitch.svg.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#pragma once
+
+/* Embed SVG files into code as debian packages does weird things when svgs are included as qrc */
+namespace ToggleSwitchSVG {
+static constexpr char s_toggledOnContent[] =
+ "\n"
+ "\n";
+static constexpr char s_toggledOffContent[] =
+ "";
+}
diff --git a/util/coreboot-configurator/src/application/Util.h b/util/coreboot-configurator/src/application/Util.h
new file mode 100644
index 0000000000..55553f2981
--- /dev/null
+++ b/util/coreboot-configurator/src/application/Util.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#pragma once
+
+#include
+#include
+#include
+
+namespace Util {
+ inline QMap parseParameters(QIODevice& dev){
+ QString curr_line;
+ QMap result;
+
+ while (!dev.atEnd()) {
+ curr_line = dev.readLine().trimmed();
+
+ auto split = curr_line.split('=');
+ if(split.size()!=2){
+ continue;
+ }
+
+ result.insert(split[0].trimmed(), split[1].trimmed());
+ }
+ return result;
+ }
+}
diff --git a/util/coreboot-configurator/src/application/lang.qrc b/util/coreboot-configurator/src/application/lang.qrc
new file mode 100644
index 0000000000..e25d9df240
--- /dev/null
+++ b/util/coreboot-configurator/src/application/lang.qrc
@@ -0,0 +1,3 @@
+
+
+
diff --git a/util/coreboot-configurator/src/application/main.cpp b/util/coreboot-configurator/src/application/main.cpp
new file mode 100644
index 0000000000..94b10d9fff
--- /dev/null
+++ b/util/coreboot-configurator/src/application/main.cpp
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include
+#include
+
+#include "MainWindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ QTranslator translator;
+ if (translator.load(QLocale(), QLatin1String("corebootconfigurator"), QLatin1String("_"), QLatin1String(":/lang/i18n"))){
+ a.installTranslator(&translator);
+ }
+
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/util/coreboot-configurator/src/application/meson.build b/util/coreboot-configurator/src/application/meson.build
new file mode 100644
index 0000000000..cb9b50e8d1
--- /dev/null
+++ b/util/coreboot-configurator/src/application/meson.build
@@ -0,0 +1,35 @@
+## SPDX-License-Identifier: GPL-2.0-only
+
+# Documentation: https://mesonbuild.com/Qt5-module.html
+qt5 = import('qt5')
+qt5_dep = dependency('qt5', modules : ['Core', 'Widgets', 'Svg'])
+yamlcpp_dep = dependency('yaml-cpp', version: '>= 0.5.1', required: true)
+
+# TODO: Translations
+# lang_cpp = qt5.compile_translations(qresource: 'lang.qrc')
+
+generated_files = qt5.preprocess(
+ moc_headers : ['MainWindow.h', 'AboutDialog.h', 'ToggleSwitch.h'],
+ ui_files : ['MainWindow.ui', 'AboutDialog.ui'],
+ dependencies : [qt5_dep],
+ qresources : ['resources.qrc'],
+)
+
+mock = get_option('mock')
+
+if mock
+ add_project_arguments('-DMOCK', language : 'cpp')
+endif
+
+executable('coreboot-configurator',
+ 'main.cpp',
+ 'MainWindow.cpp',
+ 'AboutDialog.cpp',
+ 'Configuration.cpp',
+ 'ToggleSwitch.cpp',
+ 'NvramToolCli.cpp',
+# lang_cpp,
+ generated_files,
+ dependencies : [qt5_dep, yamlcpp_dep],
+ install : true
+)
diff --git a/util/coreboot-configurator/src/application/qrc/categories.yaml b/util/coreboot-configurator/src/application/qrc/categories.yaml
new file mode 100644
index 0000000000..21419511fe
--- /dev/null
+++ b/util/coreboot-configurator/src/application/qrc/categories.yaml
@@ -0,0 +1,119 @@
+ processor:
+ displayName: Processor
+ hyper_threading:
+ displayName: Hyper-Threading
+ type: bool
+ help: Enable or disable Hyper-Threading
+ vtd:
+ displayName: Intel VT-d
+ type: bool
+ help: Enable or disable Intel VT-d (virtualisation)
+ power_profile:
+ displayName: Power Profile
+ type: enum
+ help: Select whether to maximise performance, battery life or both
+ me_state:
+ displayName: Intel Management Engine
+ type: bool
+ help: Enable or disable the Intel Management Engine
+
+ devices:
+ displayName: Devices
+ wireless:
+ displayName: Wireless
+ type: bool
+ help: Enable or disable the built-in wireless card
+ wlan:
+ displayName: Wireless
+ type: bool
+ help: Enable or disable the built-in wireless card
+ bluetooth:
+ displayName: Bluetooth
+ type: bool
+ help: Enable or disable the built-in bluetooth
+ wwan:
+ displayName: Mobile Network
+ type: bool
+ help: Enable or disable the built-in mobile network
+ ethernet1:
+ displayName: Ethernet 1
+ type: bool
+ help: Enable or disable the built-in Ethernet Port 1
+ ethernet2:
+ displayName: Ethernet 2
+ type: bool
+ help: Enable or disable the built-in Ethernet Port 2
+ ethernet3:
+ displayName: Ethernet 3
+ type: bool
+ help: Enable or disable the built-in Ethernet Port 3
+ webcam:
+ displayName: Webcam
+ type: bool
+ help: Enable or disable the built-in webcam
+ microphone:
+ displayName: Microphone
+ type: bool
+ help: Enable or disable the built-in microphone
+ legacy_8254_timer:
+ displayName: Clock Gating
+ type: bool
+ help: Enable or disable the legacy 8254 timer. Reduces power consumption when enabled but must be disabled for certain distributions such as Qubes
+ usb_always_on:
+ displayName: USB Always On
+ type: bool
+ help: Allow the USB ports to provide power to connected devices when the computer is suspended
+ touchpad:
+ displayName: Touchpad
+ type: bool
+ help: Enable or disable the built-in touchpad
+ trackpoint:
+ displayName: Trackpoint
+ type: bool
+ help: Enable or disable the built-in trackpoint
+ sata_mode:
+ displayName: SATA Mode
+ type: enum
+ help: Set the mode of the SATA controller from AHCI or Compatible
+ thunderbolt:
+ displayName: Thunderbolt
+ type: bool
+ help: Enable or disable Thunderbolt functionality
+
+ system:
+ displayName: System
+ kbl_timeout:
+ displayName: Keyboard Backlight Timeout
+ type: enum
+ help: Adjust the amout of time before the keyboard backlight turns off when un-used
+ fn_ctrl_swap:
+ displayName: Fn Ctrl Reverse
+ type: bool
+ help: Swap the functions of the [Fn] and [Ctrl] keys
+ max_charge:
+ displayName: Max Charge
+ type: enum
+ help: Set the maximum level the battery will charge to
+ fan_mode:
+ displayName: Fan Mode
+ type: enum
+ help: Adjust the fan curve to priotise performance or noise levels
+ f1_to_f12_as_primary:
+ displayName: Function Lock
+ type: bool
+ help: Make the F-keys behave as if you are holding down the Fn key
+
+ advanced:
+ displayName: Advanced
+ boot_option:
+ displayName: Boot Options
+ type: enum
+ help: Change the boot device in the event of a failed boot
+ debug_level:
+ displayName: Debug Level
+ type: enum
+ help: Set the verbosity of the debug output
+ power_on_after_fail:
+ displayName: Power on Behaviour
+ type: enum
+ help: Select whether to power on in the event of a power failure
diff --git a/util/coreboot-configurator/src/application/qrc/star.svg b/util/coreboot-configurator/src/application/qrc/star.svg
new file mode 100644
index 0000000000..3bb9802ff5
--- /dev/null
+++ b/util/coreboot-configurator/src/application/qrc/star.svg
@@ -0,0 +1,391 @@
+
+
+
+
diff --git a/util/coreboot-configurator/src/application/qrc/toggle-off.svg b/util/coreboot-configurator/src/application/qrc/toggle-off.svg
new file mode 100644
index 0000000000..504ea58c5f
--- /dev/null
+++ b/util/coreboot-configurator/src/application/qrc/toggle-off.svg
@@ -0,0 +1,4 @@
+
diff --git a/util/coreboot-configurator/src/application/qrc/toggle-on.svg b/util/coreboot-configurator/src/application/qrc/toggle-on.svg
new file mode 100644
index 0000000000..0b8e61848c
--- /dev/null
+++ b/util/coreboot-configurator/src/application/qrc/toggle-on.svg
@@ -0,0 +1,65 @@
+
+
diff --git a/util/coreboot-configurator/src/application/resources.qrc b/util/coreboot-configurator/src/application/resources.qrc
new file mode 100644
index 0000000000..06264d63d1
--- /dev/null
+++ b/util/coreboot-configurator/src/application/resources.qrc
@@ -0,0 +1,12 @@
+
+
+ qrc/toggle-off.svg
+ qrc/toggle-on.svg
+
+
+ qrc/categories.yaml
+
+
+ qrc/star.svg
+
+
diff --git a/util/coreboot-configurator/src/meson.build b/util/coreboot-configurator/src/meson.build
new file mode 100644
index 0000000000..cb73f0818b
--- /dev/null
+++ b/util/coreboot-configurator/src/meson.build
@@ -0,0 +1,4 @@
+## SPDX-License-Identifier: GPL-2.0-only
+
+subdir('application')
+subdir('resources')
diff --git a/util/coreboot-configurator/src/resources/coreboot-configurator.desktop b/util/coreboot-configurator/src/resources/coreboot-configurator.desktop
new file mode 100644
index 0000000000..5f17d000e4
--- /dev/null
+++ b/util/coreboot-configurator/src/resources/coreboot-configurator.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=coreboot configurator
+StartupWMCLass=coreboot_configurator
+Exec=/usr/bin/coreboot-configurator
+Icon=coreboot-configurator.png
+Type=Application
+Categories=Settings;System
+Comment=A graphical interface to set options on devices with coreboot firmware.
+Keywords=coreboot;BIOS;Firmware;uefi;
diff --git a/util/coreboot-configurator/src/resources/coreboot_configurator.svg b/util/coreboot-configurator/src/resources/coreboot_configurator.svg
new file mode 100644
index 0000000000..33a7229891
--- /dev/null
+++ b/util/coreboot-configurator/src/resources/coreboot_configurator.svg
@@ -0,0 +1,748 @@
+
+
diff --git a/util/coreboot-configurator/src/resources/meson.build b/util/coreboot-configurator/src/resources/meson.build
new file mode 100644
index 0000000000..12270ab14e
--- /dev/null
+++ b/util/coreboot-configurator/src/resources/meson.build
@@ -0,0 +1,43 @@
+## SPDX-License-Identifier: GPL-2.0-only
+
+# Polkit Files
+polkit_dir = join_paths(get_option('datadir'), 'polkit-1', 'actions')
+polkit_sources = [
+ 'org.coreboot.nvramtool.policy',
+ 'org.coreboot.reboot.policy',
+]
+
+install_data(polkit_sources,
+ install_dir: polkit_dir)
+
+# Desktop Entry
+desktop_dir = join_paths(get_option('datadir'), 'applications')
+desktop_sources = [
+ 'coreboot-configurator.desktop',
+]
+
+install_data(desktop_sources,
+ install_dir: desktop_dir)
+
+# Icon
+inkscape = find_program('inkscape')
+icon_dir = join_paths(get_option('datadir'),'icons', 'hicolor')
+foreach size: get_option('sizes')
+ target_temp_name = '@0@'.format(size)
+ dpi=size.to_int() * 2
+ png = configure_file(
+ input: 'coreboot_configurator.svg',
+ output: target_temp_name + '.png',
+ command: [
+ inkscape,
+ '--export-height=@0@'.format(size),
+ '--export-width=@0@'.format(size),
+ '--export-png=@OUTPUT@',
+ '@INPUT@',
+ ]
+ )
+
+ install_data(png,
+ rename: meson.project_name() + '.png',
+ install_dir: join_paths(icon_dir, '@0@x@1@'.format(size, size), 'apps'))
+endforeach
diff --git a/util/coreboot-configurator/src/resources/org.coreboot.nvramtool.policy b/util/coreboot-configurator/src/resources/org.coreboot.nvramtool.policy
new file mode 100644
index 0000000000..c95bc8b9a3
--- /dev/null
+++ b/util/coreboot-configurator/src/resources/org.coreboot.nvramtool.policy
@@ -0,0 +1,13 @@
+
+
+
+
+ Authentication is required to read and write to coreboot settings.
+
+ auth_admin_keep
+
+ /usr/sbin/nvramtool
+
+
diff --git a/util/coreboot-configurator/src/resources/org.coreboot.reboot.policy b/util/coreboot-configurator/src/resources/org.coreboot.reboot.policy
new file mode 100644
index 0000000000..5364c8c22c
--- /dev/null
+++ b/util/coreboot-configurator/src/resources/org.coreboot.reboot.policy
@@ -0,0 +1,12 @@
+
+
+
+
+
+ yes
+
+ /usr/sbin/reboot
+
+