build: Add meson build

Changes to note,
- `with_systemdsystemunitdir` and `with_tmpfilesdir` is removed since it
  is not being documented nor used in OpenBMC.
- Removed the Code coverage feature with `-DDHAVE_GCOV`, since it is not
  used and meson covers it.
- Removed `--enable-oe-sdk` for using the OpenBMC SDK. It should work
  directly with no change required.

Tested:
```
Jan 01 00:01:54 ipmid[709]: Try loading blob from persistent data
Jan 01 00:01:54 ipmid[709]: Stale blob data, resetting internals...
Jan 01 00:01:56 ipmid[709]: config loaded: /flash/bios
Jan 01 00:01:56 ipmid[709]: config loaded: /flash/image
Jan 01 00:01:56 ipmid[709]: config loaded: /flash/dummy
...
```

```
$ ls /usr/lib/blob-ipmid/
libfirmwareblob.so
libfirmwarecleanupblob.so  libversionblob.so
```

Testing the service,
```
$ echo "hello" > /tmp/test.txt
$ burn_my_bmc -command update -layout dummy -image /tmp/test.txt
Sending over the firmware image.
Opening the verification file
Committing to /flash/verify to trigger service
Calling stat on /flash/verify session to check status
running
success
Returned success
succeeded
```

On the BMC.
```
/run/initramfs$ cat dummy
hello
```

Change-Id: I21c7c33bd62c0ee40681cb40da90125c125bea2f
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/.gitignore b/.gitignore
index 9cb1b4c..25427d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,7 @@
 
 # Output binaries
 burn_my_bmc
+
+# Meson Outputs
+/build*/
+/subprojects/*/
diff --git a/bmc/firmware-handler/meson.build b/bmc/firmware-handler/meson.build
new file mode 100644
index 0000000..7d6b719
--- /dev/null
+++ b/bmc/firmware-handler/meson.build
@@ -0,0 +1,126 @@
+firmware_inc = include_directories('.')
+
+# phosphor-ipmi-flash config
+config_data = []
+if get_option('update-type') == 'static-layout'
+  if get_option('reboot-update')
+    config_data += 'config-static-bmc-reboot.json'
+  else
+    if get_option('update-status')
+      config_data += 'config-static-bmc-with-update-status.json'
+    else
+      config_data += 'config-static-bmc.json'
+    endif
+  endif
+endif
+
+if get_option('host-bios')
+  config_data += 'config-bios.json'
+endif
+
+foreach data : config_data
+  configure_file(
+    input: data + '.in',
+    output: data,
+    configuration: conf_data,
+    install: true,
+    install_dir: get_option('datadir') / 'phosphor-ipmi-flash')
+endforeach
+
+# temp files
+install_data(
+  'phosphor-ipmi-flash.conf',
+  install_dir: get_option('libdir') / 'tmpfiles.d')
+
+# systemd configs
+systemd_data = [
+  'phosphor-ipmi-flash-bmc-prepare.target',
+  'phosphor-ipmi-flash-bmc-verify.target',
+  'phosphor-ipmi-flash-bmc-update.target',
+]
+
+if get_option('host-bios')
+  systemd_data += [
+    'phosphor-ipmi-flash-bios-prepare.target',
+    'phosphor-ipmi-flash-bios-verify.target',
+    'phosphor-ipmi-flash-bios-update.target']
+endif
+
+systemd = dependency('systemd')
+if systemd.found()
+  foreach data : systemd_data
+    configure_file(
+      input: data + '.in',
+      output: data,
+      configuration: conf_data,
+      install: true,
+      install_dir: systemd.get_variable(pkgconfig: 'systemdsystemunitdir'))
+  endforeach
+endif
+
+firmware_source = [
+  'firmware_handlers_builder.cpp',
+  'firmware_handler.cpp',
+  'lpc_handler.cpp']
+
+if (get_option('lpc-type') == 'aspeed-lpc' or
+    not get_option('tests').disabled())
+  firmware_source += 'lpc_aspeed.cpp'
+endif
+
+if (get_option('lpc-type') == 'nuvoton-lpc' or
+    not get_option('tests').disabled())
+  firmware_source += 'lpc_nuvoton.cpp'
+endif
+
+if (get_option('p2a-type') == 'aspeed-p2a' or
+    not get_option('tests').disabled())
+  firmware_source += 'pci_handler.cpp'
+endif
+
+if get_option('p2a-type') == 'nuvoton-p2a-vga'
+  firmware_source += 'pci_nuvoton_handler.cpp'
+endif
+
+if get_option('p2a-type') == 'nuvoton-p2a-mbox'
+  firmware_source += 'pci_nuvoton_handler.cpp'
+endif
+
+if get_option('net-bridge')
+  firmware_source += 'net_handler.cpp'
+endif
+
+firmware_pre = declare_dependency(
+  include_directories: [root_inc, bmc_inc, firmware_inc],
+  dependencies : [
+    dependency('sdbusplus', fallback: ['sdbusplus', 'sdbusplus_dep']),
+    common_dep,
+    blobs_dep,
+    sys_dep,
+    phosphor_logging_dep])
+
+firmware_lib = static_library(
+  'firmwareblob',
+  firmware_source,
+  conf_h,
+  implicit_include_directories: false,
+  dependencies: firmware_pre)
+
+firmware_dep = declare_dependency(
+  link_with: firmware_lib,
+  dependencies: firmware_pre)
+
+shared_module(
+  'firmwareblob',
+  'main.cpp',
+  implicit_include_directories: false,
+  dependencies: [
+    firmware_dep,
+    dependency('libipmid'),
+  ],
+  install: true,
+  install_dir: get_option('libdir') / 'blob-ipmid')
+
+if not get_option('tests').disabled()
+  subdir('test')
+endif
\ No newline at end of file
diff --git a/bmc/firmware-handler/test/meson.build b/bmc/firmware-handler/test/meson.build
new file mode 100644
index 0000000..38a8a1c
--- /dev/null
+++ b/bmc/firmware-handler/test/meson.build
@@ -0,0 +1,42 @@
+firmware_tests = [
+  'handler',
+  'stat',
+  'canhandle',
+  'write',
+  'writemeta',
+  'open',
+  'close',
+  'sessionstat',
+  'commit',
+  'state_notyetstarted',
+  'state_uploadinprogress',
+  'state_verificationpending',
+  'state_verificationstarted',
+  'state_verificationcompleted',
+  'state_updatepending',
+  'state_updatestarted',
+  'state_updatecompleted',
+  'state_notyetstarted_tarball',
+  'multiplebundle',
+  'json',
+  'skip']
+
+foreach t : firmware_tests
+  test(
+    t,
+    executable(
+      t.underscorify(), 'firmware_' + t + '_unittest.cpp',
+      build_by_default: false,
+      implicit_include_directories: false,
+      include_directories: [root_inc, bmc_test_inc, firmware_inc],
+      dependencies: [firmware_dep, gtest, gmock]))
+endforeach
+
+file_handler_test = executable(
+  'file_handler',
+  'file_handler_unittest.cpp',
+  build_by_default: false,
+  implicit_include_directories: false,
+  include_directories: [root_inc, bmc_inc, bmc_test_inc, firmware_inc],
+  dependencies: [common_dep, blobs_dep, gtest, gmock])
+test('file_handler', file_handler_test)
diff --git a/bmc/meson.build b/bmc/meson.build
new file mode 100644
index 0000000..0ccd3c2
--- /dev/null
+++ b/bmc/meson.build
@@ -0,0 +1,25 @@
+bmc_inc = include_directories('.')
+
+common_pre = declare_dependency(
+  include_directories: [root_inc, bmc_inc])
+
+common_lib = static_library(
+  'common',
+  'buildjson.cpp',
+  'file_handler.cpp',
+  'fs.cpp',
+  'general_systemd.cpp',
+  'skip_action.cpp',
+  implicit_include_directories: false,
+  dependencies: common_pre)
+
+common_dep = declare_dependency(
+  link_with: common_lib,
+  dependencies: common_pre)
+
+if not get_option('tests').disabled()
+  subdir('test')
+endif
+
+subdir('firmware-handler')
+subdir('version-handler')
\ No newline at end of file
diff --git a/bmc/test/meson.build b/bmc/test/meson.build
new file mode 100644
index 0000000..c579ec8
--- /dev/null
+++ b/bmc/test/meson.build
@@ -0,0 +1 @@
+bmc_test_inc = include_directories('.')
diff --git a/bmc/version-handler/meson.build b/bmc/version-handler/meson.build
new file mode 100644
index 0000000..f5b4694
--- /dev/null
+++ b/bmc/version-handler/meson.build
@@ -0,0 +1,35 @@
+version_inc = include_directories('.')
+
+version_pre = declare_dependency(
+  include_directories: [root_inc, version_inc],
+  dependencies : [
+    common_dep,
+    firmware_dep,
+  ])
+
+version_lib = static_library(
+  'versionblob',
+  'version_handler.cpp',
+  'version_handlers_builder.cpp',
+  implicit_include_directories: false,
+  dependencies: version_pre)
+
+
+version_dep = declare_dependency(
+  link_with: version_lib,
+  dependencies: common_pre)
+
+shared_module(
+  'versionblob',
+  'main.cpp',
+  implicit_include_directories: false,
+  dependencies: [
+    version_dep,
+    dependency('libipmid'),
+  ],
+  install: true,
+  install_dir: get_option('libdir') / 'blob-ipmid')
+
+if not get_option('tests').disabled()
+  subdir('test')
+endif
\ No newline at end of file
diff --git a/bmc/version-handler/test/meson.build b/bmc/version-handler/test/meson.build
new file mode 100644
index 0000000..4c12464
--- /dev/null
+++ b/bmc/version-handler/test/meson.build
@@ -0,0 +1,19 @@
+version_tests = [
+  'json',
+  'canhandle_enumerate',
+  'createhandler',
+  'open',
+  'close',
+  'read',
+  'stat']
+
+foreach t : version_tests
+  test(
+    t,
+    executable(
+      t.underscorify(), 'version_' + t + '_unittest.cpp',
+      build_by_default: false,
+      implicit_include_directories: false,
+      include_directories: [root_inc, bmc_test_inc, version_inc],
+      dependencies: [version_dep, blobs_dep, gtest, gmock]))
+endforeach
diff --git a/cleanup/meson.build b/cleanup/meson.build
new file mode 100644
index 0000000..fa053a0
--- /dev/null
+++ b/cleanup/meson.build
@@ -0,0 +1,32 @@
+cleanup_pre = declare_dependency(
+  include_directories: [root_inc, include_directories('.')],
+  dependencies : [
+    blobs_dep,
+    phosphor_logging_dep])
+
+cleanup_lib = static_library(
+  'firmwarecleanupblob',
+  'cleanup.cpp',
+  'fs.cpp',
+  conf_h,
+  implicit_include_directories: false,
+  dependencies: cleanup_pre)
+
+cleanup_dep = declare_dependency(
+  link_with: cleanup_lib,
+  dependencies: cleanup_pre)
+
+shared_module(
+  'firmwarecleanupblob',
+  'main.cpp',
+  implicit_include_directories: false,
+  dependencies: [
+    cleanup_dep,
+    dependency('libipmid'),
+  ],
+  install: true,
+  install_dir: get_option('libdir') / 'blob-ipmid')
+
+if not get_option('tests').disabled()
+  subdir('test')
+endif
diff --git a/cleanup/test/meson.build b/cleanup/test/meson.build
new file mode 100644
index 0000000..3a7111d
--- /dev/null
+++ b/cleanup/test/meson.build
@@ -0,0 +1,8 @@
+cleanup_test = executable(
+  'cleanup',
+  'cleanup_handler_unittest.cpp',
+  build_by_default: false,
+  implicit_include_directories: false,
+  include_directories: root_inc,
+  dependencies: [cleanup_dep, gtest, gmock])
+test('cleanup', cleanup_test)
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..0246aa2
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,169 @@
+project(
+  'phosphor-ipmi-flash',
+  'cpp',
+  version: '0.1',
+  meson_version: '>=0.57.0',
+  default_options: [
+    'cpp_std=c++20',
+    'warning_level=3',
+    'werror=true',
+  ])
+
+root_inc = include_directories('.')
+
+# Setting up config data
+conf_data = configuration_data()
+conf_data.set_quoted('STATIC_HANDLER_STAGED_NAME', get_option('static-handler-staged-name'))
+conf_data.set_quoted('PREPARATION_DBUS_SERVICE', get_option('preparation-dbus-service'))
+conf_data.set_quoted('VERIFY_DBUS_SERVICE', get_option('verify-dbus-service'))
+conf_data.set_quoted('UPDATE_DBUS_SERVICE', get_option('update-dbus-service'))
+conf_data.set_quoted('BIOS_STAGED_NAME', get_option('bios-staged-name'))
+conf_data.set_quoted('PREPARATION_BIOS_TARGET', get_option('preparation-bios-target'))
+conf_data.set_quoted('VERIFY_BIOS_TARGET', get_option('verify-bios-target'))
+conf_data.set_quoted('UPDATE_BIOS_TARGET', get_option('update-bios-target'))
+
+conf_data.set_quoted('TARBALL_STAGED_NAME', get_option('tarball-staged-name'))
+conf_data.set_quoted('HASH_FILENAME', get_option('hash-filename'))
+conf_data.set_quoted('VERIFY_STATUS_FILENAME', get_option('verify-status-filename'))
+conf_data.set_quoted('UPDATE_STATUS_FILENAME', get_option('update-status-filename'))
+conf_data.set_quoted('BIOS_VERIFY_STATUS_FILENAME', get_option('bios-verify-status-filename'))
+conf_data.set('MAPPED_ADDRESS', get_option('mapped-address'))
+
+
+conf_h = configure_file(
+  output: 'config.h',
+  configuration: conf_data)
+
+# Setup for the test config
+if not get_option('tests').disabled()
+  add_project_arguments('-DENABLE_STATIC_LAYOUT', language: 'cpp')
+  add_project_arguments('-DENABLE_TARBALL_UBI', language: 'cpp')
+  add_project_arguments('-DASPEED_P2A', language: 'cpp')
+  add_project_arguments('-DENABLE_PCI_BRIDGE', language: 'cpp')
+  add_project_arguments('-DASPEED_LPC', language: 'cpp')
+  add_project_arguments('-DNUVOTON_LPC', language: 'cpp')
+  add_project_arguments('-DENABLE_LPC_BRIDGE', language: 'cpp')
+  add_project_arguments('-DENABLE_HOST_BIOS', language: 'cpp')
+endif
+
+if get_option('lpc-type') != 'none'
+  add_project_arguments('-DENABLE_LPC_BRIDGE', language: 'cpp')
+endif
+
+# Enable LPC and PCI for tests only.
+assert(
+  not get_option('tests').disabled() \
+    or get_option('lpc-type') == 'none' \
+    or get_option('p2a-type') == 'none',
+  'Invalid configuration enabling both PCI and LPC.')
+
+if get_option('p2a-type') != 'none'
+  add_project_arguments('-DENABLE_PCI_BRIDGE', language: 'cpp')
+endif
+
+feature_map = {
+  'host-bios'        : '-DENABLE_HOST_BIOS',
+  'ppc'              : '-DENABLE_PPC',
+  'reboot-update'    : '-DENABLE_REBOOT_UPDATE',
+  'update-status'    : '-DENABLE_UPDATE_STATUS',
+  'net-bridge'       : '-DENABLE_NET_BRIDGE',
+}
+
+# Get the options status and build a project summary to show which flags are
+# being enabled during the configuration time.
+
+foreach option_key, option_value : feature_map
+  if get_option(option_key)
+    add_project_arguments(option_value, language: 'cpp')
+    summary(option_key, option_value, section : 'Enabled Features')
+  endif
+endforeach
+
+
+update_type_combo_map = {
+  'static-layout'    : '-DENABLE_STATIC_LAYOUT',
+  'tarball-ubi'      : '-DENABLE_TARBALL_UBI',
+}
+
+foreach option_key, option_value : update_type_combo_map
+  if get_option('update-type') == option_key
+    add_project_arguments(option_value, language: 'cpp')
+    summary(option_key, option_value, section : 'Enabled Firmware Update Features')
+  endif
+endforeach
+
+lpc_type_combo_map = {
+  'aspeed-lpc'       : '-DASPEED_LPC',
+  'nuvoton-lpc'      : '-DASPEED_LPC',
+}
+
+foreach option_key, option_value : lpc_type_combo_map
+  if get_option('lpc-type') == option_key
+    add_project_arguments(option_value, language: 'cpp')
+    summary(option_key, option_value, section : 'Enabled LPC Features')
+  endif
+endforeach
+
+pci_type_combo_map = {
+  'aspeed-p2a'       : '-DASPEED_P2A',
+  'nuvoton-p2a-vga'  : '-DNUVOTON_P2A_VGA',
+  'nuvoton-p2a-mbox' : '-DNUVOTON_P2A_MBOX',
+}
+
+foreach option_key, option_value : pci_type_combo_map
+  if get_option('p2a-type') == option_key
+    add_project_arguments(option_value, language: 'cpp')
+    summary(option_key, option_value, section : 'Enabled PCI Features')
+  endif
+endforeach
+
+
+sys_lib = static_library(
+  'sys',
+  'internal/sys.cpp',
+  implicit_include_directories: false)
+
+sys_dep = declare_dependency(
+  link_with: sys_lib)
+
+phosphor_logging_dep = dependency(
+  'phosphor-logging',
+  fallback : [
+    'phosphor-logging',
+    'phosphor_logging_dep'])
+
+blobs_dep = dependency('phosphor-ipmi-blobs')
+
+if not get_option('tests').disabled()
+  gtest = dependency('gtest', main: true, disabler: true, required: false)
+  gmock = dependency('gmock', disabler: true, required: false)
+  if not gtest.found() or not gmock.found()
+    gtest_opt = import('cmake').subproject_options()
+    gtest_opt.append_compile_args('c++', ['-DCMAKE_CXX_FLAGS=-Wno-pedantic'])
+    gtest_proj = cmake.subproject('googletest', options: gtest_opt, required: false)
+    fmt_depj.dependency('fmt')
+
+    if gtest_proj.found()
+      gtest = declare_dependency(
+        dependencies: [
+          dependency('threads'),
+          gtest_proj.dependency('gtest'),
+          gtest_proj.dependency('gtest_main'),
+        ])
+      gmock = gtest_proj.dependency('gmock')
+    endif
+  endif
+endif
+
+
+if not get_option('bmc-blob-handler').disabled()
+  subdir('bmc')
+endif
+
+if not get_option('host-tool').disabled()
+  subdir('tools')
+endif
+
+if not get_option('cleanup-delete').disabled()
+  subdir('cleanup')
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..c348409
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,43 @@
+option('tests', type: 'feature', description: 'Build tests')
+
+# Build Options
+option('bmc-blob-handler', type: 'feature', description: 'Build the BMC BLOB handler')
+option('cleanup-delete', type: 'feature', description: 'Enable use of the delete files cleanup mechanism')
+option('host-tool', type: 'feature', description: 'Build the host tool')
+
+# BMC Blob Handler Options
+option('host-bios', type: 'boolean', value: false, description: 'Install default BIOS update configs')
+option('reboot-update', type: 'boolean', value: false, description: 'Enable use of reboot update mechanism')
+option('update-status', type: 'boolean', value: false, description: 'Enable use of update status file')
+
+option('update-type', type : 'combo', choices : ['none', 'static-layout', 'tarball-ubi'], description: 'Enable firmware update via Blobs')
+
+option('lpc-type', type : 'combo', choices : ['none', 'aspeed-lpc', 'nuvoton-lpc'], description: 'Enable external transfers using Aspeed/Nuvoton LPC')
+option('p2a-type', type : 'combo', choices : ['none', 'aspeed-p2a', 'nuvoton-p2a-vga', 'nuvoton-p2a-mbox'], description: 'Enable external transfers using Aspeed PCI-to-AHB, Nuvoton PCI-to-AHB via VGA, or Nuvoton PCI-to-AHB via MBOX')
+option('net-bridge', type: 'boolean', value: false, description: 'Enable external transfers using a TCP connection')
+
+# Host Tool Options
+option('ppc', type: 'boolean', value: false, description: 'Enable ppc host memory access')
+
+# Configuration Details
+
+# The address used for mapping P2A or LPC into the BMC's memory-space:
+# e.g. https://github.com/openbmc/linux/blob/1da2ce51886a3b2f5db2087f26c661e13ee13b84/arch/arm/boot/dts/aspeed-bmc-quanta-q71l.dts#L26
+# or https://github.com/openbmc/linux/blob/1da2ce51886a3b2f5db2087f26c661e13ee13b84/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts#L166
+# for PCI, this address is passed back to the host and is used directly.
+option('mapped-address', type : 'string', value : '0', description : 'Value for memory region mapping')
+
+option('static-handler-staged-name', type : 'string', value : '/run/initramfs/bmc-image', description : 'The file to use for staging the firmware update')
+option('tarball-staged-name', type : 'string', value : '/tmp/image-update.tar', description : 'The file to use for staging the firmware update')
+option('hash-filename', type : 'string', value : '/tmp/bmc.sig', description : 'The file to use for the hash provided')
+option('verify-status-filename', type : 'string', value : '/tmp/bmc.verify', description : 'The file checked for the verification status.')
+option('update-status-filename', type : 'string', value : '/tmp/bmc.update', description : 'The file checked for the update status')
+option('bios-verify-status-filename', type : 'string', value : '/tmp/bios.verify', description : 'The file checked for the verification status')
+
+option('preparation-dbus-service', type : 'string', value : 'phosphor-ipmi-flash-bmc-prepare.target', description : 'The systemd target started when the host starts to send an update')
+option('verify-dbus-service', type : 'string', value : 'phosphor-ipmi-flash-bmc-verify.target', description : 'The systemd target started for verification')
+option('update-dbus-service', type : 'string', value : 'phosphor-ipmi-flash-bmc-update.target', description : 'The systemd target started for updating the BMC')
+option('bios-staged-name', type : 'string', value : 'bios-staged-name', description : 'The file to use for staging the bios firmware update')
+option('preparation-bios-target', type : 'string', value : 'phosphor-ipmi-flash-bios-prepare.target', description : 'The systemd target started when the host starts to send an update')
+option('verify-bios-target', type : 'string', value : 'phosphor-ipmi-flash-bios-verify.target', description : 'The systemd target started for verifying the BIOS image')
+option('update-bios-target', type : 'string', value : 'phosphor-ipmi-flash-bios-update.target', description : 'The systemd target started for updating the BIOS')
\ No newline at end of file
diff --git a/subprojects/fmt.wrap b/subprojects/fmt.wrap
new file mode 100644
index 0000000..6847ae5
--- /dev/null
+++ b/subprojects/fmt.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/fmtlib/fmt
+revision = HEAD
diff --git a/subprojects/googletest.wrap b/subprojects/googletest.wrap
new file mode 100644
index 0000000..56da9ef
--- /dev/null
+++ b/subprojects/googletest.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/google/googletest
+revision = HEAD
diff --git a/subprojects/pciaccess.wrap b/subprojects/pciaccess.wrap
new file mode 100644
index 0000000..33e2fd4
--- /dev/null
+++ b/subprojects/pciaccess.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://gitlab.freedesktop.org/xorg/lib/libpciaccess
+revision = HEAD
diff --git a/subprojects/phosphor-dbus-interfaces.wrap b/subprojects/phosphor-dbus-interfaces.wrap
new file mode 100644
index 0000000..935a8b2
--- /dev/null
+++ b/subprojects/phosphor-dbus-interfaces.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/openbmc/phosphor-dbus-interfaces.git
+revision = HEAD
diff --git a/subprojects/phosphor-ipmi-blobs.wrap b/subprojects/phosphor-ipmi-blobs.wrap
new file mode 100644
index 0000000..1be7719
--- /dev/null
+++ b/subprojects/phosphor-ipmi-blobs.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/openbmc/phosphor-ipmi-blobs
+revision = HEAD
diff --git a/subprojects/phosphor-logging.wrap b/subprojects/phosphor-logging.wrap
new file mode 100644
index 0000000..2847cc8
--- /dev/null
+++ b/subprojects/phosphor-logging.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/openbmc/phosphor-logging
+revision = HEAD
\ No newline at end of file
diff --git a/subprojects/sdbusplus.wrap b/subprojects/sdbusplus.wrap
new file mode 100644
index 0000000..7f736e7
--- /dev/null
+++ b/subprojects/sdbusplus.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/openbmc/sdbusplus
+revision = HEAD
diff --git a/subprojects/stdplus.wrap b/subprojects/stdplus.wrap
new file mode 100644
index 0000000..00dae65
--- /dev/null
+++ b/subprojects/stdplus.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/openbmc/stdplus
+revision = HEAD
diff --git a/tools/meson.build b/tools/meson.build
new file mode 100644
index 0000000..826d04c
--- /dev/null
+++ b/tools/meson.build
@@ -0,0 +1,42 @@
+tools_inc = include_directories('.')
+
+updater_pre = [
+  dependency('ipmiblob'),
+  dependency('pciaccess', fallback: ['pciaccess', 'dep_pciaccess']),
+  dependency('stdplus', fallback: ['stdplus', 'stdplus_dep']),
+  blobs_dep,
+  sys_dep]
+
+updater_lib = static_library(
+  'updater_lib',
+  'updater.cpp',
+  'handler.cpp',
+  'helper.cpp',
+  'bt.cpp',
+  'lpc.cpp',
+  'io.cpp',
+  'net.cpp',
+  'pci.cpp',
+  'pciaccess.cpp',
+  'p2a.cpp',
+  'progress.cpp',
+  dependencies: updater_pre,
+  include_directories: root_inc)
+
+updater_dep = declare_dependency(
+  dependencies: updater_pre,
+  include_directories: root_inc,
+  link_with: updater_lib)
+
+executable(
+  'burn_my_bmc',
+  'main.cpp',
+  implicit_include_directories: false,
+  dependencies: updater_dep,
+  include_directories: root_inc,
+  install: true,
+  install_dir: get_option('bindir'))
+
+if not get_option('tests').disabled()
+  subdir('test')
+endif
diff --git a/tools/test/meson.build b/tools/test/meson.build
new file mode 100644
index 0000000..99aab7a
--- /dev/null
+++ b/tools/test/meson.build
@@ -0,0 +1,20 @@
+tool_tests = [
+  'tools_bt',
+  'tools_lpc',
+  'tools_pci',
+  'tools_net',
+  'tools_updater',
+  'tools_helper',
+  'io',
+]
+
+foreach t : tool_tests
+  test(
+    t,
+    executable(
+      t.underscorify(), t + '_unittest.cpp',
+      build_by_default: false,
+      implicit_include_directories: false,
+      include_directories: [root_inc, tools_inc],
+      dependencies: [updater_dep, gtest, gmock]))
+endforeach