User- and system mode

User mode

  • Goal: run Linux binaries compiled for a different arch
  • JIT compile
  • Map syscalls

System mode

  • Full system simulation (CPU, MMU, buses, …)
  • Not cycle accurate, not cache model
  • (aka softmmu)

Major Internal API

QOM

qdev

Monitor

HMP

Ctrl-A C info qom-tree

QMP

Json API

QAPI

  • autogenerate C from JSON
  • simplify impl. of QMP commands
  • introspection
  • Serialization/deserialization

High Level Control flow (User-mode)

For user mode, the folders that should be needed to care about is

  • linux-user
    • loading of binary
    • entry-point
    • syscalls
  • accel
    • KVM/HVF
    • core translation loop
    • memory mapping
    • Tinycode state
  • target
    • Instruction decoding and translating
  • tcg
    • Tinycode optimization
    • JIT engine

Which machine

System-mode high-level control flow

system-mode entry point

// system/main.c
int main(int argc, char **argv) {
	qemu_init(argc, argv);
	...
	qemu_default_main(NULL); // end up with qemu_main_loop
}
 
// system/vl.c
void qemu_init(int argc, char** argv) {
	// CLI parsing
	...
	qemu_create_machine(machine_opts_dict); 
		// -> machine init: hw/<arch>/<machine>.c
		//  -> vCPU realization: target/<arch>/cpu.c
		//   -> vCPU thread creation: qemu_init_vcpu in system/cpus.c
		//    -> vCPU thread loop: (cpus_accel->create_vcpu_thread(cpu)) in accel/tcg/tcg-accel-ops-mttcg.c
	
	// e.q. accel/tcg
	configure_accelerators(argv[0]);
	
	qemu_init_displays();
}
  • BIOS is executed
  • Load our program at 0x7c00
  • Jumps to 0x7c00

System-mode threads

  • 1 main event loop thread
  • N vCPU threads
  • ~1 large mutex(BQL)
// system/runstate.c
int qemu_main_loop(void) {
	int status = EXIT_SUCCESS;
	while (!main_loop_should_exit(&status)) {
		main_loop_wait(false);
	}
	return status;
}
 
// util/main-loop.c
void main_loop_wait(int nonblocking) {
	// Waiting for events, e.g. keyboard
	ret = os_host_main_loop_wait(timeout_ns);
	// Notify timers updates. e.g. VGA
	qemu_clock_run_all_timers();
}
 
static int os_host_main_loop_wait(int64_t timeout) {
	bql_unlock();
	ret = qemu_poll_ns((GPollFD*)gpollfds->data, gpollfds->len, timeout);
	bql_lock();
}
// <=>. 
// accel/tcg-accel-ops-mttcg.c
static void *mttcg_cpu_thread_fn(void *arg) {
	...
	do {
		qemu_process_cpu_events(cpu);
		
		bql_unlock();
		r = tcg_cpu_exec(cpu);
		bql_lock();
	} while(!cpu->unplug || cpu_can_run(cpu));
}

Memory Regions

How does our program work?

for x86 machine

  • Bootloader stage 1
    • Bootsector headers
    • Loads stage 2
  • Bootloader stage 2
    • Loads program
    • Gets VESA frambuffer from BIOS
    • set-up page-table
    • switch to 64-bit long mode
    • jump to program
  • Actual program
    • set up programmable Interrupt Controller(PIC)
    • Register
      • Interrupt Service Routines(ISRs)
      • Interrupt Request Handlers(IRQs)
    • When a ps/2 keyboard interrupt occurs, draw a character to the VESA framebuffer

Summary

  • 1 main event thread
  • N vCPU threads
  • machine modeled in QOM types
  • memory regions link together devices

reference