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