Skip to content

Commit 56547f1

Browse files
committed
WIP: trying to fix memory conversion error
Signed-off-by: Jake Correnti <[email protected]>
1 parent bbc776a commit 56547f1

File tree

5 files changed

+396
-75
lines changed

5 files changed

+396
-75
lines changed

src/libkrun/src/lib.rs

+110-42
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,10 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 {
11931193
match receiver.recv() {
11941194
Err(e) => error!("Error in receiver: {:?}", e),
11951195
Ok((gpa, size, private)) => {
1196-
let _ = convert_memory(&mapper_vmm, gpa, size, private);
1196+
let ret = convert_memory(&mapper_vmm, gpa, size, private);
1197+
if ret < 0 {
1198+
panic!("{}", format!("ERROR CONVERTING MEMORY: {:x} {:x} {}", gpa, size, private));
1199+
}
11971200
},
11981201
}
11991202
}).unwrap();
@@ -1227,74 +1230,139 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 {
12271230
}
12281231
}
12291232

1233+
use vm_memory::Address;
1234+
fn has_guest_memory(gpa: u64, size: u64, memfd_regions: &Vec<(vm_memory::GuestAddress, u64, u64)>) -> (bool, i64) {
1235+
for (a, s, i) in memfd_regions.iter() {
1236+
if gpa >= a.0 && gpa + size <= a.0 + *s {
1237+
return (true, *i as i64);
1238+
}
1239+
}
1240+
(false, -1)
1241+
}
1242+
12301243
use std::sync::Arc;
12311244
use vm_memory::GuestAddress;
1245+
use vm_memory::GuestMemory;
1246+
use libc::fallocate;
1247+
use libc::madvise;
1248+
use libc::FALLOC_FL_KEEP_SIZE;
1249+
use libc::FALLOC_FL_PUNCH_HOLE;
1250+
use libc::MADV_DONTNEED;
1251+
use libc::MADV_REMOVE;
12321252
fn convert_memory(vmm: &Arc<Mutex<vmm::Vmm>>, gpa: u64, size: u64, to_private: bool) -> i32 {
1253+
1254+
// check to make sure the starting address is aligned with the page size
1255+
// check to make sure the size of the memory block is also aligned with the page size
1256+
// if size is non-positive then return -1
1257+
// retrive the memory region associated with the starting address and the size
1258+
// set the memory attributes to the desired value
1259+
// if converting memory from shared to private, then discard the ram range
1260+
// if converting from private to shared, then discard the guest memfd range
1261+
12331262
let mut ret = -1;
1234-
let is_aligned = |n: u64, m: u64| -> bool {
1235-
((n) % (m)) == 0
1236-
};
1237-
1238-
if !is_aligned(gpa, 4096) || !is_aligned(size, 4096) {
1263+
let vmm = vmm.as_ref().lock().unwrap();
1264+
let guest_memfd_regions = vmm.guest_memfd_regions();
1265+
1266+
let page_size = 4096;
1267+
1268+
// check to make sure the starting address is aligned with the page size
1269+
// check to make sure the size of the memory block is also aligned with the page size
1270+
if (gpa % page_size) != 0 || (size % page_size) != 0 {
1271+
println!("ALIGNMENT ERROR");
12391272
return -1;
12401273
}
12411274

1275+
// if size is non-positive then return -1
12421276
if size < 1 {
1277+
println!("BAD SIZE");
12431278
return -1;
12441279
}
12451280

1246-
use vm_memory::guest_memory::GuestMemory;
1247-
let binding = vmm.as_ref().lock().unwrap();
1248-
let region = binding.guest_memory().find_region(GuestAddress(gpa));
1249-
1281+
let region = vmm.guest_memory().find_region(GuestAddress(gpa));
12501282
if let None = region {
1251-
// Ignore converting non-assigned region to shared
1283+
// ignore converting non-assigned region to shared
12521284
//
12531285
// TDX requires vMMIO region to be shared to inject #VE to guest. OVMF issues
1254-
// conservatively MapGPA(shared) on 32bit PCI MMIO region, and V vIO-APIC 0xFEC00000 4K
1255-
// page. OVMF assigns 32bit PCI MMIO region to [top of low memory: typically 2GB=0xC000000,
1256-
// 0xFC00000)
1286+
// conservatively MapGPA(shared) on 32bit PCI MMIO region, and vIO-APIC 0xFEC 4k page. OVMF
1287+
// assignes 32bit PCI MMIO region to [top of low memory: typically 2GB=0xC0000000,
1288+
// 0xFC000000)
12571289
if !to_private {
1290+
println!("IGNORE NON-ASSIGNED");
12581291
return 0;
12591292
}
1293+
1294+
println!("ERROR FINDING REGION");
12601295
return -1;
12611296
}
1262-
12631297
let region = region.unwrap();
12641298

1265-
use vm_memory::Address;
1266-
let mut region_has_guest_memfd = false;
1267-
for region in binding.guest_memfd_regions().iter() {
1268-
if gpa >= region.0.raw_value() && gpa + size <= region.0.raw_value() + region.1 {
1269-
region_has_guest_memfd = true;
1270-
}
1271-
}
1299+
// retrive the memory region associated with the starting address and the size
1300+
let (region_has_guest_memfd, memfd_id) = has_guest_memory(gpa, size, guest_memfd_regions);
12721301

1302+
// check to make sure there is a guest memfd backing
12731303
if !region_has_guest_memfd {
1274-
println!("DOESNT HAVE MEMFD");
1275-
1276-
// Because vMMIO region must be shared, guest TD may convert vMMIO region to shared
1277-
// explicitly. Don't complain such case. See memory_region_type() for checking if the
1278-
// region is MMIO region.
1279-
// if !to_private && !is_ram && !is_ram_device && !is_rom && !is_romd {
1280-
// ret = 0;
1281-
// } else {
1282-
// println!("Convert non guest_memfd backed memory region (0x{:x}, 0x{:x}, {}", gpa, size, if to_private { "private" } else { "shared" });
1283-
// }
1284-
1285-
return ret;
1304+
panic!("cannot convert non guest_memfd backed memory region");
1305+
return -1;
12861306
}
1287-
1307+
1308+
// set the memory attributes to the desired value
12881309
let attr = kvm_bindings::kvm_memory_attributes {
1289-
address: gpa,
1290-
size,
1291-
attributes: if to_private {
1292-
// KVM_MEMORY_ATTRIBUTE_PRIVATE,
1293-
1 << 3 } else { 0 },
1294-
flags: 0,
1310+
address: gpa,
1311+
size,
1312+
attributes: if to_private {
1313+
// KVM_MEMORY_ATTRIBUTE_PRIVATE,
1314+
1 << 3 } else { 0 },
1315+
flags: 0,
12951316
};
12961317

1297-
binding.vm_fd().set_memory_attributes(attr).unwrap();
1318+
vmm.vm_fd().set_memory_attributes(attr).unwrap();
1319+
1320+
use vm_memory::GuestMemoryRegion;
1321+
1322+
let offset = gpa - region.start_addr().raw_value();
1323+
if to_private {
1324+
// ram_block_discard_range
1325+
println!("DISCARDING MEMORY RANGE WHEN CONVERTING SHARED TO PRIVATE");
1326+
1327+
let host_addr = region.get_host_address(vm_memory::MemoryRegionAddress(gpa)).unwrap();
1328+
1329+
// let host_addr = gpa + offset;
1330+
unsafe {
1331+
let _ret = madvise(
1332+
host_addr as *mut libc::c_void,
1333+
size.try_into().unwrap(),
1334+
// madv_remove,
1335+
MADV_DONTNEED,
1336+
);
1337+
println!("gpa: {:x} size: {:x}", gpa, size);
1338+
1339+
if _ret < 0 {
1340+
println!("error discarding memory range: gpa: 0x{:x} size: 0x{:x} res: {}", gpa, size, std::io::Error::last_os_error());
1341+
return _ret;
1342+
}
1343+
}
1344+
} else {
1345+
// ram_block_discard_guest_memfd_range
1346+
println!("DISCARDING GUEST MEMFD MEMORY REGION WHEN CONVERTING PRIVATE TO SHARED");
1347+
unsafe {
1348+
let _ret = fallocate(
1349+
memfd_id as i32,
1350+
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
1351+
offset as i64,
1352+
size as i64,
1353+
);
1354+
1355+
if _ret < 0 {
1356+
println!("error discarding guest memfd memory range: {}", std::io::Error::last_os_error());
1357+
return _ret;
1358+
}
1359+
}
1360+
}
12981361

1362+
0
1363+
}
1364+
1365+
fn ram_block_discard_range<T>(rb: &vm_memory::GuestRegionMmap<T>, start: u64, length: u64) -> i64 {
1366+
let mut ret = -1;
12991367
ret
13001368
}

src/rutabaga_gfx/src/generated/generate

-1
This file was deleted.
+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2018 The ChromiumOS Authors
3+
# Use of this source code is governed by a BSD-style license that can be
4+
# found in the LICENSE file.
5+
6+
"""Generates bindings that are used gpu_renderer.
7+
8+
A sysroot and virglrenderer source checkout is required. The defaults to the
9+
root directory.
10+
"""
11+
12+
from __future__ import print_function
13+
import argparse
14+
import multiprocessing.pool
15+
import os
16+
import subprocess
17+
import sys
18+
import tempfile
19+
20+
# Bright green.
21+
PASS_COLOR = "\033[1;32m"
22+
# Bright red.
23+
FAIL_COLOR = "\033[1;31m"
24+
# Default color.
25+
END_COLOR = "\033[0m"
26+
27+
verbose = False
28+
29+
30+
def generate_module(
31+
module_name, allowlist, blocklist, header, clang_args, lib_name, derive_default
32+
):
33+
args = [
34+
"bindgen",
35+
"--no-layout-tests",
36+
"--allowlist-function",
37+
allowlist,
38+
"--allowlist-var",
39+
allowlist,
40+
"--allowlist-type",
41+
allowlist,
42+
"--blocklist-function",
43+
blocklist,
44+
"--blocklist-item",
45+
blocklist,
46+
"--blocklist-type",
47+
blocklist,
48+
"--no-prepend-enum-name",
49+
"-o",
50+
module_name + "_bindings.rs",
51+
]
52+
53+
if lib_name:
54+
args.extend(["--raw-line", '#[cfg(feature = "{}")]'.format(module_name)])
55+
args.extend(["--raw-line", '#[link(name = "{}")] extern {{}}'.format(lib_name)])
56+
57+
if derive_default:
58+
args.append("--with-derive-default")
59+
60+
args.extend([header, "--"])
61+
args.extend(clang_args)
62+
63+
if verbose:
64+
print(" ".join(args))
65+
66+
if subprocess.Popen(args).wait() == 0:
67+
return "pass"
68+
else:
69+
return "bindgen failed"
70+
71+
72+
def download_virgl(src, dst, branch):
73+
virgl_src = tempfile.TemporaryDirectory(prefix="virglrenderer-src")
74+
75+
args = ["git", "clone"]
76+
77+
if branch:
78+
args.extend(["-b", branch])
79+
80+
args.extend([src, dst])
81+
82+
if verbose:
83+
print(" ".join(args))
84+
85+
if subprocess.Popen(args).wait() == 0:
86+
return True
87+
else:
88+
return False
89+
90+
91+
def get_parser():
92+
"""Gets the argument parser"""
93+
parser = argparse.ArgumentParser(description=__doc__)
94+
parser.add_argument("--sysroot", default="/", help="sysroot directory (default=%(default)s)")
95+
parser.add_argument("--virglrenderer", help="virglrenderer src dir/repo (default=%(default)s)")
96+
parser.add_argument(
97+
"--virgl_branch",
98+
default="master",
99+
help="virglrenderer branch name (default=%(default)s)",
100+
)
101+
parser.add_argument(
102+
"--verbose",
103+
"-v",
104+
action="store_true",
105+
help="enable verbose output (default=%(default)s)",
106+
)
107+
return parser
108+
109+
110+
def main(argv):
111+
global verbose
112+
os.chdir(os.path.dirname(sys.argv[0]))
113+
opts = get_parser().parse_args(argv)
114+
if opts.verbose:
115+
verbose = True
116+
117+
if opts.virglrenderer:
118+
if "://" in opts.virglrenderer:
119+
virgl_src_dir_temp = tempfile.TemporaryDirectory(prefix="virglrenderer-src")
120+
virgl_src_dir = virgl_src_dir_temp.name
121+
if not download_virgl(opts.virglrenderer, virgl_src_dir, opts.virgl_branch):
122+
print("failed to clone '{}' to '{}'".format(virgl_src_dir, opts.virgl_branch))
123+
sys.exit(1)
124+
else:
125+
virgl_src_dir = opts.virglrenderer
126+
127+
header = os.path.join(virgl_src_dir, "src/virglrenderer.h")
128+
else:
129+
header = os.path.join(opts.sysroot, "usr/include/virgl/virglrenderer.h")
130+
131+
clang_args = [
132+
"-I",
133+
os.path.join(opts.sysroot, "usr/include"),
134+
"-D",
135+
"VIRGL_RENDERER_UNSTABLE_APIS",
136+
]
137+
138+
modules = (
139+
(
140+
"virgl_renderer",
141+
"(virgl|VIRGL)_.+", # allowlist
142+
".*(va_list|debug_callback).*", # blocklist
143+
header,
144+
clang_args,
145+
"virglrenderer",
146+
True,
147+
),
148+
)
149+
150+
pool = multiprocessing.pool.Pool(len(modules))
151+
results = pool.starmap(generate_module, modules, 1)
152+
153+
return_fail = False
154+
print("---")
155+
print("generate module summary:")
156+
for module, result in zip(modules, results):
157+
result_color = FAIL_COLOR
158+
if result == "pass":
159+
result_color = PASS_COLOR
160+
else:
161+
return_fail = True
162+
163+
print("%15s: %s%s%s" % (module[0], result_color, result, END_COLOR))
164+
165+
if return_fail:
166+
sys.exit(1)
167+
168+
with open("mod.rs", "w") as f:
169+
print("/* generated by generate.py */", file=f)
170+
print("#![allow(dead_code)]", file=f)
171+
print("#![allow(non_camel_case_types)]", file=f)
172+
print("#![allow(non_snake_case)]", file=f)
173+
print("#![allow(non_upper_case_globals)]", file=f)
174+
print("pub mod virgl_debug_callback_bindings;", file=f)
175+
for module in modules:
176+
print("pub mod", module[0] + "_bindings;", file=f)
177+
178+
179+
if __name__ == "__main__":
180+
sys.exit(main(sys.argv[1:]))

src/vmm/src/builder.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ pub fn build_microvm(
358358
#[cfg(target_os = "macos")] _map_sender: Sender<MemoryMapping>,
359359
) -> std::result::Result<Arc<Mutex<Vmm>>, StartMicrovmError> {
360360

361-
let mut guest_memfd_regions: Vec<(GuestAddress, u64)> = vec![];
361+
let mut guest_memfd_regions: Vec<(vm_memory::GuestAddress, u64, u64)> = vec![];
362362

363363
#[cfg(not(feature = "efi"))]
364364
let kernel_bundle = vm_resources
@@ -993,7 +993,7 @@ pub(crate) fn setup_vm(
993993
kvm: &KvmContext,
994994
guest_memory: &GuestMemoryMmap,
995995
tee_config: &TeeConfig,
996-
guest_memfd_regions: &mut Vec<(GuestAddress, u64)>,
996+
guest_memfd_regions: &mut Vec<(vm_memory::GuestAddress, u64, u64)>,
997997
) -> std::result::Result<Vm, StartMicrovmError> {
998998
let mut vm = Vm::new(kvm.fd(), tee_config)
999999
.map_err(Error::Vm)

0 commit comments

Comments
 (0)