x86_64: set reset vector when using bios

BIOS expect all the cpus to be pointed at the i386 reset vector before
boot. We can't guarantee that a fresh vcpu will be pointed to the reset
vector by default, so we should set the reset vector when we're
configuring the vcpu when we're using a BIOS.

Cherrypick from downstream branch.
Actual author: Colin Downs-Razouk <colindr@google.com>.

TEST=builds
BUG=b:213152505

Change-Id: Idf4e0a200c8141adf5cbb83856cbd57362d84716
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3657811
Reviewed-by: Colin Downs-Razouk <colindr@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Noah Gold <nkgold@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index 2fe9ad7..db941e1 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -777,6 +777,7 @@
         }
 
         if has_bios {
+            regs::set_reset_vector(vcpu).map_err(Error::SetupRegs)?;
             return Ok(());
         }
 
diff --git a/x86_64/src/regs.rs b/x86_64/src/regs.rs
index 82df5d9..7c950ad 100644
--- a/x86_64/src/regs.rs
+++ b/x86_64/src/regs.rs
@@ -21,6 +21,9 @@
     /// Failed to get sregs for this cpu.
     #[error("failed to get sregs for this cpu: {0}")]
     GetSRegsIoctlFailed(base::Error),
+    /// Failed to get base registers for this cpu.
+    #[error("failed to get base registers for this cpu: {0}")]
+    GettingRegistersIoctl(base::Error),
     /// Setting up msrs failed.
     #[error("setting up msrs failed: {0}")]
     MsrIoctlFailed(base::Error),
@@ -349,6 +352,31 @@
     Ok(())
 }
 
+/// Configures a CPU to be pointed at the i386 reset vector.
+///
+/// The reset vector is the default location a CPU will go to find the first instruction it will
+/// execute after a reset. On i386, the reset vector means the RIP is set to 0xfff0 the CS base is
+/// set to 0xffff0000, and the CS selector is set to 0xf000.
+///
+/// When using a BIOS, each of the VCPUs should be pointed at the reset vector before execution
+/// begins.
+///
+/// # Arguments
+/// * `vcpu` - the VCPU to configure.
+pub fn set_reset_vector(vcpu: &dyn VcpuX86_64) -> Result<()> {
+    let mut sregs = vcpu.get_sregs().map_err(Error::GetSRegsIoctlFailed)?;
+    let mut regs = vcpu.get_regs().map_err(Error::GettingRegistersIoctl)?;
+
+    regs.rip = 0xfff0;
+    sregs.cs.base = 0xffff0000;
+    sregs.cs.selector = 0xf000;
+
+    vcpu.set_sregs(&sregs).map_err(Error::SetSRegsIoctlFailed)?;
+    vcpu.set_regs(&regs).map_err(Error::SettingRegistersIoctl)?;
+
+    Ok(())
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;