Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
V
virtual_game_machine
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
adrian.spycher
virtual_game_machine
Commits
48c5a7c8
Commit
48c5a7c8
authored
7 months ago
by
adrian.spycher
Browse files
Options
Downloads
Patches
Plain Diff
feat!: add KVM workflow and read binary (end lab 01)
parent
e79d968b
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
vmm/vmm_main.c
+165
-0
165 additions, 0 deletions
vmm/vmm_main.c
with
165 additions
and
0 deletions
vmm/vmm_main.c
0 → 100644
+
165
−
0
View file @
48c5a7c8
#include
<err.h>
#include
<stdbool.h>
#include
<fcntl.h>
#include
<linux/kvm.h>
#include
<stdint.h>
#include
<stdio.h>
#include
<unistd.h>
#include
<stdlib.h>
#include
<string.h>
#include
<sys/ioctl.h>
#include
<sys/mman.h>
#include
<sys/stat.h>
#include
<sys/types.h>
// -- DEFINE --
#define KVM_API_VERSION 12
#define RAM_SIZE (512 * 1024)
// -- MAIN --
int
main
(
int
argc
,
char
*
argv
[])
{
int
kvmfd
,
vmfd
,
vcpufd
;
struct
kvm_sregs
sregs
;
struct
kvm_run
*
run
;
size_t
mmap_size
;
uint8_t
*
mem
;
// -- 0. Handle Args --
char
*
file_path
=
argv
[
1
];
// -- 1. Create a KVM device --
kvmfd
=
open
(
"/dev/kvm"
,
O_RDWR
|
O_CLOEXEC
);
// get file descriptor
if
(
kvmfd
==
-
1
)
err
(
1
,
"/dev/kvm"
);
// check stable version of the API
int
version
=
ioctl
(
kvmfd
,
KVM_GET_API_VERSION
,
NULL
);
if
(
version
==
-
1
)
err
(
1
,
"KVM_GET_API_VERSION"
);
if
(
version
!=
KVM_API_VERSION
)
errx
(
1
,
"KVM_GET_API_VERSION %d, expected 12"
,
version
);
// -- 2. Create a VM --
vmfd
=
ioctl
(
kvmfd
,
KVM_CREATE_VM
,
(
unsigned
long
)
0
);
if
(
vmfd
==
-
1
)
err
(
1
,
"KVM_CREATE_VM"
);
// -- 3. Allocate RAM for the VM --
mem
=
mmap
(
NULL
,
RAM_SIZE
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
|
MAP_ANONYMOUS
,
-
1
,
0
);
// memory to hold the code
if
(
!
mem
)
err
(
1
,
"allocating guest memory"
);
// -- 4. Map allocated RAM into the VM’s address space --
struct
kvm_userspace_memory_region
region
=
{
.
slot
=
0
,
.
guest_phys_addr
=
0
,
.
memory_size
=
RAM_SIZE
,
.
userspace_addr
=
(
uint64_t
)
mem
,
.
flags
=
0
,
};
int
memreg_err
=
ioctl
(
vmfd
,
KVM_SET_USER_MEMORY_REGION
,
&
region
);
if
(
memreg_err
==
-
1
)
err
(
1
,
"KVM_SET_USER_MEMORY_REGION"
);
// -- 5. Load guest OS into VM’s RAM --
// Open the binary file
int
binfd
=
open
(
file_path
,
O_RDONLY
);
if
(
binfd
<
0
)
err
(
1
,
"Error opening guestOS binary file"
);
// Get the file size using fstat
struct
stat
st
;
if
(
fstat
(
binfd
,
&
st
)
<
0
)
perror
(
"Error getting file size"
);
// Check if the file size exceeds the available memory
if
(
st
.
st_size
>
RAM_SIZE
)
err
(
1
,
"Error: GuestOS binary size exceeds 512KB
\n
"
);
// Read the file into the provided memory (mem)
ssize_t
bytes_read
=
read
(
binfd
,
mem
,
st
.
st_size
);
if
(
bytes_read
<
0
)
err
(
1
,
"Error reading guestOS binary file"
);
// Check if all bytes were read
if
(
bytes_read
!=
st
.
st_size
)
err
(
1
,
"Error: Only %ld of %ld bytes read from file
\n
"
,
bytes_read
,
st
.
st_size
);
// Close the file descriptor
close
(
binfd
);
// -- 6.1. Create a vCPU --
vcpufd
=
ioctl
(
vmfd
,
KVM_CREATE_VCPU
,
(
unsigned
long
)
0
);
if
(
vcpufd
==
-
1
)
err
(
1
,
"KVM_CREATE_VCPU"
);
// map the shared kvm_run structure and following data
mmap_size
=
ioctl
(
kvmfd
,
KVM_GET_VCPU_MMAP_SIZE
,
NULL
);
if
(
mmap_size
==
-
1
)
err
(
1
,
"KVM_GET_VCPU_MMAP_SIZE"
);
if
(
mmap_size
<
sizeof
(
*
run
))
errx
(
1
,
"KVM_GET_VCPU_MMAP_SIZE unexpectedly small"
);
// get memory-mapped file
run
=
mmap
(
NULL
,
mmap_size
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
vcpufd
,
0
);
if
(
!
run
)
err
(
1
,
"mmap vcpu"
);
// -- 6.2. Initialize vCPU registers --
int
sregs_err
=
ioctl
(
vcpufd
,
KVM_GET_SREGS
,
&
sregs
);
if
(
sregs_err
==
-
1
)
err
(
1
,
"KVM_GET_SREGS"
);
// initialize segment registers to zero, via a read-modify-write of sregs
sregs
.
cs
.
base
=
0
;
sregs
.
cs
.
selector
=
0
;
sregs
.
ds
.
base
=
0
;
sregs
.
ds
.
selector
=
0
;
sregs
.
es
.
base
=
0
;
sregs
.
es
.
selector
=
0
;
sregs
.
ss
.
base
=
0
;
sregs
.
ss
.
selector
=
0
;
sregs_err
=
ioctl
(
vcpufd
,
KVM_SET_SREGS
,
&
sregs
);
if
(
sregs_err
==
-
1
)
err
(
1
,
"KVM_SET_SREGS"
);
// initialize pointer and flags
struct
kvm_regs
regs
=
{
.
rip
=
0
,
// instruction pointer -> beginning of OS's code
.
rsp
=
RAM_SIZE
,
// stack pointer -> top of RAM
.
rflags
=
0x2
,
// flags required by x86 architecture
};
int
regs_err
=
ioctl
(
vcpufd
,
KVM_SET_REGS
,
&
regs
);
if
(
regs_err
==
-
1
)
err
(
1
,
"KVM_SET_REGS"
);
// -- 7. Run the vCPU --
bool
done
=
false
;
while
(
!
done
)
{
if
(
ioctl
(
vcpufd
,
KVM_RUN
,
NULL
)
==
-
1
)
err
(
1
,
"KVM_RUN"
);
// handle VM exits (blocking call)
switch
(
run
->
exit_reason
)
{
case
KVM_EXIT_HLT
:
puts
(
"KVM_EXIT_HLT"
);
done
=
true
;
break
;
case
KVM_EXIT_IO
:
if
(
run
->
io
.
direction
==
KVM_EXIT_IO_OUT
&&
run
->
io
.
size
==
1
&&
run
->
io
.
port
==
0x3f8
&&
run
->
io
.
count
==
1
)
putchar
(
*
(((
char
*
)
run
)
+
run
->
io
.
data_offset
));
else
errx
(
1
,
"unhandled KVM_EXIT_IO"
);
break
;
case
KVM_EXIT_MMIO
:
// !TODO!
done
=
true
;
break
;
case
KVM_EXIT_FAIL_ENTRY
:
errx
(
1
,
"KVM_EXIT_FAIL_ENTRY: hardware_entry_failure_reason = 0x%llx"
,
(
unsigned
long
long
)
run
->
fail_entry
.
hardware_entry_failure_reason
);
done
=
true
;
break
;
case
KVM_EXIT_INTERNAL_ERROR
:
errx
(
1
,
"KVM_EXIT_INTERNAL_ERROR: suberror = 0x%x"
,
run
->
internal
.
suberror
);
done
=
true
;
break
;
default:
errx
(
1
,
"exit_reason = 0x%x"
,
run
->
exit_reason
);
done
=
true
;
break
;
}
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment