xref: /aosp_15_r20/external/crosvm/x86_64/src/gdb.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2024 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! x86 architecture gdb debugging support.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use gdbstub_arch::x86::reg::id::X86_64CoreRegId;
8*bb4ee6a4SAndroid Build Coastguard Worker use gdbstub_arch::x86::reg::X86SegmentRegs;
9*bb4ee6a4SAndroid Build Coastguard Worker use gdbstub_arch::x86::reg::X86_64CoreRegs;
10*bb4ee6a4SAndroid Build Coastguard Worker use gdbstub_arch::x86::reg::X87FpuInternalRegs;
11*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::x86_64::Regs;
12*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::x86_64::Sregs;
13*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::VcpuX86_64;
14*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
15*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
16*bb4ee6a4SAndroid Build Coastguard Worker 
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::Error;
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::Result;
19*bb4ee6a4SAndroid Build Coastguard Worker use crate::X8664arch;
20*bb4ee6a4SAndroid Build Coastguard Worker 
21*bb4ee6a4SAndroid Build Coastguard Worker impl<T: VcpuX86_64> arch::GdbOps<T> for X8664arch {
22*bb4ee6a4SAndroid Build Coastguard Worker     type Error = Error;
23*bb4ee6a4SAndroid Build Coastguard Worker 
read_registers(vcpu: &T) -> Result<X86_64CoreRegs>24*bb4ee6a4SAndroid Build Coastguard Worker     fn read_registers(vcpu: &T) -> Result<X86_64CoreRegs> {
25*bb4ee6a4SAndroid Build Coastguard Worker         // General registers: RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, r8-r15
26*bb4ee6a4SAndroid Build Coastguard Worker         let gregs = vcpu.get_regs().map_err(Error::ReadRegs)?;
27*bb4ee6a4SAndroid Build Coastguard Worker         let regs = [
28*bb4ee6a4SAndroid Build Coastguard Worker             gregs.rax, gregs.rbx, gregs.rcx, gregs.rdx, gregs.rsi, gregs.rdi, gregs.rbp, gregs.rsp,
29*bb4ee6a4SAndroid Build Coastguard Worker             gregs.r8, gregs.r9, gregs.r10, gregs.r11, gregs.r12, gregs.r13, gregs.r14, gregs.r15,
30*bb4ee6a4SAndroid Build Coastguard Worker         ];
31*bb4ee6a4SAndroid Build Coastguard Worker 
32*bb4ee6a4SAndroid Build Coastguard Worker         // GDB exposes 32-bit eflags instead of 64-bit rflags.
33*bb4ee6a4SAndroid Build Coastguard Worker         // https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/64bit-core.xml
34*bb4ee6a4SAndroid Build Coastguard Worker         let eflags = gregs.rflags as u32;
35*bb4ee6a4SAndroid Build Coastguard Worker         let rip = gregs.rip;
36*bb4ee6a4SAndroid Build Coastguard Worker 
37*bb4ee6a4SAndroid Build Coastguard Worker         // Segment registers: CS, SS, DS, ES, FS, GS
38*bb4ee6a4SAndroid Build Coastguard Worker         let sregs = vcpu.get_sregs().map_err(Error::ReadRegs)?;
39*bb4ee6a4SAndroid Build Coastguard Worker         let segments = X86SegmentRegs {
40*bb4ee6a4SAndroid Build Coastguard Worker             cs: sregs.cs.selector as u32,
41*bb4ee6a4SAndroid Build Coastguard Worker             ss: sregs.ss.selector as u32,
42*bb4ee6a4SAndroid Build Coastguard Worker             ds: sregs.ds.selector as u32,
43*bb4ee6a4SAndroid Build Coastguard Worker             es: sregs.es.selector as u32,
44*bb4ee6a4SAndroid Build Coastguard Worker             fs: sregs.fs.selector as u32,
45*bb4ee6a4SAndroid Build Coastguard Worker             gs: sregs.gs.selector as u32,
46*bb4ee6a4SAndroid Build Coastguard Worker         };
47*bb4ee6a4SAndroid Build Coastguard Worker 
48*bb4ee6a4SAndroid Build Coastguard Worker         // x87 FPU internal state
49*bb4ee6a4SAndroid Build Coastguard Worker         // TODO(dverkamp): floating point tag word, instruction pointer, and data pointer
50*bb4ee6a4SAndroid Build Coastguard Worker         let fpu = vcpu.get_fpu().map_err(Error::ReadRegs)?;
51*bb4ee6a4SAndroid Build Coastguard Worker         let fpu_internal = X87FpuInternalRegs {
52*bb4ee6a4SAndroid Build Coastguard Worker             fctrl: u32::from(fpu.fcw),
53*bb4ee6a4SAndroid Build Coastguard Worker             fstat: u32::from(fpu.fsw),
54*bb4ee6a4SAndroid Build Coastguard Worker             fop: u32::from(fpu.last_opcode),
55*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
56*bb4ee6a4SAndroid Build Coastguard Worker         };
57*bb4ee6a4SAndroid Build Coastguard Worker 
58*bb4ee6a4SAndroid Build Coastguard Worker         let mut regs = X86_64CoreRegs {
59*bb4ee6a4SAndroid Build Coastguard Worker             regs,
60*bb4ee6a4SAndroid Build Coastguard Worker             eflags,
61*bb4ee6a4SAndroid Build Coastguard Worker             rip,
62*bb4ee6a4SAndroid Build Coastguard Worker             segments,
63*bb4ee6a4SAndroid Build Coastguard Worker             st: Default::default(),
64*bb4ee6a4SAndroid Build Coastguard Worker             fpu: fpu_internal,
65*bb4ee6a4SAndroid Build Coastguard Worker             xmm: Default::default(),
66*bb4ee6a4SAndroid Build Coastguard Worker             mxcsr: fpu.mxcsr,
67*bb4ee6a4SAndroid Build Coastguard Worker         };
68*bb4ee6a4SAndroid Build Coastguard Worker 
69*bb4ee6a4SAndroid Build Coastguard Worker         // x87 FPU registers: ST0-ST7
70*bb4ee6a4SAndroid Build Coastguard Worker         for (dst, src) in regs.st.iter_mut().zip(fpu.fpr.iter()) {
71*bb4ee6a4SAndroid Build Coastguard Worker             // `fpr` contains the x87 floating point registers in FXSAVE format.
72*bb4ee6a4SAndroid Build Coastguard Worker             // Each element contains an 80-bit floating point value.
73*bb4ee6a4SAndroid Build Coastguard Worker             *dst = (*src).into();
74*bb4ee6a4SAndroid Build Coastguard Worker         }
75*bb4ee6a4SAndroid Build Coastguard Worker 
76*bb4ee6a4SAndroid Build Coastguard Worker         // SSE registers: XMM0-XMM15
77*bb4ee6a4SAndroid Build Coastguard Worker         for (dst, src) in regs.xmm.iter_mut().zip(fpu.xmm.iter()) {
78*bb4ee6a4SAndroid Build Coastguard Worker             *dst = u128::from_le_bytes(*src);
79*bb4ee6a4SAndroid Build Coastguard Worker         }
80*bb4ee6a4SAndroid Build Coastguard Worker 
81*bb4ee6a4SAndroid Build Coastguard Worker         Ok(regs)
82*bb4ee6a4SAndroid Build Coastguard Worker     }
83*bb4ee6a4SAndroid Build Coastguard Worker 
write_registers(vcpu: &T, regs: &X86_64CoreRegs) -> Result<()>84*bb4ee6a4SAndroid Build Coastguard Worker     fn write_registers(vcpu: &T, regs: &X86_64CoreRegs) -> Result<()> {
85*bb4ee6a4SAndroid Build Coastguard Worker         // General purpose registers (RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, r8-r15) + RIP + rflags
86*bb4ee6a4SAndroid Build Coastguard Worker         let orig_gregs = vcpu.get_regs().map_err(Error::ReadRegs)?;
87*bb4ee6a4SAndroid Build Coastguard Worker         let gregs = Regs {
88*bb4ee6a4SAndroid Build Coastguard Worker             rax: regs.regs[0],
89*bb4ee6a4SAndroid Build Coastguard Worker             rbx: regs.regs[1],
90*bb4ee6a4SAndroid Build Coastguard Worker             rcx: regs.regs[2],
91*bb4ee6a4SAndroid Build Coastguard Worker             rdx: regs.regs[3],
92*bb4ee6a4SAndroid Build Coastguard Worker             rsi: regs.regs[4],
93*bb4ee6a4SAndroid Build Coastguard Worker             rdi: regs.regs[5],
94*bb4ee6a4SAndroid Build Coastguard Worker             rbp: regs.regs[6],
95*bb4ee6a4SAndroid Build Coastguard Worker             rsp: regs.regs[7],
96*bb4ee6a4SAndroid Build Coastguard Worker             r8: regs.regs[8],
97*bb4ee6a4SAndroid Build Coastguard Worker             r9: regs.regs[9],
98*bb4ee6a4SAndroid Build Coastguard Worker             r10: regs.regs[10],
99*bb4ee6a4SAndroid Build Coastguard Worker             r11: regs.regs[11],
100*bb4ee6a4SAndroid Build Coastguard Worker             r12: regs.regs[12],
101*bb4ee6a4SAndroid Build Coastguard Worker             r13: regs.regs[13],
102*bb4ee6a4SAndroid Build Coastguard Worker             r14: regs.regs[14],
103*bb4ee6a4SAndroid Build Coastguard Worker             r15: regs.regs[15],
104*bb4ee6a4SAndroid Build Coastguard Worker             rip: regs.rip,
105*bb4ee6a4SAndroid Build Coastguard Worker             // Update the lower 32 bits of rflags.
106*bb4ee6a4SAndroid Build Coastguard Worker             rflags: (orig_gregs.rflags & !(u32::MAX as u64)) | (regs.eflags as u64),
107*bb4ee6a4SAndroid Build Coastguard Worker         };
108*bb4ee6a4SAndroid Build Coastguard Worker         vcpu.set_regs(&gregs).map_err(Error::WriteRegs)?;
109*bb4ee6a4SAndroid Build Coastguard Worker 
110*bb4ee6a4SAndroid Build Coastguard Worker         // Segment registers: CS, SS, DS, ES, FS, GS
111*bb4ee6a4SAndroid Build Coastguard Worker         // Since GDB care only selectors, we call get_sregs() first.
112*bb4ee6a4SAndroid Build Coastguard Worker         let mut sregs = vcpu.get_sregs().map_err(Error::ReadRegs)?;
113*bb4ee6a4SAndroid Build Coastguard Worker         sregs.cs.selector = regs.segments.cs as u16;
114*bb4ee6a4SAndroid Build Coastguard Worker         sregs.ss.selector = regs.segments.ss as u16;
115*bb4ee6a4SAndroid Build Coastguard Worker         sregs.ds.selector = regs.segments.ds as u16;
116*bb4ee6a4SAndroid Build Coastguard Worker         sregs.es.selector = regs.segments.es as u16;
117*bb4ee6a4SAndroid Build Coastguard Worker         sregs.fs.selector = regs.segments.fs as u16;
118*bb4ee6a4SAndroid Build Coastguard Worker         sregs.gs.selector = regs.segments.gs as u16;
119*bb4ee6a4SAndroid Build Coastguard Worker 
120*bb4ee6a4SAndroid Build Coastguard Worker         vcpu.set_sregs(&sregs).map_err(Error::WriteRegs)?;
121*bb4ee6a4SAndroid Build Coastguard Worker 
122*bb4ee6a4SAndroid Build Coastguard Worker         // FPU and SSE registers
123*bb4ee6a4SAndroid Build Coastguard Worker         let mut fpu = vcpu.get_fpu().map_err(Error::ReadRegs)?;
124*bb4ee6a4SAndroid Build Coastguard Worker         fpu.fcw = regs.fpu.fctrl as u16;
125*bb4ee6a4SAndroid Build Coastguard Worker         fpu.fsw = regs.fpu.fstat as u16;
126*bb4ee6a4SAndroid Build Coastguard Worker         fpu.last_opcode = regs.fpu.fop as u16;
127*bb4ee6a4SAndroid Build Coastguard Worker         // TODO(dverkamp): floating point tag word, instruction pointer, and data pointer
128*bb4ee6a4SAndroid Build Coastguard Worker 
129*bb4ee6a4SAndroid Build Coastguard Worker         // x87 FPU registers: ST0-ST7
130*bb4ee6a4SAndroid Build Coastguard Worker         for (dst, src) in fpu.fpr.iter_mut().zip(regs.st.iter()) {
131*bb4ee6a4SAndroid Build Coastguard Worker             *dst = (*src).into();
132*bb4ee6a4SAndroid Build Coastguard Worker         }
133*bb4ee6a4SAndroid Build Coastguard Worker 
134*bb4ee6a4SAndroid Build Coastguard Worker         // SSE registers: XMM0-XMM15
135*bb4ee6a4SAndroid Build Coastguard Worker         for (dst, src) in fpu.xmm.iter_mut().zip(regs.xmm.iter()) {
136*bb4ee6a4SAndroid Build Coastguard Worker             dst.copy_from_slice(&src.to_le_bytes());
137*bb4ee6a4SAndroid Build Coastguard Worker         }
138*bb4ee6a4SAndroid Build Coastguard Worker 
139*bb4ee6a4SAndroid Build Coastguard Worker         vcpu.set_fpu(&fpu).map_err(Error::WriteRegs)?;
140*bb4ee6a4SAndroid Build Coastguard Worker 
141*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
142*bb4ee6a4SAndroid Build Coastguard Worker     }
143*bb4ee6a4SAndroid Build Coastguard Worker 
144*bb4ee6a4SAndroid Build Coastguard Worker     #[inline]
read_register(_vcpu: &T, _reg: X86_64CoreRegId) -> Result<Vec<u8>>145*bb4ee6a4SAndroid Build Coastguard Worker     fn read_register(_vcpu: &T, _reg: X86_64CoreRegId) -> Result<Vec<u8>> {
146*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::ReadRegIsUnsupported)
147*bb4ee6a4SAndroid Build Coastguard Worker     }
148*bb4ee6a4SAndroid Build Coastguard Worker 
149*bb4ee6a4SAndroid Build Coastguard Worker     #[inline]
write_register(_vcpu: &T, _reg: X86_64CoreRegId, _buf: &[u8]) -> Result<()>150*bb4ee6a4SAndroid Build Coastguard Worker     fn write_register(_vcpu: &T, _reg: X86_64CoreRegId, _buf: &[u8]) -> Result<()> {
151*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::WriteRegIsUnsupported)
152*bb4ee6a4SAndroid Build Coastguard Worker     }
153*bb4ee6a4SAndroid Build Coastguard Worker 
read_memory( vcpu: &T, guest_mem: &GuestMemory, vaddr: GuestAddress, len: usize, ) -> Result<Vec<u8>>154*bb4ee6a4SAndroid Build Coastguard Worker     fn read_memory(
155*bb4ee6a4SAndroid Build Coastguard Worker         vcpu: &T,
156*bb4ee6a4SAndroid Build Coastguard Worker         guest_mem: &GuestMemory,
157*bb4ee6a4SAndroid Build Coastguard Worker         vaddr: GuestAddress,
158*bb4ee6a4SAndroid Build Coastguard Worker         len: usize,
159*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Vec<u8>> {
160*bb4ee6a4SAndroid Build Coastguard Worker         let sregs = vcpu.get_sregs().map_err(Error::ReadRegs)?;
161*bb4ee6a4SAndroid Build Coastguard Worker         let mut buf = vec![0; len];
162*bb4ee6a4SAndroid Build Coastguard Worker         let mut total_read = 0u64;
163*bb4ee6a4SAndroid Build Coastguard Worker         // Handle reads across page boundaries.
164*bb4ee6a4SAndroid Build Coastguard Worker 
165*bb4ee6a4SAndroid Build Coastguard Worker         while total_read < len as u64 {
166*bb4ee6a4SAndroid Build Coastguard Worker             let (paddr, psize) = phys_addr(guest_mem, vaddr.0 + total_read, &sregs)?;
167*bb4ee6a4SAndroid Build Coastguard Worker             let read_len = std::cmp::min(len as u64 - total_read, psize - (paddr & (psize - 1)));
168*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem
169*bb4ee6a4SAndroid Build Coastguard Worker                 .get_slice_at_addr(GuestAddress(paddr), read_len as usize)
170*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(Error::ReadingGuestMemory)?
171*bb4ee6a4SAndroid Build Coastguard Worker                 .copy_to(&mut buf[total_read as usize..]);
172*bb4ee6a4SAndroid Build Coastguard Worker             total_read += read_len;
173*bb4ee6a4SAndroid Build Coastguard Worker         }
174*bb4ee6a4SAndroid Build Coastguard Worker         Ok(buf)
175*bb4ee6a4SAndroid Build Coastguard Worker     }
176*bb4ee6a4SAndroid Build Coastguard Worker 
write_memory( vcpu: &T, guest_mem: &GuestMemory, vaddr: GuestAddress, buf: &[u8], ) -> Result<()>177*bb4ee6a4SAndroid Build Coastguard Worker     fn write_memory(
178*bb4ee6a4SAndroid Build Coastguard Worker         vcpu: &T,
179*bb4ee6a4SAndroid Build Coastguard Worker         guest_mem: &GuestMemory,
180*bb4ee6a4SAndroid Build Coastguard Worker         vaddr: GuestAddress,
181*bb4ee6a4SAndroid Build Coastguard Worker         buf: &[u8],
182*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
183*bb4ee6a4SAndroid Build Coastguard Worker         let sregs = vcpu.get_sregs().map_err(Error::ReadRegs)?;
184*bb4ee6a4SAndroid Build Coastguard Worker         let mut total_written = 0u64;
185*bb4ee6a4SAndroid Build Coastguard Worker         // Handle writes across page boundaries.
186*bb4ee6a4SAndroid Build Coastguard Worker         while total_written < buf.len() as u64 {
187*bb4ee6a4SAndroid Build Coastguard Worker             let (paddr, psize) = phys_addr(guest_mem, vaddr.0 + total_written, &sregs)?;
188*bb4ee6a4SAndroid Build Coastguard Worker             let write_len = std::cmp::min(
189*bb4ee6a4SAndroid Build Coastguard Worker                 buf.len() as u64 - total_written,
190*bb4ee6a4SAndroid Build Coastguard Worker                 psize - (paddr & (psize - 1)),
191*bb4ee6a4SAndroid Build Coastguard Worker             );
192*bb4ee6a4SAndroid Build Coastguard Worker 
193*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem
194*bb4ee6a4SAndroid Build Coastguard Worker                 .write_all_at_addr(
195*bb4ee6a4SAndroid Build Coastguard Worker                     &buf[total_written as usize..(total_written as usize + write_len as usize)],
196*bb4ee6a4SAndroid Build Coastguard Worker                     GuestAddress(paddr),
197*bb4ee6a4SAndroid Build Coastguard Worker                 )
198*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(Error::WritingGuestMemory)?;
199*bb4ee6a4SAndroid Build Coastguard Worker             total_written += write_len;
200*bb4ee6a4SAndroid Build Coastguard Worker         }
201*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
202*bb4ee6a4SAndroid Build Coastguard Worker     }
203*bb4ee6a4SAndroid Build Coastguard Worker 
enable_singlestep(vcpu: &T) -> Result<()>204*bb4ee6a4SAndroid Build Coastguard Worker     fn enable_singlestep(vcpu: &T) -> Result<()> {
205*bb4ee6a4SAndroid Build Coastguard Worker         vcpu.set_guest_debug(&[], true /* enable_singlestep */)
206*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::EnableSinglestep)
207*bb4ee6a4SAndroid Build Coastguard Worker     }
208*bb4ee6a4SAndroid Build Coastguard Worker 
get_max_hw_breakpoints(_vcpu: &T) -> Result<usize>209*bb4ee6a4SAndroid Build Coastguard Worker     fn get_max_hw_breakpoints(_vcpu: &T) -> Result<usize> {
210*bb4ee6a4SAndroid Build Coastguard Worker         Ok(4usize)
211*bb4ee6a4SAndroid Build Coastguard Worker     }
212*bb4ee6a4SAndroid Build Coastguard Worker 
set_hw_breakpoints(vcpu: &T, breakpoints: &[GuestAddress]) -> Result<()>213*bb4ee6a4SAndroid Build Coastguard Worker     fn set_hw_breakpoints(vcpu: &T, breakpoints: &[GuestAddress]) -> Result<()> {
214*bb4ee6a4SAndroid Build Coastguard Worker         vcpu.set_guest_debug(breakpoints, false /* enable_singlestep */)
215*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::SetHwBreakpoint)
216*bb4ee6a4SAndroid Build Coastguard Worker     }
217*bb4ee6a4SAndroid Build Coastguard Worker }
218*bb4ee6a4SAndroid Build Coastguard Worker 
219*bb4ee6a4SAndroid Build Coastguard Worker // return the translated address and the size of the page it resides in.
phys_addr(mem: &GuestMemory, vaddr: u64, sregs: &Sregs) -> Result<(u64, u64)>220*bb4ee6a4SAndroid Build Coastguard Worker fn phys_addr(mem: &GuestMemory, vaddr: u64, sregs: &Sregs) -> Result<(u64, u64)> {
221*bb4ee6a4SAndroid Build Coastguard Worker     const CR0_PG_MASK: u64 = 1 << 31;
222*bb4ee6a4SAndroid Build Coastguard Worker     const CR4_PAE_MASK: u64 = 1 << 5;
223*bb4ee6a4SAndroid Build Coastguard Worker     const CR4_LA57_MASK: u64 = 1 << 12;
224*bb4ee6a4SAndroid Build Coastguard Worker     const MSR_EFER_LMA: u64 = 1 << 10;
225*bb4ee6a4SAndroid Build Coastguard Worker     // bits 12 through 51 are the address in a PTE.
226*bb4ee6a4SAndroid Build Coastguard Worker     const PTE_ADDR_MASK: u64 = ((1 << 52) - 1) & !0x0fff;
227*bb4ee6a4SAndroid Build Coastguard Worker     const PAGE_PRESENT: u64 = 0x1;
228*bb4ee6a4SAndroid Build Coastguard Worker     const PAGE_PSE_MASK: u64 = 0x1 << 7;
229*bb4ee6a4SAndroid Build Coastguard Worker 
230*bb4ee6a4SAndroid Build Coastguard Worker     const PAGE_SIZE_4K: u64 = 4 * 1024;
231*bb4ee6a4SAndroid Build Coastguard Worker     const PAGE_SIZE_2M: u64 = 2 * 1024 * 1024;
232*bb4ee6a4SAndroid Build Coastguard Worker     const PAGE_SIZE_1G: u64 = 1024 * 1024 * 1024;
233*bb4ee6a4SAndroid Build Coastguard Worker 
234*bb4ee6a4SAndroid Build Coastguard Worker     fn next_pte(mem: &GuestMemory, curr_table_addr: u64, vaddr: u64, level: usize) -> Result<u64> {
235*bb4ee6a4SAndroid Build Coastguard Worker         let ent: u64 = mem
236*bb4ee6a4SAndroid Build Coastguard Worker             .read_obj_from_addr(GuestAddress(
237*bb4ee6a4SAndroid Build Coastguard Worker                 (curr_table_addr & PTE_ADDR_MASK) + page_table_offset(vaddr, level),
238*bb4ee6a4SAndroid Build Coastguard Worker             ))
239*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|_| Error::TranslatingVirtAddr)?;
240*bb4ee6a4SAndroid Build Coastguard Worker         /* TODO - convert to a trace
241*bb4ee6a4SAndroid Build Coastguard Worker         println!(
242*bb4ee6a4SAndroid Build Coastguard Worker             "level {} vaddr {:x} table-addr {:x} mask {:x} ent {:x} offset {:x}",
243*bb4ee6a4SAndroid Build Coastguard Worker             level,
244*bb4ee6a4SAndroid Build Coastguard Worker             vaddr,
245*bb4ee6a4SAndroid Build Coastguard Worker             curr_table_addr,
246*bb4ee6a4SAndroid Build Coastguard Worker             PTE_ADDR_MASK,
247*bb4ee6a4SAndroid Build Coastguard Worker             ent,
248*bb4ee6a4SAndroid Build Coastguard Worker             page_table_offset(vaddr, level)
249*bb4ee6a4SAndroid Build Coastguard Worker         );
250*bb4ee6a4SAndroid Build Coastguard Worker         */
251*bb4ee6a4SAndroid Build Coastguard Worker         if ent & PAGE_PRESENT == 0 {
252*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::PageNotPresent);
253*bb4ee6a4SAndroid Build Coastguard Worker         }
254*bb4ee6a4SAndroid Build Coastguard Worker         Ok(ent)
255*bb4ee6a4SAndroid Build Coastguard Worker     }
256*bb4ee6a4SAndroid Build Coastguard Worker 
257*bb4ee6a4SAndroid Build Coastguard Worker     // Get the offset in to the page of `vaddr`.
258*bb4ee6a4SAndroid Build Coastguard Worker     fn page_offset(vaddr: u64, page_size: u64) -> u64 {
259*bb4ee6a4SAndroid Build Coastguard Worker         vaddr & (page_size - 1)
260*bb4ee6a4SAndroid Build Coastguard Worker     }
261*bb4ee6a4SAndroid Build Coastguard Worker 
262*bb4ee6a4SAndroid Build Coastguard Worker     // Get the offset in to the page table of the given `level` specified by the virtual `address`.
263*bb4ee6a4SAndroid Build Coastguard Worker     // `level` is 1 through 5 in x86_64 to handle the five levels of paging.
264*bb4ee6a4SAndroid Build Coastguard Worker     fn page_table_offset(addr: u64, level: usize) -> u64 {
265*bb4ee6a4SAndroid Build Coastguard Worker         let offset = (level - 1) * 9 + 12;
266*bb4ee6a4SAndroid Build Coastguard Worker         ((addr >> offset) & 0x1ff) << 3
267*bb4ee6a4SAndroid Build Coastguard Worker     }
268*bb4ee6a4SAndroid Build Coastguard Worker 
269*bb4ee6a4SAndroid Build Coastguard Worker     if sregs.cr0 & CR0_PG_MASK == 0 {
270*bb4ee6a4SAndroid Build Coastguard Worker         return Ok((vaddr, PAGE_SIZE_4K));
271*bb4ee6a4SAndroid Build Coastguard Worker     }
272*bb4ee6a4SAndroid Build Coastguard Worker 
273*bb4ee6a4SAndroid Build Coastguard Worker     if sregs.cr4 & CR4_PAE_MASK == 0 {
274*bb4ee6a4SAndroid Build Coastguard Worker         return Err(Error::TranslatingVirtAddr);
275*bb4ee6a4SAndroid Build Coastguard Worker     }
276*bb4ee6a4SAndroid Build Coastguard Worker 
277*bb4ee6a4SAndroid Build Coastguard Worker     if sregs.efer & MSR_EFER_LMA != 0 {
278*bb4ee6a4SAndroid Build Coastguard Worker         // TODO - check LA57
279*bb4ee6a4SAndroid Build Coastguard Worker         if sregs.cr4 & CR4_LA57_MASK != 0 {
280*bb4ee6a4SAndroid Build Coastguard Worker             todo!("handle LA57");
281*bb4ee6a4SAndroid Build Coastguard Worker         }
282*bb4ee6a4SAndroid Build Coastguard Worker         let p4_ent = next_pte(mem, sregs.cr3, vaddr, 4)?;
283*bb4ee6a4SAndroid Build Coastguard Worker         let p3_ent = next_pte(mem, p4_ent, vaddr, 3)?;
284*bb4ee6a4SAndroid Build Coastguard Worker         // TODO check if it's a 1G page with the PSE bit in p2_ent
285*bb4ee6a4SAndroid Build Coastguard Worker         if p3_ent & PAGE_PSE_MASK != 0 {
286*bb4ee6a4SAndroid Build Coastguard Worker             // It's a 1G page with the PSE bit in p3_ent
287*bb4ee6a4SAndroid Build Coastguard Worker             let paddr = p3_ent & PTE_ADDR_MASK | page_offset(vaddr, PAGE_SIZE_1G);
288*bb4ee6a4SAndroid Build Coastguard Worker             return Ok((paddr, PAGE_SIZE_1G));
289*bb4ee6a4SAndroid Build Coastguard Worker         }
290*bb4ee6a4SAndroid Build Coastguard Worker         let p2_ent = next_pte(mem, p3_ent, vaddr, 2)?;
291*bb4ee6a4SAndroid Build Coastguard Worker         if p2_ent & PAGE_PSE_MASK != 0 {
292*bb4ee6a4SAndroid Build Coastguard Worker             // It's a 2M page with the PSE bit in p2_ent
293*bb4ee6a4SAndroid Build Coastguard Worker             let paddr = p2_ent & PTE_ADDR_MASK | page_offset(vaddr, PAGE_SIZE_2M);
294*bb4ee6a4SAndroid Build Coastguard Worker             return Ok((paddr, PAGE_SIZE_2M));
295*bb4ee6a4SAndroid Build Coastguard Worker         }
296*bb4ee6a4SAndroid Build Coastguard Worker         let p1_ent = next_pte(mem, p2_ent, vaddr, 1)?;
297*bb4ee6a4SAndroid Build Coastguard Worker         let paddr = p1_ent & PTE_ADDR_MASK | page_offset(vaddr, PAGE_SIZE_4K);
298*bb4ee6a4SAndroid Build Coastguard Worker         return Ok((paddr, PAGE_SIZE_4K));
299*bb4ee6a4SAndroid Build Coastguard Worker     }
300*bb4ee6a4SAndroid Build Coastguard Worker     Err(Error::TranslatingVirtAddr)
301*bb4ee6a4SAndroid Build Coastguard Worker }
302